Support moving messages across named queues. Bug 2456
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 24 Oct 2019 22:34:19 +0000 (23:34 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 24 Oct 2019 23:55:45 +0000 (00:55 +0100)
13 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/src/exim.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/macros.h
src/src/queue.c
src/src/spool_out.c
test/log/0576
test/runtest
test/scripts/0000-Basic/0576
test/stdout/0576

index 4fa87ff..7cd3e86 100644 (file)
@@ -3963,6 +3963,20 @@ is sent to the sender, containing the text &"cancelled by administrator"&.
 Bounce messages are just discarded. This option can be used only by an admin
 user.
 
+.new
+.vitem &%-MG%&&~<&'queue&~name'&&~<&'message&~id'&>&~<&'message&~id'&>&~...
+.oindex "&%-MG%&"
+.cindex queue named
+.cindex "named queues"
+.cindex "queue" "moving messages"
+This option requests that each listed message be moved from its current
+queue to the given named queue.
+The destination queue name argument is required, but can be an empty
+string to define the default queue.
+If the messages are not currently located in the default queue,
+a &%-qG<name>%& option will be required to define the source queue.
+.wen
+
 .vitem &%-Mmad%&&~<&'message&~id'&>&~<&'message&~id'&>&~...
 .oindex "&%-Mmad%&"
 .cindex "delivery" "cancelling all"
index 7317696..5d0c8bd 100644 (file)
@@ -48,6 +48,8 @@ Version 4.93
     GnuTLS was already there, being done purely by the library (server side
     only, and exim must be run as root).
 
+16: Command-line option to move messages from one named queue to another.
+
 
 Version 4.92
 --------------
index 2b6297b..3290d63 100644 (file)
@@ -2787,6 +2787,11 @@ for (i = 1; i < argc; i++)
       msg_action = MSG_DELIVER;
       deliver_give_up = TRUE;
       }
