Fix three issues highlighted by clang analyser.
[users/heiko/exim.git] / src / src / transports / autoreply.c
index cccd82c8825544ecfff18aa9fdb3507dfab7c428..cce1cd77130863a73f2f6f8bb1c03f79098b2a6a 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/transports/autoreply.c,v 1.2 2005/01/04 10:00:45 ph10 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -277,6 +275,7 @@ uschar *from, *reply_to, *to, *cc, *bcc, *subject, *headers, *text, *file;
 uschar *logfile, *oncelog;
 uschar *cache_buff = NULL;
 uschar *cache_time = NULL;
+uschar *message_id = NULL;
 header_line *h;
 time_t now = time(NULL);
 time_t once_repeat_sec = 0;
@@ -420,7 +419,7 @@ recipient, the effect might not be quite as envisaged. If once_file_size is
 set, instead of a dbm file, we use a regular file containing a circular buffer
 recipient cache. */
 
-if (oncelog != NULL && to != NULL)
+if (oncelog != NULL && *oncelog != 0 && to != NULL)
   {
   time_t then = 0;
 
@@ -530,8 +529,8 @@ if (oncelog != NULL && to != NULL)
       uschar *ptr = log_buffer;
       sprintf(CS ptr, "%s\n  previously sent to %.200s\n", tod_stamp(tod_log), to);
       while(*ptr) ptr++;
-      write(log_fd, log_buffer, ptr - log_buffer);
-      close(log_fd);
+      (void)write(log_fd, log_buffer, ptr - log_buffer);
+      (void)close(log_fd);
       }
     goto END_OFF;
     }
@@ -590,9 +589,57 @@ for (h = header_list; h != NULL; h = h->next)
 
 if (h != NULL)
   {
-  uschar *s = Ustrchr(h->text, ':') + 1;
-  while (isspace(*s)) s++;
-  fprintf(f, "In-Reply-To: %s", s);
+  message_id = Ustrchr(h->text, ':') + 1;
+  while (isspace(*message_id)) message_id++;
+  fprintf(f, "In-Reply-To: %s", message_id);
+  }
+
+/* Generate a References header if there is at least one of Message-ID:,
+References:, or In-Reply-To: (see RFC 2822). */
+
+for (h = header_list; h != NULL; h = h->next)
+  if (h->type != htype_old && strncmpic(US"References:", h->text, 11) == 0)
+    break;
+
+if (h == NULL)
+  for (h = header_list; h != NULL; h = h->next)
+    if (h->type != htype_old && strncmpic(US"In-Reply-To:", h->text, 12) == 0)
+      break;
+
+/* We limit the total length of references.  Although there is no fixed
+limit, some systems do not like headers growing beyond recognition.
+Keep the first message ID for the thread root and the last few for
+the position inside the thread, up to a maximum of 12 altogether. */
+
+if (h != NULL || message_id != NULL)
+  {
+  fprintf(f, "References:");
+  if (h != NULL)
+    {
+    uschar *s, *id, *error;
+    uschar *referenced_ids[12];
+    int reference_count = 0;
+    int i;
+
+    s = Ustrchr(h->text, ':') + 1;
+    parse_allow_group = FALSE;
+    while (*s != 0 && (s = parse_message_id(s, &id, &error)) != NULL)
+      {
+      if (reference_count == sizeof(referenced_ids)/sizeof(uschar *))
+        {
+        memmove(referenced_ids + 1, referenced_ids + 2,
+           sizeof(referenced_ids) - 2*sizeof(uschar *));
+        referenced_ids[reference_count - 1] = id;
+        }
+      else referenced_ids[reference_count++] = id;
+      }
+    for (i = 0; i < reference_count; ++i) fprintf(f, " %s", referenced_ids[i]);
+    }
+
+  /* The message id will have a newline on the end of it. */
+
+  if (message_id != NULL) fprintf(f, " %s", message_id);
+    else fprintf(f, "\n");
   }
 
 /* Add an Auto-Submitted: header */
@@ -630,28 +677,32 @@ if (ff != NULL)
   }
 
 /* Copy the original message if required, observing the return size
-limit. */
+limit if we are returning the body. */
 
 if (return_message)
   {
-  if (bounce_return_size_limit > 0)
+  uschar *rubric = (tblock->headers_only)?
+    US"------ This is a copy of the message's header lines.\n"
+    : (tblock->body_only)?
+    US"------ This is a copy of the body of the message, without the headers.\n"
+    :
+    US"------ This is a copy of the message, including all the headers.\n";
+
+  if (bounce_return_size_limit > 0 && !tblock->headers_only)
     {
     struct stat statbuf;
     int max = (bounce_return_size_limit/DELIVER_IN_BUFFER_SIZE + 1) *
       DELIVER_IN_BUFFER_SIZE;
     if (fstat(deliver_datafile, &statbuf) == 0 && statbuf.st_size > max)
       {
-      int size = statbuf.st_size;  /* Because might be a long */
-      fprintf(f, "\n"
-"------ This is a copy of the message, including all the headers.\n"
-"------ The body of the message is %d characters long; only the first\n"
-"------ %d or so are included here.\n\n", size, (max/1000)*1000);
+      fprintf(f, "\n%s"
+"------ The body of the message is " OFF_T_FMT " characters long; only the first\n"
+"------ %d or so are included here.\n\n", rubric, statbuf.st_size,
+        (max/1000)*1000);
       }
-    else fprintf(f, "\n"
-"------ This is a copy of the message, including all the headers. ------\n\n");
+    else fprintf(f, "\n%s\n", rubric);
     }
-  else fprintf(f, "\n"
-"------ This is a copy of the message, including all the headers. ------\n\n");
+  else fprintf(f, "\n%s\n", rubric);
 
   fflush(f);
   transport_count = 0;
@@ -667,7 +718,7 @@ if (return_message)
 
 /* End the message and wait for the child process to end; no timeout. */
 
-fclose(f);
+(void)fclose(f);
 rc = child_close(pid, 0);
 
 /* Update the "sent to" log whatever the yield. This errs on the side of
@@ -702,7 +753,7 @@ if (cache_fd >= 0)
     }
 
   memcpy(cache_time, &now, sizeof(time_t));
-  write(cache_fd, from, size);
+  (void)write(cache_fd, from, size);
   }
 
 /* Update DBM file */
@@ -798,8 +849,8 @@ if (logfile != NULL)
         "  %s\n", headers);
       while(*ptr) ptr++;
       }
-    write(log_fd, log_buffer, ptr - log_buffer);
-    close(log_fd);
+    (void)write(log_fd, log_buffer, ptr - log_buffer);
+    (void)close(log_fd);
     }
   else DEBUG(D_transport) debug_printf("Failed to open log file %s for %s "
     "transport: %s\n", logfile, tblock->name, strerror(errno));
@@ -807,7 +858,7 @@ if (logfile != NULL)
 
 END_OFF:
 if (dbm_file != NULL) EXIM_DBCLOSE(dbm_file);
-if (cache_fd > 0) close(cache_fd);
+if (cache_fd > 0) (void)close(cache_fd);
 
 DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);