]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.11-20130405
authorWietse Venema <wietse@porcupine.org>
Fri, 5 Apr 2013 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sat, 6 Apr 2013 04:20:09 +0000 (00:20 -0400)
34 files changed:
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/html/local.8.html
postfix/html/pipe.8.html
postfix/html/postconf.5.html
postfix/html/smtpd.8.html
postfix/html/trivial-rewrite.8.html
postfix/man/man5/postconf.5
postfix/man/man8/local.8
postfix/man/man8/pipe.8
postfix/man/man8/smtpd.8
postfix/man/man8/trivial-rewrite.8
postfix/proto/postconf.proto
postfix/src/global/mail_addr_find.c
postfix/src/global/mail_params.c
postfix/src/global/mail_version.h
postfix/src/global/split_addr.c
postfix/src/global/split_addr.h
postfix/src/global/strip_addr.c
postfix/src/global/strip_addr.h
postfix/src/global/strip_addr.ref
postfix/src/local/bounce_workaround.c
postfix/src/local/local.c
postfix/src/local/local_expand.c
postfix/src/local/recipient.c
postfix/src/local/resolve.c
postfix/src/oqmgr/qmgr_message.c
postfix/src/pipe/pipe.c
postfix/src/qmgr/qmgr_message.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_check.c
postfix/src/trivial-rewrite/transport.c
postfix/src/trivial-rewrite/trivial-rewrite.c
postfix/src/util/dict.c

index b2e474cd6c25d20b55dd0d77b90570d8a274b878..e885287b7fe14378cd2e8041200c4c5c71242dd7 100644 (file)
@@ -18410,3 +18410,24 @@ Apologies for any names omitted.
 
        Documentation: in smtpd.c, the comment that justifies the
        454 reply for "TLS unavailable" cited the wrong RFC.
+
+20130404
+
+       Human factors: warning when a main.cf parameter has multiple
+       entries with different values.  File: util/dict.c.
+
+20130405
+
+       Feature: the recipient_delimiter parameter can now specify
+       a set of characters. A user name is now separated from its
+       address extension by the first character that matches the
+       recipient_delimiter set.  Files: proto/postconf.proto,
+       src/global/mail_addr_find.c, src/global/mail_params.c,
+       src/global/split_addr.c, src/global/split_addr.h,
+       src/global/strip_addr.c, src/global/strip_addr.h,
+       src/global/strip_addr.ref, src/local/bounce_workaround.c,
+       src/local/local.c, src/local/local_expand.c, src/local/recipient.c,
+       src/local/resolve.c, src/oqmgr/qmgr_message.c, src/pipe/pipe.c,
+       src/qmgr/qmgr_message.c, src/smtpd/smtpd.c,
+       src/smtpd/smtpd_check.c, src/trivial-rewrite/transport.c,
+       src/trivial-rewrite/trivial-rewrite.c.
index 76565134848c7774b7ce775136c4b01dd342dd3b..593f1d7c3c6086da0cba65170096e7c69e4228a3 100644 (file)
@@ -14,6 +14,19 @@ specifies the release date of a stable release or snapshot release.
 If you upgrade from Postfix 2.9 or earlier, read RELEASE_NOTES-2.10
 before proceeding.
 
+Major changes with snapshot 20130405
+====================================
+
+The recipient_delimiter parameter can now specify a set of characters.
+A user name is now separated from its address extension by the first
+character that matches the recipient_delimiter set.
+
+For example, specify "recipient_delimiter = +-" to support both the
+Postfix-style "+" and the qmail-style "-" extension delimiter.  
+
+As before, this implementation recognizes one delimiter character
+per email address, and one address extension per email address.
+
 Major changes with snapshot 20130319
 ====================================
 
index e2cfed120f7efcacf459d75a853fa622d34a4911..ee4dff4de3fdd3b69e8c79c5a6e02e8c54edfd40 100644 (file)
@@ -608,8 +608,8 @@ LOCAL(8)                                                              LOCAL(8)
               tory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
-              The separator between user names and address exten-
-              sions (user+foo).
+              The set of characters that can separate a user name
+              from its address extension (user+foo).
 
        <b><a href="postconf.5.html#require_home_directory">require_home_directory</a> (no)</b>
               Require that a <a href="local.8.html"><b>local</b>(8)</a> recipient's home  directory
index 94be20a98683fcfb9e272ee20c11f31fd04191f4..afe2b5a2e2d7fa6f892033bca32a48dacfa9f315 100644 (file)
@@ -481,8 +481,8 @@ PIPE(8)                                                                PIPE(8)
               tory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
-              The separator between user names and address exten-
-              sions (user+foo).
+              The set of characters that can separate a user name
+              from its address extension (user+foo).
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
index 1c7b27b8e178f4d422ca54e36805f41d12d2ed61..09d0cf166c507108b69f8ebd4f8e3c9ab224b59f 100644 (file)
@@ -1451,7 +1451,9 @@ with the character set that is specified with the
 
 <dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>${name?value}</b></dt>
 
