[exim-cvs] cvs commit: exim/exim-doc/doc-txt ChangeLog NewSt…

Top Page
Delete this message
Reply to this message
Author: Philip Hazel
Date:  
To: exim-cvs
Subject: [exim-cvs] cvs commit: exim/exim-doc/doc-txt ChangeLog NewStuff exim/exim-src ACKNOWLEDGMENTS exim/exim-src/src acl.c functions.h receive.c smtp_in.c exim/exim-test runtest exim/exim-test/confs 0023
ph10 2006/11/14 16:40:37 GMT

  Modified files:
    exim-doc/doc-txt     ChangeLog NewStuff 
    exim-src             ACKNOWLEDGMENTS 
    exim-src/src         acl.c functions.h receive.c smtp_in.c 
    exim-test            runtest 
    exim-test/confs      0023 
    exim-test/stdout     0023 
  Added files:
    exim-test/confs      0546 
    exim-test/log        0546 
    exim-test/paniclog   0546 
    exim-test/scripts/0000-Basic 0546 
    exim-test/stderr     0546 
    exim-test/stdout     0546 
  Log:
  Applied a modified version of Brad Jorsch's patch for "message" with
  "accept".


  Revision  Changes    Path
  1.434     +3 -0      exim/exim-doc/doc-txt/ChangeLog
  1.123     +45 -0     exim/exim-doc/doc-txt/NewStuff
  1.64      +2 -1      exim/exim-src/ACKNOWLEDGMENTS
  1.67      +34 -22    exim/exim-src/src/acl.c
  1.31      +1 -0      exim/exim-src/src/functions.h
  1.31      +57 -30    exim/exim-src/src/receive.c
  1.47      +213 -97   exim/exim-src/src/smtp_in.c
  1.3       +1 -1      exim/exim-test/confs/0023
  1.1       +46 -0     exim/exim-test/confs/0546 (new)
  1.1       +3 -0      exim/exim-test/log/0546 (new)
  1.1       +2 -0      exim/exim-test/paniclog/0546 (new)
  1.19      +1 -1      exim/exim-test/runtest
  1.1       +19 -0     exim/exim-test/scripts/0000-Basic/0546 (new)
  1.1       +2 -0      exim/exim-test/stderr/0546 (new)
  1.3       +1 -1      exim/exim-test/stdout/0023
  1.1       +20 -0     exim/exim-test/stdout/0546 (new)


  Index: ChangeLog
  ===================================================================
  RCS file: /home/cvs/exim/exim-doc/doc-txt/ChangeLog,v
  retrieving revision 1.433
  retrieving revision 1.434
  diff -u -r1.433 -r1.434
  --- ChangeLog    13 Nov 2006 12:29:30 -0000    1.433
  +++ ChangeLog    14 Nov 2006 16:40:36 -0000    1.434
  @@ -1,4 +1,4 @@
  -$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.433 2006/11/13 12:29:30 ph10 Exp $
  +$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.434 2006/11/14 16:40:36 ph10 Exp $


