]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.3-20051226
authorWietse Venema <wietse@porcupine.org>
Mon, 26 Dec 2005 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:31:59 +0000 (06:31 +0000)
23 files changed:
postfix/HISTORY
postfix/README_FILES/DSN_README
postfix/conf/access
postfix/html/DSN_README.html
postfix/html/access.5.html
postfix/html/pcre_table.5.html
postfix/html/regexp_table.5.html
postfix/man/man5/access.5
postfix/man/man5/pcre_table.5
postfix/man/man5/regexp_table.5
postfix/proto/DSN_README.html
postfix/proto/access
postfix/proto/pcre_table
postfix/proto/regexp_table
postfix/src/global/mail_version.h
postfix/src/util/dict.h
postfix/src/util/dict_alloc.c
postfix/src/util/dict_pcre.c
postfix/src/util/dict_regexp.c
postfix/src/util/dict_regexp.ref
postfix/src/util/myaddrinfo.c
postfix/src/xsasl/xsasl_cyrus_client.c
postfix/src/xsasl/xsasl_cyrus_server.c

index b189360902e2a595ef5fa572647b6a60b504065d..b17574f33aac1927862bc7339f2784b85eb9cdf5 100644 (file)
@@ -11660,6 +11660,23 @@ Apologies for any names omitted.
        Bugfix: 20051219 "postconf -A" produced "postconf -a" output.
        Andreas Winkelmann.
 
+20051225
+
+       Bugfix: the regexp map cleverly avoided scanning constant
+       lookup results for non-existent $number expressions, but
+       failed to subject those results to the necessary $$ -> $
+       replacement. Files: util/dict_regexp.c.
+
+       Performance: the pcre map did not optimize constant lookup
+       results; they were always scanned for non-existent $number
+       expressions.  File: util/dict_pcre.c.
+
+       This round of edits eliminates architectural differences
+       between the pcre and regexp table implementations.  The
+       remaining difference is that regexp tables still support
+       the obsolete "/pattern1/!/pattern2/ action" syntax, for
+       backwards compatibility with Postfix 2.0 and earlier.
+
 Open problems:
 
        "postsuper -r" no longer resets the message arrival time,
@@ -11670,11 +11687,6 @@ Open problems:
        Is it safe to cache a connection after it has been used for
        more than some number of address verification probes?
 
-       Access map actions such as FILTER and REDIRECT don't work
-       in smtpd_end_of_data_restrictions (or anything else that
-       generates additional queue file records after the message
-       content is stored).
-
        Try to recognize that Resent- headers appear in blocks,
        newest block first. But don't break on incorrect header
        block organization.
index 25f4d917d47e02885ad5738825627ccc3a5eeb8a..b7bc3fd10685f61c78c9c0eeb95737c011472e5b 100644 (file)
@@ -10,7 +10,9 @@ delivery notifications.
 
 Specifically, DSN support gives an email sender the ability to specify:
 
-  * What notifications are sent: success, failure, delay, or none.
+  * What notifications are sent: success, failure, delay, or none. Normally,
+    Postfix informs the sender only mail when delivery is delayed or when
+    delivery fails.
 
   * What content is returned in case of failure: only the message headers, or
     the full message.
@@ -37,9 +39,11 @@ Unfortunately, disallowing "success" notification requests requires disallowing
 other DSN requests as well. The RFCs do not offer the option to negotiate
 feature subsets.
 
