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 4fa87ff9efe240f84b696d84021460788b96bdff..7cd3e86213e3ecf3251aefe14638dd607b27f4e0 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.
 
 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"
 .vitem &%-Mmad%&&~<&'message&~id'&>&~<&'message&~id'&>&~...
 .oindex "&%-Mmad%&"
 .cindex "delivery" "cancelling all"
index 731769629c2027890f0e06d3bb19b02ef00010b0..5d0c8bd31e732ecf3bce0b7420ebd5596aa43880 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).
 
     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
 --------------
 
 Version 4.92
 --------------
index 2b6297bf5d73524fbc6ac0945e33797134c50b2e..3290d63465b334be55a151c2fbc8737aa3d8287c 100644 (file)
@@ -2787,6 +2787,11 @@ for (i = 1; i < argc; i++)
       msg_action = MSG_DELIVER;
       deliver_give_up = TRUE;
       }
       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;
     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 (!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" : "");
   }
 
     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
 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();
   load_average = OS_GETLOADAVG();
-  }
 #endif
 
 /* The queue_only configuration option can be overridden by -odx on the command
 #endif
 
 /* The queue_only configuration option can be overridden by -odx on the command
index 8905d02a2537578987f6a1a9f2ecbb3598012a88..3b3a12b18c2fbf1cfbcde79622f04b874209ab12 100644 (file)
@@ -878,20 +878,33 @@ return string_sprintf("%s/%s/%s/%s",
 # endif
 
 static inline uschar *
 # 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",
 {
 return string_sprintf("%s%s%s%s%s",
-                   queue_name, *queue_name ? "/" : "",
+                   q, *q ? "/" : "",
                    purpose,
                    *subdir ? "/" : "", subdir);
 }
 
                    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)
 {
 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
 }
 
 static inline void
index 677c03e77074a12831539d54db65149684490870..07665bf756b0ba9455284e7be61ce8a6f3051f4c 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_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";
 uschar *queue_only_file        = NULL;
 int     queue_only_load        = -1;
 uschar *queue_run_max          = US"5";
index e4725a7195e10fb7484ac14a7ff436ccf12105f0..0466da5001c18900d23f019bf535b292f0c26ec7 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 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 */
 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 e36c09c475ef97091b858eb02c982f026a805af6..76913d64ed37c8f62f95e581dd224ad650172232 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,
 
 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 };
        /* 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 670f51c45296926f506238dbdfffbefb333dd208..d9ff133759cf8e326947d38c1c8dca342009d910 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);
   case MSG_MARK_ALL_DELIVERED:
   for (int i = 0; i < recipients_count; i++)
     tree_add_nonrecipient(recipients_list[i].address);
index acc6c7b5f8ad08580df9cb61e18e7ec23cf37cc3..463961f57e270dd726a7b5f03dcd3d9b48692fd0 100644 (file)
@@ -417,6 +417,7 @@ start-up time.
 
 Arguments:
   dir        base directory name
 
 Arguments:
   dir        base directory name
+  dq        destiinationqueue name
   subdir     subdirectory name
   id         message id
   suffix     suffix to add to id
   subdir     subdirectory name
   id         message id
   suffix     suffix to add to id
@@ -429,11 +430,11 @@ Returns:     TRUE if all went well
 */
 
 static BOOL
 */
 
 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 * 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 "
 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)
 {
 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,
 /* 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,
   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
   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. */
 
 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) ||
   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;
 
     !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;
 }
 
 return TRUE;
 }
index 8c1cb73dfd0a81fee40c255079f9cfe35656cd27..246b105781f5915b905612fb2602f429feec4963 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 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
 
 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, -qGlowpri/3s, not listening for SMTP
index 0d6bcd1d769a98ff0c34c46d386c3ebcdb1e32e9..db855baf9e6271cc502c3c21a194916262974be5 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/)
     {
 
   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");
                    "-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
     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 dedc73d2337fd89100ad6ce13b3890b635a45603..becd160569d16f3b024bffdbe47c6d0ee7dea3e8 100644 (file)
@@ -72,4 +72,44 @@ sudo mv DIR/spool/alternate/input/* DIR/spool/input/
 exim -q
 ****
 #
 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
 no_stderr_check
index a15ecdd5dd3a2d31a4fa3f7c8da979ec9b0a936c..91c57a20d989ad8982b5d2eda4d05bf9d0f3f62b 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
 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
 
 ******** SERVER ********
 ### default q