constification
[exim.git] / src / src / moan.c
index 63b3426bf9c7279d03336593d8ea5ffabb75628e..a369989564cda037afce9fe5e272ee9e4a102eb0 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/moan.c,v 1.5 2006/02/07 11:19:00 ph10 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2006 */
+/* Copyright (c) University of Cambridge 1995 - 2014 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions for sending messages to sender or to mailmaster. */
 
 
 
+/*************************************************
+*            Write From: line for DSN            *
+*************************************************/
+
+/* This function is called to write the From: line in automatically generated
+messages - bounces, warnings, etc. It expands a configuration item in order to
+get the text. If the expansion fails, a panic is logged and the default value
+for the option is used.
+
+Argument:   the FILE to write to
+Returns:    nothing
+*/
+
+void
+moan_write_from(FILE *f)
+{
+uschar *s = expand_string(dsn_from);
+if (s == NULL)
+  {
+  log_write(0, LOG_MAIN|LOG_PANIC,
+    "Failed to expand dsn_from (using default): %s", expand_string_message);
+  s = expand_string(US DEFAULT_DSN_FROM);
+  }
+fprintf(f, "From: %s\n", s);
+}
+
+
+
 /*************************************************
 *              Send error message                *
 *************************************************/
@@ -62,8 +88,7 @@ else DEBUG(D_any) debug_printf("Child process %d for sending message\n", pid);
 f = fdopen(fd, "wb");
 if (errors_reply_to != NULL) fprintf(f, "Reply-To: %s\n", errors_reply_to);
 fprintf(f, "Auto-Submitted: auto-replied\n");
-fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
-  qualify_domain_sender);
+moan_write_from(f);
 fprintf(f, "To: %s\n", recipient);
 
 switch(ident)
@@ -177,6 +202,26 @@ switch(ident)
   fprintf(f, "\n");
   break;
 
+#ifdef EXPERIMENTAL_DMARC
+  case ERRMESS_DMARC_FORENSIC:
+  bounce_return_message = TRUE;
+  bounce_return_body    = FALSE;
+  fprintf(f,
+          "Subject: DMARC Forensic Report for %s from IP %s\n\n",
+         ((eblock == NULL) ? US"Unknown" : eblock->text2),
+          sender_host_address);
+  fprintf(f,
+  "A message claiming to be from you has failed the published DMARC\n"
+  "policy for your domain.\n\n");
+  while (eblock != NULL)
+    {
+    fprintf(f, "  %s: %s\n", eblock->text1, eblock->text2);
+    count++;
+    eblock = eblock->next;
+    }
+  break;
+#endif
+
   default:
   fprintf(f, "Subject: Mail failure\n\n");
   fprintf(f,
@@ -185,66 +230,86 @@ switch(ident)
   break;
   }
 
-/* Now copy the message - headers then the rest of the input if
-available, up to the configured limit. */
+/* Now, if configured, copy the message; first the headers and then the rest of
+the input if available, up to the configured limit, if the option for including
+message bodies in bounces is set. */
 
-if (size_limit == 0 || size_limit > thismessage_size_limit)
-  size_limit = thismessage_size_limit;
-
-if (size_limit > 0 && size_limit < message_size)
+if (bounce_return_message)
   {
-  int x = size_limit;
-  uschar *k = US"";
-  if ((x & 1023) == 0)
+  if (bounce_return_body)
     {
-    k = US"K";
-    x >>= 10;
+    fprintf(f, "\n"
+      "------ This is a copy of your message, including all the headers.");
+    if (size_limit == 0 || size_limit > thismessage_size_limit)
+      size_limit = thismessage_size_limit;
+    if (size_limit > 0 && size_limit < message_size)
+      {
+      int x = size_limit;
+      uschar *k = US"";
+      if ((x & 1023) == 0)
+        {
+        k = US"K";
+        x >>= 10;
+        }
+      fprintf(f, "\n"
+        "------ No more than %d%s characters of the body are included.\n\n",
+          x, k);
+      }
+    else fprintf(f, " ------\n\n");
+    }
+  else
+    {
+    fprintf(f, "\n"
+      "------ This is a copy of the headers that were received before the "
+      "error\n       was detected.\n\n");
     }
-  fprintf(f, "\n"
-  "------ This is a copy of your message, including all the headers.\n"
-  "------ No more than %d%s characters of the body are included.\n\n", x, k);
-  }
-else fprintf(f, "\n"
-  "------ This is a copy of your message, including all the headers. ------"
-  "\n\n");
 
-/* If the error occurred before the Received: header was created, its text
-field will still be NULL; just omit such a header line. */
+  /* If the error occurred before the Received: header was created, its text
+  field will still be NULL; just omit such a header line. */
 
-while (headers != NULL)
-  {
-  if (headers->text != NULL) fprintf(f, "%s", CS headers->text);
-  headers = headers->next;
-  }
+  while (headers != NULL)
+    {
+    if (headers->text != NULL) fprintf(f, "%s", CS headers->text);
+    headers = headers->next;
+    }
 
-if (ident != ERRMESS_VLONGHEADER && ident != ERRMESS_VLONGHDRLINE)
-  fputc('\n', f);
+  if (ident != ERRMESS_VLONGHEADER && ident != ERRMESS_VLONGHDRLINE)
+    fputc('\n', f);
 