-This is not as bad as it sounds. Remote senders with DSN support will still be
-informed that their mail reached your Postfix gateway successfully; they just
-will not get successful delivery notices from your internal systems.
+This is not as bad as it sounds. When you turn off DSN for remote inbound mail,
+remote senders with DSN support will still be informed that their mail reached
+your Postfix gateway successfully; they just will not get successful delivery
+notices from your internal systems. Remote senders lose very little: they can
+no longer specify how Postfix should report delayed or failed delivery.
 
 Use the smtpd_discard_ehlo_keyword_address_maps feature if you wish to allow
 DSN requests from trusted clients but not from random strangers (see below for
index bacefdaa67cde345ffc4776a476a999572892eff..515ee6d2f3a91fefdcba6fc66ab06df4e6855180 100644 (file)
 #               transport(5) table to direct mail to the discard(8)
 #               service.
 # 
-#               Note:  this  action  does  not  work in Postfix 2.2
-#               smtpd_end_of_data_restrictions.
-# 
 #               This feature is available in Postfix 2.0 and later.
 # 
-#        DUNNO  Pretend  that  the  lookup  key was not found. This
-#               prevents Postfix  from  trying  substrings  of  the
-#               lookup  key (such as a subdomain name, or a network
+#        DUNNO  Pretend that the lookup key  was  not  found.  This
+#               prevents  Postfix  from  trying  substrings  of the
+#               lookup key (such as a subdomain name, or a  network
 #               address subnetwork).
 # 
 #               This feature is available in Postfix 2.0 and later.
 # 
 #        FILTER transport:destination
-#               After  the  message is queued, send the entire mes-
+#               After the message is queued, send the  entire  mes-
 #               sage through the specified external content filter.
-#               The  transport:destination  syntax  is described in
-#               the transport(5)  manual  page.   More  information
-#               about  external  content  filters is in the Postfix
+#               The transport:destination syntax  is  described  in
+#               the  transport(5)  manual  page.   More information
+#               about external content filters is  in  the  Postfix
 #               FILTER_README file.
 # 
-#               Note:  this  action  overrides  the  main.cf   con-
+#               Note:   this  action  overrides  the  main.cf  con-
 #               tent_filter  setting,  and  currently  affects  all
 #               recipients of the message.
 # 
-#               Note: this action does  not  work  in  Postfix  2.2
-#               smtpd_end_of_data_restrictions.
-# 
 #               This feature is available in Postfix 2.0 and later.
 # 
 #        HOLD optional text...
 #               Note: this action currently affects all  recipients
 #               of the message.
 # 
-#               Note:  this  action  does  not  work in Postfix 2.2
-#               smtpd_end_of_data_restrictions.
-# 
 #               This feature is available in Postfix 2.0 and later.
 # 
 #        PREPEND headername: headervalue
-#               Prepend  the  specified  message header to the mes-
+#               Prepend the specified message header  to  the  mes-
 #               sage.  When this action is used multiple times, the
-#               first  prepended  header  appears before the second
+#               first prepended header appears  before  the  second
 #               etc. prepended header.
 # 
-#               Note: this action does not support multi-line  mes-
+#               Note:  this action does not support multi-line mes-
 #               sage headers.
 # 
-#               Note:  this  action must be used before the message
-#               content  is  received;  it  cannot   be   used   in
+#               Note: this action must be used before  the  message
+#               content   is   received;   it  cannot  be  used  in
 #               smtpd_end_of_data_restrictions.
 # 
 #               This feature is available in Postfix 2.1 and later.
 # 
 #        REDIRECT user@domain
-#               After the message is queued, send  the  message  to
+#               After  the  message  is queued, send the message to
 #               the  specified  address  instead  of  the  intended
 #               recipient(s).
 # 
-#               Note: this action overrides the FILTER action,  and
+#               Note:  this action overrides the FILTER action, and
 #               currently affects all recipients of the message.
 # 
-#               Note:  this  action  does  not  work in Postfix 2.2
-#               smtpd_end_of_data_restrictions.
-# 
 #               This feature is available in Postfix 2.1 and later.
 # 
 #        WARN optional text...
index 41c529113d4a8dd02f142d28d9ccb8ca74bf2c62..38d1efe71aa642ca47c0437d89e3594a7f65d329 100644 (file)
@@ -30,7 +30,8 @@ specify: </p>
 <ul>
 
 <li> <p> What notifications are sent: success, failure, delay, or
-none. </p>
+none. Normally, Postfix informs the sender only mail when delivery
+is delayed or when delivery fails.  </p>
 
 <li> <p> What content is returned in case of failure: only the
 message headers, or the full message. </p>
@@ -68,10 +69,12 @@ internal infrastructure than desirable.  Unfortunately, disallowing
 requests as well. The RFCs do not offer the option to negotiate
 feature subsets. </p>
 
-<p> This is not as bad as it sounds. Remote senders with DSN support
-will still be informed that their mail reached your Postfix gateway
-successfully; they just will not get successful delivery notices
-from your internal systems. </p>
+<p> This is not as bad as it sounds. When you turn off DSN for
+remote inbound mail, remote senders with DSN support will still be
+informed that their mail reached your Postfix gateway successfully;
+they just will not get successful delivery notices from your internal
+systems. Remote senders lose very little: they can no longer specify
+how Postfix should report delayed or failed delivery.  </p>
 
 <p> Use the <a href="postconf.5.html#smtpd_discard_ehlo_keyword_address_maps">smtpd_discard_ehlo_keyword_address_maps</a> feature if you
 wish to allow DSN requests from trusted clients but not from random
index 3890e73a954bef925d8de1a00840cc8177e0261d..bb7a9bcfc0df30acdffeca24d33bf667e6d321ef 100644 (file)
@@ -227,33 +227,27 @@ ACCESS(5)                                                            ACCESS(5)
               <a href="transport.5.html">transport(5)</a> table to direct mail to the <a href="discard.8.html">discard(8)</a>
               service.
 
-              Note:  this  action  does  not  work in Postfix 2.2
-              <b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>.
-
               This feature is available in Postfix 2.0 and later.
 
-       <b>DUNNO</b>  Pretend  that  the  lookup  key was not found. This
-              prevents Postfix  from  trying  substrings  of  the
-              lookup  key (such as a subdomain name, or a network
+       <b>DUNNO</b>  Pretend that the lookup key  was  not  found.  This
+              prevents  Postfix  from  trying  substrings  of the
+              lookup key (such as a subdomain name, or a  network
               address subnetwork).
 
               This feature is available in Postfix 2.0 and later.
 
        <b>FILTER</b> <i>transport:destination</i>
-              After  the  message is queued, send the entire mes-
+              After the message is queued, send the  entire  mes-
               sage through the specified external content filter.
-              The  <i>transport:destination</i>  syntax  is described in
-              the <a href="transport.5.html"><b>transport</b>(5)</a>  manual  page.   More  information
-              about  external  content  filters is in the Postfix
+              The <i>transport:destination</i> syntax  is  described  in
+              the  <a href="transport.5.html"><b>transport</b>(5)</a>  manual  page.   More information
+              about external content filters is  in  the  Postfix
               <a href="FILTER_README.html">FILTER_README</a> file.
 
-              Note:  this  action  overrides  the  <b>main.cf   <a href="postconf.5.html#content_filter">con</a>-</b>
+              Note:   this  action  overrides  the  <b>main.cf  <a href="postconf.5.html#content_filter">con</a>-</b>
               <b><a href="postconf.5.html#content_filter">tent_filter</a></b>  setting,  and  currently  affects  all
               recipients of the message.
 
-              Note: this action does  not  work  in  Postfix  2.2
-              <b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>.
-
               This feature is available in Postfix 2.0 and later.
 
        <b>HOLD</b> <i>optional text...</i>
@@ -274,37 +268,31 @@ ACCESS(5)                                                            ACCESS(5)
               Note: this action currently affects all  recipients
               of the message.
 
-              Note:  this  action  does  not  work in Postfix 2.2
-              <b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>.
-
               This feature is available in Postfix 2.0 and later.
 
        <b>PREPEND</b> <i>headername: headervalue</i>
-              Prepend  the  specified  message header to the mes-
+              Prepend the specified message header  to  the  mes-
               sage.  When this action is used multiple times, the
-              first  prepended  header  appears before the second
+              first prepended header appears  before  the  second
               etc. prepended header.
 
-              Note: this action does not support multi-line  mes-
+              Note:  this action does not support multi-line mes-
               sage headers.
 
-              Note:  this  action must be used before the message
-              content  is  received;  it  cannot   be   used   in
+              Note: this action must be used before  the  message
+              content   is   received;   it  cannot  be  used  in
               <b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>.
 
               This feature is available in Postfix 2.1 and later.
 
        <b>REDIRECT</b> <i>user@domain</i>
-              After the message is queued, send  the  message  to
+              After  the  message  is queued, send the message to
               the  specified  address  instead  of  the  intended
               recipient(s).
 
-              Note: this action overrides the FILTER action,  and
+              Note:  this action overrides the FILTER action, and
               currently affects all recipients of the message.
 
-              Note:  this  action  does  not  work in Postfix 2.2
-              <b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>.
-
               This feature is available in Postfix 2.1 and later.
 
        <b>WARN</b> <i>optional text...</i>
index 238c1c2061e97140a3afcc46c62f35f85a7adb47..8698d02a88c5044e94eb2c51e976615905bcfec7 100644 (file)
@@ -50,112 +50,120 @@ PCRE_TABLE(5)                                                    PCRE_TABLE(5)
               Note: do not prepend whitespace to patterns  inside
               <b>if</b>..<b>endif</b>.
 
+              This feature is available in Postfix 2.1 and later.
+
        <b>if !/</b><i>pattern</i><b>/</b><i>flags</i>
 
        <b>endif</b>  Match the input string against the patterns between
-              <b>if</b> and <b>endif</b>, if and only if the input string  does
+              <b>if</b>  and <b>endif</b>, if and only if the input string does
               <b>not</b> match <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
 
+              Note: do not prepend whitespace to patterns  inside
+              <b>if</b>..<b>endif</b>.
+
+              This feature is available in Postfix 2.1 and later.
+
        blank lines and comments
-              Empty  lines and whitespace-only lines are ignored,
-              as are lines whose first  non-whitespace  character
+              Empty lines and whitespace-only lines are  ignored,
+              as  are  lines whose first non-whitespace character
               is a `#'.
 
        multi-line text
-              A  logical  line starts with non-whitespace text. A
-              line that starts with whitespace continues a  logi-
+              A logical line starts with non-whitespace  text.  A
+              line  that starts with whitespace continues a logi-
               cal line.
 
        Each  pattern  is  a  perl-like  regular  expression.  The
-       expression delimiter can be any character,  except  white-
-       space  or characters that have special meaning (tradition-
-       ally the forward slash is used).  The  regular  expression
+       expression  delimiter  can be any character, except white-
+       space or characters that have special meaning  (tradition-
+       ally  the  forward slash is used).  The regular expression
        can contain whitespace.
 
        By default, matching is case-insensitive, and newlines are
-       not treated as special characters. The  behavior  is  con-
-       trolled  by  flags,  which are toggled by appending one or
+       not  treated  as  special characters. The behavior is con-
+       trolled by flags, which are toggled by  appending  one  or
        more of the following characters after the pattern:
 
        <b>i</b> (default: on)
-              Toggles the  case  sensitivity  flag.  By  default,
+              Toggles  the  case  sensitivity  flag.  By default,
               matching is case insensitive.
 
        <b>m</b> (default: off)
-              Toggles  the PCRE_MULTILINE flag. When this flag is
-              on, the <b>^</b> and <b>$</b>  metacharacters  match  immediately
-              after  and  immediately before a newline character,
-              respectively, in addition to matching at the  start
+              Toggles the PCRE_MULTILINE flag. When this flag  is
+              on,  the  <b>^</b>  and <b>$</b> metacharacters match immediately
+              after and immediately before a  newline  character,
+              respectively,  in addition to matching at the start
               and end of the subject string.
 
        <b>s</b> (default: on)
               Toggles the PCRE_DOTALL flag. When this flag is on,
               the <b>.</b>  metacharacter matches the newline character.
               With Postfix versions prior to 2.0, The flag is off
-              by default, which is  inconvenient  for  multi-line
+              by  default,  which  is inconvenient for multi-line
               message header matching.
 
        <b>x</b> (default: off)
-              Toggles  the  pcre extended flag. When this flag is
-              on, whitespace in the  pattern  (other  than  in  a
+              Toggles the pcre extended flag. When this  flag  is
+              on,  whitespace  in  the  pattern  (other than in a
               character class) and characters between a <b>#</b> outside
-              a character class and the  next  newline  character
-              are  ignored.  An escaping backslash can be used to
-              include a whitespace or <b>#</b> character as part of  the
+              a  character  class  and the next newline character
+              are ignored. An escaping backslash can be  used  to
+              include  a whitespace or <b>#</b> character as part of the
               pattern.
 
        <b>A</b> (default: off)
-              Toggles  the PCRE_ANCHORED flag.  When this flag is
-              on, the pattern is forced to  be  "anchored",  that
+              Toggles the PCRE_ANCHORED flag.  When this flag  is
+              on,  the  pattern  is forced to be "anchored", that
               is, it is constrained to match only at the start of
-              the string which is being  searched  (the  "subject
-              string").  This  effect  can  also  be  achieved by
+              the  string  which  is being searched (the "subject
+              string"). This  effect  can  also  be  achieved  by
               appropriate constructs in the pattern itself.
 
        <b>E</b> (default: off)
-              Toggles the  PCRE_DOLLAR_ENDONLY  flag.  When  this
-              flag  is  on,  a  <b>$</b>  metacharacter  in  the pattern
-              matches only at the  end  of  the  subject  string.
-              Without  this  flag,  a dollar also matches immedi-
+              Toggles  the  PCRE_DOLLAR_ENDONLY  flag.  When this
+              flag is  on,  a  <b>$</b>  metacharacter  in  the  pattern
+              matches  only  at  the  end  of the subject string.
+              Without this flag, a dollar  also  matches  immedi-
               ately before the final character if it is a newline
               character (but not before any other newline charac-
-              ters). This flag is ignored if PCRE_MULTILINE  flag
+              ters).  This flag is ignored if PCRE_MULTILINE flag
               is set.
 
        <b>U</b> (default: off)
               Toggles the ungreedy matching flag.  When this flag
-              is on, the  pattern  matching  engine  inverts  the
-              "greediness"  of  the  quantifiers so that they are
-              not greedy by default, but become  greedy  if  fol-
-              lowed  by  "?".   This  flag can also set by a (?U)
+              is  on,  the  pattern  matching  engine inverts the
+              "greediness" of the quantifiers so  that  they  are
+              not  greedy  by  default, but become greedy if fol-
+              lowed by "?".  This flag can also  set  by  a  (?U)
               modifier within the pattern.
 
        <b>X</b> (default: off)
               Toggles the PCRE_EXTRA flag.  When this flag is on,
-              any  backslash  in  a pattern that is followed by a
+              any backslash in a pattern that is  followed  by  a
               letter that has no special meaning causes an error,
               thus reserving these combinations for future expan-
               sion.
 
 <b>SEARCH ORDER</b>
-       Patterns are applied in the order as specified in the  ta-
-       ble,  until  a  pattern  is  found  that matches the input
+       Patterns  are applied in the order as specified in the ta-
+       ble, until a pattern  is  found  that  matches  the  input
        string.
 
-       Each pattern  is  applied  to  the  entire  input  string.
-       Depending  on  the  application,  that string is an entire
+       Each  pattern  is  applied  to  the  entire  input string.
+       Depending on the application, that  string  is  an  entire
        client hostname, an entire client IP address, or an entire
-       mail  address.   Thus,  no parent domain or parent network
-       search is done, and <i>user@domain</i>  mail  addresses  are  not
-       broken  up  into  their <i>user</i> and <i>domain</i> constituent parts,
+       mail address.  Thus, no parent domain  or  parent  network
+       search  is  done,  and  <i>user@domain</i> mail addresses are not
+       broken up into their <i>user</i> and  <i>domain</i>  constituent  parts,
        nor is <i>user+foo</i> broken up into <i>user</i> and <i>foo</i>.
 
 <b>TEXT SUBSTITUTION</b>
-       Substitution of substrings  from  the  matched  expression
-       into  the result string is possible using the conventional
-       perl syntax ($1, $2, etc.).   The  macros  in  the  result
-       string  may  need  to  be  written as ${n} or $(n) if they
-       aren't followed by whitespace.
+       Substitution  of  substrings  from  the matched expression
+       into the result string is possible using the  conventional
+       perl  syntax  ($1,  $2,  etc.);  specify $$ to produce a $
+       character as output.  The macros in the result string  may
+       need to be written as ${n} or $(n) if they aren't followed
+       by whitespace.
 
        Note: since negated patterns (those preceded by <b>!</b>)  return
        a result when the expression does not match, substitutions
index aa543964b82d193cf0175b3809f6776e369b15d8..d42fa44832e246a21bf8064fdb65e502c32ad6d8 100644 (file)
@@ -50,11 +50,19 @@ REGEXP_TABLE(5)                                                REGEXP_TABLE(5)
               Note: do not prepend whitespace to patterns  inside
               <b>if</b>..<b>endif</b>.
 
+              This feature is available in Postfix 2.1 and later.
+
        <b>if !/</b><i>pattern</i><b>/</b><i>flags</i>
 
        <b>endif</b>  Match the input string against the patterns between
               <b>if</b> and <b>endif</b>, if and only if that same input string
-              does <b>not</b> match <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
+              does <b>not</b> match <i>pattern</i>.  The  <b>if</b>..<b>endif</b>  can  nest.
+              matches <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
+
+              Note:  do not prepend whitespace to patterns inside
+              <b>if</b>..<b>endif</b>.
+
+              This feature is available in Postfix 2.1 and later.
 
        blank lines and comments
               Empty  lines and whitespace-only lines are ignored,
@@ -113,11 +121,12 @@ REGEXP_TABLE(5)                                                REGEXP_TABLE(5)
 
 <b>TEXT SUBSTITUTION</b>
        Substitution of substrings  from  the  matched  expression
-       into the result string is possible using $1, $2, etc.. The
-       macros in the result string may need to be written as ${n}
-       or $(n) if they aren't followed by whitespace.
+       into  the  result  string  is possible using $1, $2, etc.;
+       specify $$ to produce a $ character as output.  The macros
+       in  the  result  string  may need to be written as ${n} or
+       $(n) if they aren't followed by whitespace.
 
-       Note:  since negated patterns (those preceded by <b>!</b>) return
+       Note: since negated patterns (those preceded by <b>!</b>)  return
        a result when the expression does not match, substitutions
        are not available for negated patterns.
 
index 8f7df2a130c1da7848501febe674ac24107c6ae7..761e5d99ef87c3209f4eba5de7007b2f394b0c43 100644 (file)
@@ -212,9 +212,6 @@ Note: this action currently affects all recipients of the message.
 To discard only one recipient without discarding the entire message,
 use the transport(5) table to direct mail to the discard(8) service.
 .sp
-Note: this action does not work in Postfix 2.2
-\fBsmtpd_end_of_data_restrictions\fR.
-.sp
 This feature is available in Postfix 2.0 and later.
 .IP \fBDUNNO\fR
 Pretend that the lookup key was not found. This
@@ -232,9 +229,6 @@ about external content filters is in the Postfix FILTER_README file.
 Note: this action overrides the \fBmain.cf content_filter\fR setting,
 and currently affects all recipients of the message.
 .sp
-Note: this action does not work in Postfix 2.2
-\fBsmtpd_end_of_data_restrictions\fR.
-.sp
 This feature is available in Postfix 2.0 and later.
 .IP "\fBHOLD \fIoptional text...\fR"
 Place the message on the \fBhold\fR queue, where it will sit
@@ -252,9 +246,6 @@ or \fB$bounce_queue_lifetime\fR, or longer.
 .sp
 Note: this action currently affects all recipients of the message.
 .sp
-Note: this action does not work in Postfix 2.2
-\fBsmtpd_end_of_data_restrictions\fR.
-.sp
 This feature is available in Postfix 2.0 and later.
 .IP "\fBPREPEND \fIheadername: headervalue\fR"
 Prepend the specified message header to the message.
@@ -274,9 +265,6 @@ address instead of the intended recipient(s).
 Note: this action overrides the FILTER action, and currently affects
 all recipients of the message.
 .sp
-Note: this action does not work in Postfix 2.2
-\fBsmtpd_end_of_data_restrictions\fR.
-.sp
 This feature is available in Postfix 2.1 and later.
 .IP "\fBWARN \fIoptional text...\fR
 Log a warning with the optional text, together with client information
index 90e72e99f6757620dfedf5803048f00b8a86532f..dc2cb3dfaedcaaae1c66264e80de14c14a43db9c 100644 (file)
@@ -48,11 +48,18 @@ and \fBendif\fR, if and only if the input string also matches
 .sp
 Note: do not prepend whitespace to patterns inside
 \fBif\fR..\fBendif\fR.
+.sp
+This feature is available in Postfix 2.1 and later.
 .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
 .IP "\fBendif\fR"
 Match the input string against the patterns between \fBif\fR
 and \fBendif\fR, if and only if the input string does \fBnot\fR
 match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
+.sp
+Note: do not prepend whitespace to patterns inside
+\fBif\fR..\fBendif\fR.
+.sp
+This feature is available in Postfix 2.1 and later.
 .IP "blank lines and comments"
 Empty lines and whitespace-only lines are ignored, as
 are lines whose first non-whitespace character is a `#'.
@@ -137,7 +144,8 @@ broken up into \fIuser\fR and \fIfoo\fR.
 .ad
 .fi
 Substitution of substrings from the matched expression into the result
-string is possible using the conventional perl syntax ($1, $2, etc.).
+string is possible using the conventional perl syntax ($1, $2, etc.);
+specify $$ to produce a $ character as output.
 The macros in the result string may need to be written as ${n}
 or $(n) if they aren't followed by whitespace.
 
index 432f4e977859b2235f27ec040ae6cd70e2225513..43af5f38b18ede5e9945651dc7548ef198ba2973 100644 (file)
@@ -48,11 +48,19 @@ matches \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
 .sp
 Note: do not prepend whitespace to patterns inside
 \fBif\fR..\fBendif\fR.
+.sp
+This feature is available in Postfix 2.1 and later.
 .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
 .IP "\fBendif\fR"
 Match the input string against the patterns between \fBif\fR
 and \fBendif\fR, if and only if that same input string does
 \fBnot\fR match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
+matches \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
+.sp
+Note: do not prepend whitespace to patterns inside
+\fBif\fR..\fBendif\fR.
+.sp
+This feature is available in Postfix 2.1 and later.
 .IP "blank lines and comments"
 Empty lines and whitespace-only lines are ignored, as
 are lines whose first non-whitespace character is a `#'.
@@ -105,7 +113,9 @@ broken up into \fIuser\fR and \fIfoo\fR.
 .ad
 .fi
 Substitution of substrings from the matched expression into the result
-string is possible using $1, $2, etc.. The macros in the result string
+string is possible using $1, $2, etc.;
+specify $$ to produce a $ character as output.
+The macros in the result string
 may need to be written as ${n} or $(n) if they aren't followed
 by whitespace.
 
index adcd4a642e31585a791b2000f664458a23a10223..ec219ca459c9105ab971aa959524b52a9ad00b5e 100644 (file)
@@ -30,7 +30,8 @@ specify: </p>
 <ul>
 
 <li> <p> What notifications are sent: success, failure, delay, or
-none. </p>
+none. Normally, Postfix informs the sender only mail when delivery
+is delayed or when delivery fails.  </p>
 
 <li> <p> What content is returned in case of failure: only the
 message headers, or the full message. </p>
@@ -68,10 +69,12 @@ internal infrastructure than desirable.  Unfortunately, disallowing
 requests as well. The RFCs do not offer the option to negotiate
 feature subsets. </p>
 
-<p> This is not as bad as it sounds. Remote senders with DSN support
-will still be informed that their mail reached your Postfix gateway
-successfully; they just will not get successful delivery notices
-from your internal systems. </p>
+<p> This is not as bad as it sounds. When you turn off DSN for
+remote inbound mail, remote senders with DSN support will still be
+informed that their mail reached your Postfix gateway successfully;
+they just will not get successful delivery notices from your internal
+systems. Remote senders lose very little: they can no longer specify
+how Postfix should report delayed or failed delivery.  </p>
 
 <p> Use the smtpd_discard_ehlo_keyword_address_maps feature if you
 wish to allow DSN requests from trusted clients but not from random
index e164c21e931a79ecd0bf622615bdb460656e134a..d4530eb085aac38c03f5fde6734e4206a7bef90c 100644 (file)
 #      To discard only one recipient without discarding the entire message,
 #      use the transport(5) table to direct mail to the discard(8) service.
 # .sp
-#      Note: this action does not work in Postfix 2.2
-#      \fBsmtpd_end_of_data_restrictions\fR.
-# .sp
 #      This feature is available in Postfix 2.0 and later.
 # .IP \fBDUNNO\fR
 #      Pretend that the lookup key was not found. This
 #      Note: this action overrides the \fBmain.cf content_filter\fR setting,
 #      and currently affects all recipients of the message.
 # .sp
-#      Note: this action does not work in Postfix 2.2
-#      \fBsmtpd_end_of_data_restrictions\fR.
-# .sp
 #      This feature is available in Postfix 2.0 and later.
 # .IP "\fBHOLD \fIoptional text...\fR"
 #      Place the message on the \fBhold\fR queue, where it will sit
 # .sp
 #      Note: this action currently affects all recipients of the message.
 # .sp
-#      Note: this action does not work in Postfix 2.2
-#      \fBsmtpd_end_of_data_restrictions\fR.
-# .sp
 #      This feature is available in Postfix 2.0 and later.
 # .IP "\fBPREPEND \fIheadername: headervalue\fR"
 #      Prepend the specified message header to the message.
 #      Note: this action overrides the FILTER action, and currently affects
 #      all recipients of the message.
 # .sp
-#      Note: this action does not work in Postfix 2.2
-#      \fBsmtpd_end_of_data_restrictions\fR.
-# .sp
 #      This feature is available in Postfix 2.1 and later.
 # .IP "\fBWARN \fIoptional text...\fR
 #      Log a warning with the optional text, together with client information
index 55eaa2b59c1f7c59ea748351d1339d8d721dc655..a2620d2caec99f38dd53f5f404c1632a55076d1d 100644 (file)
 # .sp
 #      Note: do not prepend whitespace to patterns inside
 #      \fBif\fR..\fBendif\fR.
+# .sp
+#      This feature is available in Postfix 2.1 and later.
 # .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
 # .IP "\fBendif\fR"
 #      Match the input string against the patterns between \fBif\fR
 #      and \fBendif\fR, if and only if the input string does \fBnot\fR
 #      match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
+# .sp
+#      Note: do not prepend whitespace to patterns inside
+#      \fBif\fR..\fBendif\fR.
+# .sp
+#      This feature is available in Postfix 2.1 and later.
 # .IP "blank lines and comments"
 #      Empty lines and whitespace-only lines are ignored, as
 #      are lines whose first non-whitespace character is a `#'.
 # .ad
 # .fi
 #      Substitution of substrings from the matched expression into the result
-#      string is possible using the conventional perl syntax ($1, $2, etc.).
+#      string is possible using the conventional perl syntax ($1, $2, etc.);
+#      specify $$ to produce a $ character as output.
 #      The macros in the result string may need to be written as ${n}
 #      or $(n) if they aren't followed by whitespace.
 #
index 0785fd28587b4717bb28ee559163c2eea884eda0..5662d46035eeb25358605430875d2d3baf011cd8 100644 (file)
 # .sp
 #       Note: do not prepend whitespace to patterns inside
 #      \fBif\fR..\fBendif\fR.
+# .sp
+#      This feature is available in Postfix 2.1 and later.
 # .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
 # .IP "\fBendif\fR"
 #       Match the input string against the patterns between \fBif\fR
 #      and \fBendif\fR, if and only if that same input string does
 #      \fBnot\fR match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
+#      matches \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
+# .sp
+#       Note: do not prepend whitespace to patterns inside
+#      \fBif\fR..\fBendif\fR.
+# .sp
+#      This feature is available in Postfix 2.1 and later.
 # .IP "blank lines and comments"
 #      Empty lines and whitespace-only lines are ignored, as
 #      are lines whose first non-whitespace character is a `#'.
 # .ad
 # .fi
 #      Substitution of substrings from the matched expression into the result
-#      string is possible using $1, $2, etc.. The macros in the result string
+#      string is possible using $1, $2, etc.;
+#      specify $$ to produce a $ character as output.
+#      The macros in the result string
 #      may need to be written as ${n} or $(n) if they aren't followed
 #      by whitespace.
 #
index 361b4bff1a7f493a93782423be548985cec8520f..4572e1b3b9e35b3926be681477bdbcf5f63d85f0 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      "20051223"
+#define MAIL_RELEASE_DATE      "20051226"
 #define MAIL_VERSION_NUMBER    "2.3"
 
 #ifdef SNAPSHOT
index 1465124fedf93fb6f9dd98233b2f6b47f2fe7a96..9532fec0befc3f4132b5434341037ac195681f94 100644 (file)
@@ -40,7 +40,7 @@ typedef struct DICT {
     time_t  mtime;                     /* mod time at open */
 } DICT;
 
-extern DICT *dict_alloc(const char *, const char *, int);
+extern DICT *dict_alloc(const char *, const char *, ssize_t);
 extern void dict_free(DICT *);
 
 extern DICT *dict_debug(DICT *);
index 3ac5be42ff28a6b3c5ce5b12bc09af3a5f9ed419..5d9dc83a68d850894f14159b625158e9b5918ff9 100644 (file)
@@ -9,7 +9,7 @@
 /*     DICT    *dict_alloc(dict_type, dict_name, size)
 /*     const char *dict_type;
 /*     const char *dict_name;
-/*     int     size;
+/*     ssize_t size;
 /*
 /*     void    dict_free(dict)
 /*     DICT    *ptr;
@@ -105,7 +105,7 @@ static void dict_default_close(DICT *dict)
 
 /* dict_alloc - allocate dictionary object, initialize super-class */
 
-DICT   *dict_alloc(const char *dict_type, const char *dict_name, int size)
+DICT   *dict_alloc(const char *dict_type, const char *dict_name, ssize_t size)
 {
     DICT   *dict = (DICT *) mymalloc(size);
 
index cc7b24bcfd68b83e27b9182318df306d6c8da711..c706f522f5afff87b0728a49a1e633cde7bc9e70 100644 (file)
@@ -101,6 +101,7 @@ typedef struct {
     pcre_extra *hints;                 /* hints to speed pattern execution */
     char   *replacement;               /* replacement string */
     int     match;                     /* positive or negative match */
+    size_t  max_sub;                   /* largest $number in replacement */
 } DICT_PCRE_MATCH_RULE;
 
 typedef struct {
@@ -116,6 +117,7 @@ typedef struct {
 typedef struct {
     DICT    dict;                      /* generic members */
     DICT_PCRE_RULE *head;
+    VSTRING *expansion_buf;            /* lookup result */
 } DICT_PCRE;
 
 static int dict_pcre_init = 0;         /* flag need to init pcre library */
@@ -124,9 +126,8 @@ static int dict_pcre_init = 0;              /* flag need to init pcre library */
  * Context for $number expansion callback.
  */
 typedef struct {
-    const char *mapname;               /* source dict name */
-    int     lineno;                    /* source file line number */
-    VSTRING *expansion_buf;            /* target string buffer */
+    DICT_PCRE *dict_pcre;              /* the dictionary handle */
+    DICT_PCRE_MATCH_RULE *match_rule;  /* the rule we matched */
     const char *lookup_string;         /* string against which we match */
     int     offsets[PCRE_MAX_CAPTURE * 3];     /* Cut substrings */
     int     matches;                   /* Count of cuts */
@@ -138,8 +139,8 @@ typedef struct {
 typedef struct {
     const char *mapname;               /* name of regexp map */
     int     lineno;                    /* where in file */
-    int     flags;                     /* dict_flags */
     size_t  max_sub;                   /* Largest $n seen */
+    char   *literal;                   /* constant result, $$ -> $ */
 } DICT_PCRE_PRESCAN_CONTEXT;
 
  /*
@@ -162,6 +163,8 @@ typedef struct {
 static int dict_pcre_expand(int type, VSTRING *buf, char *ptr)
 {
     DICT_PCRE_EXPAND_CONTEXT *ctxt = (DICT_PCRE_EXPAND_CONTEXT *) ptr;
+    DICT_PCRE_MATCH_RULE *match_rule = ctxt->match_rule;
+    DICT_PCRE *dict_pcre = ctxt->dict_pcre;
     const char *pp;
     int     n;
     int     ret;
@@ -176,16 +179,16 @@ static int dict_pcre_expand(int type, VSTRING *buf, char *ptr)
        if (ret < 0) {
            if (ret == PCRE_ERROR_NOSUBSTRING)
                msg_fatal("regexp %s, line %d: replace index out of range",
-                         ctxt->mapname, ctxt->lineno);
+                         dict_pcre->dict.name, match_rule->rule.lineno);
            else
                msg_fatal("regexp %s, line %d: pcre_get_substring error: %d",
-                         ctxt->mapname, ctxt->lineno, ret);
+                   dict_pcre->dict.name, match_rule->rule.lineno, ret);
        }
        if (*pp == 0) {
            myfree((char *) pp);
            return (MAC_PARSE_UNDEF);
        }
-       vstring_strcat(ctxt->expansion_buf, pp);
+       vstring_strcat(dict_pcre->expansion_buf, pp);
        myfree((char *) pp);
        return (MAC_PARSE_OK);
     }
@@ -194,7 +197,7 @@ static int dict_pcre_expand(int type, VSTRING *buf, char *ptr)
      * Straight text - duplicate with no substitution.
      */
     else {
-       vstring_strcat(ctxt->expansion_buf, vstring_str(buf));
+       vstring_strcat(dict_pcre->expansion_buf, vstring_str(buf));
        return (MAC_PARSE_OK);
     }
 }
@@ -252,7 +255,6 @@ static const char *dict_pcre_lookup(DICT *dict, const char *lookup_string)
     DICT_PCRE_MATCH_RULE *match_rule;
     int     lookup_len = strlen(lookup_string);
     DICT_PCRE_EXPAND_CONTEXT ctxt;
-    static VSTRING *expansion_buf;
     int     nesting = 0;
 
     dict_errno = 0;
@@ -292,28 +294,31 @@ static const char *dict_pcre_lookup(DICT *dict, const char *lookup_string)
                continue;                       /* pcre_exec failed */
            }
 
-           /* Negative rules can't have any substitutions */
-           if (!match_rule->match)
+           /*
+            * Skip $number substitutions when the replacement text contains
+            * no $number strings, as learned during the compile time
+            * pre-scan. The pre-scan already replaced $$ by $.
+            */
+           if (match_rule->max_sub == 0)
                return match_rule->replacement;
 
            /*
             * We've got a match. Perform substitution on replacement string.
             */
-           if (expansion_buf == 0)
-               expansion_buf = vstring_alloc(10);
-           VSTRING_RESET(expansion_buf);
-           ctxt.expansion_buf = expansion_buf;
+           if (dict_pcre->expansion_buf == 0)
+               dict_pcre->expansion_buf = vstring_alloc(10);
+           VSTRING_RESET(dict_pcre->expansion_buf);
+           ctxt.dict_pcre = dict_pcre;
+           ctxt.match_rule = match_rule;
            ctxt.lookup_string = lookup_string;
-           ctxt.mapname = dict->name;
-           ctxt.lineno = rule->lineno;
 
            if (mac_parse(match_rule->replacement, dict_pcre_expand,
                          (char *) &ctxt) & MAC_PARSE_ERROR)
                msg_fatal("pcre map %s, line %d: bad replacement syntax",
                          dict->name, rule->lineno);
 
-           VSTRING_TERMINATE(expansion_buf);
-           return (vstring_str(expansion_buf));
+           VSTRING_TERMINATE(dict_pcre->expansion_buf);
+           return (vstring_str(dict_pcre->expansion_buf));
 
            /*
             * Conditional. XXX We provide space for matched substring info
@@ -392,6 +397,8 @@ static void dict_pcre_close(DICT *dict)
        }
        myfree((char *) rule);
     }
+    if (dict_pcre->expansion_buf)
+       vstring_free(dict_pcre->expansion_buf);
     dict_free(dict);
 }
 
@@ -493,12 +500,15 @@ static int dict_pcre_prescan(int type, VSTRING *buf, char *context)
     DICT_PCRE_PRESCAN_CONTEXT *ctxt = (DICT_PCRE_PRESCAN_CONTEXT *) context;
     size_t  n;
 
+    /*
+     * Keep a copy of literal text (with $$ already replaced by $) if and
+     * only if the replacement text contains no $number expression. This way
+     * we can avoid having to scan the replacement text at lookup time.
+     */
     if (type == MAC_PARSE_VARNAME) {
-       if (ctxt->flags & DICT_FLAG_NO_REGSUB) {
-           msg_warn("pcre map %s, line %d: "
-                    "regular expression substitution is not allowed",
-                    ctxt->mapname, ctxt->lineno);
-           return (MAC_PARSE_ERROR);
+       if (ctxt->literal) {
+           myfree(ctxt->literal);
+           ctxt->literal = 0;
        }
        if (!alldig(vstring_str(buf))) {
            msg_warn("pcre map %s, line %d: non-numeric replacement index \"%s\"",
@@ -513,6 +523,11 @@ static int dict_pcre_prescan(int type, VSTRING *buf, char *context)
        }
        if (n > ctxt->max_sub)
            ctxt->max_sub = n;
+    } else if (type == MAC_PARSE_LITERAL && ctxt->max_sub == 0) {
+       if (ctxt->literal)
+           msg_panic("pcre map %s, line %d: multiple literals but no $number",
+                     ctxt->mapname, ctxt->lineno);
+       ctxt->literal = mystrdup(vstring_str(buf));
     }
     return (MAC_PARSE_OK);
 }
@@ -599,14 +614,23 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
         */
        prescan_context.mapname = mapname;
        prescan_context.lineno = lineno;
-       prescan_context.flags = dict_flags;
        prescan_context.max_sub = 0;
+       prescan_context.literal = 0;
+
+       /*
+        * The optimizer will eliminate code duplication and/or dead code.
+        */
+#define CREATE_MATCHOP_ERROR_RETURN(rval) do { \
+       if (prescan_context.literal) \
+           myfree(prescan_context.literal); \
+       return (rval); \
+    } while (0)
 
        if (mac_parse(p, dict_pcre_prescan, (char *) &prescan_context)
            & MAC_PARSE_ERROR) {
            msg_warn("pcre map %s, line %d: bad replacement syntax: "
                     "skipping this rule", mapname, lineno);
-           return (0);
+           CREATE_MATCHOP_ERROR_RETURN(0);
        }
 
        /*
@@ -615,14 +639,20 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
        if (prescan_context.max_sub > 0 && regexp.match == 0) {
            msg_warn("pcre map %s, line %d: $number found in negative match "
                   "replacement text: skipping this rule", mapname, lineno);
-           return (0);
+           CREATE_MATCHOP_ERROR_RETURN(0);
+       }
+       if (prescan_context.max_sub > 0 && (dict_flags & DICT_FLAG_NO_REGSUB)) {
+           msg_warn("pcre map %s, line %d: "
+                    "regular expression substitution is not allowed: "
+                    "skipping this rule", mapname, lineno);
+           CREATE_MATCHOP_ERROR_RETURN(0);
        }
 
        /*
         * Compile the pattern.
         */
        if (dict_pcre_compile(mapname, lineno, &regexp, &engine) == 0)
-           return (0);
+           CREATE_MATCHOP_ERROR_RETURN(0);
 
        /*
         * Save the result.
@@ -631,7 +661,11 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
            dict_pcre_rule_alloc(DICT_PCRE_OP_MATCH, nesting, lineno,
                                 sizeof(DICT_PCRE_MATCH_RULE));
        match_rule->match = regexp.match;
-       match_rule->replacement = mystrdup(p);
+       match_rule->max_sub = prescan_context.max_sub;
+        if (prescan_context.literal)
+            match_rule->replacement = prescan_context.literal;
+        else
+           match_rule->replacement = mystrdup(p);
        match_rule->pattern = engine.pattern;
        match_rule->hints = engine.hints;
        return ((DICT_PCRE_RULE *) match_rule);
@@ -747,6 +781,7 @@ DICT   *dict_pcre_open(const char *mapname, int unused_flags, int dict_flags)
     dict_pcre->dict.close = dict_pcre_close;
     dict_pcre->dict.flags = dict_flags | DICT_FLAG_PATTERN;
     dict_pcre->head = 0;
+    dict_pcre->expansion_buf = 0;
 
     if (dict_pcre_init == 0) {
        pcre_malloc = (void *(*) (size_t)) mymalloc;
index 8bb73bc7420983b09694b4d6164ef73282ee565a..f56a7ea595b55687d80c9ae9e9670032a26a6c26 100644 (file)
@@ -110,6 +110,7 @@ typedef struct {
     DICT    dict;                      /* generic members */
     regmatch_t *pmatch;                        /* matched substring info */
     DICT_REGEXP_RULE *head;            /* first rule */
+    VSTRING *expansion_buf;            /* lookup result */
 } DICT_REGEXP;
 
  /*
@@ -122,10 +123,9 @@ typedef struct {
   * Context for $number expansion callback.
   */
 typedef struct {
-    DICT_REGEXP *dict_regexp;          /* the dictionary entry */
+    DICT_REGEXP *dict_regexp;          /* the dictionary handle */
     DICT_REGEXP_MATCH_RULE *match_rule;        /* the rule we matched */
     const char *lookup_string;         /* matched text */
-    VSTRING *expansion_buf;            /* buffer for $number expansion */
 } DICT_REGEXP_EXPAND_CONTEXT;
 
  /*
@@ -135,6 +135,7 @@ typedef struct {
     const char *mapname;               /* name of regexp map */
     int     lineno;                    /* where in file */
     size_t  max_sub;                   /* largest $number seen */
+    char   *literal;                   /* constant result, $$ -> $ */
 } DICT_REGEXP_PRESCAN_CONTEXT;
 
  /*
@@ -168,7 +169,7 @@ static int dict_regexp_expand(int type, VSTRING *buf, char *ptr)
        pmatch = dict_regexp->pmatch + n;
        if (pmatch->rm_so < 0 || pmatch->rm_so == pmatch->rm_eo)
            return (MAC_PARSE_UNDEF);           /* empty or not matched */
-       vstring_strncat(ctxt->expansion_buf,
+       vstring_strncat(dict_regexp->expansion_buf,
                        ctxt->lookup_string + pmatch->rm_so,
                        pmatch->rm_eo - pmatch->rm_so);
        return (MAC_PARSE_OK);
@@ -178,7 +179,7 @@ static int dict_regexp_expand(int type, VSTRING *buf, char *ptr)
      * Straight text - duplicate with no substitution.
      */
     else {
-       vstring_strcat(ctxt->expansion_buf, vstring_str(buf));
+       vstring_strcat(dict_regexp->expansion_buf, vstring_str(buf));
        return (MAC_PARSE_OK);
     }
 }
@@ -212,7 +213,6 @@ static const char *dict_regexp_lookup(DICT *dict, const char *lookup_string)
     DICT_REGEXP_IF_RULE *if_rule;
     DICT_REGEXP_MATCH_RULE *match_rule;
     DICT_REGEXP_EXPAND_CONTEXT expand_context;
-    static VSTRING *expansion_buf;
     int     error;
     int     nesting = 0;
 
@@ -256,7 +256,8 @@ static const char *dict_regexp_lookup(DICT *dict, const char *lookup_string)
 
            /*
             * Skip $number substitutions when the replacement text contains
-            * no $number strings (as learned during the pre-scan).
+            * no $number strings, as learned during the compile time
+            * pre-scan. The pre-scan already replaced $$ by $.
             */
            if (match_rule->max_sub == 0)
                return (match_rule->replacement);
@@ -267,10 +268,9 @@ static const char *dict_regexp_lookup(DICT *dict, const char *lookup_string)
             * expansion errors at this point mean something impossible has
             * happened.
             */
-           if (!expansion_buf)
-               expansion_buf = vstring_alloc(10);
-           VSTRING_RESET(expansion_buf);
-           expand_context.expansion_buf = expansion_buf;
+           if (!dict_regexp->expansion_buf)
+               dict_regexp->expansion_buf = vstring_alloc(10);
+           VSTRING_RESET(dict_regexp->expansion_buf);
            expand_context.lookup_string = lookup_string;
            expand_context.match_rule = match_rule;
            expand_context.dict_regexp = dict_regexp;
@@ -279,8 +279,8 @@ static const char *dict_regexp_lookup(DICT *dict, const char *lookup_string)
                          (char *) &expand_context) & MAC_PARSE_ERROR)
                msg_panic("regexp map %s, line %d: bad replacement syntax",
                          dict->name, rule->lineno);
-           VSTRING_TERMINATE(expansion_buf);
-           return (vstring_str(expansion_buf));
+           VSTRING_TERMINATE(dict_regexp->expansion_buf);
+           return (vstring_str(dict_regexp->expansion_buf));
 
            /*
             * Conditional.
@@ -349,6 +349,8 @@ static void dict_regexp_close(DICT *dict)
     }
     if (dict_regexp->pmatch)
        myfree((char *) dict_regexp->pmatch);
+    if (dict_regexp->expansion_buf)
+       vstring_free(dict_regexp->expansion_buf);
     dict_free(dict);
 }
 
@@ -467,15 +469,34 @@ static int dict_regexp_prescan(int type, VSTRING *buf, char *context)
     DICT_REGEXP_PRESCAN_CONTEXT *ctxt = (DICT_REGEXP_PRESCAN_CONTEXT *) context;
     size_t  n;
 
+    /*
+     * Keep a copy of literal text (with $$ already replaced by $) if and
+     * only if the replacement text contains no $number expression. This way
+     * we can avoid having to scan the replacement text at lookup time.
+     */
     if (type == MAC_PARSE_VARNAME) {
+       if (ctxt->literal) {
+           myfree(ctxt->literal);
+           ctxt->literal = 0;
+       }
        if (!alldig(vstring_str(buf))) {
            msg_warn("regexp map %s, line %d: non-numeric replacement index \"%s\"",
                     ctxt->mapname, ctxt->lineno, vstring_str(buf));
            return (MAC_PARSE_ERROR);
        }
        n = atoi(vstring_str(buf));
+       if (n < 1) {
+           msg_warn("regexp map %s, line %d: out-of-range replacement index \"%s\"",
+                    ctxt->mapname, ctxt->lineno, vstring_str(buf));
+           return (MAC_PARSE_ERROR);
+       }
        if (n > ctxt->max_sub)
            ctxt->max_sub = n;
+    } else if (type == MAC_PARSE_LITERAL && ctxt->max_sub == 0) {
+       if (ctxt->literal)
+           msg_panic("regexp map %s, line %d: multiple literals but no $number",
+                     ctxt->mapname, ctxt->lineno);
+       ctxt->literal = mystrdup(vstring_str(buf));
     }
     return (MAC_PARSE_OK);
 }
