global queue_name
[exim.git] / src / src / queue.c
index cfcb0440afb6f4de1d914af6bf8bc8e15866bec3..c971790927475b39f17e2e647c5fbd33a8fed721 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/queue.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2004 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions that operate on the input queue. */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions that operate on the input queue. */
@@ -144,7 +142,8 @@ else i = subdiroffset;
 
 /* Set up prototype for the directory name. */
 
 
 /* Set up prototype for the directory name. */
 
-sprintf(CS buffer, "%s/input", spool_directory);
+snprintf(CS buffer, sizeof(buffer), "%s/input/%s", spool_directory, queue_name);
+buffer[sizeof(buffer) - 3] = 0;
 subptr = Ustrlen(buffer);
 buffer[subptr+2] = 0;               /* terminator for lengthened name */
 
 subptr = Ustrlen(buffer);
 buffer[subptr+2] = 0;               /* terminator for lengthened name */
 
@@ -163,8 +162,8 @@ for (; i <= *subcount; i++)
     buffer[subptr+1] = subdirchar;
     }
 
     buffer[subptr+1] = subdirchar;
     }
 
-  dd = opendir(CS buffer);
-  if (dd == NULL) continue;
+  if (!(dd = opendir(CS buffer)))
+    continue;
 
   /* Now scan the directory. */
 
 
   /* Now scan the directory. */
 
@@ -267,7 +266,8 @@ for (; i <= *subcount; i++)
     if (!split_spool_directory && count <= 2)
       {
       rmdir(CS buffer);
     if (!split_spool_directory && count <= 2)
       {
       rmdir(CS buffer);
-      sprintf(CS big_buffer, "%s/msglog/%c", spool_directory, subdirchar);
+      sprintf(CS big_buffer, "%s/msglog/%s/%c",
+               spool_directory, queue_name, subdirchar);
       rmdir(CS big_buffer);
       }
     if (subdiroffset > 0) break;    /* Single sub-directory */
       rmdir(CS big_buffer);
       }
     if (subdiroffset > 0) break;    /* Single sub-directory */
@@ -453,7 +453,8 @@ for (i  = (queue_run_in_order? -1 : 0);
       load_average = os_getloadavg();
       if (load_average > deliver_queue_load_max)
         {
       load_average = os_getloadavg();
       if (load_average > deliver_queue_load_max)
         {
-        log_write(0, LOG_MAIN, "abandon queue run (load %.2f, max %.2f)",
+        log_write(L_queue_run, LOG_MAIN, "Abandon queue run: %s (load %.2f, max %.2f)",
+          log_detail,
           (double)load_average/1000.0,
           (double)deliver_queue_load_max/1000.0);
         i = subcount;                 /* Don't process other directories */
           (double)load_average/1000.0,
           (double)deliver_queue_load_max/1000.0);
         i = subcount;                 /* Don't process other directories */
@@ -477,8 +478,8 @@ for (i  = (queue_run_in_order? -1 : 0);
     /* Check that the message still exists */
 
     message_subdir[0] = f->dir_uschar;
     /* 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);
+    snprintf(CS buffer, sizeof(buffer), "%s/input/%s/%s/%s",
+      spool_directory, queue_name, message_subdir, f->text);
     if (Ustat(buffer, &statbuf) < 0) continue;
 
     /* There are some tests that require the reading of the header file. Ensure
     if (Ustat(buffer, &statbuf) < 0) continue;
 
     /* There are some tests that require the reading of the header file. Ensure
@@ -594,7 +595,7 @@ for (i  = (queue_run_in_order? -1 : 0);
     if (queue_run_pipe == 0)
       {
       queue_run_pipe = dup(queue_run_pipe);
     if (queue_run_pipe == 0)
       {
       queue_run_pipe = dup(queue_run_pipe);
-      close(0);
+      (void)close(0);
       }
 
     /* Before forking to deliver the message, ensure any open and cached
       }
 
     /* Before forking to deliver the message, ensure any open and cached
@@ -615,6 +616,7 @@ for (i  = (queue_run_in_order? -1 : 0);
     if ((pid = fork()) == 0)
       {
       int rc;
     if ((pid = fork()) == 0)
       {
       int rc;
+      if (running_in_test_harness) millisleep(100);
       (void)close(pfd[pipe_read]);
       rc = deliver_message(f->text, force_delivery, FALSE);
       _exit(rc == DELIVER_NOT_ATTEMPTED);
       (void)close(pfd[pipe_read]);
       rc = deliver_message(f->text, force_delivery, FALSE);
       _exit(rc == DELIVER_NOT_ATTEMPTED);
@@ -626,7 +628,7 @@ for (i  = (queue_run_in_order? -1 : 0);
     /* Close the writing end of the synchronizing pipe in this process,
     then wait for the first level process to terminate. */
 
     /* Close the writing end of the synchronizing pipe in this process,
     then wait for the first level process to terminate. */
 
-    close(pfd[pipe_write]);
+    (void)close(pfd[pipe_write]);
     set_process_info("running queue: waiting for %s (%d)", f->text, pid);
     while (wait(&status) != pid);
 
     set_process_info("running queue: waiting for %s (%d)", f->text, pid);
     while (wait(&status) != pid);
 
@@ -650,7 +652,8 @@ for (i  = (queue_run_in_order? -1 : 0);
     the mere fact that read() unblocks is enough. */
 
     set_process_info("running queue: waiting for children of %d", pid);
     the mere fact that read() unblocks is enough. */
 
     set_process_info("running queue: waiting for children of %d", pid);
-    (void)read(pfd[pipe_read], buffer, sizeof(buffer));
+    if (read(pfd[pipe_read], buffer, sizeof(buffer)) > 0)
+      log_write(0, LOG_MAIN|LOG_PANIC, "queue run: unexpected data on pipe");
     (void)close(pfd[pipe_read]);
     set_process_info("running queue");
 
     (void)close(pfd[pipe_read]);
     set_process_info("running queue");
 
@@ -841,8 +844,8 @@ for (; f != NULL; f = f->next)
     FILE *jread;
     struct stat statbuf;
 
     FILE *jread;
     struct stat statbuf;
 
-    sprintf(CS big_buffer, "%s/input/%s/%s", spool_directory, message_subdir,
-      f->text);
+    sprintf(CS big_buffer, "%s/input/%s/%s/%s",
+      spool_directory, queue_name, message_subdir, f->text);
     ptr = Ustrlen(big_buffer)-1;
     big_buffer[ptr] = 'D';
 
     ptr = Ustrlen(big_buffer)-1;
     big_buffer[ptr] = 'D';
 
@@ -872,7 +875,7 @@ for (; f != NULL; f = f->next)
         big_buffer[n-1] = 0;
         tree_add_nonrecipient(big_buffer);
         }
         big_buffer[n-1] = 0;
         tree_add_nonrecipient(big_buffer);
         }
-      fclose(jread);
+      (void)fclose(jread);
       }
     }
 
       }
     }
 