@@ -3254,7 +3256,9 @@ filtered with the character set that is specified with the
 
 <dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>${name?value}</b></dt>
 
@@ -5308,7 +5312,9 @@ The following $name expansions are done on <a href="postconf.5.html#luser_relay"
 
 <dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>$shell</b></dt>
 
@@ -8498,22 +8504,53 @@ Example:
 <DT><b><a name="recipient_delimiter">recipient_delimiter</a>
 (default: empty)</b></DT><DD>
 
-<p>
-The separator between user names and address extensions (user+foo).
-See <a href="canonical.5.html">canonical(5)</a>, <a href="local.8.html">local(8)</a>, <a href="relocated.5.html">relocated(5)</a> and <a href="virtual.5.html">virtual(5)</a> for the
-effects this has on aliases, canonical, virtual, relocated and
-on .forward file lookups.  Basically, the software tries user+foo
-and .forward+foo before trying user and .forward.
+<p> The set of characters that can separate a user name from its
+address extension (user+foo).  See <a href="canonical.5.html">canonical(5)</a>, <a href="local.8.html">local(8)</a>, <a href="relocated.5.html">relocated(5)</a>
+and <a href="virtual.5.html">virtual(5)</a> for the effects this has on aliases, canonical,
+virtual, and relocated lookups.  Basically, the software tries
+user+foo and .forward+foo before trying user and .forward.  </p>
+
+<p> This implementation recognizes one delimiter character per email
+address, and one address extension per email address.  </p>
+
+<p> When the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> set contains multiple characters
+(Postfix 2.11 and later), a user name is separated from its address
+extension by the first character that matches the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>
+set. </p>
+
+<p> When used in <a href="postconf.5.html#forward_path">forward_path</a>, ${<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>} is replaced
+with the recipient delimiter that was found in the recipient email
+address (Postfix 2.11 and later), or it is replaced with the <a href="postconf.5.html">main.cf</a>
+<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> parameter value (Postfix 2.10 and earlier).
 </p>
 
+<p> The <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> is not applied to the mailer-daemon
+address, the postmaster address, or the double-bounce address. With
+the default "<a href="postconf.5.html#owner_request_special">owner_request_special</a> = yes" setting, the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>
+is also not applied to addresses with the special "owner-" prefix
+or the special "-request" suffix. </p>
+
 <p>
-Example:
+Examples:
 </p>
 
 <pre>
+# Handle Postfix-style extensions.
 <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> = +
 </pre>
 
+<pre>
+# Handle both Postfix and qmail extensions (Postfix 2.11 and later).
+recipient_delimiters = +-
+</pre>
+
+<pre>
+# Use .forward for mail without address extension, and for mail with
+# an unrecognized address extension.
+<a href="postconf.5.html#forward_path">forward_path</a> = $home/.forward${<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>}${extension},
+    $home/.forward,
+</pre>
+
 
 </DD>
 
index dc934bb9091698fed30550a8252689f17ad60156..b879d1418b91c10cb8c05614d2b4fef82dc0e10d 100644 (file)
@@ -1293,8 +1293,8 @@ SMTPD(8)                                                              SMTPD(8)
               tory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
-              The separator between user names and address exten-
-              sions (user+foo).
+              The set of characters that can separate a user name
+              from its address extension (user+foo).
 
        <b><a href="postconf.5.html#smtpd_banner">smtpd_banner</a> ($<a href="postconf.5.html#myhostname">myhostname</a> ESMTP $<a href="postconf.5.html#mail_name">mail_name</a>)</b>
               The  text  that  follows the 220 status code in the
index 6da7aced56749467ed476fb914daced52c1cffd9..e47d39e0ecb0873a36d511cf0ff702cf94e1adb0 100644 (file)
@@ -133,8 +133,8 @@ TRIVIAL-REWRITE(8)                                          TRIVIAL-REWRITE(8)
               information.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
-              The separator between user names and address exten-
-              sions (user+foo).
+              The set of characters that can separate a user name
+              from its address extension (user+foo).
 
        <b><a href="postconf.5.html#swap_bangpath">swap_bangpath</a> (yes)</b>
               Enable   the   rewriting   of   "site!user"    into
index 3f981492718a4a5704d784eff14173f0a047c6e0..8d22aa22d83cadae8af045a70ae248ffdb91ed83 100644 (file)
@@ -835,7 +835,9 @@ The recipient domain.
 The entire recipient localpart.
 .br
 .IP "\fB$recipient_delimiter\fR"
-The system-wide recipient address extension delimiter.
+The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier).
 .br
 .IP "\fB${name?value}\fR"
 Expands to \fIvalue\fR when \fI$name\fR is non-empty.
