Delivery: quieten smtp transport conn reuse vs. delivery race. Bug 1810
[exim.git] / src / src / queue.c
index cfcb0440afb6f4de1d914af6bf8bc8e15866bec3..cc8d36b235274d1c7957e33877bd00b8c2e0867c 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    *
 *************************************************/
 
-/* 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. */
@@ -453,7 +451,8 @@ for (i  = (queue_run_in_order? -1 : 0);
       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 */
@@ -594,7 +593,7 @@ for (i  = (queue_run_in_order? -1 : 0);
     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
@@ -615,6 +614,7 @@ for (i  = (queue_run_in_order? -1 : 0);
     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);
@@ -626,7 +626,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(pfd[pipe_write]);
+    (void)close(pfd[pipe_write]);
     set_process_info("running queue: waiting for %s (%d)", f->text, pid);
     while (wait(&status) != pid);
 
@@ -650,7 +650,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);
-    (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");
 
@@ -872,7 +873,7 @@ for (; f != NULL; f = f->next)
         big_buffer[n-1] = 0;
         tree_add_nonrecipient(big_buffer);
         }
-      fclose(jread);
+      (void)fclose(jread);
       }
     }
 
@@ -894,10 +895,8 @@ for (; f != NULL; f = f->next)
       sprintf(CS big_buffer, "%s/input/%s/%s", spool_directory, message_subdir,
         f->text);
       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));
@@ -936,9 +935,9 @@ for (; f != NULL; f = f->next)
 *             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
@@ -1020,9 +1019,9 @@ if (action >= MSG_SHOW_BODY)
     }
 
   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;
   }
 
@@ -1031,7 +1030,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)
     {
@@ -1065,7 +1064,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)
     {
-    close(deliver_datafile);
+    (void)close(deliver_datafile);
     deliver_datafile = -1;
     return FALSE;
     }
@@ -1080,7 +1079,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");
-  close(deliver_datafile);
+  (void)close(deliver_datafile);
   deliver_datafile = -1;
   return FALSE;
   }
@@ -1093,10 +1092,17 @@ username = (pw != NULL)?
 
 /* Take the necessary action. */
 
-printf("Message %s ", id);
+if (action != MSG_SHOW_COPY) printf("Message %s ", id);
 
 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)
     {
@@ -1190,7 +1196,11 @@ switch(action)
 
   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;
 
 
@@ -1264,6 +1274,9 @@ switch(action)
       {
       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);
@@ -1287,6 +1300,9 @@ switch(action)
         }
       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);
@@ -1311,7 +1327,7 @@ switch(action)
 /* 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;
 }
@@ -1335,7 +1351,8 @@ queue_check_only(void)
 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;