]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-19990507
authorWietse Venema <wietse@porcupine.org>
Fri, 7 May 1999 05:00:00 +0000 (00:00 -0500)
committerWietse Venema <wietse@porcupine.org>
Thu, 17 Jan 2013 03:34:21 +0000 (22:34 -0500)
25 files changed:
postfix/conf/main.cf
postfix/conf/main.cf.default
postfix/conf/sample-local.cf
postfix/global/mail_version.h
postfix/html/local.8.html
postfix/local/Makefile.in
postfix/local/alias.c
postfix/local/command.c
postfix/local/deliver_attr.c
postfix/local/dotforward.c
postfix/local/local.c
postfix/local/local.h
postfix/local/local_expand.c
postfix/local/mailbox.c
postfix/local/recipient.c
postfix/local/resolve.c
postfix/makedefs
postfix/man/man8/local.8
postfix/postconf/Makefile.in
postfix/smtpd/smtpd_check.c
postfix/util/hattr.c [new file with mode: 0644]
postfix/util/htable.c
postfix/util/mac_expand.c
postfix/util/mac_expand.h
postfix/util/mac_expand.ref

index 35e3aedf70a2ca6bb8b5fa73dfff7afde97ff9a4..e79c06851ae339dfe0171275180480cfc7152f23 100644 (file)
@@ -228,9 +228,9 @@ program_directory = /some/where/postfix/bin
 # The following expansions are done on mailbox_command: $user (recipient
 # username), $shell (recipient shell), $home (recipient home directory),
 # $recipient (full recipient address), $extension (recipient address
-# extension), $domain (recipient domain), $recipient_delimiter. Specify
-# ${name?value} or ${name:value} to expand value only when $name does
-# (does not) exist.
+# extension), $domain (recipient domain), $mailbox (entire recipient
+# localpart), $recipient_delimiter. Specify ${name?value} or
+# ${name:value} to expand value only when $name does (does not) exist.
 # 
 # Avoid shell meta characters because they will force Postfix to run
 # an expensive shell process. Procmail alone is expensive enough.
@@ -250,16 +250,20 @@ program_directory = /some/where/postfix/bin
 #
 #fallback_transport =
 
-# The luser_relay parameter specifies an optional destination 
-# (@domain, address, "|command", /file/name) for unknown recipients.
-# By default, mail for unknown local recipients is bounced.
+# The luser_relay parameter specifies an optional destination (@domain,
+# address) for unknown recipients.  By default, mail for unknown
+# local recipients is bounced.
 #
 # Specify @domain in order to keep the original recipient name.
-# If an address is specified, and if a recipient delimiter is 
-# specified, the original recipient name is appended to the addres
-# localpart.
+# The following expansions are done on luser_relay: $user (recipient
+# username), $shell (recipient shell), $home (recipient home directory),
+# $recipient (full recipient address), $extension (recipient address
+# extension), $domain (recipient domain), $mailbox (entire recipient
+# localpart), $recipient_delimiter. Specify ${name?value} or
+# ${name:value} to expand value only when $name does (does not) exist.
 #
-# luser_relay =
+# luser_relay = @other.host
+# luser_relay = admin+$mailbox
   
 # JUNK MAIL CONTROLS
 # 
index 83ded82759f68f6889da5d49ee2c3f7a36646d8c..eccb1988a9675f9c74b6f396d1e8da322bb40ef5 100644 (file)
@@ -61,7 +61,7 @@ luser_relay =
 mail_name = Postfix
 mail_owner = postfix
 mail_spool_directory = /var/mail
-mail_version = Snapshot-19990505
+mail_version = Snapshot-19990507
 mailbox_command = 
 mailbox_transport = 
 maps_rbl_domains = rbl.maps.vix.com
index 379db64360d194068ced2c0450a47e6720678eef..b083dffa589792e9ff43963d71182490e90d0d22 100644 (file)
@@ -30,9 +30,9 @@
 # The following expansions are done on forward_path: $user (recipient
 # username), $shell (recipient shell), $home (recipient home directory),
 # $recipient (full recipient address), $extension (recipient address
-# extension), $domain (recipient domain), $recipient_delimiter. Specify
-# ${name?value} or ${name:value} to expand value only when $name does
-# (does not) exist.
+# extension), $domain (recipient domain), $mailbox (entire recipient
+# localpart), $recipient_delimiter. Specify ${name?value} or
+# ${name:value} to expand value only when $name does (does not) exist.
 #
 #forward_path = /var/forward/$user
 forward_path = $home/.forward$recipient_delimiter$extension,$home/.forward
@@ -76,11 +76,15 @@ home_mailbox =
 # By default, mail for unknown local recipients is bounced.
 #
 # Specify @domain in order to keep the original recipient name.
-# If an address is specified, and if a recipient delimiter is
-# specified, the original recipient name is appended to the addres
-# localpart.
+# The following expansions are done on luser_relay: $user (recipient
+# username), $shell (recipient shell), $home (recipient home directory),
+# $recipient (full recipient address), $extension (recipient address
+# extension), $domain (recipient domain), $mailbox (entire recipient
+# localpart), $recipient_delimiter. Specify ${name?value} or
+# ${name:value} to expand value only when $name does (does not) exist.
 #
-# luser_relay =
+# luser_relay = @other.host
+# luser_relay = admin+$mailbox
 
 # The mail_spool_directory parameter specifies the directory where
 # UNIX-style mailboxes are kept. The default setting depends on the
@@ -97,9 +101,9 @@ home_mailbox =
 # The following expansions are done on mailbox_command: $user (recipient
 # username), $shell (recipient shell), $home (recipient home directory),
 # $recipient (full recipient address), $extension (recipient address
-# extension), $domain (recipient domain), $recipient_delimiter. Specify
-# ${name?value} or ${name:value} to expand value only when $name does
-# (does not) exist.
+# extension), $domain (recipient domain), $mailbox (entire recipient
+# localpart), $recipient_delimiter. Specify ${name?value} or
+# ${name:value} to expand value only when $name does (does not) exist.
 #
 # Avoid shell meta characters because they will force Postfix to run
 # an expensive shell process. Procmail alone is expensive enough.