@@ -1919,7 +1921,9 @@ The recipient domain.
 The entire recipient localpart.
 .br
 .IP "\fB$recipient_delimiter\fR"
-The system-wide recipient address extension delimiter.
+The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier).
 .br
 .IP "\fB${name?value}\fR"
 Expands to \fIvalue\fR when \fI$name\fR is non-empty.
@@ -3068,7 +3072,9 @@ The entire recipient address localpart.
 The full recipient address.
 .br
 .IP "\fB$recipient_delimiter\fR"
-The system-wide recipient address extension delimiter.
+The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier).
 .br
 .IP "\fB$shell\fR"
 The recipient's login shell.
@@ -5095,21 +5101,61 @@ recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
 .ad
 .ft R
 .SH recipient_delimiter (default: empty)
-The separator between user names and address extensions (user+foo).
-See \fBcanonical\fR(5), \fBlocal\fR(8), \fBrelocated\fR(5) and \fBvirtual\fR(5) for the
-effects this has on aliases, canonical, virtual, relocated and
-on .forward file lookups.  Basically, the software tries user+foo
-and .forward+foo before trying user and .forward.
+The set of characters that can separate a user name from its
+address extension (user+foo).  See \fBcanonical\fR(5), \fBlocal\fR(8), \fBrelocated\fR(5)
+and \fBvirtual\fR(5) for the effects this has on aliases, canonical,
+virtual, and relocated lookups.  Basically, the software tries
+user+foo and .forward+foo before trying user and .forward.
+.PP
+This implementation recognizes one delimiter character per email
+address, and one address extension per email address.
+.PP
+When the recipient_delimiter set contains multiple characters
+(Postfix 2.11 and later), a user name is separated from its address
+extension by the first character that matches the recipient_delimiter
+set.
+.PP
+When used in forward_path, ${recipient_delimiter} is replaced
+with the recipient delimiter that was found in the recipient email
+address (Postfix 2.11 and later), or it is replaced with the main.cf
+recipient_delimiter parameter value (Postfix 2.10 and earlier).
+.PP
+The recipient_delimiter is not applied to the mailer-daemon
+address, the postmaster address, or the double-bounce address. With
+the default "owner_request_special = yes" setting, the recipient_delimiter
+is also not applied to addresses with the special "owner-" prefix
+or the special "-request" suffix.
 .PP
-Example:
+Examples:
 .PP
 .nf
 .na
 .ft C
+# Handle Postfix-style extensions.
 recipient_delimiter = +
 .fi
 .ad
 .ft R
+.PP
+.nf
+.na
+.ft C
+# Handle both Postfix and qmail extensions (Postfix 2.11 and later).
+recipient_delimiters = +-
+.fi
+.ad
+.ft R
+.PP
+.nf
+.na
+.ft C
+# Use .forward for mail without address extension, and for mail with
+# an unrecognized address extension.
+forward_path = $home/.forward${recipient_delimiter}${extension},
+    $home/.forward,
+.fi
+.ad
+.ft R
 .SH reject_code (default: 554)
 The numerical Postfix SMTP server response code when a remote SMTP
 client request is rejected by the "reject" restriction.
index 5b6bc81b4484454eb0a1c7f1993e3019241e8134..b872ce6fe8b061a727865d4ba01cf5db50abecd7 100644 (file)
@@ -575,7 +575,8 @@ key to the lookup result.
 .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 The location of the Postfix top-level queue directory.
 .IP "\fBrecipient_delimiter (empty)\fR"
-The separator between user names and address extensions (user+foo).
+The set of characters that can separate a user name from its
+address extension (user+foo).
 .IP "\fBrequire_home_directory (no)\fR"
 Require that a \fBlocal\fR(8) recipient's home directory exists
 before mail delivery is attempted.
index ec088ac6b5508606213bd2369e9d136550c1396f..a24a5ee48d08ed1483d0fccd661f99e6dc2cd5a0 100644 (file)
@@ -412,7 +412,8 @@ The process name of a Postfix command or daemon process.
 .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 The location of the Postfix top-level queue directory.
 .IP "\fBrecipient_delimiter (empty)\fR"
-The separator between user names and address extensions (user+foo).
+The set of characters that can separate a user name from its
+address extension (user+foo).
 .IP "\fBsyslog_facility (mail)\fR"
 The syslog facility of Postfix logging.
 .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
index d6c8bce001efcf3e26683a43b57d8433ab051992..fd71de239f1d6d1b840916fde42c900a8a6131d6 100644 (file)
@@ -1012,7 +1012,8 @@ The process name of a Postfix command or daemon process.
 .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 The location of the Postfix top-level queue directory.
 .IP "\fBrecipient_delimiter (empty)\fR"
-The separator between user names and address extensions (user+foo).
+The set of characters that can separate a user name from its
+address extension (user+foo).
 .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR"
 The text that follows the 220 status code in the SMTP greeting
 banner.