@@ -891,13 +894,11 @@ for (; f != NULL; f = f->next)
     if (save_errno == ERRNO_SPOOLFORMAT)
       {
       struct stat statbuf;
     if (save_errno == ERRNO_SPOOLFORMAT)
       {
       struct stat statbuf;
-      sprintf(CS big_buffer, "%s/input/%s/%s", spool_directory, message_subdir,
-        f->text);
+      sprintf(CS big_buffer, "%s/input/%s/%s/%s",
+        spool_directory, queue_name, message_subdir, f->text);
       if (Ustat(big_buffer, &statbuf) == 0)
       if (Ustat(big_buffer, &statbuf) == 0)
-        {
-        int size = statbuf.st_size;    /* Because might be a long */
-        printf("*** spool format error: size=%d ***", size);
-        }
+        printf("*** spool format error: size=" OFF_T_FMT " ***",
+          statbuf.st_size);
       else printf("*** spool format error ***");
       }
     else printf("*** spool read error: %s ***", strerror(save_errno));
       else printf("*** spool format error ***");
       }
     else printf("*** spool read error: %s ***", strerror(save_errno));
@@ -936,9 +937,9 @@ for (; f != NULL; f = f->next)
 *             Act on a specific message          *
 *************************************************/
 
 *             Act on a specific message          *
 *************************************************/
 