index 97dc67f3aebfd6c1a6c0da6db5eba788ac605329..bab9fdc6685926b492e826ca80d2eaca342adc5e 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-19990505"
+#define DEF_MAIL_VERSION       "Snapshot-19990507"
 extern char *var_mail_version;
 
 /* LICENSE
index 336b5359ef47fca5ab3311b40a6363bb007e2d1e..f1678022639d187988f13ee6d24375d0e6cb0384 100644 (file)
@@ -41,10 +41,10 @@ LOCAL(8)                                                 LOCAL(8)
        interpolation of <b>$user</b> (recipient username), <b>$home</b> (recip-
        ient home directory), <b>$shell</b> (recipient shell), <b>$recipient</b>
        (complete  recipient   address),   <b>$extension</b>   (recipient
-       address extension), <b>$domain</b> (recipient domain) and <b>$recip-</b>
-       <b>ient</b><i>_</i><b>delimiter.</b> The forms <i>${name?value}</i> and  <i>${name:value}</i>
-       expand  conditionally  to  <i>value</i>  when  <i>$name</i>  is (is not)
-       defined.
+       address  extension),  <b>$domain</b>  (recipient domain), <b>mailbox</b>
+       (entire recipient address localpart) and <b>$recipient</b><i>_</i><b>delim-</b>
+       <b>iter.</b>  The  forms  <i>${name?value}</i>  and <i>${name:value}</i> expand
+       conditionally to <i>value</i> when <i>$name</i> is (is not) defined.
 
        An alias or ~/.<b>forward</b> file may list  any  combination  of
        external   commands,  destination  file  names,  <b>:include:</b>
@@ -111,20 +111,20 @@ LOCAL(8)                                                 LOCAL(8)
        ent  username),  <b>$home</b>  (recipient home directory), <b>$shell</b>
        (recipient   shell),   <b>$recipient</b>   (complete    recipient
        address),   <b>$extension</b>   (recipient   address  extension),
-       <b>$domain</b> (recipient domain) and  <b>$recipient</b><i>_</i><b>delimiter.</b>  The
-       forms <i>${name?value}</i> and <i>${name:value}</i> expand conditionally
-       to <i>value</i> when <i>$name</i> is (is not) defined. In the result  of
-       <i>name</i>  expansion,  characters  that have special meaning to
+       <b>$domain</b>  (recipient  domain),  <b>mailbox</b>  (entire  recipient
+       address  localpart)  and  <b>$recipient</b><i>_</i><b>delimiter.</b>  The forms
+       <i>${name?value}</i> and <i>${name:value}</i>  expand  conditionally  to
+       <i>value</i>  when  <i>$name</i>  is  (is not) defined. In the result of
+       <i>name</i> expansion, characters that have  special  meaning  to
        the shell are censored and replaced by underscores.
 
-       Mailbox delivery can be delegated to  alternative  message
-       transports  specified  in  the  <b>master.cf</b> file.  The <b>mail-</b>
-       <b>box</b><i>_</i><b>transport</b> configuration parameter specifies a  message
-       transport  that  is  to  be used for all local recipients,
-       regardless of whether they are found in  the  UNIX  passwd
-       database.   The  <b>fallback</b><i>_</i><b>transport</b>  parameter specifies a
+       Mailbox  delivery  can be delegated to alternative message
+       transports specified in the  <b>master.cf</b>  file.   The  <b>mail-</b>
+       <b>box</b><i>_</i><b>transport</b>  configuration parameter specifies a message
+       transport that is to be used  for  all  local  recipients,
+       regardless  of  whether  they are found in the UNIX passwd
+       database.  The <b>fallback</b><i>_</i><b>transport</b>  parameter  specifies  a
        message transport for recipients that are not found in the
-       UNIX passwd database.
 
 
 
@@ -137,37 +137,39 @@ LOCAL(8)                                                 LOCAL(8)
 LOCAL(8)                                                 LOCAL(8)
 
 
+       UNIX passwd database.
+
        In the case of UNIX-style mailbox delivery, the <b>local</b> dae-
        mon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope header to
-       each  message,  prepends  a  <b>Delivered-To:</b> header with the
+       each message, prepends a  <b>Delivered-To:</b>  header  with  the
        envelope recipient address, prepends a <b>Return-Path:</b> header
-       with  the  envelope sender address, prepends a &gt; character
-       to lines beginning with "<b>From</b>  ",  and  appends  an  empty
-       line.   The  mailbox  is locked for exclusive access while
-       delivery is in progress. In case of problems,  an  attempt
+       with the envelope sender address, prepends a  &gt;  character
+       to  lines  beginning  with  "<b>From</b>  ", and appends an empty
+       line.  The mailbox is locked for  exclusive  access  while
+       delivery  is  in progress. In case of problems, an attempt
        is made to truncate the mailbox to its original length.
 
        In the case of <b>maildir</b> delivery, the local daemon prepends
        a <b>Delivered-To:</b> header with the envelope recipient address
-       and  prepends  a  <b>Return-Path:</b>  header  with  the envelope
+       and prepends  a  <b>Return-Path:</b>  header  with  the  envelope
        sender address.
 
 <b>EXTERNAL</b> <b>COMMAND</b> <b>DELIVERY</b>
-       The   <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b>    configuration    parameter
-       restricts  delivery to external commands. The default set-
-       ting (<b>alias,</b>  <b>forward</b>)  forbids  command  destinations  in
+       The    <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b>    configuration   parameter
+       restricts delivery to external commands. The default  set-
+       ting  (<b>alias,</b>  <b>forward</b>)  forbids  command  destinations in
        <b>:include:</b> files.
 
-       The  command  is  executed directly where possible. Assis-
-       tance by the shell (<b>/bin/sh</b> on UNIX systems) is used  only
-       when  the command contains shell magic characters, or when
+       The command is executed directly  where  possible.  Assis-
+       tance  by the shell (<b>/bin/sh</b> on UNIX systems) is used only
+       when the command contains shell magic characters, or  when
        the command invokes a shell built-in command.
 
-       A limited amount of command output  (standard  output  and
-       standard  error) is captured for inclusion with non-deliv-
-       ery status reports.  A command is forcibly  terminated  if
-       it  does  not  complete within <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> seconds.
-       Command exit status codes are expected to follow the  con-
+       A  limited  amount  of command output (standard output and
+       standard error) is captured for inclusion with  non-deliv-
+       ery  status  reports.  A command is forcibly terminated if
+       it does not complete  within  <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b>  seconds.
+       Command  exit status codes are expected to follow the con-
        ventions defined in &lt;<b>sysexits.h</b>&gt;.
 
        When mail is delivered on behalf of a user, the <b>HOME</b>, <b>LOG-</b>
@@ -179,18 +181,16 @@ LOCAL(8)                                                 LOCAL(8)
        The current working directory is the mail queue directory.
 
        The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve-
-       lope  header  to  each  message,  prepends a <b>Delivered-To:</b>
-       header with the recipient  envelope  address,  prepends  a
-       <b>Return-Path:</b>  header with the sender envelope address, and
+       lope header to  each  message,  prepends  a  <b>Delivered-To:</b>
+       header  with  the  recipient  envelope address, prepends a
+       <b>Return-Path:</b> header with the sender envelope address,  and
        appends an empty line.
 
 <b>EXTERNAL</b> <b>FILE</b> <b>DELIVERY</b>
-       The <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> configuration parameter  restricts
-       delivery  to  external  files. The default setting (<b>alias,</b>
-       <b>forward</b>) forbids file  destinations  in  <b>:include:</b>  files.
+       The  <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> configuration parameter restricts
+       delivery to external files. The  default  setting  (<b>alias,</b>
+       <b>forward</b>)  forbids  file  destinations  in <b>:include:</b> files.
        Specify  a  pathname  ending  in  <b>/</b>  for  <b>qmail</b>-compatible
-       <b>maildir</b> delivery.
-
 
 
 
@@ -203,40 +203,42 @@ LOCAL(8)                                                 LOCAL(8)
 LOCAL(8)                                                 LOCAL(8)
 
 
+       <b>maildir</b> delivery.
+
        The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve-
-       lope  header  to  each  message,  prepends a <b>Delivered-To:</b>
-       header with the recipient envelope address, prepends  a  &gt;
-       character  to lines beginning with "<b>From</b> ", and appends an
-       empty line.  The envelope sender address is  available  in
-       the  <b>Return-Path:</b> header.  When the destination is a regu-
+       lope header to  each  message,  prepends  a  <b>Delivered-To:</b>
+       header  with  the recipient envelope address, prepends a &gt;
+       character to lines beginning with "<b>From</b> ", and appends  an
+       empty  line.   The envelope sender address is available in
+       the <b>Return-Path:</b> header.  When the destination is a  regu-
        lar file, it is locked for exclusive access while delivery
        is in progress. In case of problems, an attempt is made to
        truncate a regular file to its original length.
 
        In the case of <b>maildir</b> delivery, the local daemon prepends
-       a   <b>Delivered-To:</b>   header  with  the  envelope  recipient
-       address.  The envelope sender address is available in  the
+       a  <b>Delivered-To:</b>  header  with  the   envelope   recipient
+       address.   The envelope sender address is available in the
        <b>Return-Path:</b> header.
 
 <b>ADDRESS</b> <b>EXTENSION</b>
-       The  optional  <b>recipient</b><i>_</i><b>delimiter</b> configuration parameter
-       specifies how to separate address  extensions  from  local
+       The optional <b>recipient</b><i>_</i><b>delimiter</b>  configuration  parameter
+       specifies  how  to  separate address extensions from local
        recipient names.
 
-       For  example,  with  "<b>recipient</b><i>_</i><b>delimiter</b>  <b>=</b>  <b>+</b>", mail for
-       <i>name</i>+<i>foo</i> is delivered to the  alias  <i>name</i>+<i>foo</i>  or  to  the
-       alias  <i>name</i>,  to  the  destinations  listed in ~<i>name</i>/.<b>for-</b>
+       For example, with  "<b>recipient</b><i>_</i><b>delimiter</b>  <b>=</b>  <b>+</b>",  mail  for
+       <i>name</i>+<i>foo</i>  is  delivered  to  the  alias <i>name</i>+<i>foo</i> or to the
+       alias <i>name</i>, to  the  destinations  listed  in  ~<i>name</i>/.<b>for-</b>
        <b>ward</b>+<i>foo</i> or in ~<i>name</i>/.<b>forward</b>, to the mailbox owned by the
        user <i>name</i>, or it is sent back as undeliverable.
 
-       In  all  cases  the <b>local</b> daemon prepends a `<b>Delivered-To:</b>
+       In all cases the <b>local</b> daemon  prepends  a  `<b>Delivered-To:</b>
        <i>name</i>+<i>foo</i>' header line.
 
 <b>DELIVERY</b> <b>RIGHTS</b>
-       Deliveries to external files  and  external  commands  are
+       Deliveries  to  external  files  and external commands are
        made with the rights of the receiving user on whose behalf
-       the delivery is made.  In the absence of a  user  context,
-       the  <b>local</b>  daemon  uses the owner rights of the <b>:include:</b>
+       the  delivery  is made.  In the absence of a user context,
+       the <b>local</b> daemon uses the owner rights  of  the  <b>:include:</b>
        file or alias database.  When those files are owned by the
        superuser, delivery is made with the rights specified with
        the <b>default</b><i>_</i><b>privs</b> configuration parameter.
@@ -245,18 +247,16 @@ LOCAL(8)                                                 LOCAL(8)
        RFC 822 (ARPA Internet Text Messages)
 
 <b>DIAGNOSTICS</b>
-       Problems and transactions are logged to <b>syslogd</b>(8).   Cor-
-       rupted  message files are marked so that the queue manager
+       Problems  and transactions are logged to <b>syslogd</b>(8).  Cor-
+       rupted message files are marked so that the queue  manager
        can move them to the <b>corrupt</b> queue afterwards.
 
-       Depending on the setting of the <b>notify</b><i>_</i><b>classes</b>  parameter,
-       the  postmaster  is notified of bounces and of other trou-
+       Depending  on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
+       the postmaster is notified of bounces and of  other  trou-
        ble.
 
 <b>BUGS</b>
-       For security  reasons,  the  message  delivery  status  of
-       external  commands  or  of  external files is never check-
-       pointed to file. As a result, the program may occasionally
+       For  security  reasons,  the  message  delivery  status of
 
 
 
@@ -269,17 +269,19 @@ LOCAL(8)                                                 LOCAL(8)
 LOCAL(8)                                                 LOCAL(8)
 
 
+       external commands or of external  files  is  never  check-
+       pointed to file. As a result, the program may occasionally
        deliver more than once to a command or external file. Bet-
        ter safe than sorry.
 
-       Mutually-recursive aliases or  ~/.<b>forward</b>  files  are  not
-       detected  early.   The  resulting  mail forwarding loop is
+       Mutually-recursive  aliases  or  ~/.<b>forward</b>  files are not
+       detected early.  The resulting  mail  forwarding  loop  is
        broken by the use of the <b>Delivered-To:</b> message header.
 
 <b>CONFIGURATION</b> <b>PARAMETERS</b>
-       The following <b>main.cf</b> parameters are  especially  relevant
-       to  this  program. See the Postfix <b>main.cf</b> file for syntax
-       details and for default values.  Use  the  <b>postfix</b>  <b>reload</b>
+       The  following  <b>main.cf</b> parameters are especially relevant
+       to this program. See the Postfix <b>main.cf</b> file  for  syntax
+       details  and  for  default  values. Use the <b>postfix</b> <b>reload</b>
        command after a configuration change.
 
 <b>Miscellaneous</b>
@@ -287,10 +289,8 @@ LOCAL(8)                                                 LOCAL(8)
               List of alias databases.
 
        <b>forward</b><i>_</i><b>path</b>
-              Search  list  for  .forward  files.   The following
-              macros  are  recognized:  <b>$home</b>  (home  directory),
-              <b>$user</b> (login name), <b>$extension</b> (address extension),
-              <b>$recipient</b><i>_</i><b>delimiter</b> (address extension delimiter).
+              Search list for .forward files.  The names are sub-
+              ject to <i>$name</i> expansion.
 
        <b>local</b><i>_</i><b>command</b><i>_</i><b>shell</b>
               Shell  to  use  for external command execution (for
@@ -319,8 +319,8 @@ LOCAL(8)                                                 LOCAL(8)
 
        <b>luser</b><i>_</i><b>relay</b>
               Destination (<i>@domain</i> or <i>address</i>)  for  non-existent
-              users.   The <i>address</i> can be any destination that is
-              valid in an alias file.
+              users.   The  <i>address</i>  is subjected to <i>$name</i> expan-
+              sion.
 
 
 
index 0eb8d6d3eb519c7de1b74f7ad3a49e01cfabc1ad..943b2b70f4f88e852177631b18f272c464f1673e 100644 (file)
@@ -97,6 +97,7 @@ command.o: ../include/vstring.h
 command.o: ../include/vbuf.h
 command.o: ../include/vstream.h
 command.o: ../include/argv.h
+command.o: ../include/mac_expand.h
 command.o: ../include/defer.h
 command.o: ../include/bounce.h
 command.o: ../include/sent.h
@@ -154,7 +155,7 @@ dotforward.o: ../include/lstat_as.h
 dotforward.o: ../include/iostuff.h
 dotforward.o: ../include/stringops.h
 dotforward.o: ../include/mymalloc.h
-dotforward.o: ../include/mac_parse.h
+dotforward.o: ../include/mac_expand.h
 dotforward.o: ../include/mypwd.h
 dotforward.o: ../include/bounce.h
 dotforward.o: ../include/been_here.h
@@ -291,13 +292,11 @@ local.o: ../include/tok822.h
 local.o: ../include/resolve_clnt.h
 local_expand.o: local_expand.c
 local_expand.o: ../include/sys_defs.h
-local_expand.o: ../include/vstring.h
-local_expand.o: ../include/vbuf.h
-local_expand.o: ../include/mac_expand.h
-local_expand.o: ../include/mail_params.h
-local_expand.o: local.h
 local_expand.o: ../include/htable.h
+local_expand.o: local.h
 local_expand.o: ../include/vstream.h
+local_expand.o: ../include/vbuf.h
+local_expand.o: ../include/vstring.h
 local_expand.o: ../include/been_here.h
 local_expand.o: ../include/tok822.h
 local_expand.o: ../include/resolve_clnt.h
index 982567babd3546c18442677c4cbaee645a73d2bd..cd975ebcd2955c309faa774b4a5df07f272f92fc 100644 (file)
@@ -6,9 +6,10 @@
 /* SYNOPSIS
 /*     #include "local.h"
 /*
-/*     int     deliver_alias(state, usr_attr, statusp)
+/*     int     deliver_alias(state, usr_attr, name, statusp)
 /*     LOCAL_STATE state;
 /*     USER_ATTR usr_attr;
+/*     char    *name;
 /*     int     *statusp;
 /* DESCRIPTION
 /*     deliver_alias() looks up the expansion of the recipient in
@@ -37,6 +38,8 @@
 /*      A table with delivered-to: addresses taken from the message.
 /* .IP usr_attr
 /*     User attributes (rights, environment).
+/* .IP name
+/*     The alias to be looked up.
 /* .IP statusp
 /*     Delivery status. See below.
 /* DIAGNOSTICS
@@ -119,7 +122,8 @@ static uid_t dict_owner(char *table)
 
 /* deliver_alias - expand alias file entry */
 