@@ -532,7 +553,7 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
        DICT_REGEXP_PATTERN first_pat;
        DICT_REGEXP_PATTERN second_pat;
        DICT_REGEXP_PRESCAN_CONTEXT prescan_context;
-       regex_t *first_exp;
+       regex_t *first_exp = 0;
        regex_t *second_exp;
        DICT_REGEXP_MATCH_RULE *match_rule;
 
@@ -563,12 +584,26 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
        prescan_context.mapname = mapname;
        prescan_context.lineno = lineno;
        prescan_context.max_sub = 0;
+       prescan_context.literal = 0;
+
+       /*
+        * The optimizer will eliminate code duplication and/or dead code.
+        */
+#define CREATE_MATCHOP_ERROR_RETURN(rval) do { \
+       if (first_exp) { \
+           regfree(first_exp); \
+           myfree((char *) first_exp); \
+       } \
+       if (prescan_context.literal) \
+           myfree(prescan_context.literal); \
+       return (rval); \
+    } while (0)
 
        if (mac_parse(p, dict_regexp_prescan, (char *) &prescan_context)
            & MAC_PARSE_ERROR) {
            msg_warn("regexp map %s, line %d: bad replacement syntax: "
                     "skipping this rule", mapname, lineno);
-           return (0);
+           CREATE_MATCHOP_ERROR_RETURN(0);
        }
 
        /*
@@ -577,36 +612,33 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
         * result string, or when the highest numbered substring is less than
         * the total number of () subpatterns.
         */
