smtp output
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 12 Apr 2015 18:19:58 +0000 (19:19 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 12 Apr 2015 18:19:58 +0000 (19:19 +0100)
16 files changed:
TODO
src/src/deliver.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/macros.h
src/src/parse.c
src/src/smtp_in.c
src/src/spool_in.c
src/src/spool_out.c
src/src/structs.h
src/src/transports/smtp.c
test/confs/4201
test/log/4201
test/scripts/4200-International/4201
test/stdout/4201

diff --git a/TODO b/TODO
index cca33151f6c221517e0855c3291dcfbc1177ad37..a282dc59235bed520447e02d6b15213abae7bc83 100644 (file)
--- a/TODO
+++ b/TODO
@@ -26,7 +26,13 @@ to-Alabel convert of helo name
 --- mua-wrapper
 --- acl control?
 
+++ flag in spool file
+
+retries
+- apply to a-label or utf8 form?
+
 dsn handling                           rfc6533
+
 logging
 ++ - international msg
 - presentation of local-part in log
@@ -42,8 +48,6 @@ forwarding checks                     rfc6530 7.1 -3-
 - mail-time rejects get 550 mailbox unavailable
 - bounces (see dsn handling)
 
-flag in spool file
-
 ++ expansions for to- and from-Alabel ?        bug1567
 
 enhanced status codes?                 rfc5248++
index 1cdecc6e93be9d0a294f6c56cf126fe8810126da..cc43c921a27d8786dbda533e25b105e4e5b547d0 100644 (file)
@@ -5594,6 +5594,10 @@ if (process_recipients != RECIP_IGNORE)
       recipient_item *r = recipients_list + i;
       address_item *new = deliver_make_addr(r->address, FALSE);
       new->p.errors_address = r->errors_to;
+#ifdef EXPERIMENTAL_INTERNATIONAL
+      new->p.utf8 = message_smtputf8;
+      DEBUG(D_deliver) debug_printf("utf8: %c\n", message_smtputf8 ? 'T':'F');
+#endif
 
       if (r->pno >= 0)
         new->onetime_parent = recipients_list[r->pno].address;
@@ -7857,6 +7861,11 @@ if (!regex_PRDR) regex_PRDR =
   regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
 #endif
 
+#ifdef SUPPORT_TLS
+if (!regex_UTF8) regex_UTF8 =
+  regex_must_compile(US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE);
+#endif
+
 if (!regex_DSN) regex_DSN  =
   regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
 
index fdd6292283631b168e29d9cd881a7c9f9e9c266c..d1ada38443f5900a3c64a8beb87c75cd8e6e22c8 100644 (file)
@@ -422,6 +422,7 @@ extern const uschar *string_printing2(const uschar *, BOOL);
 extern uschar *string_split_message(uschar *);
 extern uschar *string_unprinting(uschar *);
 #ifdef EXPERIMENTAL_INTERNATIONAL
+extern uschar *string_address_alabel_to_utf8(const uschar *, uschar **);
 extern uschar *string_address_utf8_to_alabel(uschar *, uschar **, int *);
 extern uschar *string_domain_alabel_to_utf8(const uschar *, uschar **);
 extern uschar *string_domain_utf8_to_alabel(const uschar *, uschar **);
index 2cbafcdcef51a11fa721364e7d08e7c88dddf407..2bf4d0a02fca999d8e8ab7ba08897dbff4fdebc0 100644 (file)
@@ -175,6 +175,10 @@ BOOL    prdr_requested         = FALSE;
 const pcre *regex_PRDR         = NULL;
 #endif
 
+#ifdef EXPERIMENTAL_INTERNATIONAL
+const pcre *regex_UTF8         = 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
 stand-alone tests. */
@@ -383,6 +387,9 @@ address_item address_defaults = {
     NULL,               /* remove_headers */
 #ifdef EXPERIMENTAL_SRS
     NULL,               /* srs_sender */
+#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+    FALSE,             /* utf8 */
 #endif
   }
 };
index d5b34201b7e47262f7eaac76774281edbb6fde6c..7cbf7bfab3dd05bf79de446a1d6a302ec96971e6 100644 (file)
@@ -572,6 +572,7 @@ extern int     message_size;           /* Size of message */
 extern uschar *message_size_limit;     /* As it says */
 #ifdef EXPERIMENTAL_INTERNATIONAL
 extern BOOL    message_smtputf8;       /* Internationalized mail handling */
+const extern pcre *regex_UTF8;         /* For recognizing SMTPUTF8 settings */
 #endif
 extern uschar  message_subdir[];       /* Subdirectory for messages */
 extern uschar *message_reference;      /* Reference for error messages */