-int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
+int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
+                             char *name, int *statusp)
 {
     char   *myname = "deliver_alias";
     const char *alias_result;
@@ -161,15 +165,15 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      * a possible alias loop.
      */
     if (state.msg_attr.exp_from != 0
-       && strcasecmp(state.msg_attr.exp_from, state.msg_attr.local) == 0)
+       && strcasecmp(state.msg_attr.exp_from, name) == 0)
        return (NO);
     if (state.level > 100) {
-       msg_warn("possible alias database loop for %s", state.msg_attr.local);
+       msg_warn("possible alias database loop for %s", name);
        *statusp = bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
-              "possible alias database loop for %s", state.msg_attr.local);
+              "possible alias database loop for %s", name);
        return (YES);
     }
-    state.msg_attr.exp_from = state.msg_attr.local;
+    state.msg_attr.exp_from = name;
 
     /*
      * There are a bunch of roles that we're trying to keep track of.
@@ -196,10 +200,9 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
            msg_warn("invalid alias map type: %s", *cpp);
            continue;
        }
-       if ((alias_result = dict_get(dict, state.msg_attr.local)) != 0) {
+       if ((alias_result = dict_get(dict, name)) != 0) {
            if (msg_verbose)
-               msg_info("%s: %s: %s = %s", myname, *cpp,
-                        state.msg_attr.local, alias_result);
+               msg_info("%s: %s: %s = %s", myname, *cpp, name, alias_result);
 
            /*
             * DELIVERY POLICY
@@ -243,7 +246,7 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
 #define STR(x) vstring_str(x)
 #define OWNER_ASSIGN(own) \
            (own = (var_ownreq_special == 0 ? 0 : \
-           concatenate("owner-", state.msg_attr.local, (char *) 0)))
+           concatenate("owner-", name, (char *) 0)))
 
            expansion = mystrdup(alias_result);
            if (OWNER_ASSIGN(owner) != 0 && maps_find(maps, owner,
@@ -292,8 +295,7 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
            return (YES);
        } else {
            if (msg_verbose)
-               msg_info("%s: %s: %s not found", myname, *cpp,
-                        state.msg_attr.local);
+               msg_info("%s: %s: %s not found", myname, *cpp, name);
        }
     }
 
@@ -303,9 +305,9 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      */
 #define STREQ(x,y) (strcasecmp(x,y) == 0)
 
-    if (STREQ(state.msg_attr.local, MAIL_ADDR_MAIL_DAEMON)
-       || STREQ(state.msg_attr.local, MAIL_ADDR_POSTMASTER)) {
-       msg_warn("required alias not found: %s", state.msg_attr.local);
+    if (STREQ(name, MAIL_ADDR_MAIL_DAEMON)
+       || STREQ(name, MAIL_ADDR_POSTMASTER)) {
+       msg_warn("required alias not found: %s", name);
        *statusp = sent(SENT_ATTR(state.msg_attr), "discarded");
        return (YES);
     }
index c6a4b2425cdf97e8d1f06ad13eb26e42fa8988b9..481223fc55686e205284f042ea84187d9dc60ec9 100644 (file)
@@ -57,6 +57,7 @@
 #include <vstring.h>
 #include <vstream.h>
 #include <argv.h>
+#include <mac_expand.h>
 
 /* Global library. */
 
@@ -86,6 +87,7 @@ int     deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, char *command)
 abcdefghijklmnopqrstuvwxyz\
 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     VSTRING *expanded_cmd;
+    HTABLE  *expand_attr;
 
     /*
      * Make verbose logging easier to understand.
@@ -151,9 +153,14 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     argv_terminate(env);
 
     expanded_cmd = vstring_alloc(10);
-    if (command == var_mailbox_command)
-       local_expand(expanded_cmd, command, state, usr_attr, ok_chars);
-    else
+    if (command == var_mailbox_command) {
+       expand_attr = local_expand(state, usr_attr);
+       mac_expand(expanded_cmd, command, MAC_EXP_FLAG_NONE,
+                  MAC_EXP_ARG_FILTER, ok_chars,
+                  MAC_EXP_ARG_TABLE, expand_attr,
+                  0);
+       htable_free(expand_attr, (void (*) (char *)) 0);
+    } else
        vstring_strcpy(expanded_cmd, command);
 
     cmd_status = pipe_command(state.msg_attr.fp, why,
index 7b62509df1e8e21f3f15f37f7dd2b794bcab9039..11dbf09a5a4f4ba3c8fcd38bf6e942dea42ceb99 100644 (file)
@@ -52,8 +52,11 @@ void    deliver_attr_init(DELIVER_ATTR *attrp)
     attrp->offset = 0;
     attrp->sender = 0;
     attrp->recipient = 0;
+    attrp->domain = 0;
     attrp->local = 0;
+    attrp->user = 0;
     attrp->extension = 0;
+    attrp->unmatched = 0;
     attrp->owner = 0;
     attrp->delivered = 0;
     attrp->relay = 0;
@@ -74,8 +77,11 @@ void    deliver_attr_dump(DELIVER_ATTR *attrp)
     msg_info("offset: %ld", attrp->offset);
     msg_info("sender: %s", attrp->sender ? attrp->sender : "null");
     msg_info("recipient: %s", attrp->recipient ? attrp->recipient : "null");
+    msg_info("domain: %s", attrp->domain ? attrp->domain : "null");
     msg_info("local: %s", attrp->local ? attrp->local : "null");
+    msg_info("user: %s", attrp->user ? attrp->user : "null");
     msg_info("extension: %s", attrp->extension ? attrp->extension : "null");
+    msg_info("unmatched: %s", attrp->unmatched ? attrp->unmatched : "null");
     msg_info("owner: %s", attrp->owner ? attrp->owner : "null");
     msg_info("delivered: %s", attrp->delivered ? attrp->delivered : "null");
     msg_info("relay: %s", attrp->relay ? attrp->relay : "null");
index 0c73a981a5ec854c216d0176711af4b5d466b2af..aef9e0eed2121145c3cbb43749075e8d9a66bc1d 100644 (file)
@@ -67,7 +67,7 @@
 #include <iostuff.h>
 #include <stringops.h>
 #include <mymalloc.h>
-#include <mac_parse.h>
+#include <mac_expand.h>
 
 /* Global library. */
 
