PRDR support, if compiled with EXPERIMENTAL_PRDR
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 26 Jan 2013 23:21:37 +0000 (23:21 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 26 Jan 2013 23:21:37 +0000 (23:21 +0000)
42 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
doc/doc-txt/experimental-spec.txt
src/src/EDITME
src/src/acl.c
src/src/config.h.defaults
src/src/deliver.c
src/src/exim.c
src/src/globals.c
src/src/globals.h
src/src/macros.h
src/src/readconf.c
src/src/receive.c
src/src/smtp_in.c
src/src/structs.h
src/src/transports/smtp.c
src/src/transports/smtp.h
test/confs/5500 [new file with mode: 0644]
test/confs/5510 [new file with mode: 0644]
test/log/2002
test/log/2102
test/log/5500 [new file with mode: 0644]
test/log/5510 [new file with mode: 0644]
test/mail/2002.CALLER
test/mail/2102.CALLER
test/mail/5500.user1 [new file with mode: 0644]
test/mail/5500.userx [new file with mode: 0644]
test/rejectlog/5500 [new file with mode: 0644]
test/scripts/0000-Basic/0121
test/scripts/2000-GnuTLS/2002
test/scripts/2100-OpenSSL/2102
test/scripts/5500-PRDR/5500 [new file with mode: 0644]
test/scripts/5500-PRDR/5510 [new file with mode: 0644]
test/scripts/5500-PRDR/REQUIRES [new file with mode: 0644]
test/stderr/0121
test/stderr/5500 [new file with mode: 0644]
test/stdout/0121
test/stdout/2002
test/stdout/2102
test/stdout/5500 [new file with mode: 0644]
test/stdout/5510 [new file with mode: 0644]

index 7126fb0ed3a276bfcec563b871941bc8f8910198..9c03523bb828dfe8b9c619843754aa62030f0475 100644 (file)
@@ -19603,7 +19603,7 @@ so on when debugging driver configurations. For example, if a &%headers_add%&
 option is not working properly, &%debug_print%& could be used to output the
 variables it references. A newline is added to the text if it does not end with
 one.
-The variables &$transport_name$ and &$router_name$& contain the name of the
+The variables &$transport_name$& and &$router_name$& contain the name of the
 transport and the router that called it.
 
 
index 3a1e39c4577a0fe32af5758cd2601fb642a86e3b..2ce297fcb2a71462c4fd7c43a8cbfb82da42ca1f 100644 (file)
@@ -156,6 +156,18 @@ PP/15 Define SIOCGIFCONF_GIVES_ADDR for GNU Hurd.
 
 SC/01 Update eximstats to watch out for senders sending 'HELO [IpAddr]'
 
+JH/14 SMTP PRDR (http://www.eric-a-hall.com/specs/draft-hall-prdr-00.txt).
+      Server implementation by Todd Lyons, client by JH.
+      Only enabled when compiled with EXPERIMENTAL_PRDR.  A new
+      config variable "prdr_enable" controls whether the server
+      advertises the facility.  If the client requests PRDR a new
+      acl_data_smtp_prdr ACL is called once for each recipient, after
+      the body content is received and before the acl_smtp_data ACL.
+      The client is controlled by bolth of: a hosts_try_prdr option
+      on the smtp transport, and the server advertisement.
+      Default client logging of deliveries and rejections involving
+      PRDR are flagged with the string "PRDR".
+
 
 Exim version 4.80.1
 -------------------
index 70890b1853feb3f8072fd0686955f32cdda8b2b5..47c5f6fecd086a7c2a880641d8adf57f55585da2 100644 (file)
@@ -126,6 +126,9 @@ Version 4.82
     particularly for debug_print as -bt commandline option does not
     require privilege whereas -d does.
 
+18. If built with EXPERIMENTAL_PRDR, per-recipient data responses per a
+    proposed extension to SMTP from Eric Hall.
+
 
 Version 4.80
 ------------
index 7bb17883c77143434880f96872197045d72b3a00..f419bfedf3a73f5de8addd0d011ee855860337d8 100644 (file)
@@ -6,6 +6,34 @@ about experimental  features, all  of which  are unstable and
 liable to incompatible change.
 
 
+PRDR support
+--------------------------------------------------------------
+
+Per-Recipient Data Reponse is an SMTP extension proposed by Eric Hall
+in a (now-expired) IETF draft from 2007.  It's not hit mainstream
+use, but has apparently been implemented in the META1 MTA.
+
+There is mention at http://mail.aegee.org/intern/sendmail.html
+of a patch to sendmail "to make it PRDR capable".
+
+ ref: http://www.eric-a-hall.com/specs/draft-hall-prdr-00.txt
+
+If Exim is built with EXPERIMENTAL_PRDR there is a new config
+boolean "prdr_enable" which controls whether PRDR is advertised
+as part of an EHLO response, a new "acl_data_smtp_prdr" ACL
+(called for each recipient, after data arrives but before the
+data ACL), and a new smtp transport option "hosts_try_prdr".
+
+PRDR may be used to support per-user content filtering.  Without it
+one must defer any recipient after the first that has a different
+content-filter configuration.  With PRDR, the RCPT-time check
+for this can be disabled when the MAIL-time $smtp_command included
+"PRDR".  Any required difference in behaviour of the main DATA-time
+ACL should however depend on the PRDR-time ACL having run, as Exim
+will avoid doing so in some situations (eg.  single-recipient mails).
+
+
+
 OCSP Stapling support
 --------------------------------------------------------------
 
index 95a0c02f4dcd04ffd71cf3cf88f95caa02fbbf50..7de915ae9fd9981fe1095acd1c65ca9605f0e1c8 100644 (file)
@@ -460,6 +460,10 @@ EXIM_MONITOR=eximon.bin
 
 # EXPERIMENTAL_OCSP=yes
 
+# Uncomment the following line to add Per-Recipient-Data-Response support.
+
+# EXPERIMENTAL_PRDR=yes
+
 
 
 ###############################################################################
index 5af408c5c1346440df8bc6c2758c4d7a39fa7c18..f61d2dfdfe560ec04eab4711533a1375ee4c4e16 100644 (file)
@@ -368,6 +368,9 @@ static unsigned int cond_forbids[] = {
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* add_header */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif
     (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
     (1<<ACL_WHERE_DKIM)|
     (1<<ACL_WHERE_NOTSMTP_START)),
@@ -380,6 +383,9 @@ static unsigned int cond_forbids[] = {
   (1<<ACL_WHERE_AUTH)|                             /* bmi_optin */
     (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
     (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif
     (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
     (1<<ACL_WHERE_MAILAUTH)|
     (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
@@ -398,7 +404,11 @@ static unsigned int cond_forbids[] = {
 
   #ifdef EXPERIMENTAL_DCC
   (unsigned int)
-  ~((1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)),   /* dcc */
+  ~((1<<ACL_WHERE_DATA)|                           /* dcc */
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif /* EXPERIMENTAL_PRDR */
+    (1<<ACL_WHERE_NOTSMTP)),
   #endif
 
   #ifdef WITH_CONTENT_SCAN
@@ -410,7 +420,11 @@ static unsigned int cond_forbids[] = {
 
   #ifdef WITH_OLD_DEMIME
   (unsigned int)
-  ~((1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)),   /* demime */
+  ~((1<<ACL_WHERE_DATA)|                           /* demime */
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif /* EXPERIMENTAL_PRDR */
+    (1<<ACL_WHERE_NOTSMTP)),
   #endif
 
   #ifndef DISABLE_DKIM
@@ -425,7 +439,11 @@ static unsigned int cond_forbids[] = {
     (1<<ACL_WHERE_NOTSMTP_START),
 
   (unsigned int)
-  ~(1<<ACL_WHERE_RCPT),                            /* domains */
+  ~((1<<ACL_WHERE_RCPT)                            /* domains */
+  #ifdef EXPERIMENTAL_PRDR
+    |(1<<ACL_WHERE_PRDR)
+  #endif
+    ),
 
   (1<<ACL_WHERE_NOTSMTP)|                          /* encrypted */
     (1<<ACL_WHERE_CONNECT)|
@@ -438,7 +456,11 @@ static unsigned int cond_forbids[] = {
     (1<<ACL_WHERE_NOTSMTP_START),
 
   (unsigned int)
-  ~(1<<ACL_WHERE_RCPT),                            /* local_parts */
+  ~((1<<ACL_WHERE_RCPT)                             /* local_parts */
+  #ifdef EXPERIMENTAL_PRDR
+    |(1<<ACL_WHERE_PRDR)
+  #endif
+    ),
 
   0,                                               /* log_message */
 
@@ -448,7 +470,11 @@ static unsigned int cond_forbids[] = {
 
   #ifdef WITH_CONTENT_SCAN
   (unsigned int)
-  ~((1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)),   /* malware */
+  ~((1<<ACL_WHERE_DATA)|                           /* malware */
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif /* EXPERIMENTAL_PRDR */
+    (1<<ACL_WHERE_NOTSMTP)),
   #endif
 
   0,                                               /* message */
@@ -465,13 +491,20 @@ static unsigned int cond_forbids[] = {
 
   #ifdef WITH_CONTENT_SCAN
   (unsigned int)
-  ~((1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|    /* regex */
+  ~((1<<ACL_WHERE_DATA)|                           /* regex */
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif /* EXPERIMENTAL_PRDR */
+    (1<<ACL_WHERE_NOTSMTP)|
     (1<<ACL_WHERE_MIME)),
   #endif
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* remove_header */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif
     (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
     (1<<ACL_WHERE_NOTSMTP_START)),
 
@@ -491,7 +524,11 @@ static unsigned int cond_forbids[] = {
 
   #ifdef WITH_CONTENT_SCAN
   (unsigned int)
-  ~((1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)),   /* spam */
+  ~((1<<ACL_WHERE_DATA)|                           /* spam */
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif /* EXPERIMENTAL_PRDR */
+    (1<<ACL_WHERE_NOTSMTP)),
   #endif
 
   #ifdef EXPERIMENTAL_SPF
@@ -535,6 +572,9 @@ static unsigned int control_forbids[] = {
 
   #ifndef DISABLE_DKIM
   (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|      /* dkim_disable_verify */
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif /* EXPERIMENTAL_PRDR */
     (1<<ACL_WHERE_NOTSMTP_START),
   #endif
 
@@ -562,11 +602,13 @@ static unsigned int control_forbids[] = {
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* freeze */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+    // (1<<ACL_WHERE_PRDR)|    /* Not allow one user to freeze for all */
     (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME)),
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* queue_only */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+    // (1<<ACL_WHERE_PRDR)|    /* Not allow one user to freeze for all */
     (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME)),
 
   (unsigned int)
@@ -582,17 +624,24 @@ static unsigned int control_forbids[] = {
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* no_mbox_unspool */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+    // (1<<ACL_WHERE_PRDR)|    /* Not allow one user to freeze for all */
     (1<<ACL_WHERE_MIME)),
   #endif
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* fakedefer */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif /* EXPERIMENTAL_PRDR */
     (1<<ACL_WHERE_MIME)),
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* fakereject */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+  #ifdef EXPERIMENTAL_PRDR
+    (1<<ACL_WHERE_PRDR)|
+  #endif /* EXPERIMENTAL_PRDR */
     (1<<ACL_WHERE_MIME)),
 
   (1<<ACL_WHERE_NOTSMTP)|                          /* no_multiline */
@@ -4067,7 +4116,11 @@ sender_verified_failed = NULL;
 ratelimiters_cmd = NULL;
 log_reject_target = LOG_MAIN|LOG_REJECT;
 
-if (where == ACL_WHERE_RCPT)
+#ifdef EXPERIMENTAL_PRDR
+if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR )
+#else
+if (where == ACL_WHERE_RCPT )
+#endif
   {
   adb = address_defaults;
   addr = &adb;
@@ -4107,6 +4160,9 @@ If conn-failure, no action (and keep the spooled copy).
 switch (where)
 {
 case ACL_WHERE_RCPT:
+#ifdef EXPERIMENTAL_PRDR
+case ACL_WHERE_PRDR:
+#endif
   if( rcpt_count > 1 )
     cancel_cutthrough_connection("more than one recipient");
   else if (rc == OK  &&  cutthrough_delivery  &&  cutthrough_fd < 0)
index 361051858fee7176867592a07fbfad948baae0f1..b6772c275234d2463b010d89d229914c79ddee16 100644 (file)
@@ -166,6 +166,7 @@ it's a default value. */
 #define EXPERIMENTAL_BRIGHTMAIL
 #define EXPERIMENTAL_DCC
 #define EXPERIMENTAL_OCSP
+#define EXPERIMENTAL_PRDR
 #define EXPERIMENTAL_SPF
 #define EXPERIMENTAL_SRS
 
index e2605ab2cf9453783bc1e50c3b26f5023d8f1126..23e63d553d188426538ad0e826a0b72d090812db 100644 (file)
@@ -785,6 +785,11 @@ else
       }
     }
 
+  #ifdef EXPERIMENTAL_PRDR
+  if (addr->flags & af_prdr_used)
+    s = string_append(s, &size, &ptr, 1, US" PRDR");
+  #endif
+
   if ((log_extra_selector & LX_smtp_confirmation) != 0 &&
       addr->message != NULL)
     {
@@ -2913,6 +2918,11 @@ while (!done)
     while (*ptr++);
     break;
 
+#ifdef EXPERIMENTAL_PRDR
+    case 'P':
+      addr->flags |= af_prdr_used; break;
+#endif
+
     case 'A':
     if (addr == NULL)
       {
@@ -4017,6 +4027,10 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
         rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
        }
 
+      #ifdef EXPERIMENTAL_PRDR
+      if (addr->flags & af_prdr_used) rmt_dlv_checked_write(fd, "P", 1);
+      #endif
+
       /* Retry information: for most success cases this will be null. */
 
       for (r = addr->retries; r != NULL; r = r->next)
@@ -6101,6 +6115,11 @@ if (addr_remote != NULL)
     regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
   #endif
 
+  #ifdef EXPERIMENTAL_PRDR
+  if (regex_PRDR == NULL) regex_PRDR =
+    regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
+  #endif
+
   /* Now sort the addresses if required, and do the deliveries. The yield of
   do_remote_deliveries is FALSE when mua_wrapper is set and all addresses
   cannot be delivered in one transaction. */
index 91a3f7a4c676e2b831a859b453d3befe505b80dd..e66a9664d04b938a920fa9efb35c71137742a882 100644 (file)
@@ -819,6 +819,9 @@ fprintf(f, "Support for:");
 #ifdef EXPERIMENTAL_OCSP
   fprintf(f, " Experimental_OCSP");
 #endif
+#ifdef EXPERIMENTAL_PRDR
+  fprintf(f, " Experimental_PRDR");
+#endif
 fprintf(f, "\n");
 
 fprintf(f, "Lookups (built-in):");
index 43cf73d5be2c35f3ddffba055abefe972ddb1324..5db858bfcd318953a642af0f4934f213f3358699 100644 (file)
@@ -145,6 +145,12 @@ uschar *tls_verify_certificates= NULL;
 uschar *tls_verify_hosts       = NULL;
 #endif
 
+#ifdef EXPERIMENTAL_PRDR
+/* Per Recipient Data Response variables */
+BOOL    prdr_enable            = FALSE;
+BOOL    prdr_requested         = FALSE;
+const pcre *regex_PRDR         = NULL;
+#endif
 
 /* Input-reading functions for messages, so we can use special ones for
 incoming TCP/IP. The defaults use stdin. We never need these for any
@@ -202,6 +208,9 @@ uschar *acl_removed_headers    = NULL;
 uschar *acl_smtp_auth          = NULL;
 uschar *acl_smtp_connect       = NULL;
 uschar *acl_smtp_data          = NULL;
+#ifdef EXPERIMENTAL_PRDR
+uschar *acl_smtp_data_prdr     = NULL;
+#endif
 #ifndef DISABLE_DKIM
 uschar *acl_smtp_dkim          = NULL;
 #endif
@@ -235,6 +244,9 @@ uschar *acl_wherenames[]       = { US"RCPT",
                                    US"MIME",
                                    US"DKIM",
                                    US"DATA",
+#ifdef EXPERIMENTAL_PRDR
+                                   US"PRDR",
+#endif
                                    US"non-SMTP",
                                    US"AUTH",
                                    US"connection",
@@ -257,6 +269,9 @@ uschar *acl_wherecodes[]       = { US"550",     /* RCPT */
                                    US"550",     /* MIME */
                                    US"550",     /* DKIM */
                                    US"550",     /* DATA */
+#ifdef EXPERIMENTAL_PRDR
+                                   US"550",    /* RCPT PRDR */
+#endif
                                    US"0",       /* not SMTP; not relevant */
                                    US"503",     /* AUTH */
                                    US"550",     /* connect */
index 06cbf312ba0cd9bf3708251be279903501fffbee..8d83be7108958700ade5c620ba15665881b12c6b 100644 (file)
@@ -147,6 +147,10 @@ extern uschar *acl_removed_headers;    /* Headers deleted by an ACL */
 extern uschar *acl_smtp_auth;          /* ACL run for AUTH */
 extern uschar *acl_smtp_connect;       /* ACL run on SMTP connection */
 extern uschar *acl_smtp_data;          /* ACL run after DATA received */
+#ifdef EXPERIMENTAL_PRDR
+extern uschar *acl_smtp_data_prdr;     /* ACL run after DATA received if in PRDR mode*/
+const extern pcre *regex_PRDR;         /* For recognizing PRDR settings */
+#endif
 #ifndef DISABLE_DKIM
 extern uschar *acl_smtp_dkim;          /* ACL run for DKIM signatures / domains */
 #endif
@@ -560,6 +564,10 @@ extern uschar *percent_hack_domains;   /* Local domains for which '% operates */
 extern uschar *pid_file_path;          /* For writing daemon pids */
 extern uschar *pipelining_advertise_hosts; /* As it says */
 extern BOOL    pipelining_enable;      /* As it says */
+#ifdef EXPERIMENTAL_PRDR
+extern BOOL    prdr_enable;            /* As it says */
+extern BOOL    prdr_requested;         /* Connecting mail server wants PRDR */
+#endif
 extern BOOL    preserve_message_logs;  /* Save msglog files */
 extern uschar *primary_hostname;       /* Primary name of this computer */
 extern BOOL    print_topbitchars;      /* Topbit chars are printing chars */
index f19d6fdbf50ad49bfd6b6004d8e391eccf1b6ff2..b878b415c0e8c0385723d3f93de195766144873b 100644 (file)
@@ -813,6 +813,9 @@ enum { ACL_WHERE_RCPT,       /* Some controls are for RCPT only */
        ACL_WHERE_MIME,       /* ) implemented by <= WHERE_NOTSMTP           */
        ACL_WHERE_DKIM,       /* )                                           */
        ACL_WHERE_DATA,       /* )                                           */
+#ifdef EXPERIMENTAL_PRDR
+       ACL_WHERE_PRDR,       /* )                                           */
+#endif
        ACL_WHERE_NOTSMTP,    /* )                                           */
 
        ACL_WHERE_AUTH,       /* These remaining ones are not currently    */
index dbec45de326d9d6ce7817189950b90a824e3cf13..bba5325945bfaa5386382bd071bedf74e1a7fad0 100644 (file)
@@ -140,6 +140,9 @@ static optionlist optionlist_config[] = {
   { "acl_smtp_auth",            opt_stringptr,   &acl_smtp_auth },
   { "acl_smtp_connect",         opt_stringptr,   &acl_smtp_connect },
   { "acl_smtp_data",            opt_stringptr,   &acl_smtp_data },
+#ifdef EXPERIMENTAL_PRDR
+  { "acl_smtp_data_prdr",       opt_stringptr,   &acl_smtp_data_prdr },
+#endif
 #ifndef DISABLE_DKIM
   { "acl_smtp_dkim",            opt_stringptr,   &acl_smtp_dkim },
 #endif
@@ -316,6 +319,9 @@ static optionlist optionlist_config[] = {
 #endif
   { "pid_file_path",            opt_stringptr,   &pid_file_path },
   { "pipelining_advertise_hosts", opt_stringptr, &pipelining_advertise_hosts },
+#ifdef EXPERIMENTAL_PRDR
+  { "prdr_enable",              opt_bool,        &prdr_enable },
+#endif
   { "preserve_message_logs",    opt_bool,        &preserve_message_logs },
   { "primary_hostname",         opt_stringptr,   &primary_hostname },
   { "print_topbitchars",        opt_bool,        &print_topbitchars },
index efd0766e77ff3ae157f4517808c05d2ddb73f9f1..e0c1c73939325ad31668a735ced5eb0a8d259916 100644 (file)
@@ -481,6 +481,34 @@ recipients_list[recipients_count++].errors_to = NULL;
 
 
 
+/*************************************************
+*        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);
+}           
+                        
+            
+          
+          
+
 /*************************************************
 *        Remove a recipient from the list        *
 *************************************************/
@@ -3199,6 +3227,77 @@ else
       goto TIDYUP;
 #endif /* WITH_CONTENT_SCAN */
 
+#ifdef EXPERIMENTAL_PRDR
+    if (prdr_requested && recipients_count > 1 && acl_smtp_data_prdr != NULL )
+      {
+      unsigned int c;
+      int all_pass = OK;
+      int all_fail = FAIL;
+
+      smtp_printf("353 PRDR content analysis beginning\r\n");
+      /* Loop through recipients, responses must be in same order received */
+      for (c = 0; recipients_count > c; c++)
+        {
+       uschar * addr= recipients_list[c].address;
+       uschar * msg= US"PRDR R=<%s> %s";
+       uschar * code;
+        DEBUG(D_receive)
+          debug_printf("PRDR processing recipient %s (%d of %d)\n",
+                       addr, c+1, recipients_count);
+        rc = acl_check(ACL_WHERE_PRDR, addr,
+                       acl_smtp_data_prdr, &user_msg, &log_msg);
+
+        /* If any recipient rejected content, indicate it in final message */
+        all_pass |= rc;
+        /* If all recipients rejected, indicate in final message */
+        all_fail &= rc;
+
+        switch (rc)
+          {
+          case OK: case DISCARD: code = US"250"; break;
+          case DEFER:            code = US"450"; break;
+          default:               code = US"550"; break;
+          }
+       if (user_msg != NULL)
+         smtp_user_msg(code, user_msg);
+       else
+         {
+         switch (rc)
+            {
+            case OK: case DISCARD:
+              msg = string_sprintf(CS msg, addr, "acceptance");        break;
+            case DEFER:
+              msg = string_sprintf(CS msg, addr, "temporary refusal"); break;
+            default:
+              msg = string_sprintf(CS msg, addr, "refusal");           break;
+            }
+          smtp_user_msg(code, msg);
+         }
+       if (log_msg)       log_write(0, LOG_MAIN, "PRDR %s %s", addr, log_msg);
+       else if (user_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, user_msg);
+       else               log_write(0, LOG_MAIN, CS msg);
+
+       if (rc != OK) { receive_remove_recipient(addr); c--; }
+        }
+      /* Set up final message, used if data acl gives OK */
+      smtp_reply = string_sprintf("%s id=%s message %s",
+                      all_fail == FAIL ? US"550" : US"250",
+                      message_id,
+                       all_fail == FAIL
+                        ? US"rejected for all recipients"
+                        : all_pass == OK
+                          ? US"accepted"
+                          : US"accepted for some recipients");
+      if (recipients_count == 0)
+        {
+        message_id[0] = 0;       /* Indicate no message accepted */
+       goto TIDYUP;
+       }
+      }
+    else
+      prdr_requested = FALSE;
+#endif /* EXPERIMENTAL_PRDR */
+
     /* Check the recipients count again, as the MIME ACL might have changed
     them. */
 
@@ -3615,6 +3714,11 @@ if (sender_host_authenticated != NULL)
     }
   }
 
+#ifdef EXPERIMENTAL_PRDR
+if (prdr_requested)
+  s = string_append(s, &size, &sptr, 1, US" PRDR");
+#endif
+
 sprintf(CS big_buffer, "%d", msg_size);
 s = string_append(s, &size, &sptr, 2, US" S=", big_buffer);
 
@@ -3831,7 +3935,11 @@ if(cutthrough_fd >= 0)
     }
   }
 
-if(smtp_reply == NULL)
+if(smtp_reply == NULL
+#ifdef EXPERIMENTAL_PRDR
+                     || prdr_requested
+#endif
+  )
   {
   log_write(0, LOG_MAIN |
     (((log_extra_selector & LX_received_recipients) != 0)? LOG_RECIPIENTS : 0) |
index 243b8f7d1bd52ed1bf47fee8c3978ba2f2b01b80..cb1a86991fe1eb62dffcf8a9d60485f952d80a41 100644 (file)
@@ -210,7 +210,10 @@ static uschar *protocols[] = {
 /* Sanity check and validate optional args to MAIL FROM: envelope */
 enum {
   ENV_MAIL_OPT_SIZE, ENV_MAIL_OPT_BODY, ENV_MAIL_OPT_AUTH,
-  ENV_MAIL_OPT_PRDR, ENV_MAIL_OPT_NULL
+#ifdef EXPERIMENTAL_PRDR
+  ENV_MAIL_OPT_PRDR,
+#endif
+  ENV_MAIL_OPT_NULL
   };
 typedef struct {
   uschar *   name;  /* option requested during MAIL cmd */
@@ -222,7 +225,10 @@ static env_mail_type_t env_mail_type_list[] = {
     { US"SIZE",   ENV_MAIL_OPT_SIZE,   TRUE  },
     { US"BODY",   ENV_MAIL_OPT_BODY,   TRUE  },
     { US"AUTH",   ENV_MAIL_OPT_AUTH,   TRUE  },
-    { US"NULL",   ENV_MAIL_OPT_NULL,   FALSE }  /* Placeholder for ending */
+#ifdef EXPERIMENTAL_PRDR
+    { US"PRDR",   ENV_MAIL_OPT_PRDR,   FALSE },
+#endif
+    { US"NULL",   ENV_MAIL_OPT_NULL,   FALSE }
   };
 
 /* When reading SMTP from a remote host, we have to use our own versions of the
@@ -998,19 +1004,23 @@ uschar *n;
 uschar *v = smtp_cmd_data + Ustrlen(smtp_cmd_data) - 1;
 while (isspace(*v)) v--;
 v[1] = 0;
-
 while (v > smtp_cmd_data && *v != '=' && !isspace(*v)) v--;
-if (*v != '=') return FALSE;
 
 n = v;
-while(isalpha(n[-1])) n--;
-
-/* RFC says SP, but TAB seen in wild and other major MTAs accept it */
-if (!isspace(n[-1])) return FALSE;
-
-n[-1] = 0;
-*name = n;
+if (*v == '=')
+{
+  while(isalpha(n[-1])) n--;
+  /* RFC says SP, but TAB seen in wild and other major MTAs accept it */
+  if (!isspace(n[-1])) return FALSE;
+  n[-1] = 0;
+}
+else
+{
+  n++;
+  if (v == smtp_cmd_data) return FALSE;
+}
 *v++ = 0;
+*name = n;
 *value = v;
 return TRUE;
 }
@@ -2201,6 +2211,9 @@ uschar *what =
 #endif
   (where == ACL_WHERE_PREDATA)? US"DATA" :
   (where == ACL_WHERE_DATA)? US"after DATA" :
+#ifdef EXPERIMENTAL_PRDR
+  (where == ACL_WHERE_PRDR)? US"after DATA PRDR" :
+#endif
   (smtp_cmd_data == NULL)?
     string_sprintf("%s in \"connect\" ACL", acl_wherenames[where]) :
     string_sprintf("%s %s", acl_wherenames[where], smtp_cmd_data);
@@ -3119,6 +3132,7 @@ while (done <= 0)
         pipelining_advertised = TRUE;
         }
 
+
       /* If any server authentication mechanisms are configured, advertise
       them if the current host is in auth_advertise_hosts. The problem with
       advertising always is that some clients then require users to
@@ -3177,6 +3191,14 @@ while (done <= 0)
         }
       #endif
 
+      #ifdef EXPERIMENTAL_PRDR
+      /* Per Recipient Data Response, draft by Eric A. Hall extending RFC */
+      if (prdr_enable) {
+        s = string_cat(s, &size, &ptr, smtp_code, 3);
+        s = string_cat(s, &size, &ptr, US"-PRDR\r\n", 7);
+      }
+      #endif
+
       /* Finish off the multiline reply with one that is always available. */
 
       s = string_cat(s, &size, &ptr, smtp_code, 3);
@@ -3293,17 +3315,12 @@ while (done <= 0)
         }
       if (mail_args->need_value && strcmpic(value, US"") == 0)
         break;
-      /* This doesn't seem right to use
-        if ((char *)mail_args >= (char *)env_mail_type_list + sizeof(env_mail_type_list))
-        goto BAD_MAIL_ARGS;
-      */
 
       switch(mail_args->value)
         {
         /* Handle SIZE= by reading the value. We don't do the check till later,
         in order to be able to log the sender address on failure. */
         case ENV_MAIL_OPT_SIZE:
-          /* if (strcmpic(name, US"SIZE") == 0 && */
           if (((size = Ustrtoul(value, &end, 10)), *end == 0))
             {
             if ((size == ULONG_MAX && errno == ERANGE) || size > INT_MAX)
@@ -3355,8 +3372,8 @@ while (done <= 0)
             if (auth_xtextdecode(value, &authenticated_sender) < 0)
               {
               /* Put back terminator overrides for error message */
-              name[-1] = ' ';
               value[-1] = '=';
+              name[-1] = ' ';
               done = synprot_error(L_smtp_syntax_error, 501, NULL,
                 US"invalid data for AUTH");
               goto COMMAND_LOOP;
@@ -3399,22 +3416,30 @@ while (done <= 0)
               overrides for error message */
   
               default:
-              name[-1] = ' ';
               value[-1] = '=';
+              name[-1] = ' ';
               (void)smtp_handle_acl_fail(ACL_WHERE_MAILAUTH, rc, user_msg,
                 log_msg);
               goto COMMAND_LOOP;
               }
             }
             break;
+
+#ifdef EXPERIMENTAL_PRDR
+        case ENV_MAIL_OPT_PRDR:
+          if ( prdr_enable )
+            prdr_requested = TRUE;
+          break;
+#endif
+
         /* Unknown option. Stick back the terminator characters and break
-        the loop. An error for a malformed address will occur. */
+        the loop.  Do the name-terminator second as extract_option sets
+       value==name when it found no equal-sign.
+       An error for a malformed address will occur. */
         default:
-
-          /* BAD_MAIL_ARGS: */
-          name[-1] = ' ';
           value[-1] = '=';
+          name[-1] = ' ';
+          arg_error = TRUE;
           break;
         }
       /* Break out of for loop if switch() had bad argument or
@@ -3536,8 +3561,21 @@ while (done <= 0)
 
     if (rc == OK || rc == DISCARD)
       {
-      if (user_msg == NULL) smtp_printf("250 OK\r\n");
-        else smtp_user_msg(US"250", user_msg);
+      if (user_msg == NULL) 
+        smtp_printf("%s%s%s", US"250 OK",
+                  #ifdef EXPERIMENTAL_PRDR
+                    prdr_requested == TRUE ? US", PRDR Requested" :
+                  #endif
+                    US"",
+                    US"\r\n");
+      else 
+        {
+      #ifdef EXPERIMENTAL_PRDR
+        if ( prdr_requested == TRUE )
+           user_msg = string_sprintf("%s%s", user_msg, US", PRDR Requested");
+      #endif
+        smtp_user_msg(US"250",user_msg);
+        }
       smtp_delay_rcpt = smtp_rlr_base;
       recipients_discarded = (rc == DISCARD);
       was_rej_mail = FALSE;
@@ -3801,9 +3839,11 @@ while (done <= 0)
 
     if (rc == OK)
       {
+      uschar * code;
+      code = US"354";
       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);
+        smtp_printf("%s Enter message, ending with \".\" on a line by itself\r\n", code);
+      else smtp_user_msg(code, user_msg);
       done = 3;
       message_ended = END_NOTENDED;   /* Indicate in middle of data */
       }
index 5fc01e9e5316490777b23d5a1e72d6a3149b28b7..d11e91adbbe49e8f3c8cb14770b49ffc68fbe5ce 100644 (file)
@@ -483,6 +483,10 @@ typedef struct address_item_propagated {
 #define af_pass_message        0x02000000 /* pass message in bounces */
 #define af_bad_reply           0x04000000 /* filter could not generate autoreply */
 
+#ifdef EXPERIMENTAL_PRDR
+# define af_prdr_used          0x08000000 /* delivery used SMTP PRDR */
+#endif
+
 /* These flags must be propagated when a child is created */
 
 #define af_propagate           (af_ignore_error)
index 6c3507609f2671e8c6b66284aecd2635cd67365a..ee260a129b3e2d62d0b073b97236857d10e4fc84 100644 (file)
@@ -106,6 +106,10 @@ optionlist smtp_transport_options[] = {
 #endif
   { "hosts_try_auth",       opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_try_auth) },
+#ifdef EXPERIMENTAL_PRDR
+  { "hosts_try_prdr",       opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, hosts_try_prdr) },
+#endif
 #ifdef SUPPORT_TLS
   { "hosts_verify_avoid_tls", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_verify_avoid_tls) },
@@ -172,6 +176,9 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   NULL,                /* serialize_hosts */
   NULL,                /* hosts_try_auth */
   NULL,                /* hosts_require_auth */
+#ifdef EXPERIMENTAL_PRDR
+  NULL,                /* hosts_try_prdr */
+#endif
   NULL,                /* hosts_require_tls */
   NULL,                /* hosts_avoid_tls */
   US"*",               /* hosts_verify_avoid_tls */
@@ -871,6 +878,10 @@ BOOL completed_address = FALSE;
 BOOL esmtp = TRUE;
 BOOL pending_MAIL;
 BOOL pass_message = FALSE;
+#ifdef EXPERIMENTAL_PRDR
+BOOL prdr_offered = FALSE;
+BOOL prdr_active;
+#endif
 smtp_inblock inblock;
 smtp_outblock outblock;
 int max_rcpt = tblock->max_addresses;
@@ -1066,6 +1077,17 @@ goto SEND_QUIT;
     pcre_exec(regex_STARTTLS, NULL, CS buffer, Ustrlen(buffer), 0,
       PCRE_EOPT, NULL, 0) >= 0;
   #endif
+
+  #ifdef EXPERIMENTAL_PRDR
+  prdr_offered = esmtp &&
+    (pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(buffer), 0,
+      PCRE_EOPT, NULL, 0) >= 0) &&
+    (verify_check_this_host(&(ob->hosts_try_prdr), NULL, host->name,
+      host->address, NULL) == OK);
+
+  if (prdr_offered)
+    {DEBUG(D_transport) debug_printf("PRDR usable\n");}
+  #endif
   }
 
 /* For continuing deliveries down the same channel, the socket is the standard
@@ -1266,6 +1288,17 @@ if (continue_hostname == NULL
   DEBUG(D_transport) debug_printf("%susing PIPELINING\n",
     smtp_use_pipelining? "" : "not ");
 
+#ifdef EXPERIMENTAL_PRDR
+  prdr_offered = esmtp &&
+    pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(CS buffer), 0,
+      PCRE_EOPT, NULL, 0) >= 0 &&
+    verify_check_this_host(&(ob->hosts_try_prdr), NULL, host->name,
+      host->address, NULL) == OK;
+
+  if (prdr_offered)
+    {DEBUG(D_transport) debug_printf("PRDR usable\n");}
+#endif
+
   /* Note if the response to EHLO specifies support for the AUTH extension.
   If it has, check that this host is one we want to authenticate to, and do
   the business. The host name and address must be available when the
@@ -1469,6 +1502,26 @@ if (smtp_use_size)
   while (*p) p++;
   }
 
+#ifdef EXPERIMENTAL_PRDR
+prdr_active = FALSE;
+if (prdr_offered)
+  {
+  for (addr = first_addr; addr; addr = addr->next)
+    if (addr->transport_return == PENDING_DEFER)
+      {
+      for (addr = addr->next; addr; addr = addr->next)
+        if (addr->transport_return == PENDING_DEFER)
+         {                     /* at least two recipients to send */
+         prdr_active = TRUE;
+         sprintf(CS p, " PRDR"); p += 5;
+         goto prdr_is_active;
+         }
+      break;
+      }
+  }
+prdr_is_active:
+#endif
+
 /* If an authenticated_sender override has been specified for this transport
 instance, expand it. If the expansion is forced to fail, and there was already
 an authenticated_sender for this message, the original value will be used.
@@ -1709,8 +1762,31 @@ if (!ok) ok = TRUE; else
 
   smtp_command = US"end of data";
 
-  /* For SMTP, we now read a single response that applies to the whole message.
-  If it is OK, then all the addresses have been delivered. */
+#ifdef EXPERIMENTAL_PRDR
+  /* For PRDR we optionally get a partial-responses warning
+   * followed by the individual responses, before going on with
+   * the overall response.  If we don't get the warning then deal
+   * with per non-PRDR. */
+  if(prdr_active)
+    {
+    ok = smtp_read_response(&inblock, buffer, sizeof(buffer), '3',
+      ob->final_timeout);
+    if (!ok && errno == 0)
+      switch(buffer[0])
+        {
+       case '2': prdr_active = FALSE;
+                 ok = TRUE;
+                 break;
+       case '4': errno = ERRNO_DATA4XX;
+                  addrlist->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
+                 break;
+        }
+    }
+  else
+#endif
+
+  /* For non-PRDR SMTP, we now read a single response that applies to the
+  whole message.  If it is OK, then all the addresses have been delivered. */
 
   if (!lmtp)
     {
@@ -1764,7 +1840,7 @@ if (!ok) ok = TRUE; else
       conf = (s == buffer)? (uschar *)string_copy(s) : s;
       }
 
-    /* Process all transported addresses - for LMTP, read a status for
+    /* Process all transported addresses - for LMTP or PRDR, read a status for
     each one. */
 
     for (addr = addrlist; addr != first_addr; addr = addr->next)
@@ -1776,13 +1852,22 @@ if (!ok) ok = TRUE; else
       address. For temporary errors, add a retry item for the address so that
       it doesn't get tried again too soon. */
 
+#ifdef EXPERIMENTAL_PRDR
+      if (lmtp || prdr_active)
+#else
       if (lmtp)
+#endif
         {
         if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
             ob->final_timeout))
           {
           if (errno != 0 || buffer[0] == 0) goto RESPONSE_FAILED;
-          addr->message = string_sprintf("LMTP error after %s: %s",
+          addr->message = string_sprintf(
+#ifdef EXPERIMENTAL_PRDR
+           "%s error after %s: %s", prdr_active ? "PRDR":"LMTP",
+#else
+           "LMTP error after %s: %s",
+#endif
             big_buffer, string_printing(buffer));
           setflag(addr, af_pass_message);   /* Allow message to go to user */
           if (buffer[0] == '5')
@@ -1792,7 +1877,10 @@ if (!ok) ok = TRUE; else
             errno = ERRNO_DATA4XX;
             addr->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
             addr->transport_return = DEFER;
-            retry_add_item(addr, addr->address_retry_key, 0);
+#ifdef EXPERIMENTAL_PRDR
+            if (!prdr_active)
+#endif
+              retry_add_item(addr, addr->address_retry_key, 0);
             }
           continue;
           }
@@ -1812,25 +1900,73 @@ if (!ok) ok = TRUE; else
       addr->host_used = thost;
       addr->special_action = flag;
       addr->message = conf;
+#ifdef EXPERIMENTAL_PRDR
+      if (prdr_active) addr->flags |= af_prdr_used;
+#endif
       flag = '-';
 
-      /* Update the journal. For homonymic addresses, use the base address plus
-      the transport name. See lots of comments in deliver.c about the reasons
-      for the complications when homonyms are involved. Just carry on after
-      write error, as it may prove possible to update the spool file later. */
-
-      if (testflag(addr, af_homonym))
-        sprintf(CS buffer, "%.500s/%s\n", addr->unique + 3, tblock->name);
-      else
-        sprintf(CS buffer, "%.500s\n", addr->unique);
-
-      DEBUG(D_deliver) debug_printf("journalling %s", buffer);
-      len = Ustrlen(CS buffer);
-      if (write(journal_fd, buffer, len) != len)
-        log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
-          "%s: %s", buffer, strerror(errno));
+#ifdef EXPERIMENTAL_PRDR
+      if (!prdr_active)
+#endif
+        {
+        /* Update the journal. For homonymic addresses, use the base address plus
+        the transport name. See lots of comments in deliver.c about the reasons
+        for the complications when homonyms are involved. Just carry on after
+        write error, as it may prove possible to update the spool file later. */
+  
+        if (testflag(addr, af_homonym))
+          sprintf(CS buffer, "%.500s/%s\n", addr->unique + 3, tblock->name);
+        else
+          sprintf(CS buffer, "%.500s\n", addr->unique);
+  
+        DEBUG(D_deliver) debug_printf("journalling %s", buffer);
+        len = Ustrlen(CS buffer);
+        if (write(journal_fd, buffer, len) != len)
+          log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
+            "%s: %s", buffer, strerror(errno));
+        }
       }
 
+#ifdef EXPERIMENTAL_PRDR
+      if (prdr_active)
+        {
+       /* PRDR - get the final, overall response.  For any non-success
+       upgrade all the address statuses. */
+        ok = smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
+          ob->final_timeout);
+        if (!ok)
+         {
+         if(errno == 0 && buffer[0] == '4')
+            {
+            errno = ERRNO_DATA4XX;
+            addrlist->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
+            }
+         for (addr = addrlist; addr != first_addr; addr = addr->next)
+            if (buffer[0] == '5' || addr->transport_return == OK)
+              addr->transport_return = PENDING_OK; /* allow set_errno action */
+         goto RESPONSE_FAILED;
+         }
+
+       /* Update the journal, or setup retry. */
+        for (addr = addrlist; addr != first_addr; addr = addr->next)
+         if (addr->transport_return == OK)
+         {
+          if (testflag(addr, af_homonym))
+            sprintf(CS buffer, "%.500s/%s\n", addr->unique + 3, tblock->name);
+          else
+            sprintf(CS buffer, "%.500s\n", addr->unique);
+  
+          DEBUG(D_deliver) debug_printf("journalling(PRDR) %s", buffer);
+          len = Ustrlen(CS buffer);
+          if (write(journal_fd, buffer, len) != len)
+            log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
+              "%s: %s", buffer, strerror(errno));
+         }
+       else if (addr->transport_return == DEFER)
+          retry_add_item(addr, addr->address_retry_key, -2);
+       }
+#endif
+
     /* Ensure the journal file is pushed out to disk. */
 
     if (EXIMfsync(journal_fd) < 0)
index 79f1b8c50965e527eeea87295ae36f16aba31058..ef53292bc5ab36668ae9397d7edd5d30fa6f7a18 100644 (file)
@@ -21,6 +21,9 @@ typedef struct {
   uschar *serialize_hosts;
   uschar *hosts_try_auth;
   uschar *hosts_require_auth;
+#ifdef EXPERIMENTAL_PRDR
+  uschar *hosts_try_prdr;
+#endif
   uschar *hosts_require_tls;
   uschar *hosts_avoid_tls;
   uschar *hosts_verify_avoid_tls;
diff --git a/test/confs/5500 b/test/confs/5500
new file mode 100644 (file)
index 0000000..1bc830e
--- /dev/null
@@ -0,0 +1,66 @@
+# Exim test configuration 5500
+# Server PRDR
+
+LOG_SELECTOR=
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+primary_hostname = myhost.test.ex
+rfc1413_query_timeout = 0s
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex : *.test.ex
+
+LOG_SELECTOR
+
+qualify_domain = test.ex
+trusted_users = CALLER
+
+prdr_enable = true
+
+acl_smtp_rcpt = accept
+acl_smtp_data_prdr = prdr_acl
+acl_smtp_data = data_acl
+
+# ----- ACLs -----
+
+begin acl
+
+prdr_acl:
+  defer        local_parts = usery
+  deny local_parts = userz
+  accept
+
+data_acl:
+  deny condition = ${if match {$recipients}{userq}}
+  accept
+
+# ----- Transports -----
+
+begin transports
+
+t1:
+  driver = appendfile
+  file = DIR/test-mail/$local_part
+  user = CALLER
+
+# ----- Routers -----
+
+begin routers
+
+r0:
+  driver = accept
+  transport = t1
+
+# ----- Retry -----
+
+begin retry
+
+*                *   F,5d,5m
+
+# End
diff --git a/test/confs/5510 b/test/confs/5510
new file mode 100644 (file)
index 0000000..4872421
--- /dev/null
@@ -0,0 +1,62 @@
+# Exim test configuration 5510
+# Client PRDR
+
+LOG_SELECTOR=
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+primary_hostname = myhost.test.ex
+rfc1413_query_timeout = 0s
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex : *.test.ex
+
+LOG_SELECTOR
+
+qualify_domain = test.ex
+trusted_users = CALLER
+
+prdr_enable = true
+
+acl_smtp_rcpt = accept
+acl_smtp_data = data_acl
+
+# ----- ACLs -----
+
+begin acl
+
+data_acl:
+  deny local_parts = usery
+  accept
+
+# ----- Transports -----
+
+begin transports
+
+t1:
+  driver = smtp
+  hosts = 127.0.0.1
+  port = PORT_S
+  allow_localhost
+  hosts_try_prdr = *
+
+# ----- Routers -----
+
+begin routers
+
+r0:
+  driver = accept
+  transport = t1
+
+# ----- Retry -----
+
+begin retry
+
+*                *   F,5d,5m
+
+# End
index 4b0512a14446e74f6dd8e787f9c68e960213bac6..774495514786280fd66c8596a50c3dfc935ae7c3 100644 (file)
@@ -1,10 +1,13 @@
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex H=[127.0.0.1] P=smtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= "name with spaces"@test.ex H=[127.0.0.1] P=smtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 S=sss
 1999-03-02 09:44:33 TLS error on connection from (rhu.barb) [ip4.ip4.ip4.ip4] (gnutls_handshake): The peer did not send any certificate.
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex H=[ip4.ip4.ip4.ip4] P=smtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex H=[ip4.ip4.ip4.ip4] P=smtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" S=sss
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
 1999-03-02 09:44:33 10HmaX-0005vi-00 => CALLER <CALLER@test.ex> R=abc T=local_delivery
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaY-0005vi-00 => CALLER <CALLER@test.ex> R=abc T=local_delivery
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => CALLER <CALLER@test.ex> R=abc T=local_delivery
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
 1999-03-02 09:44:33 End queue run: pid=pppp -qf
index a0d9fc2058109038481a49008e72d705146a3a7b..da4ee49d721e183ae725dce51f4ce00a12566bbd 100644 (file)
@@ -1,11 +1,14 @@
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex H=[127.0.0.1] P=smtps X=TLSv1:AES256-SHA:256 S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= "name with spaces"@test.ex H=[127.0.0.1] P=smtps X=TLSv1:AES256-SHA:256 S=sss
 1999-03-02 09:44:33 TLS error on connection from (rhu.barb) [ip4.ip4.ip4.ip4] (SSL_accept): error: <<detail omitted>>
 1999-03-02 09:44:33 TLS client disconnected cleanly (rejected our certificate?)
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex H=[ip4.ip4.ip4.ip4] P=smtps X=TLSv1:AES256-SHA:256 DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex H=[ip4.ip4.ip4.ip4] P=smtps X=TLSv1:AES256-SHA:256 DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" S=sss
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
 1999-03-02 09:44:33 10HmaX-0005vi-00 => CALLER <CALLER@test.ex> R=abc T=local_delivery
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaY-0005vi-00 => CALLER <CALLER@test.ex> R=abc T=local_delivery
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => CALLER <CALLER@test.ex> R=abc T=local_delivery
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
 1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/5500 b/test/log/5500
new file mode 100644 (file)
index 0000000..ef5372c
--- /dev/null
@@ -0,0 +1,17 @@
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 PRDR R=<userx@test.ex> acceptance
+1999-03-02 09:44:33 10HmaY-0005vi-00 PRDR R=<usery@test.ex> temporary refusal
+1999-03-02 09:44:33 10HmaY-0005vi-00 PRDR R=<userz@test.ex> refusal
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> H=(rhu.barb) [127.0.0.1] P=esmtp PRDR S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 => userx <userx@test.ex> R=r0 T=t1
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaX-0005vi-00 PRDR R=<userp@test.ex> acceptance
+1999-03-02 09:44:33 10HmaX-0005vi-00 PRDR R=<userq@test.ex> acceptance
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=(rhu.barb) [127.0.0.1] F=<> rejected after DATA
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= <> H=(rhu.barb) [127.0.0.1] P=esmtp S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => user1 <user1@test.ex> R=r0 T=t1
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 PRDR R=<usery@test.ex> temporary refusal
+1999-03-02 09:44:33 10HmbA-0005vi-00 PRDR R=<usery@test.ex> temporary refusal
+1999-03-02 09:44:33 10HmbB-0005vi-00 PRDR R=<userz@test.ex> refusal
+1999-03-02 09:44:33 10HmbB-0005vi-00 PRDR R=<userz@test.ex> refusal
diff --git a/test/log/5510 b/test/log/5510
new file mode 100644 (file)
index 0000000..86a9bab
--- /dev/null
@@ -0,0 +1,31 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= userx@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => usery@test.ex R=r0 T=t1 H=127.0.0.1 [127.0.0.1] PRDR C="250 first rcpt was good"
+1999-03-02 09:44:33 10HmaX-0005vi-00 -> userz@test.ex R=r0 T=t1 H=127.0.0.1 [127.0.0.1] PRDR C="250 second rcpt was good"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= userx@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 => user2.1@test.ex R=r0 T=t1 H=127.0.0.1 [127.0.0.1] C="250 OK got that"
+1999-03-02 09:44:33 10HmaY-0005vi-00 -> user2.2@test.ex R=r0 T=t1 H=127.0.0.1 [127.0.0.1] C="250 OK got that"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= userx@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => usery@test.ex R=r0 T=t1 H=127.0.0.1 [127.0.0.1] PRDR C="250 first rcpt was good"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 == userz@test.ex R=r0 T=t1 defer (0): PRDR error after DATA: 450 cannot handle second rcpt right now
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbA-0005vi-00 => userp@test.ex R=r0 T=t1 H=127.0.0.1 [127.0.0.1] PRDR C="250 first rcpt was good"
+1999-03-02 09:44:33 10HmbA-0005vi-00 ** userq@test.ex R=r0 T=t1: PRDR error after DATA: 550 second rcpt does not like content
+1999-03-02 09:44:33 10HmbA-0005vi-00 Frozen (delivery error message)
+1999-03-02 09:44:33 10HmaZ-0005vi-00 == userz@test.ex routing defer (-51): retry time not reached
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= <> U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbB-0005vi-00 ** user5.1@test.ex R=r0 T=t1 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after end of data: host 127.0.0.1 [127.0.0.1]: 550 oops, overall rejection
+1999-03-02 09:44:33 10HmbB-0005vi-00 ** user5.2@test.ex R=r0 T=t1 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after end of data: host 127.0.0.1 [127.0.0.1]: 550 oops, overall rejection
+1999-03-02 09:44:33 10HmbB-0005vi-00 Frozen (delivery error message)
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= <> U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbC-0005vi-00 ** user6.1@test.ex R=r0 T=t1: SMTP error from remote mail server after end of data: host 127.0.0.1 [127.0.0.1]: 550 naah mate
+1999-03-02 09:44:33 10HmbC-0005vi-00 ** user6.2@test.ex R=r0 T=t1: SMTP error from remote mail server after end of data: host 127.0.0.1 [127.0.0.1]: 550 naah mate
+1999-03-02 09:44:33 10HmbC-0005vi-00 Frozen (delivery error message)
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= <> U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbD-0005vi-00 == user7.1@test.ex R=r0 T=t1 defer (-46): SMTP error from remote mail server after end of data: host 127.0.0.1 [127.0.0.1]: 450 oops, try again later please
+1999-03-02 09:44:33 10HmbD-0005vi-00 == user7.2@test.ex R=r0 T=t1 defer (-46): SMTP error from remote mail server after end of data: host 127.0.0.1 [127.0.0.1]: 450 oops, try again later please
+1999-03-02 09:44:33 10HmbD-0005vi-00 == user7.3@test.ex R=r0 T=t1 defer (-46): SMTP error from remote mail server after end of data: host 127.0.0.1 [127.0.0.1]: 450 oops, try again later please
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= <> U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbE-0005vi-00 => user8.1@test.ex R=r0 T=t1 H=127.0.0.1 [127.0.0.1] C="250 OK, got that"
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
index cc606bb0ea455c6be0aaa163a74d103d601e7852..a4e0dd526a79c506329f241ed387d49c3f0ea753 100644 (file)
@@ -10,12 +10,24 @@ TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
 
 This is a test encrypted message.
 
+From "name with spaces"@test.ex Tue Mar 02 09:44:33 1999
+Received: from [127.0.0.1]
+       by myhost.test.ex with smtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       (envelope-from <"name with spaces"@test.ex>)
+       id 10HmaY-0005vi-00
+       for CALLER@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+tls-certificate-verified: 0
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+This is a test encrypted message.
+
 From CALLER@test.ex Tue Mar 02 09:44:33 1999
 Received: from [ip4.ip4.ip4.ip4]
        by myhost.test.ex with smtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
        (Exim x.yz)
        (envelope-from <CALLER@test.ex>)
-       id 10HmaY-0005vi-00
+       id 10HmaZ-0005vi-00
        for CALLER@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
 tls-certificate-verified: 1
 TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock
index 0a2adcf1c64a8b3e1061bc7695969238bf187007..e4be6a342d1f0a059e1f030da08ff30d14d1958a 100644 (file)
@@ -10,12 +10,24 @@ TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
 
 This is a test encrypted message.
 
+From "name with spaces"@test.ex Tue Mar 02 09:44:33 1999
+Received: from [127.0.0.1]
+       by myhost.test.ex with smtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       (envelope-from <"name with spaces"@test.ex>)
+       id 10HmaY-0005vi-00
+       for CALLER@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+tls-certificate-verified: 0
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+This is a test encrypted message.
+
 From CALLER@test.ex Tue Mar 02 09:44:33 1999
 Received: from [ip4.ip4.ip4.ip4]
        by myhost.test.ex with smtps (TLSv1:AES256-SHA:256)
        (Exim x.yz)
        (envelope-from <CALLER@test.ex>)
-       id 10HmaY-0005vi-00
+       id 10HmaZ-0005vi-00
        for CALLER@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
 tls-certificate-verified: 1
 TLS: cipher=TLSv1:AES256-SHA:256 peerdn=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
diff --git a/test/mail/5500.user1 b/test/mail/5500.user1
new file mode 100644 (file)
index 0000000..a485c7c
--- /dev/null
@@ -0,0 +1,8 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Received: from [127.0.0.1] (helo=rhu.barb)
+       by myhost.test.ex with esmtp (Exim x.yz)
+       id 10HmaZ-0005vi-00
+       for user1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Sender: sender@some.where
+
+
diff --git a/test/mail/5500.userx b/test/mail/5500.userx
new file mode 100644 (file)
index 0000000..c46897f
--- /dev/null
@@ -0,0 +1,7 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Received: from [127.0.0.1] (helo=rhu.barb)
+       by myhost.test.ex with esmtp (Exim x.yz)
+       id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Sender: sender@some.where
+
+
diff --git a/test/rejectlog/5500 b/test/rejectlog/5500
new file mode 100644 (file)
index 0000000..89372dc
--- /dev/null
@@ -0,0 +1,8 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=(rhu.barb) [127.0.0.1] F=<> rejected after DATA
+Envelope-from: <>
+Envelope-to: <userp@test.ex>
+    <userq@test.ex>
+P Received: from [127.0.0.1] (helo=rhu.barb)
+       by myhost.test.ex with esmtp (Exim x.yz)
+       id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+S Sender: sender@some.where
index 4bcb99b4767584344ad3aa5c1eb111044259b5e3..9ff68fa13b7a69ecba29d0f8c40c90dd1a35cd20 100644 (file)
@@ -6,6 +6,9 @@ rset
 mail from:<userx@unknown.dom.ain>
 rcpt to:<userx@test.ex>
 rset
+mail from:<"unknown with spaces"@test.ex>
+rcpt to:<userx@test.ex>
+rset
 mail from:<userx@test.ex>
 rcpt to:<userx@test.ex>
 data
index 06e1a82575ba7056766b22ebcd710a238d50c0ac..06a7b31d0165d8be16640f922911847ad7e6a9b8 100644 (file)
@@ -25,6 +25,29 @@ This is a test encrypted message.
 quit
 ??? 221
 ****
+client-gnutls 127.0.0.1 PORT_D
+??? 220
+ehlo rhu.barb
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+starttls
+??? 220
+mail from:<"name with spaces"@test.ex>
+??? 250
+rcpt to:<CALLER@test.ex>
+??? 250
+DATA
+??? 3
+This is a test encrypted message.
+.
+??? 250
+quit
+??? 221
+****
 client-gnutls HOSTIPV4 PORT_D
 ??? 220
 ehlo rhu.barb
index 7f9279acd12160a53ef2b33fba3d31e277d887cd..2e7dca0a65e82976b512588b46a2aa194be4a606 100644 (file)
@@ -24,6 +24,29 @@ This is a test encrypted message.
 quit
 ??? 221
 ****
+client-ssl 127.0.0.1 PORT_D
+??? 220
+ehlo rhu.barb
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+starttls
+??? 220
+mail from:<"name with spaces"@test.ex>
+??? 250
+rcpt to:<CALLER@test.ex>
+??? 250
+DATA
+??? 3
+This is a test encrypted message.
+.
+??? 250
+quit
+??? 221
+****
 client-ssl HOSTIPV4 PORT_D
 ??? 220
 ehlo rhu.barb
diff --git a/test/scripts/5500-PRDR/5500 b/test/scripts/5500-PRDR/5500
new file mode 100644 (file)
index 0000000..567b000
--- /dev/null
@@ -0,0 +1,155 @@
+# PRDR (Per-Recipient Data Responses) server
+need_ipv4
+no_msglog_check
+#
+# 1: userx should be accepted, y should be tmp-rejected,
+#    z rejected, all after data per PRDR spec
+exim -DSERVER=server -bd -oX PORT_D
+****
+client 127.0.0.1 PORT_D
+??? 220
+ehlo rhu.barb
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-PRDR
+??? 250
+mail from:<> PRDR
+??? 250
+rcpt to:<userx@test.ex>
+??? 250
+rcpt to:<usery@test.ex>
+??? 250
+rcpt to:<userz@test.ex>
+??? 250
+data
+??? 354
+Sender: sender@some.where
+.
+??? 353
+??? 250
+??? 450
+??? 550
+??? 250
+quit
+??? 221
+****
+sleep 1
+#
+#
+# 2: traditional data acl should be called, resulting in an overall reject
+client 127.0.0.1 PORT_D
+??? 220
+ehlo rhu.barb
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-PRDR
+??? 250
+mail from:<> PRDR
+??? 250
+rcpt to:<userp@test.ex>
+??? 250
+rcpt to:<userq@test.ex>
+??? 250
+data
+??? 354
+Sender: sender@some.where
+.
+??? 353
+??? 250
+??? 250
+??? 550
+quit
+??? 221
+****
+sleep 1
+#
+#
+# 3: PRDR should be avoided for a single-recipient message
+# even though the client showed support.
+client 127.0.0.1 PORT_D
+??? 220
+ehlo rhu.barb
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-PRDR
+??? 250
+mail from:<> PRDR
+??? 250
+rcpt to:<user1@test.ex>
+??? 250
+data
+??? 354
+Sender: sender@some.where
+.
+??? 250
+quit
+??? 221
+****
+sleep 1
+#
+# 4: double temp-reject
+client 127.0.0.1 PORT_D
+??? 220
+ehlo rhu.barb
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-PRDR
+??? 250
+mail from:<> PRDR
+??? 250
+rcpt to:<usery@test.ex>
+??? 250
+rcpt to:<usery@test.ex>
+??? 250
+data
+??? 354
+Sender: sender@some.where
+.
+??? 353
+??? 450
+??? 450
+??? 250
+quit
+??? 221
+****
+sleep 1
+#
+# 5: double reject
+client 127.0.0.1 PORT_D
+??? 220
+ehlo rhu.barb
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-PRDR
+??? 250
+mail from:<> PRDR
+??? 250
+rcpt to:<userz@test.ex>
+??? 250
+rcpt to:<userz@test.ex>
+??? 250
+data
+??? 354
+Sender: sender@some.where
+.
+??? 353
+??? 550
+??? 550
+??? 550
+quit
+??? 221
+****
+sleep 1
+#
+killdaemon
+#
diff --git a/test/scripts/5500-PRDR/5510 b/test/scripts/5500-PRDR/5510
new file mode 100644 (file)
index 0000000..e5063a4
--- /dev/null
@@ -0,0 +1,228 @@
+# PRDR client
+need_ipv4
+no_msglog_check
+#
+# 1: Two recipients, accepted by full PRDR response sequence
+server PORT_S
+220 Server ready
+EHLO
+250-
+250-PRDR
+250 OK
+MAIL FROM:<userx@test.ex> PRDR
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+300 gimme yer body
+.
+353 prdr responses coming up
+250 first rcpt was good
+250 second rcpt was good
+250 OK, overall
+QUIT
+250 OK
+****
+exim -odi -f userx usery userz
+Some message text.
+****
+#
+#
+# 2: Two recipients, accepted by traditional response
+# though client offered full PRDR capability
+server PORT_S
+220 Server ready
+EHLO
+250-
+250-PRDR
+250 OK
+MAIL FROM:<userx@test.ex> PRDR
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+300 gimme that body
+.
+250 OK got that
+QUIT
+250 OK, bye
+****
+exim -odi -f userx user2.1 user2.2
+Some message text.
+****
+#
+#
+# 3: Two recipients, one accepted one tmp-rejected
+server PORT_S
+220 Server ready
+EHLO
+250-
+250-PRDR
+250 OK
+MAIL FROM:<userx@test.ex> PRDR
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+300 gimme yer body
+.
+353 prdr responses coming up
+250 first rcpt was good
+450 cannot handle second rcpt right now
+250 OK, overall
+QUIT
+250 OK
+****
+exim -odi -f userx usery userz
+Some message text.
+****
+#
+#
+# 4: Two recipients, one accepted one rejected
+# Avoid tester issues dealing with the bounce by sending
+# with a null from.
+#
+server PORT_S
+220 Server ready
+EHLO
+250-
+250-PRDR
+250 OK
+MAIL FROM:<> PRDR
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+300 gimme yer body
+.
+353 prdr responses coming up
+250 first rcpt was good
+550 second rcpt does not like content
+250 OK, overall
+QUIT
+250 OK
+****
+exim -odi -f "" userp userq
+Some message text.
+****
+#
+#
+# 5: Two recipients, rejected by final after PRDR accepts.
+#
+server PORT_S
+220 Server ready
+EHLO
+250-
+250-PRDR
+250 OK
+MAIL FROM:<> PRDR
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+300 yeah baby
+.
+353 prdr responses coming up
+250 first rcpt was good
+250 second rcpt was good
+550 oops, overall rejection
+QUIT
+250 OK
+****
+exim -odi -f "" user5.1 user5.2
+text
+****
+#
+#
+# 6: Two recipients, rejected traditionally though PRDR negociated.
+#
+server PORT_S
+220 Server ready
+EHLO
+250-
+250-PRDR
+250 OK
+MAIL FROM:<> PRDR
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+300 yeah baby
+.
+550 naah mate
+QUIT
+250 OK
+****
+exim -odi -f "" user6.1 user6.2
+text
+****
+#
+#
+# 7: Temp-reject at final
+server PORT_S
+220 Server ready
+EHLO
+250-
+250-PRDR
+250 OK
+MAIL FROM:<> PRDR
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+300 go ahead
+.
+353 prdr responses coming up
+250 first rcpt does not like you
+250 second rcpt has a temporary problem
+250 third rcpt is ok
+450 oops, try again later please
+QUIT
+250 OK
+****
+exim -odi -f "" user7.1 user7.2 user7.3
+text
+****
+#
+#
+#
+# 8: Client should avoid requesting PRDR for a single-recipient mail
+# even though the server offers
+server PORT_S
+220 Server ready
+EHLO
+250-
+250-PRDR
+250 OK
+MAIL FROM:<>
+250 OK
+RCPT TO
+250 OK
+DATA
+300 go ahead
+.
+250 OK, got that
+QUIT
+250 OK, bye
+****
+exim -odi -f "" user8.1
+text
+****
+#
+#
diff --git a/test/scripts/5500-PRDR/REQUIRES b/test/scripts/5500-PRDR/REQUIRES
new file mode 100644 (file)
index 0000000..b3c9939
--- /dev/null
@@ -0,0 +1 @@
+support Experimental_PRDR
index c7fcec4018a5bde4e0bbc9dd33acc55af79a00ae..39cdfba9bfdc268cbf28fa434f7354bc969f73bb 100644 (file)
@@ -38,6 +38,20 @@ LOG: H=[127.0.0.1] F=<userx@unknown.dom.ain> rejected RCPT <userx@test.ex>: Send
 >>> processing "require"
 >>> check verify = sender
 >>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+>>> routing "unknown with spaces"@test.ex
+>>> test.ex in "test.ex"? yes (matched "test.ex")
+>>> test.ex in "! +local_domains"? no (matched "! +local_domains")
+>>> unknown with spaces in "defer"? no (end of list)
+>>> unknown with spaces in "userx"? no (end of list)
+>>> no more routers
+>>> ----------- end verify ------------
+>>> require: condition test failed in ACL "check_recipient"
+LOG: H=[127.0.0.1] sender verify fail for <"unknown with spaces"@test.ex>: Unrouteable address
+LOG: H=[127.0.0.1] F=<"unknown with spaces"@test.ex> rejected RCPT <userx@test.ex>: Sender verify failed
+>>> using ACL "check_recipient"
+>>> processing "require"
+>>> check verify = sender
+>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 >>> routing userx@test.ex
 >>> test.ex in "test.ex"? yes (matched "test.ex")
 >>> test.ex in "! +local_domains"? no (matched "! +local_domains")
diff --git a/test/stderr/5500 b/test/stderr/5500
new file mode 100644 (file)
index 0000000..045fadc
--- /dev/null
@@ -0,0 +1,2 @@
+
+******** SERVER ********
index 7ef5e4024cf997254d341ae88faaf6411030369c..5e3968243567ed87c0c3c9d449daeee0a790435f 100644 (file)
 550 Sender verify failed\r
 250 Reset OK\r
 250 OK\r
+550-Verification failed for <"unknown with spaces"@test.ex>\r
+550-Unrouteable address\r
+550 Sender verify failed\r
+250 Reset OK\r
+250 OK\r
 250 Accepted\r
 354 Enter message, ending with "." on a line by itself\r
 550 Administrative prohibition\r
index 7b2a47fca3889181b6ccefbce88c19c7298d4231..a248be7c0a2aee565bc71d09814e96755f664f6b 100644 (file)
@@ -36,6 +36,44 @@ Succeeded in starting TLS
 ??? 221
 <<< 221 myhost.test.ex closing connection
 End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo rhu.barb
+??? 250-
+<<< 250-myhost.test.ex Hello rhu.barb [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-STARTTLS
+??? 250
+<<< 250 HELP
+>>> starttls
+??? 220
+<<< 220 TLS go ahead
+Attempting to start TLS
+Succeeded in starting TLS
+>>> mail from:<"name with spaces"@test.ex>
+??? 250
+<<< 250 OK
+>>> rcpt to:<CALLER@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 3
+<<< 354 Enter message, ending with "." on a line by itself
+>>> This is a test encrypted message.
+>>> .
+??? 250
+<<< 250 OK id=10HmaY-0005vi-00
+>>> quit
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
 Connecting to ip4.ip4.ip4.ip4 port 1225 ... connected
 ??? 220
 <<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
@@ -93,7 +131,7 @@ Succeeded in starting TLS
 >>> This is a test encrypted message from a verified host.
 >>> .
 ??? 250
-<<< 250 OK id=10HmaY-0005vi-00
+<<< 250 OK id=10HmaZ-0005vi-00
 >>> quit
 ??? 221
 <<< 221 myhost.test.ex closing connection
index d3c18a8bfeeecf96402df17ca477126060a14370..23c39cdf4e041a7b1b743d8316ea4cd69920db3e 100644 (file)
@@ -52,6 +52,60 @@ Succeeded in starting TLS
 ??? 221
 <<< 221 myhost.test.ex closing connection
 End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo rhu.barb
+??? 250-
+<<< 250-myhost.test.ex Hello rhu.barb [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-STARTTLS
+??? 250
+<<< 250 HELP
+>>> starttls
+??? 220
+<<< 220 TLS go ahead
+Attempting to start TLS
+SSL info: before/connect initialization
+SSL info: before/connect initialization
+SSL info: SSLv2/v3 write client hello A
+SSL info: SSLv3 read server hello A
+SSL info: SSLv3 read server certificate A
+SSL info: SSLv3 read server key exchange A
+SSL info: SSLv3 read server done A
+SSL info: SSLv3 write client key exchange A
+SSL info: SSLv3 write change cipher spec A
+SSL info: SSLv3 write finished A
+SSL info: SSLv3 flush data
+SSL info: SSLv3 read server session ticket A
+SSL info: SSLv3 read finished A
+SSL info: SSL negotiation finished successfully
+SSL info: SSL negotiation finished successfully
+SSL connection using AES256-SHA
+Succeeded in starting TLS
+>>> mail from:<"name with spaces"@test.ex>
+??? 250
+<<< 250 OK
+>>> rcpt to:<CALLER@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 3
+<<< 354 Enter message, ending with "." on a line by itself
+>>> This is a test encrypted message.
+>>> .
+??? 250
+<<< 250 OK id=10HmaY-0005vi-00
+>>> quit
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
 Connecting to ip4.ip4.ip4.ip4 port 1225 ... connected
 ??? 220
 <<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
@@ -144,7 +198,7 @@ Succeeded in starting TLS
 >>> This is a test encrypted message from a verified host.
 >>> .
 ??? 250
-<<< 250 OK id=10HmaY-0005vi-00
+<<< 250 OK id=10HmaZ-0005vi-00
 >>> quit
 ??? 221
 <<< 221 myhost.test.ex closing connection
diff --git a/test/stdout/5500 b/test/stdout/5500
new file mode 100644 (file)
index 0000000..d5efef7
--- /dev/null
@@ -0,0 +1,206 @@
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo rhu.barb
+??? 250-
+<<< 250-myhost.test.ex Hello rhu.barb [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-PRDR
+<<< 250-PRDR
+??? 250
+<<< 250 HELP
+>>> mail from:<> PRDR
+??? 250
+<<< 250 OK, PRDR Requested
+>>> rcpt to:<userx@test.ex>
+??? 250
+<<< 250 Accepted
+>>> rcpt to:<usery@test.ex>
+??? 250
+<<< 250 Accepted
+>>> rcpt to:<userz@test.ex>
+??? 250
+<<< 250 Accepted
+>>> data
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Sender: sender@some.where
+>>> .
+??? 353
+<<< 353 PRDR content analysis beginning
+??? 250
+<<< 250 PRDR R=<userx@test.ex> acceptance
+??? 450
+<<< 450 PRDR R=<usery@test.ex> temporary refusal
+??? 550
+<<< 550 PRDR R=<userz@test.ex> refusal
+??? 250
+<<< 250 id=10HmaY-0005vi-00 message accepted for some recipients
+>>> quit
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo rhu.barb
+??? 250-
+<<< 250-myhost.test.ex Hello rhu.barb [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-PRDR
+<<< 250-PRDR
+??? 250
+<<< 250 HELP
+>>> mail from:<> PRDR
+??? 250
+<<< 250 OK, PRDR Requested
+>>> rcpt to:<userp@test.ex>
+??? 250
+<<< 250 Accepted
+>>> rcpt to:<userq@test.ex>
+??? 250
+<<< 250 Accepted
+>>> data
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Sender: sender@some.where
+>>> .
+??? 353
+<<< 353 PRDR content analysis beginning
+??? 250
+<<< 250 PRDR R=<userp@test.ex> acceptance
+??? 250
+<<< 250 PRDR R=<userq@test.ex> acceptance
+??? 550
+<<< 550 Administrative prohibition
+>>> quit
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo rhu.barb
+??? 250-
+<<< 250-myhost.test.ex Hello rhu.barb [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-PRDR
+<<< 250-PRDR
+??? 250
+<<< 250 HELP
+>>> mail from:<> PRDR
+??? 250
+<<< 250 OK, PRDR Requested
+>>> rcpt to:<user1@test.ex>
+??? 250
+<<< 250 Accepted
+>>> data
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Sender: sender@some.where
+>>> .
+??? 250
+<<< 250 OK id=10HmaZ-0005vi-00
+>>> quit
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo rhu.barb
+??? 250-
+<<< 250-myhost.test.ex Hello rhu.barb [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-PRDR
+<<< 250-PRDR
+??? 250
+<<< 250 HELP
+>>> mail from:<> PRDR
+??? 250
+<<< 250 OK, PRDR Requested
+>>> rcpt to:<usery@test.ex>
+??? 250
+<<< 250 Accepted
+>>> rcpt to:<usery@test.ex>
+??? 250
+<<< 250 Accepted
+>>> data
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Sender: sender@some.where
+>>> .
+??? 353
+<<< 353 PRDR content analysis beginning
+??? 450
+<<< 450 PRDR R=<usery@test.ex> temporary refusal
+??? 450
+<<< 450 PRDR R=<usery@test.ex> temporary refusal
+??? 250
+<<< 250 id=10HmbA-0005vi-00 message accepted for some recipients
+>>> quit
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo rhu.barb
+??? 250-
+<<< 250-myhost.test.ex Hello rhu.barb [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-PRDR
+<<< 250-PRDR
+??? 250
+<<< 250 HELP
+>>> mail from:<> PRDR
+??? 250
+<<< 250 OK, PRDR Requested
+>>> rcpt to:<userz@test.ex>
+??? 250
+<<< 250 Accepted
+>>> rcpt to:<userz@test.ex>
+??? 250
+<<< 250 Accepted
+>>> data
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Sender: sender@some.where
+>>> .
+??? 353
+<<< 353 PRDR content analysis beginning
+??? 550
+<<< 550 PRDR R=<userz@test.ex> refusal
+??? 550
+<<< 550 PRDR R=<userz@test.ex> refusal
+??? 550
+<<< 550 id=10HmbB-0005vi-00 message rejected for all recipients
+>>> quit
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
diff --git a/test/stdout/5510 b/test/stdout/5510
new file mode 100644 (file)
index 0000000..b9eb9db
--- /dev/null
@@ -0,0 +1,231 @@
+
+******** SERVER ********
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250-
+250-PRDR
+250 OK
+MAIL FROM:<userx@test.ex> PRDR
+250 OK
+RCPT TO:<usery@test.ex>
+250 OK
+RCPT TO:<userz@test.ex>
+250 OK
+DATA
+300 gimme yer body
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <userx@test.ex>)
+       id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: userx@test.ex
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+Some message text.
+.
+353 prdr responses coming up
+250 first rcpt was good
+250 second rcpt was good
+250 OK, overall
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250-
+250-PRDR
+250 OK
+MAIL FROM:<userx@test.ex> PRDR
+250 OK
+RCPT TO:<user2.1@test.ex>
+250 OK
+RCPT TO:<user2.2@test.ex>
+250 OK
+DATA
+300 gimme that body
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <userx@test.ex>)
+       id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: userx@test.ex
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+Some message text.
+.
+250 OK got that
+QUIT
+250 OK, bye
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250-
+250-PRDR
+250 OK
+MAIL FROM:<userx@test.ex> PRDR
+250 OK
+RCPT TO:<usery@test.ex>
+250 OK
+RCPT TO:<userz@test.ex>
+250 OK
+DATA
+300 gimme yer body
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <userx@test.ex>)
+       id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+From: userx@test.ex
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+Some message text.
+.
+353 prdr responses coming up
+250 first rcpt was good
+450 cannot handle second rcpt right now
+250 OK, overall
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250-
+250-PRDR
+250 OK
+MAIL FROM:<> PRDR
+250 OK
+RCPT TO:<userp@test.ex>
+250 OK
+RCPT TO:<userq@test.ex>
+250 OK
+DATA
+300 gimme yer body
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       id 10HmbA-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbA-0005vi-00@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+Some message text.
+.
+353 prdr responses coming up
+250 first rcpt was good
+550 second rcpt does not like content
+250 OK, overall
+Unexpected EOF read from client
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250-
+250-PRDR
+250 OK
+MAIL FROM:<> PRDR
+250 OK
+RCPT TO:<user5.1@test.ex>
+250 OK
+RCPT TO:<user5.2@test.ex>
+250 OK
+DATA
+300 yeah baby
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       id 10HmbB-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbB-0005vi-00@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+text
+.
+353 prdr responses coming up
+250 first rcpt was good
+250 second rcpt was good
+550 oops, overall rejection
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250-
+250-PRDR
+250 OK
+MAIL FROM:<> PRDR
+250 OK
+RCPT TO:<user6.1@test.ex>
+250 OK
+RCPT TO:<user6.2@test.ex>
+250 OK
+DATA
+300 yeah baby
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       id 10HmbC-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbC-0005vi-00@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+text
+.
+550 naah mate
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250-
+250-PRDR
+250 OK
+MAIL FROM:<> PRDR
+250 OK
+RCPT TO:<user7.1@test.ex>
+250 OK
+RCPT TO:<user7.2@test.ex>
+250 OK
+RCPT TO:<user7.3@test.ex>
+250 OK
+DATA
+300 go ahead
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       id 10HmbD-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbD-0005vi-00@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+text
+.
+353 prdr responses coming up
+250 first rcpt does not like you
+250 second rcpt has a temporary problem
+250 third rcpt is ok
+450 oops, try again later please
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250-
+250-PRDR
+250 OK
+MAIL FROM:<>
+250 OK
+RCPT TO:<user8.1@test.ex>
+250 OK
+DATA
+300 go ahead
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       id 10HmbE-0005vi-00
+       for user8.1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbE-0005vi-00@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+text
+.
+250 OK, got that
+QUIT
+250 OK, bye
+End of script