Change log file for Exim from version 4.21
-------------------------------------------
@@ -273,6 +273,9 @@

   PH/44 There was no timeout on the connect() call when using a Unix domain
         socket in the ${readsocket expansion. There now is.
  +
  +PH/45 Applied a modified version of Brad Jorsch's patch to allow "message" to
  +      be meaningful with "accept".



Exim version 4.63

  Index: NewStuff
  ===================================================================
  RCS file: /home/cvs/exim/exim-doc/doc-txt/NewStuff,v
  retrieving revision 1.122
  retrieving revision 1.123
  diff -u -r1.122 -r1.123
  --- NewStuff    13 Nov 2006 12:07:46 -0000    1.122
  +++ NewStuff    14 Nov 2006 16:40:36 -0000    1.123
  @@ -1,4 +1,4 @@
  -$Cambridge: exim/exim-doc/doc-txt/NewStuff,v 1.122 2006/11/13 12:07:46 ph10 Exp $
  +$Cambridge: exim/exim-doc/doc-txt/NewStuff,v 1.123 2006/11/14 16:40:36 ph10 Exp $


   New Features in Exim
   --------------------
  @@ -196,6 +196,51 @@
       as $received_ip_address and $received_port, to make it clear that they
       relate to message reception rather than delivery. (The old names remain
       available for compatibility.)
  +
  +12. The "message" modifier can now be used on acl verbs to vary the message
  +    that is sent when an SMTP command. For example, in a RCPT ACL you could
  +    have:
  +
  +      accept  <some conditions>
  +              message = OK, I'll allow you through today
  +
  +    Previously, this message modifier would have had no effect whatsoever.
  +
  +    IMPORTANT: The new behaviour applies to "accept" (and "discard") only if
  +    there is no occurrence of "endpass" in the statement. If "endpass" is
  +    present, the behaviour reverts to the old case, where "message" applies to
  +    rejection. This is for backwards compatibility.
  +
  +    It is always possible to rewrite ACL statements so that "endpass" is not
  +    needed (and indeed it is no longer used in the default configuration, and
  +    is somewhat not recommended nowadays because it causes confusion.)
  +
  +    It is now generally true that the "message" modifier sets up a text string
  +    that is expanded and used as a response message if the current statement
  +    terminates the ACL. The expansion happens at the time Exim decides that the
  +    ACL is to end, not at the time it processes "message". If the expansion
  +    fails, or generates an empty string, the modifier is ignored.
  +
  +    For ACLs that are triggered by SMTP commands, the message is returned as
  +    part of the SMTP response. In this situation, the message may begin with an
  +    overriding SMTP response code, optionally followed by an "extended response
  +    code". However, the first digit of the supplied response code must be the
  +    same as would be sent by default. A panic occurs if it is not. For the
  +    predata ACL, note that the default success code is 354, not 2xx.
  +
  +    However, notwithstanding the previous paragraph, for the QUIT ACL, unlike
  +    the others, the message modifier cannot override the 221 response code.
  +
  +    In the case of the "connect" ACL, accepting with a message modifier
  +    overrides the value of smtp_banner.
  +
  +    The ACL test specified by acl_smtp_helo happens when the client issues the
  +    HELO or EHLO commands, after the tests specified by helo_accept_junk_hosts,
  +    helo_allow_chars and helo(_try)_verify_hosts. An acceptance message
  +    modifier for EHLO/HELO may not contain more than one line (it will be
  +    truncated at the first newline and a panic logged), and it cannot affect
  +    the EHLO options.
  +



Version 4.63

  Index: ACKNOWLEDGMENTS
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/ACKNOWLEDGMENTS,v
  retrieving revision 1.63
  retrieving revision 1.64
  diff -u -r1.63 -r1.64
  --- ACKNOWLEDGMENTS    13 Nov 2006 11:26:37 -0000    1.63
  +++ ACKNOWLEDGMENTS    14 Nov 2006 16:40:36 -0000    1.64
  @@ -1,4 +1,4 @@
  -$Cambridge: exim/exim-src/ACKNOWLEDGMENTS,v 1.63 2006/11/13 11:26:37 ph10 Exp $
  +$Cambridge: exim/exim-src/ACKNOWLEDGMENTS,v 1.64 2006/11/14 16:40:36 ph10 Exp $


EXIM ACKNOWLEDGEMENTS

@@ -20,7 +20,7 @@
Philip Hazel

Lists created: 20 November 2002
-Last updated: 13 November 2006
+Last updated: 14 November 2006


   THE OLD LIST
  @@ -174,6 +174,7 @@
   Bob Johannessen           Patch for Sieve envelope tests bug
                             Patch for negative uid/gid bug
   Brad Jorsch               Patch for bitwise logical operators
  +                          Patch for using "message" on acceptance
   Christian Kellner         Patch for LDAP dereferencing
   Alex Kiernan              Patches for libradius
                             Diagnosis of milliwait clock-backwards bug


  Index: acl.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/acl.c,v
  retrieving revision 1.66
  retrieving revision 1.67
  diff -u -r1.66 -r1.67
  --- acl.c    25 Sep 2006 10:14:20 -0000    1.66
  +++ acl.c    14 Nov 2006 16:40:36 -0000    1.67
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/acl.c,v 1.66 2006/09/25 10:14:20 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/acl.c,v 1.67 2006/11/14 16:40:36 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -27,9 +27,20 @@
     { US"accept", US"defer", US"deny", US"discard", US"drop", US"require",
       US"warn" };


  -/* For each verb, the condition for which "message" is used */
  -
  -static int msgcond[] = { FAIL, OK, OK, FAIL, OK, FAIL, OK };
  +/* For each verb, the conditions for which "message" or "log_message" are used
  +are held as a bitmap. This is to avoid expanding the strings unnecessarily. For
  +"accept", the FAIL case is used only after "endpass", but that is selected in
  +the code. */
  +
  +static int msgcond[] = {
  +  (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP),  /* accept */
  +  (1<<OK),                               /* defer */
  +  (1<<OK),                               /* deny */
  +  (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP),  /* discard */
  +  (1<<OK),                               /* drop */
  +  (1<<FAIL) | (1<<FAIL_DROP),            /* require */
  +  (1<<OK)                                /* warn */
  +  };


/* ACL condition and modifier codes - keep in step with the table that
follows, and the cond_expand_at_top and uschar cond_modifiers tables lower
@@ -3035,13 +3046,8 @@


/* If the result is the one for which "message" and/or "log_message" are used,
-handle the values of these options. Most verbs have but a single return for
-which the messages are relevant, but for "discard", it's useful to have the log
-message both when it succeeds and when it fails. Also, for an "accept" that
-appears in a QUIT ACL, we want to handle the user message. Since only "accept"
-and "warn" are permitted in that ACL, we don't need to test the verb.
-
-These modifiers act in different ways:
+handle the values of these modifiers. If there isn't a log message set, we make
+it the same as the user message.

"message" is a user message that will be included in an SMTP response. Unless
it is empty, it overrides any previously set user message.
@@ -3049,23 +3055,29 @@
"log_message" is a non-user message, and it adds to any existing non-user
message that is already set.

-If there isn't a log message set, we make it the same as the user message. */
+Most verbs have but a single return for which the messages are relevant, but
+for "discard", it's useful to have the log message both when it succeeds and
+when it fails. For "accept", the message is used in the OK case if there is no
+"endpass", but (for backwards compatibility) in the FAIL case if "endpass" is
+present. */

  -if (((rc == FAIL_DROP)? FAIL : rc) == msgcond[verb] ||
  -    (verb == ACL_DISCARD && rc == OK) ||
  -    (where == ACL_WHERE_QUIT))
  +if (*epp && rc == OK) user_message = NULL;
  +
  +if (((1<<rc) & msgcond[verb]) != 0)
     {
     uschar *expmessage;
  +  uschar *old_user_msgptr = *user_msgptr;
  +  uschar *old_log_msgptr = (*log_msgptr != NULL)? *log_msgptr : old_user_msgptr;


     /* If the verb is "warn", messages generated by conditions (verification or
  -  nested ACLs) are discarded. Only messages specified at this level are used.
  +  nested ACLs) are always discarded. This also happens for acceptance verbs
  +  when they actually do accept. Only messages specified at this level are used.
     However, the value of an existing message is available in $acl_verify_message
     during expansions. */


  -  uschar *old_user_msgptr = *user_msgptr;
  -  uschar *old_log_msgptr = (*log_msgptr != NULL)? *log_msgptr : old_user_msgptr;
  -
  -  if (verb == ACL_WARN) *log_msgptr = *user_msgptr = NULL;
  +  if (verb == ACL_WARN ||
  +      (rc == OK && (verb == ACL_ACCEPT || verb == ACL_DISCARD)))
  +    *log_msgptr = *user_msgptr = NULL;


     if (user_message != NULL)
       {
  @@ -3595,10 +3607,10 @@
     return ERROR;
     }


-/* Before giving an error response, take a look at the length of any user
-message, and split it up into multiple lines if possible. */
+/* Before giving a response, take a look at the length of any user message, and
+split it up into multiple lines if possible. */

  -if (rc != OK && *user_msgptr != NULL && Ustrlen(*user_msgptr) > 75)
  +if (*user_msgptr != NULL && Ustrlen(*user_msgptr) > 75)
     {
     uschar *s = *user_msgptr = string_copy(*user_msgptr);
     uschar *ss = s;


  Index: functions.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/functions.h,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- functions.h    24 Oct 2006 12:56:06 -0000    1.30
  +++ functions.h    14 Nov 2006 16:40:36 -0000    1.31
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/functions.h,v 1.30 2006/10/24 12:56:06 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/functions.h,v 1.31 2006/11/14 16:40:36 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -269,6 +269,7 @@
   extern BOOL    smtp_get_port(uschar *, address_item *, int *, uschar *);
   extern int     smtp_getc(void);
   extern int     smtp_handle_acl_fail(int, int, uschar *, uschar *);
  +extern void    smtp_message_code(uschar **, int *, uschar **, uschar **);
   extern BOOL    smtp_read_response(smtp_inblock *, uschar *, int, int, int);
   extern void    smtp_respond(uschar *, int, BOOL, uschar *);
   extern void    smtp_send_prohibition_message(int, uschar *);


  Index: receive.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/receive.c,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- receive.c    10 Oct 2006 15:36:50 -0000    1.30
  +++ receive.c    14 Nov 2006 16:40:36 -0000    1.31
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/receive.c,v 1.30 2006/10/10 15:36:50 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/receive.c,v 1.31 2006/11/14 16:40:36 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -1042,18 +1042,21 @@


   /* check if it is a MIME message */
   my_headerlist = header_list;
  -while (my_headerlist != NULL) {
  +while (my_headerlist != NULL)
  +  {
     /* skip deleted headers */
  -  if (my_headerlist->type == '*') {
  +  if (my_headerlist->type == '*')
  +    {
       my_headerlist = my_headerlist->next;
       continue;
  -  };
  -  if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0) {
  +    }
  +  if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0)
  +    {
       DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n");
       goto DO_MIME_ACL;
  -  };
  +    }
     my_headerlist = my_headerlist->next;
  -};
  +  }


DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n");
return TRUE;
@@ -1080,18 +1083,21 @@
rc = mime_acl_check(acl, mbox_file, NULL, &user_msg, &log_msg);
(void)fclose(mbox_file);

  -if (Ustrlen(rfc822_file_path) > 0) {
  +if (Ustrlen(rfc822_file_path) > 0)
  +  {
     mime_part_count = mime_part_count_buffer;


  -  if (unlink(CS rfc822_file_path) == -1) {
  +  if (unlink(CS rfc822_file_path) == -1)
  +    {
       log_write(0, LOG_PANIC,
            "acl_smtp_mime: can't unlink RFC822 spool file, skipping.");
         goto END_MIME_ACL;
  -  };
  -};
  +    }
  +  }


   /* check if we must check any message/rfc822 attachments */
  -if (rc == OK) {
  +if (rc == OK)
  +  {
     uschar temp_path[1024];
     int n;
     struct dirent *entry;
  @@ -1100,33 +1106,37 @@
     (void)string_format(temp_path, 1024, "%s/scan/%s", spool_directory,
       message_id);


  - tempdir = opendir(CS temp_path);
  - n = 0;
  - do {
  -   entry = readdir(tempdir);
  -   if (entry == NULL) break;
  -    if (strncmpic(US entry->d_name,US"__rfc822_",9) == 0) {
  +  tempdir = opendir(CS temp_path);
  +  n = 0;
  +  do
  +    {
  +    entry = readdir(tempdir);
  +    if (entry == NULL) break;
  +    if (strncmpic(US entry->d_name,US"__rfc822_",9) == 0)
  +      {
         (void)string_format(rfc822_file_path, 2048,"%s/scan/%s/%s", spool_directory, message_id, entry->d_name);
  -     debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path);
  -     break;
  -    };
  - } while (1);
  - closedir(tempdir);
  +      debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path);
  +      break;
  +      }
  +    } while (1);
  +  closedir(tempdir);


  -  if (entry != NULL) {
  +  if (entry != NULL)
  +    {
       mbox_file = Ufopen(rfc822_file_path,"rb");
  -    if (mbox_file == NULL) {
  +    if (mbox_file == NULL)
  +      {
         log_write(0, LOG_PANIC,
            "acl_smtp_mime: can't open RFC822 spool file, skipping.");
         unlink(CS rfc822_file_path);
         goto END_MIME_ACL;
  -    };
  +      }
       /* set RFC822 expansion variable */
       mime_is_rfc822 = 1;
       mime_part_count_buffer = mime_part_count;
       goto MIME_ACL_CHECK;
  -  };
  -};
  +    }
  +  }


   END_MIME_ACL:
   add_acl_headers(US"MIME");
  @@ -1144,7 +1154,7 @@
     *smtp_reply_ptr = US"";       /* Indicate reply already sent */
     message_id[0] = 0;            /* Indicate no message accepted */
     return FALSE;                 /* Cause skip to end of receive function */
  -  };
  +  }