@@ -102,6 +102,9 @@ int     deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
     char   *lhs;
     char   *next;
     const char *forward_path;
+    HTABLE *expand_attr;
+    HTABLE *record_attr;
+    HTABLE_INFO *extension_record;
 
     /*
      * Make verbose logging easier to understand.
@@ -112,8 +115,8 @@ int     deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
 
     /*
      * Skip this module if per-user forwarding is disabled. XXX We need to
-     * extend the mail_conf_XXX() interface to request no expansion of $names in
-     * the given value or in the default value.
+     * extend the mail_conf_XXX() interface to request no expansion of $names
+     * in the given value or in the default value.
      */
     if ((forward_path = mail_conf_lookup(VAR_FORWARD_PATH)) == 0)
        forward_path = DEF_FORWARD_PATH;
@@ -134,7 +137,7 @@ int     deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      * Skip non-existing users. The mailbox delivery routine will catch the
      * error.
      */
-    if ((mypwd = mypwnam(state.msg_attr.local)) == 0)
+    if ((mypwd = mypwnam(state.msg_attr.user)) == 0)
        return (NO);
 
     /*
@@ -197,19 +200,33 @@ int     deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
     next = saved_forward_path;
     lookup_status = -1;
 
+    expand_attr = local_expand(state, usr_attr);
+    record_attr = htable_create(0);
+    extension_record = htable_enter(record_attr, "extension", (char *) 0);
+
     while ((lhs = mystrtok(&next, ", \t\r\n")) != 0) {
        VSTRING_RESET(path);
-       if (local_expand(path, lhs, state, usr_attr, (char *) 0) == 0) {
+       extension_record->value = 0;
+       if (mac_expand(path, lhs, MAC_EXP_FLAG_NONE,
+                      MAC_EXP_ARG_TABLE, expand_attr,
+                      MAC_EXP_ARG_RECORD, record_attr,
+                      0) == 0) {
            lookup_status =
                lstat_as(STR(path), &st, usr_attr.uid, usr_attr.gid);
            if (msg_verbose)
                msg_info("%s: path %s status %d", myname,
                         STR(path), lookup_status);
-           if (lookup_status >= 0) 
+           if (lookup_status >= 0) {
+               if (extension_record->value != 0)
+                   state.msg_attr.unmatched = 0;
                break;
+           }
        }
     }
 
+    htable_free(expand_attr, (void (*) (char *)) 0);
+    htable_free(record_attr, (void (*) (char *)) 0);
+
     if (lookup_status >= 0) {
        if (S_ISREG(st.st_mode) == 0) {
            msg_warn("file %s is not a regular file", STR(path));
index 3147a3928511ee19d1ec3abf3e8f5ccda2f4e67d..7a29b49b05193d47ebf2d67d41f4b789a7b97ba9 100644 (file)
@@ -35,7 +35,8 @@
 /*     \fB$user\fR (recipient username), \fB$home\fR (recipient home
 /*     directory), \fB$shell\fR (recipient shell), \fB$recipient\fR
 /*     (complete recipient address), \fB$extension\fR (recipient address
-/*     extension), \fB$domain\fR (recipient domain) and
+/*     extension), \fB$domain\fR (recipient domain), \fBmailbox\fR
+/*     (entire recipient address localpart) and
 /*     \fB$recipient_delimiter.\fR The forms \fI${name?value}\fR and
 /*     \fI${name:value}\fR expand conditionally to \fIvalue\fR when
 /*     \fI$name\fR is (is not) defined.
@@ -94,7 +95,8 @@
 /*     username), \fB$home\fR (recipient home directory), \fB$shell\fR
 /*     (recipient shell), \fB$recipient\fR (complete recipient address),
 /*     \fB$extension\fR (recipient address extension), \fB$domain\fR
-/*     (recipient domain) and \fB$recipient_delimiter.\fR The forms
+/*     (recipient domain), \fBmailbox\fR (entire recipient address 
+/*     localpart) and \fB$recipient_delimiter.\fR The forms
 /*     \fI${name?value}\fR and \fI${name:value}\fR expand conditionally to
 /*     \fIvalue\fR when \fI$name\fR is (is not) defined. In the result
 /*     of \fIname\fR expansion, characters that have special meaning to
 /* .IP \fBalias_maps\fR
 /*     List of alias databases.
 /* .IP \fBforward_path\fR
-/*     Search list for .forward files.  The following macros are recognized:
-/*     \fB$home\fR (home directory), \fB$user\fR (login name),
-/*     \fB$extension\fR (address extension), \fB$recipient_delimiter\fR
-/*     (address extension delimiter).
+/*     Search list for .forward files.  The names are subject to \fI$name\fR
+/*     expansion.
 /* .IP \fBlocal_command_shell\fR
 /*     Shell to use for external command execution (for example,
 /*     /some/where/smrsh -c).
 /*     Specify a path ending in \fB/\fR for maildir-style delivery.
 /* .IP \fBluser_relay\fR
 /*     Destination (\fI@domain\fR or \fIaddress\fR) for non-existent users.
-/*     The \fIaddress\fR can be any destination that is valid in an alias
-/*     file.
+/*     The \fIaddress\fR is subjected to \fI$name\fR expansion.
 /* .IP \fBmail_spool_directory\fR
 /*     Directory with UNIX-style mailboxes. The default pathname is system
 /*     dependent.
@@ -577,6 +576,7 @@ int     main(int argc, char **argv)
     static CONFIG_STR_TABLE raw_table[] = {
        VAR_FORWARD_PATH, DEF_FORWARD_PATH, &var_forward_path, 0, 0,
        VAR_MAILBOX_COMMAND, DEF_MAILBOX_COMMAND, &var_mailbox_command, 0, 0,
+       VAR_LUSER_RELAY, DEF_LUSER_RELAY, &var_luser_relay, 0, 0,
        0,
     };
 
index 2f72de13c293adf787ddb416adeeecc7c853efc8..0ec125ecc881b44e7bbda7532572f1b3bafea50d 100644 (file)
@@ -68,8 +68,11 @@ typedef struct DELIVER_ATTR {
     long    offset;                    /* data offset */
     char   *sender;                    /* taken from envelope */
     char   *recipient;                 /* taken from resolver */
-    char   *local;                     /* recipient localpart, base name */
+    char   *domain;                    /* recipient domain */
+    char   *local;                     /* recipient full localpart */
+    char   *user;                      /* recipient localpart, base name */
     char   *extension;                 /* recipient localpart, extension */
+    char   *unmatched;                 /* unmatched extension */
     char   *owner;                     /* null or list owner */
     char   *delivered;                 /* for loop detection */
     char   *relay;                     /* relay host */
