Merge branch 'multiqueue_336': Named queues
[exim.git] / src / src / queue.c
index 5f7781c8e120b1e17f3897f6a94bc4160570b89f..f53759c43ee0e92bf1a6e346dd5d4cbea5cbec1e 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions that operate on the input queue. */
 
 
 
+/* Routines with knowlege of spool layout */
+
+static void
+spool_pname_buf(uschar * buf, int len)
+{
+snprintf(CS buf, len, "%s/%s/input", spool_directory, queue_name);
+}
+
+static uschar *
+spool_dname(const uschar * purpose, uschar * subdir)
+{
+return string_sprintf("%s/%s/%s/%s",
+       spool_directory, queue_name, purpose, subdir);
+}
+
+uschar *
+spool_sname(const uschar * purpose, uschar * subdir)
+{
+return string_sprintf("%s%s%s%s%s",
+                   queue_name, *queue_name ? "/" : "",
+                   purpose,
+                   *subdir ? "/" : "", subdir);
+}
+
+uschar *
+spool_fname(const uschar * purpose, uschar * subdir, uschar * fname, uschar * suffix)
+{
+return string_sprintf("%s/%s/%s/%s/%s%s",
+       spool_directory, queue_name, purpose, subdir, fname, suffix);
+}
+
+
+
+
+#ifndef COMPILE_UTILITY
+
 /* The number of nodes to use for the bottom-up merge sort when a list of queue
 items is to be ordered. The code for this sort was contributed as a patch by
 Michael Haardt. */
@@ -142,7 +178,8 @@ else i = subdiroffset;
 
 /* Set up prototype for the directory name. */
 
-sprintf(CS buffer, "%s/input", spool_directory);
+spool_pname_buf(buffer, sizeof(buffer));
+buffer[sizeof(buffer) - 3] = 0;
 subptr = Ustrlen(buffer);
 buffer[subptr+2] = 0;               /* terminator for lengthened name */
 
@@ -161,8 +198,9 @@ for (; i <= *subcount; i++)
     buffer[subptr+1] = subdirchar;
     }
 
-  dd = opendir(CS buffer);
-  if (dd == NULL) continue;
+  DEBUG(D_queue_run) debug_printf("looking in %s\n", buffer);
+  if (!(dd = opendir(CS buffer)))
+    continue;
 
   /* Now scan the directory. */
 
@@ -264,9 +302,11 @@ for (; i <= *subcount; i++)
     {
     if (!split_spool_directory && count <= 2)
       {
+      uschar subdir[2];
+
       rmdir(CS buffer);
-      sprintf(CS big_buffer, "%s/msglog/%c", spool_directory, subdirchar);
-      rmdir(CS big_buffer);
+      subdir[0] = subdirchar; subdir[1] = 0;
+      rmdir(CS spool_dname(US"msglog", subdir));
       }
     if (subdiroffset > 0) break;    /* Single sub-directory */
     }
@@ -389,7 +429,11 @@ if (!recurse)
     }
 
   log_detail = string_copy(big_buffer);
-  log_write(L_queue_run, LOG_MAIN, "Start queue run: %s", log_detail);
+  if (*queue_name)
+    log_write(L_queue_run, LOG_MAIN, "Start '%s' queue run: %s",
+      queue_name, log_detail);
+  else
+    log_write(L_queue_run, LOG_MAIN, "Start queue run: %s", log_detail);
   }
 
 /* If deliver_selectstring is a regex, compile it. */
@@ -476,9 +520,8 @@ for (i  = (queue_run_in_order? -1 : 0);
     /* Check that the message still exists */
 
     message_subdir[0] = f->dir_uschar;
-    sprintf(CS buffer, "%s/input/%s/%s", spool_directory, message_subdir,
-      f->text);
-    if (Ustat(buffer, &statbuf) < 0) continue;
+    if (Ustat(spool_fname(US"input", message_subdir, f->text, US""), &statbuf) < 0)
+      continue;
 
     /* There are some tests that require the reading of the header file. Ensure
     the store used is scavenged afterwards so that this process doesn't keep
@@ -698,7 +741,12 @@ if (queue_2stage)
 
 /* At top level, log the end of the run. */
 
-if (!recurse) log_write(L_queue_run, LOG_MAIN, "End queue run: %s", log_detail);
+if (!recurse)
+  if (*queue_name)
+    log_write(L_queue_run, LOG_MAIN, "End '%s' queue run: %s",
+      queue_name, log_detail);
+  else
+    log_write(L_queue_run, LOG_MAIN, "End queue run: %s", log_detail);
 }
 
 