index ca85bd36bf19fc00629d96b564b7c71d6e67e07c..134c108be5c0127bc8dd86eb6743ab4571cb66bc 100644 (file)
@@ -130,7 +130,8 @@ addresses without domain information.
 With locally submitted mail, append the string ".$mydomain" to
 addresses that have no ".domain" information.
 .IP "\fBrecipient_delimiter (empty)\fR"
-The separator between user names and address extensions (user+foo).
+The set of characters that can separate a user name from its
+address extension (user+foo).
 .IP "\fBswap_bangpath (yes)\fR"
 Enable the rewriting of "site!user" into "user@site".
 .PP
index c42856f1bd9ab0b1f9591e20b415d5bd4ad16846..9c8d9fd8c32b8a569544007ae8fbd2bcf0176332 100644 (file)
@@ -1609,7 +1609,9 @@ execution_directory_expansion_filter parameter.  </p>
 
 <dt><b>$recipient_delimiter</b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>${name?value}</b></dt>
 
@@ -1670,7 +1672,9 @@ forward_expansion_filter parameter.  </p>
 
 <dt><b>$recipient_delimiter</b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>${name?value}</b></dt>
 
@@ -2404,7 +2408,9 @@ The following $name expansions are done on luser_relay:
 
 <dt><b>$recipient_delimiter</b></dt>
 
-<dd>The system-wide recipient address extension delimiter. </dd>
+<dd>The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier). </dd>
 
 <dt><b>$shell</b></dt>
 
@@ -3495,24 +3501,55 @@ Example:
 recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
 </pre>
 
-%PARAM recipient_delimiter 
+%PARAM recipient_delimiter
 
-<p>
-The separator between user names and address extensions (user+foo).
-See canonical(5), local(8), relocated(5) and virtual(5) for the
-effects this has on aliases, canonical, virtual, relocated and
-on .forward file lookups.  Basically, the software tries user+foo
-and .forward+foo before trying user and .forward.
+<p> The set of characters that can separate a user name from its
+address extension (user+foo).  See canonical(5), local(8), relocated(5)
+and virtual(5) for the effects this has on aliases, canonical,
+virtual, and relocated lookups.  Basically, the software tries
+user+foo and .forward+foo before trying user and .forward.  </p>
+
+<p> This implementation recognizes one delimiter character per email
+address, and one address extension per email address.  </p>
+
+<p> When the recipient_delimiter set contains multiple characters
+(Postfix 2.11 and later), a user name is separated from its address
+extension by the first character that matches the recipient_delimiter
+set. </p>
+
+<p> When used in forward_path, ${recipient_delimiter} is replaced
+with the recipient delimiter that was found in the recipient email
+address (Postfix 2.11 and later), or it is replaced with the main.cf
+recipient_delimiter parameter value (Postfix 2.10 and earlier).
 </p>
 
+<p> The recipient_delimiter is not applied to the mailer-daemon
+address, the postmaster address, or the double-bounce address. With
+the default "owner_request_special = yes" setting, the recipient_delimiter
+is also not applied to addresses with the special "owner-" prefix
+or the special "-request" suffix. </p>
+
 <p>
-Example:
+Examples:
 </p>
-
+  
 <pre>
+# Handle Postfix-style extensions.
 recipient_delimiter = +
 </pre>
 
+<pre>
+# Handle both Postfix and qmail extensions (Postfix 2.11 and later).
+recipient_delimiters = +-
+</pre>
+
+<pre>
+# Use .forward for mail without address extension, and for mail with
+# an unrecognized address extension.
+forward_path = $home/.forward${recipient_delimiter}${extension},
+    $home/.forward,
+</pre>
+
 %PARAM reject_code 554
 
 <p>