return TRUE;
}
@@ -1276,9 +1286,10 @@
uschar *errmsg, *s;
struct stat statbuf;

-/* Final message to give to SMTP caller */
+/* Final message to give to SMTP caller, and messages from ACLs */

uschar *smtp_reply = NULL;
+uschar *user_msg, *log_msg;

/* Working header pointers */

@@ -2902,6 +2913,7 @@
*/

deliver_datafile = data_fd;
+user_msg = NULL;

   if (recipients_count == 0)
     {
  @@ -2931,7 +2943,6 @@


       if (acl_smtp_data != NULL && recipients_count > 0)
         {
  -      uschar *user_msg, *log_msg;
         rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg);
         add_acl_headers(US"DATA");
         if (rc == DISCARD)
  @@ -3491,12 +3502,28 @@
         if (fake_response != OK)
           smtp_respond((fake_response == DEFER)? US"450" : US"550", 3, TRUE,
             fake_response_text);
  +
  +      /* An OK response is required; use "message" text if present. */
  +
  +      else if (user_msg != NULL)
  +        {
  +        uschar *code = US"250";
  +        int len = 3;
  +        smtp_message_code(&code, &len, &user_msg, NULL);
  +        smtp_respond(code, len, TRUE, user_msg);
  +        }
  +
  +      /* Default OK response */
  +
         else
           smtp_printf("250 OK id=%s\r\n", message_id);
         if (host_checking)
           fprintf(stdout,
             "\n**** SMTP testing: that is not a real message id!\n\n");
         }
  +
  +    /* smtp_reply was previously set */
  +
       else if (smtp_reply[0] != 0)
         {
         if (fake_response != OK && (smtp_reply[0] == '2'))


  Index: smtp_in.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/smtp_in.c,v
  retrieving revision 1.46
  retrieving revision 1.47
  diff -u -r1.46 -r1.47
  --- smtp_in.c    23 Oct 2006 10:55:10 -0000    1.46
  +++ smtp_in.c    14 Nov 2006 16:40:36 -0000    1.47
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/smtp_in.c,v 1.46 2006/10/23 10:55:10 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/smtp_in.c,v 1.47 2006/11/14 16:40:36 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -874,7 +874,7 @@


/* Warning log messages are also saved in malloc store. They are saved to avoid
repetition in the same message, but it seems right to repeat them for different
-messagess. */
+messages. */

   while (acl_warn_logged != NULL)
     {
  @@ -1141,7 +1141,9 @@
   smtp_start_session(void)
   {
   int size = 256;
  -int ptr;
  +int ptr, esclen;
  +uschar *user_msg, *log_msg;
  +uschar *code, *esc;
   uschar *p, *s, *ss;


/* Default values for certain variables */
@@ -1571,10 +1573,10 @@

/* Run the ACL if it exists */

  +user_msg = NULL;
   if (acl_smtp_connect != NULL)
     {
     int rc;
  -  uschar *user_msg, *log_msg;
     rc = acl_check(ACL_WHERE_CONNECT, NULL, acl_smtp_connect, &user_msg,
       &log_msg);
     if (rc != OK)
  @@ -1587,10 +1589,28 @@
   /* Output the initial message for a two-way SMTP connection. It may contain
   newlines, which then cause a multi-line response to be given. */


  -s = expand_string(smtp_banner);
  -if (s == NULL)
  -  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Expansion of \"%s\" (smtp_banner) "
  -    "failed: %s", smtp_banner, expand_string_message);
  +code = US"220";   /* Default status code */
  +esc = US"";       /* Default extended status code */
  +esclen = 0;       /* Length of esc */
  +
  +if (user_msg == NULL)
  +  {
  +  s = expand_string(smtp_banner);
  +  if (s == NULL)
  +    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Expansion of \"%s\" (smtp_banner) "
  +      "failed: %s", smtp_banner, expand_string_message);
  +  }
  +else
  +  {
  +  int codelen = 3;
  +  s = user_msg;
  +  smtp_message_code(&code, &codelen, &s, NULL);
  +  if (codelen > 3)
  +    {
  +    esc = code + 4;
  +    esclen = codelen - 4;
  +    }
  +  }


/* Remove any terminating newlines; might as well remove trailing space too */

  @@ -1615,16 +1635,18 @@
     {
     int len;
     uschar *linebreak = Ustrchr(p, '\n');
  +  ss = string_cat(ss, &size, &ptr, code, 3);
     if (linebreak == NULL)
       {
       len = Ustrlen(p);
  -    ss = string_cat(ss, &size, &ptr, US"220 ", 4);
  +    ss = string_cat(ss, &size, &ptr, US" ", 1);
       }
     else
       {
       len = linebreak - p;
  -    ss = string_cat(ss, &size, &ptr, US"220-", 4);
  +    ss = string_cat(ss, &size, &ptr, US"-", 1);
       }
  +  ss = string_cat(ss, &size, &ptr, esc, esclen);
     ss = string_cat(ss, &size, &ptr, p, len);
     ss = string_cat(ss, &size, &ptr, US"\r\n", 2);
     p += len;
  @@ -1771,7 +1793,7 @@


   Arguments:
     code          SMTP code, may involve extended status codes
  -  codelen       length of smtp code; uf > 3 there's an ESC
  +  codelen       length of smtp code; if > 3 there's an ESC
     final         FALSE if the last line isn't the final line
     msg           message text, possibly containing newlines


@@ -1819,6 +1841,62 @@


   /*************************************************
  +*            Parse user SMTP message             *
  +*************************************************/
  +
  +/* This function allows for user messages overriding the response code details
  +by providing a suitable response code string at the start of the message
  +user_msg. Check the message for starting with a response code and optionally an
  +extended status code. If found, check that the first digit is valid, and if so,
  +change the code pointer and length to use the replacement. An invalid code
  +causes a panic log; in this case, if the log messages is the same as the user
  +message, we must also adjust the value of the log message to show the code that
  +is actually going to be used (the original one).
  +
  +This function is global because it is called from receive.c as well as within
  +this module.
  +
  +Arguments:
  +  code          SMTP code, may involve extended status codes
  +  codelen       length of smtp code; if > 3 there's an ESC
  +  msg           message text
  +  log_msg       optional log message, to be adjusted with the new SMTP code
  +
  +Returns:        nothing
  +*/
  +
  +void
  +smtp_message_code(uschar **code, int *codelen, uschar **msg, uschar **log_msg)
  +{
  +int n;
  +int ovector[3];
  +
  +if (msg == NULL || *msg == NULL) return;
  +
  +n = pcre_exec(regex_smtp_code, NULL, CS *msg, Ustrlen(*msg), 0,
  +  PCRE_EOPT, ovector, sizeof(ovector)/sizeof(int));
  +if (n < 0) return;
  +
  +if ((*msg)[0] != (*code)[0])
  +  {
  +  log_write(0, LOG_MAIN|LOG_PANIC, "configured error code starts with "
  +    "incorrect digit (expected %c) in \"%s\"", (*code)[0], *msg);
  +  if (log_msg != NULL && *log_msg == *msg)
  +    *log_msg = string_sprintf("%s %s", *code, *log_msg + ovector[1]);
  +  }
  +else
  +  {
  +  *code = *msg;
  +  *codelen = ovector[1];    /* Includes final space */
  +  }
  +*msg += ovector[1];         /* Chop the code off the message */
  +return;
  +}
  +
  +
  +
  +
  +/*************************************************
   *           Handle an ACL failure                *
   *************************************************/


@@ -1858,7 +1936,6 @@
{
BOOL drop = rc == FAIL_DROP;
int codelen = 3;
-int ovector[3];
uschar *smtp_code;
uschar *lognl;
uschar *sender_info = US"";
@@ -1874,40 +1951,10 @@

if (drop) rc = FAIL;

-/* Set the default SMTP code */
+/* Set the default SMTP code, and allow a user message to change it. */

   smtp_code = (rc != FAIL)? US"451" : acl_wherecodes[where];
  -
  -/* Check a user message for starting with a response code and optionally an
  -extended status code. If found, check that the first digit is valid, and if so,
  -use it instead of the default code. */
  -
  -if (user_msg != NULL)
  -  {
  -  int n = pcre_exec(regex_smtp_code, NULL, CS user_msg, Ustrlen(user_msg), 0,
  -    PCRE_EOPT, ovector, sizeof(ovector)/sizeof(int));
  -  if (n >= 0)
  -    {
  -    if (user_msg[0] != smtp_code[0])
  -      {
  -      log_write(0, LOG_MAIN|LOG_PANIC, "configured error code starts with "
  -        "incorrect digit (expected %c) in \"%s\"", smtp_code[0], user_msg);
  -
  -      /* If log_msg == user_msg (the default set in acl.c if no log message is
  -      specified, we must adjust the log message to show the code that is
  -      actually going to be used. */
  -
  -      if (log_msg == user_msg)
  -        log_msg = string_sprintf("%s %s", smtp_code, log_msg + ovector[1]);
  -      }
  -    else
  -      {
  -      smtp_code = user_msg;
  -      codelen = ovector[1];    /* Includes final space */
  -      }
  -    user_msg += ovector[1];    /* Chop the code off the message */
  -    }
  -  }
  +smtp_message_code(&smtp_code, &codelen, &user_msg, &log_msg);


/* We used to have sender_address here; however, there was a bug that was not
updating sender_address after a rewrite during a verify. When this bug was
@@ -2157,6 +2204,33 @@


   /*************************************************
  +*        Send user response message              *
  +*************************************************/
  +
  +/* This function is passed a default response code and a user message. It calls
  +smtp_message_code() to check and possibly modify the response code, and then
  +calls smtp_respond() to transmit the response. I put this into a function
  +just to avoid a lot of repetition.
  +
  +Arguments:
  +  code         the response code
  +  user_msg     the user message
  +
  +Returns:       nothing
  +*/
  +
  +static void
  +smtp_user_msg(uschar *code, uschar *user_msg)
  +{
  +int len = 3;
  +smtp_message_code(&code, &len, &user_msg, NULL);
  +smtp_respond(code, len, TRUE, user_msg);
  +}
  +
  +
  +
  +
  +/*************************************************
   *       Initialize for SMTP incoming message     *
   *************************************************/


  @@ -2226,7 +2300,8 @@
     uschar *etrn_command;
     uschar *etrn_serialize_key;
     uschar *errmess;
  -  uschar *user_msg, *log_msg;
  +  uschar *log_msg, *smtp_code;
  +  uschar *user_msg = NULL;
     uschar *recipient = NULL;
     uschar *hello = NULL;
     uschar *set_id = NULL;
  @@ -2563,26 +2638,11 @@
           }
         }


  -    /* The EHLO/HELO command is acceptable. Reset the protocol and the state,
  -    abandoning any previous message. */
  -
  -    received_protocol = (esmtp?
  -      protocols[pextend +
  -        ((sender_host_authenticated != NULL)? pauthed : 0) +
  -        ((tls_active >= 0)? pcrpted : 0)]
  -      :
  -      protocols[pnormal + ((tls_active >= 0)? pcrpted : 0)])
  -      +
  -      ((sender_host_address != NULL)? pnlocal : 0);
  -
  -    smtp_reset(reset_point);
  -    toomany = FALSE;
  -
  -    /* Generate an OK reply, including the ident if present, and also
  -    the IP address if present. Reflecting back the ident is intended
  -    as a deterrent to mail forgers. For maximum efficiency, and also
  -    because some broken systems expect each response to be in a single
  -    packet, arrange that it is sent in one write(). */
  +    /* Generate an OK reply. The default string includes the ident if present,
  +    and also the IP address if present. Reflecting back the ident is intended
  +    as a deterrent to mail forgers. For maximum efficiency, and also because
  +    some broken systems expect each response to be in a single packet, arrange
  +    that the entire reply is sent in one write(). */


       auth_advertised = FALSE;
       pipelining_advertised = FALSE;
  @@ -2590,21 +2650,44 @@
       tls_advertised = FALSE;
       #endif


  -    s = string_sprintf("250 %s Hello %s%s%s",
  -      smtp_active_hostname,
  -      (sender_ident == NULL)?  US"" : sender_ident,
  -      (sender_ident == NULL)?  US"" : US" at ",
  -      (sender_host_name == NULL)? sender_helo_name : sender_host_name);
  -
  -    ptr = Ustrlen(s);
  -    size = ptr + 1;
  -
  -    if (sender_host_address != NULL)
  -      {
  -      s = string_cat(s, &size, &ptr, US" [", 2);
  -      s = string_cat(s, &size, &ptr, sender_host_address,
  -        Ustrlen(sender_host_address));
  -      s = string_cat(s, &size, &ptr, US"]", 1);
  +    smtp_code = US"250";        /* Default response code */
  +    if (user_msg == NULL)
  +      {
  +      s = string_sprintf("%.3s %s Hello %s%s%s",
  +        smtp_code,
  +        smtp_active_hostname,
  +        (sender_ident == NULL)?  US"" : sender_ident,
  +        (sender_ident == NULL)?  US"" : US" at ",
  +        (sender_host_name == NULL)? sender_helo_name : sender_host_name);
  +
  +      ptr = Ustrlen(s);
  +      size = ptr + 1;
  +
  +      if (sender_host_address != NULL)
  +        {
  +        s = string_cat(s, &size, &ptr, US" [", 2);
  +        s = string_cat(s, &size, &ptr, sender_host_address,
  +          Ustrlen(sender_host_address));
  +        s = string_cat(s, &size, &ptr, US"]", 1);
  +        }
  +      }
  +
  +    /* A user-supplied EHLO greeting may not contain more than one line */
  +
  +    else
  +      {
  +      char *ss;
  +      int codelen = 3;
  +      smtp_message_code(&smtp_code, &codelen, &user_msg, NULL);
  +      s = string_sprintf("%.*s %s", codelen, smtp_code, user_msg);
  +      if ((ss = strpbrk(CS s, "\r\n")) != NULL)
  +        {
  +        log_write(0, LOG_MAIN|LOG_PANIC, "EHLO/HELO response must not contain "
  +          "newlines: message truncated: %s", string_printing(s));
  +        *ss = 0;
  +        }
  +      ptr = Ustrlen(s);
  +      size = ptr + 1;
         }


       s = string_cat(s, &size, &ptr, US"\r\n", 2);
  @@ -2624,12 +2707,14 @@


         if (thismessage_size_limit > 0)
           {
  -        sprintf(CS big_buffer, "250-SIZE %d\r\n", thismessage_size_limit);
  +        sprintf(CS big_buffer, "%.3s-SIZE %d\r\n", smtp_code,
  +          thismessage_size_limit);
           s = string_cat(s, &size, &ptr, big_buffer, Ustrlen(big_buffer));
           }
         else
           {
  -        s = string_cat(s, &size, &ptr, US"250-SIZE\r\n", 10);
  +        s = string_cat(s, &size, &ptr, smtp_code, 3);
  +        s = string_cat(s, &size, &ptr, US"-SIZE\r\n", 7);
           }


         /* Exim does not do protocol conversion or data conversion. It is 8-bit
  @@ -2640,14 +2725,18 @@
         provided as an option. */


         if (accept_8bitmime)
  -        s = string_cat(s, &size, &ptr, US"250-8BITMIME\r\n", 14);
  +        {
  +        s = string_cat(s, &size, &ptr, smtp_code, 3);
  +        s = string_cat(s, &size, &ptr, US"-8BITMIME\r\n", 11);
  +        }


         /* Advertise ETRN if there's an ACL checking whether a host is
         permitted to issue it; a check is made when any host actually tries. */


         if (acl_smtp_etrn != NULL)
           {
  -        s = string_cat(s, &size, &ptr, US"250-ETRN\r\n", 10);
  +        s = string_cat(s, &size, &ptr, smtp_code, 3);
  +        s = string_cat(s, &size, &ptr, US"-ETRN\r\n", 7);
           }


         /* Advertise EXPN if there's an ACL checking whether a host is
  @@ -2655,7 +2744,8 @@


         if (acl_smtp_expn != NULL)
           {
  -        s = string_cat(s, &size, &ptr, US"250-EXPN\r\n", 10);
  +        s = string_cat(s, &size, &ptr, smtp_code, 3);
  +        s = string_cat(s, &size, &ptr, US"-EXPN\r\n", 7);
           }


         /* Exim is quite happy with pipelining, so let the other end know that
  @@ -2663,7 +2753,8 @@


         if (verify_check_host(&pipelining_advertise_hosts) == OK)
           {
  -        s = string_cat(s, &size, &ptr, US"250-PIPELINING\r\n", 16);
  +        s = string_cat(s, &size, &ptr, smtp_code, 3);
  +        s = string_cat(s, &size, &ptr, US"-PIPELINING\r\n", 13);
           sync_cmd_limit = NON_SYNC_CMD_PIPELINING;
           pipelining_advertised = TRUE;
           }
  @@ -2693,7 +2784,8 @@
                 int saveptr;
                 if (first)
                   {
  -                s = string_cat(s, &size, &ptr, US"250-AUTH", 8);
  +                s = string_cat(s, &size, &ptr, smtp_code, 3);
  +                s = string_cat(s, &size, &ptr, US"-AUTH", 5);
                   first = FALSE;
                   auth_advertised = TRUE;
                   }
  @@ -2719,14 +2811,16 @@
         if (tls_active < 0 &&
             verify_check_host(&tls_advertise_hosts) != FAIL)
           {
  -        s = string_cat(s, &size, &ptr, US"250-STARTTLS\r\n", 14);
  +        s = string_cat(s, &size, &ptr, smtp_code, 3);
  +        s = string_cat(s, &size, &ptr, US"-STARTTLS\r\n", 11);
           tls_advertised = TRUE;
           }
         #endif


         /* Finish off the multiline reply with one that is always available. */


  -      s = string_cat(s, &size, &ptr, US"250 HELP\r\n", 10);
  +      s = string_cat(s, &size, &ptr, smtp_code, 3);
  +      s = string_cat(s, &size, &ptr, US" HELP\r\n", 7);
         }


       /* Terminate the string (for debug), write it, and note that HELO/EHLO
  @@ -2747,6 +2841,20 @@
         debug_printf("SMTP>> %s", s);
         }
       helo_seen = TRUE;
  +
  +    /* Reset the protocol and the state, abandoning any previous message. */
  +
  +    received_protocol = (esmtp?
  +      protocols[pextend +
  +        ((sender_host_authenticated != NULL)? pauthed : 0) +
  +        ((tls_active >= 0)? pcrpted : 0)]
  +      :
  +      protocols[pnormal + ((tls_active >= 0)? pcrpted : 0)])
  +      +
  +      ((sender_host_address != NULL)? pnlocal : 0);
  +
  +    smtp_reset(reset_point);
  +    toomany = FALSE;
       break;   /* HELO/EHLO */



@@ -3024,12 +3132,12 @@

       if (rc == OK || rc == DISCARD)
         {
  -      smtp_printf("250 OK\r\n");
  +      if (user_msg == NULL) smtp_printf("250 OK\r\n");
  +        else smtp_user_msg(US"250", user_msg);
         smtp_delay_rcpt = smtp_rlr_base;
         recipients_discarded = (rc == DISCARD);
         was_rej_mail = FALSE;
         }
  -
       else
         {
         done = smtp_handle_acl_fail(ACL_WHERE_MAIL, rc, user_msg, log_msg);
  @@ -3184,7 +3292,8 @@


       if (rc == OK)
         {
  -      smtp_printf("250 Accepted\r\n");
  +      if (user_msg == NULL) smtp_printf("250 Accepted\r\n");
  +        else smtp_user_msg(US"250", user_msg);
         receive_add_recipient(recipient, -1);
         }


@@ -3192,7 +3301,8 @@

       else if (rc == DISCARD)
         {
  -      smtp_printf("250 Accepted\r\n");
  +      if (user_msg == NULL) smtp_printf("250 Accepted\r\n");
  +        else smtp_user_msg(US"250", user_msg);
         rcpt_fail_count++;
         discarded = TRUE;
         log_write(0, LOG_MAIN|LOG_REJECT, "%s F=<%s> rejected RCPT %s: "
  @@ -3259,7 +3369,9 @@


       if (rc == OK)
         {
  -      smtp_printf("354 Enter message, ending with \".\" on a line by itself\r\n");
  +      if (user_msg == NULL)
  +        smtp_printf("354 Enter message, ending with \".\" on a line by itself\r\n");
  +      else smtp_user_msg(US"354", user_msg);
         done = 3;
         message_ended = END_NOTENDED;   /* Indicate in middle of data */
         }
  @@ -3461,12 +3573,11 @@
           log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s",
             log_msg);
         }
  -    else user_msg = NULL;


       if (user_msg == NULL)
         smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
       else
  -      smtp_printf("221 %s\r\n", user_msg);
  +      smtp_respond(US"221", 3, TRUE, user_msg);


       #ifdef SUPPORT_TLS
       tls_close(TRUE);
  @@ -3606,7 +3717,8 @@
           debug_printf("ETRN command is: %s\n", etrn_command);
           debug_printf("ETRN command execution skipped\n");
           }
  -      smtp_printf("250 OK\r\n");
  +      if (user_msg == NULL) smtp_printf("250 OK\r\n");
  +        else smtp_user_msg(US"250", user_msg);
         break;
         }


  @@ -3682,7 +3794,11 @@
         smtp_printf("458 Unable to fork process\r\n");
         if (smtp_etrn_serialize) enq_end(etrn_serialize_key);
         }
  -    else smtp_printf("250 OK\r\n");
  +    else
  +      {
  +      if (user_msg == NULL) smtp_printf("250 OK\r\n");
  +        else smtp_user_msg(US"250", user_msg);
  +      }


       signal(SIGCHLD, oldsignal);
       break;


  Index: runtest
  ===================================================================
  RCS file: /home/cvs/exim/exim-test/runtest,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- runtest    7 Nov 2006 15:11:34 -0000    1.18
  +++ runtest    14 Nov 2006 16:40:36 -0000    1.19
  @@ -1,6 +1,6 @@
   #! /usr/bin/perl -w