-#define FREE_EXPR_AND_RETURN(expr, rval) \
-       { regfree(expr); myfree((char *) (expr)); return (rval); }
-
-       if (prescan_context.max_sub == 0 || first_pat.match == 0) {
+       if (prescan_context.max_sub == 0) 
            first_pat.options |= REG_NOSUB;
-       } else if (dict_flags & DICT_FLAG_NO_REGSUB) {
+       if (prescan_context.max_sub > 0 && first_pat.match == 0) {
+           msg_warn("regexp map %s, line %d: $number found in negative match "
+                  "replacement text: skipping this rule", mapname, lineno);
+           CREATE_MATCHOP_ERROR_RETURN(0);
+       } 
+       if (prescan_context.max_sub > 0 && (dict_flags & DICT_FLAG_NO_REGSUB)) {
            msg_warn("regexp map %s, line %d: "
                     "regular expression substitution is not allowed: "
                     "skipping this rule", mapname, lineno);
-           return (0);
+           CREATE_MATCHOP_ERROR_RETURN(0);
        }
        if ((first_exp = dict_regexp_compile_pat(mapname, lineno,
                                                 &first_pat)) == 0)
-           return (0);
-       if (prescan_context.max_sub > 0 && first_pat.match == 0) {
-           msg_warn("regexp map %s, line %d: $number found in negative match replacement text: "
-                    "skipping this rule", mapname, lineno);
-           FREE_EXPR_AND_RETURN(first_exp, 0);
-       }
+           CREATE_MATCHOP_ERROR_RETURN(0);
        if (prescan_context.max_sub > first_exp->re_nsub) {
            msg_warn("regexp map %s, line %d: out of range replacement index \"%d\": "
                     "skipping this rule", mapname, lineno,
                     (int) prescan_context.max_sub);
-           FREE_EXPR_AND_RETURN(first_exp, 0);
+           CREATE_MATCHOP_ERROR_RETURN(0);
        }
        if (second_pat.regexp != 0) {
            second_pat.options |= REG_NOSUB;
            if ((second_exp = dict_regexp_compile_pat(mapname, lineno,
                                                      &second_pat)) == 0)
-               FREE_EXPR_AND_RETURN(first_exp, 0);
+               CREATE_MATCHOP_ERROR_RETURN(0);
        } else {
            second_exp = 0;
        }
@@ -615,11 +647,13 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
                                   sizeof(DICT_REGEXP_MATCH_RULE));
        match_rule->first_exp = first_exp;
        match_rule->first_match = first_pat.match;