index ed8caab6dc74e3d9aa634331b26d5b709d21511a..e21dd360018da3ca0d806276167dd012de90e410 100644 (file)
@@ -109,7 +109,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
     if (*var_rcpt_delim == 0) {
        bare_key = saved_ext = 0;
     } else {
-       bare_key = strip_addr(full_key, &saved_ext, *var_rcpt_delim);
+       bare_key = strip_addr(full_key, &saved_ext, var_rcpt_delim);
     }
 
     /*
index 94ea155d7eb5bc79e006599973eda254a49e7d71..5bc95c659759aff6423b27f6f0b78107441837e7 100644 (file)
@@ -557,7 +557,7 @@ void    mail_params_init()
        VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0,
        VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0,
        VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0,
-       VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 1,
+       VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 0,
        VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0,
        VAR_FFLUSH_DOMAINS, DEF_FFLUSH_DOMAINS, &var_fflush_domains, 0, 0,
        VAR_EXPORT_ENVIRON, DEF_EXPORT_ENVIRON, &var_export_environ, 0, 0,
index a869f257d30069be25d76c11a4e14b09338fe77e..434e516e84da5d54c7459865ddd017bdfffbb9e5 100644 (file)
@@ -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      "20130403"
+#define MAIL_RELEASE_DATE      "20130405"
 #define MAIL_VERSION_NUMBER    "2.11"
 
 #ifdef SNAPSHOT
index 279ad4fb697cfa66f21c2c2844fc8e12a52fbe8f..7e7cc27c8c19e207b10bc0dd8cf203ec09378a71 100644 (file)
@@ -6,12 +6,12 @@
 /* SYNOPSIS
 /*     #include <split_addr.h>
 /*
-/*     char    *split_addr(localpart, delimiter)
+/*     char    *split_addr(localpart, delimiter_set)
 /*     char    *localpart;
-/*     int     delimiter;
+/*     const char *delimiter_set;
 /* DESCRIPTION
 /*     split_addr() null-terminates \fIlocalpart\fR at the first
-/*     occurrence of the \fIdelimiter\fR character found, and
+/*     occurrence of the \fIdelimiter\fR character(s) found, and
 /*     returns a pointer to the remainder.
 /*
 /*     Reserved addresses are not split: postmaster, mailer-daemon,
@@ -50,7 +50,7 @@
 
 /* split_addr - split address with extreme prejudice */
 