@@ -136,7 +139,7 @@ typedef struct LOCAL_STATE {
   * "inner" nodes of the delivery graph.
   */
 extern int deliver_recipient(LOCAL_STATE, USER_ATTR);
-extern int deliver_alias(LOCAL_STATE, USER_ATTR, int *);
+extern int deliver_alias(LOCAL_STATE, USER_ATTR, char *, int *);
 extern int deliver_dotforward(LOCAL_STATE, USER_ATTR, int *);
 extern int deliver_include(LOCAL_STATE, USER_ATTR, char *);
 extern int deliver_token(LOCAL_STATE, USER_ATTR, TOK822 *);
@@ -184,7 +187,7 @@ extern int feature_control(const char *);
  /*
   * local_expand.c
   */
-int     local_expand(VSTRING *, const char *, LOCAL_STATE, USER_ATTR, const char *);
+HTABLE *local_expand(LOCAL_STATE, USER_ATTR);
 
 /* LICENSE
 /* .ad
index e8563e45a8007ffb2b785a8b9fa5bfe1ec28c578..dbeeb90909b27b9a5d682773a632ccc844cdb3da 100644 (file)
@@ -2,41 +2,36 @@
 /* NAME
 /*     local_expand 3
 /* SUMMARY
-/*     expand $name based on delivery attributes
+/*     set up attribute list for $name expansion
 /* SYNOPSIS
 /*     #include "local.h"
 /*
-/*     int     local_expand(result, pattern, state, usr_attr, filter)
-/*     VSTRING *result;
-/*     const char *pattern;
+/*     HTABLE *local_expand(state, usr_attr)
 /*     LOCAL_STATE state;
 /*     USER_ATTR usr_attr;
-/*     const char *filter;
 /* DESCRIPTION
-/*     local_expand() expands $name instances on the basis of message
-/*     delivery attributes.
+/*     local_expand() instantiates an attribute table for $name
+/*     expansion.
 /*
-/*     Macros:
-/* .IP $domain
+/*     Attributes:
+/* .IP domain
 /*     The recipient address domain.
-/* .IP $extension
+/* .IP extension
 /*     The recipient address extension.
-/* .IP $home
+/* .IP home
 /*     The recipient home directory.
-/* .IP $recipient
+/* .IP mailbox
+/*     The full recipient address localpart.
+/* .IP recipient
 /*     The full recipient address.
-/* .IP $recipient_delimiter
+/* .IP recipient_delimiter
 /*     The recipient delimiter.
-/* .IP $shell
+/* .IP shell
 /*     The recipient shell program.
-/* .IP $user
+/* .IP user
 /*     The recipient user name.
 /* .PP
 /*     Arguments:
-/* .IP result
-/*     Storage for the result. The result is truncated upon entry.
-/* .IP pattern
-/*     The input with zero or more $name references.
 /* .IP state
 /*     Message delivery attributes (sender, recipient etc.).
 /*     Attributes describing alias, include or forward expansion.
@@ -44,9 +39,6 @@
 /*     A table with delivered-to: addresses taken from the message.
 /* .IP usr_attr
 /*     Attributes describing user rights and environment.
-/* .IP filter
-/*     A null pointer, or a null-terminated list of characters that
-/*     are allowed to appear in the result if a $name expansion.
 /* DIAGNOSTICS
 /*     Fatal errors: out of memory.
 /* SEE ALSO
 
 /* Utility library. */
 
-#include <vstring.h>
-#include <mac_expand.h>
+#include <htable.h>
 
-/* Global library. */
+/* Global library */
 
 #include <mail_params.h>
 
 
 #include "local.h"
 
-/* local_expand - expand contents of .forward file */
+/* local_expand - set up macro expansion attributes */
 
-int     local_expand(VSTRING *result, const char *pattern,
-                 LOCAL_STATE state, USER_ATTR usr_attr, const char *filter)
+HTABLE *local_expand(LOCAL_STATE state, USER_ATTR usr_attr)
 {
-    char   *domain;
+    HTABLE *expand_attr;
 
     /*
      * Impedance matching between the local delivery agent data structures
      * and the mac_expand() interface. The CPU cycles wasted will be
      * negligible.
      */
-    if ((domain = strrchr(state.msg_attr.recipient, '@')) != 0)
-       domain++;
-
-    return (mac_expand(result, pattern, MAC_EXP_FLAG_NONE,
-                      MAC_EXP_ARG_FILTER, filter,
-                      MAC_EXP_ARG_ATTR, "user", usr_attr.logname,
-                      MAC_EXP_ARG_ATTR, "home", usr_attr.home,
-                      MAC_EXP_ARG_ATTR, "shell", usr_attr.shell,
-                      MAC_EXP_ARG_ATTR, "domain", domain,
-                   MAC_EXP_ARG_ATTR, "recipient", state.msg_attr.recipient,
-                   MAC_EXP_ARG_ATTR, "extension", state.msg_attr.extension,
-                      MAC_EXP_ARG_ATTR, "recipient_delimiter",
-                      *var_rcpt_delim ? var_rcpt_delim : 0,
-                      0));
+    expand_attr = htable_create(0);
+    htable_enter(expand_attr, "user", usr_attr.logname);
+    htable_enter(expand_attr, "home", usr_attr.home);
+    htable_enter(expand_attr, "shell", usr_attr.shell);
+    htable_enter(expand_attr, "domain", state.msg_attr.domain);
+    htable_enter(expand_attr, "mailbox", state.msg_attr.local);
+    htable_enter(expand_attr, "recipient", state.msg_attr.recipient);
+    htable_enter(expand_attr, "extension", state.msg_attr.extension);
+    htable_enter(expand_attr, "recipient_delimiter", var_rcpt_delim);
+    return (expand_attr);
 }
index 9ac2489df32a69279e5bb3146f77ffeb883d7a07..da51c7dddd48f4ad3c6495448bbfbea3eaecaf2a 100644 (file)
@@ -129,7 +129,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
        mailbox = concatenate(usr_attr.home, "/", var_home_mailbox, (char *) 0);
     } else {
        spool_dir = var_mail_spool_dir;
-       mailbox = concatenate(spool_dir, "/", state.msg_attr.local, (char *) 0);
+       mailbox = concatenate(spool_dir, "/", state.msg_attr.user, (char *) 0);
     }
 
     /*
@@ -241,7 +241,7 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      * 
      * Don't come here more than once, whether or not the recipient exists.
      */
-    if (been_here(state.dup_filter, "mailbox %s", state.msg_attr.local))
+    if (been_here(state.dup_filter, "mailbox %s", state.msg_attr.user))
        return (YES);
 
     /*
@@ -256,7 +256,7 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
     /*
      * Skip delivery when this recipient does not exist.
      */
-    if ((mbox_pwd = mypwnam(state.msg_attr.local)) == 0)
+    if ((mbox_pwd = mypwnam(state.msg_attr.user)) == 0)
        return (NO);
 
     /*
index 36452618f3dac053ac6b489b5c9c8e9c3eb40313..9680f2f8cdb810d63c6ccb712c3dc28386830018 100644 (file)
@@ -105,35 +105,23 @@ static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr)
      * \user is special: it means don't do any alias or forward expansion.
      */
     if (state.msg_attr.recipient[0] == '\\') {
-       state.msg_attr.recipient++, state.msg_attr.local++;
-       if (*var_rcpt_delim)
-           state.msg_attr.extension =
-               split_addr(state.msg_attr.local, *var_rcpt_delim);
+       state.msg_attr.recipient++, state.msg_attr.local++, state.msg_attr.user++;
        if (deliver_mailbox(state, usr_attr, &status) == 0)
            status = deliver_unknown(state, usr_attr);
        return (status);
     }
 
     /*
-     * Otherwise, alias expansion has highest precedence.
+     * Otherwise, alias expansion has highest precedence. First look up the
+     * full localpart, then the bare user.
      */
-    if (deliver_alias(state, usr_attr, &status))
-       return (status);
-
-    /*
-     * Don't apply the recipient delimiter to reserved addresses. After
-     * stripping the recipient extension, try aliases again.
-     */
-    if (*var_rcpt_delim)
-       state.msg_attr.extension =
-           split_addr(state.msg_attr.local, *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.recipient);
-       state.msg_attr.extension = 0;
-    }
-    if (state.msg_attr.extension && deliver_alias(state, usr_attr, &status))
+    state.msg_attr.unmatched = 0;
+    if (deliver_alias(state, usr_attr, state.msg_attr.local, &status))
        return (status);
+    state.msg_attr.unmatched = state.msg_attr.extension;
+    if (state.msg_attr.extension != 0)
+       if (deliver_alias(state, usr_attr, state.msg_attr.user, &status))
+           return (status);
 
     /*
      * Special case for mail locally forwarded or aliased to a different
@@ -202,11 +190,26 @@ int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
     if (state.msg_attr.delivered == 0)
        state.msg_attr.delivered = state.msg_attr.recipient;
     state.msg_attr.local = mystrdup(state.msg_attr.recipient);
-    if (split_at_right(state.msg_attr.local, '@') == 0)
-       msg_warn("no @ in recipient address: %s", state.msg_attr.local);
     lowercase(state.msg_attr.local);
+    if ((state.msg_attr.domain = split_at_right(state.msg_attr.local, '@')) == 0)
+       msg_warn("no @ in recipient address: %s", state.msg_attr.local);
     state.msg_attr.features = feature_control(state.msg_attr.local);
-    state.msg_attr.extension = 0;
+
+    /*
+     * Address extension management.
+     */
+    state.msg_attr.user = mystrdup(state.msg_attr.local);
+    if (*var_rcpt_delim) {
+       state.msg_attr.extension =
+           split_addr(state.msg_attr.local, *var_rcpt_delim);
+       if (strchr(state.msg_attr.extension, '/')) {
+           msg_warn("%s: address with illegal extension: %s",
+                    state.msg_attr.queue_id, state.msg_attr.local);
+           state.msg_attr.extension = 0;
+       }
+    } else
+       state.msg_attr.extension = 0;
+    state.msg_attr.unmatched = state.msg_attr.extension;
 
     /*
      * Run the recipient through the delivery switch.
index 04ce7405da1b2987b0db932187b2d9dbb9fd0aab..2067c4766e0f602dc3cc0dc8fb43935a5da05a2e 100644 (file)
@@ -114,24 +114,22 @@ int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
     tok822_resolve(addr, &reply);
     state.msg_attr.recipient = STR(reply.recipient);
 
-#if 0
     /*
      * Splice in the optional unmatched address extension.
      */
-    if (state.msg_attr.extension) {
+    if (state.msg_attr.unmatched) {
        if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) {
            VSTRING_ADDCH(reply.recipient, *var_rcpt_delim);
-           vstring_strcat(reply.recipient, state.msg_attr.extension);
+           vstring_strcat(reply.recipient, state.msg_attr.unmatched);
        } else {
-           ext_len = strlen(state.msg_attr.extension);
+           ext_len = strlen(state.msg_attr.unmatched);
            VSTRING_SPACE(reply.recipient, ext_len + 2);
            memmove(ratsign + ext_len + 1, ratsign, strlen(ratsign) + 1);
            *ratsign = *var_rcpt_delim;
-           memcpy(ratsign + 1, state.msg_attr.extension, ext_len);
+           memcpy(ratsign + 1, state.msg_attr.unmatched, ext_len);
            VSTRING_SKIP(reply.recipient);
        }
     }
