After applying this patch and running configure, you MUST run this
command before "make":

    make proto


--- orig/generator.c	2005-02-20 00:02:23
+++ generator.c	2005-02-15 21:33:51
@@ -42,6 +42,7 @@ extern int preserve_gid;
 extern int preserve_times;
 extern int omit_dir_times;
 extern int delete_during;
+extern int remove_sent_files;
 extern int update_only;
 extern int opt_ignore_existing;
 extern int inplace;
@@ -559,6 +560,11 @@ static void recv_generator(char *fname, 
 				rprintf(code, "%s -> %s\n", safe_fname(fname),
 					safe_fname(file->u.link));
 			}
+			if (remove_sent_files && !dry_run) {
+				char numbuf[4];
+				SIVAL(numbuf, 0, ndx);
+				io_multiplex_write(MSG_SUCCESS, numbuf, 4);
+			}
 		}
 #endif
 		return;
--- orig/io.c	2005-02-19 09:27:48
+++ io.c	2005-02-15 21:33:51
@@ -256,6 +256,14 @@ static void read_msg_fd(void)
 		read_loop(fd, buf, len);
 		io_multiplex_write(MSG_DELETED, buf, len);
 		break;
+	case MSG_SUCCESS:
+		if (len != 4 || !am_generator) {
+			rprintf(FERROR, "invalid message %d:%d\n", tag, len);
+			exit_cleanup(RERR_STREAMIO);
+		}
+		read_loop(fd, buf, len);
+		io_multiplex_write(MSG_SUCCESS, buf, len);
+		break;
 	case MSG_INFO:
 	case MSG_ERROR:
 	case MSG_LOG:
