]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-19990508
authorWietse Venema <wietse@porcupine.org>
Sat, 8 May 1999 05:00:00 +0000 (00:00 -0500)
committerWietse Venema <wietse@porcupine.org>
Thu, 17 Jan 2013 03:34:23 +0000 (22:34 -0500)
73 files changed:
postfix/.indent.pro
postfix/DEBUG_README
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/bounce/.indent.pro
postfix/cleanup/.indent.pro
postfix/cleanup/Makefile.in
postfix/cleanup/cleanup.c
postfix/cleanup/cleanup.h
postfix/cleanup/cleanup_envelope.c
postfix/cleanup/cleanup_map11.c
postfix/cleanup/cleanup_map1n.c
postfix/cleanup/cleanup_message.c
postfix/cleanup/cleanup_out_recipient.c
postfix/conf/main.cf
postfix/conf/main.cf.default
postfix/conf/sample-local.cf
postfix/dns/.indent.pro
postfix/error/.indent.pro
postfix/error/Makefile.in
postfix/fsstone/.indent.pro
postfix/global/.indent.pro
postfix/global/Makefile.in
postfix/global/ext_prop.c [new file with mode: 0644]
postfix/global/ext_prop.h [new file with mode: 0644]
postfix/global/mail_addr_map.c
postfix/global/mail_addr_map.h
postfix/global/mail_params.h
postfix/global/mail_version.h
postfix/html/local.8.html
postfix/html/rewrite.html
postfix/local/.indent.pro
postfix/local/Makefile.in
postfix/local/command.c
postfix/local/dotforward.c
postfix/local/include.c
postfix/local/local.c
postfix/local/local.h
postfix/local/local_expand.c
postfix/local/recipient.c
postfix/local/unknown.c
postfix/man/man8/local.8
postfix/master/.indent.pro
postfix/pickup/.indent.pro
postfix/pipe/.indent.pro
postfix/pipe/pipe.c
postfix/postalias/.indent.pro
postfix/postcat/.indent.pro
postfix/postconf/.indent.pro
postfix/postdrop/.indent.pro
postfix/postfix/.indent.pro
postfix/postkick/.indent.pro
postfix/postlock/.indent.pro
postfix/postlog/.indent.pro
postfix/postmap/.indent.pro
postfix/postsuper/.indent.pro
postfix/qmgr/.indent.pro
postfix/sendmail/.indent.pro
postfix/showq/.indent.pro
postfix/smtp/.indent.pro
postfix/smtpd/.indent.pro
postfix/smtpstone/.indent.pro
postfix/trivial-rewrite/.indent.pro
postfix/util/.indent.pro
postfix/util/Makefile.in
postfix/util/dict.c
postfix/util/dict_pcre.c
postfix/util/dict_regexp.c
postfix/util/mac_expand.c
postfix/util/mac_expand.h
postfix/util/mac_expand.ref
postfix/util/mac_parse.c
postfix/util/mac_parse.h

index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index 1ed6e6bfc92cf4f126555e168804d150231a4aa1..be66f3ad27027a274f729ac8c0c46d4cc692e8e2 100644 (file)
@@ -19,9 +19,9 @@ from or to the loopback interface:
 3 - Making daemon programs more verbose
 =======================================
 
-Append one or more -v options to commands in /etc/postfix/master.cf
-and type "postfix reload". This will cause a lot of activity to be
-logged to the syslog daemon.
+Append one or more -v options to selected daemon definitions in
+/etc/postfix/master.cf and type "postfix reload". This will cause
+a lot of activity to be logged to the syslog daemon.
 
 4 - Tracing a Postfix daemon process
 ====================================
@@ -34,9 +34,12 @@ call tracer. For example:
        # truss -p process-id
        # ktrace -p process-id
 
-This can give valuable information about what a process is attempting
-to do. This is as much information as you can get without running
-a debugger program, as described in the next section.
+See your system documentation for details.
+
+Tracing a running process can give valuable information about what
+a process is attempting to do. This is as much information as you
+can get without running an interactive debugger program, as described
+in the next section.
 
 5 - Running daemon programs under an interactive debugger
 =========================================================
@@ -53,6 +56,8 @@ that it invokes the debugger of your choice, for example:
          PATH=/usr/bin:/usr/X11R6/bin
          xxgdb $daemon_directory/$process_name $process_id & sleep 5
 
+If you use xxgdb, be sure that gdb is in the command search path.
+
 Export XAUTHORITY so that X access control works, for example:
 
     % setenv XAUTHORITY ~/.Xauthority
index 8c534d4ab341ed20f6a709cf1bdc3c4c906011f6..b2f54c9f6f4c7b6b2be6988e9d9a6806c2379566 100644 (file)
@@ -2706,13 +2706,45 @@ Apologies for any names omitted.
        ${name:text} expands to text when name is undefined,
        otherwise the result is empty. File: util/mac_expand.c.
 
-       Feature: conditional macro expansion in forward_path and
-       mailbox_command of $user, $home, $shell, $recipient,
-       $extension, $domain, and $recipient_delimiter. Files:
-       local/command.c, local/dotforward.c, local/local_expand.c.
+       Feature: conditional macro expansion of the forward_path and
+       mailbox_command configuration parameters of $user, $home,
+       $shell, $recipient, $extension, $domain, $mailbox and
+       $recipient_delimiter.  Files:  local/command.c,
+       local/dotforward.c, local/local_expand.c.
 
 19990506
 
        Cleanup: eliminated misleading warnings about unknown HELO
        etc. SMTPD restrictions when the HELO etc. information is
        not available. File: smtpd/smtpd_check.c.
+
+19990507
+
+       Feature: all smtpd reject messages now contain the MAIL
+       FROM and RCPT TO addresses, if available.
+
+19990508
+
+       Feature: conditional macro expansion of the luser_relay
+       configuration parameter. It is no longer possible to specify
+       /file/name or "|command" destinations. File: local/unknown.c.
+
+       Cleanup: changed the mac_parse interface so that the
+       application callback routine can return status information.
+       Updated the dict_regexp and dict_pcre modules accordingly.
+
+       Cleanup: changed the mac_expand interface so that the caller
+       provides an attribute lookup routine, instead of having to
+       provide a copy of all attributes upfront. Files:
+       util/mac_expand.c, local/local_expand.c.
+
+       Feature: control over how address extensions are propagated
+       to other addresses. By default, propagation of unmatched
+       address extensions is now restricted to canonical and
+       virtual mappings. Specify "propagate_unmatched_extension
+       = canonical, virtual, alias, forward, include" to restore
+       previous behavior.
+
+       Feature: command_expansion_filter and forward_expansion_filter
+       configuration parameters that control what characters may
+       appear in $name expansions of mailbox_command and forward_path.
index 4511722482e32283ee1fe26fa22c6e209fb9dbe7..3c0413232effa1905ab47f6d598adc07e80e7b66 100644 (file)
@@ -1,13 +1,22 @@
 Incompatible changes with snapshot-19990504:
 ===========================================
 
+- The Postfix local delivery agent no longer automatically propagates
+the address extension to aliases/include/forward addresses.  Specify
+"propagate_unmatched_extensions = canonical, virtual, alias, forward,
+include" to restore the old behavior.
+
+- The luser_relay syntax has changed. You can specify one address,
+and it is subjected to $user, etc. expansions. See conf/main.cf.
+
+- The mailbox_command parameter is now subjected to $name expansion
+(see below). This means that you can no longer use shell variables
+in mailbox_command, or that you have to use $$ instead of $.
+
 - File system reorganization: daemon executables are in the libexec
 subdirectory, command executables in the bin subdirectory.  The
-INSTALL instructions now install daemons and commands into separate
-directories.
-
-- The local delivery agent no longer appends address extensions to
-addresses found in aliases, :include: files or .forward files.
+INSTALL instructions now recommend installing daemons and commands
+into separate directories.
 
 Major changes with snapshot-19990504:
 =====================================
@@ -18,15 +27,18 @@ of Solaris workarounds.
 
 - Specify "forward_path = /var/forward/$user" to avoid looking up
 .forward files in user home directories.  The default value is
-$home/.forward$recipient_delimiter$extension,$home/.forward. Initial
-forward_path code by Philip A.  Prindeville, Mirapoint, Inc., USA.
-
-- Conditional macro expansion in forward_path and mailbox_command.
-$name expands to itself. ${name?value} expands to value when $name
-is defined.  ${name:value} expands to value when $name is not
-defined. With ${name?value} and ${name:value}, the value is subject
-to $name expansion. Available macros are: $user, $shell, $home,
-$recipient, $extension, $domain, and $recipient_delimiter.  
+$home/.forward$recipient_delimiter$extension, $home/.forward.
+Initial code by Philip A.  Prindeville, Mirapoint, Inc., USA.
+
+- Conditional $name expansion in forward_path, mailbox_command,
+and luser_relay.  Available names are: $user (bare user name) $shell
+(user login shell), $home (user home directory), $recipient
+(everything to the left of @), $extension (optional address
+extension), $domain (everything to the right of @), and
+$recipient_delimiter.  A simple $name expands as usual.  ${name?value}
+expands to value when $name is defined.  ${name:value} expands to
+value when $name is not defined. With ${name?value} and ${name:value},
+the value is subject to another iteration of $name expansion.
 
 - POSIX regular expression support, enabled by default on 4.4BSD,
 LINUX, HP-UX, and Solaris 2.5 and later. See conf/sample-regexp.cf.
@@ -45,7 +57,8 @@ will be delegated to an external command.
 - Regular expression support for all lookup tables, including access
 control (full mail addresses only), address rewriting (canonical/virtual,
 full mail addresses only) and transport tables (full domain names
-only).  However, regular expressions are not allowed for aliases.
+only).  However, regular expressions are not allowed for aliases,
+because that would open up security exposures.
 
 - Automatic detection of changes to DB or DBM lookup tables.  This
 eliminates the need to run "postfix reload" after each change to
@@ -53,7 +66,7 @@ the SMTP access table, or to the canonical, virtual, transport or
 aliases tables.
 
 - New error mailer. Specify ".domain.name error:domain is undeliverable"
-in the transport table to bounce entire domains.
+in the transport table to bounce mail for entire domains.
 
 - No more Postfix lockups on Solaris (knock on wood). The code no
 longer uses Solaris UNIX-domain sockets, because they are still
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index 63cc3edc6cf3024e49fe8e3096d373239262bd80..2ee78f30ee578189df0aed93f168ae9304ab1e93 100644 (file)
@@ -78,6 +78,7 @@ cleanup.o: ../include/bounce.h
 cleanup.o: ../include/mail_params.h
 cleanup.o: ../include/mail_stream.h
 cleanup.o: ../include/mail_addr.h
+cleanup.o: ../include/ext_prop.h
 cleanup.o: ../include/mail_server.h
 cleanup.o: cleanup.h
 cleanup.o: ../include/argv.h
@@ -98,6 +99,7 @@ cleanup_envelope.o: ../include/cleanup_user.h
 cleanup_envelope.o: ../include/tok822.h
 cleanup_envelope.o: ../include/resolve_clnt.h
 cleanup_envelope.o: ../include/mail_params.h
+cleanup_envelope.o: ../include/ext_prop.h
 cleanup_envelope.o: cleanup.h
 cleanup_envelope.o: ../include/argv.h
 cleanup_envelope.o: ../include/maps.h
@@ -197,6 +199,7 @@ cleanup_message.o: ../include/mail_params.h
 cleanup_message.o: ../include/mail_date.h
 cleanup_message.o: ../include/mail_addr.h
 cleanup_message.o: ../include/is_header.h
+cleanup_message.o: ../include/ext_prop.h
 cleanup_message.o: cleanup.h
 cleanup_message.o: ../include/maps.h
 cleanup_message.o: ../include/dict.h
@@ -225,6 +228,7 @@ cleanup_out_recipient.o: ../include/argv.h
 cleanup_out_recipient.o: ../include/been_here.h
 cleanup_out_recipient.o: ../include/mail_params.h
 cleanup_out_recipient.o: ../include/rec_type.h
+cleanup_out_recipient.o: ../include/ext_prop.h
 cleanup_out_recipient.o: cleanup.h
 cleanup_out_recipient.o: ../include/vstring.h
 cleanup_out_recipient.o: ../include/vbuf.h
index 2127a96d916cb9c9134bf4bcbd12d483780db085..2a66a5f1a8125865a1c0d496ed16153100472f6d 100644 (file)
 #include <mail_params.h>
 #include <mail_stream.h>
 #include <mail_addr.h>
+#include <ext_prop.h>
 
 /* Single-threaded server skeleton. */
 
@@ -172,6 +173,7 @@ char   *var_header_checks;          /* any header checks */
 int     var_dup_filter_limit;          /* recipient dup filter */
 char   *var_empty_addr;                        /* destination of bounced bounces */
 int     var_delay_warn_time;           /* delay that triggers warning */
+char   *var_prop_extension;            /* propagate unmatched extension */
 
  /*
   * Mappings.
@@ -183,6 +185,11 @@ MAPS   *cleanup_header_checks;
 MAPS   *cleanup_virtual_maps;
 ARGV   *cleanup_masq_domains;
 
+ /*
+  * Address extension propagation restrictions.
+  */
+int     cleanup_ext_prop_mask;
+
 /* cleanup_service - process one request to inject a message into the queue */
 
 static void cleanup_service(VSTREAM *src, char *unused_service, char **argv)