-#endif
 
     /*
      * Delivery to a local or non-local address. For a while there was some
index ef7e37e4e9288216bf4191bfa09f188b3435101f..33ae8d1687ba425754b3dcc3ee6c7bc4440656e8 100644 (file)
@@ -156,6 +156,8 @@ HP-UX.A.09.*)       SYSTYPE=HPUX9
                fi
                ;;
 HP-UX.B.10.*)  SYSTYPE=HPUX10
+               CCARGS="$CCARGS `nm /usr/lib/libc.a 2>/dev/null |
+                   (grep usleep >/dev/null || echo '-Dusleep=doze')`"
                if [ -f /usr/lib/libdb.a ]; then
                    CCARGS="$CCARGS -DHAS_DB"
                    SYSLIBS=-ldb
index dca195cb85947391dcc6d35bc8bf715b1b5ccbaf..bfa8abb164a2170cce0c845ffcb69cba0fa0e02f 100644 (file)
@@ -43,7 +43,8 @@ The \fBforward_path\fR parameter is subject to interpolation of
 \fB$user\fR (recipient username), \fB$home\fR (recipient home
 directory), \fB$shell\fR (recipient shell), \fB$recipient\fR
 (complete recipient address), \fB$extension\fR (recipient address
-extension), \fB$domain\fR (recipient domain) and
+extension), \fB$domain\fR (recipient domain), \fBmailbox\fR
+(entire recipient address localpart) and
 \fB$recipient_delimiter.\fR The forms \fI${name?value}\fR and
 \fI${name:value}\fR expand conditionally to \fIvalue\fR when
 \fI$name\fR is (is not) defined.
@@ -106,7 +107,8 @@ The command is subject to interpolation of \fB$user\fR (recipient
 username), \fB$home\fR (recipient home directory), \fB$shell\fR
 (recipient shell), \fB$recipient\fR (complete recipient address),
 \fB$extension\fR (recipient address extension), \fB$domain\fR
-(recipient domain) and \fB$recipient_delimiter.\fR The forms
+(recipient domain), \fBmailbox\fR (entire recipient address
+localpart) and \fB$recipient_delimiter.\fR The forms
 \fI${name?value}\fR and \fI${name:value}\fR expand conditionally to
 \fIvalue\fR when \fI$name\fR is (is not) defined. In the result
 of \fIname\fR expansion, characters that have special meaning to
@@ -263,10 +265,8 @@ a configuration change.
 .IP \fBalias_maps\fR
 List of alias databases.
 .IP \fBforward_path\fR
-Search list for .forward files.  The following macros are recognized:
-\fB$home\fR (home directory), \fB$user\fR (login name),
-\fB$extension\fR (address extension), \fB$recipient_delimiter\fR
-(address extension delimiter).
+Search list for .forward files.  The names are subject to \fI$name\fR
+expansion.
 .IP \fBlocal_command_shell\fR
 Shell to use for external command execution (for example,
 /some/where/smrsh -c).
@@ -289,8 +289,7 @@ Pathname of a mailbox relative to a user's home directory.
 Specify a path ending in \fB/\fR for maildir-style delivery.
 .IP \fBluser_relay\fR
 Destination (\fI@domain\fR or \fIaddress\fR) for non-existent users.
-The \fIaddress\fR can be any destination that is valid in an alias
-file.
+The \fIaddress\fR is subjected to \fI$name\fR expansion.
 .IP \fBmail_spool_directory\fR
 Directory with UNIX-style mailboxes. The default pathname is system
 dependent.
index b608720a2e1b197f61b6f9d1232cc252d70dfb77..44875dc5dcb9e2bf6e8d95437be12d3b80a033dc 100644 (file)
@@ -22,6 +22,7 @@ $(PROG): $(OBJS) $(LIBS)
        $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
 
 ../conf/main.cf.default: $(PROG) Makefile
+       rm -f $@
        ./$(PROG) -d |egrep -v '^(myhostname|mydomain|mynetworks) ' >$@
 
 Makefile: Makefile.in
index 426663d9630933f53b4ee49f0b2f7167ab1c47ae..d25e29da2a69ff0b5ccdda4feda0ed5ed0d3f84a 100644 (file)
@@ -368,7 +368,6 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
     va_start(ap, format);
     vstring_vsprintf(error_text, format, ap);
     va_end(ap);
-    printable(STR(error_text), ' ');
 
     /*
      * Validate the response, that is, the response must begin with a
@@ -382,13 +381,24 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
        vstring_strcpy(error_text, "450 Service unavailable");
     }
 
+    /*
+     * Give everyone involved a clue.
+     */
+    if (state->sender) {
+       vstring_sprintf_append(error_text, " (from=<%s>", state->sender);
+       if (state->recipient)
+           vstring_sprintf_append(error_text, " to=<%s>", state->recipient);
+       VSTRING_ADDCH(error_text, ')');
+    }
+    printable(STR(error_text), ' ');
+
     /*
      * Log what is happening. When the sysadmin discards policy violation
      * postmaster notices, this may be the only trace left that service was
      * rejected. Print the request, client name/address, and response.
      */
-    msg_info("reject: %s from %s[%s]: %s", state->where, state->name,
-            state->addr, STR(error_text));
+    msg_info("%s: reject: %s from %s[%s]: %s", state->queue_id, state->where,
+            state->name, state->addr, STR(error_text));
 
     return (SMTPD_CHECK_REJECT);
 }
@@ -1356,6 +1366,7 @@ char   *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
     char  **cpp;
     char   *name;
     int     status;
+    char   *saved_recipient = state->recipient;
 
     /*
      * Initialize.
@@ -1365,8 +1376,10 @@ char   *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
        return (0);
 
     /*
-     * Apply restrictions in the order as specified.
+     * Apply restrictions in the order as specified. Minor kluge so that we
+     * can delegate work to the generic routine.
      */
+    state->recipient = mystrdup(recipient);
     for (cpp = rcpt_restrctions->argv; (name = *cpp) != 0; cpp++) {
        if (strchr(name, ':') != 0) {
            status = check_mail_access(state, name, recipient);
@@ -1387,6 +1400,8 @@ char   *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
        if (status != 0)
            break;
     }
+    myfree(state->recipient);
+    state->recipient = saved_recipient;
     return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
 }
 