index 0f893e812cfd21883d7647319f8f856452bd0fc3..a8ab4f7ae61ecb7335fc023c83b85d73ad189830 100644 (file)
@@ -503,7 +503,11 @@ to conflict with system errno values. */
 #define ERRNO_MAIL4XX        (-45)   /* MAIL gave 4xx error */
 #define ERRNO_DATA4XX        (-46)   /* DATA gave 4xx error */
 #define ERRNO_PROXYFAIL      (-47)   /* Negotiation failed for proxy configured host */
-#define ERRNO_AUTHPROB       (-48)   /* Autheticator "other" failure */
+#define ERRNO_AUTHPROB       (-48)   /* Authenticator "other" failure */
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+# define ERRNO_UTF8_FWD      (-49)   /* target not supporting SMTPUTF8 */
+#endif
 
 /* These must be last, so all retry deferments can easily be identified */
 
index a648f755aeb66a9ad83f62599957d1c054c15dba..9e57365be4891d6739e454d02f88682b634b9f2a 100644 (file)
@@ -740,7 +740,7 @@ if (*s == '<')
   while (bracket_count-- > 0) if (*s++ != '>')
     {
     *errorptr = (s[-1] == 0)? US"'>' missing at end of address" :
-      string_sprintf("malformed address A: %.32s may not follow %.*s",
+      string_sprintf("malformed address: %.32s may not follow %.*s",
         s-1, s - (uschar *)mailbox - 1, mailbox);
     goto PARSE_FAILED;
     }
@@ -793,7 +793,7 @@ if (*s != 0)
     }
   else
     {
-    *errorptr = string_sprintf("malformed address B: %.32s may not follow %.*s",
+    *errorptr = string_sprintf("malformed address: %.32s may not follow %.*s",
       s, s - (uschar *)mailbox, mailbox);
     goto PARSE_FAILED;
     }
index eb22233ca706d6306d001b45a3a1403e2e6ad477..a9c7fb25ce62306943becec46415bc6c006dd434 100644 (file)
@@ -4409,16 +4409,12 @@ while (done <= 0)
       receive_add_recipient(recipient, -1);
  
       /* Set the dsn flags in the recipients_list */
-      if (orcpt != NULL)
-        recipients_list[recipients_count-1].orcpt = orcpt;
-      else
-        recipients_list[recipients_count-1].orcpt = NULL;
+      recipients_list[recipients_count-1].orcpt = orcpt;
+      recipients_list[recipients_count-1].dsn_flags = flags;
 
-      if (flags != 0)
-        recipients_list[recipients_count-1].dsn_flags = flags;
-      else
-        recipients_list[recipients_count-1].dsn_flags = 0;
-      DEBUG(D_receive) debug_printf("DSN: orcpt: %s  flags: %d\n", recipients_list[recipients_count-1].orcpt, recipients_list[recipients_count-1].dsn_flags);
+      DEBUG(D_receive) debug_printf("DSN: orcpt: %s  flags: %d\n",
+       recipients_list[recipients_count-1].orcpt,
+       recipients_list[recipients_count-1].dsn_flags);
       }
 
     /* The recipient was discarded */
index 79970cb40b89d706972a591b96001833fa30eb90..742f4b579e582c3bb30bce24ff8e41b56efb86a0 100644 (file)
@@ -299,6 +299,10 @@ tls_in.ocsp = OCSP_NOT_REQ;
 spam_score_int = NULL;
 #endif
 
+#if defined(EXPERIMENTAL_INTERNATIONAL) && !defined(COMPILE_UTILITY)
+message_smtputf8 = FALSE;
+#endif
+
 dsn_ret = 0;
 dsn_envid = NULL;
 
@@ -568,6 +572,10 @@ for (;;)
 #ifdef WITH_CONTENT_SCAN
     else if (Ustrncmp(p, "pam_score_int ", 14) == 0)
       spam_score_int = string_copy(big_buffer + 16);
+#endif
+#if defined(EXPERIMENTAL_INTERNATIONAL) && !defined(COMPILE_UTILITY)
+    else if (Ustrncmp(p, "mtputf8", 7) == 0)
+      message_smtputf8 = TRUE;
 #endif
     break;
 
index fc56057c1469495ae312b1e44129a13395513644..6d22bff2c8f9df721d40b6712ddbe0d1e1aca2a1 100644 (file)
@@ -245,6 +245,10 @@ if (tls_in.ourcert)
 if (tls_in.ocsp)        fprintf(f, "-tls_ocsp %d\n",   tls_in.ocsp);
 #endif
 