-/* Actions that require a list of addresses make use of
-argv/argc/recipients_arg. Other actions do not. This function does its
-own authority checking.
+/* Actions that require a list of addresses make use of argv/argc/
+recipients_arg. Other actions do not. This function does its own
+authority checking.
 
 Arguments:
   id              id of the message to work on
 
 Arguments:
   id              id of the message to work on
@@ -1005,12 +1006,15 @@ if (action >= MSG_SHOW_BODY)
 
   for (i = 0; i < 2; i++)
     {
 
   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;
+    snprintf(CS spoolname, sizeof(spoolname), "%s/%s/%s/%s/%s%s",
+             spool_directory, subdirectory, queue_name,
+             message_subdir, id, suffix);
+    if ((fd = Uopen(spoolname, 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)
     printf("Failed to open %s file for %s%s: %s\n", subdirectory, id, suffix,
       strerror(errno));
     if (action == MSG_SHOW_LOG && !message_logs)
@@ -1020,9 +1024,9 @@ if (action >= MSG_SHOW_BODY)
     }
 
   while((rc = read(fd, big_buffer, big_buffer_size)) > 0)
     }
 
   while((rc = read(fd, big_buffer, big_buffer_size)) > 0)
-    write(fileno(stdout), big_buffer, rc);
+    rc = write(fileno(stdout), big_buffer, rc);
 
 
-  close(fd);
+  (void)close(fd);
   return TRUE;
   }
 
   return TRUE;
   }
 
@@ -1031,7 +1035,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. */
 
 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)
     {
   {
   if (errno == ENOENT)
     {
@@ -1065,7 +1069,7 @@ if (spool_read_header(spoolname, TRUE, FALSE) != spool_read_OK)
     printf("Spool format error for %s\n", spoolname);
   if (action != MSG_REMOVE || !admin_user)
     {
     printf("Spool format error for %s\n", spoolname);
   if (action != MSG_REMOVE || !admin_user)
     {
-    close(deliver_datafile);
+    (void)close(deliver_datafile);
     deliver_datafile = -1;
     return FALSE;
     }
     deliver_datafile = -1;
     return FALSE;
     }
@@ -1080,7 +1084,7 @@ why we leave this check until after the headers are read. */
 if (!admin_user && (action != MSG_REMOVE || real_uid != originator_uid))
   {
   printf("Permission denied\n");
 if (!admin_user && (action != MSG_REMOVE || real_uid != originator_uid))
   {
   printf("Permission denied\n");
-  close(deliver_datafile);
+  (void)close(deliver_datafile);
   deliver_datafile = -1;
   return FALSE;
   }
   deliver_datafile = -1;
   return FALSE;
   }
@@ -1093,10 +1097,17 @@ username = (pw != NULL)?
 
 /* Take the necessary action. */
 
 
 /* Take the necessary action. */
 
-printf("Message %s ", id);
+if (action != MSG_SHOW_COPY) printf("Message %s ", id);
 
 switch(action)
   {
 
 switch(action)
   {
+  case MSG_SHOW_COPY:
+  deliver_in_buffer = store_malloc(DELIVER_IN_BUFFER_SIZE);
+  deliver_out_buffer = store_malloc(DELIVER_OUT_BUFFER_SIZE);
+  transport_write_message(NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, 0);
+  break;
+
+
   case MSG_FREEZE:
   if (deliver_freeze)
     {
   case MSG_FREEZE:
   if (deliver_freeze)
     {
@@ -1156,7 +1167,8 @@ switch(action)
   message_subdir[0] = id[5];
   for (j = 0; j < 2; message_subdir[0] = 0, j++)
     {
   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);
+    snprintf(CS spoolname, sizeof(spoolname), "%s/msglog/%s/%s/%s",
+      spool_directory, queue_name, message_subdir, id);
     if (Uunlink(spoolname) < 0)
       {
       if (errno != ENOENT)
     if (Uunlink(spoolname) < 0)
       {
       if (errno != ENOENT)
@@ -1170,8 +1182,8 @@ switch(action)
 
     for (i = 0; i < 3; i++)
       {
 
     for (i = 0; i < 3; i++)
       {
-      sprintf(CS spoolname, "%s/input/%s/%s-%c", spool_directory, message_subdir,
-        id, "DHJ"[i]);
+      snprintf(CS spoolname, sizeof(spoolname), "%s/input/%s/%s/%s-%c",
+        spool_directory, queue_name, message_subdir, id, "DHJ"[i]);
       if (Uunlink(spoolname) < 0)
         {
         if (errno != ENOENT)
       if (Uunlink(spoolname) < 0)
         {
         if (errno != ENOENT)
@@ -1190,7 +1202,11 @@ switch(action)
 
   if (deliver_datafile >= 0) printf("has been removed\n");
     else printf("has been removed or did not exist\n");
 
   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);
+  if (removed)
+    {
+    log_write(0, LOG_MAIN, "removed by %s", username);
+    log_write(0, LOG_MAIN, "Completed");
+    }
   break;
 
 
   break;
 
 
@@ -1264,6 +1280,9 @@ switch(action)
       {
       if (action == MSG_ADD_RECIPIENT)
         {
       {
       if (action == MSG_ADD_RECIPIENT)
         {
+#ifdef SUPPORT_I18N
+       if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE;
+#endif
         receive_add_recipient(recipient, -1);
         log_write(0, LOG_MAIN, "recipient <%s> added by %s",
           recipient, username);
         receive_add_recipient(recipient, -1);
         log_write(0, LOG_MAIN, "recipient <%s> added by %s",
           recipient, username);
@@ -1287,6 +1306,9 @@ switch(action)
         }
       else  /* MSG_EDIT_SENDER */
         {
         }
       else  /* MSG_EDIT_SENDER */
         {
+#ifdef SUPPORT_I18N
+       if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE;
+#endif
         sender_address = recipient;
         log_write(0, LOG_MAIN, "sender address changed to <%s> by %s",
           recipient, username);
         sender_address = recipient;
         log_write(0, LOG_MAIN, "sender address changed to <%s> by %s",
           recipient, username);
@@ -1311,7 +1333,7 @@ switch(action)
 /* Closing the datafile releases the lock and permits other processes
 to operate on the message (if it still exists). */
 
 /* Closing the datafile releases the lock and permits other processes
 to operate on the message (if it still exists). */
 
-close(deliver_datafile);
+(void)close(deliver_datafile);
 deliver_datafile = -1;
 return yield;
 }
 deliver_datafile = -1;
 return yield;
 }
@@ -1335,7 +1357,8 @@ queue_check_only(void)
 BOOL *set;
 int sep = 0;
 struct stat statbuf;
 BOOL *set;
 int sep = 0;
 struct stat statbuf;
-uschar *s, *ss, *name;
+const uschar *s;
+uschar *ss, *name;
 uschar buffer[1024];
 
 if (queue_only_file == NULL) return;
 uschar buffer[1024];
 
 if (queue_only_file == NULL) return;