diff --git a/postfix/util/hattr.c b/postfix/util/hattr.c
new file mode 100644 (file)
index 0000000..70cd423
--- /dev/null
@@ -0,0 +1,89 @@
+/* mac_expand_update_va - update engine */
+
+static MAC_EXP *mac_expand_update_va(MAC_EXP *mc, int key, va_list ap)
+{
+    HTABLE_INFO **ht_info;
+    HTABLE_INFO **ht;
+    HTABLE *table;
+    char   *name;
+    char   *value;
+
+#define HTABLE_CLOBBER(t, n, v) do { \
+       HTABLE_INFO *_ht; \
+       if ((_ht = htable_locate(t, n)) != 0) \
+           _ht->value = v; \
+       else \
+           htable_enter(t, n, v); \
+    } while(0);
+
+    /*
+     * Optionally create expansion context.
+     */
+    if (mc == 0) {
+       mc = (MAC_EXP *) mymalloc(sizeof(*mc));
+       mc->table = htable_create(0);
+       mc->result = 0;
+       mc->flags = 0;
+       mc->filter = 0;
+       mc->clobber = '_';
+       mc->level = 0;
+    }
+
+    /*
+     * Stash away the attributes.
+     */
+    for ( /* void */ ; key != 0; key = va_arg(ap, int)) {
+       switch (key) {
+       case MAC_EXP_ARG_ATTR:
+           name = va_arg(ap, char *);
+           value = va_arg(ap, char *);
+           HTABLE_CLOBBER(mc->table, name, value);
+           break;
+       case MAC_EXP_ARG_TABLE:
+           table = va_arg(ap, HTABLE *);
+           ht_info = htable_list(table);
+           for (ht = ht_info; *ht; ht++)
+               HTABLE_CLOBBER(mc->table, ht[0]->key, ht[0]->value);
+           myfree((char *) ht_info);
+           break;
+       case MAC_EXP_ARG_FILTER:
+           mc->filter = va_arg(ap, char *);
+           break;
+       case MAC_EXP_ARG_CLOBBER:
+           mc->clobber = va_arg(ap, int);
+           break;
+       }
+    }
+    return (mc);
+}
+
+/* mac_expand_update - update or create macro expansion context */
+
+MAC_EXP *mac_expand_update(MAC_EXP *mc, int key,...)
+{
+    va_list ap;
+
+    va_start(ap, key);
+    mc = mac_expand_update(mc, key, ap);
+    va_end(ap);
+    return (mc);
+}
+
+/* .IP key
+/*     The attribute information is specified as a null-terminated list.
+/*     Attributes are defined left to right; only the last definition
+/*     of an attribute is remembered.
+/*     The following keys are understood (types of arguments indicated
+/*     in parentheses):
+/* .RS
+/* .IP "MAC_EXP_ARG_ATTR (char *, char *)"
+/*     The next two arguments specify an attribute name and its attribute
+/*     string value.  Specify a null string value for an attribute that is
+/*     known but unset. Attribute string values are not copied.
+/* .IP "MAC_EXP_ARG_TABLE (HTABLE *)"
+/*     The next argument is a hash table with attribute names and values.
+/*     Specify a null string value for an attribute that is known but unset. 
+/*     Attribute string values are not copied.
+/* .RE
+/* .IP MAC_EXP_ARG_END
+/*     A manifest constant that indicates the end of the argument list.
index 299d0c614a546ac944ed1cac82de4e669d452853..29ad1236bdbdb1988d526f9691b2f9c738a82e7d 100644 (file)
 /*
 /*     htable_delete() removes one entry that was stored under the given key.
 /*     If the free_fn argument is not a null pointer, the corresponding
-/*     function is called with as argument the value that was stored under
+/*     function is called with as argument the non-zero value stored under
 /*     the key.
 /*
 /*     htable_free() destroys a hash table, including contents. If the free_fn
 /*     argument is not a null pointer, the corresponding function is called
-/*     for each table entry, with as argument the value that was stored
+/*     for each table entry, with as argument the non-zero value stored
 /*     with the entry.
 /*
 /*     htable_walk() invokes the action function for each table entry, with
@@ -261,7 +261,7 @@ void    htable_delete(HTABLE *table, const char *key, void (*free_fn) (char *))
                    *h = ht->next;
                table->used--;
                myfree(ht->key);
-               if (free_fn)
+               if (free_fn && ht->value)
                    (*free_fn) (ht->value);
                myfree((char *) ht);
                return;
@@ -285,7 +285,7 @@ void    htable_free(HTABLE *table, void (*free_fn) (char *))
            for (ht = *h++; ht; ht = next) {
                next = ht->next;
                myfree(ht->key);
-               if (free_fn)
+               if (free_fn && ht->value)
                    (*free_fn) (ht->value);
                myfree((char *) ht);
            }
index 6ee96b07a60efd9e8120ec3d8727ea7f01db27ba..23f0756ab422a9f6403f3f4ce5410756c8cddf90 100644 (file)
@@ -6,54 +6,37 @@
 /* SYNOPSIS
 /*     #include <mac_expand.h>
 /*
-/*     MAC_EXP *mac_exp_update(handle, key, ...)
-/*     MAC_EXP *handle;
-/*     int     key;
-/*
-/*     int     mac_expand_use(handle, result, pattern, flags)
-/*     MAC_EXP *handle;
-/*     VSTRING *result;
-/*     const char *pattern;
-/*     int     flags;
-/*
-/*     void    mac_expand_free(handle)
-/*     MAC_EXP *handle;
-/*
 /*     int     mac_expand(result, pattern, flags, key, ...)
 /*     VSTRING *result;
 /*     const char *pattern;
 /*     int     flags;
 /*     int     key;
 /* DESCRIPTION
-/*     This module maintains a private attribute-value list and implements
-/*     the following expansions:
+/*     This module implements parameter-less macro expansions, both
+/*     conditional and unconditional, and both recursive and non-recursive.
+/*     The algorithm can search multiple user-specified symbol tables.
+/*     In the text below, an attribute is "defined" when its value is a
+/*     string of non-zero length. In all other cases the attribute is
+/*     considered "undefined".
+/*
+/*     The following expansions are implemented:
 /* .IP "$name, ${name}, $(name)"
-/*     The result is the value of the named attribute. Optionally, the
-/*     result is subjected to further expansions.
+/*     Unconditional expansion. If the named attribute is defined, the
+/*     expansion is the value of the named attribute,  optionally subjected
+/*     to further $name expansions.  Otherwise, the expansion is empty.
 /* .IP "${name?text}, $(name?text)"
-/*     If the named attribute is defined, the result is the given text,
-/*     after another iteration of $name expansion. Otherwise, the result is
-/*     empty.
+/*     Conditional expansion. If the named attribute is defined, the
+/*     expansion is the given text, subjected to another iteration of
+/*     $name expansion.  Otherwise, the expansion is empty.
 /* .IP "${name:text}, $(name:text)"
-/*     If the named attribute is undefined, the result is the given text,
-/*     after another iteration of $name expansion. Otherwise, the result is
-/*     empty.
+/*     Conditional expansion. If the named attribute is undefined, the
+/*     the expansion is the given text, after another iteration of $name
+/*     expansion.  Otherwise, the expansion is empty.
 /* .PP
-/*     max_expand_update() updates an existing macro expansion context
-/*     or instantiates a new one when given a null handle.  The result
-/*     is a handle that can be used by other mac_expand_xxx() routines.
-/*
-/*     mac_expand_use() uses a macro expansion context to replace $name etc.
-/*     instances in \fBpattern\fR and stores the result into \fBresult\fR.
-/*
-/*     mac_expand_free() destroys a macro expansion context.
-/*
-/*     mac_expand() is a convenience routine that combines all of the
-/*     above in one function call.
+/*     mac_expand() replaces $name etc. instances in \fBpattern\fR
+/*     and stores the result into \fBresult\fR.
 /*
 /*     Arguments:
-/* .IP mc
-/*     Macro expansion context created or update with mac_expand_update().
 /* .IP result
 /*     Storage for the result of expansion. The result is truncated
 /*     upon entry.
 /*     The constant MAC_EXP_FLAG_NONE specifies a manifest null value.
 /* .IP key
 /*     The attribute information is specified as a null-terminated list.
-/*     Attributes are defined left to right; only the last definition
-/*     of an attribute is remembered.
+/*     Attributes may appear multiple times; the right-most definition
+/*     of an attribute determines the result of attribute lookup.
+/* .sp
 /*     The following keys are understood (types of arguments indicated
 /*     in parentheses):
 /* .RS
 /* .IP "MAC_EXP_ARG_ATTR (char *, char *)"
 /*     The next two arguments specify an attribute name and its attribute
-/*     string value.  Specify a null string value for an attribute that is
-/*     known but unset. Attribute string values are not copied.
+/*     string value.  Specify a null pointer or empty string for an
+/*     attribute value that is unset. Attribute keys and string values
+/*     are copied.
 /* .IP "MAC_EXP_ARG_TABLE (HTABLE *)"
 /*     The next argument is a hash table with attribute names and values.
-/*     Specify a null string value for an attribute that is known but unset. 
-/*     Attribute string values are not copied.
-/* .IP "MAC_EXP_ARG_FILTER (char *)"
-/*     The next argument specifies a null-terminated list of characters
-/*     that are allowed to appear in $name expansions. By default, illegal
-/*     characters are replaced by underscore. Only the last specified
-/*     filter takes effect. Specify a null pointer to disable filtering.
-/* .IP "MAC_EXP_ARG_CLOBBER (int)"
-/*     Character value to be used when the result of expansion is not
-/*     allowed according to the MAC_EXP_ARG_FILTER argument. Only the
-/*     last specified replacement value takes effect.
+/*     Specify a null pointer or empty string for an attribute value that
+/*     is unset. Hash tables are not copied.
+/* .IP "MAC_EXP_ARG_RECORD (HTABLE *)"
+/*     Record in the specified table how many times an attribute was
+/*     referenced.
 /* .RE
 /* .IP MAC_EXP_ARG_END
 /*     A manifest constant that indicates the end of the argument list.
 /*     macro nesting.
 /*
 /*     The result value is the binary OR of zero or more of the following:
+/* .IP MAC_EXP_FLAG_ERROR
+/*     A syntax error was foud in the \fBpattern\fR, or some macro had
+/*     an unreasonable nesting depth.
 /* .IP MAC_EXP_FLAG_UNDEF
-/*     The pattern contains a reference to an unknown parameter or to
-/*     a parameter whose value is not defined.
-/*     A zero-length string was used as replacement.
+/*     The pattern contains a reference to an undefined attribute.
 /* SEE ALSO
 /*     mac_parse(3) locate macro references in string.
 /* LICENSE
 /* System library. */
 
 #include <sys_defs.h>
-#include <setjmp.h>
 #include <ctype.h>
 #include <string.h>
 
 #include <mac_expand.h>
 
  /*
-  * Little helper structure.
+  * Little helper structure. Name-value pairs given as explicit arguments are
+  * stored into private hash tables. Hash tables provided by the caller are
+  * simply referenced. For now we do only hash tables. The structure can be
+  * generalized when needed.
   */
+struct table_info {
+    int     status;                    /* who owns this table */
+    HTABLE *table;                     /* table reference */
+};
+
+#define MAC_EXP_STAT_UNUSED    0       /* this slot is unused */
+#define MAC_EXP_STAT_PRIVATE   1       /* we own this table */
+#define MAC_EXP_STAT_EXTERN    2       /* caller owns this table */
+
+#define MAC_EXP_MIN_LEN                2       /* min number of table slots */
+
 struct MAC_EXP {
-    HTABLE *table;                     /* private symbol table */
     VSTRING *result;                   /* result buffer */
     const char *filter;                        /* safe character list */
     int     clobber;                   /* safe replacement */
     int     flags;                     /* findings, features */
     int     level;                     /* nesting level */
-    jmp_buf jbuf;                      /* escape */
+    HTABLE *record;                    /* record of substitutions */
+    int     len;                       /* table list length */
+    int     last;                      /* last element used */
+    struct table_info table_info[MAC_EXP_MIN_LEN];
 };
 
 /* mac_expand_callback - callback for mac_parse */
@@ -154,10 +149,15 @@ static void mac_expand_callback(int type, VSTRING *buf, char *ptr)
     char   *text;
     char   *cp;
     int     ch;
+    int     n;
 
+    /*
+     * Sanity check.
+     */
     if (mc->level++ > 100) {
        msg_warn("unreasonable macro call nesting: \"%s\"", vstring_str(buf));
-       longjmp(mc->jbuf, 1);
+       mc->flags |= MAC_EXP_FLAG_ERROR;
+       return;
     }
 
     /*
@@ -177,15 +177,21 @@ static void mac_expand_callback(int type, VSTRING *buf, char *ptr)
            }
            if (!ISALNUM(ch) && ch != '_') {
                msg_warn("macro name syntax error: \"%s\"", vstring_str(buf));
-               longjmp(mc->jbuf, 1);
+               mc->flags |= MAC_EXP_FLAG_ERROR;
+               return;
            }
        }
 
        /*
         * Look up the named parameter.
         */
-       text = (ht = htable_locate(mc->table, vstring_str(buf))) == 0 ?
-           0 : ht->value;
+       for (text = 0, n = mc->last; n >= 0; n--) {
+           ht = htable_locate(mc->table_info[n].table, vstring_str(buf));
+           if (ht != 0) {
+               text = ht->value;
+               break;
+           }
+       }
 
        /*
         * Perform the requested substitution.
@@ -207,7 +213,7 @@ static void mac_expand_callback(int type, VSTRING *buf, char *ptr)
            if (mc->filter) {
                vstring_strcpy(buf, text);
                text = vstring_str(buf);
-               for (cp = text; (cp += strspn(cp, mc->filter))[0];)
+               for (cp = text; (cp += strspn(cp, mc->filter))[0]; /* void */ )
                    *cp++ = mc->clobber;
            }
            if (mc->flags & MAC_EXP_FLAG_RECURSE)