@@ -421,6 +428,11 @@ static void post_jail_init(char *unused_name, char **unused_argv)
      */
     if (var_message_limit > 0)
        set_file_limit((off_t) var_message_limit);
+
+    /*
+     * Control how unmatched extensions are propagated.
+     */
+    cleanup_ext_prop_mask = ext_prop_mask(var_prop_extension);
 }
 
 /* main - the main program */
@@ -443,6 +455,7 @@ int     main(int argc, char **argv)
        VAR_EMPTY_ADDR, DEF_EMPTY_ADDR, &var_empty_addr, 1, 0,
        VAR_MASQ_EXCEPTIONS, DEF_MASQ_EXCEPTIONS, &var_masq_exceptions, 0, 0,
        VAR_HEADER_CHECKS, DEF_HEADER_CHECKS, &var_header_checks, 0, 0,
+       VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
        0,
     };
 
index 7523262c6f927e80d9a4fee46362d7d4cd9704b8..69fc0142988eda94f86d3b1202b1810c2760d0f7 100644 (file)
@@ -66,18 +66,15 @@ extern MAPS *cleanup_virtual_maps;
 extern ARGV *cleanup_masq_domains;
 
  /*
-  * Saved queue file name, so the file can be removed in case of a fatal
-  * run-time error.
+  * Restrictions on extension propagation.
   */
-extern char *cleanup_path;
+extern int cleanup_ext_prop_mask;
 
  /*
-  * Tunable parameters.
+  * Saved queue file name, so the file can be removed in case of a fatal
+  * run-time error.
   */
-extern int var_bounce_limit;           /* max bounce message size */
-extern int var_message_limit;          /* max message size */
-extern int var_hopcount_limit;         /* max mailer hop count */
-extern int var_header_limit;           /* max header length */
+extern char *cleanup_path;
 
  /*
   * cleanup_state.c
@@ -128,14 +125,14 @@ extern void cleanup_rewrite_tree(TOK822 *);
  /*
   * cleanup_map11.c
   */
-extern void cleanup_map11_external(VSTRING *, MAPS *);
-extern void cleanup_map11_internal(VSTRING *, MAPS *);
-extern void cleanup_map11_tree(TOK822 *, MAPS *);
+extern void cleanup_map11_external(VSTRING *, MAPS *, int);
+extern void cleanup_map11_internal(VSTRING *, MAPS *, int);
+extern void cleanup_map11_tree(TOK822 *, MAPS *, int);
 
  /*
   * cleanup_map1n.c
   */
-ARGV   *cleanup_map1n_internal(char *, MAPS *);
+ARGV   *cleanup_map1n_internal(char *, MAPS *, int);
 
  /*
   * cleanup_masquerade.c
index fbef42f97c3b31afc352c8d5aafe681281d588f4..e7c29bf1c8189bf9c7364d3a8597bbf916636e23 100644 (file)
@@ -44,6 +44,7 @@
 #include <cleanup_user.h>
 #include <tok822.h>
 #include <mail_params.h>
+#include <ext_prop.h>
 
 /* Application-specific. */
 
