Index: libgnomevfs/gnome-vfs-xfer.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-xfer.c,v
retrieving revision 1.110
diff -u -r1.110 gnome-vfs-xfer.c
--- libgnomevfs/gnome-vfs-xfer.c	15 Dec 2003 14:57:07 -0000	1.110
+++ libgnomevfs/gnome-vfs-xfer.c	10 Apr 2004 12:37:39 -0000
@@ -317,30 +317,34 @@
 /* This is conceptually similiar to the previous `handle_error()' function, but
  * handles the overwrite case. 
  */
-static gboolean
+static void
 handle_overwrite (GnomeVFSResult *result,
 		  GnomeVFSProgressCallbackState *progress,
 		  GnomeVFSXferErrorMode *error_mode,
 		  GnomeVFSXferOverwriteMode *overwrite_mode,
 		  gboolean *replace,
-		  gboolean *skip)
+		  gboolean *skip,
+		  gboolean *merge)
 {
 	GnomeVFSXferOverwriteAction action;
 
+        *replace = FALSE;
+	*skip = FALSE;
+	*merge = FALSE;
+	
 	switch (*overwrite_mode) {
 	case GNOME_VFS_XFER_OVERWRITE_MODE_ABORT:
-		*replace = FALSE;
 		*result = GNOME_VFS_ERROR_FILE_EXISTS;
-		*skip = FALSE;
-		return FALSE;
+		return;
 	case GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE:
 		*replace = TRUE;
-		*skip = FALSE;
-		return TRUE;
+		return;
 	case GNOME_VFS_XFER_OVERWRITE_MODE_SKIP:
-		*replace = FALSE;
 		*skip = TRUE;
-		return FALSE;
+		return;
+	case GNOME_VFS_XFER_OVERWRITE_MODE_MERGE:
+		*merge = FALSE;
+		return;
 	case GNOME_VFS_XFER_OVERWRITE_MODE_QUERY:
 		progress->progress_info->vfs_status = *result;
 		progress->progress_info->status = GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE;
@@ -349,34 +353,33 @@
 
 		switch (action) {
 		case GNOME_VFS_XFER_OVERWRITE_ACTION_ABORT:
-			*replace = FALSE;
 			*result = GNOME_VFS_ERROR_FILE_EXISTS;
-			*skip = FALSE;
-			return FALSE;
+			return;
 		case GNOME_VFS_XFER_OVERWRITE_ACTION_REPLACE:
 			*replace = TRUE;
-			*skip = FALSE;
-			return TRUE;
+			return;
 		case GNOME_VFS_XFER_OVERWRITE_ACTION_REPLACE_ALL:
 			*replace = TRUE;
 			*overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE;
-			*skip = FALSE;
-			return TRUE;
+			return;
 		case GNOME_VFS_XFER_OVERWRITE_ACTION_SKIP:
-			*replace = FALSE;
 			*skip = TRUE;
-			return FALSE;
+			return;
 		case GNOME_VFS_XFER_OVERWRITE_ACTION_SKIP_ALL:
-			*replace = FALSE;
 			*skip = TRUE;
 			*overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_SKIP;
-			return FALSE;
+			return;
+		case GNOME_VFS_XFER_OVERWRITE_ACTION_MERGE:
+			*merge = TRUE;
+			return;
+		case GNOME_VFS_XFER_OVERWRITE_ACTION_MERGE_ALL:
+			*merge = TRUE;
+			*overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_MERGE;
+			return
+			;
 		}
 	}
-
-	*replace = FALSE;
-	*skip = FALSE;
-	return FALSE;
+	return;
 }
 
 static GnomeVFSResult