@@ -216,6 +222,15 @@ static void mac_expand_callback(int type, VSTRING *buf, char *ptr)
                vstring_strcat(mc->result, text);
            break;
        }
+
+       /*
+        * Record keeping...
+        */
+       if (mc->record) {
+           if ((ht = htable_locate(mc->record, vstring_str(buf))) == 0)
+               ht = htable_enter(mc->record, vstring_str(buf), (char *) 0);
+           ht->value++;
+       }
     }
 
     /*
@@ -236,53 +251,68 @@ static void mac_expand_callback(int type, VSTRING *buf, char *ptr)
     mc->level--;
 }
 
-/* mac_expand_update_va - update engine */
+/* mac_expand_addtable - add table to expansion context */
 
-static MAC_EXP *mac_expand_update_va(MAC_EXP *mc, int key, va_list ap)
+static MAC_EXP *mac_expand_addtable(MAC_EXP *mc, HTABLE *table, int status)
 {
-    HTABLE_INFO **ht_info;
-    HTABLE_INFO **ht;
-    HTABLE *table;
+    mc->last += 1;
+    if (mc->last >= mc->len) {
+       mc->len *= 2;
+       mc = (MAC_EXP *) myrealloc((char *) mc, sizeof(*mc) + sizeof(mc->table_info[0]) * (mc->len - MAC_EXP_MIN_LEN));
+    }
+    mc->table_info[mc->last].table = table;
+    mc->table_info[mc->last].status = status;
+    return (mc);
+}
+
+/* mac_expand - expand $name instances */
+
+int     mac_expand(VSTRING *result, const char *pattern, int flags, int key,...)
+{
+    MAC_EXP *mc;
+    va_list ap;
     char   *name;
     char   *value;
-
-#define HTABLE_CLOBBER(t, n, v) do { \
-       HTABLE_INFO *_ht; \
-       if ((_ht = htable_locate(t, n)) != 0) \
-           _ht->value = v; \
-       else \
-           htable_enter(t, n, v); \
-    } while(0);
+    HTABLE *table;
+    HTABLE_INFO *ht;
+    int     status;
 
     /*
-     * Optionally create expansion context.
+     * Initialize.
      */
-    if (mc == 0) {
-       mc = (MAC_EXP *) mymalloc(sizeof(*mc));
-       mc->table = htable_create(0);
-       mc->result = 0;
-       mc->flags = 0;
-       mc->filter = 0;
-       mc->clobber = '_';
-       mc->level = 0;
-    }
+    mc = (MAC_EXP *) mymalloc(sizeof(*mc));
+    mc->result = result;
+    mc->flags = (flags & MAC_EXP_FLAG_INMASK);
+    mc->filter = 0;
+    mc->clobber = '_';
+    mc->record = 0;
+    mc->level = 0;
+    mc->len = MAC_EXP_MIN_LEN;
+    mc->last = -1;
 
     /*
      * Stash away the attributes.
      */
-    for ( /* void */ ; key != 0; key = va_arg(ap, int)) {
+    for (va_start(ap, key); key != 0; key = va_arg(ap, int)) {
        switch (key) {
        case MAC_EXP_ARG_ATTR:
            name = va_arg(ap, char *);
            value = va_arg(ap, char *);
-           HTABLE_CLOBBER(mc->table, name, value);
+           if (mc->last < 0
+               || mc->table_info[mc->last].status != MAC_EXP_STAT_PRIVATE) {
+               table = htable_create(0);
+               mc = mac_expand_addtable(mc, table, MAC_EXP_STAT_PRIVATE);
+           } else
+               table = mc->table_info[mc->last].table;
+           if ((ht = htable_locate(table, name)) == 0)
+               ht = htable_enter(table, name, (char *) 0);
+           if (ht->value != 0)
+               myfree(ht->value);
+           ht->value = (value ? mystrdup(value) : 0);
            break;
        case MAC_EXP_ARG_TABLE:
            table = va_arg(ap, HTABLE *);
-           ht_info = htable_list(table);
-           for (ht = ht_info; *ht; ht++)
-               HTABLE_CLOBBER(mc->table, ht[0]->key, ht[0]->value);
-           myfree((char *) ht_info);
+           mc = mac_expand_addtable(mc, table, MAC_EXP_STAT_EXTERN);
            break;
        case MAC_EXP_ARG_FILTER:
            mc->filter = va_arg(ap, char *);
@@ -290,69 +320,31 @@ static MAC_EXP *mac_expand_update_va(MAC_EXP *mc, int key, va_list ap)
        case MAC_EXP_ARG_CLOBBER:
            mc->clobber = va_arg(ap, int);
            break;
+       case MAC_EXP_ARG_RECORD:
+           mc->record = va_arg(ap, HTABLE *);
+           break;
        }
     }
-    return (mc);
-}
-
-/* mac_expand_update - update or create macro expansion context */
-
-MAC_EXP *mac_expand_update(MAC_EXP *mc, int key,...)
-{
-    va_list ap;
-
-    va_start(ap, key);
-    mc = mac_expand_update(mc, key, ap);
-    va_end(ap);
-    return (mc);
-}
-
-/* mac_expand_use - string expansion */
-
-int     mac_expand_use(MAC_EXP *mc, VSTRING *result, const char *pattern, int flags)
-{
-    VSTRING_RESET(result);
-    mc->result = result;
-    mc->level = 0;
-    mc->flags = flags;
-    if (setjmp(mc->jbuf) == 0)
-       mac_parse(pattern, mac_expand_callback, (char *) mc);
-    VSTRING_TERMINATE(result);
-    return (mc->flags & MAC_EXP_FLAG_UNDEF);
-}
-
-/* mac_expand_free - destroy macro expansion context */
-
-void    mac_expand_free(MAC_EXP *mc)
-{
-    htable_free(mc->table, (void (*) (char *)) 0);
-    myfree((char *) mc);
-}
-
-/* mac_expand - expand $name instances */
-
-int     mac_expand(VSTRING *result, const char *pattern, int flags, int key,...)
-{
-    MAC_EXP *mc = 0;
-    va_list ap;
-    int     status;
-
-    /*
-     * Stash away the attributes.
-     */
-    va_start(ap, key);
-    mc = mac_expand_update_va(mc, key, ap);
     va_end(ap);
 
     /*
      * Do the substitutions.
      */
-    status = mac_expand_use(mc, result, pattern, flags);
+    VSTRING_RESET(result);
+    mac_parse(pattern, mac_expand_callback, (char *) mc);
+    VSTRING_TERMINATE(result);
+    status = (mc->flags & MAC_EXP_FLAG_OUTMASK);
 
     /*
      * Clean up.
      */
-    mac_expand_free(mc);
+    while (mc->last >= 0) {
+       if (mc->table_info[mc->last].status == MAC_EXP_STAT_PRIVATE)
+           htable_free(mc->table_info[mc->last].table, myfree);
+       mc->last--;
+    }
+    myfree((char *) mc);
+
     return (status);
 }
 
@@ -365,12 +357,6 @@ int     mac_expand(VSTRING *result, const char *pattern, int flags, int key,...)
 #include <vstream.h>
 #include <vstring_vstream.h>
 
-static void nfree(char *ptr)
-{
-    if (ptr)
-       myfree(ptr);
-}
-
 int     main(int unused_argc, char **unused_argv)
 {
     VSTRING *buf = vstring_alloc(100);
@@ -411,7 +397,7 @@ int     main(int unused_argc, char **unused_argv)
            vstream_printf("stat=%d result=%s\n", stat, vstring_str(result));
            vstream_fflush(VSTREAM_OUT);
        }
-       htable_free(table, nfree);
+       htable_free(table, myfree);
        vstream_printf("\n");
     }
 
index 9a3cce818a0ed8112c95e0df7f99c283d5d21eed..cf61b686efc588f9eec33284fca4c3f7553d89da 100644 (file)
@@ -24,12 +24,17 @@ typedef struct MAC_EXP MAC_EXP;
 #define MAC_EXP_FLAG_NONE      (0)
 #define MAC_EXP_FLAG_UNDEF     (1<<0)
 #define MAC_EXP_FLAG_RECURSE   (1<<1)
+#define MAC_EXP_FLAG_ERROR     (1<<2)
+
+#define MAC_EXP_FLAG_INMASK    MAC_EXP_FLAG_RECURSE
+#define MAC_EXP_FLAG_OUTMASK   (MAC_EXP_FLAG_UNDEF | MAC_EXP_FLAG_ERROR)
 
 #define MAC_EXP_ARG_END                0
 #define MAC_EXP_ARG_ATTR       1
 #define MAC_EXP_ARG_TABLE      2
 #define MAC_EXP_ARG_FILTER     3
 #define MAC_EXP_ARG_CLOBBER    4
+#define MAC_EXP_ARG_RECORD     5
 
 extern MAC_EXP *mac_expand_update(MAC_EXP *, int,...);
 extern int mac_expand_use(MAC_EXP *, VSTRING *, const char *, int);
index 7fb2909287cb3e22bc58b49c6438558c1818bbf9..0fb6cea984cf394f1ec0fb4d01d08bca0d478492 100644 (file)
@@ -4,7 +4,7 @@ stat=0 result=
 stat=1 result=name 2 undefined, |name1-value||
 stat=1 result=|name1-value||
 stat=0 result=name1-value
-stat=0 result=
+stat=4 result=
 
 stat=0 result=
 stat=1 result=name 1 undefined, ||name2-value|