-       match_rule->max_sub =
-           (prescan_context.max_sub > 0 ? prescan_context.max_sub + 1 : 0);
+       match_rule->max_sub = prescan_context.max_sub;
        match_rule->second_exp = second_exp;
        match_rule->second_match = second_pat.match;
-       match_rule->replacement = mystrdup(p);
+       if (prescan_context.literal)
+           match_rule->replacement = prescan_context.literal;
+       else
+           match_rule->replacement = mystrdup(p);
        return ((DICT_REGEXP_RULE *) match_rule);
     }
 
@@ -706,6 +740,7 @@ DICT   *dict_regexp_open(const char *mapname, int unused_flags, int dict_flags)
     dict_regexp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
     dict_regexp->head = 0;
     dict_regexp->pmatch = 0;
+    dict_regexp->expansion_buf = 0;
 
     /*
      * Parse the regexp table.
index 4e9e0660e807675881f817f5e1d8847d1c59b989..62d05f8d666739705fc658677c4a50f9cdc7653e 100644 (file)
@@ -4,20 +4,37 @@
 ./dict_open: warning: regexp map dict_regexp.map, line 10: out of range replacement index "5": skipping this rule
 ./dict_open: warning: regexp map dict_regexp.map, line 17: $number found in negative match replacement text: skipping this rule
 ./dict_open: warning: regexp map dict_regexp.map, line 22: no regexp: skipping this rule
+> get true
 true: not found
+> get true1
 true1=1
+> get true2
 true2: not found
+> get truefalse2
 truefalse2=2
+> get 3
 3: not found
+> get true3
 true3=3
+> get c
 c=
+> get d
 d: not found
+> get ab
 ab: not found
+> get aa
 aa=a!b
+> get 1235
 1235=(1)(2)(3)
+> get 1234
 1234=(1)(2)(3)(4)
+> get 123
 123=(1)(2)(3)
+> get bar/find
 bar/find: not found
+> get bar/whynot
 bar/whynot=Don't have a liquor license
+> get bar/elbereth
 bar/elbereth=(elbereth)
+> get say/elbereth
 say/elbereth: not found
index 941d58b94f17f1101d0a7d86b16e29945648c928..0cf8ab2b257b395a3a8abc9f21fb612ac3b45006 100644 (file)
@@ -550,6 +550,7 @@ int     sockaddr_to_hostaddr(const struct sockaddr * sa, SOCKADDR_SIZE salen,
     if (hostaddr != 0) {
        if (inet_ntop(AF_INET, (void *) &(SOCK_ADDR_IN_ADDR(sa)),
                      hostaddr->buf, sizeof(hostaddr->buf)) == 0)
+           errno = ENOSPC;
            return (EAI_SYSTEM);
     }
     if (portnum != 0) {
index 5e9e85b66ee610d935eee29f8b0da251ffabb086..b42065e8752e452689c6a48921d44e1f74aae6ac 100644 (file)
@@ -300,7 +300,7 @@ XSASL_CLIENT *xsasl_cyrus_client_create(XSASL_CLIENT_IMPL *unused_impl,
     int     sasl_status;
 
     /*
-     * The optimizer will eliminate duplication and/or dead code.
+     * The optimizer will eliminate code duplication and/or dead code.
      */
 #define XSASL_CYRUS_CLIENT_CREATE_ERROR_RETURN(x) \
     do { \
index f9ecbe1b653f4ada5d052829262ee05f70c2da1d..182213f32533a1c4a54a6329bd60b8185973f24c 100644 (file)
@@ -262,7 +262,7 @@ static XSASL_SERVER *xsasl_cyrus_server_create(XSASL_SERVER_IMPL *unused_impl,
                 myname, service, realm ? realm : "(null)");
 
     /*
-     * The optimizer will eliminate duplication and/or dead code.
+     * The optimizer will eliminate code duplication and/or dead code.
      */
 #define XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(x) \
     do { \