diff --git a/postfix/.indent.pro b/postfix/.indent.pro
index c690ce828..37dcdeaef 100644
--- a/postfix/.indent.pro
+++ b/postfix/.indent.pro
@@ -26,6 +26,7 @@
-TBOUNCE_LOG_FORGE
-TBOUNCE_LOG_RCPT_BUF
-TBOUNCE_STAT
+-TBOUNCE_STR_PARAMETER
-TBOUNCE_TEMPLATE
-TBOUNCE_TEMPLATES
-TBOUNCE_TIME_DIVISOR
diff --git a/postfix/HISTORY b/postfix/HISTORY
index 51ea7b184..00297dba2 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -20261,3 +20261,18 @@ Apologies for any names omitted.
Cleanup: hard-coded GCC dependencies. Eray Aslan. File:
makedefs.
+
+20140717
+
+ Safety: manipulate unsigned characters while decoding.
+ Files: global/xtext.c, global/uxtext.c.
+
+ Infrastructure: ACE label to UTF-8 conversion. Files:
+ util/midna.[hc].
+
+ Infrastructure: macro expansion with printable() filter.
+ Files: util/mac_expand.[hc].
+
+ Feature: when expanding myhostname or mydomain in bounce
+ template messages, and smtputf8_enable=yes, convert ACE
+ (xn--mumble) labels into UTF-8. bounce/bounce_template.c.
diff --git a/postfix/WISHLIST b/postfix/WISHLIST
index 7f4be0f6b..dffb68ea2 100644
--- a/postfix/WISHLIST
+++ b/postfix/WISHLIST
@@ -8,6 +8,11 @@ Wish list:
Things to do after the stable release:
+ up-convert myhostname in MIME boundary strings?
+
+ Table-driven case folding and case-insensitive string
+ comparison specifically for UTF-8.
+
When downgrading message/global to 7bit, is quoted-printable
the appropriate encoding? Should it be base64?
diff --git a/postfix/html/bounce.5.html b/postfix/html/bounce.5.html
index 1c0860e97..18051cd40 100644
--- a/postfix/html/bounce.5.html
+++ b/postfix/html/bounce.5.html
@@ -16,16 +16,16 @@ BOUNCE(5) BOUNCE(5)
DESCRIPTION
The Postfix bounce(8) server produces delivery status notification
- (DSN) messages for undeliverable mail, delayed mail, successful deliv-
+ (DSN) messages for undeliverable mail, delayed mail, successful deliv‐
ery or address verification requests.
By default, these notifications are generated from built-in templates
with message headers and message text. Sites can override the built-in
- information by specifying a bounce template file with the bounce_tem-
- plate_file configuration parameter.
+ information by specifying a bounce template file with the bounce_tem‐‐
+ plate_file configuration parameter.
- This document describes the general procedure to create a bounce tem-
- plate file, followed by the specific details of bounce template for-
+ This document describes the general procedure to create a bounce tem‐
+ plate file, followed by the specific details of bounce template for‐
mats.
GENERAL PROCEDURE
@@ -44,7 +44,7 @@ BOUNCE(5) BOUNCE(5)
expansion of time value parameters that appear in the delayed mail
notification text.
- Once the result is satisfactory, copy the template to the Postfix con-
+ Once the result is satisfactory, copy the template to the Postfix con‐
figuration directory and specify in main.cf something like:
/etc/postfix/main.cf:
@@ -53,13 +53,13 @@ BOUNCE(5) BOUNCE(5)
TEMPLATE FILE FORMAT
The template file can specify templates for failed mail, delayed mail,
successful delivery or for address verification. These templates are
- named failure_template, delay_template, success_template and ver-
+ named failure_template, delay_template, success_template and ver‐‐
ify_template, respectively. You can but do not have to specify all
four templates in a bounce template file.
Each template starts with "template_name = <<EOF" and ends with a line
that contains the word "EOF" only. You can change the word EOF, but you
- can't enclose it in quotes as with the shell or with Perl (tem-
+ can't enclose it in quotes as with the shell or with Perl (tem‐
plate_name = <<'EOF'). Here is an example:
# The failure template is used for undeliverable mail.
@@ -83,16 +83,16 @@ BOUNCE(5) BOUNCE(5)
The mail system
EOF
- The usage and specification of bounce templates is subject to the fol-
+ The usage and specification of bounce templates is subject to the fol‐
lowing restrictions:
- o No special meaning is given to the backslash character or to
+ · No special meaning is given to the backslash character or to
leading whitespace; these are always taken literally.
- o Inside the << context, the "$" character is special. To produce
+ · Inside the << context, the "$" character is special. To produce
a "$" character as output, specify "$$".
- o Outside the << context, lines beginning with "#" are ignored, as
+ · Outside the << context, lines beginning with "#" are ignored, as
are empty lines, and lines consisting of whitespace only.
Examples of all templates can be found in the file bounce.cf.default in
@@ -100,7 +100,7 @@ BOUNCE(5) BOUNCE(5)
TEMPLATE HEADER FORMAT
The first portion of a bounce template consists of optional template
- headers. Some become message headers in the delivery status notifica-
+ headers. Some become message headers in the delivery status notifica‐
tion; some control the formatting of that notification. Headers not
specified in a template will be left at their default value.
@@ -114,26 +114,26 @@ BOUNCE(5) BOUNCE(5)
notification.
Subject:
- The subject in the message header of the delivery status notifi-
+ The subject in the message header of the delivery status notifi‐
cation that is returned to the sender.
Postmaster-Subject:
- The subject that will be used in Postmaster copies of undeliver-
+ The subject that will be used in Postmaster copies of undeliver‐
able or delayed mail notifications. These copies are sent under
control of the notify_classes configuration parameter.
The usage and specification of template message headers is subject to
the following restrictions:
- o Template message header names can be specified in upper case,
+ · Template message header names can be specified in upper case,
lower case or mixed case. Postfix always produces bounce message
header labels of the form "From:" and "Subject:".
- o Template message headers must not span multiple lines.
+ · Template message headers must not span multiple lines.
- o Template message headers do not support $parameter expansions.
+ · Template message headers do not support $parameter expansions.
- o Template message headers must contain ASCII characters only, and
+ · Template message headers must contain ASCII characters only, and
must not contain ASCII null characters.
TEMPLATE MESSAGE TEXT FORMAT
@@ -153,16 +153,30 @@ BOUNCE(5) BOUNCE(5)
expressed in the time unit specified by suffix. See above under
delay_warning_time for possible suffix values.
+ mydomain
+ Expands into the value of the mydomain parameter. With "smt‐
+ putf8_enable = yes", this replaces ACE labels (xn--mumble) with
+ their UTF-8 equivalent.
+
+ This feature is available in Postfix 2.12.
+
+ myhostname
+ Expands into the value of the myhostname parameter. With "smt‐
+ putf8_enable = yes", this replaces ACE labels (xn--mumble) with
+ their UTF-8 equivalent.
+
+ This feature is available in Postfix 2.12.
+
The usage and specification of template message text is subject to the
following restrictions:
- o The template message text is not sent in Postmaster copies of
+ · The template message text is not sent in Postmaster copies of
delivery status notifications.
- o If the template message text contains non-ASCII characters,
+ · If the template message text contains non-ASCII characters,
Postfix requires that the Charset: template header is updated.
Specify an appropriate superset of US-ASCII. A superset is
- needed because Postfix appends ASCII text after the message tem-
+ needed because Postfix appends ASCII text after the message tem‐
plate when it sends a delivery status notification.
SEE ALSO
diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html
index 90a52c4fa..8af0a3cce 100644
--- a/postfix/html/postconf.5.html
+++ b/postfix/html/postconf.5.html
@@ -16413,13 +16413,12 @@ daemon.
daemon.
forward Local forwarding or aliasing. When
-a message is received with "SMTPUTF8 requested", then the forwarded
-(aliased) message automatically has "SMTPUTF8 requested".
+a message is received with "SMTPUTF8 required", then the forwarded
+(aliased) message always has "SMTPUTF8 required".
bounce Submission by the bounce(8) daemon.
-When a message is received with "SMTPUTF8 requested", then the
-delivery status notification automatically has "SMTPUTF8 requested".
-
+When a message is received with "SMTPUTF8 required", then the
+delivery status notification always has "SMTPUTF8 required".
notify Postmaster notification from the
smtp(8) or smtpd(8) daemon.
diff --git a/postfix/man/man5/bounce.5 b/postfix/man/man5/bounce.5
index f039f1810..b8aa51bca 100644
--- a/postfix/man/man5/bounce.5
+++ b/postfix/man/man5/bounce.5
@@ -178,6 +178,18 @@ Expands into the value of the \fBmaximal_queue_lifetime\fR
parameter, expressed in the time unit specified by
\fIsuffix\fR. See above under \fBdelay_warning_time\fR for
possible \fIsuffix\fR values.
+.IP \fBmydomain\fR
+Expands into the value of the \fBmydomain\fR parameter.
+With "smtputf8_enable = yes", this replaces ACE labels
+(xn--mumble) with their UTF-8 equivalent.
+.sp
+This feature is available in Postfix 2.12.
+.IP \fBmyhostname\fR
+Expands into the value of the \fBmyhostname\fR parameter.
+With "smtputf8_enable = yes", this replaces ACE labels
+(xn--mumble) with their UTF-8 equivalent.
+.sp
+This feature is available in Postfix 2.12.
.PP
The usage and specification of template message text is
subject to the following restrictions:
diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5
index 7c73e1d07..50471fc47 100644
--- a/postfix/man/man5/postconf.5
+++ b/postfix/man/man5/postconf.5
@@ -11229,13 +11229,13 @@ daemon.
.br
.IP "\fB forward \fR"
Local forwarding or aliasing. When
-a message is received with "SMTPUTF8 requested", then the forwarded
-(aliased) message automatically has "SMTPUTF8 requested".
+a message is received with "SMTPUTF8 required", then the forwarded
+(aliased) message always has "SMTPUTF8 required".
.br
.IP "\fB bounce \fR"
Submission by the \fBbounce\fR(8) daemon.
-When a message is received with "SMTPUTF8 requested", then the
-delivery status notification automatically has "SMTPUTF8 requested".
+When a message is received with "SMTPUTF8 required", then the
+delivery status notification always has "SMTPUTF8 required".
.br
.IP "\fB notify \fR"
Postmaster notification from the
diff --git a/postfix/proto/bounce b/postfix/proto/bounce
index a76da97c7..b838f5c3a 100644
--- a/postfix/proto/bounce
+++ b/postfix/proto/bounce
@@ -164,6 +164,18 @@
# parameter, expressed in the time unit specified by
# \fIsuffix\fR. See above under \fBdelay_warning_time\fR for
# possible \fIsuffix\fR values.
+# .IP \fBmydomain\fR
+# Expands into the value of the \fBmydomain\fR parameter.
+# With "smtputf8_enable = yes", this replaces ACE labels
+# (xn--mumble) with their UTF-8 equivalent.
+# .sp
+# This feature is available in Postfix 2.12.
+# .IP \fBmyhostname\fR
+# Expands into the value of the \fBmyhostname\fR parameter.
+# With "smtputf8_enable = yes", this replaces ACE labels
+# (xn--mumble) with their UTF-8 equivalent.
+# .sp
+# This feature is available in Postfix 2.12.
# .PP
# The usage and specification of template message text is
# subject to the following restrictions:
diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto
index 98a82e2f0..908d19dbc 100644
--- a/postfix/proto/postconf.proto
+++ b/postfix/proto/postconf.proto
@@ -16097,13 +16097,12 @@ daemon.
daemon.
forward Local forwarding or aliasing. When
-a message is received with "SMTPUTF8 requested", then the forwarded
-(aliased) message automatically has "SMTPUTF8 requested".
+a message is received with "SMTPUTF8 required", then the forwarded
+(aliased) message always has "SMTPUTF8 required".
bounce Submission by the bounce(8) daemon.
-When a message is received with "SMTPUTF8 requested", then the
-delivery status notification automatically has "SMTPUTF8 requested".
-
+When a message is received with "SMTPUTF8 required", then the
+delivery status notification always has "SMTPUTF8 required".
notify Postmaster notification from the
smtp(8) or smtpd(8) daemon.
diff --git a/postfix/src/bounce/Makefile.in b/postfix/src/bounce/Makefile.in
index 3206537a5..1fd913f5c 100644
--- a/postfix/src/bounce/Makefile.in
+++ b/postfix/src/bounce/Makefile.in
@@ -298,6 +298,7 @@ bounce_template.o: ../../include/mac_parse.h
bounce_template.o: ../../include/mail_conf.h
bounce_template.o: ../../include/mail_params.h
bounce_template.o: ../../include/mail_proto.h
+bounce_template.o: ../../include/midna.h
bounce_template.o: ../../include/msg.h
bounce_template.o: ../../include/mymalloc.h
bounce_template.o: ../../include/split_at.h
diff --git a/postfix/src/bounce/bounce_notify_util.c b/postfix/src/bounce/bounce_notify_util.c
index e1c27a122..d48b77948 100644
--- a/postfix/src/bounce/bounce_notify_util.c
+++ b/postfix/src/bounce/bounce_notify_util.c
@@ -227,18 +227,19 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service,
/*
* Bundle up a bunch of parameters and initialize information that will
* be discovered on the fly.
+ *
+ * XXX Instead of overriding the returned-message MIME encoding, separate
+ * the returned-message MIME encoding from the (boiler plate, delivery
+ * status) MIME encoding.
*/
bounce_info = (BOUNCE_INFO *) mymalloc(sizeof(*bounce_info));
bounce_info->service = service;
bounce_info->queue_name = queue_name;
bounce_info->queue_id = queue_id;
bounce_info->smtputf8 = smtputf8;
- /* Fix 20140708: propagate smtputf8 attribute to bounce message. */
- bounce_info->smtputf8_attr =
- vstring_export(vstring_sprintf(vstring_alloc(20), "%s=%d",
- MAIL_ATTR_SMTPUTF8, smtputf8));
/* Fix 20140708: override MIME encoding: addresses may be 8bit. */
- if (bounce_info->smtputf8) {
+ /* Fix 20140718: override MIME encoding: 8bit $myhostname expansion. */
+ if (var_smtputf8_enable /* was: bounce_info->smtputf8 */ ) {
bounce_info->mime_encoding = "8bit";
} else if (strcmp(encoding, MAIL_ATTR_ENC_8BIT) == 0) {
bounce_info->mime_encoding = "8bit";
@@ -442,7 +443,6 @@ void bounce_mail_free(BOUNCE_INFO *bounce_info)
bounce_info->queue_id);
vstring_free(bounce_info->buf);
vstring_free(bounce_info->sender);
- myfree(bounce_info->smtputf8_attr);
myfree(bounce_info->mail_name);
myfree((char *) bounce_info->mime_boundary);
myfree((char *) bounce_info);
@@ -460,6 +460,7 @@ int bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
* headers and will make all addresses fully qualified.
*/
#define STREQ(a, b) (strcasecmp((a), (b)) == 0)
+#define STRNE(a, b) (strcasecmp((a), (b)) != 0)
/*
* Generic headers.
@@ -493,15 +494,25 @@ int bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
/*
* MIME header.
*/
+#define NOT_US_ASCII(tp) \
+ STRNE(bounce_template_charset(template), "us-ascii")
+
+#define NOT_7BIT_MIME(bp) \
+ (bp->mime_encoding && STRNE(bp->mime_encoding, MAIL_ATTR_ENC_7BIT))
+
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
post_mail_fprintf(bounce, "Content-Description: %s", "Notification");
+ /* Fix 20140718: UTF-8 address or $myhostname expansion. */
post_mail_fprintf(bounce, "Content-Type: %s; charset=%s",
- "text/plain", bounce_template_charset(template));
+ "text/plain", NOT_US_ASCII(template) ?
+ bounce_template_charset(template) :
+ NOT_7BIT_MIME(bounce_info) ?
+ "utf-8" : "us-ascii");
/* Fix 20140709: addresses may be 8bit. */
- if (bounce_info->smtputf8)
+ if (NOT_7BIT_MIME(bounce_info))
post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
- bounce_info->mime_encoding);
+ bounce_info->mime_encoding);
post_mail_fputs(bounce, "");
return (vstream_ferror(bounce));
@@ -626,7 +637,7 @@ int bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
(bounce_info->smtputf8 & SMTPUTF8_FLAG_REQUESTED) ?
"global-" : "");
/* Fix 20140709: addresses may be 8bit. */
- if (bounce_info->smtputf8)
+ if (NOT_7BIT_MIME(bounce_info))
post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
bounce_info->mime_encoding);
@@ -647,13 +658,15 @@ int bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
}
post_mail_fprintf(bounce, "X-%s-Queue-ID: %s",
bounce_info->mail_name, bounce_info->queue_id);
+
+#define IS_UTF8_ADDRESS(str, len) \
+ ((str)[0] != 0 && !allascii(str) && valid_utf8_string((str), (len)))
+
/* Fix 20140708: use "utf-8" or "rfc822" as appropriate. */
if (VSTRING_LEN(bounce_info->sender) > 0)
post_mail_fprintf(bounce, "X-%s-Sender: %s; %s",
bounce_info->mail_name, bounce_info->smtputf8
- && STR(bounce_info->sender)[0]
- && !allascii(STR(bounce_info->sender))
- && valid_utf8_string(STR(bounce_info->sender),
+ && IS_UTF8_ADDRESS(STR(bounce_info->sender),
VSTRING_LEN(bounce_info->sender)) ?
"utf-8" : "rfc822", STR(bounce_info->sender));
if (bounce_info->arrival_time > 0)
@@ -672,10 +685,9 @@ int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
post_mail_fputs(bounce, "");
/* Fix 20140708: Don't send "utf-8" type with non-UTF8 address. */
post_mail_fprintf(bounce, "Final-Recipient: %s; %s",
- bounce_info->smtputf8 && rcpt->address[0]
- && !allascii(rcpt->address)
- && valid_utf8_string(rcpt->address,
- strlen(rcpt->address)) ?
+ bounce_info->smtputf8
+ && IS_UTF8_ADDRESS(rcpt->address,
+ strlen(rcpt->address)) ?
"utf-8" : "rfc822", rcpt->address);
/*
@@ -702,10 +714,9 @@ int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
} else if (NON_NULL_EMPTY(rcpt->orig_addr)) {
/* Fix 20140708: Don't send "utf-8" type with non-UTF8 address. */
post_mail_fprintf(bounce, "Original-Recipient: %s; %s",
- bounce_info->smtputf8 && rcpt->orig_addr[0]
- && !allascii(rcpt->orig_addr)
- && valid_utf8_string(rcpt->orig_addr,
- strlen(rcpt->orig_addr)) ?
+ bounce_info->smtputf8
+ && IS_UTF8_ADDRESS(rcpt->orig_addr,
+ strlen(rcpt->orig_addr)) ?
"utf-8" : "rfc822", rcpt->orig_addr);
}
post_mail_fprintf(bounce, "Action: %s",
@@ -807,7 +818,7 @@ int bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
post_mail_fprintf(bounce, "Content-Type: %s",
headers_only == DSN_RET_HDRS ?
"text/rfc822-headers" : "message/rfc822");
- if (bounce_info->mime_encoding)
+ if (NOT_7BIT_MIME(bounce_info))
post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
bounce_info->mime_encoding);
post_mail_fputs(bounce, "");
diff --git a/postfix/src/bounce/bounce_service.h b/postfix/src/bounce/bounce_service.h
index 9ba5ca503..f8cc4d6dc 100644
--- a/postfix/src/bounce/bounce_service.h
+++ b/postfix/src/bounce/bounce_service.h
@@ -85,7 +85,6 @@ typedef struct {
BOUNCE_LOG *log_handle; /* open logfile */
char *mail_name; /* $mail_name, cooked */
int smtputf8; /* SMTPUTF8 requested */
- char *smtputf8_attr; /* pre-formatted record value */
} BOUNCE_INFO;
/* */
diff --git a/postfix/src/bounce/bounce_template.c b/postfix/src/bounce/bounce_template.c
index 7888a1867..f5b7e19a1 100644
--- a/postfix/src/bounce/bounce_template.c
+++ b/postfix/src/bounce/bounce_template.c
@@ -117,6 +117,9 @@
#include
#include
#include
+#ifndef NO_EAI
+#include
+#endif
/* Global library. */
@@ -198,6 +201,21 @@ static const BOUNCE_TIME_PARAMETER time_parameter[] = {
0, 0,
};
+ /*
+ * Parameters whose value may have to be converted to UTF-8 for presentation
+ * purposes.
+ */
+typedef struct {
+ const char *param_name; /* parameter name */
+ char **value; /* parameter value */
+} BOUNCE_STR_PARAMETER;
+
+static const BOUNCE_STR_PARAMETER str_parameter[] = {
+ VAR_MYHOSTNAME, &var_myhostname,
+ VAR_MYDOMAIN, &var_mydomain,
+ 0, 0,
+};
+
/*
* SLMs.
*/
@@ -387,8 +405,11 @@ static const char *bounce_template_lookup(const char *key, int unused_mode,
BOUNCE_TEMPLATE *tp = (BOUNCE_TEMPLATE *) context;
const BOUNCE_TIME_PARAMETER *bp;
const BOUNCE_TIME_DIVISOR *bd;
+ const BOUNCE_STR_PARAMETER *sp;
static VSTRING *buf;
int result;
+ const char *asc_val;
+ const char *utf8_val;
/*
* Look for parameter names that can have a time unit suffix, and scale
@@ -426,6 +447,33 @@ static const char *bounce_template_lookup(const char *key, int unused_mode,
key + bp->param_name_len + 1, key);
}
}
+
+ /*
+ * Look for parameter names that may have to be up-converted for
+ * presentation purposes.
+ */
+#ifndef NO_EAI
+ if (var_smtputf8_enable) {
+ for (sp = str_parameter; sp->param_name; sp++) {
+ if (strcmp(key, sp->param_name) == 0) {
+ asc_val = sp->value[0];
+ if (!allascii(asc_val)) {
+ msg_warn("%s: conversion \"%s\" failed: "
+ "non-ASCII input value: \"%s\"",
+ tp->origin, key, asc_val);
+ return (asc_val);
+ } else if ((utf8_val = midna_ascii_to_utf8(asc_val)) == 0) {
+ msg_warn("%s: conversion \"%s\" failed: "
+ "input value: \"%s\"",
+ tp->origin, key, asc_val);
+ return (asc_val);
+ } else {
+ return (utf8_val);
+ }
+ }
+ }
+ }
+#endif
return (mail_conf_lookup_eval(key));
}
@@ -453,13 +501,12 @@ void bounce_template_expand(BOUNCE_XP_PUT_FN out_fn, VSTREAM *fp,
VSTRING *buf = vstring_alloc(100);
const char **cpp;
int stat;
- const char *filter = "\t !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
if (tp->flags & BOUNCE_TMPL_FLAG_NEW_BUFFER)
bounce_template_parse_buffer(tp);
for (cpp = tp->message_text; *cpp; cpp++) {
- stat = mac_expand(buf, *cpp, MAC_EXP_FLAG_NONE, filter,
+ stat = mac_expand(buf, *cpp, MAC_EXP_FLAG_PRINTABLE, (char *) 0,
bounce_template_lookup, (char *) tp);
if (stat & MAC_PARSE_ERROR)
msg_fatal("%s: bad $name syntax in %s template: %s",
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index beb6e6c49..e216b07af 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20140716"
+#define MAIL_RELEASE_DATE "20140720"
#define MAIL_VERSION_NUMBER "2.12"
#ifdef SNAPSHOT
diff --git a/postfix/src/global/uxtext.c b/postfix/src/global/uxtext.c
index ccd0d84a8..aade6a8ce 100644
--- a/postfix/src/global/uxtext.c
+++ b/postfix/src/global/uxtext.c
@@ -146,10 +146,10 @@ VSTRING *uxtext_quote(VSTRING *quoted, const char *unquoted, const char *special
VSTRING *uxtext_unquote_append(VSTRING *unquoted, const char *quoted)
{
- const char *cp;
+ const unsigned char *cp;
int ch;
- for (cp = quoted; (ch = *cp) != 0; cp++) {
+ for (cp = (const unsigned char *) quoted; (ch = *cp) != 0; cp++) {
if (ch == '\\' && cp[1] == 'x' && cp[2] == '{') {
cp += 2;
int unicode = 0;
diff --git a/postfix/src/global/xtext.c b/postfix/src/global/xtext.c
index 4e7373344..e5605d7be 100644
--- a/postfix/src/global/xtext.c
+++ b/postfix/src/global/xtext.c
@@ -101,10 +101,10 @@ VSTRING *xtext_quote(VSTRING *quoted, const char *unquoted, const char *special)
VSTRING *xtext_unquote_append(VSTRING *unquoted, const char *quoted)
{
- const char *cp;
+ const unsigned char *cp;
int ch;
- for (cp = quoted; (ch = *cp) != 0; cp++) {
+ for (cp = (const unsigned char *) quoted; (ch = *cp) != 0; cp++) {
if (ch == '+') {
if (ISDIGIT(cp[1]))
ch = (cp[1] - '0') << 4;
diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in
index b6c7d5795..4dbe47db4 100644
--- a/postfix/src/util/Makefile.in
+++ b/postfix/src/util/Makefile.in
@@ -1523,8 +1523,6 @@ load_file.o: vbuf.h
load_file.o: vstream.h
load_file.o: warn_stat.h
load_lib.o: load_lib.c
-load_lib.o: load_lib.h
-load_lib.o: msg.h
load_lib.o: sys_defs.h
lowercase.o: lowercase.c
lowercase.o: stringops.h
@@ -1542,6 +1540,7 @@ mac_expand.o: mac_expand.h
mac_expand.o: mac_parse.h
mac_expand.o: msg.h
mac_expand.o: mymalloc.h
+mac_expand.o: stringops.h
mac_expand.o: sys_defs.h
mac_expand.o: vbuf.h
mac_expand.o: vstring.h
@@ -1599,6 +1598,7 @@ midna.o: msg.h
midna.o: mymalloc.h
midna.o: stringops.h
midna.o: sys_defs.h
+midna.o: valid_hostname.h
midna.o: vbuf.h
midna.o: vstring.h
msg.o: msg.c
diff --git a/postfix/src/util/mac_expand.c b/postfix/src/util/mac_expand.c
index f9fd2e82a..8c6f6bb31 100644
--- a/postfix/src/util/mac_expand.c
+++ b/postfix/src/util/mac_expand.c
@@ -54,6 +54,8 @@
/* string, including macro names in the values of conditional
/* expressions. Do not expand macros, and do not write to the
/* result argument.
+/* .IP MAC_EXP_FLAG_PRINTABLE
+/* Use the printable() function instead of \fIfilter\fR.
/* .PP
/* The constant MAC_EXP_FLAG_NONE specifies a manifest null value.
/* .RE
@@ -103,6 +105,7 @@
#include
#include
#include
+#include
#include
#include
@@ -197,7 +200,9 @@ static int mac_expand_callback(int type, VSTRING *buf, char *ptr)
} else {
len = VSTRING_LEN(mc->result);
vstring_strcat(mc->result, text);
- if (mc->filter) {
+ if (mc->flags & MAC_EXP_FLAG_PRINTABLE) {
+ printable(vstring_str(mc->result) + len, '_');
+ } else if (mc->filter) {
cp = vstring_str(mc->result) + len;
while (*(cp += strspn(cp, mc->filter)))
*cp++ = '_';
diff --git a/postfix/src/util/mac_expand.h b/postfix/src/util/mac_expand.h
index f08cd9c86..f8fcffebd 100644
--- a/postfix/src/util/mac_expand.h
+++ b/postfix/src/util/mac_expand.h
@@ -24,6 +24,7 @@
#define MAC_EXP_FLAG_RECURSE (1<<0)
#define MAC_EXP_FLAG_APPEND (1<<1)
#define MAC_EXP_FLAG_SCAN (1<<2)
+#define MAC_EXP_FLAG_PRINTABLE (1<<3)
/*
* Real lookup or just a test?
diff --git a/postfix/src/util/midna.c b/postfix/src/util/midna.c
index 87f71e676..446af8991 100644
--- a/postfix/src/util/midna.c
+++ b/postfix/src/util/midna.c
@@ -10,6 +10,9 @@
/*
/* const char *midna_utf8_to_ascii(
/* const char *name)
+/*
+/* const char *midna_ascii_to_utf8(
+/* const char *name)
/* DESCRIPTION
/* The functions in this module transform domain names from
/* or to IDNA form. The result is cached to avoid repeated
@@ -18,6 +21,9 @@
/* midna_utf8_to_ascii() converts an UTF-8 domain name to
/* ASCII. The result is a null pointer in case of error.
/*
+/* midna_ascii_to_utf8() converts an ASCII domain name to
+/* UTF-8. The result is a null pointer in case of error.
+/*
/* midna_cache_size specifies the size of the conversion result
/* cache. This value is used only once, upon the first lookup
/* request.
@@ -55,6 +61,7 @@
#include
#include
#include
+#include
#include
/*
@@ -99,9 +106,44 @@ static void *midna_utf8_to_ascii_create(const char *name, void *unused_context)
}
}
-/* midna_utf8_to_ascii_free - cache element destructor */
+/* midna_ascii_to_utf8_create - convert ASCII domain to UTF8 */
-static void midna_utf8_to_ascii_free(void *value, void *unused_context)
+static void *midna_ascii_to_utf8_create(const char *name, void *unused_context)
+{
+ const char myname[] = "midna_ascii_to_utf8_create";
+ char buf[1024]; /* XXX */
+ UErrorCode error = U_ZERO_ERROR;
+ UIDNAInfo info = UIDNA_INFO_INITIALIZER;
+ UIDNA *idna;
+ int anl;
+
+ /*
+ * Paranoia: do not expose uidna_*() to unfiltered network data.
+ */
+ if (valid_hostname(name, DONT_GRIPE) == 0) {
+ msg_warn("%s: Problem translating domain \"%s\" to UTF8 form: %s",
+ myname, name, "malformed ASCII");
+ return (0);
+ }
+ idna = uidna_openUTS46(UIDNA_DEFAULT, &error);
+ anl = uidna_nameToUnicodeUTF8(idna,
+ name, strlen(name),
+ buf, sizeof(buf),
+ &info,
+ &error);
+ uidna_close(idna);
+ if (U_SUCCESS(error) && info.errors == 0 && anl > 0) {
+ return (mystrndup(buf, anl));
+ } else {
+ msg_warn("%s: Problem translating domain \"%s\" to IDNA form: %s",
+ myname, name, u_errorName(error));
+ return (0);
+ }
+}
+
+/* midna_cache_free - cache element destructor */
+
+static void midna_cache_free(void *value, void *unused_context)
{
if (value)
myfree(value);
@@ -116,11 +158,25 @@ const char *midna_utf8_to_ascii(const char *name)
if (midna_utf8_to_ascii_cache == 0)
midna_utf8_to_ascii_cache = ctable_create(midna_cache_size,
midna_utf8_to_ascii_create,
- midna_utf8_to_ascii_free,
+ midna_cache_free,
(void *) 0);
return (ctable_locate(midna_utf8_to_ascii_cache, name));
}
+/* midna_ascii_to_utf8 - convert UTF8 hostname to ASCII */
+
+const char *midna_ascii_to_utf8(const char *name)
+{
+ static CTABLE *midna_ascii_to_utf8_cache = 0;
+
+ if (midna_ascii_to_utf8_cache == 0)
+ midna_ascii_to_utf8_cache = ctable_create(midna_cache_size,
+ midna_ascii_to_utf8_create,
+ midna_cache_free,
+ (void *) 0);
+ return (ctable_locate(midna_ascii_to_utf8_cache, name));
+}
+
#ifdef TEST
/*
@@ -128,6 +184,7 @@ const char *midna_utf8_to_ascii(const char *name)
* stderr.
*/
#include
+#include
#include /* XXX temp_utf8_kludge */
#include
@@ -138,17 +195,44 @@ const char *midna_utf8_to_ascii(const char *name)
int main(int argc, char **argv)
{
VSTRING *buffer = vstring_alloc(1);
- const char *res;
+ const char *bp;
+ const char *ascii;
+ const char *utf8;
+
+ if (setlocale(LC_ALL, "C") == 0)
+ msg_fatal("setlocale(LC_ALL, C) failed: %m");
msg_vstream_init(argv[0], VSTREAM_ERR);
msg_verbose = 1;
temp_utf8_kludge = 1;
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
- msg_info("testing: \"%s\"", vstring_str(buffer));
- res = midna_utf8_to_ascii(vstring_str(buffer));
- if (res != 0)
- msg_info("result: \"%s\"", res);
+ msg_info("testing: \"%s\"", bp = vstring_str(buffer));
+ if (!allascii(bp)) {
+ ascii = midna_utf8_to_ascii(bp);
+ if (ascii != 0) {
+ msg_info("\"%s\" -> \"%s\"", bp, ascii);
+ utf8 = midna_ascii_to_utf8(ascii);
+ if (utf8 != 0) {
+ msg_info("\"%s\" -> \"%s\" -> \"%s\"",
+ bp, ascii, utf8);
+ if (strcmp(utf8, bp) != 0)
+ msg_warn("\"%s\" != \"%s\"", bp, utf8);
+ }
+ }
+ } else {
+ utf8 = midna_ascii_to_utf8(bp);
+ if (utf8 != 0) {
+ msg_info("\"%s\" -> \"%s\"", bp, utf8);
+ ascii = midna_utf8_to_ascii(utf8);
+ if (ascii != 0) {
+ msg_info("\"%s\" -> \"%s\" -> \"%s\"",
+ bp, utf8, ascii);
+ if (strcmp(ascii, bp) != 0)
+ msg_warn("\"%s\" != \"%s\"", bp, ascii);
+ }
+ }
+ }
}
exit(0);
}
diff --git a/postfix/src/util/midna.h b/postfix/src/util/midna.h
index 5a24a113e..1d2477773 100644
--- a/postfix/src/util/midna.h
+++ b/postfix/src/util/midna.h
@@ -15,6 +15,7 @@
* External interface.
*/
extern const char *midna_utf8_to_ascii(const char *);
+extern const char *midna_ascii_to_utf8(const char *);
/* LICENSE
/* .ad