@@ -875,6 +878,7 @@
 	     target_item != NULL;) {
 		gboolean replace;
 		gboolean skip;
+		gboolean merge;
 		gboolean is_move_to_self;
 		GnomeVFSURI *uri, *source_uri;
 		GnomeVFSFileInfo *info;
@@ -888,19 +892,25 @@
 			progress_set_source_target_uris (progress, source_uri, uri);
 			 
 			/* no error getting info -- file exists, ask what to do */
-			replace = handle_overwrite (&result, progress, error_mode,
-				overwrite_mode, &replace, &skip);
+			handle_overwrite (&result, progress, error_mode,
+				overwrite_mode, &replace, &skip, &merge);
 
 			/* FIXME bugzilla.eazel.com 1207:
 			 * move items to Trash here
 			 */
+			 
+                	/* FIXME: it seems, that removing conflicting files 
+			here is duplicated functionality, since conflicting
+			file already removed in create_directory and 
+			xfer_create_target functions. Probably, the more clean 
+			code needed? i.e. any removing should be in one place */
 
 			/* get rid of the conflicting file */
-			if (replace) {
+			if (replace || merge) {
 				info = gnome_vfs_file_info_new ();
 				gnome_vfs_get_file_info_uri (uri, info, GNOME_VFS_FILE_INFO_DEFAULT);
 				progress_set_source_target_uris (progress, uri, NULL);
-				if (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
+				if (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY && replace) {
 					if (move_source_is_in_target (source_uri, uri)) {
 						/* Would like a better error here */
 						result = GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY;
@@ -966,32 +976,40 @@
 {
 	GnomeVFSResult result;
 	gboolean retry;
+	gboolean merge, skip_override, replace;
 	
 	*skip = FALSE;
 	do {
+         	replace = FALSE;
 		retry = FALSE;
-
+		
 		result = gnome_vfs_make_directory_for_uri (dir_uri, 0777);
 
 		if (result == GNOME_VFS_ERROR_FILE_EXISTS) {
-			gboolean force_replace;
 
 			if ((xfer_options & GNOME_VFS_XFER_USE_UNIQUE_NAMES) != 0) {
 				/* just let the caller pass a unique name*/
 				return result;
 			}
 
-			retry = handle_overwrite (&result,
+			         handle_overwrite (&result,
 						  progress,
 						  error_mode,
 						  overwrite_mode,
-						  &force_replace,
-						  skip);
+						  &replace,
+						  &skip_override, &merge);
 
-			if (*skip) {
+			if (skip_override) {
+			        *skip = TRUE;
 				return GNOME_VFS_OK;
 			}
-			if (force_replace) {
+		        if (merge) {
+		  	        return 
+				gnome_vfs_directory_open_from_uri (return_handle, 
+    								   dir_uri, 
+								   GNOME_VFS_FILE_INFO_DEFAULT);
+			}
+			if (replace) {
 				result = remove_directory (dir_uri, TRUE, progress, 
 							   xfer_options, error_mode, 
 							   skip);
@@ -1013,7 +1031,7 @@
 			return GNOME_VFS_OK;
 		}
 
-	} while (retry);
+	} while (retry || replace);
 
 	return result;
 }
@@ -1158,37 +1176,42 @@
 		    gboolean *skip)
 {
 	GnomeVFSResult result;
-	gboolean retry;
 	gboolean exclusive;
+	gboolean retry;
+	gboolean merge, replace, skip_override;
 
-	exclusive = (*overwrite_mode != GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE);
 
-	*skip = FALSE;
+	exclusive = (*overwrite_mode != GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE
+	&& *overwrite_mode != GNOME_VFS_XFER_OVERWRITE_MODE_MERGE);
+
 	do {
-		retry = FALSE;
+              retry = FALSE;
+   	      replace = FALSE;
+     	      merge = FALSE;
 
 		result = gnome_vfs_create_uri (target_handle, target_uri,
 					       GNOME_VFS_OPEN_WRITE,
 					       exclusive, 0666);
 
 		if (result == GNOME_VFS_ERROR_FILE_EXISTS) {
-			gboolean replace;
 
-			retry = handle_overwrite (&result,
+			         handle_overwrite (&result,
 						  progress,
 						  error_mode,
 						  overwrite_mode,
 						  &replace,
-						  skip);
+						  &skip_override, &merge);
+						  
+			*skip =  skip_override;
 
-			if (replace) {
+			if (replace || merge) {
 				exclusive = FALSE;
 			}
 
 		} else if (result != GNOME_VFS_OK) {
 			retry = handle_error (&result,  progress, error_mode, skip);
 		}
-	} while (retry);
+	} while (replace || retry || merge);
 
 	return result;
 }
@@ -1520,7 +1543,6 @@
 		if (result == GNOME_VFS_OK) {
 			/* optionally keep trying until we hit a unique target name */
 			for (count = 1; ; count++) {
-				GnomeVFSXferOverwriteMode overwrite_mode_abort;
 
 				target_uri = gnome_vfs_uri_append_string
 					(target_dir_uri, 
@@ -1536,18 +1558,16 @@
 					result = GNOME_VFS_ERROR_INTERRUPTED;
 				}
 
-				overwrite_mode_abort = GNOME_VFS_XFER_OVERWRITE_MODE_ABORT;
-				
 				
 				if (info->type == GNOME_VFS_FILE_TYPE_REGULAR) {
 					result = copy_file (info, source_uri, target_uri, 
 							    xfer_options, error_mode, 
-							    &overwrite_mode_abort, 
+							    &overwrite_mode, 
 							    progress, &skip);
 				} else if (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
 					result = copy_directory (info, source_uri, target_uri, 
 								 xfer_options, error_mode,
-								 &overwrite_mode_abort,
+								 &overwrite_mode,
 								 progress, &skip);
                                 } else if (info->type == GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK) {
 					result = copy_symlink (source_uri, target_uri, info->symlink_name,
Index: libgnomevfs/gnome-vfs-xfer.h
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-xfer.h,v
retrieving revision 1.13
diff -u -r1.13 gnome-vfs-xfer.h
--- libgnomevfs/gnome-vfs-xfer.h	1 Aug 2003 09:06:05 -0000	1.13
+++ libgnomevfs/gnome-vfs-xfer.h	10 Apr 2004 12:37:39 -0000
@@ -68,7 +68,9 @@
 	/* Overwrite files silently.  */
 	GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE = 2,
 	/* Ignore files silently.  */
-	GNOME_VFS_XFER_OVERWRITE_MODE_SKIP = 3
+	GNOME_VFS_XFER_OVERWRITE_MODE_SKIP = 3,
+	/* Replace dirs when have the same name*/
+	GNOME_VFS_XFER_OVERWRITE_MODE_MERGE = 4
 } GnomeVFSXferOverwriteMode;
 
 /**
@@ -80,6 +82,10 @@
  * @GNOME_VFS_XFER_OVERWRITE_ACTION_SKIP: don't copy over the existing file
  * @GNOME_VFS_XFER_OVERWRITE_ACTION_SKIP_ALL: don't copy over the existing file, and all future
  * files without prompting the callback.
+ * @GNOME_VFS_XFER_OVERWRITE_ACTION_MERGE: merge the source file or dir with the 
+ * distination file or dir
+ * @GNOME_VFS_XFER_OVERWRITE_ACTION_MERGE_ALL: merge the source file or dir with 
+ * the distination file or dir, and all future files without prompting the callback.
  * 
  * This defines the actions to perform before a file is being overwritten
  * (i.e., these are the answers that can be given to a replace query).  
@@ -89,7 +95,9 @@
 	GNOME_VFS_XFER_OVERWRITE_ACTION_REPLACE = 1,
 	GNOME_VFS_XFER_OVERWRITE_ACTION_REPLACE_ALL = 2,
 	GNOME_VFS_XFER_OVERWRITE_ACTION_SKIP = 3,
-	GNOME_VFS_XFER_OVERWRITE_ACTION_SKIP_ALL = 4
+	GNOME_VFS_XFER_OVERWRITE_ACTION_SKIP_ALL = 4,
+	GNOME_VFS_XFER_OVERWRITE_ACTION_MERGE = 5,
+	GNOME_VFS_XFER_OVERWRITE_ACTION_MERGE_ALL = 6
 } GnomeVFSXferOverwriteAction;
 
 typedef enum {
Index: test/test-xfer.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/test/test-xfer.c,v
retrieving revision 1.10
diff -u -r1.10 test-xfer.c
--- test/test-xfer.c	29 Oct 2002 10:37:23 -0000	1.10
+++ test/test-xfer.c	10 Apr 2004 12:37:40 -0000
@@ -31,6 +31,7 @@
 
 static int recursive = 0;
 static int replace = 0;
+static int merge = 0;
 static int remove_source = 0;
 static int follow_symlinks = 0;
 static int follow_symlinks_recursive = 0;
@@ -74,6 +75,15 @@
 		NULL
 	},
 	{
+		"merge",
+		'M',
+		POPT_ARG_NONE,
+		&merge,
+		0,
+		"Merge files automatically",
+		NULL
+	},
+	{
 		"delete-source",
 		'd',
 		POPT_ARG_NONE,
@@ -232,6 +242,10 @@
 	if (replace) {
 		fprintf (stderr, "Warning: Using replace overwrite mode.\n");
 		overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE;
+	}
+	if (merge) {
+		fprintf (stderr, "Warning: Using merge overwrite mode.\n");
+		overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_MERGE;
 	}
 	if (remove_source) {
 		fprintf (stderr, "Warning: Removing source files.\n");