@@ -841,17 +889,16 @@ for (; f != NULL; f = f->next)
     int ptr;
     FILE *jread;
     struct stat statbuf;
+    uschar * fname = spool_fname(US"input", message_subdir, f->text, US"");
 
-    sprintf(CS big_buffer, "%s/input/%s/%s", spool_directory, message_subdir,
-      f->text);
-    ptr = Ustrlen(big_buffer)-1;
-    big_buffer[ptr] = 'D';
+    ptr = Ustrlen(fname)-1;
+    fname[ptr] = 'D';
 
     /* Add the data size to the header size; don't count the file name
     at the start of the data file, but add one for the notional blank line
     that precedes the data. */
 
-    if (Ustat(big_buffer, &statbuf) == 0)
+    if (Ustat(fname, &statbuf) == 0)
       size = message_size + statbuf.st_size - SPOOL_DATA_START_OFFSET + 1;
     i = (now - received_time)/60;  /* minutes on queue */
     if (i > 90)
@@ -863,8 +910,8 @@ for (; f != NULL; f = f->next)
 
     /* Collect delivered addresses from any J file */
 
-    big_buffer[ptr] = 'J';
-    jread = Ufopen(big_buffer, "rb");
+    fname[ptr] = 'J';
+    jread = Ufopen(fname, "rb");
     if (jread != NULL)
       {
       while (Ufgets(big_buffer, big_buffer_size, jread) != NULL)
@@ -892,9 +939,9 @@ for (; f != NULL; f = f->next)
     if (save_errno == ERRNO_SPOOLFORMAT)
       {
       struct stat statbuf;
-      sprintf(CS big_buffer, "%s/input/%s/%s", spool_directory, message_subdir,
-        f->text);
-      if (Ustat(big_buffer, &statbuf) == 0)
+      uschar * fname = spool_fname(US"input", message_subdir, f->text, US"");
+
+      if (Ustat(fname, &statbuf) == 0)
         printf("*** spool format error: size=" OFF_T_FMT " ***",
           statbuf.st_size);
       else printf("*** spool format error ***");
@@ -959,7 +1006,7 @@ struct passwd *pw;
 uschar *doing = NULL;
 uschar *username;
 uschar *errmsg;
-uschar spoolname[256];
+uschar spoolname[32];
 
 /* Set the global message_id variable, used when re-writing spool files. This
 also causes message ids to be added to log messages. */
@@ -1004,12 +1051,13 @@ if (action >= MSG_SHOW_BODY)
 
   for (i = 0; i < 2; i++)
     {
-    message_subdir[0] = (split_spool_directory == (i == 0))? id[5] : 0;
-    sprintf(CS spoolname, "%s/%s/%s/%s%s", spool_directory, subdirectory,
-      message_subdir, id, suffix);
-    fd = Uopen(spoolname, O_RDONLY, 0);
-    if (fd >= 0) break;
-    if (i == 0) continue;
+    message_subdir[0] = split_spool_directory == (i == 0) ? id[5] : 0;
+    if ((fd = Uopen(spool_fname(subdirectory, message_subdir, id, suffix),
+                   O_RDONLY, 0)) >= 0)
+      break;
+    if (i == 0)
+      continue;
+
     printf("Failed to open %s file for %s%s: %s\n", subdirectory, id, suffix,
       strerror(errno));
     if (action == MSG_SHOW_LOG && !message_logs)
@@ -1030,8 +1078,7 @@ other process is working on this message. If the file does not exist, continue
 only if the action is remove and the user is an admin user, to allow for
 tidying up broken states. */
 
-if (!spool_open_datafile(id))
-  {
+if ((deliver_datafile = spool_open_datafile(id)) < 0)
   if (errno == ENOENT)
     {
     yield = FALSE;
@@ -1046,7 +1093,6 @@ if (!spool_open_datafile(id))
         strerror(errno));
     return FALSE;
     }
-  }
 
 /* Read the spool header file for the message. Again, continue after an
 error only in the case of deleting by an administrator. Setting the third
@@ -1159,49 +1205,70 @@ switch(action)
   operation, just run everything twice. */
 
   case MSG_REMOVE:
-  message_subdir[0] = id[5];
-  for (j = 0; j < 2; message_subdir[0] = 0, j++)
     {
-    sprintf(CS spoolname, "%s/msglog/%s/%s", spool_directory, message_subdir, id);
-    if (Uunlink(spoolname) < 0)
-      {
-      if (errno != ENOENT)
-        {
-        yield = FALSE;
-        printf("Error while removing %s: %s\n", spoolname,
-          strerror(errno));
-        }
-      }
-    else removed = TRUE;
+    uschar suffix[3];
 
-    for (i = 0; i < 3; i++)
+    suffix[0] = '-';
+    suffix[2] = 0;
+    message_subdir[0] = id[5];
+
+    for (j = 0; j < 2; message_subdir[0] = 0, j++)
       {
-      sprintf(CS spoolname, "%s/input/%s/%s-%c", spool_directory, message_subdir,
-        id, "DHJ"[i]);
-      if (Uunlink(spoolname) < 0)
-        {
-        if (errno != ENOENT)
-          {
-          yield = FALSE;
-          printf("Error while removing %s: %s\n", spoolname,
-            strerror(errno));
-          }
-        }
-      else removed = TRUE;
+      uschar * fname = spool_fname(US"msglog", message_subdir, id, US"");
+
+      DEBUG(D_any) debug_printf(" removing %s", fname);
+      if (Uunlink(fname) < 0)
+       {
+       if (errno != ENOENT)
+         {
+         yield = FALSE;
+         printf("Error while removing %s: %s\n", fname, strerror(errno));
+         }
+       else DEBUG(D_any) debug_printf(" (no file)\n");
+       }
+      else
+       {
+       removed = TRUE;
+       DEBUG(D_any) debug_printf(" (ok)\n");
+       }
+
+      for (i = 0; i < 3; i++)
+       {
+       uschar * fname;
+
+       suffix[1] = (US"DHJ")[i];
+       fname = spool_fname(US"input", message_subdir, id, suffix);
+
+       DEBUG(D_any) debug_printf(" removing %s", fname);
+       if (Uunlink(fname) < 0)
+         {
+         if (errno != ENOENT)
+           {
+           yield = FALSE;
+           printf("Error while removing %s: %s\n", fname, strerror(errno));
+           }
+         else DEBUG(D_any) debug_printf(" (no file)\n");
+         }
+       else
+         {
+         removed = TRUE;
+         DEBUG(D_any) debug_printf(" (done)\n");
+         }
+       }
       }
-    }
 
-  /* In the common case, the datafile is open (and locked), so give the
-  obvious message. Otherwise be more specific. */
+    /* In the common case, the datafile is open (and locked), so give the
+    obvious message. Otherwise be more specific. */
 
-  if (deliver_datafile >= 0) printf("has been removed\n");
-    else printf("has been removed or did not exist\n");
-  if (removed)
-    {
-    log_write(0, LOG_MAIN, "removed by %s", username);
-    log_write(0, LOG_MAIN, "Completed");
+    if (deliver_datafile >= 0) printf("has been removed\n");
+      else printf("has been removed or did not exist\n");
+    if (removed)
+      {
+      log_write(0, LOG_MAIN, "removed by %s", username);
+      log_write(0, LOG_MAIN, "Completed");
+      }
+    break;
     }
-  break;
 
 
   case MSG_MARK_ALL_DELIVERED:
@@ -1274,7 +1341,7 @@ switch(action)
       {
       if (action == MSG_ADD_RECIPIENT)
         {
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
        if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE;
 #endif
         receive_add_recipient(recipient, -1);
@@ -1300,7 +1367,7 @@ switch(action)
         }
       else  /* MSG_EDIT_SENDER */
         {
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
        if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE;
 #endif
         sender_address = recipient;
@@ -1380,4 +1447,6 @@ while ((ss = string_nextinlist(&s, &sep, buffer, sizeof(buffer))) != NULL)
   }
 }
 
+#endif /*!COMPILE_UTILITY*/
+
 /* End of queue.c */