======================
to-Alabel convert of helo name
+- smtp transport
++ An "international" flag on the message?
++ An is-international expansion condition?
++ helo-time option handling
-conversion of utf-8 domains on input rfc5890
-- deconversion on forwarding
-- deconversion for trace headers
+++ conversion of utf-8 domains for DNS rfc5890
+-- MSA mode: convert on forward?
+
dsn handling rfc6533
logging
- international msg
- presentation of local-part in log
-- a log option?
encoding of local_part
-encoding transform string-expansions
+
Recieved-by header tracking info
- WITH protocol types get UTF8 prefix
+- use for logging also
forwarding checks rfc6530 7.1 -3-
- rcpt-time rejects get 533 mailbox name not allowed
- bounces (see dsn handling)
-expansions for to- and from-Alabel ? bug1567
+++ expansions for to- and from-Alabel ? bug1567
enhanced status codes? rfc5248++
VRFY
EXPN
+
+non-smtp input
Compile with EXPERIMENTAL_INTERNATIONAL and libidn.
+Main config option smtputf8_advertise_hosts, default '*',
+a host list. If this matches the sending host and
+accept_8bitmime is true (the default) then the ESMTP option
+SMTPUTF8 will be advertised.
+
+If the sender specifies the SMTPUTF8 option on a MAIL command
+international handling for the message is enabled and
+the expansion variable $message_smtputf8 will have value TRUE.
+
+The option allow_utf8_domains is set to true for this
+message, but all DNS lookups are converted to a-label form.
+
+Log lines and Received-by: header lines will aquire a "utf8"
+prefix on the 'with' element, eg. utf8esmtp.
+
Expansion operators:
${utf8_domain_to_alabel:str}
${utf8_domain_from_alabel:str}
return previous->data.val;
}
+#ifdef EXPERIMENTAL_INTERNATIONAL
+/* Convert all names to a-label form before doing lookup */
+ {
+ uschar * alabel;
+ uschar * errstr = NULL;
+ if ((alabel = string_domain_utf8_to_alabel(name, &errstr)), errstr)
+ {
+ DEBUG(D_dns)
+ debug_printf("DNS name '%s' utf8 conversion to alabel failed: %s", name,
+ errstr);
+ host_find_failed_syntax = TRUE;
+ return DNS_NOMATCH;
+ }
+ name = alabel;
+ }
+#endif
+
/* If configured, check the hygene of the name passed to lookup. Otherwise,
although DNS lookups may give REFUSED at the lower level, some resolvers
turn this into TRY_AGAIN, which is silly. Give a NOMATCH return, since such
This needs to happen before we read the main configuration. */
init_lookup_list();
+#ifdef EXPERIMENTAL_INTERNATIONAL
+if (running_in_test_harness) smtputf8_advertise_hosts = NULL;
+#endif
+
/* Read the main runtime configuration data; this gives up if there
is a failure. It leaves the configuration file open so that the subsequent
configuration data for delivery can be read if needed. */
extern uschar *string_split_message(uschar *);
extern uschar *string_unprinting(uschar *);
#ifdef EXPERIMENTAL_INTERNATIONAL
+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 **);
extern uschar *string_localpart_alabel_to_utf8(const uschar *, uschar **);
BOOL smtp_use_pipelining = FALSE;
BOOL smtp_use_size = FALSE;
#ifdef EXPERIMENTAL_INTERNATIONAL
-uschar *smtputf8_advertise_hosts = US"*";
+uschar *smtputf8_advertise_hosts = US"*"; /* overridden under test-harness */
#endif
#ifdef WITH_CONTENT_SCAN
{
s = read_local_part(s, t, errorptr, FALSE);
if (*errorptr == NULL)
- {
if (*s != term)
- {
if (*s != '@')
*errorptr = string_sprintf("\"@\" or \".\" expected after \"%s\"", t);
else
*domainptr = t;
s = read_domain(s, t, errorptr);
}
- }
- }
return s;
}
while (bracket_count-- > 0) if (*s++ != '>')
{
*errorptr = (s[-1] == 0)? US"'>' missing at end of address" :
- string_sprintf("malformed address: %.32s may not follow %.*s",
+ string_sprintf("malformed address A: %.32s may not follow %.*s",
s-1, s - (uschar *)mailbox - 1, mailbox);
goto PARSE_FAILED;
}
}
else
{
- *errorptr = string_sprintf("malformed address: %.32s may not follow %.*s",
+ *errorptr = string_sprintf("malformed address B: %.32s may not follow %.*s",
s, s - (uschar *)mailbox, mailbox);
goto PARSE_FAILED;
}
return NULL;
}
-return (uschar *)yield;
+return yield;
/* Use goto (via the macro FAILED) to get to here from a variety of places.
We might have an empty address in a group - the caller can choose to ignore
(char *)mail_args < (char *)env_mail_type_list + sizeof(env_mail_type_list);
mail_args++
)
- {
if (strcmpic(name, mail_args->name) == 0)
break;
- }
if (mail_args->need_value && strcmpic(value, US"") == 0)
break;
and "7BIT" as body types, but take no action. */
case ENV_MAIL_OPT_BODY:
if (accept_8bitmime) {
- if (strcmpic(value, US"8BITMIME") == 0) {
+ if (strcmpic(value, US"8BITMIME") == 0)
body_8bitmime = 8;
- } else if (strcmpic(value, US"7BIT") == 0) {
+ else if (strcmpic(value, US"7BIT") == 0)
body_8bitmime = 7;
- } else {
+ else
+ {
body_8bitmime = 0;
done = synprot_error(L_smtp_syntax_error, 501, NULL,
US"invalid data for BODY");
goto COMMAND_LOOP;
- }
+ }
DEBUG(D_receive) debug_printf("8BITMIME: %d\n", body_8bitmime);
break;
}
is included only if configured in at build time. */
case ENV_MAIL_OPT_RET:
- if (dsn_advertised) {
+ if (dsn_advertised)
+ {
/* Check if RET has already been set */
- if (dsn_ret > 0) {
+ if (dsn_ret > 0)
+ {
synprot_error(L_smtp_syntax_error, 501, NULL,
US"RET can be specified once only");
goto COMMAND_LOOP;
- }
- dsn_ret = (strcmpic(value, US"HDRS") == 0)? dsn_ret_hdrs :
- (strcmpic(value, US"FULL") == 0)? dsn_ret_full : 0;
+ }
+ dsn_ret = strcmpic(value, US"HDRS") == 0
+ ? dsn_ret_hdrs
+ : strcmpic(value, US"FULL") == 0
+ ? dsn_ret_full
+ : 0;
DEBUG(D_receive) debug_printf("DSN_RET: %d\n", dsn_ret);
/* Check for invalid invalid value, and exit with error */
- if (dsn_ret == 0) {
+ if (dsn_ret == 0)
+ {
synprot_error(L_smtp_syntax_error, 501, NULL,
US"Value for RET is invalid");
goto COMMAND_LOOP;
- }
- }
+ }
+ }
break;
case ENV_MAIL_OPT_ENVID:
- if (dsn_advertised) {
+ if (dsn_advertised)
+ {
/* Check if the dsn envid has been already set */
- if (dsn_envid != NULL) {
+ if (dsn_envid != NULL)
+ {
synprot_error(L_smtp_syntax_error, 501, NULL,
US"ENVID can be specified once only");
goto COMMAND_LOOP;
- }
+ }
dsn_envid = string_copy(value);
DEBUG(D_receive) debug_printf("DSN_ENVID: %s\n", dsn_envid);
- }
+ }
break;
/* Handle the AUTH extension. If the value given is not "<>" and either
switch (rc)
{
case OK:
- if (authenticated_by == NULL ||
- authenticated_by->mail_auth_condition == NULL ||
- expand_check_condition(authenticated_by->mail_auth_condition,
- authenticated_by->name, US"authenticator"))
- break; /* Accept the AUTH */
-
- ignore_msg = US"server_mail_auth_condition failed";
- if (authenticated_id != NULL)
- ignore_msg = string_sprintf("%s: authenticated ID=\"%s\"",
- ignore_msg, authenticated_id);
+ if (authenticated_by == NULL ||
+ authenticated_by->mail_auth_condition == NULL ||
+ expand_check_condition(authenticated_by->mail_auth_condition,
+ authenticated_by->name, US"authenticator"))
+ break; /* Accept the AUTH */
+
+ ignore_msg = US"server_mail_auth_condition failed";
+ if (authenticated_id != NULL)
+ ignore_msg = string_sprintf("%s: authenticated ID=\"%s\"",
+ ignore_msg, authenticated_id);
/* Fall through */
case FAIL:
- authenticated_sender = NULL;
- log_write(0, LOG_MAIN, "ignoring AUTH=%s from %s (%s)",
- value, host_and_ident(TRUE), ignore_msg);
- break;
+ authenticated_sender = NULL;
+ log_write(0, LOG_MAIN, "ignoring AUTH=%s from %s (%s)",
+ value, host_and_ident(TRUE), ignore_msg);
+ break;
/* Should only get DEFER or ERROR here. Put back terminator
overrides for error message */
default:
- value[-1] = '=';
- name[-1] = ' ';
- (void)smtp_handle_acl_fail(ACL_WHERE_MAILAUTH, rc, user_msg,
- log_msg);
- goto COMMAND_LOOP;
+ value[-1] = '=';
+ name[-1] = ' ';
+ (void)smtp_handle_acl_fail(ACL_WHERE_MAILAUTH, rc, user_msg,
+ log_msg);
+ goto COMMAND_LOOP;
}
}
break;
#ifdef EXPERIMENTAL_INTERNATIONAL
case ENV_MAIL_OPT_UTF8:
if (smtputf8_advertised)
- message_smtputf8 = TRUE;
+ message_smtputf8 = allow_utf8_domains = TRUE;
break;
#endif
/* Unknown option. Stick back the terminator characters and break
/* Now extract the address, first applying any SMTP-time rewriting. The
TRUE flag allows "<>" as a sender address. */
- raw_sender = ((rewrite_existflags & rewrite_smtp) != 0)?
- rewrite_one(smtp_cmd_data, rewrite_smtp, NULL, FALSE, US"",
- global_rewrite_rules) : smtp_cmd_data;
+ raw_sender = rewrite_existflags & rewrite_smtp
+ ? rewrite_one(smtp_cmd_data, rewrite_smtp, NULL, FALSE, US"",
+ global_rewrite_rules)
+ : smtp_cmd_data;
/* rfc821_domains = TRUE; << no longer needed */
raw_sender =
uschar * res = store_get(p_len+5);
int rc;
-DEBUG(D_expand) debug_printf("l_u2a: ulen %d plen %d\n", ucs4_len, p_len);
-DEBUG(D_expand) for (rc = 0; rc < ucs4_len; rc++) debug_printf("%08x ", p[rc]);
-
res[0] = 'x'; res[1] = 'n'; res[2] = res[3] = '-';
if ((rc = punycode_encode(ucs4_len, p, NULL, &p_len, res+4)) != PUNYCODE_SUCCESS)
if (err) *err = US punycode_strerror(rc);
return NULL;
}
-DEBUG(D_expand) debug_printf("l_u2a: plen %d\n", p_len);
p_len += 4;
-DEBUG(D_expand) for (rc = 0; rc < p_len; rc++) debug_printf("%02x ", res[rc]);
-DEBUG(D_expand) debug_printf("\n");
free(p);
res[p_len] = '\0';
return res;
if (err) *err = US"bad alabel prefix";
return NULL;
}
-p_len -= 4;
-DEBUG(D_expand) debug_printf("l_a2u: plen %d\n", p_len);
+p_len -= 4;
p = (punycode_uint *) store_get((p_len+1) * sizeof(*p));
if ((rc = punycode_decode(p_len, CCS alabel+4, &p_len, p, NULL)) != PUNYCODE_SUCCESS)
if (err) *err = US punycode_strerror(rc);
return NULL;
}
-DEBUG(D_expand) debug_printf("l_a2u: dlen %d\n", p_len);
s = stringprep_ucs4_to_utf8(p, p_len, NULL, &p_len);
res = string_copyn(s, p_len);
--- /dev/null
+# Exim test configuration 4201
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex
+
+acl_smtp_rcpt = check_recipient
+trusted_users = CALLER
+log_selector = +received_recipients
+
+queue_only
+queue_run_in_order
+
+smtputf8_advertise_hosts = *
+
+
+# ----- ACL -----
+
+begin acl
+
+check_recipient:
+ accept hosts = :
+ accept domains = +local_domains
+ deny message = relay not permitted
+
+# ----- Routers -----
+
+begin routers
+
+fail_remote_domains:
+ driver = redirect
+ domains = ! +local_domains
+ data = :fail: unrouteable mail domain "$domain"
+
+localuser:
+ driver = redirect
+ data = :blackhole:
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ delivery_date_add
+ envelope_to_add
+ file = DIR/test-mail/$local_part
+ headers_add = "X-body-linecount: $body_linecount\n\
+ X-message-linecount: $message_linecount\n\
+ X-received-count: $received_count"
+ return_path_add
+
+# End
--- /dev/null
+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=esmtp 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=esmtp S=sss for userx@test.ex
+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
next if /^SSL info: unknown state/;
next if /^SSL info: SSLv2\/v3 write client hello A/;
next if /^SSL info: SSLv3 read server key exchange A/;
-
}
# ======== stderr ========
next if /in\shosts_require_dane\?\sno\s\(option\sunset\)/x;
+ # Experimental_International
+ next if / in smtputf8_advertise_hosts\? no \(option unset\)/;
+
# Skip some lines that Exim puts out at the start of debugging output
# because they will be different in different binaries.
/^Fixed never_users:/ ||
/^Size of off_t:/
);
+
+
}
next;
--- /dev/null
+# Internationalised mail: smtp
+# Exim test configuration 4200
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+#
+# Basic smtp input, no delivery
+client 127.0.0.1 PORT_D
+??? 220
+EHLO client
+??? 250-
+??? 250-SIZE
+??? 250-8BITMIME
+??? 250-PIPELINING
+??? 250-SMTPUTF8
+??? 250 HELP
+MAIL FROM: <someone@some.domain> SMTPUTF8
+??? 250
+RCPT TO: <userx@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
+# utf-8 from, Basic smtp input, no delivery
+client 127.0.0.1 PORT_D
+??? 220
+EHLO client
+??? 250-
+??? 250-SIZE
+??? 250-8BITMIME
+??? 250-PIPELINING
+??? 250-SMTPUTF8
+??? 250 HELP
+MAIL FROM: <ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com> SMTPUTF8
+??? 250
+RCPT TO: <userx@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
+killdaemon
+exim -DSERVER=server -qq
+****
+no_msglog_check
+
--- /dev/null
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO client
+??? 250-
+<<< 250-the.local.host.name Hello client [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-SMTPUTF8
+<<< 250-SMTPUTF8
+??? 250 HELP
+<<< 250 HELP
+>>> MAIL FROM: <someone@some.domain> SMTPUTF8
+??? 250
+<<< 250 OK
+>>> RCPT TO: <userx@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: test
+>>>
+>>> body
+>>> .
+??? 250
+<<< 250 OK id=10HmaX-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 the.local.host.name closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO client
+??? 250-
+<<< 250-the.local.host.name Hello client [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-SMTPUTF8
+<<< 250-SMTPUTF8
+??? 250 HELP
+<<< 250 HELP
+>>> MAIL FROM: <ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com> SMTPUTF8
+??? 250
+<<< 250 OK
+>>> RCPT TO: <userx@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: test
+>>>
+>>> body
+>>> .
+??? 250
+<<< 250 OK id=10HmaY-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 the.local.host.name closing connection
+End of script