-# $Cambridge: exim/exim-test/runtest,v 1.18 2006/11/07 15:11:34 ph10 Exp $
+# $Cambridge: exim/exim-test/runtest,v 1.19 2006/11/14 16:40:36 ph10 Exp $

   ###############################################################################
   # This is the controlling script for the "new" test suite for Exim. It should #
  @@ -1514,7 +1514,7 @@
     # This gives the server time to get started; otherwise the next
     # process may not find it there when it expects it.


  -  select(undef, undef, undef, 0.05);
  +  select(undef, undef, undef, 0.5);
     return 3;
     }



Index: 0546
====================================================================
# Exim test configuration 0546

HELO_MSG=One line
RCPT_MSG=RCPT is OK

exim_path = EXIM_PATH
host_lookup_order = bydns
rfc1413_query_timeout = 0s
spool_directory = DIR/spool
log_file_path = DIR/spool/log/%slog
gecos_pattern = ""
gecos_name = CALLER_NAME

# ----- Main settings -----

acl_smtp_helo = check_helo
acl_smtp_mail = check_mail
acl_smtp_rcpt = check_rcpt
acl_smtp_data = check_data
acl_smtp_predata = check_predata

qualify_domain = test.ex
queue_only


# ----- ACLs -----

begin acl

  check_helo:
    accept     message = HELO_MSG


  check_mail:
    accept     message = 299 MAIL is\nOK


  check_rcpt:
    accept     message = RCPT_MSG


  check_data:
    accept     message = 288 I like the data


  check_predata:
    accept     message = 300 Funny, but OK code