+#ifdef EXPERIMENTAL_INTERNATIONAL
+if (message_smtputf8)    fprintf(f, "-smtputf8\n");
+#endif
+
 /* Write the dsn flags to the spool header file */
 DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_envid %s\n", dsn_envid);
 if (dsn_envid != NULL) fprintf(f, "-dsn_envid %s\n", dsn_envid);
index 6ec52e1ec5ddeac11b05c0e01896375d0fdef373..df19cfad4796b6e41726a6e6860d22f132077462 100644 (file)
@@ -459,6 +459,9 @@ typedef struct address_item_propagated {
   #ifdef EXPERIMENTAL_SRS
   uschar *srs_sender;             /* Change return path when delivering */
   #endif
+  #ifdef EXPERIMENTAL_INTERNATIONAL
+  BOOL    utf8;                          /* requires SMTPUTF8 processing */
+  #endif
 } address_item_propagated;
 
 /* Bits for the flags field below */
index b0fe177e905139b88cfb3779a0fdc0e2ce1be6b3..ffba14662538687b7385f640967c7cdcff772ce0 100644 (file)
@@ -1355,6 +1355,9 @@ BOOL pass_message = FALSE;
 BOOL prdr_offered = FALSE;
 BOOL prdr_active;
 #endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+BOOL utf8_offered = FALSE;
+#endif
 BOOL dsn_all_lasthop = TRUE;
 #if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE)
 BOOL dane = FALSE;
@@ -1614,6 +1617,13 @@ goto SEND_QUIT;
   if (prdr_offered)
     {DEBUG(D_transport) debug_printf("PRDR usable\n");}
 #endif
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+  utf8_offered = esmtp
+    && addrlist->p.utf8
+    && pcre_exec(regex_UTF8, NULL, CS buffer, Ustrlen(buffer), 0,
+                 PCRE_EOPT, NULL, 0) >= 0;
+#endif
   }
 
 /* For continuing deliveries down the same channel, the socket is the standard
@@ -1821,16 +1831,24 @@ if (continue_hostname == NULL
 #ifndef DISABLE_PRDR
   prdr_offered = esmtp
     && pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(CS buffer), 0,
-      PCRE_EOPT, NULL, 0) >= 0
+                 PCRE_EOPT, NULL, 0) >= 0
     && verify_check_given_host(&ob->hosts_try_prdr, host) == OK;
 
   if (prdr_offered)
     {DEBUG(D_transport) debug_printf("PRDR usable\n");}
 #endif
 
+#ifdef EXPERIMENTAL_INTERNATIONAL
+  utf8_offered = esmtp
+    && addrlist->p.utf8
+    && pcre_exec(regex_UTF8, NULL, CS buffer, Ustrlen(buffer), 0,
+                 PCRE_EOPT, NULL, 0) >= 0;
+#endif
+
   /* Note if the server supports DSN */
-  smtp_use_dsn = esmtp && pcre_exec(regex_DSN, NULL, CS buffer, (int)Ustrlen(CS buffer), 0,
-       PCRE_EOPT, NULL, 0) >= 0;
+  smtp_use_dsn = esmtp
+    && pcre_exec(regex_DSN, NULL, CS buffer, Ustrlen(CS buffer), 0,
+                 PCRE_EOPT, NULL, 0) >= 0;
   DEBUG(D_transport) debug_printf("use_dsn=%d\n", smtp_use_dsn);
 
   /* Note if the response to EHLO specifies support for the AUTH extension.
@@ -1853,6 +1871,15 @@ message-specific. */
 
 setting_up = FALSE;
 
+#ifdef EXPERIMENTAL_INTERNATIONAL
+/* If this is an international message we need the host to speak SMTPUTF8 */
+if (addrlist->p.utf8 && !utf8_offered)
+  {
+  errno = ERRNO_UTF8_FWD;
+  goto RESPONSE_FAILED;
+  }
+#endif
+
 /* If there is a filter command specified for this transport, we can now
 set it up. This cannot be done until the identify of the host is known. */
 
@@ -1929,18 +1956,25 @@ if (prdr_offered)
   }
 #endif
 
+#ifdef EXPERIMENTAL_INTERNATIONAL
+if (addrlist->p.utf8)
+  sprintf(CS p, " SMTPUTF8"), p += 9;
+#endif
+
 /* check if all addresses have lasthop flag */
 /* do not send RET and ENVID if true */