@@ -704,6 +712,16 @@ static int readfd_unbuffered(int fd, cha
 				log_delete(line, S_IFREG);
 			remaining = 0;
 			break;
+		case MSG_SUCCESS:
+			if (remaining != 4) {
+				rprintf(FERROR, "invalid multi-message %d:%ld\n",
+					tag, (long)remaining);
+				exit_cleanup(RERR_STREAMIO);
+			}
+			read_loop(fd, line, remaining);
+			successful_send(IVAL(line, 0));
+			remaining = 0;
+			break;
 		case MSG_INFO:
 		case MSG_ERROR:
 			if (remaining >= sizeof line) {
--- orig/main.c	2005-02-20 00:02:23
+++ main.c	2005-02-20 00:09:59
@@ -33,7 +33,9 @@ extern int am_generator;
 extern int am_daemon;
 extern int blocking_io;
 extern int delete_before;
+extern int remove_sent_files;
 extern int daemon_over_rsh;
+extern int need_messages_from_generator;
 extern int do_stats;
 extern int log_got_error;
 extern int module_id;
@@ -441,6 +443,12 @@ static void do_server_sender(int f_in, i
 		exit_cleanup(RERR_SYNTAX);
 		return;
 	}
+	if (am_daemon && lp_read_only(module_id) && remove_sent_files) {
+		rprintf(FERROR,
+		    "ERROR: --remove-sent-files cannot be used with a read-only module\n");
+		exit_cleanup(RERR_SYNTAX);
+		return;
+	}
 
 	if (!relative_paths && !push_dir(dir)) {
 		rsyserr(FERROR, errno, "push_dir#3 %s failed",
@@ -672,6 +680,8 @@ void start_server(int f_in, int f_out, i
 
 	if (am_sender) {
 		keep_dirlinks = 0; /* Must be disabled on the sender. */
+		if (need_messages_from_generator)
+			io_start_multiplex_in();
 
 		recv_filter_list(f_in);
 		do_server_sender(f_in, f_out, argc, argv);
@@ -749,6 +759,9 @@ int client_run(int f_in, int f_out, pid_
 		exit_cleanup(status);
 	}
 
+	if (need_messages_from_generator && !read_batch)
+		io_start_multiplex_out();
+
 	if (argc == 0)
 		list_only |= 1;
 
--- orig/options.c	2005-02-20 00:02:23
+++ options.c	2005-02-15 21:33:52
@@ -59,6 +59,7 @@ int delete_during = 0;
 int delete_before = 0;
 int delete_after = 0;
 int delete_excluded = 0;
+int remove_sent_files = 0;
 int one_file_system = 0;
 int protocol_version = PROTOCOL_VERSION;
 int sparse_files = 0;
@@ -93,6 +94,7 @@ int fuzzy_basis = 0;
 size_t bwlimit_writemax = 0;
 int only_existing = 0;
 int opt_ignore_existing = 0;
+int need_messages_from_generator = 0;
 int max_delete = 0;
 OFF_T max_size = 0;
 int ignore_errors = 0;
@@ -288,6 +290,7 @@ void usage(enum logcode F)
   rprintf(F,"     --rsync-path=PATH       specify path to rsync on the remote machine\n");
   rprintf(F,"     --existing              only update files that already exist on receiver\n");
   rprintf(F,"     --ignore-existing       ignore files that already exist on receiving side\n");
+  rprintf(F,"     --remove-sent-files     sent files/symlinks are removed from sending side\n");
   rprintf(F,"     --del                   an alias for --delete-during\n");
   rprintf(F,"     --delete                delete files that don't exist on the sending side\n");
   rprintf(F,"     --delete-before         receiver deletes before transfer (default)\n");
@@ -371,6 +374,7 @@ static struct poptOption long_options[] 
   {"delete-during",    0,  POPT_ARG_NONE,   &delete_during, 0, 0, 0 },
   {"delete-after",     0,  POPT_ARG_NONE,   &delete_after, 0, 0, 0 },
   {"delete-excluded",  0,  POPT_ARG_NONE,   &delete_excluded, 0, 0, 0 },
+  {"remove-sent-files",0,  POPT_ARG_NONE,   &remove_sent_files, 0, 0, 0 },
   {"force",            0,  POPT_ARG_NONE,   &force_delete, 0, 0, 0 },
   {"numeric-ids",      0,  POPT_ARG_NONE,   &numeric_ids, 0, 0, 0 },
   {"filter",          'f', POPT_ARG_STRING, 0, OPT_FILTER, 0, 0 },
@@ -978,6 +982,17 @@ int parse_arguments(int *argc, const cha
 		return 0;
 	}
 
+	if (remove_sent_files) {
+		/* We only want to infer this refusal of --remove-sent-files
+		 * via the refusal of "delete", not any of the "delete-FOO"
+		 * options. */
+		if (refused_delete && am_sender) {
+			create_refuse_error(refused_delete);
+			return 0;
+		}
+		need_messages_from_generator = 1;
+	}
+
 	*argv = poptGetArgs(pc);
 	*argc = count_args(*argv);
 
@@ -1435,6 +1450,9 @@ void server_options(char **args,int *arg
 	if (fuzzy_basis && am_sender)
 		args[ac++] = "--fuzzy";
 
+	if (remove_sent_files)
+		args[ac++] = "--remove-sent-files";
+
 	*argc = ac;
 	return;
 
--- orig/receiver.c	2005-02-20 00:16:35
+++ receiver.c	2005-02-15 21:33:52
@@ -41,6 +41,7 @@ extern int io_error;
 extern int basis_dir_cnt;
 extern int make_backups;
 extern int cleanup_got_literal;
+extern int remove_sent_files;
 extern int module_id;
 extern int ignore_errors;
 extern int orig_umask;
@@ -312,7 +313,7 @@ int recv_files(int f_in, struct file_lis
 	char *fname, fbuf[MAXPATHLEN];
 	char template[MAXPATHLEN];
 	char fnametmp[MAXPATHLEN];
-	char *fnamecmp, *partialptr;
+	char *fnamecmp, *partialptr, numbuf[4];
 	char fnamecmpbuf[MAXPATHLEN];
 	uchar *delayed_bits = NULL;
 	struct file_struct *file;
@@ -595,7 +596,12 @@ int recv_files(int f_in, struct file_lis
 
 		cleanup_disable();
 
-		if (!recv_ok) {
+		if (recv_ok) {
+			if (remove_sent_files) {
+				SIVAL(numbuf, 0, i);
+				send_msg(MSG_SUCCESS, numbuf, 4);
+			}
+		} else {
 			int msgtype = csum_length == SUM_LENGTH || read_batch ?
 				FERROR : FINFO;
 			if (msgtype == FERROR || verbose) {
@@ -619,9 +625,8 @@ int recv_files(int f_in, struct file_lis
 					keptstr, redostr);
 			}
 			if (csum_length != SUM_LENGTH) {
-				char buf[4];
-				SIVAL(buf, 0, i);
-				send_msg(MSG_REDO, buf, 4);
+				SIVAL(numbuf, 0, i);
+				send_msg(MSG_REDO, numbuf, 4);
 			}
 		}
 	}
--- orig/rsync.yo	2005-02-19 09:27:49
+++ rsync.yo	2005-02-15 21:33:55
@@ -332,6 +332,7 @@ to the detailed description below for a 
      --rsync-path=PATH       specify path to rsync on the remote machine
      --existing              only update files that already exist
      --ignore-existing       ignore files that already exist on receiver
+     --remove-sent-files     sent files/symlinks are removed from sender
      --del                   an alias for --delete-during
      --delete                delete files that don't exist on sender
      --delete-before         receiver deletes before transfer (default)
@@ -674,6 +675,11 @@ dit(bf(--ignore-existing))
 This tells rsync not to update files that already exist on
 the destination.
 
+dit(bf(--remove-sent-files)) This tells rsync to remove from the sending
+side the files and/or symlinks that are newly created or whose content is
+updated on the receiving side.  Directories and devices are not removed,
+nor are files/symlinks whose attributes are merely changed.
+
 dit(bf(--delete)) This tells rsync to delete extraneous files from the
 receiving side (ones that aren't on the sending side), but only for the
 directories that are being synchronized.  You must have asked rsync to
--- orig/rsyncd.conf.yo	2005-02-20 00:02:23
+++ rsyncd.conf.yo	2005-02-15 21:33:55
@@ -459,6 +459,10 @@ quote(tt(    refuse options = c delete))
 
 The reason the above refuses all delete options is that the options imply
 bf(--delete), and implied options are refused just like explicit options.
+As an additional safety feature, the refusal of "delete" also refuses
+bf(remove-sent-files) when the daemon is the sender; if you want the latter
+without the former, instead refuse "delete-*" -- that refuses all the
+delete modes without affecting bf(--remove-sent-files).
 
 When an option is refused, the server prints an error message and exits.
 To prevent all compression, you can use "dont compress = *" (see below)
--- orig/sender.c	2005-02-20 00:16:35
+++ sender.c	2005-02-20 00:10:24
@@ -29,6 +29,7 @@ extern int daemon_log_format_has_i;
 extern int csum_length;
 extern int io_error;
 extern int protocol_version;
+extern int remove_sent_files;
 extern int updating_basis_file;
 extern int make_backups;
 extern int do_progress;
@@ -98,7 +99,32 @@ static struct sum_struct *receive_sums(i
 	return s;
 }
 
+static struct file_list *the_flist;
 
+void successful_send(int i)
+{
+	char fname[MAXPATHLEN];
+	struct file_struct *file;
+	unsigned int offset;
+
+	if (!the_flist || i < 0 || i >= the_flist->count)
+		return;
+
+	file = the_flist->files[i];
+	/* The generator might tell us about symlinks we didn't send. */
+	if (!(file->flags & FLAG_SENT) && !S_ISLNK(file->mode))
+		return;
+	if (file->dir.root) {
+		offset = stringjoin(fname, sizeof fname,
+				    file->dir.root, "/", NULL);
+	} else
+		offset = 0;
+	f_name_to(file, fname + offset);
+	if (remove_sent_files && do_unlink(fname) == 0 && verbose) {
+		rprintf(FINFO, "sender removed %s\n",
+			safe_fname(fname + offset));
+	}
+}
 
 void send_files(struct file_list *flist, int f_out, int f_in)
 {
@@ -119,6 +145,8 @@ void send_files(struct file_list *flist,
 	if (verbose > 2)
 		rprintf(FINFO, "send_files starting\n");
 
+	the_flist = flist;
+
 	while (1) {
 		unsigned int offset;
 
@@ -285,6 +313,9 @@ void send_files(struct file_list *flist,
 			rprintf(FINFO, "sender finished %s\n",
 				safe_fname(fname));
 		}
+
+		/* Flag that we actually sent this entry. */
+		file->flags |= FLAG_SENT;
 	}
 	make_backups = save_make_backups;
 