+   else if (Ustrcmp(argrest, "G") == 0)
+      {
+      msg_action = MSG_SETQUEUE;
+      queue_name_dest = argv[++i];
+      }
     else if (Ustrcmp(argrest, "mad") == 0)
       {
       msg_action = MSG_MARK_ALL_DELIVERED;
@@ -4064,11 +4069,13 @@ count. Only an admin user can use the test interface to scan for email
 if (!f.admin_user)
   {
   BOOL debugset = (debug_selector & ~D_v) != 0;
-  if (deliver_give_up || f.daemon_listen || malware_test_file ||
-     (count_queue && queue_list_requires_admin) ||
-     (list_queue && queue_list_requires_admin) ||
-     (queue_interval >= 0 && prod_requires_admin) ||
-     (debugset && !f.running_in_test_harness))
+  if (  deliver_give_up || f.daemon_listen || malware_test_file
+     || count_queue && queue_list_requires_admin
+     || list_queue && queue_list_requires_admin
+     || queue_interval >= 0 && prod_requires_admin
+     || queue_name_dest && prod_requires_admin
+     || debugset && !f.running_in_test_harness
+     )
     exim_fail("exim:%s permission denied\n", debugset? " debugging" : "");
   }
 
@@ -4165,13 +4172,9 @@ now for those OS that require the first call to os_getloadavg() to be done as
 root. There will be further calls later for each message received. */
 
 #ifdef LOAD_AVG_NEEDS_ROOT
-if (receiving_message &&
-      (queue_only_load >= 0 ||
-        (f.is_inetd && smtp_load_reserve >= 0)
-      ))
-  {
+if (  receiving_message
+   && (queue_only_load >= 0 || (f.is_inetd && smtp_load_reserve >= 0)))
   load_average = OS_GETLOADAVG();
-  }
 #endif
 
 /* The queue_only configuration option can be overridden by -odx on the command
index 8905d02..3b3a12b 100644 (file)
@@ -878,20 +878,33 @@ return string_sprintf("%s/%s/%s/%s",
 # endif
 
 static inline uschar *
-spool_sname(const uschar * purpose, uschar * subdir)
+spool_q_sname(const uschar * purpose, const uschar * q, uschar * subdir)
 {
 return string_sprintf("%s%s%s%s%s",
-                   queue_name, *queue_name ? "/" : "",
+                   q, *q ? "/" : "",
                    purpose,
                    *subdir ? "/" : "", subdir);
 }
 
 static inline uschar *
+spool_sname(const uschar * purpose, uschar * subdir)
+{
+return spool_q_sname(purpose, queue_name, subdir);
+}
+
+static inline uschar *
+spool_q_fname(const uschar * purpose, const uschar * q,
+       const uschar * subdir, const uschar * fname, const uschar * suffix)
+{
+return string_sprintf("%s/%s/%s/%s/%s%s",
+       spool_directory, q, purpose, subdir, fname, suffix);
+}
+
+static inline uschar *
 spool_fname(const uschar * purpose, const uschar * subdir, const uschar * fname,
                const uschar * suffix)
 {
-return string_sprintf("%s/%s/%s/%s/%s%s",
-       spool_directory, queue_name, purpose, subdir, fname, suffix);
+return spool_q_fname(purpose, queue_name, subdir, fname, suffix);
 }
 
 static inline void
index 677c03e..07665bf 100644 (file)
@@ -1194,6 +1194,7 @@ uschar *qualify_domain_sender  = NULL;
 uschar *queue_domains          = NULL;
 int     queue_interval         = -1;
 uschar *queue_name             = US"";
+uschar *queue_name_dest        = NULL;
 uschar *queue_only_file        = NULL;
 int     queue_only_load        = -1;
 uschar *queue_run_max          = US"5";
index e4725a7..0466da5 100644 (file)
@@ -787,6 +787,7 @@ extern pid_t   queue_run_pid;          /* PID of the queue running process or 0
 extern int     queue_run_pipe;         /* Pipe for synchronizing */
 extern int     queue_interval;         /* Queue running interval */
 extern uschar *queue_name;             /* Name of queue, if nondefault spooling */
+extern uschar *queue_name_dest;               /* Destination queue, for moving messages */
 extern BOOL    queue_only;             /* TRUE to disable immediate delivery */
 extern int     queue_only_load;        /* Max load before auto-queue */
 extern BOOL    queue_only_load_latch;  /* Latch queue_only_load TRUE */
index e36c09c..76913d6 100644 (file)
@@ -845,7 +845,7 @@ enum {
 
 enum { MSG_DELIVER, MSG_FREEZE, MSG_REMOVE, MSG_THAW, MSG_ADD_RECIPIENT,
        MSG_MARK_ALL_DELIVERED, MSG_MARK_DELIVERED, MSG_EDIT_SENDER,
-       MSG_SHOW_COPY, MSG_LOAD,
+       MSG_SHOW_COPY, MSG_LOAD, MSG_SETQUEUE,
        /* These ones must be last: a test for >= MSG_SHOW_BODY is used
        to test for actions that list individual spool files. */
        MSG_SHOW_BODY, MSG_SHOW_HEADER, MSG_SHOW_LOG };
index 670f51c..d9ff133 100644 (file)
@@ -1265,6 +1265,14 @@ switch(action)
     }
 
 
+  case MSG_SETQUEUE:
+    /* The global "queue_name_dest" is used as destination, "queue_name"
+    as source */
+
+    spool_move_message(id, message_subdir, US"", US"");
+    break;
+
+
   case MSG_MARK_ALL_DELIVERED:
   for (int i = 0; i < recipients_count; i++)
     tree_add_nonrecipient(recipients_list[i].address);
index acc6c7b..463961f 100644 (file)
@@ -417,6 +417,7 @@ start-up time.
 
 Arguments:
   dir        base directory name
+  dq        destiinationqueue name
   subdir     subdirectory name
   id         message id
   suffix     suffix to add to id
@@ -429,11 +430,11 @@ Returns:     TRUE if all went well
 */
 
 static BOOL
-make_link(uschar *dir, uschar *subdir, uschar *id, uschar *suffix, uschar *from,
-  uschar *to, BOOL noentok)
+make_link(uschar *dir, uschar * dq, uschar *subdir, uschar *id, uschar *suffix,
+  uschar *from, uschar *to, BOOL noentok)
 {
 uschar * fname = spool_fname(string_sprintf("%s%s", from, dir), subdir, id, suffix);
-uschar * tname = spool_fname(string_sprintf("%s%s", to,   dir), subdir, id, suffix);
+uschar * tname = spool_q_fname(string_sprintf("%s%s", to,   dir), dq, subdir, id, suffix);
 if (Ulink(fname, tname) < 0 && (!noentok || errno != ENOENT))
   {
   log_write(0, LOG_MAIN|LOG_PANIC, "link(\"%s\", \"%s\") failed while moving "
@@ -503,13 +504,15 @@ Returns:      TRUE if all is well
 BOOL
 spool_move_message(uschar *id, uschar *subdir, uschar *from, uschar *to)
 {
+uschar * dest_qname = queue_name_dest ? queue_name_dest : queue_name;
+
 /* Create any output directories that do not exist. */
 
 (void) directory_make(spool_directory,
-  spool_sname(string_sprintf("%sinput", to), subdir),
+  spool_q_sname(string_sprintf("%sinput", to), dest_qname, subdir),
   INPUT_DIRECTORY_MODE, TRUE);
 (void) directory_make(spool_directory,
-  spool_sname(string_sprintf("%smsglog", to), subdir),
+  spool_q_sname(string_sprintf("%smsglog", to), dest_qname, subdir),
   INPUT_DIRECTORY_MODE, TRUE);
 
 /* Move the message by first creating new hard links for all the files, and
@@ -521,9 +524,9 @@ rule of waiting for a -H file before doing anything. When moving messages off
 the mail spool, the -D file should be open and locked at the time, thus keeping
 Exim's hands off. */
 
-if (!make_link(US"msglog", subdir, id, US"", from, to, TRUE) ||
-    !make_link(US"input",  subdir, id, US"-D", from, to, FALSE) ||
-    !make_link(US"input",  subdir, id, US"-H", from, to, FALSE))
+if (!make_link(US"msglog", dest_qname, subdir, id, US"", from, to, TRUE) ||
+    !make_link(US"input",  dest_qname, subdir, id, US"-D", from, to, FALSE) ||
+    !make_link(US"input",  dest_qname, subdir, id, US"-H", from, to, FALSE))
   return FALSE;
 
 if (!break_link(US"input",  subdir, id, US"-H", from, FALSE) ||
@@ -531,8 +534,11 @@ if (!break_link(US"input",  subdir, id, US"-H", from, FALSE) ||
     !break_link(US"msglog", subdir, id, US"", from, TRUE))
   return FALSE;
 
-log_write(0, LOG_MAIN, "moved from %sinput, %smsglog to %sinput, %smsglog",
-   from, from, to, to);
+log_write(0, LOG_MAIN, "moved from %s%s%s%sinput, %smsglog to %s%s%s%sinput, %smsglog",
+   *queue_name?"(":"", *queue_name?queue_name:US"", *queue_name?") ":"",
+   from, from,
+   *dest_qname?"(":"", *dest_qname?dest_qname:US"", *dest_qname?") ":"",
+   to, to);
 
 return TRUE;
 }
index 8c1cb73..246b105 100644 (file)
 1999-03-02 09:44:33 10HmbA-0005vi-00 => alternate <alternate@test.ex> F=<CALLER@the.local.host.name> R=all T=dump
 1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
 1999-03-02 09:44:33 End queue run: pid=pppp
+1999-03-02 09:44:33 using queue ''
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local-smtp S=sss for normal@test.ex
+1999-03-02 09:44:33 using queue 'alternate'
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local-smtp S=sss Q=alternate for alternate@test.ex
+1999-03-02 09:44:33 10HmbB-0005vi-00 moved from input, msglog to (third) input, msglog
+1999-03-02 09:44:33 10HmbC-0005vi-00 moved from (alternate) input, msglog to (third) input, msglog
+1999-03-02 09:44:33 10HmbB-0005vi-00 moved from (third) input, msglog to input, msglog
+1999-03-02 09:44:33 10HmbC-0005vi-00 moved from (third) input, msglog to input, msglog
 
 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, -qGlowpri/3s, not listening for SMTP
index 0d6bcd1..db855ba 100755 (executable)
@@ -2546,9 +2546,24 @@ elsif (/^((?i:[A-Z\d_]+=\S+\s+)+)?(\d+)?\s*(sudo(?:\s+-u\s+(\w+))?\s+)?exim(_\S+
 
   if ($args =~ /\$msg/)
     {
-    my @listcmd  = ("$parm_cwd/eximdir/exim", '-bp',
+    my($queuespec);
+    if ($args =~ /-qG\w+/) { $queuespec = $&; }
+
+    my @listcmd;
+
+    if (defined $queuespec)
+      {
+      @listcmd  = ("$parm_cwd/eximdir/exim", '-bp',
+                  $queuespec,
                    "-DEXIM_PATH=$parm_cwd/eximdir/exim",
                    -C => "$parm_cwd/test-config");
+      }
+    else
+      {
+      @listcmd  = ("$parm_cwd/eximdir/exim", '-bp',
+                   "-DEXIM_PATH=$parm_cwd/eximdir/exim",
+                   -C => "$parm_cwd/test-config");
+      }
     print ">> Getting queue list from:\n>>    @listcmd\n" if $debug;
     # We need the message ids sorted in ascending order.
     # Message id is: <timestamp>-<pid>-<fractional-time>. On some systems (*BSD) the
index dedc73d..becd160 100644 (file)
@@ -72,4 +72,44 @@ sudo mv DIR/spool/alternate/input/* DIR/spool/input/
 exim -q
 ****
 #
+#
+# Native queue transfer
+exim -bs
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO: <normal@test.ex>
+DATA
+Subject: test
+
+foo
+.
+RSET
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO: <alternate@test.ex>
+DATA
+Subject: test
+
+foo
+.
+QUIT
+****
+exim -bp
+****
+exim -bp -qGalternate
+****
+#
+exim -MG third $msg1
+****
+exim -qGalternate -MG third $msg1
+****
+exim -bp -qGthird
+****
+exim -qGthird -MG '' $msg1 $msg2
+****
+exim -bp
+****
+exim -bp -qGalternate
+****
+exim -bp -qGthird
+****
+#
 no_stderr_check
index a15ecdd..91c57a2 100644 (file)
 354 Enter message, ending with "." on a line by itself\r
 250 OK id=10HmbA-0005vi-00\r
 221 the.local.host.name closing connection\r
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmbB-0005vi-00\r
+250 Reset OK\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmbC-0005vi-00\r
+221 the.local.host.name closing connection\r
+ 0m   sss 10HmbB-0005vi-00 <CALLER@the.local.host.name>
+          normal@test.ex
+
+ 0m   sss 10HmbC-0005vi-00 <CALLER@the.local.host.name>
+          alternate@test.ex
+
+Message 10HmbB-0005vi-00 Message 10HmbC-0005vi-00  0m   323 10HmbB-0005vi-00 <CALLER@the.local.host.name>
+          normal@test.ex
+
+ 0m   sss 10HmbC-0005vi-00 <CALLER@the.local.host.name>
+          alternate@test.ex
+
+Message 10HmbB-0005vi-00 Message 10HmbC-0005vi-00  0m   323 10HmbB-0005vi-00 <CALLER@the.local.host.name>
+          normal@test.ex
+
+ 0m   sss 10HmbC-0005vi-00 <CALLER@the.local.host.name>
+          alternate@test.ex
+
 
 ******** SERVER ********
 ### default q