-dsn_all_lasthop = TRUE;
-for (addr = first_addr;
+for (dsn_all_lasthop = TRUE, addr = first_addr;
      address_count < max_rcpt && addr != NULL;
      addr = addr->next)
   if ((addr->dsn_flags & rf_dsnlasthop) != 1)
+    {
     dsn_all_lasthop = FALSE;
+    break;
+    }
 
 /* Add any DSN flags to the mail command */
 
-if ((smtp_use_dsn) && (dsn_all_lasthop == FALSE))
+if (smtp_use_dsn && !dsn_all_lasthop)
   {
   if (dsn_ret == dsn_ret_hdrs)
     {
@@ -1981,27 +2015,27 @@ buffer. */
 pending_MAIL = TRUE;     /* The block starts with MAIL */
 
 rc = smtp_write_command(&outblock, smtp_use_pipelining,
-       "MAIL FROM:<%s>%s\r\n", return_path, buffer);
+       "MAIL FROM:<%s>%s\r\n", return_path, buffer);
 mail_command = string_copy(big_buffer);  /* Save for later error message */
 
 switch(rc)
   {
   case -1:                /* Transmission error */
-  goto SEND_FAILED;
+    goto SEND_FAILED;
 
   case +1:                /* Block was sent */
-  if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
+    if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
        ob->command_timeout))
-    {
-    if (errno == 0 && buffer[0] == '4')
       {
-      errno = ERRNO_MAIL4XX;
-      addrlist->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
+      if (errno == 0 && buffer[0] == '4')
+       {
+       errno = ERRNO_MAIL4XX;
+       addrlist->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
+       }
+      goto RESPONSE_FAILED;
       }
-    goto RESPONSE_FAILED;
-    }
-  pending_MAIL = FALSE;
-  break;
+    pending_MAIL = FALSE;
+    break;
   }
 
 /* Pass over all the relevant recipient addresses for this host, which are the
index 7d9af4bf37b2f016684f8fa9cf948155e9c8b464..3b87cd5fcf93726db3cdc4a3f14dba2cc191f72c 100644 (file)
@@ -15,8 +15,10 @@ acl_smtp_rcpt = check_recipient
 trusted_users = CALLER
 log_selector = +received_recipients
 
+.ifdef SERVER
 queue_only
 queue_run_in_order
+.endif
 
 smtputf8_advertise_hosts = *
 
@@ -34,6 +36,8 @@ check_recipient:
 
 begin routers
 
+.ifdef SERVER
+
 fail_remote_domains:
   driver = redirect
   domains = ! +local_domains
@@ -43,6 +47,16 @@ localuser:
   driver = redirect
   data = :blackhole:
 
+.else
+
+rmt:
+  driver = manualroute
+  route_data = <;[127.0.0.1]:PORT_D
+  transport = rmt_smtp
+  self = send
+
+.endif
+
 # ----- Transports -----
 
 begin transports
@@ -57,4 +71,7 @@ local_delivery:
                  X-received-count: $received_count"
   return_path_add
 
+rmt_smtp:
+  driver = smtp
+
 # End
index 299952090ce419384f2f430d1140ff19d05c43f6..ebc09936a33ad83ed2a4726e698112c69e2dcb32 100644 (file)
@@ -1,9 +1,12 @@
 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 <= someone@some.domain H=(client) [127.0.0.1] P=utf8esmtp S=sss for userx@test.ex
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com H=(client) [127.0.0.1] P=utf8esmtp S=sss for userx@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= 他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com U=CALLER P=utf8local-esmtp S=sss for usery@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= 他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtp S=sss id=E10HmaZ-0005vi-00@the.local.host.name for usery@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => usery@test.ex R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
 1999-03-02 09:44:33 Start queue run: pid=pppp -qq
 1999-03-02 09:44:33 10HmaX-0005vi-00 => :blackhole: <userx@test.ex> R=localuser
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userx@test.ex> R=localuser
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
-1999-03-02 09:44:33 End queue run: pid=pppp -qq
index bac040f9b9975a0ca4f32d1c82547167af0115d4..1bb978634eb21f4a71567c0b958d360fddd0b513 100644 (file)
@@ -57,6 +57,21 @@ QUIT
 ****
 #
 #
+# utf-8 from, -bs input and forwarding
+exim -bs -odi
+EHLO client.bh
+MAIL FROM: <他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com> SMTPUTF8
+RCPT TO: <usery@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+#
+#
 killdaemon
 exim -DSERVER=server -qq
 ****
index b37028d5914794c571df20624239fb89fe6e7a23..8b89b2bd3c94a347083f02d47cd91a4094bbd702 100644 (file)
@@ -68,3 +68,15 @@ Connecting to 127.0.0.1 port 1225 ... connected
 ??? 221
 <<< 221 the.local.host.name closing connection
 End of script
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-the.local.host.name Hello CALLER at client.bh\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250-SMTPUTF8\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmaZ-0005vi-00\r
+221 the.local.host.name closing connection\r