]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-19991116
authorWietse Venema <wietse@porcupine.org>
Tue, 16 Nov 1999 05:00:00 +0000 (00:00 -0500)
committerWietse Venema <wietse@porcupine.org>
Thu, 17 Jan 2013 23:09:46 +0000 (18:09 -0500)
27 files changed:
postfix/DEBUG_README
postfix/HISTORY
postfix/dns/Makefile.in
postfix/dns/dns_lookup.c
postfix/global/Makefile.in
postfix/global/local_transport.c [new file with mode: 0644]
postfix/global/local_transport.h [new file with mode: 0644]
postfix/global/mail_params.c
postfix/global/mail_params.h
postfix/global/mail_version.h
postfix/local/Makefile.in
postfix/local/resolve.c
postfix/master/master_ent.c
postfix/postalias/postalias.c
postfix/postconf/postconf.c
postfix/postmap/postmap.c
postfix/qmgr/qmgr_message.c
postfix/smtpd/Makefile.in
postfix/smtpd/smtpd_check.c
postfix/trivial-rewrite/resolve.c
postfix/util/dict.c
postfix/util/dict.h
postfix/util/dict_open.c
postfix/util/dict_pcre.c
postfix/util/dict_regexp.c
postfix/util/readlline.c
postfix/util/readlline.h

index c309f4263c1e433a1669f3ac3e9c34789cf64422..89ca9913621da2a027cc47fe5b5e8f5e35cfc81d 100644 (file)
@@ -43,6 +43,9 @@ 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.
 
+See the next section on how to automatically attach a program to
+a Postfix daemon.
+
 5 - Running daemon programs under an interactive debugger
 =========================================================
 
@@ -68,3 +71,48 @@ Stop and start the Postfix system.
 
 Whenever the suspect daemon process is started, a debugger window
 pops up and you can watch in detail what happens.
+
+6 - Unreasonable behavior
+=========================
+
+Sometimes the behavior exhibit by Postfix just does not match the
+source code. Why can a program deviate from the instructions given
+by its author? There are two possibilities.
+
+1 - The compiler has messed up.
+
+2 - The hardware has messed up.
+
+In both cases, the program being executed is not the program that
+was supposed to be executed, so anything can happen.
+
+Hardware-related failures happen erratically, and they usually do
+not reproduce after power cycling and rebooting the system.  There's
+little I can do about bad hardware.  Be sure to use hardware that
+at the very least can detect memory errors. Otherwise, Postfix will
+just be a sitting duck waiting to be hit by a bit error. Critical
+systems deserve real hardware.
+
+When a compiler messes up, the problem can be reproduced whenever
+the resulting program is run. Compiler errors are most likely to
+happen in the code optimizer. If a problem is reproducible across
+power cycles and system reboots, it can be worthwhile to rebuild
+Postfix with optimization disabled, and to see if optimization
+makes a difference.
+
+In order to compile Postfix with optimizations turned off:
+
+    % make tidy
+    % make makefiles OPT=
+
+This produces a set of Makefiles that do not request compiler
+optomization. 
+
+Once the makefiles are set up, build the software:
+
+    % make
+    % su
+    # make install
+
+And see if the problem reproduces. If the problem goes away, talk
+to your vendor.
index 9996bd4345538d724623c51796d91a41ad537988..5618544890b420c8c1bc70f40fdb587bb4ee2240 100644 (file)
@@ -3220,6 +3220,23 @@ Apologies for any names omitted.
        Feature: permit_auth_destination restriction based on code
        by Jesper Skriver @ skriver.dk.
 
-       Code cleanup: the transport table now can override local
-       deliveries. Postfix no longer uses the "empty next-hop
-       hostname hack" to remember that a destination is local.
+       Code cleanup: the transport table now can override all
+       deliveries, including local ones.
+
+19991116
+
+       Code cleanup: a new "local_transports" configuration
+       parameter explicitly lists all transports that deliver
+       mail locally. The first name listed there is the default
+       local transport.  This is the end of the "empty next-hop
+       hostname" hack to indicate that a destination is local.
+       Files:  trivial-rewrite/resolve.c, global/local_transport.[hc]
+
+       Feature: "postconf -m" shows what lookup table types are
+       available.  Code by Scott Cotton, Internet Consultants
+       Group, Inc.
+
+       Feature: "postconf -e" edits any number of main.cf parameters.
+       The edit is done on a copy, and the copy is renamed into
+       the place of the original. File: postconf/postconf.c,
+       util/readlline.[hc].
index 5deff368a7b94176f1b4bcdafae1c4478fc7919a..be767bef2770b93732d42b6a1306aa5a722fd8c1 100644 (file)
@@ -75,6 +75,7 @@ dns_lookup.o: ../include/vstring.h
 dns_lookup.o: ../include/vbuf.h
 dns_lookup.o: ../include/msg.h
 dns_lookup.o: ../include/valid_hostname.h
+dns_lookup.o: ../include/stringops.h
 dns_lookup.o: dns.h
 dns_rr.o: dns_rr.c
 dns_rr.o: ../include/sys_defs.h