@@ -104,9 +105,11 @@ void    cleanup_envelope(void)
        } else if (type == REC_TYPE_FROM) {
            cleanup_rewrite_internal(clean_addr, STR(cleanup_inbuf));
            if (cleanup_send_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_send_canon_maps);
+               cleanup_map11_internal(clean_addr, cleanup_send_canon_maps,
+                               cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
            if (cleanup_comm_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_comm_canon_maps);
+               cleanup_map11_internal(clean_addr, cleanup_comm_canon_maps,
+                               cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
            if (cleanup_masq_domains)
                cleanup_masquerade_internal(clean_addr, cleanup_masq_domains);
            CLEANUP_OUT_BUF(type, clean_addr);
@@ -121,9 +124,11 @@ void    cleanup_envelope(void)
            cleanup_rewrite_internal(clean_addr, *STR(cleanup_inbuf) ?
                                     STR(cleanup_inbuf) : var_empty_addr);
            if (cleanup_rcpt_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_rcpt_canon_maps);
+               cleanup_map11_internal(clean_addr, cleanup_rcpt_canon_maps,
+                               cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
            if (cleanup_comm_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_comm_canon_maps);
+               cleanup_map11_internal(clean_addr, cleanup_comm_canon_maps,
+                               cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
            cleanup_out_recipient(STR(clean_addr));
            if (cleanup_recip == 0)
                cleanup_recip = mystrdup(STR(clean_addr));
index cac495f9a7bf25d510555183083d880c27e4da81..0680191a87eecb80f95678e52ee4407671f78a04 100644 (file)
@@ -6,17 +6,20 @@
 /* SYNOPSIS
 /*     #include <cleanup.h>
 /*
-/*     void    cleanup_map11_external(addr, maps)
+/*     void    cleanup_map11_external(addr, maps, propagate)
 /*     VSTRING *addr;
 /*     MAPS    *maps;
+/*     int     propagate;
 /*
-/*     void    cleanup_map11_internal(addr, maps)
+/*     void    cleanup_map11_internal(addr, maps, propagate)
 /*     VSTRING *addr;
 /*     MAPS    *maps;
+/*     int     propagate;
 /*
-/*     void    cleanup_map11_tree(tree, maps)
+/*     void    cleanup_map11_tree(tree, maps, propagate)
 /*     TOK822  *tree;
 /*     MAPS    *maps;
+/*     int     propagate;
 /* DESCRIPTION
 /*     This module performs one-to-one map lookups.
 /*
@@ -24,6 +27,8 @@
 /*     subjected to another iteration of rewriting and mapping.
 /*     Recursion continues until an address maps onto itself,
 /*     or until an unreasonable recursion level is reached.
+/*     An unmatched address extension is propagated when 
+/*     \fIpropagate\fR is non-zero.
 /*
 /*     cleanup_map11_external() looks up the external (quoted) string
 /*     form of an address in the maps specified via the \fImaps\fR argument.
@@ -82,7 +87,7 @@
 
 /* cleanup_map11_external - one-to-one table lookups */
 
-void    cleanup_map11_external(VSTRING *addr, MAPS *maps)
+void    cleanup_map11_external(VSTRING *addr, MAPS *maps, int propagate)
 {
     int     count;
     int     expand_to_self;
@@ -96,7 +101,7 @@ void    cleanup_map11_external(VSTRING *addr, MAPS *maps)
      * the place.
      */
     for (count = 0; count < MAX_RECURSION; count++) {
-       if ((new_addr = mail_addr_map(maps, STR(addr))) != 0) {
+       if ((new_addr = mail_addr_map(maps, STR(addr), propagate)) != 0) {
            if (new_addr->argc > 1)
                msg_warn("multi-valued %s entry for %s",
                         maps->title, STR(addr));
@@ -122,7 +127,7 @@ void    cleanup_map11_external(VSTRING *addr, MAPS *maps)
 
 /* cleanup_map11_tree - rewrite address node */
 
-void    cleanup_map11_tree(TOK822 *tree, MAPS *maps)
+void    cleanup_map11_tree(TOK822 *tree, MAPS *maps, int propagate)
 {
     VSTRING *temp = vstring_alloc(100);
 
@@ -133,7 +138,7 @@ void    cleanup_map11_tree(TOK822 *tree, MAPS *maps)
      * the place.
      */
     tok822_externalize(temp, tree->head, TOK822_STR_DEFL);
-    cleanup_map11_external(temp, maps);
+    cleanup_map11_external(temp, maps, propagate);
     tok822_free_tree(tree->head);
     tree->head = tok822_scan(STR(temp), &tree->tail);
     vstring_free(temp);
@@ -141,7 +146,7 @@ void    cleanup_map11_tree(TOK822 *tree, MAPS *maps)
 
 /* cleanup_map11_internal - rewrite address internal form */
 
-void    cleanup_map11_internal(VSTRING *addr, MAPS *maps)
+void    cleanup_map11_internal(VSTRING *addr, MAPS *maps, int propagate)
 {
     VSTRING *temp = vstring_alloc(100);
 
@@ -152,7 +157,7 @@ void    cleanup_map11_internal(VSTRING *addr, MAPS *maps)
      * the place.
      */
     quote_822_local(temp, STR(addr));
-    cleanup_map11_external(temp, maps);
+    cleanup_map11_external(temp, maps, propagate);
     unquote_822_local(addr, STR(temp));
     vstring_free(temp);
 }
index 2addef510a5cad5a20a223db0b2ab2d97bf7aca8..2bab163df5b3ed95d06583fb9528beacd3f2cb69 100644 (file)
@@ -61,7 +61,7 @@
 
 /* cleanup_map1n_internal - one-to-many table lookups */
 
-ARGV   *cleanup_map1n_internal(char *addr, MAPS *maps)
+ARGV   *cleanup_map1n_internal(char *addr, MAPS *maps, int propagate)
 {
     ARGV   *argv;
     ARGV   *lookup;
@@ -102,7 +102,7 @@ ARGV   *cleanup_map1n_internal(char *addr, MAPS *maps)
                         cleanup_queue_id, maps->title, addr);
                break;
            }
-           if ((lookup = mail_addr_map(maps, argv->argv[arg])) != 0) {
+           if ((lookup = mail_addr_map(maps, argv->argv[arg], propagate)) != 0) {
                saved_lhs = mystrdup(argv->argv[arg]);
                for (i = 0; i < lookup->argc; i++) {
                    unquote_822_local(cleanup_temp1, lookup->argv[i]);
index 67a67919730f8dc22a329bb97ecb28fe130f8c12..592a8696d3f7f916d15f083a73567944e5db8830 100644 (file)
@@ -59,6 +59,7 @@
 #include <mail_date.h>
 #include <mail_addr.h>
 #include <is_header.h>
+#include <ext_prop.h>
 
 /* Application-specific. */
 
@@ -153,9 +154,11 @@ static void cleanup_rewrite_sender(HEADER_OPTS *hdr_opts)
     for (tpp = addr_list; *tpp; tpp++) {
        cleanup_rewrite_tree(*tpp);
        if (cleanup_send_canon_maps)
-           cleanup_map11_tree(*tpp, cleanup_send_canon_maps);
+           cleanup_map11_tree(*tpp, cleanup_send_canon_maps,
+                              cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
        if (cleanup_comm_canon_maps)
-           cleanup_map11_tree(*tpp, cleanup_comm_canon_maps);
+           cleanup_map11_tree(*tpp, cleanup_comm_canon_maps,
+                              cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
        if (cleanup_masq_domains)
            cleanup_masquerade_tree(*tpp, cleanup_masq_domains);
        if (hdr_opts->type == HDR_FROM && cleanup_from == 0)
@@ -194,9 +197,11 @@ static void cleanup_rewrite_recip(HEADER_OPTS *hdr_opts)
     for (tpp = addr_list; *tpp; tpp++) {
        cleanup_rewrite_tree(*tpp);
        if (cleanup_rcpt_canon_maps)
-           cleanup_map11_tree(*tpp, cleanup_rcpt_canon_maps);
+           cleanup_map11_tree(*tpp, cleanup_rcpt_canon_maps,
+                              cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
        if (cleanup_comm_canon_maps)
-           cleanup_map11_tree(*tpp, cleanup_comm_canon_maps);
+           cleanup_map11_tree(*tpp, cleanup_comm_canon_maps,
+                              cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
        tok822_internalize(cleanup_temp1, tpp[0]->head, TOK822_STR_DEFL);
        if (cleanup_recip == 0 && (hdr_opts->flags & HDR_OPT_EXTRACT) != 0)
            argv_add((hdr_opts->flags & HDR_OPT_RR) ?
index e1899a20b4b1b8e33590ed7f985cce0ca89c1f62..596e172582f2580cdf35b49ac4d6970af71b9348 100644 (file)
@@ -47,6 +47,7 @@
 #include <been_here.h>
 #include <mail_params.h>
 #include <rec_type.h>
+#include <ext_prop.h>
 
 /* Application-specific. */
 
@@ -63,7 +64,8 @@ void    cleanup_out_recipient(char *recip)
        if (been_here_fixed(cleanup_dups, recip) == 0)
            cleanup_out_string(REC_TYPE_RCPT, recip);
     } else {
-       argv = cleanup_map1n_internal(recip, cleanup_virtual_maps);
+       argv = cleanup_map1n_internal(recip, cleanup_virtual_maps,
+                                 cleanup_ext_prop_mask & EXT_PROP_VIRTUAL);
        for (cpp = argv->argv; *cpp; cpp++)
            if (been_here_fixed(cleanup_dups, *cpp) == 0)
                cleanup_out_string(REC_TYPE_RCPT, *cpp);
index e79c06851ae339dfe0171275180480cfc7152f23..e6657abff80eb2aa19970addc5a25c9efcd59aa7 100644 (file)
@@ -250,11 +250,10 @@ program_directory = /some/where/postfix/bin
 #
 #fallback_transport =
 
-# The luser_relay parameter specifies an optional destination (@domain,
-# address) for unknown recipients.  By default, mail for unknown
-# local recipients is bounced.
+# The luser_relay parameter specifies an optional destination address
+# for unknown recipients.  By default, mail for unknown local recipients
+# is bounced.
 #
-# Specify @domain in order to keep the original recipient name.
 # 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
@@ -262,7 +261,8 @@ program_directory = /some/where/postfix/bin
 # localpart), $recipient_delimiter. Specify ${name?value} or
 # ${name:value} to expand value only when $name does (does not) exist.
 #
-# luser_relay = @other.host
+# luser_relay = $user@other.host
+# luser_relay = $mailbox@other.host
 # luser_relay = admin+$mailbox
   
 # JUNK MAIL CONTROLS
index eccb1988a9675f9c74b6f396d1e8da322bb40ef5..1028765867387d71a1c9468d1171ca6d97fcb72e 100644 (file)
@@ -14,6 +14,7 @@ bounce_notice_recipient = postmaster
 bounce_size_limit = 50000
 canonical_maps = 
 command_directory = $program_directory
+command_expansion_filter = 1234567890!@%-_=+:,./abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
 command_time_limit = 1000
 daemon_directory = $program_directory
 daemon_timeout = 18000
@@ -40,6 +41,7 @@ fallback_relay =
 fallback_transport = 
 fork_attempts = 5
 fork_delay = 1
+forward_expansion_filter = 1234567890!@%-_=+:,./abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
 forward_path = $home/.forward${recipient_delimiter}${extension},$home/.forward
 hash_queue_depth = 2
 hash_queue_names = defer
@@ -61,7 +63,7 @@ luser_relay =
 mail_name = Postfix
 mail_owner = postfix
 mail_spool_directory = /var/mail
-mail_version = Snapshot-19990507
+mail_version = Snapshot-19990508
 mailbox_command = 
 mailbox_transport = 
 maps_rbl_domains = rbl.maps.vix.com
@@ -81,6 +83,7 @@ notify_classes = resource,software
 owner_request_special = yes
 process_id_directory = pid
 program_directory = /usr/libexec/postfix
+propagate_unmatched_extension = canonical, virtual
 qmgr_message_active_limit = 1000
 qmgr_message_recipient_limit = 10000
 queue_directory = /var/spool/postfix
index b083dffa589792e9ff43963d71182490e90d0d22..f6dce292bec6b59c553426b835e509924b3f7abe 100644 (file)
@@ -71,11 +71,10 @@ default_privs = nobody
 # home_mailbox = Maildir/
 home_mailbox = 
 
-# 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 address
+# for unknown recipients.  By default, mail for unknown local recipients
+# is bounced.
 #
-# Specify @domain in order to keep the original recipient name.
 # 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
@@ -83,7 +82,8 @@ home_mailbox =
 # localpart), $recipient_delimiter. Specify ${name?value} or
 # ${name:value} to expand value only when $name does (does not) exist.
 #
-# luser_relay = @other.host
+# luser_relay = $user@other.host
+# luser_relay = $mailbox@other.host
 # luser_relay = admin+$mailbox
 
 # The mail_spool_directory parameter specifies the directory where
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index 96f90c0fa21e500948db6d6b033386bc41276395..62f013b27d8de68ff76d8a1118bdeabba37aa00d 100644 (file)
@@ -62,4 +62,6 @@ error.o: ../include/deliver_request.h
 error.o: ../include/vstring.h
 error.o: ../include/recipient_list.h
 error.o: ../include/mail_queue.h
+error.o: ../include/bounce.h
+error.o: ../include/deliver_completed.h
 error.o: ../include/mail_server.h
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index 9f78c7c3e48fcdd54076cbe7b5ea2225f5b31678..cc1c3b7ccaaaf18bf4a11a7b75737570ed30ed8a 100644 (file)
@@ -16,7 +16,7 @@ SRCS  = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
        recipient_list.c record.c remove.c resolve_clnt.c resolve_local.c \
        rewrite_clnt.c sent.c smtp_stream.c split_addr.c string_list.c \
        sys_exits.c timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
-       tok822_resolve.c tok822_rewrite.c tok822_tree.c
+       tok822_resolve.c tok822_rewrite.c tok822_tree.c ext_prop.c
 OBJS   = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
        debug_peer.o debug_process.o defer.o deliver_completed.o \
        deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
@@ -34,7 +34,7 @@ OBJS  = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
        recipient_list.o record.o remove.o resolve_clnt.o resolve_local.o \
        rewrite_clnt.o sent.o smtp_stream.o split_addr.o string_list.o \
        sys_exits.o timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
-       tok822_resolve.o tok822_rewrite.o tok822_tree.o
+       tok822_resolve.o tok822_rewrite.o tok822_tree.o ext_prop.o
 HDRS   = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
        config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
        deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
@@ -48,7 +48,7 @@ HDRS  = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
        quote_822_local.h rec_streamlf.h rec_type.h recipient_list.h \
        record.h resolve_clnt.h resolve_local.h rewrite_clnt.h sent.h \
        smtp_stream.h split_addr.h string_list.h sys_exits.h timed_ipc.h \
-       tok822.h
+       tok822.h ext_prop.h
 TESTSRC        = rec2stream.c stream2rec.c recdump.c
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
        -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
@@ -330,6 +330,10 @@ dot_lockfile.o: ../include/stringops.h
 dot_lockfile.o: ../include/mymalloc.h
 dot_lockfile.o: mail_params.h
 dot_lockfile.o: dot_lockfile.h
+ext_prop.o: ext_prop.c
+ext_prop.o: ../include/sys_defs.h
+ext_prop.o: ../include/name_mask.h
+ext_prop.o: ext_prop.h
 file_id.o: file_id.c
 file_id.o: ../include/sys_defs.h
 file_id.o: ../include/msg.h
diff --git a/postfix/global/ext_prop.c b/postfix/global/ext_prop.c
new file mode 100644 (file)
index 0000000..845c3a0
--- /dev/null
@@ -0,0 +1,72 @@
+/*++
+/* NAME
+/*     exp_prop 3
+/* SUMMARY
+/*     address extension propagation control
+/* SYNOPSIS
+/*     #include <exp_prop.h>
+/*
+/*     int     ext_prop_mask(pattern)
+/*     const char *pattern;
+/* DESCRIPTION
+/*     This module controld address extension propagation.
+/*
+/*     ext_prop_mask() takes a comma-separated list of names and
+/*     computes the corresponding mask. The following names are
+/*     recognized in \fBpattern\fR, with the corresponding bit mask
+/*     given in parentheses:
+/* .IP "canonical (EXP_PROP_CANONICAL)"
+/*     Propagate unmatched address extensions tothe right-hand side
+/*     canonical map entries.
+/* .IP "virtual (EXP_PROP_VIRTUAL)
+/*     Propagate unmatched address extensions tothe right-hand side
+/*     canonical map entries.
+/* .IP "alias (EXP_PROP_ALIAS)
+/*     Propagate unmatched address extensions tothe right-hand side
+/*     canonical map entries.
+/* .IP "forward (EXP_PROP_FORWARD)"
+/*     Propagate unmatched address extensions tothe right-hand side
+/*     canonical map entries.
+/* .IP "include (EXP_PROP_INCLUDE)"
+/*     Propagate unmatched address extensions tothe right-hand side
+/*     canonical map entries.
+/* DIAGNOSTICS
+/*     Panic: inappropriate use.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <name_mask.h>
+
+/* Global library. */
+
+#include <ext_prop.h>
+
+/* ext_prop_mask - compute extension propagation mask */
+
+int     ext_prop_mask(const char *pattern)
+{
+    static NAME_MASK table[] = {
+       "canonical", EXT_PROP_CANONICAL,
+       "virtual", EXT_PROP_VIRTUAL,
+       "alias", EXT_PROP_ALIAS,
+       "forward", EXT_PROP_FORWARD,
+       "include", EXT_PROP_INCLUDE,
+       0,
+    };
+
+    return (name_mask(table, pattern));
+}
diff --git a/postfix/global/ext_prop.h b/postfix/global/ext_prop.h
new file mode 100644 (file)
index 0000000..99e0911
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _EXT_PROP_INCLUDED_
+#define _EXT_PROP_INCLUDED_
+
+/*++
+/* NAME
+/*     ext_prop 3h
+/* SUMMARY
+/*     address extension propagation control
+/* SYNOPSIS
+/*     #include <ext_prop.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * External interface.
+  */
+#define EXT_PROP_CANONICAL     (1<<0)
+#define EXT_PROP_VIRTUAL       (1<<1)
+#define EXT_PROP_ALIAS         (1<<2)
+#define EXT_PROP_FORWARD       (1<<3)
+#define EXT_PROP_INCLUDE       (1<<4)
+
+extern int ext_prop_mask(const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
index 8d9436804b8fea9dc0e2afb4a56e57e901d8e9a7..508251f8b909c1b8eb865641953a41a650ad3f25 100644 (file)
@@ -6,15 +6,17 @@
 /* SYNOPSIS
 /*     #include <mail_addr_map.h>
 /*
-/*     ARGV    *mail_addr_map(path, address)
+/*     ARGV    *mail_addr_map(path, address, propagate)
 /*     MAPS    *path;
 /*     const char *address;
+/*     int     propagate;
 /* DESCRIPTION
 /*     mail_addr_map() returns the translation for the named address,
 /*     or a null pointer if none is found.  The result is in canonical
 /*     external (quoted) form.  The search is case insensitive.
 /*
-/*     Address extensions that aren't explicitly matched in the lookup
+/*     When the \fBpropagate\fR argument is non-zero,
+/*     address extensions that aren't explicitly matched in the lookup
 /*     table are propagated to the result addresses. The caller is
 /*     expected to pass the result to argv_free().
 /*
@@ -69,7 +71,7 @@
 
 /* mail_addr_map - map a canonical address */
 
-ARGV   *mail_addr_map(MAPS *path, const char *address)
+ARGV   *mail_addr_map(MAPS *path, const char *address, int propagate)
 {
     VSTRING *buffer = 0;
     char   *myname = "mail_addr_map";
@@ -102,7 +104,7 @@ ARGV   *mail_addr_map(MAPS *path, const char *address)
         * Canonicalize and externalize the result, and propagate the
         * unmatched extension to each address found.
         */
-       argv = mail_addr_crunch(string, extension);
+       argv = mail_addr_crunch(string, propagate ? extension : 0);
        if (buffer)
            vstring_free(buffer);
        if (msg_verbose)
index bfc07c07cf711e7fd11e4ab87b0b654df1f3cc94..f887c611a2a31d75fb51a4e8501e22a4553e60ac 100644 (file)
@@ -24,7 +24,7 @@
  /*
   * External interface.
   */
-extern ARGV *mail_addr_map(MAPS *, const char *);
+extern ARGV *mail_addr_map(MAPS *, const char *, int);
 
 /* LICENSE
 /* .ad
index 9fef329bf530f436f56c4b0bff31178ab6fa6cb5..a6650583dc5568d6b7993e9efac610f4d739cc6b 100644 (file)
@@ -328,10 +328,26 @@ extern char *var_fallback_transport;
 #define DEF_FORWARD_PATH       "$home/.forward${recipient_delimiter}${extension},$home/.forward"
 extern char *var_forward_path;
 
+#define VAR_PROP_EXTENSION     "propagate_unmatched_extension"
+#define DEF_PROP_EXTENSION     "canonical, virtual"
+extern char *var_prop_extension;
+
 #define VAR_RCPT_DELIM         "recipient_delimiter"
 #define DEF_RCPT_DELIM         ""
 extern char *var_rcpt_delim;
 
+#define VAR_CMD_EXP_FILTER     "command_expansion_filter"
+#define DEF_CMD_EXP_FILTER     "1234567890!@%-_=+:,./\
+abcdefghijklmnopqrstuvwxyz\
+ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+extern char *var_cmd_exp_filter;;
+
+#define VAR_FWD_EXP_FILTER     "forward_expansion_filter"
+#define DEF_FWD_EXP_FILTER     "1234567890!@%-_=+:,./\
+abcdefghijklmnopqrstuvwxyz\
+ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+extern char *var_fwd_exp_filter;;
+
 #define VAR_RCPT_FDELIM                "recipient_feature_delimiter"
 #define DEF_RCPT_FDELIM                ""
 extern char *var_rcpt_fdelim;
index bab9fdc6685926b492e826ca80d2eaca342adc5e..540f9a01fc81b4586f34958ee8e5a81d4ddaef3f 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-19990507"
+#define DEF_MAIL_VERSION       "Snapshot-19990508"
 extern char *var_mail_version;
 
 /* LICENSE
index f1678022639d187988f13ee6d24375d0e6cb0384..099d80630682e76ea6dafc64b0bf174edd089023 100644 (file)
@@ -44,7 +44,11 @@ LOCAL(8)                                                 LOCAL(8)
        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.
+       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 replaced by underscores. The list
+       of  legal  characters is specified with the <b>forward</b><i>_</i><b>expan-</b>
+       <b>sion</b><i>_</i><b>filter</b> configuration parameter.
 
        An alias or ~/.<b>forward</b> file may list  any  combination  of
        external   commands,  destination  file  names,  <b>:include:</b>
@@ -55,10 +59,6 @@ LOCAL(8)                                                 LOCAL(8)
        When an address is  found  in  its  own  alias  expansion,
        delivery  is  made  to  the  user  instead. When a user is
        listed in the user's own ~/.<b>forward</b> file, delivery is made
-       to  the  user's mailbox instead.  An empty ~/.<b>forward</b> file
-       means do not forward mail.
-
-       In  order  to  prevent  the  mail  system  from  using  up
 
 
 
@@ -71,7 +71,11 @@ LOCAL(8)                                                 LOCAL(8)
 LOCAL(8)                                                 LOCAL(8)
 
 
-       unreasonable  amounts  of  memory, input records read from
+       to  the  user's mailbox instead.  An empty ~/.<b>forward</b> file
+       means do not forward mail.
+
+       In order to prevent the mail system from using  up  unrea-
+       sonable   amounts  of  memory,  input  records  read  from
        <b>:include:</b> or from ~/.<b>forward</b>  files  are  broken  up  into
        chunks of length <b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>.
 
@@ -106,25 +110,21 @@ LOCAL(8)                                                 LOCAL(8)
        specified with the <b>mailbox</b><i>_</i><b>command</b>  configuration  parame-
        ter.  The  command  executes  with  the  privileges of the
        recipient user (exception: in case of  delivery  as  root,
-       the command executes with the privileges of <b>default</b><i>_</i><b>user</b>).
-       The command is subject to interpolation of <b>$user</b>  (recipi-
-       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),  <b>mailbox</b>  (entire  recipient
-       address  localpart)  and  <b>$recipient</b><i>_</i><b>delimiter.</b>  The forms
+       the    command    executes    with   the   privileges   of
+       <b>default</b><i>_</i><b>privs</b>).  The command is subject  to  interpolation
+       of  <b>$user</b>  (recipient  username),  <b>$home</b>  (recipient  home
+       directory), <b>$shell</b> (recipient shell), <b>$recipient</b> (complete
+       recipient  address),  <b>$extension</b> (recipient address exten-
+       sion), <b>$domain</b> (recipient domain), <b>mailbox</b> (entire recipi-
+       ent 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>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.
+       the  shell  are replaced by underscores. The list of legal
+       characters is specified with the  <b>command</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
+       configuration parameter.
 
        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
 
 
 
@@ -137,6 +137,12 @@ LOCAL(8)                                                 LOCAL(8)
 LOCAL(8)                                                 LOCAL(8)
 
 
+       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.
 
        In the case of UNIX-style mailbox delivery, the <b>local</b> dae-
@@ -186,12 +192,6 @@ LOCAL(8)                                                 LOCAL(8)
        <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.
-       Specify  a  pathname  ending  in  <b>/</b>  for  <b>qmail</b>-compatible
-
 
 
                                                                 3
@@ -203,6 +203,11 @@ LOCAL(8)                                                 LOCAL(8)
 LOCAL(8)                                                 LOCAL(8)
 
 
+<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.
+       Specify  a  pathname  ending  in  <b>/</b>  for  <b>qmail</b>-compatible
        <b>maildir</b> delivery.
 
        The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve-
@@ -252,11 +257,6 @@ LOCAL(8)                                                 LOCAL(8)
        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-
-       ble.
-
-<b>BUGS</b>
-       For  security  reasons,  the  message  delivery  status of
 
 
 
@@ -269,6 +269,11 @@ LOCAL(8)                                                 LOCAL(8)
 LOCAL(8)                                                 LOCAL(8)
 
 
+       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
        deliver more than once to a command or external file. Bet-
@@ -317,11 +322,6 @@ LOCAL(8)                                                 LOCAL(8)
               directory.  Specify a path ending in <b>/</b> for maildir-
               style delivery.
 
-       <b>luser</b><i>_</i><b>relay</b>
-              Destination (<i>@domain</i> or <i>address</i>)  for  non-existent
-              users.   The  <i>address</i>  is subjected to <i>$name</i> expan-
-              sion.
-
 
 
 
@@ -335,6 +335,11 @@ LOCAL(8)                                                 LOCAL(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>  is subjected to <i>$name</i> expan-
+              sion.
+
        <b>mail</b><i>_</i><b>spool</b><i>_</i><b>directory</b>
               Directory with UNIX-style  mailboxes.  The  default
               pathname is system dependent.
@@ -342,22 +347,23 @@ LOCAL(8)                                                 LOCAL(8)
        <b>mailbox</b><i>_</i><b>command</b>
               External  command  to use for mailbox delivery. The
               command  executes  with  the  recipient  privileges
-              (exception: root).
+              (exception:  root).  The string is subject to $name
+              expansions.
 
        <b>mailbox</b><i>_</i><b>transport</b>
-              Message  transport  to  use for mailbox delivery to
+              Message transport to use for  mailbox  delivery  to
               all local recipients, whether or not they are found
-              in  the UNIX passwd database.  This parameter over-
-              rides all other configuration parameters that  con-
+              in the UNIX passwd database.  This parameter  over-
+              rides  all other configuration parameters that con-
               trol mailbox delivery, including <b>luser</b><i>_</i><b>relay</b>.
 
 <b>Locking</b> <b>controls</b>
        <b>deliver</b><i>_</i><b>lock</b><i>_</i><b>attempts</b>
-              Limit  the  number of attempts to acquire an exclu-
+              Limit the number of attempts to acquire  an  exclu-
               sive lock on a mailbox or external file.
 
        <b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b>
-              Time in  seconds  between  successive  attempts  to
+              Time  in  seconds  between  successive  attempts to
               acquire an exclusive lock.
 
        <b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
@@ -365,30 +371,24 @@ LOCAL(8)                                                 LOCAL(8)
 
 <b>Resource</b> <b>controls</b>
        <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b>
-              Limit the amount of time for delivery  to  external
+              Limit  the  amount of time for delivery to external
               command.
 
        <b>duplicate</b><i>_</i><b>filter</b><i>_</i><b>limit</b>
-              Limit  the size of the duplicate filter for results
+              Limit the size of the duplicate filter for  results
               from alias etc. expansion.
 
        <b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
-              Limit the amount of memory used  for  processing  a
+              Limit  the  amount  of memory used for processing a
               partial input line.
 
        <b>local</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
               Limit the number of parallel deliveries to the same
-              user.   The  default  limit  is  taken   from   the
+              user.    The   default  limit  is  taken  from  the
               <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter.
 
        <b>local</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Limit  the  number of recipients per message deliv-
-              ery.   The  default  limit  is   taken   from   the
-              <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
-
-<b>Security</b> <b>controls</b>
-       <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b>
-              Restrict  the  usage  of  mail delivery to external
+              Limit  the  number  of   recipients   per   message
 
 
 
@@ -401,21 +401,37 @@ LOCAL(8)                                                 LOCAL(8)
 LOCAL(8)                                                 LOCAL(8)
 
 
+              delivery.   The  default  limit  is  taken from the
+              <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
+
+<b>Security</b> <b>controls</b>
+       <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b>
+              Restrict the usage of  mail  delivery  to  external
               command.
 
        <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b>
-              Restrict the usage of  mail  delivery  to  external
+              Restrict  the  usage  of  mail delivery to external
               file.
 
+       <b>command</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
+              What characters are  allowed  to  appear  in  $name
+              expansions  of  mailbox_command. Illegal characters
+              are replaced by underscores.
+
        <b>default</b><i>_</i><b>privs</b>
-              Default  rights  for  delivery  to external file or
+              Default rights for delivery  to  external  file  or
               command.
 
+       <b>forward</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
+              What  characters  are  allowed  to  appear in $name
+              expansions of forward_path. Illegal characters  are
+              replaced by underscores.
+
 <b>HISTORY</b>
-       The <b>Delivered-To:</b> header appears in the  <b>qmail</b>  system  by
+       The  <b>Delivered-To:</b>  header  appears in the <b>qmail</b> system by
        Daniel Bernstein.
 
-       The  <i>maildir</i>  structure  appears  in  the  <b>qmail</b> system by
+       The <i>maildir</i> structure  appears  in  the  <b>qmail</b>  system  by
        Daniel Bernstein.
 
 <b>SEE</b> <b>ALSO</b>
@@ -426,7 +442,7 @@ LOCAL(8)                                                 LOCAL(8)
        <a href="qmgr.8.html">qmgr(8)</a> queue manager
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
@@ -437,22 +453,6 @@ LOCAL(8)                                                 LOCAL(8)
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 
 
 
index 4673d04093167bb064906b3597a6f9a26467ee20..fae9e4a48e305af2bad4ec7242697df758077c14 100644 (file)
@@ -425,37 +425,41 @@ see the <a href="local.8.html"> local</a> delivery agent.
 
 <p>
 
-<b>luser_relay</b> can specify any number of destinations that are
-valid in an alias file.  In fact, the same restrictions for command
-and file destinations apply as for true aliases.
+<b>luser_relay</b> can specify one address. It is subjected to
+<i>$name</i> expansions. The most useful examples are:
 
 <p>
 
-In addition, some <b>luser_relay</b> destinations can receive
-special treatment:
+<dl>
 
-<p>
+<dt><b>$user@other.host</b>
 
-<dl>
+<dd>The bare username, without address extension, is prepended to
+<i>@other.host</i>. For example, mail for <i>username+foo</i> is
+sent to <i>username@other.host</i>.
+
+<p>
 
-<dt><b>luser_relay = </b><i>@some.where.else</i>
+<dt><b>$mailbox@other.host</b>
 
-<dd>The entire original recipient localpart is prepended. For
-example, mail for <i>unknown+foo</i> is sent to
-<i>unknown+foo@some.where.else</i>.
+<dd>The entire original recipient localpart, including address
+extension, is prepended to <i>@other.host</i>. For example, mail
+for <i>username+foo</i> is sent to <i>username+foo@other.host</i>.
 
 <p>
 
-<dt><b>luser_relay = </b><i>someone@some.where.else</i>
-<dt><b>luser_relay = </b><i>someone</i>
+<dt><b>sysadmin+$user</b>
+
+<dd>The bare username, without address extension, is appended to
+<i>sysadmin</i>. For example, mail for <i>username+foo</i> is sent
+to <i>sysadmin+username</i>.
+
+<dt><b>sysadmin+$mailbox</b>
+
+<dd>The entire original recipient localpart, including address
+extension, is appended to <i>sysadmin</i>. For example, mail for
+<i>username+foo</i> is sent to <i>sysadmin+username+foo</i>.
 
-<dd>If no <b>recipient_delimiter</b> has been specified, mail is
-sent to the <b>luser_relay</b> address. If the <b>recipient_delimiter</b>
-has been specified, the entire original recipient localpart is
-appended as an address extension to the <b>luser_relay</b> address.
-For example, with <b>recipient_delimiter = +</b>, mail for
-<i>unknown+foo</i> is sent to <i>someone+unknown+foo@some.where.else</i>
-and <i>someone+unknown+foo</i>, respectively.
 
 </dl>
 
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index 943b2b70f4f88e852177631b18f272c464f1673e..38e36a2bb752dcbfc6b2d72daa7da6fb723e9203 100644 (file)
@@ -98,6 +98,7 @@ command.o: ../include/vbuf.h
 command.o: ../include/vstream.h
 command.o: ../include/argv.h
 command.o: ../include/mac_expand.h
+command.o: ../include/mac_parse.h
 command.o: ../include/defer.h
 command.o: ../include/bounce.h
 command.o: ../include/sent.h
@@ -156,11 +157,13 @@ dotforward.o: ../include/iostuff.h
 dotforward.o: ../include/stringops.h
 dotforward.o: ../include/mymalloc.h
 dotforward.o: ../include/mac_expand.h
+dotforward.o: ../include/mac_parse.h
 dotforward.o: ../include/mypwd.h
 dotforward.o: ../include/bounce.h
 dotforward.o: ../include/been_here.h
 dotforward.o: ../include/mail_params.h
 dotforward.o: ../include/mail_conf.h
+dotforward.o: ../include/ext_prop.h
 dotforward.o: local.h
 dotforward.o: ../include/tok822.h
 dotforward.o: ../include/resolve_clnt.h
@@ -244,6 +247,7 @@ include.o: ../include/bounce.h
 include.o: ../include/defer.h
 include.o: ../include/been_here.h
 include.o: ../include/mail_params.h
+include.o: ../include/ext_prop.h
 include.o: local.h
 include.o: ../include/vstring.h
 include.o: ../include/tok822.h
@@ -286,17 +290,21 @@ local.o: ../include/mail_params.h
 local.o: ../include/mail_addr.h
 local.o: ../include/mail_conf.h
 local.o: ../include/been_here.h
+local.o: ../include/ext_prop.h
 local.o: ../include/mail_server.h
 local.o: local.h
 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/htable.h
+local_expand.o: ../include/vstring.h
+local_expand.o: ../include/vbuf.h
+local_expand.o: ../include/mac_expand.h
+local_expand.o: ../include/mac_parse.h
+local_expand.o: ../include/mail_params.h
 local_expand.o: local.h
+local_expand.o: ../include/htable.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
@@ -365,6 +373,7 @@ recipient.o: ../include/vbuf.h
 recipient.o: ../include/bounce.h
 recipient.o: ../include/mail_params.h
 recipient.o: ../include/split_addr.h
+recipient.o: ../include/ext_prop.h
 recipient.o: local.h
 recipient.o: ../include/vstring.h
 recipient.o: ../include/been_here.h
@@ -411,16 +420,16 @@ unknown.o: ../include/sys_defs.h
 unknown.o: ../include/msg.h
 unknown.o: ../include/stringops.h
 unknown.o: ../include/mymalloc.h
+unknown.o: ../include/vstring.h
+unknown.o: ../include/vbuf.h
 unknown.o: ../include/been_here.h
 unknown.o: ../include/mail_params.h
 unknown.o: ../include/mail_proto.h
 unknown.o: ../include/vstream.h
-unknown.o: ../include/vbuf.h
 unknown.o: ../include/iostuff.h
 unknown.o: ../include/bounce.h
 unknown.o: local.h
 unknown.o: ../include/htable.h
-unknown.o: ../include/vstring.h
 unknown.o: ../include/tok822.h
 unknown.o: ../include/resolve_clnt.h
 unknown.o: ../include/deliver_request.h
index 481223fc55686e205284f042ea84187d9dc60ec9..4d61c72842cae948b41e9acaec26c600a0fb1714 100644 (file)
@@ -24,9 +24,9 @@
 /* .IP usr_attr
 /*     Attributes describing user rights and environment.
 /* .IP command
-/*     The shell command to be executed, after $name expansion of recipient
-/*     attributes. If possible, the command is executed without actually
-/*     invoking a shell.
+/*     The shell command to be executed. If possible, the command is
+/*     executed without actually invoking a shell. if the command is
+/*     the mailbox_command, it is subjected to $name expansion.
 /* DIAGNOSTICS
 /*     deliver_command() returns non-zero when delivery should be
 /*     tried again,
@@ -83,11 +83,8 @@ int     deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, char *command)
     int     deliver_status;
     ARGV   *env;
     int     copy_flags;
-    static char *ok_chars = "1234567890!@%-_=+:,./\
-abcdefghijklmnopqrstuvwxyz\
-ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-    VSTRING *expanded_cmd;
-    HTABLE  *expand_attr;
+    VSTRING *expanded_cmd = 0;
+    char   *xcommand ;
 
     /*
      * Make verbose logging easier to understand.
@@ -152,21 +149,18 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        argv_add(env, "SHELL", usr_attr.shell, ARGV_END);
     argv_terminate(env);
 
-    expanded_cmd = vstring_alloc(10);
     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);
-
+       expanded_cmd = vstring_alloc(100);
+       local_expand(expanded_cmd, command, &state,
+                    &usr_attr, var_cmd_exp_filter);
+       xcommand = vstring_str(expanded_cmd);
+    } else {
+       xcommand = command;
+    }
     cmd_status = pipe_command(state.msg_attr.fp, why,
                              PIPE_CMD_UID, usr_attr.uid,
                              PIPE_CMD_GID, usr_attr.gid,
-                             PIPE_CMD_COMMAND, vstring_str(expanded_cmd),
+                             PIPE_CMD_COMMAND, xcommand,
                              PIPE_CMD_COPY_FLAGS, copy_flags,
                              PIPE_CMD_SENDER, state.msg_attr.sender,
                              PIPE_CMD_DELIVERED, state.msg_attr.delivered,
@@ -176,7 +170,8 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ";
                              PIPE_CMD_END);
 
     argv_free(env);
-    vstring_free(expanded_cmd);
+    if (expanded_cmd)
+       vstring_free(expanded_cmd);
 
     /*
      * Depending on the result, bounce or defer the message.
index aef9e0eed2121145c3cbb43749075e8d9a66bc1d..b2250d9cca60c3172bd65581af68dd93456cb34e 100644 (file)
@@ -76,6 +76,7 @@
 #include <been_here.h>
 #include <mail_params.h>
 #include <mail_conf.h>
+#include <ext_prop.h>
 
 /* Application-specific. */
 
@@ -102,9 +103,7 @@ 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;
+    int     expand_status;
 
     /*
      * Make verbose logging easier to understand.
@@ -184,13 +183,11 @@ int     deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
     state.msg_attr.owner = state.msg_attr.recipient;
 
     /*
-     * Assume that usernames do not have file system meta characters. Open
-     * the .forward file as the user. Ignore files that aren't regular files,
-     * files that are owned by the wrong user, or files that have world write
-     * permission enabled.
+     * Search the forward_path for an existing forward file.
      * 
-     * If a forward file name includes the address extension, don't propagate
-     * the extension to the recipient addresses.
+     * If unmatched extensions should never be propagated, or if a forward file
+     * name includes the address extension, don't propagate the extension to
+     * the recipient addresses.
      */
 #define STR(x) vstring_str(x)
 
@@ -200,33 +197,32 @@ 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);
-       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) {
+       expand_status = local_expand(path, lhs, &state,
+                                    &usr_attr, var_fwd_exp_filter);
+       if ((expand_status & (MAC_PARSE_ERROR | MAC_PARSE_UNDEF)) == 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);
+               msg_info("%s: path %s expand_status %d look_status %d", myname,
+                        STR(path), expand_status, lookup_status);
            if (lookup_status >= 0) {
-               if (extension_record->value != 0)
+               if ((expand_status & LOCAL_EXP_EXTENSION_MATCHED) != 0
+                   || (local_ext_prop_mask & EXT_PROP_FORWARD) == 0)
                    state.msg_attr.unmatched = 0;
                break;
            }
        }
     }
 
-    htable_free(expand_attr, (void (*) (char *)) 0);
-    htable_free(record_attr, (void (*) (char *)) 0);
-
+    /*
+     * Process the forward file.
+     * 
+     * Assume that usernames do not have file system meta characters. Open the
+     * .forward file as the user. Ignore files that aren't regular files,
+     * files that are owned by the wrong user, or files that have world write
+     * permission enabled.
+     */
     if (lookup_status >= 0) {
        if (S_ISREG(st.st_mode) == 0) {
            msg_warn("file %s is not a regular file", STR(path));
index 38a8d72ad042abe8f372c5b83dfadb9935d8e6ed..e5ac2179894e057fbf52224c927ff12ed539b959 100644 (file)
@@ -67,6 +67,7 @@
 #include <defer.h>
 #include <been_here.h>
 #include <mail_params.h>
+#include <ext_prop.h>
 
 /* Application-specific. */
 
@@ -169,6 +170,8 @@ int     deliver_include(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
      * The command and file delivery routines are responsible for setting the
      * proper delivery rights. These are the rights of the default user, in
      * case the :include: is in a root-owned alias.
+     * 
+     * Don't propagate unmatched extensions unless permitted to do so.
      */
 #define FOPEN_AS(p,u,g) ((fd = open_as(p,O_RDONLY,0,u,g)) >= 0 ? \
                                vstream_fdopen(fd,O_RDONLY) : 0)
@@ -177,6 +180,8 @@ int     deliver_include(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
        status = bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
                               "cannot open include file %s: %m", path);
     } else {
+       if ((local_ext_prop_mask & EXT_PROP_INCLUDE) == 0)
+           state.msg_attr.unmatched = 0;
        close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);
        status = deliver_token_stream(state, usr_attr, fp, (int *) 0);
        if (vstream_fclose(fp))
index 7a29b49b05193d47ebf2d67d41f4b789a7b97ba9..a910855be796e5f641c37a65fe183cf49e2c112e 100644 (file)
 /*     \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 the shell are replaced by underscores. The list of legal 
+/*     characters is specified with the \fBforward_expansion_filter\fR 
+/*     configuration parameter.
 /*
 /*     An alias or ~/.\fBforward\fR file may list any combination of external
 /*     commands, destination file names, \fB:include:\fR directives, or
@@ -90,7 +94,7 @@
 /*     with the \fBmailbox_command\fR configuration parameter. The command
 /*     executes with the privileges of the recipient user (exception: in
 /*     case of delivery as root, the command executes with the privileges
-/*     of \fBdefault_user\fR).
+/*     of \fBdefault_privs\fR).
 /*     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),
 /*     (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
-/*     the shell are censored and replaced by underscores.
+/*     \fIvalue\fR when \fI$name\fR is (is not) defined. 
+/*     In the result of \fIname\fR expansion, characters that have special 
+/*     meaning to the shell are replaced by underscores. The list of legal 
+/*     characters is specified with the \fBcommand_expansion_filter\fR 
+/*     configuration parameter.
 /*
 /*     Mailbox delivery can be delegated to alternative message transports
 /*     specified in the \fBmaster.cf\fR file.
 /*     dependent.
 /* .IP \fBmailbox_command\fR
 /*     External command to use for mailbox delivery. The command executes
-/*     with the recipient privileges (exception: root).
+/*     with the recipient privileges (exception: root). The string is subject
+/*     to $name expansions.
 /* .IP \fBmailbox_transport\fR
 /*     Message transport to use for mailbox delivery to all local
 /*     recipients, whether or not they are found in the UNIX passwd database.
 /*     Restrict the usage of mail delivery to external command.
 /* .IP \fBallow_mail_to_files\fR
 /*     Restrict the usage of mail delivery to external file.
+/* .IP \fBcommand_expansion_filter\fR
+/*     What characters are allowed to appear in $name expansions of
+/*     mailbox_command. Illegal characters are replaced by underscores.
 /* .IP \fBdefault_privs\fR
 /*     Default rights for delivery to external file or command.
+/* .IP \fBforward_expansion_filter\fR
+/*     What characters are allowed to appear in $name expansions of
+/*     forward_path. Illegal characters are replaced by underscores.
 /* HISTORY
 /* .ad
 /* .fi
 #include <mail_conf.h>
 #include <been_here.h>
 #include <mail_params.h>
+#include <ext_prop.h>
 
 /* Single server skeleton. */
 
@@ -398,9 +412,13 @@ char   *var_mail_spool_dir;
 char   *var_mailbox_transport;
 char   *var_fallback_transport;
 char   *var_forward_path;
+char   *var_cmd_exp_filter;
+char   *var_fwd_exp_filter;
+char   *var_prop_extension;
 
 int     local_cmd_deliver_mask;
 int     local_file_deliver_mask;
+int     local_ext_prop_mask;
 
 /* local_deliver - deliver message with extreme prejudice */
 
@@ -521,6 +539,7 @@ static void local_mask_init(void)
 
     local_file_deliver_mask = name_mask(file_mask, var_allow_files);
     local_cmd_deliver_mask = name_mask(command_mask, var_allow_commands);
+    local_ext_prop_mask = ext_prop_mask(var_prop_extension);
 }
 
 /* pre_accept - see if tables have changed */
@@ -565,6 +584,9 @@ int     main(int argc, char **argv)
        VAR_MAIL_SPOOL_DIR, DEF_MAIL_SPOOL_DIR, &var_mail_spool_dir, 0, 0,
        VAR_MAILBOX_TRANSP, DEF_MAILBOX_TRANSP, &var_mailbox_transport, 0, 0,
        VAR_FALLBACK_TRANSP, DEF_FALLBACK_TRANSP, &var_fallback_transport, 0, 0,
+       VAR_CMD_EXP_FILTER, DEF_CMD_EXP_FILTER, &var_cmd_exp_filter, 1, 0,
+       VAR_FWD_EXP_FILTER, DEF_FWD_EXP_FILTER, &var_fwd_exp_filter, 1, 0,
+       VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
        0,
     };
     static CONFIG_BOOL_TABLE bool_table[] = {
index 0ec125ecc881b44e7bbda7532572f1b3bafea50d..63e7b1fcc1d22687b48e7b53908062e05820743c 100644 (file)
@@ -164,6 +164,11 @@ extern int deliver_unknown(LOCAL_STATE, USER_ATTR);
 extern int local_file_deliver_mask;
 extern int local_cmd_deliver_mask;
 
+ /*
+  * Restrictions on extension propagation.
+  */
+extern int local_ext_prop_mask;
+
  /*
   * delivered.c
   */
@@ -187,7 +192,9 @@ extern int feature_control(const char *);
  /*
   * local_expand.c
   */
-HTABLE *local_expand(LOCAL_STATE, USER_ATTR);
+int     local_expand(VSTRING *, const char *, LOCAL_STATE *, USER_ATTR *, const char *);
+
+#define LOCAL_EXP_EXTENSION_MATCHED    (1<<MAC_PARSE_USER)
 
 /* LICENSE
 /* .ad
index dbeeb90909b27b9a5d682773a632ccc844cdb3da..e42d2e6855526aa97cfc184deea1732d21a6f0d7 100644 (file)
@@ -6,13 +6,21 @@
 /* SYNOPSIS
 /*     #include "local.h"
 /*
-/*     HTABLE *local_expand(state, usr_attr)
+/*     int     local_expand(result, pattern, state, usr_attr, filter)
+/*     VSTRING *result;
+/*     const   char *pattern;
 /*     LOCAL_STATE state;
 /*     USER_ATTR usr_attr;
+/*     const char *filter;
 /* DESCRIPTION
-/*     local_expand() instantiates an attribute table for $name
-/*     expansion.
-/*
+/*     local_expand() performs conditional and unconditional $name
+/*     expansion based on message delivery attributes.
+/*     The result is the bitwise OR or zero or more of the following:
+/* .IP LOCAL_EXP_EXTENSION_MATCHED
+/*     The result of expansion contains the $extension attribute.
+/* .IP MAC_PARSE_XXX
+/*     See mac_parse(3).
+/* .PP
 /*     Attributes:
 /* .IP domain
 /*     The recipient address domain.
 /*     The recipient user name.
 /* .PP
 /*     Arguments:
+/* .IP result
+/*     Storage for the result of expansion. The buffer is truncated
+/*     upon entry.
+/* .IP pattern
+/*     The string with unconditional and conditional macro expansions.
 /* .IP state
 /*     Message delivery attributes (sender, recipient etc.).
 /*     Attributes describing alias, include or forward expansion.
@@ -39,6 +52,9 @@
 /*     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 string of allowed characters in $name
+/*     expansions. Illegal characters are replaced by underscores.
 /* DIAGNOSTICS
 /*     Fatal errors: out of memory.
 /* SEE ALSO
@@ -61,7 +77,8 @@
 
 /* Utility library. */
 
-#include <htable.h>
+#include <vstring.h>
+#include <mac_expand.h>
 
 /* Global library */
 
 
 #include "local.h"
 
-/* local_expand - set up macro expansion attributes */
+typedef struct {
+    LOCAL_STATE *state;
+    USER_ATTR *usr_attr;
+    int     status;
+} LOCAL_EXP;
+
+/* local_expand_lookup - mac_expand() lookup routine */
+
+static const char *local_expand_lookup(const char *name, int mode, char *ptr)
+{
+    LOCAL_EXP *local = (LOCAL_EXP *) ptr;
+
+#define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0)
+
+    if (STREQ(name, "user")) {
+       return (local->usr_attr->logname);
+    } else if (STREQ(name, "home")) {
+       return (local->usr_attr->home);
+    } else if (STREQ(name, "shell")) {
+       return (local->usr_attr->shell);
+    } else if (STREQ(name, "domain")) {
+       return (local->state->msg_attr.domain);
+    } else if (STREQ(name, "mailbox")) {
+       return (local->state->msg_attr.local);
+    } else if (STREQ(name, "recipient")) {
+       return (local->state->msg_attr.recipient);
+    } else if (STREQ(name, "extension")) {
+       if (mode == MAC_EXP_MODE_USE)
+           local->status |= LOCAL_EXP_EXTENSION_MATCHED;
+       return (local->state->msg_attr.extension);
+    } else if (STREQ(name, "recipient_delimiter")) {
+       return (*var_rcpt_delim ? var_rcpt_delim : 0);
+    } else {
+       return (0);
+    }
+}
 
-HTABLE *local_expand(LOCAL_STATE state, USER_ATTR usr_attr)
+/* local_expand - expand message delivery attributes */
+
+int     local_expand(VSTRING *result, const char *pattern,
+               LOCAL_STATE *state, USER_ATTR *usr_attr, const char *filter)
 {
-    HTABLE *expand_attr;
-
-    /*
-     * Impedance matching between the local delivery agent data structures
-     * and the mac_expand() interface. The CPU cycles wasted will be
-     * negligible.
-     */
-    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);
+    LOCAL_EXP local;
+    int     expand_status;
+
+    local.state = state;
+    local.usr_attr = usr_attr;
+    local.status = 0;
+    expand_status = mac_expand(result, pattern, MAC_EXP_FLAG_NONE,
+                              filter, local_expand_lookup, (char *) &local);
+    return (local.status | expand_status);
 }
index 9680f2f8cdb810d63c6ccb712c3dc28386830018..252071f8461a2b9dcbc0ca030edc1b5bc0a62cf3 100644 (file)
@@ -81,6 +81,7 @@
 #include <bounce.h>
 #include <mail_params.h>
 #include <split_addr.h>
+#include <ext_prop.h>
 
 /* Application-specific. */
 
@@ -113,15 +114,19 @@ static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr)
 
     /*
      * Otherwise, alias expansion has highest precedence. First look up the
-     * full localpart, then the bare user.
+     * full localpart, then the bare user. Obey the address extension
+     * propagation policy.
      */
     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 (state.msg_attr.extension != 0) {
+       if (local_ext_prop_mask & EXT_PROP_ALIAS)
+           state.msg_attr.unmatched = state.msg_attr.extension;
        if (deliver_alias(state, usr_attr, state.msg_attr.user, &status))
            return (status);
+       state.msg_attr.unmatched = state.msg_attr.extension;
+    }
 
     /*
      * Special case for mail locally forwarded or aliased to a different
@@ -202,7 +207,7 @@ int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
     if (*var_rcpt_delim) {
        state.msg_attr.extension =
            split_addr(state.msg_attr.local, *var_rcpt_delim);
-       if (strchr(state.msg_attr.extension, '/')) {
+       if (state.msg_attr.extension && strchr(state.msg_attr.extension, '/')) {
            msg_warn("%s: address with illegal extension: %s",
                     state.msg_attr.queue_id, state.msg_attr.local);
            state.msg_attr.extension = 0;
@@ -222,6 +227,7 @@ int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
      * Clean up.
      */
     myfree(state.msg_attr.local);
+    myfree(state.msg_attr.user);
 
     return (rcpt_stat);
 }
index 0689289a18d7f8bb7880ecc149456cfb14c88ec2..c24ef79f101be8d8182fd66f5e9a555268253290 100644 (file)
 /*     fallback_transport parameter, delivery is delegated to the
 /*     named transport.
 /* .IP \(bu
-/*     If an alternative address is specified via the luser_relay 
+/*     If an alternative address is specified via the luser_relay
 /*     configuration parameter, mail is forwarded to that address.
 /* .IP \(bu
 /*     Otherwise the recipient is bounced.
 /* .PP
-/*     If the luser_relay parameter specifies a @domain, the entire
-/*     original recipient localpart is prepended. For example: with
-/*     "luser_relay = @some.where", unknown+foo becomes
-/*     unknown+foo@some.where.
-/*
-/*     Otherwise, the luser_relay parameter can specify any number of
-/*     destinations that are valid in an alias file or in a .forward file.
-/*     For example, a destination could be an address, a "|command" or
-/*     a /file/name. The luser_relay feature is treated as an alias, and
-/*     the usual restrictions for command and file destinations apply.
-/*
-/*     If the luser_relay destination is a mail address, and the
-/*     recipient delimiter has been defined, the entire original recipient
-/*     localpart is appended as an address extension. For example: with
-/*     "luser_relay = someone@some.where", unknown+foo becomes
-/*     someone+unknown+foo@some.where.
+/*     The luser_relay parameter is subjected to $name expansion of
+/*     the standard message attributes: $user, $home, $shell, $domain,
+/*     $recipient, $mailbox, $extension, $recipient_delimiter, not
+/*     all of which actually make sense.
 /*
 /*     Arguments:
 /* .IP state
@@ -68,6 +56,7 @@
 #include <msg.h>
 #include <stringops.h>
 #include <mymalloc.h>
+#include <vstring.h>
 
 /* Global library. */
 
@@ -86,8 +75,7 @@ int     deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr)
 {
     char   *myname = "deliver_unknown";
     int     status;
-    char   *dest;
-    char   *saved_extension;
+    VSTRING *expand_luser;
 
     /*
      * Make verbose logging easier to understand.
@@ -120,60 +108,16 @@ int     deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr)
                              "unknown user: \"%s\"", state.msg_attr.local));
 
     /*
-     * EXTERNAL LOOP CONTROL
-     * 
-     * Set the delivered message attribute to the recipient, so that this
-     * message will list the correct forwarding address.
-     */
-    state.msg_attr.delivered = state.msg_attr.recipient;
-
-    /*
-     * DELIVERY POLICY
-     * 
-     * The luser relay is just another alias. Update the expansion type
-     * attribute, so we can decide if deliveries to |command and /file/name
-     * are allowed at all.
-     */
-    state.msg_attr.exp_type = EXPAND_TYPE_ALIAS;
-
-    /*
-     * DELIVERY RIGHTS
-     * 
-     * What rights to use for |command and /file/name deliveries? The luser
-     * relay is a root-owned alias, so we use default rights.
-     */
-    RESET_USER_ATTR(usr_attr, state.level);
-
-    /*
-     * If the luser destination is specified as @domain, prepend the
-     * localpart. The local resolver will append the optional address
-     * extension, so we don't do that here.
-     */
-    if (*var_luser_relay == '@') {             /* @domain */
-       dest = concatenate(state.msg_attr.local, var_luser_relay, (char *) 0);
-       status = deliver_token_string(state, usr_attr, dest, (int *) 0);
-       myfree(dest);
-    }
-
-    /*
-     * Otherwise, optionally arrange for the local resolver to append the
-     * entire localpart, including the optional address extension, to the
-     * destination localpart.
+     * Subject the luser_relay address to $name expansion, disable
+     * propagation of unmatched address extension, and re-inject the address
+     * into the delivery machinery. Donot give special treatment to "|stuff"
+     * or /stuff.
      */
-    else {                                     /* other */
-       if ((saved_extension = state.msg_attr.extension) != 0)
-           state.msg_attr.extension = concatenate(state.msg_attr.local,
-                                                  var_rcpt_delim,
-                                                  state.msg_attr.extension,
-                                                  (char *) 0);
-       else if (*var_rcpt_delim)
-           state.msg_attr.extension = state.msg_attr.local;
-       status = deliver_token_string(state, usr_attr, var_luser_relay,
-                                     (int *) 0);
-       if (saved_extension != 0)
-           myfree(state.msg_attr.extension);
-       state.msg_attr.extension = saved_extension;
-    }
+    state.msg_attr.unmatched = 0;
+    expand_luser = vstring_alloc(100);
+    local_expand(expand_luser, var_luser_relay, &state, &usr_attr, (char *) 0);
+    status = deliver_resolve_addr(state, usr_attr, vstring_str(expand_luser));
+    vstring_free(expand_luser);
 
     /*
      * Done.
index bfa8abb164a2170cce0c845ffcb69cba0fa0e02f..7c9c5dea04f7b8191559658c7a1998f3b3a89cb3 100644 (file)
@@ -48,6 +48,10 @@ extension), \fB$domain\fR (recipient domain), \fBmailbox\fR
 \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 the shell are replaced by underscores. The list of legal
+characters is specified with the \fBcommand_expansion_filter\fR
+configuration parameter.
 
 An alias or ~/.\fBforward\fR file may list any combination of external
 commands, destination file names, \fB:include:\fR directives, or
@@ -102,7 +106,7 @@ Mailbox delivery can be delegated to an external command specified
 with the \fBmailbox_command\fR configuration parameter. The command
 executes with the privileges of the recipient user (exception: in
 case of delivery as root, the command executes with the privileges
-of \fBdefault_user\fR).
+of \fBdefault_privs\fR).
 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),
@@ -110,9 +114,11 @@ username), \fB$home\fR (recipient home directory), \fB$shell\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. In the result
-of \fIname\fR expansion, characters that have special meaning to
-the shell are censored and replaced by underscores.
+\fIvalue\fR when \fI$name\fR is (is not) defined.
+In the result of \fIname\fR expansion, characters that have special
+meaning to the shell are replaced by underscores. The list of legal
+characters is specified with the \fBforward_expansion_filter\fR
+configuration parameter.
 
 Mailbox delivery can be delegated to alternative message transports
 specified in the \fBmaster.cf\fR file.
@@ -338,8 +344,14 @@ The default limit is taken from the
 Restrict the usage of mail delivery to external command.
 .IP \fBallow_mail_to_files\fR
 Restrict the usage of mail delivery to external file.
+.IP \fBcommand_expansion_filter\fR
+What characters are allowed to appear in $name expansions
+of mailbox_command.
 .IP \fBdefault_privs\fR
 Default rights for delivery to external file or command.
+.IP \fBforward_expansion_filter\fR
+What characters are allowed to appear in $name expansions
+of forward_path.
 .SH HISTORY
 .na
 .nf
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index c61005f39dffb69a776186ca44f5d7c781cdc4b1..4aa7bbdbd38242ef4af5a3f2d99be3c5c014ee61 100644 (file)
@@ -251,7 +251,7 @@ typedef struct {
 
 /* parse_callback - callback for mac_parse() */
 
-static void parse_callback(int type, VSTRING *buf, char *context)
+static int parse_callback(int type, VSTRING *buf, char *context)
 {
     int    *expand_flag = (int *) context;
 
@@ -268,6 +268,7 @@ static void parse_callback(int type, VSTRING *buf, char *context)
        else if (strcmp(vstring_str(buf), PIPE_DICT_MAILBOX) == 0)
            *expand_flag |= PIPE_FLAG_MAILBOX;
     }
+    return (0);
 }
 
 /* expand_argv - expand macros in the argument vector */
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index ce21b568dc78716588719c44c5618d1dccb0827c..4972290d93520c3a44210f3c97b3b032e6294f67 100644 (file)
@@ -42,6 +42,7 @@
 -THTABLE_INFO
 -TINET_ADDR_LIST
 -TINT_TABLE
+-TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
 -TMAC_HEAD
index 95603e95a79e1294839e58db5785edeabbd8f860..8ad363f7b29bd95a56e2a42d32e682b25d673359 100644 (file)
@@ -256,7 +256,7 @@ valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
        rm -f valid_hostname.tmp
 
 mac_expand_test: mac_expand mac_expand.in mac_expand.ref
-       ./mac_expand <mac_expand.in >mac_expand.tmp
+       ./mac_expand <mac_expand.in >mac_expand.tmp 2>&1
        diff mac_expand.ref mac_expand.tmp
        rm -f mac_expand.tmp
 
@@ -476,6 +476,7 @@ get_hostname.o: mymalloc.h
 get_hostname.o: msg.h
 get_hostname.o: valid_hostname.h
 get_hostname.o: get_hostname.h
+hattr.o: hattr.c
 htable.o: htable.c
 htable.o: sys_defs.h
 htable.o: mymalloc.h
@@ -544,7 +545,6 @@ mac_expand.o: msg.h
 mac_expand.o: vstring.h
 mac_expand.o: vbuf.h
 mac_expand.o: mymalloc.h
-mac_expand.o: htable.h
 mac_expand.o: mac_parse.h
 mac_expand.o: mac_expand.h
 mac_parse.o: mac_parse.c
index 899c6c50b6d61485efd5837ce4db02ecc4915588..4a836ba42806dd33a4a03d02ad1692237eb14086 100644 (file)
@@ -359,7 +359,7 @@ struct dict_eval_context {
 
 /* dict_eval_action - macro parser call-back routine */
 
-static void dict_eval_action(int type, VSTRING *buf, char *ptr)
+static int dict_eval_action(int type, VSTRING *buf, char *ptr)
 {
     struct dict_eval_context *ctxt = (struct dict_eval_context *) ptr;
     char   *myname = "dict_eval_action";
@@ -389,6 +389,7 @@ static void dict_eval_action(int type, VSTRING *buf, char *ptr)
     } else {
        vstring_strcat(ctxt->buf, STR(buf));
     }
+    return(0);
 }
 
 /* dict_eval - expand embedded dictionary references */
index 67e53d17e344b6da5cb1957cc6f837b34d314a80..2d0be6b7a22b08e733e717b81d37dd774207da6b 100644 (file)
@@ -107,7 +107,7 @@ struct dict_pcre_context {
  * Macro expansion callback - replace $0-${99} with strings cut from
  * matched string.
  */
-static void dict_pcre_action(int type, VSTRING *buf, char *ptr)
+static int dict_pcre_action(int type, VSTRING *buf, char *ptr)
 {
     struct dict_pcre_context *ctxt = (struct dict_pcre_context *) ptr;
     const char *pp;
@@ -120,17 +120,20 @@ static void dict_pcre_action(int type, VSTRING *buf, char *ptr)
                                 n, &pp);
        if (ret < 0) {
            if (ret == PCRE_ERROR_NOSUBSTRING)
-               msg_warn("regexp %s, line %d: replace index out of range",
+               msg_fatal("regexp %s, line %d: replace index out of range",
                         ctxt->dict_name, ctxt->lineno);
            else
-               msg_warn("regexp %s, line %d: pcre_get_substring error: %d",
+               msg_fatal("regexp %s, line %d: pcre_get_substring error: %d",
                         ctxt->dict_name, ctxt->lineno, ret);
-           return;
        }
+       if (*pp == 0)
+           return (MAC_PARSE_UNDEF);
        vstring_strcat(ctxt->buf, pp);
     } else
        /* Straight text - duplicate with no substitution */
        vstring_strcat(ctxt->buf, vstring_str(buf));
+
+    return (0);
 }
 
 /*
@@ -198,7 +201,9 @@ static const char *dict_pcre_lookup(DICT *dict, const char *name)
        ctxt.dict_name = dict_pcre->map;
        ctxt.lineno = pcre_list->lineno;
 
-       mac_parse(pcre_list->replace, dict_pcre_action, (char *) &ctxt);
+       if (mac_parse(pcre_list->replace, dict_pcre_action, (char *) &ctxt) & MAC_PARSE_ERROR)
+           msg_fatal("regexp map %s, line %d: bad replacement syntax",
+                     dict_pcre->map, pcre_list->lineno);
 
        VSTRING_TERMINATE(buf);
        return (vstring_str(buf));
index 9aeee007b1793f2ea59ae5b19dadfa5870d16d21..d42deef0f741473b5ea9aa84af74ba8ef07fa745 100644 (file)
@@ -100,7 +100,7 @@ static void dict_regexp_update(DICT *dict, const char *unused_name,
  * Macro expansion callback - replace $0-${99} with strings cut from
  * matched string.
  */
-static void dict_regexp_action(int type, VSTRING *buf, char *ptr)
+static int dict_regexp_action(int type, VSTRING *buf, char *ptr)
 {
     struct dict_regexp_context *ctxt = (struct dict_regexp_context *) ptr;
     DICT_REGEXP_RULE *rule = ctxt->rule;
@@ -109,14 +109,12 @@ static void dict_regexp_action(int type, VSTRING *buf, char *ptr)
 
     if (type == MAC_PARSE_VARNAME) {
        n = atoi(vstring_str(buf));
-       if (n >= dict->nmatch) {
-           msg_warn("regexp %s, line %d: replace index out of range",
-                    dict->map, rule->lineno);
-           return;
-       }
+       if (n >= dict->nmatch)
+           msg_fatal("regexp %s, line %d: replacement index out of range",
+                     dict->map, rule->lineno);
        if (dict->pmatch[n].rm_so < 0 ||
            dict->pmatch[n].rm_so == dict->pmatch[n].rm_eo) {
-           return;                             /* empty string or not
+           return (MAC_PARSE_UNDEF);           /* empty string or not
                                                 * matched */
        }
        vstring_strncat(ctxt->buf, ctxt->subject + dict->pmatch[n].rm_so,
@@ -124,6 +122,7 @@ static void dict_regexp_action(int type, VSTRING *buf, char *ptr)
     } else
        /* Straight text - duplicate with no substitution */
        vstring_strcat(ctxt->buf, vstring_str(buf));
+    return (0);
 }
 
 /*
@@ -175,7 +174,9 @@ static const char *dict_regexp_lookup(DICT *dict, const char *name)
            ctxt.rule = rule;
            ctxt.dict = dict_regexp;
 
-           mac_parse(rule->replace, dict_regexp_action, (char *) &ctxt);
+           if (mac_parse(rule->replace, dict_regexp_action, (char *) &ctxt) & MAC_PARSE_ERROR)
+               msg_fatal("regexp map %s, line %d: bad replacement syntax.",
+                         dict_regexp->map, rule->lineno);
 
            VSTRING_TERMINATE(buf);
            return (vstring_str(buf));
index 23f0756ab422a9f6403f3f4ce5410756c8cddf90..23c239b05606245c6ade833d5273a1b4b0cfae66 100644 (file)
@@ -6,18 +6,21 @@
 /* SYNOPSIS
 /*     #include <mac_expand.h>
 /*
-/*     int     mac_expand(result, pattern, flags, key, ...)
+/*     int     mac_expand(result, pattern, flags, filter, lookup, context)
 /*     VSTRING *result;
 /*     const char *pattern;
 /*     int     flags;
-/*     int     key;
+/*     const char *filter;
+/*     const char *lookup(const char *key, int mode, char *context)
+/*     char    *context;
 /* DESCRIPTION
 /*     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".
+/*
+/*     In the text below, an attribute is considered "undefined" when its
+/*     value is a null pointer.  In all other cases the attribute is
+/*     considered "defined".
 /*
 /*     The following expansions are implemented:
 /* .IP "$name, ${name}, $(name)"
 /*     $name expansion.  Otherwise, the expansion is empty.
 /* .IP "${name:text}, $(name:text)"
 /*     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.
+/*     the expansion is the given text, subjected to another iteration
+/*     of $name expansion.  Otherwise, the expansion is empty.
 /* .PP
-/*     mac_expand() replaces $name etc. instances in \fBpattern\fR
-/*     and stores the result into \fBresult\fR.
-/*
 /*     Arguments:
 /* .IP result
 /*     Storage for the result of expansion. The result is truncated
 /*     Expand $name recursively.
 /* .RE
 /*     The constant MAC_EXP_FLAG_NONE specifies a manifest null value.
-/* .IP key
-/*     The attribute information is specified as a null-terminated list.
-/*     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 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 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.
+/* .IP filter
+/*     A null pointer, or a null-terminated array of characters that
+/*     are allowed to appear in an expansion. Illegal characters are
+/*     replaced by underscores.
+/* .IP lookup
+/*     The attribute lookup routine. Arguments are: the attribute name,
+/*     MAC_EXP_MODE_TEST to test the existence of the named attribute
+/*     or MAC_EXP_MODE_USE to use the value of the named attribute,
+/*     and the caller context that was given to mac_expand(). A null
+/*     result means that the requested attribute was not defined.
+/* .IP context
+/*     Caller context that is passed on to the attribute lookup routine.
 /* DIAGNOSTICS
 /*     Fatal errors: out of memory.  Warnings: syntax errors, unreasonable
 /*     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
+/* .IP MAC_PARSE_ERROR
+/*     A syntax error was found in \fBpattern\fR, or some macro had
 /*     an unreasonable nesting depth.
-/* .IP MAC_EXP_FLAG_UNDEF
-/*     The pattern contains a reference to an undefined attribute.
+/* .IP MAC_PARSE_UNDEF
+/*     A macro was expanded but not defined.
 /* SEE ALSO
 /*     mac_parse(3) locate macro references in string.
 /* LICENSE
 #include <msg.h>
 #include <vstring.h>
 #include <mymalloc.h>
-#include <htable.h>
 #include <mac_parse.h>
 #include <mac_expand.h>
 
  /*
-  * 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.
+  * Little helper structure.
   */
-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 {
+typedef struct {
     VSTRING *result;                   /* result buffer */
-    const char *filter;                        /* safe character list */
-    int     clobber;                   /* safe replacement */
-    int     flags;                     /* findings, features */
+    int     flags;                     /* features */
+    const char *filter;                        /* character filter */
+    MAC_EXP_LOOKUP_FN lookup;          /* lookup routine */
+    char   *context;                   /* caller context */
+    int     status;                    /* findings */
     int     level;                     /* nesting level */
-    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_EXP;
 
 /* mac_expand_callback - callback for mac_parse */
 
-static void mac_expand_callback(int type, VSTRING *buf, char *ptr)
+static int mac_expand_callback(int type, VSTRING *buf, char *ptr)
 {
     char   *myname = "mac_expand_callback";
     MAC_EXP *mc = (MAC_EXP *) ptr;
-    HTABLE_INFO *ht;
-    char   *text;
+    int     lookup_mode;
+    const char *text;
     char   *cp;
     int     ch;
-    int     n;
+    int     len;
 
     /*
      * Sanity check.
      */
     if (mc->level++ > 100) {
        msg_warn("unreasonable macro call nesting: \"%s\"", vstring_str(buf));
-       mc->flags |= MAC_EXP_FLAG_ERROR;
-       return;
+       mc->status |= MAC_PARSE_ERROR;
     }
+    if (mc->status & MAC_PARSE_ERROR)
+       return (mc->status);
 
     /*
      * $Name reference.
@@ -170,28 +143,27 @@ static void mac_expand_callback(int type, VSTRING *buf, char *ptr)
         * without doing damage. We do not have enough context to produce an
         * understandable error message, so don't try.
         */
-       for (cp = vstring_str(buf); (ch = *cp) != 0; cp++) {
+       for (cp = vstring_str(buf); /* void */ ; cp++) {
+           if ((ch = *cp) == 0) {
+               lookup_mode = MAC_EXP_MODE_USE;
+               break;
+           }
            if (ch == '?' || ch == ':') {
                *cp++ = 0;
+               lookup_mode = MAC_EXP_MODE_TEST;
                break;
            }
            if (!ISALNUM(ch) && ch != '_') {
                msg_warn("macro name syntax error: \"%s\"", vstring_str(buf));
-               mc->flags |= MAC_EXP_FLAG_ERROR;
-               return;
+               mc->status |= MAC_PARSE_ERROR;
+               return (mc->status);
            }
        }
 
        /*
         * Look up the named parameter.
         */
-       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;
-           }
-       }
+       text = mc->lookup(vstring_str(buf), lookup_mode, mc->context);
 
        /*
         * Perform the requested substitution.
@@ -207,30 +179,22 @@ static void mac_expand_callback(int type, VSTRING *buf, char *ptr)
            break;
        default:
            if (text == 0) {
-               mc->flags |= MAC_EXP_FLAG_UNDEF;
-               break;
-           }
-           if (mc->filter) {
-               vstring_strcpy(buf, text);
-               text = vstring_str(buf);
-               for (cp = text; (cp += strspn(cp, mc->filter))[0]; /* void */ )
-                   *cp++ = mc->clobber;
-           }
-           if (mc->flags & MAC_EXP_FLAG_RECURSE)
+               mc->status |= MAC_PARSE_UNDEF;
+           } else if (*text == 0) {
+                /* void */ ;
+           } else if (mc->flags & MAC_EXP_FLAG_RECURSE) {
                mac_parse(text, mac_expand_callback, (char *) mc);
-           else
+           } else {
+               len = VSTRING_LEN(mc->result);
                vstring_strcat(mc->result, text);
+               if (mc->filter) {
+                   cp = vstring_str(mc->result) + len;
+                   while (*(cp += strspn(cp, mc->filter)))
+                       *cp++ = '_';
+               }
+           }
            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++;
-       }
     }
 
     /*
@@ -249,101 +213,32 @@ static void mac_expand_callback(int type, VSTRING *buf, char *ptr)
                 text ? text : "(undef)");
 
     mc->level--;
-}
-
-/* mac_expand_addtable - add table to expansion context */
 
-static MAC_EXP *mac_expand_addtable(MAC_EXP *mc, HTABLE *table, int status)
-{
-    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);
+    return (mc->status);
 }
 
 /* mac_expand - expand $name instances */
 
-int     mac_expand(VSTRING *result, const char *pattern, int flags, int key,...)
+int     mac_expand(VSTRING *result, const char *pattern, int flags,
+                          const char *filter,
+                          MAC_EXP_LOOKUP_FN lookup, char *context)
 {
-    MAC_EXP *mc;
-    va_list ap;
-    char   *name;
-    char   *value;
-    HTABLE *table;
-    HTABLE_INFO *ht;
+    MAC_EXP mc;
     int     status;
 
     /*
-     * Initialize.
-     */
-    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 (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 *);
-           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 *);
-           mc = mac_expand_addtable(mc, table, MAC_EXP_STAT_EXTERN);
-           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;
-       case MAC_EXP_ARG_RECORD:
-           mc->record = va_arg(ap, HTABLE *);
-           break;
-       }
-    }
-    va_end(ap);
-
-    /*
-     * Do the substitutions.
+     * Bundle up the request and do the substitutions.
      */
+    mc.result = result;
+    mc.flags = flags;
+    mc.filter = filter;
+    mc.lookup = lookup;
+    mc.context = context;
+    mc.status = 0;
+    mc.level = 0;
     VSTRING_RESET(result);
-    mac_parse(pattern, mac_expand_callback, (char *) mc);
+    status = mac_parse(pattern, mac_expand_callback, (char *) &mc);
     VSTRING_TERMINATE(result);
-    status = (mc->flags & MAC_EXP_FLAG_OUTMASK);
-
-    /*
-     * Clean up.
-     */
-    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);
 }
@@ -354,9 +249,17 @@ int     mac_expand(VSTRING *result, const char *pattern, int flags, int key,...)
   * This code certainly deserves a stand-alone test program.
   */
 #include <stringops.h>
+#include <htable.h>
 #include <vstream.h>
 #include <vstring_vstream.h>
 
+static const char *lookup(const char *name, int unused_mode, char *context)
+{
+    HTABLE *table = (HTABLE *) context;
+
+    return (htable_find(table, name));
+}
+
 int     main(int unused_argc, char **unused_argv)
 {
     VSTRING *buf = vstring_alloc(100);
@@ -375,6 +278,8 @@ int     main(int unused_argc, char **unused_argv)
         * Read a block of definitions, terminated with an empty line.
         */
        while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
+           vstream_printf("<< %s\n", vstring_str(buf));
+           vstream_fflush(VSTREAM_OUT);
            if (VSTRING_LEN(buf) == 0)
                break;
            cp = vstring_str(buf);
@@ -387,13 +292,14 @@ int     main(int unused_argc, char **unused_argv)
         * Read a block of patterns, terminated with an empty line or EOF.
         */
        while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
+           vstream_printf("<< %s\n", vstring_str(buf));
+           vstream_fflush(VSTREAM_OUT);
            if (VSTRING_LEN(buf) == 0)
                break;
            cp = vstring_str(buf);
            VSTRING_RESET(result);
            stat = mac_expand(result, vstring_str(buf), MAC_EXP_FLAG_NONE,
-                             MAC_EXP_ARG_TABLE, table,
-                             MAC_EXP_ARG_END);
+                             (char *) 0, lookup, (char *) table);
            vstream_printf("stat=%d result=%s\n", stat, vstring_str(result));
            vstream_fflush(VSTREAM_OUT);
        }
index cf61b686efc588f9eec33284fca4c3f7553d89da..5ae6b5b99ab41d372b8620cad5dab96f0f38459c 100644 (file)
   * Utility library.
   */
 #include <vstring.h>
+#include <mac_parse.h>
 
  /*
-  * External interface.
+  * Features.
   */
-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_FLAG_RECURSE   (1<<0)
 
-#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
+ /*
+  * Real lookup or just a test?
+  */
+#define MAC_EXP_MODE_TEST      (0)
+#define MAC_EXP_MODE_USE       (1)
 
-extern MAC_EXP *mac_expand_update(MAC_EXP *, int,...);
-extern int mac_expand_use(MAC_EXP *, VSTRING *, const char *, int);
-extern void mac_expand_free(MAC_EXP *);
+typedef const char *(*MAC_EXP_LOOKUP_FN)(const char *, int, char *);
 
-extern int mac_expand(VSTRING *, const char *, int, int,...);
+extern int mac_expand(VSTRING *, const char *, int, const char *, MAC_EXP_LOOKUP_FN, char *);
 
 /* LICENSE
 /* .ad
index 0fb6cea984cf394f1ec0fb4d01d08bca0d478492..08e1d87eae77b1a71b158515fad11fb8df6077ee 100644 (file)
@@ -1,13 +1,33 @@
-stat=1 result=name 1 defined, |name1-value||
+<< name1 = name1-value
+<< name2 =
+<< 
+<< ${name1?name 1 defined, |$name1|$name2|}
+stat=2 result=name 1 defined, |name1-value||
+<< ${name1:name 1 undefined, |$name1|$name2|}
 stat=0 result=
+<< ${name2?name 2 defined, |$name1|$name2|}
 stat=0 result=
-stat=1 result=name 2 undefined, |name1-value||
-stat=1 result=|name1-value||
-stat=0 result=name1-value
-stat=4 result=
+<< ${name2:name 2 undefined, |$name1|$name2|}
+stat=2 result=name 2 undefined, |name1-value||
+<< |$name1|$name2|
+stat=2 result=|name1-value||
+<< $(name1
+unknown: warning: truncated macro reference: "$(name1"
+stat=1 result=name1-value
+<< $(name )
+unknown: warning: macro name syntax error: "name "
+stat=1 result=
+<< 
 
+<< name2 = name2-value
+<< 
+<< ${name1?name 1 defined, |$name1|$name2|}
 stat=0 result=
-stat=1 result=name 1 undefined, ||name2-value|
-stat=1 result=name 2 defined, ||name2-value|
+<< ${name1:name 1 undefined, |$name1|$name2|}
+stat=2 result=name 1 undefined, ||name2-value|
+<< ${name2?name 2 defined, |$name1|$name2|}
+stat=2 result=name 2 defined, ||name2-value|
+<< ${name2:name 2 undefined, |$name1|$name2|}
 stat=0 result=
-stat=1 result=||name2-value|
+<< |$name1|$name2|
+stat=2 result=||name2-value|
index 30bee99cba5990450092e138d2bc23f0691af444..de655c579a9e9376ec675e23449836cae666cbb6 100644 (file)
@@ -6,14 +6,15 @@
 /* SYNOPSIS
 /*     #include <mac_parse.h>
 /*
-/*     void    mac_parse(string, action, context)
+/*     int     mac_parse(string, action, context)
 /*     const char *string;
-/*     void    (*action)(int type, VSTRING *buf, char *context);
+/*     int     (*action)(int type, VSTRING *buf, char *context);
 /* DESCRIPTION
-/*     This module recognizes macro references in null-terminated
-/*     strings.  Macro references have the form $name, $(name) or
-/*     ${name}. A macro name consists of alphanumerics and/or
-/*     underscore. Other text is treated as literal text.
+/*     This module recognizes macro expressions in null-terminated
+/*     strings.  Macro expressions have the form $name, $(text) or
+/*     ${text}. A macro name consists of alphanumerics and/or
+/*     underscore. Text other than macro expressions is treated
+/*     as literal text.
 /*
 /*     mac_parse() breaks up its string argument into macro references
 /*     and other text, and invokes the \fIaction\fR routine for each item
 /* .IP MAC_PARSE_LITERAL
 /*     The text in \fIbuf\fR is literal text.
 /* .IP MAC_PARSE_VARNAME
-/*     The text in \fIbuf\fR is a macro name.
+/*     The text in \fIbuf\fR is a macro expression.
+/* .PP
+/*     The action routine result value is the bit-wise OR of zero or more
+/*     of the following:
+/* .IP MAC_PARSE_ERROR
+/*     A parsing error was detected.
+/* .IP MAC_PARSE_UNDEF
+/*     A macro was expanded but not defined.
 /* SEE ALSO
 /*     dict(3) dictionary interface.
 /* DIAGNOSTICS
 /*     Fatal errors: out of memory. malformed macro name.
+/*
+/*     The result value is the bit-wise OR of zero or more of the
+/*     following:
+/* .IP MAC_PARSE_ERROR
+/*     A parsing error was detected.
+/* .IP MAC_PARSE_UNDEF
+/*     A macro was expanded but not defined.
 /* LICENSE
 /* .ad
 /* .fi
   * Helper macro for consistency. Null-terminate the temporary buffer,
   * execute the action, and reset the temporary buffer for re-use.
   */
-#define MAC_PARSE_ACTION(type, buf, context) \
+#define MAC_PARSE_ACTION(status, type, buf, context) \
        { \
            VSTRING_TERMINATE(buf); \
-           action(type, buf, context); \
+           status |= action(type, buf, context); \
            VSTRING_RESET(buf); \
        }
 
 /* mac_parse - split string into literal text and macro references */
 
-void    mac_parse(const char *value, MAC_PARSE_FN action, char *context)
+int     mac_parse(const char *value, MAC_PARSE_FN action, char *context)
 {
     char   *myname = "mac_parse";
     VSTRING *buf = vstring_alloc(1);   /* result buffer */
@@ -73,6 +88,7 @@ void    mac_parse(const char *value, MAC_PARSE_FN action, char *context)
     static char open_paren[] = "({";
     static char close_paren[] = ")}";
     int     level;
+    int     status = 0;
 
 #define SKIP(start, var, cond) \
         for (var = start; *var && (cond); var++);
@@ -89,7 +105,7 @@ void    mac_parse(const char *value, MAC_PARSE_FN action, char *context)
            vp += 2;
        } else {                                /* found bare $ */
            if (VSTRING_LEN(buf) > 0)
-               MAC_PARSE_ACTION(MAC_PARSE_LITERAL, buf, context);
+               MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context);
            vp += 1;
            pp = open_paren;
            if (*vp == *pp || *vp == *++pp) {   /* ${x} or $(x) */
@@ -98,6 +114,7 @@ void    mac_parse(const char *value, MAC_PARSE_FN action, char *context)
                for (ep = vp; level > 0; ep++) {
                    if (*ep == 0) {
                        msg_warn("truncated macro reference: \"%s\"", value);
+                       status |= MAC_PARSE_ERROR;
                        break;
                    }
                    if (*ep == *pp)
@@ -112,18 +129,23 @@ void    mac_parse(const char *value, MAC_PARSE_FN action, char *context)
                vstring_strncat(buf, vp, ep - vp);
                vp = ep;
            }
-           if (VSTRING_LEN(buf) == 0)
+           if (VSTRING_LEN(buf) == 0) {
+               status |= MAC_PARSE_ERROR;
                msg_warn("empty macro name: \"%s\"", value);
-           MAC_PARSE_ACTION(MAC_PARSE_VARNAME, buf, context);
+               break;
+           }
+           MAC_PARSE_ACTION(status, MAC_PARSE_VARNAME, buf, context);
        }
     }
-    if (VSTRING_LEN(buf) > 0)
-       MAC_PARSE_ACTION(MAC_PARSE_LITERAL, buf, context);
+    if (VSTRING_LEN(buf) > 0 && (status & MAC_PARSE_ERROR) == 0)
+       MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context);
 
     /*
      * Cleanup.
      */
     vstring_free(buf);
+
+    return (status);
 }
 
 #ifdef TEST
index 856fb98306793b6487fd883f20be72b5b1aa6496..1acbb60d58ef7ad56f66475fa7935018dd323b51 100644 (file)
 #define MAC_PARSE_LITERAL      1
 #define MAC_PARSE_VARNAME      2
 
-typedef void (*MAC_PARSE_FN)(int, VSTRING *, char *);
+#define MAC_PARSE_ERROR                (1<<0)
+#define MAC_PARSE_UNDEF                (1<<1)
+#define MAC_PARSE_USER         2       /* start user definitions */
 
-extern void mac_parse(const char *, MAC_PARSE_FN, char *);
+typedef int (*MAC_PARSE_FN)(int, VSTRING *, char *);
+
+extern int mac_parse(const char *, MAC_PARSE_FN, char *);
 
 /* LICENSE
 /* .ad