-/* After early detection of an error, the message file may be STDIN,
-in which case we might have to terminate on a line containing just "."
-as well as on EOF. We may already have the first line in memory. */
+  /* After early detection of an error, the message file may be STDIN,
+  in which case we might have to terminate on a line containing just "."
+  as well as on EOF. We may already have the first line in memory. */
 
-if (message_file != NULL)
-  {
-  int ch;
-  int state = 1;
-  BOOL enddot = dot_ends && message_file == stdin;
-  if (firstline != NULL) fprintf(f, "%s", CS firstline);
-  while ((ch = fgetc(message_file)) != EOF)
+  if (bounce_return_body && message_file != NULL)
     {
-    fputc(ch, f);
-    if (size_limit > 0 && ++written > size_limit) break;
-    if (enddot)
+    int ch;
+    int state = 1;
+    BOOL enddot = dot_ends && message_file == stdin;
+    if (firstline != NULL) fprintf(f, "%s", CS firstline);
+    while ((ch = fgetc(message_file)) != EOF)
       {
-      if (state == 0) { if (ch == '\n') state = 1; }
-      else if (state == 1)
-        { if (ch == '.') state = 2; else if (ch != '\n') state = 0; }
-      else
-        { if (ch == '\n') break; else state = 0; }
+      fputc(ch, f);
+      if (size_limit > 0 && ++written > size_limit) break;
+      if (enddot)
+        {
+        if (state == 0) { if (ch == '\n') state = 1; }
+        else if (state == 1)
+          { if (ch == '.') state = 2; else if (ch != '\n') state = 0; }
+        else
+          { if (ch == '\n') break; else state = 0; }
+        }
       }
     }
+#ifdef EXPERIMENTAL_DMARC
+  /* Overkill, but use exact test in case future code gets inserted */
+  else if (bounce_return_body && message_file == NULL)
+    {
+    /* This doesn't print newlines, disable until can parse and fix
+     * output to be legible.  */
+    fprintf(f, "%s", expand_string(US"$message_body"));
+    }
+#endif
   }
-
 /* Close the file, which should send an EOF to the child process
 that is receiving the message. Wait for it to finish, without a timeout. */
 
@@ -398,8 +463,8 @@ Returns:        nothing
 */
 
 void
-moan_tell_someone(uschar *who, address_item *addr, uschar *subject,
-  char *format, ...)
+moan_tell_someone(uschar *who, address_item *addr,
+  const uschar *subject, const char *format, ...)
 {
 FILE *f;
 va_list ap;
@@ -415,8 +480,7 @@ if (pid < 0)
 
 f = fdopen(fd, "wb");
 fprintf(f, "Auto-Submitted: auto-replied\n");
-fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
-  qualify_domain_sender);
+moan_write_from(f);
 fprintf(f, "To: %s\n", who);
 fprintf(f, "Subject: %s\n\n", subject);
 va_start(ap, format);
@@ -467,7 +531,7 @@ Returns:       does not return; exits from the program
 */
 
 void
-moan_smtp_batch(uschar *cmd_buffer, char *format, ...)
+moan_smtp_batch(uschar *cmd_buffer, const char *format, ...)
 {
 va_list ap;
 int yield = (receive_messagecount > 0)? 1 : 2;
@@ -534,7 +598,7 @@ uschar *
 moan_check_errorcopy(uschar *recipient)
 {
 uschar *item, *localpart, *domain;
-uschar *listptr = errors_copy;
+const uschar *listptr = errors_copy;
 uschar *yield = NULL;
 uschar buffer[256];
 int sep = 0;
@@ -546,7 +610,7 @@ if (errors_copy == NULL) return NULL;
 length of the local part. */
 
 localpart = recipient;
-domain = Ustrchr(recipient, '@');
+domain = Ustrrchr(recipient, '@');
 if (domain == NULL) return NULL;  /* should not occur, but avoid crash */
 llen = domain++ - recipient;
 
@@ -555,8 +619,8 @@ llen = domain++ - recipient;
 while ((item = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer)))
        != NULL)
   {
-  uschar *newaddress = item;
-  uschar *pattern = string_dequote(&newaddress);
+  const uschar *newaddress = item;
+  const uschar *pattern = string_dequote(&newaddress);
 
   /* If no new address found, just skip this item. */
 
@@ -572,10 +636,7 @@ while ((item = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer)))
   if (match_address_list(recipient, TRUE, TRUE, &pattern, NULL, 0, UCHAR_MAX+1,
         NULL) == OK)
     {
-    uschar temp[256];
-    Ustrncpy(temp, localpart, llen);
-    temp[llen] = 0;
-    deliver_localpart = temp;
+    deliver_localpart = string_copyn(localpart, llen);
     deliver_domain = domain;
     yield = expand_string_copy(newaddress);
     deliver_domain = deliver_localpart = NULL;
@@ -659,8 +720,7 @@ if (pid < 0)
 
 f = fdopen(fd, "wb");
 fprintf(f, "Auto-Submitted: auto-replied\n");
-fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
-  qualify_domain_sender);
+moan_write_from(f);
 fprintf(f, "To: %s\n", s);
 fprintf(f, "Subject: error(s) in forwarding or filtering\n\n");