# End

  Index: 0023
  ===================================================================
  RCS file: /home/cvs/exim/exim-test/confs/0023,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- 0023    19 Apr 2006 11:11:12 -0000    1.2
  +++ 0023    14 Nov 2006 16:40:36 -0000    1.3
  @@ -203,7 +203,7 @@
     accept


   acl_56_56_57:
  -  accept  message = denied by condition
  +  accept  message = accepted by condition
             condition = ${substr_5:$local_part}


acl_56_56_58:

Index: 0546
====================================================================
1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@??? U=CALLER P=local-esmtp S=sss
1999-03-02 09:44:33 EHLO/HELO response must not contain newlines: message truncated: 250 Two\nlines
1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 2) in "450 Bad number"

Index: 0546
====================================================================
1999-03-02 09:44:33 EHLO/HELO response must not contain newlines: message truncated: 250 Two\nlines
1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 2) in "450 Bad number"

Index: 0546
====================================================================
# User messages for "accept" verbs
need_ipv4
#
exim -bs
ehlo a.b.c
mail from:<>
rcpt to:<userx@???>
data
This is a test
.
quit
****
exim -bs -DHELO_MSG='Two\nlines' -DRCPT_MSG='450 Bad number'
ehlo a.b.c
mail from:<>
rcpt to:<userx@???>
quit
****
no_msglog_check

Index: 0546
====================================================================
1999-03-02 09:44:33 EHLO/HELO response must not contain newlines: message truncated: 250 Two\nlines
1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 2) in "450 Bad number"

Index: 0546
====================================================================
220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250-One line
250-SIZE 52428800
250-PIPELINING
250 HELP
299-MAIL is
299 OK
250 RCPT is OK
300 Funny, but OK code
288 I like the data
221 the.local.host.name closing connection
220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250-Two
250-SIZE 52428800
250-PIPELINING
250 HELP
299-MAIL is
299 OK
250 Bad number
221 the.local.host.name closing connection

  Index: 0023
  ===================================================================
  RCS file: /home/cvs/exim/exim-test/stdout/0023,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- 0023    19 Apr 2006 11:11:13 -0000    1.2
  +++ 0023    14 Nov 2006 16:40:36 -0000    1.3
  @@ -422,7 +422,7 @@
   221 myhost.test.ex closing connection
   220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
   250 OK
  -250 Accepted
  +250 accepted by condition
   354 Enter message, ending with "." on a line by itself
   250 OK id=10HmbK-0005vi-00
   250 OK