index e548f2c0fa03fcbdd1741319f20a8b065708597c..19e809dd25f81940cbf534cd29b186684f2baaae 100644 (file)
@@ -247,7 +247,7 @@ static int dns_get_fixed(unsigned char *pos, DNS_FIXED *fixed)
 static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos,
                                  char *rr_name, DNS_FIXED *fixed)
 {
-    char    temp[DNS_NAME_LEN];
+    unsigned char temp[DNS_NAME_LEN];
     int     data_len;
     unsigned pref = 0;
     unsigned char *src;
index 25c29af3b1bd85bafca416cd6c3c17a508b06e1a..e4c6889ce0db9365e102d31dcb5f336db2d3aa76 100644 (file)
@@ -2,7 +2,8 @@ SHELL   = /bin/sh
 SRCS   = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
        debug_peer.c debug_process.c defer.c deliver_completed.c \
        deliver_flock.c deliver_pass.c deliver_request.c domain_list.c \
-       dot_lockfile.c file_id.c header_opts.c is_header.c mail_addr.c \
+       dot_lockfile.c dot_lockfile_as.c ext_prop.c file_id.c \
+       header_opts.c is_header.c local_transport.c mail_addr.c \
        mail_addr_crunch.c mail_addr_find.c mail_addr_map.c \
        mail_command_read.c mail_command_write.c mail_conf.c \
        mail_conf_bool.c mail_conf_int.c mail_conf_raw.c mail_conf_str.c \
@@ -16,12 +17,12 @@ 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 ext_prop.c \
-       dot_lockfile_as.c
+       tok822_resolve.c tok822_rewrite.c tok822_tree.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 \
-       dot_lockfile.o file_id.o header_opts.o is_header.o mail_addr.o \
+       dot_lockfile.o dot_lockfile_as.o ext_prop.o file_id.o \
+       header_opts.o is_header.o local_transport.o mail_addr.o \
        mail_addr_crunch.o mail_addr_find.o mail_addr_map.o \
        mail_command_read.o mail_command_write.o mail_conf.o \
        mail_conf_bool.o mail_conf_int.o mail_conf_raw.o mail_conf_str.o \
@@ -35,12 +36,12 @@ 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 ext_prop.o \
-       dot_lockfile_as.o
+       tok822_resolve.o tok822_rewrite.o tok822_tree.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 \
-       dot_lockfile.h file_id.h header_opts.h is_header.h mail_addr.h \
+       dot_lockfile.h dot_lockfile_as.h ext_prop.h file_id.h \
+       header_opts.h is_header.h local_transport.h mail_addr.h \
        mail_addr_crunch.h mail_addr_find.h mail_addr_map.h mail_conf.h \
        mail_copy.h mail_date.h mail_error.h mail_flush.h mail_open_ok.h \
        mail_params.h mail_proto.h mail_queue.h mail_run.h mail_scan_dir.h \
@@ -50,7 +51,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 ext_prop.h dot_lockfile_as.h
+       tok822.h
 TESTSRC        = rec2stream.c stream2rec.c recdump.c
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
        -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
@@ -62,7 +63,8 @@ LIB   = libglobal.a
 TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
        mail_addr_map mail_date maps mynetworks mypwd namadr_list \
        off_cvt quote_822_local rec2stream recdump resolve_clnt \
-       resolve_local rewrite_clnt stream2rec string_list tok822_parse
+       resolve_local rewrite_clnt stream2rec string_list tok822_parse \
+       local_transport
 
 LIBS   = ../lib/libutil.a
 LIB_DIR        = ../lib
@@ -187,6 +189,11 @@ string_list: $(LIB) $(LIBS)
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
        mv junk $@.o
 
+local_transport: $(LIB) $(LIBS)
+       mv $@.o junk
+       $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+       mv junk $@.o
+
 printfck: $(OBJS) $(PROG)
        rm -rf printfck
        mkdir printfck
@@ -361,6 +368,13 @@ header_opts.o: header_opts.h
 is_header.o: is_header.c
 is_header.o: ../include/sys_defs.h
 is_header.o: is_header.h
+local_transport.o: local_transport.c
+local_transport.o: ../include/sys_defs.h
+local_transport.o: ../include/msg.h
+local_transport.o: ../include/mymalloc.h
+local_transport.o: string_list.h
+local_transport.o: mail_params.h
+local_transport.o: local_transport.h
 mail_addr.o: mail_addr.c
 mail_addr.o: ../include/sys_defs.h
 mail_addr.o: ../include/stringops.h
diff --git a/postfix/global/local_transport.c b/postfix/global/local_transport.c
new file mode 100644 (file)
index 0000000..97f3f62
--- /dev/null
@@ -0,0 +1,134 @@
+/*++
+/* NAME
+/*     local_transport 3
+/* SUMMARY
+/*     determine if transport delivers locally
+/* SYNOPSIS
+/*     #include <local_transport.h>
+/*
+/*     const char *def_local_transport()
+/*
+/*     int     local_transport(transport)
+/*     const char *transport;
+/* DESCRIPTION
+/*     This module uses the information kept in the "local_transports"
+/*     configuration parameter, which lists the names of the default
+/*     local transport followed by zero or more other transports that
+/*     deliver locally.
+/*
+/*     def_local_transport() returns the name of the default local
+/*     transport, that is, the first transport name specified with 
+/*     the "local_transports" configuration parameter.
+/*
+/*     local_transport() determines if the named transport is listed
+/*     in the "local_transports" configuration parameter.
+/* SEE ALSO
+/*     resolve_local(3), see if address resolves locally.
+/* 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>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <string_list.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <local_transport.h>
+
+/* Application-specific */
+
+static STRING_LIST *local_transport_list;
+static char *local_transport_name;
+
+/* local_transport_init - initialize lookup table */
+
+static void local_transport_init(void)
+{
+    char   *myname = "local_transport_init";
+
+    /*
+     * Sanity check.
+     */
+    if (local_transport_list || local_transport_name)
+       msg_panic("local_transport_init: duplicate initialization");
+
+    /*
+     * Initialize.
+     */
+    local_transport_list = string_list_init(var_local_transports);
+    local_transport_name = mystrndup(var_local_transports,
+                                strcspn(var_local_transports, ", \t\r\n"));
+
+    /*
+     * Sanity check.
+     */
+    if (!local_transport(local_transport_name))
+       msg_panic("%s: unable to intialize", myname);
+}
+
+/* def_local_transport - determine default local transport */
+
+const char *def_local_transport(void)
+{
+
+    /*
+     * Initialize on the fly.
+     */
+    if (local_transport_list == 0)
+       local_transport_init();
+
+    /*
+     * Return the first transport listed.
+     */
+    return (local_transport_name);
+}
+
+/* local_transport - match address against list of local destinations */
+
+int     local_transport(const char *transport)
+{
+
+    /*
+     * Initialize on the fly.
+     */
+    if (local_transport_list == 0)
+       local_transport_init();
+
+    /*
+     * Compare the transport against the list of transports that are listed
+     * as delivering locally.
+     */
+    return (string_list_match(local_transport_list, transport));
+}
+
+#ifdef TEST
+
+#include <vstream.h>
+#include <mail_conf.h>
+
+int     main(int argc, char **argv)
+{
+    if (argc != 2)
+       msg_fatal("usage: %s transport", argv[0]);
+    mail_conf_read();
+    vstream_printf("%s\n", local_transport(argv[1]) ? "yes" : "no");
+    vstream_fflush(VSTREAM_OUT);
+}
+
+#endif
diff --git a/postfix/global/local_transport.h b/postfix/global/local_transport.h
new file mode 100644 (file)
index 0000000..d3defda
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _LOCAL_TRANSPORT_H_INCLUDED_
+#define _LOCAL_TRANSPORT_H_INCLUDED_
+
+/*++
+/* NAME
+/*     local_transport 3h
+/* SUMMARY
+/*     determine if transport delivers locally
+/* SYNOPSIS
+/*     #include <local_transport.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * External interface.
+  */
+extern const char *def_local_transport(void);
+extern int local_transport(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 00d15ef8f86187151ba30d843a3a5100fe0e2e84..7f65ef3dde0c39fb7e8b1fcdc89eda89119423b0 100644 (file)
@@ -57,6 +57,7 @@
 /*     time_t  var_starttime;
 /*     int     var_ownreq_special;
 /*     int     var_daemon_timeout;
+/*     char    *var_local_transports;
 /*
 /*     void    mail_params_init()
 /* DESCRIPTION
@@ -161,6 +162,7 @@ int     var_soft_bounce;
 time_t  var_starttime;
 int     var_ownreq_special;
 int     var_daemon_timeout;
+char   *var_local_transports;
 
 /* check_myhostname - lookup hostname and validate */
 
@@ -261,6 +263,7 @@ void    mail_params_init()
        VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0,
        VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0,
        VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 1,
+       VAR_LOCAL_TRANSP, DEF_LOCAL_TRANSP, &var_local_transports, 1, 0,
        0,
     };
     static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
index 53c2f1800cd86d923f4b66361a1989a95020605c..4ac0d40ee3b7b289b52aa692f2e0d12f937db448 100644 (file)
@@ -80,6 +80,13 @@ extern char *var_myhostname;
 #define VAR_MYDOMAIN           "mydomain"      /* my domain name */
 extern char *var_mydomain;
 
+ /*
+  * Transports that deliver locally. Order matters.
+  */
+#define VAR_LOCAL_TRANSP       "local_transports"
+#define DEF_LOCAL_TRANSP       "local"
+extern char *var_local_transports;
+
  /*
   * Where to send postmaster copies of bounced mail, and other notices.
   */
index 070732ad2d4abc923d796d675dac1065aa19ff4a..d2a5741a2159cc05ea8bd18e5b0fe0ed7bfd9570 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-19991115"
+#define DEF_MAIL_VERSION       "Snapshot-19991116"
 extern char *var_mail_version;
 
 /* LICENSE
index 738d12e57754869142b87651d82d251567a853c0..47c074ee52b2a0a0e1770a5e62847e74b8a51cfa 100644 (file)
@@ -375,6 +375,7 @@ resolve.o: ../include/resolve_clnt.h
 resolve.o: ../include/rewrite_clnt.h
 resolve.o: ../include/tok822.h
 resolve.o: ../include/mail_params.h
+resolve.o: ../include/local_transport.h
 resolve.o: local.h
 resolve.o: ../include/been_here.h
 resolve.o: ../include/deliver_request.h
index b6b1837b67d19d996ac342063d6f95c949be510b..2aa44a1ebafe43e09fa1b84c2452268bbc7d358c 100644 (file)
@@ -62,7 +62,7 @@
 #include <rewrite_clnt.h>
 #include <tok822.h>
 #include <mail_params.h>
-#include <resolve_local.h>
+#include <local_transport.h>
 
 /* Application-specific. */
 
@@ -139,7 +139,7 @@ int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
      * ugly code to force local recursive alias expansions on a host with no
      * authority over the local domain, but that code was just too unclean.
      */
-    if (resolve_local(STR(reply.nexthop))) {
+    if (local_transport(STR(reply.transport))) {
        status = deliver_recipient(state, usr_attr);
     } else {
        status = deliver_indirect(state);
index ae77491caf2dbd584011dd30a67eec9cd62b09bd..7f6b797488d130b1464d5c2c28a1defb776b6d31 100644 (file)
@@ -237,7 +237,7 @@ MASTER_SERV *get_master_ent()
      * Skip blank lines and comment lines.
      */
     do {
-       if (readlline(buf, master_fp, &master_line) == 0) {
+       if (readlline(buf, master_fp, &master_line, READLL_STRIPNL) == 0) {
            vstring_free(buf);
            vstring_free(junk);
            return (0);
index 93b8d5fe9dd1cee79ddb09607e15fb06cfef716c..79f7f40ea78e685ed7744244653c9974fafbe678 100644 (file)
@@ -164,7 +164,7 @@ static void postalias(char *map_type, char *path_name,
      * Add records to the database.
      */
     lineno = 0;
-    while (readlline(line_buffer, source_fp, &lineno)) {
+    while (readlline(line_buffer, source_fp, &lineno, READLL_STRIPNL)) {
 
        /*
         * Skip comments.
index d7d44c8719bd5be4159efa9bf08c8445e8bcbe2f..dbc99f3075332576eea90af13a4849c7a487b727 100644 (file)
@@ -5,21 +5,32 @@
 /*     Postfix configuration utility
 /* SYNOPSIS
 /* .fi
-/*     \fBpostconf\fR [\fB-c \fIconfig_dir\fR] [\fB-d\fR] [\fB-h\fR]
-/*             [\fB-n\fR] [\fB-v\fR] [\fIparameter ...\fR]
+/*     \fBpostconf\fR [\fB-dhnv\fR] [\fB-c \fIconfig_dir\fR]
+/*             [\fIparameter ...\fR]
+/*
+/*     \fBpostconf\fR [\fB-ev\fR] [\fB-c \fIconfig_dir\fR]
+/*             [\fIparameter=value ...\fR]
 /* DESCRIPTION
 /*     The \fBpostconf\fR command prints the actual value of
 /*     \fIparameter\fR (all known parameters by default), one
-/*     parameter per line.
+/*     parameter per line, changes its value, or prints other
+/*     information about the Postfix mail system.
 /*
 /*     Options:
 /* .IP "\fB-c \fIconfig_dir\fR"
 /*     The \fBmain.cf\fR configuration file is in the named directory.
 /* .IP \fB-d\fR
 /*     Print default parameter settings instead of actual settings.
+/* .IP \fB-e\fR
+/*     Edit the \fBmain.cf\fR configuration file. The file is copied
+/*     to a temporary file then renamed into place. Parameters and
+/*     values are specified on the command line. Use quotes in order
+/*     to protect shell metacharacters and whitespace.
 /* .IP \fB-h\fR
 /*     Show parameter values only, not the ``name = '' label
 /*     that normally precedes the value.
+/* .IP \fB-m\fR
+/*     List the names of all supported lookup table types.
 /* .IP \fB-n\fR
 /*     Print non-default parameter settings only.
 /* .IP \fB-v\fR
 
 #include <sys_defs.h>
 #include <sys/stat.h>
+#include <stdio.h>                     /* rename() */
 #include <pwd.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <ctype.h>
 
 #ifdef STRCASECMP_IN_STRINGS_H
 #include <strings.h>
 #include <dict.h>
 #include <safe.h>
 #include <mymalloc.h>
-#include <line_wrap.h>
+#include <argv.h>
+#include <split_at.h>
+#include <readlline.h>
+#include <myflock.h>
 
 /* Global library. */
 
 #include <mail_addr.h>
 
  /*
-  * What output we should generate.
+  * What we're supposed to be doing.
   */
 #define SHOW_NONDEF    (1<<0)          /* show non-default settings */
 #define SHOW_DEFS      (1<<1)          /* show default setting */
 #define SHOW_NAME      (1<<2)          /* show parameter name */
+#define SHOW_MAPS      (1<<3)          /* show map types */
+#define EDIT_MAIN      (1<<4)          /* edit main.cf */
 
  /*
   * Lookup table for in-core parameter info.
@@ -214,6 +232,131 @@ static const char *check_mynetworks(void)
     return (mynetworks());
 }
 
+/* edit_parameters - edit parameter file */
+
+static void edit_parameters(int argc, char **argv)
+{
+    char   *config_dir;
+    char   *path;
+    char   *temp;
+    VSTREAM *src;
+    VSTREAM *dst;
+    VSTRING *buf = vstring_alloc(100);
+    VSTRING *key = vstring_alloc(10);
+    char   *cp;
+    char   *value;
+    HTABLE *table;
+    int     first = 1;
+    struct cvalue {
+       char   *value;
+       int     found;
+    };
+    struct cvalue *cvalue;
+    HTABLE_INFO **ht_info;
+    HTABLE_INFO **ht;
+
+    /*
+     * Store command-line parameters for quick lookup.
+     */
+    table = htable_create(argc);
+    while ((cp = *argv++) != 0) {
+       if ((value = split_at(cp, '=')) == 0
+           || *(cp += strspn(cp, " \t\r\n")) == 0)
+           msg_fatal("edit requires \"key = value\" arguments");
+       cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue));
+       cvalue->value = value;
+       cvalue->found = 0;
+       htable_enter(table, mystrtok(&cp, " \t\r\n"), (char *) cvalue);
+    }
+
+    /*
+     * XXX Avoid code duplication by better code decomposition.
+     */
+    if (var_config_dir)
+       myfree(var_config_dir);
+    var_config_dir = mystrdup((config_dir = safe_getenv(CONF_ENV_PATH)) != 0 ?
+                             config_dir : DEF_CONFIG_DIR);     /* XXX */
+    set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir);
+
+    /*
+     * Open the original file for input.
+     */
+    path = concatenate(var_config_dir, "/", "main.cf", (char *) 0);
+    if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0)
+       msg_fatal("open %s for reading: %m", path);
+
+    /*
+     * Open a temp file for the result. We use a fixed name so we don't leave
+     * behind thrash with random names. Lock the temp file to avoid
+     * accidents. Truncate the file only after we have an exclusive lock.
+     */
+    temp = concatenate(path, ".tmp", (char *) 0);
+    if ((dst = vstream_fopen(temp, O_CREAT | O_WRONLY, 0644)) == 0)
+       msg_fatal("open %s: %m", temp);
+    if (myflock(vstream_fileno(dst), MYFLOCK_EXCLUSIVE) < 0)
+       msg_fatal("lock %s: %m", temp);
+    if (ftruncate(vstream_fileno(dst), 0) < 0)
+       msg_fatal("truncate %s: %m", temp);
+
+    /*
+     * Copy original file to temp file, while replacing parameters on the
+     * fly. Issue warnings for names found multiple times.
+     */
+#define STR(x) vstring_str(x)
+
+    while (readlline(buf, src, (int *) 0, READLL_KEEPNL)) {
+       cp = STR(buf);
+       if (first) {
+           first = 0;
+           if (ISSPACE(*cp))
+               msg_fatal("%s: file starts with whitespace", path);
+       }
+       if (*cp == '#') {
+           vstream_fputs(STR(buf), dst);
+           continue;
+       }
+       cp += strspn(cp, " \t\r\n");
+       vstring_strncpy(key, cp, strcspn(cp, " \t\r\n="));
+       cvalue = (struct cvalue *) htable_find(table, STR(key));
+       if (cvalue == 0) {
+           vstream_fputs(STR(buf), dst);
+       } else {
+           if (cvalue->found++ == 1)
+               msg_warn("%s: multiple entries for key %s", path, STR(key));
+           vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value);
+       }
+    }
+
+    /*
+     * Generate new entries for parameters that were not found.
+     */
+    for (ht_info = ht = htable_list(table); *ht; ht++) {
+       cvalue = (struct cvalue *) ht[0]->value;
+       if (cvalue->found == 0)
+           vstream_fprintf(dst, "%s = %s\n", ht[0]->key, cvalue->value);
+    }
+    myfree((char *) ht_info);
+
+    /*
+     * When all is well, rename the temp file to the original one.
+     */
+    if (vstream_fclose(src))
+       msg_fatal("read %s: %m", path);
+    if (vstream_fclose(dst))
+       msg_fatal("write %s: %m", temp);
+    if (rename(temp, path) < 0)
+       msg_fatal("rename %s to %s: %m", temp, path);
+
+    /*
+     * Cleanup.
+     */
+    myfree(path);
+    myfree(temp);
+    vstring_free(buf);
+    vstring_free(key);
+    htable_free(table, myfree);
+}
+
 /* read_parameters - read parameter info from file */
 
 static void read_parameters(void)
@@ -430,6 +573,19 @@ static int comp_names(const void *a, const void *b)
     return (strcmp(ap[0]->key, bp[0]->key));
 }
 
+/* show_maps - show available maps */
+
+static void show_maps(void)
+{
+    ARGV   *maps_argv;
+    int     i;
+
+    maps_argv = dict_mapnames();
+    for (i = 0; i < maps_argv->argc; i++)
+       vstream_printf("%s\n", maps_argv->argv[i]);
+    argv_free(maps_argv);
+}
+
 /* show_parameters - show parameter info */
 
 static void show_parameters(int mode, char **names)
@@ -470,6 +626,7 @@ int     main(int argc, char **argv)
     int     ch;
     int     fd;
     struct stat st;
+    int     junk;
 
     /*
      * To minimize confusion, make sure that the standard file descriptors
@@ -489,44 +646,70 @@ int     main(int argc, char **argv)
     /*
      * Parse JCL.
      */
-    while ((ch = GETOPT(argc, argv, "c:dhnv")) > 0) {
+    while ((ch = GETOPT(argc, argv, "c:dehnmv")) > 0) {
        switch (ch) {
        case 'c':
            if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
                msg_fatal("out of memory");
            break;
        case 'd':
-           if (mode & SHOW_NONDEF)
-               msg_fatal("specify one of -d and -n");
            mode |= SHOW_DEFS;
            break;
+       case 'e':
+           mode |= EDIT_MAIN;
+           break;
        case 'h':
            mode &= ~SHOW_NAME;
            break;
+       case 'm':
+           mode |= SHOW_MAPS;
+           break;
        case 'n':
-           if (mode & SHOW_DEFS)
-               msg_fatal("specify one of -d and -n");
            mode |= SHOW_NONDEF;
            break;
        case 'v':
            msg_verbose++;
            break;
        default:
-           msg_fatal("usage: %s [-c config_dir] [-d (defaults)] [-h (no names)] [-n (non-defaults)] [-v] name...", argv[0]);
+           msg_fatal("usage: %s [-c config_dir] [-d (defaults)] [-e (edit)] [-h (no names)] [-m (map types) [-n (non-defaults)] [-v] [name...]", argv[0]);
        }
     }
 
     /*
-     * If showing non-default values, read main.cf.
+     * Sanity check.
+     */
+    junk = (mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | EDIT_MAIN));
+    if (junk != 0 && junk != SHOW_DEFS && junk != SHOW_NONDEF
+       && junk != SHOW_MAPS && junk != EDIT_MAIN)
+       msg_fatal("specify one of -d, -e, -n and -m");
+
+    /*
+     * If showing map types, show them and exit
+     */
+    if (mode & SHOW_MAPS) {
+       show_maps();
+    }
+
+    /*
+     * Edit main.cf.
      */
-    if ((mode & SHOW_DEFS) == 0)
-       read_parameters();
+    if (mode & EDIT_MAIN) {
+       edit_parameters(argc - optind, argv + optind);
+    }
 
     /*
-     * Throw together all parameters and show the asked values.
+     * If showing non-default values, read main.cf.
      */
-    hash_parameters();
-    show_parameters(mode, argv + optind);
+    else {
+       if ((mode & SHOW_DEFS) == 0)
+           read_parameters();
+
+       /*
+        * Throw together all parameters and show the asked values.
+        */
+       hash_parameters();
+       show_parameters(mode, argv + optind);
+    }
     vstream_fflush(VSTREAM_OUT);
     exit(0);
 }
index af6a2b7c609d49b018e70fd1765a18af238e154a..702119aee360e7e427f703751d2db675fdd54ff3 100644 (file)
@@ -168,7 +168,7 @@ static void postmap(char *map_type, char *path_name,
      * Add records to the database.
      */
     lineno = 0;
-    while (readlline(line_buffer, source_fp, &lineno)) {
+    while (readlline(line_buffer, source_fp, &lineno, READLL_STRIPNL)) {
 
        /*
         * Skip comments.
index 522a0dcd9f3c20415b59177862be4fcb5daf1795..c3ba5e8e9fa8647d7ab60c14c5e35e3a17242350 100644 (file)
 #include <deliver_completed.h>
 #include <mail_addr_find.h>
 #include <opened.h>
-#include <resolve_local.h>
+#include <local_transport.h>
 
 /* Client stubs. */
 
@@ -477,7 +477,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
        /*
         * Bounce mail to non-existent users in virtual domains.
         */
-       if (!resolve_local(STR(reply.nexthop))
+       if (!local_transport(STR(reply.transport))
            && qmgr_virtual != 0
            && (at = strrchr(recipient->address, '@')) != 0) {
            domain = lowercase(mystrdup(at + 1));
@@ -516,7 +516,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
         * job requires knowledge of local aliases. Yuck! I don't want to
         * duplicate delivery-agent specific knowledge in the queue manager.
         */
-       if (resolve_local(STR(reply.nexthop))) {
+       if (local_transport(STR(reply.transport))) {
            vstring_strcpy(reply.nexthop, STR(reply.recipient));
            (void) split_at_right(STR(reply.nexthop), '@');
 #if 0
index 2fa6b677a24e46653c6d842e2fce5bd7aada2ff7..1b8c0cac8afeb171c46139d1136d83a35abdb8c9 100644 (file)
@@ -172,6 +172,7 @@ smtpd_check.o: ../include/own_inet_addr.h
 smtpd_check.o: ../include/mail_conf.h
 smtpd_check.o: ../include/maps.h
 smtpd_check.o: ../include/mail_addr_find.h
+smtpd_check.o: ../include/local_transport.h
 smtpd_check.o: smtpd.h
 smtpd_check.o: ../include/mail_stream.h
 smtpd_check.o: smtpd_check.h
index 8febad8c2863dbe54c8c3aadfc2a62035c2d894c..a31fcc3cef0dffb7c620065e06a620804f7005cc 100644 (file)
 #include <mail_conf.h>
 #include <maps.h>
 #include <mail_addr_find.h>
+#include <local_transport.h>
 
 /* Application-specific. */
 
@@ -712,7 +713,7 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient,
      * Permit if destination is local. XXX This must be generalized for
      * per-domain user tables and for non-UNIX local delivery agents.
      */
-    if (resolve_local(STR(reply.nexthop))
+    if (local_transport(STR(reply.transport))
        || (domain = strrchr(STR(reply.recipient), '@')) == 0)
        return (SMTPD_CHECK_OK);
     domain += 1;
@@ -751,7 +752,7 @@ static int permit_auth_destination(SMTPD_STATE *state, char *recipient)
      * Permit if destination is local. XXX This must be generalized for
      * per-domain user tables and for non-UNIX local delivery agents.
      */
-    if (resolve_local(STR(reply.nexthop))
+    if (local_transport(STR(reply.transport))
        || (domain = strrchr(STR(reply.recipient), '@')) == 0)
        return (SMTPD_CHECK_OK);
     domain += 1;
@@ -788,7 +789,7 @@ static int reject_unauth_destination(SMTPD_STATE *state, char *recipient)
      * Pass if destination is local. XXX This must be generalized for
      * per-domain user tables and for non-UNIX local delivery agents.
      */
-    if (resolve_local(STR(reply.nexthop))
+    if (local_transport(STR(reply.transport))
        || (domain = strrchr(STR(reply.recipient), '@')) == 0)
        return (SMTPD_CHECK_DUNNO);
     domain += 1;
@@ -890,7 +891,7 @@ static int permit_mx_backup(SMTPD_STATE *unused_state, const char *recipient)
      * If the destination is local, it is acceptable, because we are
      * supposedly MX for our own address.
      */
-    if (resolve_local(STR(reply.nexthop))
+    if (local_transport(STR(reply.transport))
        || (domain = strrchr(STR(reply.recipient), '@')) == 0)
        return (SMTPD_CHECK_OK);
     domain += 1;
@@ -1024,7 +1025,7 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr,
     /*
      * Skip local destinations and non-DNS forms.
      */
-    if (resolve_local(STR(reply.nexthop))
+    if (local_transport(STR(reply.transport))
        || (domain = strrchr(STR(reply.recipient), '@')) == 0)
        return (SMTPD_CHECK_DUNNO);
     domain += 1;
@@ -1064,7 +1065,7 @@ static int permit_rcpt_map(char *table, char *reply_name)
        return (SMTPD_CHECK_DUNNO);
     domain += 1;
     if (domain[0] == '#' || domain[0] == '[')
-       if (!resolve_local(STR(reply.nexthop)))
+       if (!local_transport(STR(reply.transport)))
            return (SMTPD_CHECK_DUNNO);
 
     /*
index f298da4795ddac5974e3dab0a760e5162e809537..6e8c2f74a089b1b861c55d10d177eba9eec46c99 100644 (file)
@@ -72,6 +72,7 @@
 #include <mail_conf.h>
 #include <quote_822_local.h>
 #include <tok822.h>
+#include <local_transport.h>
 
 /* Application-specific. */
 
@@ -151,44 +152,55 @@ void    resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
     }
 
     /*
-     * The transport map, if specified, overrides default routing.
+     * Make sure the resolved envelope recipient has the user@domain form. If
+     * no domain was specified in the address, assume the local machine. See
+     * above for what happens with an empty localpart.
      */
-    if (*var_transport_maps == 0
-       || (tok822_internalize(addr_buf, domain->next, TOK822_STR_DEFL),
-           transport_lookup(STR(addr_buf), channel, nexthop)) == 0) {
-
-       /*
-        * Non-local delivery. Use the default transport specified in
-        * var_def_transport. If no default mail relay is specified in
-        * var_relayhost, forward to the domain's mail exchanger.
-        */
-       if (domain != 0) {
-           vstring_strcpy(channel, var_def_transport);
-           if (*var_relayhost)
-               vstring_strcpy(nexthop, var_relayhost);
-           else
-               tok822_internalize(nexthop, domain->next, TOK822_STR_DEFL);
-       }
-
-       /*
-        * Local delivery. Use the default transport and next-hop hostname.
-        * If no domain was specified, assume the local machine. See above
-        * for what happens with an empty localpart.
-        */
-       else {
-           vstring_strcpy(channel, MAIL_SERVICE_LOCAL);
-           vstring_strcpy(nexthop, var_myhostname);
-           if (saved_domain) {
-               tok822_sub_append(tree, saved_domain);
-               saved_domain = 0;
-           } else {
-               tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
-               tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
-           }
+    if (domain == 0) {
+       if (saved_domain) {
+           tok822_sub_append(tree, saved_domain);
+           saved_domain = 0;
+       } else {
+           tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
+           tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
        }
     }
     tok822_internalize(nextrcpt, tree, TOK822_STR_DEFL);
 
+    /*
+     * The transport map overrides the default transport and next-hop host
+     * info that was set up just moments ago. For a long time, it was not
+     * possible to override routing of mail that resolves locally, because
+     * Postfix used a zero-length next-hop hostname result to indicate local
+     * delivery, and transport maps cannot return zero-length hostnames.
+     */
+    if (*var_transport_maps
+    && transport_lookup(strrchr(STR(nextrcpt), '@') + 1, channel, nexthop)) {
+        /* void */ ;
+    }
+
+    /*
+     * Non-local delivery, presumably. Set up the default remote transport
+     * specified with var_local_transports. Use the destination's mail
+     * exchanger unless a default mail relay is specified with var_relayhost.
+     */
+    else if (domain != 0) {
+       vstring_strcpy(channel, var_def_transport);
+       if (*var_relayhost)
+           vstring_strcpy(nexthop, var_relayhost);
+       else
+           tok822_internalize(nexthop, domain->next, TOK822_STR_DEFL);
+    }
+
+    /*
+     * Local delivery. Set up the default local transport and the default
+     * next-hop hostname.
+     */
+    else {
+       vstring_strcpy(channel, def_local_transport());
+       vstring_strcpy(nexthop, var_myhostname);
+    }
+
     /*
      * Clean up.
      */
index d14a5fb6f0cca24ffe11cf92bd3911cbc16fa3e0..6467441ab5fb9c62b6bbdef302c7aeed66aa35e7 100644 (file)
@@ -394,7 +394,7 @@ void    dict_load_fp(const char *dict_name, VSTREAM *fp)
     buf = vstring_alloc(100);
     lineno = 0;
 
-    while (readlline(buf, fp, &lineno)) {
+    while (readlline(buf, fp, &lineno, READLL_STRIPNL)) {
        start = STR(buf);
        SKIP(start, member, ISSPACE(*member));  /* find member begin */
        if (*member == 0 || *member == '#')
index 3ec4e93fe1e304d660be243940d98c59e72db156..88b4a698260e09d62c0b9a06f72392ec25990231 100644 (file)
@@ -20,6 +20,7 @@
   * Utility library.
   */
 #include <vstream.h>
+#include <argv.h>
 
  /*
   * Generic dictionary interface - in reality, a dictionary extends this
@@ -56,6 +57,11 @@ extern int dict_errno;
 #define DICT_SEQ_FUN_FIRST     0       /* set cursor to first record */
 #define DICT_SEQ_FUN_NEXT      1       /* set cursor to next record */
 
+ /*
+  * Interface for dictionary types.
+  */
+extern ARGV *dict_mapnames(void);
+
  /*
   * High-level interface, with logical dictionary names.
   */
@@ -96,5 +102,6 @@ extern int dict_changed(void);
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
 /*--*/
+/**INDENT** Error@47: Unmatched #endif */
 
 #endif
index 56696ee1d54f1bdd26590310e1d5f30714860cce..37b5602121d540c62e531ab734fa02591640b363 100644 (file)
@@ -280,6 +280,27 @@ void    dict_open_register(const char *type,
     htable_enter(dict_open_hash, dp->type, (char *) dp);
 }
 
+/* dict_mapnames - return an ARGV of available map_names */
+
+ARGV   *dict_mapnames()
+{
+    HTABLE_INFO **ht_info;
+    HTABLE_INFO **ht;
+    DICT_OPEN_INFO *dp;
+    ARGV   *mapnames;
+
+    if (dict_open_hash == 0)
+       dict_open_init();
+    mapnames = argv_alloc(dict_open_hash->used + 1);
+    for (ht_info = ht = htable_list(dict_open_hash); *ht; ht++) {
+       dp = (DICT_OPEN_INFO *) ht[0]->value;
+       argv_add(mapnames, dp->type, ARGV_END);
+    }
+    myfree((char *) ht_info);
+    argv_terminate(mapnames);
+    return mapnames;
+}
+
 #ifdef TEST
 
  /*
index c19c8c5ff7e612faebe435d9df821808fd784f8d..ddaf39bdded34042dc4d8659c7771ce3f3170df8 100644 (file)
@@ -273,7 +273,7 @@ DICT   *dict_pcre_open(const char *map, int unused_flags, int dict_flags)
     if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) {
        msg_fatal("open %s: %m", map);
     }
-    while (readlline(line_buffer, map_fp, &lineno)) {
+    while (readlline(line_buffer, map_fp, &lineno, READLL_STRIPNL)) {
 
        if (*vstring_str(line_buffer) == '#')   /* Skip comments */
            continue;
index d42deef0f741473b5ea9aa84af74ba8ef07fa745..85ae9a49c5ee09e1b5b00c2e9bcf505069679c93 100644 (file)
@@ -373,7 +373,7 @@ DICT   *dict_regexp_open(const char *map, int unused_flags, int dict_flags)
     if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) {
        msg_fatal("open %s: %m", map);
     }
-    while (readlline(line_buffer, map_fp, &lineno)) {
+    while (readlline(line_buffer, map_fp, &lineno, READLL_STRIPNL)) {
        p = vstring_str(line_buffer);
 
        if (*p == '#')                          /* Skip comments */
index 8d71b85c6bee0fe60ca4b63885867d2e0816cee8..314d6962bf083b3a8c4b8d978ecb4e025120c717 100644 (file)
@@ -6,14 +6,16 @@
 /* SYNOPSIS
 /*     #include <readlline.h>
 /*
-/*     VSTRING *readlline(buf, fp, lineno)
+/*     VSTRING *readlline(buf, fp, lineno, stripnl)
 /*     VSTRING *buf;
 /*     VSTREAM *fp;
 /*     int     *lineno;
+/*     int     stripnl;
 /* DESCRIPTION
 /*     readlline() reads one logical line from the named stream.
 /*     A line that starts with whitespace is a continuation of
-/*     the previous line. The newline between continued lines
+/*     the previous line. When the stripnl argument is non-zero,
+/*     the newline between continued lines
 /*     is deleted from the input. The result value is the input
 /*     buffer argument or a null pointer when no input is found.
 /*
@@ -25,6 +27,9 @@
 /* .IP lineno
 /*     A null pointer, or a pointer to an integer that is incremented
 /*     after reading a newline.
+/* .IP stripnl
+/*     Non-zero to strip newlines. readlline.h provides the symbolic
+/*     constants READLL_STRIPNL and READLL_KEEPNL for convenience.
 /* LICENSE
 /* .ad
 /* .fi
@@ -48,7 +53,7 @@
 
 /* readlline - read one logical line */
 
-VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno)
+VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno, int stripnl)
 {
     int     ch;
     int     next;
@@ -59,6 +64,8 @@ VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno)
     VSTRING_RESET(buf);
     while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF) {
        if (ch == '\n') {
+           if (stripnl == 0)
+               VSTRING_ADDCH(buf, ch);
            if (lineno)
                *lineno += 1;
            if ((next = VSTREAM_GETC(fp)) == ' ' || next == '\t') {
index 8a8bd548711fdf7654e12b0c6ce738a206317895..00658433cc2a5bdaa1f88b58dbd0a7d97384fb06 100644 (file)
  /*
   * External interface.
   */
-extern VSTRING *readlline(VSTRING *, VSTREAM *, int *);
+extern VSTRING *readlline(VSTRING *, VSTREAM *, int *, int);
+
+#define READLL_STRIPNL 1
+#define READLL_KEEPNL  0
 
 /* LICENSE
 /* .ad