-char   *split_addr(char *localpart, int delimiter)
+char   *split_addr(char *localpart, const char *delimiter_set)
 {
     int     len;
 
@@ -67,7 +67,7 @@ char   *split_addr(char *localpart, int delimiter)
     /*
      * Backwards compatibility: don't split owner-foo or foo-request.
      */
-    if (delimiter == '-' && var_ownreq_special != 0) {
+    if (strchr(delimiter_set, '-') != 0 && var_ownreq_special != 0) {
        if (strncasecmp(localpart, "owner-", 6) == 0)
            return (0);
        if ((len = strlen(localpart) - 8) > 0
@@ -79,5 +79,10 @@ char   *split_addr(char *localpart, int delimiter)
      * Safe to split this address. Do not split the address if the result
      * would have a null localpart.
      */
-    return (delimiter == *localpart ? 0 : split_at(localpart, delimiter));
+    if ((len = strcspn(localpart, delimiter_set)) == 0 || localpart[len] == 0) {
+       return (0);
+    } else {
+       localpart[len] = 0;
+       return (localpart + len + 1);
+    }
 }
index 1c87fb99ac8d6a048df2c884be8082acca8a481d..fa89faeae7bb71c504a052ff1d53c6af78e4db95 100644 (file)
@@ -13,7 +13,7 @@
 
  /* External interface. */
 
-extern char *split_addr(char *, int);
+extern char *split_addr(char *, const char *);
 
 /* LICENSE
 /* .ad
index 803db87f8fcf7e426d2721f57914fc7c374754e2..6792d35f327f09c3c5b58d491f364fb77a58f1f5 100644 (file)
@@ -6,10 +6,10 @@
 /* SYNOPSIS
 /*     #include <strip_addr.h>
 /*
-/*     char    *strip_addr(address, extension, delimiter)
+/*     char    *strip_addr(address, extension, delimiter_set)
 /*     const char *address;
 /*     char    **extension;
-/*     int     delimiter;
+/*     const char *delimiter_set;
 /* DESCRIPTION
 /*     strip_addr() takes an address and either returns a null
 /*     pointer when the address contains no address extension,
@@ -25,8 +25,8 @@
 /*     that had to be chopped off.
 /*     The copy includes the recipient address delimiter.
 /*     The caller is expected to pass the copy to myfree().
-/* .IP delimiter
-/*     Recipient address delimiter.
+/* .IP delimiter_set
+/*     Set of recipient address delimiter characters.
 /* SEE ALSO
 /*     split_addr(3) strip extension from localpart
 /* LICENSE
@@ -56,7 +56,7 @@
 
 /* strip_addr - strip extension from address */
 
-char   *strip_addr(const char *full, char **extension, int delimiter)
+char   *strip_addr(const char *full, char **extension, const char *delimiter_set)
 {
     char   *ratsign;
     char   *extent;
@@ -66,16 +66,16 @@ char   *strip_addr(const char *full, char **extension, int delimiter)
     /*
      * A quick test to eliminate inputs without delimiter anywhere.
      */
-    if (delimiter == 0 || strchr(full, delimiter) == 0) {
+    if (*delimiter_set == 0 || full[strcspn(full, delimiter_set)] == 0) {
        stripped = saved_ext = 0;
     } else {
        stripped = mystrdup(full);
        if ((ratsign = strrchr(stripped, '@')) != 0)
            *ratsign = 0;
-       if ((extent = split_addr(stripped, delimiter)) != 0) {
+       if ((extent = split_addr(stripped, delimiter_set)) != 0) {
            extent -= 1;
            if (extension) {
-               *extent = delimiter;
+               *extent = full[strlen(stripped)];
                saved_ext = mystrdup(extent);
                *extent = 0;
            } else
@@ -105,17 +105,19 @@ int     main(int unused_argc, char **unused_argv)
 {
     char   *extension;
     char   *stripped;
-    int     delim = '-';
+    char*  delim = "+-";
+
+#define NO_DELIM       ""
 
     /*
      * Incredible. This function takes only three arguments, and the tests
      * already take more lines of code than the code being tested.
      */
-    stripped = strip_addr("foo", (char **) 0, 0);
+    stripped = strip_addr("foo", (char **) 0, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 1");
 
-    stripped = strip_addr("foo", &extension, 0);
+    stripped = strip_addr("foo", &extension, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 2");
     if (extension != 0)
@@ -131,11 +133,11 @@ int     main(int unused_argc, char **unused_argv)
     if (extension != 0)
        msg_panic("strip_addr botch 6");
 
-    stripped = strip_addr("foo@bar", (char **) 0, 0);
+    stripped = strip_addr("foo@bar", (char **) 0, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 7");
 
-    stripped = strip_addr("foo@bar", &extension, 0);
+    stripped = strip_addr("foo@bar", &extension, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 8");
     if (extension != 0)
@@ -151,11 +153,11 @@ int     main(int unused_argc, char **unused_argv)
     if (extension != 0)
        msg_panic("strip_addr botch 12");
 
-    stripped = strip_addr("foo-ext", (char **) 0, 0);
+    stripped = strip_addr("foo-ext", (char **) 0, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 13");
 
-    stripped = strip_addr("foo-ext", &extension, 0);
+    stripped = strip_addr("foo-ext", &extension, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 14");
     if (extension != 0)
@@ -178,11 +180,11 @@ int     main(int unused_argc, char **unused_argv)
     myfree(stripped);
     myfree(extension);
 
-    stripped = strip_addr("foo-ext@bar", (char **) 0, 0);
+    stripped = strip_addr("foo-ext@bar", (char **) 0, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 19");
 
-    stripped = strip_addr("foo-ext@bar", &extension, 0);
+    stripped = strip_addr("foo-ext@bar", &extension, NO_DELIM);
     if (stripped != 0)
        msg_panic("strip_addr botch 20");
     if (extension != 0)
@@ -205,6 +207,16 @@ int     main(int unused_argc, char **unused_argv)
     myfree(stripped);
     myfree(extension);
 
+    stripped = strip_addr("foo+ext@bar", &extension, delim);
+    if (stripped == 0)
+       msg_panic("strip_addr botch 25");
+    if (extension == 0)
+       msg_panic("strip_addr botch 26");
+    msg_info("wanted:    foo+ext@bar -> %s %s", "foo@bar", "+ext");
+    msg_info("strip_addr foo+ext@bar -> %s %s", stripped, extension);
+    myfree(stripped);
+    myfree(extension);
+
     return (0);
 }
 
index e99c6fdf8ff6114c048d04f961b9a50f68f57493..19530e1ba2049b5bf43aff993233cda19cee5b9e 100644 (file)
@@ -13,7 +13,7 @@
 
  /* External interface. */
 
-extern char *strip_addr(const char *, char **, int);
+extern char *strip_addr(const char *, char **, const char *);
 
 /* LICENSE
 /* .ad
index 3068918caabbcdc89e833fcac192631cc70e69b7..af218e5c03105010e8a8abe0a6b0c0d05f4e28ba 100644 (file)
@@ -6,3 +6,5 @@ unknown: wanted:    foo-ext@bar -> foo@bar
 unknown: strip_addr foo-ext@bar -> foo@bar
 unknown: wanted:    foo-ext@bar -> foo@bar -ext
 unknown: strip_addr foo-ext@bar -> foo@bar -ext
+unknown: wanted:    foo+ext@bar -> foo@bar +ext
+unknown: strip_addr foo+ext@bar -> foo@bar +ext
index 8d1670c805181b98383a59024f3d9bb1c7ce427d..e7211ec552c88f83c4938067b92dcb1b16ca8f6d 100644 (file)
@@ -109,7 +109,7 @@ int     bounce_workaround(LOCAL_STATE state)
        if (alias_maps->error == 0 && owner_expansion == 0
            && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
                                                (char **) 0,
-                                               *var_rcpt_delim)) != 0) {
+                                               var_rcpt_delim)) != 0) {
            myfree(owner_alias);
            FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
            myfree(stripped_recipient);
index cec2312637e0814a1ed2862e6a8111446447e4ad..32da88bcabe854ec6e5f99807e1e609c73360b44 100644 (file)
 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 /*     The location of the Postfix top-level queue directory.
 /* .IP "\fBrecipient_delimiter (empty)\fR"
-/*     The separator between user names and address extensions (user+foo).
+/*     The set of characters that can separate a user name from its
+/*     address extension (user+foo).
 /* .IP "\fBrequire_home_directory (no)\fR"
 /*     Require that a \fBlocal\fR(8) recipient's home directory exists
 /*     before mail delivery is attempted.
index db5121ee889de8eb29425dfad5da933c31853934..612e680940956358685a8ab62ce1fa46d7d266ab 100644 (file)
@@ -113,6 +113,7 @@ typedef struct {
 static const char *local_expand_lookup(const char *name, int mode, char *ptr)
 {
     LOCAL_EXP *local = (LOCAL_EXP *) ptr;
+    static char rcpt_delim[2];
 
 #define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0)
 
@@ -135,7 +136,10 @@ static const char *local_expand_lookup(const char *name, int mode, char *ptr)
            local->status |= LOCAL_EXP_EXTENSION_MATCHED;
        return (local->state->msg_attr.extension);
     } else if (STREQ(name, "recipient_delimiter")) {
-       return (*var_rcpt_delim ? var_rcpt_delim : 0);
+       rcpt_delim[0] =
+           local->state->msg_attr.local[strlen(local->state->msg_attr.user)];
+       rcpt_delim[1] = 0;
+       return (rcpt_delim[0] ? rcpt_delim : 0);
 #if 0
     } else if (STREQ(name, "client_hostname")) {
        return (local->state->msg_attr.request->client_name);
index 19214449366f52e6fad0800500ae91b2a829eee8..8017942e5029d0a31761883cf785f9886761e9e1 100644 (file)
@@ -270,7 +270,7 @@ int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
     state.msg_attr.user = mystrdup(state.msg_attr.local);
     if (*var_rcpt_delim) {
        state.msg_attr.extension =
-           split_addr(state.msg_attr.user, *var_rcpt_delim);
+           split_addr(state.msg_attr.user, var_rcpt_delim);
        if (state.msg_attr.extension && strchr(state.msg_attr.extension, '/')) {
            msg_warn("%s: address with illegal extension: %s",
                     state.msg_attr.queue_id, state.msg_attr.local);
index 89c330325e4c00eeace390c7a8e8ee8401ab706c..a6aa9d0356df5e76a8e5966d99af4240d327a4f6 100644 (file)
@@ -90,6 +90,7 @@ int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
     int     status;
     ssize_t ext_len;
     char   *ratsign;
+    int     rcpt_delim;
 
     /*
      * Make verbose logging easier to understand.
@@ -130,8 +131,9 @@ int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
         * Splice in the optional unmatched address extension.
         */
        if (state.msg_attr.unmatched) {
+           rcpt_delim = state.msg_attr.local[strlen(state.msg_attr.user)];
            if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) {
-               VSTRING_ADDCH(reply.recipient, *var_rcpt_delim);
+               VSTRING_ADDCH(reply.recipient, rcpt_delim);
                vstring_strcat(reply.recipient, state.msg_attr.unmatched);
            } else {
                ext_len = strlen(state.msg_attr.unmatched);
@@ -139,7 +141,7 @@ int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
                if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0)
                    msg_panic("%s: recipient @ botch", myname);
                memmove(ratsign + ext_len + 1, ratsign, strlen(ratsign) + 1);
-               *ratsign = *var_rcpt_delim;
+               *ratsign = rcpt_delim;
                memcpy(ratsign + 1, state.msg_attr.unmatched, ext_len);
                VSTRING_SKIP(reply.recipient);
            }
index 71955d4f3b565b848885ee660b821d486042d7a3..e2f9237410e4029b4079973a5574844e87b86d8c 100644 (file)
@@ -1175,7 +1175,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
                   : strlen(STR(reply.recipient)));
            vstring_strncpy(queue_name, STR(reply.recipient), len);
            /* Remove the address extension from the recipient localpart. */
-           if (*var_rcpt_delim && split_addr(STR(queue_name), *var_rcpt_delim))
+           if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim))
                vstring_truncate(queue_name, strlen(STR(queue_name)));
            /* Assume the recipient domain is equivalent to nexthop. */
            vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
index 73e9978bbd10d79f36caa75553711035c71c9ee7..b6329f02f2d285ce8af3be073d5c0837d85664f2 100644 (file)
 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 /*     The location of the Postfix top-level queue directory.
 /* .IP "\fBrecipient_delimiter (empty)\fR"
-/*     The separator between user names and address extensions (user+foo).
+/*     The set of characters that can separate a user name from its
+/*     address extension (user+foo).
 /* .IP "\fBsyslog_facility (mail)\fR"
 /*     The syslog facility of Postfix logging.
 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
@@ -717,7 +718,7 @@ static ARGV *expand_argv(const char *service, char **argv,
                        msg_warn("no @ in recipient address: %s",
                                 rcpt_list->info[i].address);
                    if (*var_rcpt_delim)
-                       split_addr(STR(buf), *var_rcpt_delim);
+                       split_addr(STR(buf), var_rcpt_delim);
                    if (*STR(buf) == 0)
                        continue;
                    dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf));
@@ -735,7 +736,7 @@ static ARGV *expand_argv(const char *service, char **argv,
                        msg_warn("no @ in recipient address: %s",
                                 rcpt_list->info[i].address);
                    if (*var_rcpt_delim == 0
-                     || (ext = split_addr(STR(buf), *var_rcpt_delim)) == 0)
+                     || (ext = split_addr(STR(buf), var_rcpt_delim)) == 0)
                        ext = "";               /* insert null arg */
                    dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext);
                }
index 576fb2d6fe4bd1b35c6300fa0ee1382cc7d3fbe5..e6bbaf65cf5873727efee9f8649b01d7bf0d33c0 100644 (file)
@@ -1234,7 +1234,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
                   : strlen(STR(reply.recipient)));
            vstring_strncpy(queue_name, STR(reply.recipient), len);
            /* Remove the address extension from the recipient localpart. */
-           if (*var_rcpt_delim && split_addr(STR(queue_name), *var_rcpt_delim))
+           if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim))
                vstring_truncate(queue_name, strlen(STR(queue_name)));
            /* Assume the recipient domain is equivalent to nexthop. */
            vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
index 1f219e187c513e5640f3a33fb04349b96b6b4207..fae7358ba02ef1711b53c355ef71ad58c4e379e1 100644 (file)
 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
 /*     The location of the Postfix top-level queue directory.
 /* .IP "\fBrecipient_delimiter (empty)\fR"
-/*     The separator between user names and address extensions (user+foo).
+/*     The set of characters that can separate a user name from its
+/*     address extension (user+foo).
 /* .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR"
 /*     The text that follows the 220 status code in the SMTP greeting
 /*     banner.
index 52ebc66c1171a6a73f889907fa547eb10af4ded1..3ee7ee12fc44244703e010655270fdac262299eb 100644 (file)
@@ -2866,7 +2866,7 @@ static int check_mail_access(SMTPD_STATE *state, const char *table,
     if (*var_rcpt_delim == 0) {
        bare_addr = 0;
     } else {
-       bare_addr = strip_addr(addr, (char **) 0, *var_rcpt_delim);
+       bare_addr = strip_addr(addr, (char **) 0, var_rcpt_delim);
     }
 
 #define CHECK_MAIL_ACCESS_RETURN(x) \
index 29720541c82bd4683ceddb9545edd1ab3ff58136..61937ae42e20b36eba153c656fd3ca87bcb6fa9a 100644 (file)
@@ -286,7 +286,7 @@ int     transport_lookup(TRANSPORT_INFO *tp, const char *addr,
      * partial lookup keys with regular expressions.
      */
     if ((stripped_addr = strip_addr(addr, DISCARD_EXTENSION,
-                                   *var_rcpt_delim)) != 0) {
+                                   var_rcpt_delim)) != 0) {
        found = find_transport_entry(tp, stripped_addr, rcpt_domain, PARTIAL,
                                     channel, nexthop);
 
index b8cc438c2009830ff967427c0ea19bbf0a86a278..cafb1aceeae331b350ca404406f886a5f6c69088 100644 (file)
 /*     With locally submitted mail, append the string ".$mydomain" to
 /*     addresses that have no ".domain" information.
 /* .IP "\fBrecipient_delimiter (empty)\fR"
-/*     The separator between user names and address extensions (user+foo).
+/*     The set of characters that can separate a user name from its
+/*     address extension (user+foo).
 /* .IP "\fBswap_bangpath (yes)\fR"
 /*     Enable the rewriting of "site!user" into "user@site".
 /* .PP
index 8d77883f53466a0a52a1f8e8c29cfff5e727462e..3c4a9b1b83f3b87de85c6bb3a3f17f0dd0ddc94b 100644 (file)
@@ -431,6 +431,7 @@ void    dict_load_fp(const char *dict_name, VSTREAM *fp)
     VSTRING *buf;
     char   *member;
     char   *val;
+    const char *old;
     int     old_lineno;
     int     lineno;
     const char *err;
@@ -455,6 +456,10 @@ void    dict_load_fp(const char *dict_name, VSTREAM *fp)
                      err, STR(buf));
        if (msg_verbose > 1)
            msg_info("%s: %s = %s", myname, member, val);
+       if ((old = dict->lookup(dict, member)) != 0
+           && strcmp(old, val) != 0)
+           msg_warn("%s, line %d: overriding earlier entry: %s=%s",
+                    VSTREAM_PATH(fp), lineno, member, old);
        if (dict->update(dict, member, val) != 0)
            msg_fatal("%s, line %d: unable to update %s:%s",
                      VSTREAM_PATH(fp), lineno, dict->type, dict->name);