]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-20000504
authorWietse Venema <wietse@porcupine.org>
Thu, 4 May 2000 00:00:00 +0000 (00:00 +0000)
committerWietse Venema <wietse@porcupine.org>
Thu, 17 Jan 2013 23:10:40 +0000 (18:10 -0500)
71 files changed:
postfix/.indent.pro
postfix/base64/.indent.pro
postfix/bounce/.indent.pro
postfix/cleanup/.indent.pro
postfix/dns/.indent.pro
postfix/error/.indent.pro
postfix/fsstone/.indent.pro
postfix/global/.indent.pro
postfix/global/mail_version.h
postfix/global/smtp_stream.c
postfix/lmtp/.indent.pro [new file with mode: 0644]
postfix/lmtp/.printfck [new file with mode: 0644]
postfix/lmtp/CHANGES [new file with mode: 0644]
postfix/lmtp/Makefile.in [new file with mode: 0644]
postfix/lmtp/README [new file with mode: 0644]
postfix/lmtp/README.inet [new file with mode: 0644]
postfix/lmtp/README.local [new file with mode: 0644]
postfix/lmtp/fixnames [new file with mode: 0644]
postfix/lmtp/global-patch [new file with mode: 0644]
postfix/lmtp/lmtp.c [new file with mode: 0644]
postfix/lmtp/lmtp.h [new file with mode: 0644]
postfix/lmtp/lmtp_addr.c [new file with mode: 0644]
postfix/lmtp/lmtp_addr.h [new file with mode: 0644]
postfix/lmtp/lmtp_chat.c [new file with mode: 0644]
postfix/lmtp/lmtp_connect.c [new file with mode: 0644]
postfix/lmtp/lmtp_proto.c [new file with mode: 0644]
postfix/lmtp/lmtp_session.c [new file with mode: 0644]
postfix/lmtp/lmtp_state.c [new file with mode: 0644]
postfix/lmtp/lmtp_trouble.c [new file with mode: 0644]
postfix/lmtp/mail [new file with mode: 0644]
postfix/lmtp/makefile-patch [new file with mode: 0644]
postfix/lmtp/man-patch [new file with mode: 0644]
postfix/lmtp/quote_821_local.c [new file with mode: 0644]
postfix/lmtp/quote_821_local.h [new file with mode: 0644]
postfix/local/.indent.pro
postfix/master/.indent.pro
postfix/pickup/.indent.pro
postfix/pipe/.indent.pro
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/smtp/smtp.c
postfix/smtp/smtp.h
postfix/smtp/smtp_proto.c
postfix/smtpd/.indent.pro
postfix/smtpd/smtpd.c
postfix/smtpd/smtpd.h
postfix/smtpstone/.indent.pro
postfix/smtpstone/smtp-sink.c
postfix/smtpstone/smtp-source.c
postfix/spawn/.indent.pro
postfix/trivial-rewrite/.indent.pro
postfix/util/.indent.pro
postfix/util/Makefile.in
postfix/util/iostuff.h
postfix/util/timed_read.c
postfix/util/timed_write.c
postfix/util/vstream.c
postfix/util/vstream.h
postfix/util/vstream_attr.c [deleted file]

index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 087b0c4f163f97406f9f67da08b347c02a807308..24fb39cc1ddd6f9c2ac0e7703f7036f9671f68b8 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-20000503"
+#define DEF_MAIL_VERSION       "Snapshot-20000504"
 extern char *var_mail_version;
 
 /* LICENSE
index 0f60200c12219492a150ba6972ca01b5e9c95d63..12a411b2b5e64e022710ec720712fb5df8906ba2 100644 (file)
@@ -6,10 +6,6 @@
 /* SYNOPSIS
 /*     #include <smtp_stream.h>
 /*
-/*     void    smtp_jump_setup(stream, jbuf)
-/*     VSTREAM *stream;
-/*     jmp_buf *jbuf;
-/*
 /*     void    smtp_timeout_setup(stream, timeout)
 /*     VSTREAM *stream;
 /*     int     timeout;
 /*     with error detection: timeouts or unexpected end-of-file.
 /*     A trailing CR LF is added upon writing and removed upon reading.
 /*
-/*     smtp_jump_setup() registers a caller context that will be
-/*     jumped to (with longjmp()) when any routine in this module
-/*     experiences an error condition (timeout, I/O error, or
-/*     unexpected EOF).
-/*
 /*     smtp_timeout_setup() arranges for a time limit on the smtp read
 /*     and write operations described below.
 /*     This routine alters the behavior of streams as follows:
 /* .IP \(bu
-/*     The read routine is replaced by one than calls timed_read().
-/* .IP \(bu
-/*     The write routine is replaced by one that calls timed_write().
+/*     The read/write timeout is set to the specified value.
 /* .IP \f(bu
 /*     The stream is configured to use double buffering.
 /* .IP \f(bu
-/*     A timeout error is reported to the vstream module as an I/O error.
+/*     The stream is configured to enable exception handling.
 /* .PP
 /*     smtp_printf() formats its arguments and writes the result to
 /*     the named stream, followed by a CR LF pair. The stream is flushed.
@@ -89,9 +78,9 @@
 /* DIAGNOSTICS
 /* .fi
 /* .ad
-/*     In case of error, a longjmp() is performed to the context
-/*     specified with the smtp_jump_setup() call.
-/*     Error codes passed along with longjmp() are:
+/*     In case of error, a vstream_longjmp() call is performed to the
+/*     context specified with vstream_setjmp().
+/*     Error codes passed along with vstream_longjmp() are:
 /* .IP SMTP_ERR_EOF
 /*     An I/O error happened, or the peer has disconnected unexpectedly.
 /* .IP SMTP_ERR_TIME
 /*     The timeout deadline affects all I/O on the named stream, not
 /*     just the I/O done on behalf of this module.
 /*
-/*     The timeout deadline and exception handling context overwrite
-/*     any previously set up state on the named stream.
+/*     The timeout deadline overwrites any previously set up state on
+/*     the named stream.
 /* LICENSE
 /* .ad
 /* .fi
 
 #include "smtp_stream.h"
 
- /*
-  * Our private VSTREAM attribute name for keeping track of the
-  * caller-supplied context for exception handling.
-  */
-#define SMTP_ATTR_JBUF "smtp_timeout_buf"
-
-/* smtp_timeout_jump - release timeout trap */
-
-static void smtp_timeout_jump(VSTREAM *stream, int what)
-{
-    char   *myname = "smtp_timeout_jump";
-    jmp_buf *jbuf;
-
-    if ((jbuf = (jmp_buf *) vstream_attr_get(stream, SMTP_ATTR_JBUF)) == 0)
-       msg_panic("%s: no jump buffer", myname);
-    longjmp(jbuf[0], what);
-}
-
-/* smtp_jump_setup - configure exception handling context */
-
-void    smtp_jump_setup(VSTREAM *stream, jmp_buf * jbuf)
-{
-    vstream_attr_set(stream, SMTP_ATTR_JBUF,
-                    (char *) jbuf, (VSTREAM_ATTR_FREE_FN) 0);
-}
-
-/* smtp_timeout_protect - reset per-stream timeout flag */
+/* smtp_timeout_reset - reset per-stream timeout flag */
 
-static void smtp_timeout_protect(VSTREAM *stream)
+static void smtp_timeout_reset(VSTREAM *stream)
 {
     vstream_clearerr(stream);
 }
@@ -175,7 +138,7 @@ static void smtp_timeout_protect(VSTREAM *stream)
 static void smtp_timeout_detect(VSTREAM *stream)
 {
     if (vstream_ftimeout(stream))
-       smtp_timeout_jump(stream, SMTP_ERR_TIME);
+       vstream_longjmp(stream, SMTP_ERR_TIME);
 }
 
 /* smtp_timeout_setup - configure timeout trap */
@@ -185,13 +148,14 @@ void    smtp_timeout_setup(VSTREAM *stream, int maxtime)
 
     /*
      * Stick your TLS/whatever read-write routines here. Notice that the
-     * read/write interface now includes a timeout parameter, and that a
-     * read/write routine is supposed to set errno to ETIMEDOUT when the
-     * alarm clock goes off.
+     * read/write interface now includes a timeout parameter and application
+     * context, and that a read/write routine is supposed to set errno to
+     * ETIMEDOUT when the alarm clock goes off.
      */
     vstream_control(stream,
-                   VSTREAM_CTL_TIMEOUT, maxtime,
                    VSTREAM_CTL_DOUBLE,
+                   VSTREAM_CTL_TIMEOUT, maxtime,
+                   VSTREAM_CTL_EXCEPT,
                    VSTREAM_CTL_END);
 }
 
@@ -204,7 +168,7 @@ void    smtp_vprintf(VSTREAM *stream, const char *fmt, va_list ap)
     /*
      * Do the I/O, protected against timeout.
      */
-    smtp_timeout_protect(stream);
+    smtp_timeout_reset(stream);
     vstream_vfprintf(stream, fmt, ap);
     vstream_fputs("\r\n", stream);
     err = vstream_fflush(stream);
@@ -216,7 +180,7 @@ void    smtp_vprintf(VSTREAM *stream, const char *fmt, va_list ap)
     if (err != 0) {
        if (msg_verbose)
            msg_info("smtp_vprintf: EOF");
-       smtp_timeout_jump(stream, SMTP_ERR_EOF);
+       vstream_longjmp(stream, SMTP_ERR_EOF);
     }
 }
 
@@ -244,7 +208,7 @@ int     smtp_get(VSTRING *vp, VSTREAM *stream, int bound)
      * allow for lines ending in bare LF. The idea is to be liberal in what
      * we accept, strict in what we send.
      */
-    smtp_timeout_protect(stream);
+    smtp_timeout_reset(stream);
     last_char = (bound == 0 ? vstring_get(vp, stream) :
                 vstring_get_bound(vp, stream, bound));
 
@@ -291,7 +255,7 @@ int     smtp_get(VSTRING *vp, VSTREAM *stream, int bound)
     if (vstream_feof(stream) || vstream_ferror(stream)) {
        if (msg_verbose)
            msg_info("smtp_get: EOF");
-       smtp_timeout_jump(stream, SMTP_ERR_EOF);
+       vstream_longjmp(stream, SMTP_ERR_EOF);
     }
     return (last_char);
 }
@@ -308,7 +272,7 @@ void    smtp_fputs(const char *cp, int todo, VSTREAM *stream)
     /*
      * Do the I/O, protected against timeout.
      */
-    smtp_timeout_protect(stream);
+    smtp_timeout_reset(stream);
     err = (vstream_fwrite(stream, cp, todo) != todo
           || vstream_fputs("\r\n", stream) == VSTREAM_EOF);
     smtp_timeout_detect(stream);
@@ -319,7 +283,7 @@ void    smtp_fputs(const char *cp, int todo, VSTREAM *stream)
     if (err != 0) {
        if (msg_verbose)
            msg_info("smtp_fputs: EOF");
-       smtp_timeout_jump(stream, SMTP_ERR_EOF);
+       vstream_longjmp(stream, SMTP_ERR_EOF);
     }
 }
 
@@ -335,7 +299,7 @@ void    smtp_fwrite(const char *cp, int todo, VSTREAM *stream)
     /*
      * Do the I/O, protected against timeout.
      */
-    smtp_timeout_protect(stream);
+    smtp_timeout_reset(stream);
     err = (vstream_fwrite(stream, cp, todo) != todo);
     smtp_timeout_detect(stream);
 
@@ -345,7 +309,7 @@ void    smtp_fwrite(const char *cp, int todo, VSTREAM *stream)
     if (err != 0) {
        if (msg_verbose)
            msg_info("smtp_fwrite: EOF");
-       smtp_timeout_jump(stream, SMTP_ERR_EOF);
+       vstream_longjmp(stream, SMTP_ERR_EOF);
     }
 }
 
@@ -358,7 +322,7 @@ void    smtp_fputc(int ch, VSTREAM *stream)
     /*
      * Do the I/O, protected against timeout.
      */
-    smtp_timeout_protect(stream);
+    smtp_timeout_reset(stream);
     stat = VSTREAM_PUTC(ch, stream);
     smtp_timeout_detect(stream);
 
@@ -368,6 +332,6 @@ void    smtp_fputc(int ch, VSTREAM *stream)
     if (stat == VSTREAM_EOF) {
        if (msg_verbose)
            msg_info("smtp_fputc: EOF");
-       smtp_timeout_jump(stream, SMTP_ERR_EOF);
+       vstream_longjmp(stream, SMTP_ERR_EOF);
     }
 }
diff --git a/postfix/lmtp/.indent.pro b/postfix/lmtp/.indent.pro
new file mode 100644 (file)
index 0000000..5fbb816
--- /dev/null
@@ -0,0 +1,120 @@
+-TALIAS_TOKEN
+-TARGV
+-TBH_TABLE
+-TBINATTR
+-TBINATTR_INFO
+-TBINHASH
+-TBINHASH_INFO
+-TBOUNCE_STAT
+-TCLEANUP_STATE
+-TCLIENT_LIST
+-TCLNT_STREAM
+-TCONFIG_BOOL_FN_TABLE
+-TCONFIG_BOOL_TABLE
+-TCONFIG_INT_FN_TABLE
+-TCONFIG_INT_TABLE
+-TCONFIG_STR_FN_TABLE
+-TCONFIG_STR_TABLE
+-TDELIVER_ATTR
+-TDELIVER_REQUEST
+-TDICT
+-TDICT_DB
+-TDICT_DBM
+-TDICT_ENV
+-TDICT_HT
+-TDICT_LDAP
+-TDICT_MYSQL
+-TDICT_NI
+-TDICT_NIS
+-TDICT_NISPLUS
+-TDICT_NODE
+-TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_RULE
+-TDICT_UNIX
+-TDNS_FIXED
+-TDNS_REPLY
+-TDNS_RR
+-TDOMAIN_LIST
+-TEXPAND_ATTR
+-TFILE
+-TFORWARD_INFO
+-THEADER_OPTS
+-THOST
+-THTABLE
+-THTABLE_INFO
+-TINET_ADDR_LIST
+-TINT_TABLE
+-TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
+-TLOCAL_EXP
+-TLOCAL_STATE
+-TMAC_EXP
+-TMAC_HEAD
+-TMAC_PARSE
+-TMAIL_PRINT
+-TMAIL_SCAN
+-TMAPS
+-TMASTER_PROC
+-TMASTER_SERV
+-TMASTER_STATUS
+-TMBLOCK
+-TMKMAP
+-TMKMAP_OPEN_INFO
+-TMULTI_SERVER
+-TMVECT
+-TMYSQL_NAME
+-TNAMADR_LIST
+-TNAME_MASK
+-TPEER_NAME
+-TPICKUP_INFO
+-TPIPE_ATTR
+-TPIPE_PARAMS
+-TPLMYSQL
+-TQMGR_ENTRY
+-TQMGR_MESSAGE
+-TQMGR_QUEUE
+-TQMGR_RCPT_LIST
+-TQMGR_RECIPIENT
+-TQMGR_SCAN
+-TQMGR_TRANSPORT
+-TRECIPIENT
+-TRECIPIENT_LIST
+-TREC_TYPE_NAME
+-TRESOLVE_REPLY
+-TRESPONSE
+-TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
+-TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
+-TSMTPD_CMD
+-TSMTPD_STATE
+-TSMTPD_TOKEN
+-TSMTP_ADDR
+-TSMTP_CMD
+-TSMTP_RESP
+-TSMTP_SESSION
+-TSMTP_STATE
+-TSOCKADDR_SIZE
+-TSPAWN_ATTR
+-TSTRING_TABLE
+-TSYS_EXITS_TABLE
+-TTOK822
+-TTRIGGER_SERVER
+-TUSER_ATTR
+-TVBUF
+-TVSTREAM
+-TVSTREAM_POPEN_ARGS
+-TVSTRING
+-TWAIT_STATUS_T
+-TWATCHDOG
+-TWATCH_FD
+-Tsasl_conn_t
+-Tsasl_secret_t
diff --git a/postfix/lmtp/.printfck b/postfix/lmtp/.printfck
new file mode 100644 (file)
index 0000000..65eb6bf
--- /dev/null
@@ -0,0 +1,25 @@
+been_here_xt   2       0
+bounce_append  5       0
+cleanup_out_format     1       0
+defer_append   5       0
+mail_command   1       0
+mail_print     1       0
+msg_error      0       0
+msg_fatal      0       0
+msg_info       0       0
+msg_panic      0       0
+msg_warn       0       0
+opened 3       0
+post_mail_fprintf      1       0
+qmgr_message_bounce    2       0
+rec_fprintf    2       0
+sent   4       0
+smtp_cmd       1       0
+smtp_mesg_fail 2       0
+smtp_printf    1       0
+smtp_rcpt_fail 3       0
+smtp_site_fail 2       0
+udp_syslog     1       0
+vstream_fprintf        1       0
+vstream_printf 0       0
+vstring_sprintf        1       0
diff --git a/postfix/lmtp/CHANGES b/postfix/lmtp/CHANGES
new file mode 100644 (file)
index 0000000..ddabbdf
--- /dev/null
@@ -0,0 +1,146 @@
+2000 Feb 23
+
+* lmtp.c, lmtp_connect.c, global-patch: added the main.cf
+  configuration parameter "lmtp_tcp_port".  If no port is explicitly 
+  specificed for the connection to the inet LMTP server, first
+  lookup "lmtp" with getservbyname.  If that fails, use the value of 
+  this "lmtp_tcp_port" parameter, which as a default value of 24.
+
+
+2000 Feb 21
+
+* Updated lmtp.c to yield a lmtp.8 man page that more accurately
+  reflects the current code.
+
+* Created man-patch so that lmtp.8 man page is created.  Updated
+  README to include applying this patch.
+
+
+2000 Feb 17
+
+* Correctly handle lmtp master.cf arguments of type "inet".
+  Possible uses are:
+
+  _USAGE_                          _MEANING_
+  serv=inet:                       connect over tcp to $nexthop
+  serv=inet:hostname               connect to named host port 24
+                                   (Actually, what "lmtp" is defined to be
+                                   in /etc/services.)
+  serv=inet:hostname:port          connect to named host named port
+  serv=inet:[ip.address]           connect to named host port 24
+  serv=inet:[ip.address]:port      connect to named address named port
+
+
+2000 Feb 15
+
+* Put in comment about local_destination_recipient_limit
+  in README.local.
+
+* In lmtp_chat.c, changed error reporting so that it goes
+  to var_error_rcpt, like the other Postfix services.
+
+
+2000 Jan 31
+
+* lmtp_proto.c:lmtp_lhlo: Don't worry about LMTP_FEATURE_PIPELINING
+  for sessions of type LMTP_SERV_TYPE_UNIX.
+
+
+2000 Jan 30
+
+* BIG changes.  Removed all the pipe stuff from lmtp.c and
+  lmtp_connect.c  Now, lmtp will either do a remote connection much
+  like the smtp client, or it will connect to a UNIX domain socket
+  to an auxiliary service (spawn).  This makes the lmtp patch
+  simpler because it doesn't have to worry at all about exec-ing an
+  external command, and all the resulting security implications.
+  See README.local for details.  
+
+  NOTE: postfix-19991231-pl04 is REQUIRED for this to work!  
+        (Need the "spawn" service.)
+
+* Updated the makefile-patch for postfix-19991231-pl03.
+
+* lmtp.h: changed the LMTP_ATTR structure to contain "type", "class", and
+  "name" fields, reflecting the change from the pipe mechanism to
+  the local sockets connection.  Changed LMTP_SESSION to contain the 
+  "type" field.  The connection type is recorded in this field in
+  case it is needed elsewhere, like in lmtp_proto.
+
+* lmtp.c:get_service_attr altered for new command syntax.  Examples: 
+
+     serv=unix:private/lmtpd
+     serv=inet:public/lmtpd
+
+  After `serv=' is the "type", followed by `:', then the "class",
+  followed by '/', and then finally the "name".
+
+* Added SAME_DESTINATION macro to lmtp.c:deliver_message for
+  readability, and simpler logic.
+
+* lmtp_connect.c: changed lmtp_connect to contain logic to determine 
+  just what kind of connection to make, removing it from lmtp.c;
+  removed lmtp_connect_pipe; and added lmtp_connect_local, which
+  uses mail_connect_wait to connect to the service running the LMTP
+  server (spawn).  In lmtp_connect, the connection type stored in
+  attr.type is saved into session.type, so it can be used later if
+  necessary. 
+
+* lmtp_proto.c:lmtp_lhlo: towards the end of this function we check
+  to see if service->type is LMTP_SERV_TYPE_UNIX so that we don't
+  try to do a getsockopt on a descriptor that doesn't support it.
+  Is this the best way to handle this?  Or maybe we should just try
+  it and if it bombs, check the error code before simply going
+  fatal?
+
+* Snagged the latest quota_821_local.c from the smtp client.
+
+* Updated the README files accordingly.
+
+
+2000 Jan 28
+
+* Well, wondering about using REWRITE_ADDRESS in lmtp_proto.c,
+  putting the lowercase thing in there.  Though, that would also
+  apply to sender address.  Is that okay?
+
+* We shouldn't be doing DNS lookups at this stage, so can get rid
+  of lmtp_unalias.c.  Also cut out the unalias portion in 
+  REWRITE_ADDRESS in lmtp_proto.c
+
+
+2000 Jan 11
+
+* At the suggestion of Rupa Schomaker, added the following to 
+  lmtp_proto.c:
+
+            lowercase(rcpt->address);  /* [AAG] rupa */
+
+
+1999 Dec 1 (or thereabouts)
+
+* Added lmtp_session_reset to make it easier to remember to reset
+  certain things to 0.  Did this to lmtp_chat_reset too.
+
+* Finally, did some work with the connection caching so that an RSET
+  is sent to the LMTP server.  This is done for two reasons: first,
+  to tell the LMTP server to flush out any status information
+  because we're about to feed it another message, and second, to
+  test the link to see if it is still alive.  If the link has died
+  for some reason, it is reestablished.  Changes to lmtp.c and
+  lmtp_proto.c.
+
+* There was also some tidying in lmtp.c so that things were a little
+  clearer as to what was going on.  I added a few more comments as
+  well.
+
+* I tried to make the master.cf argument parsing a little more
+  consistent with the other Postfix services.  Changes to lmtp.c.
+
+* On the postfix-users mailing list, Valery Brasseur pointed out that
+  errors encountered during LMTP delivery were not getting bounced
+  as appropriate.  This lead me to investigate the matter, wanting
+  to put this LMTP capability into service myself.  I then realized
+  that some of the error checking was a tad over zealous, and so
+  simplified things a bit in lmtp_proto.c.
+
diff --git a/postfix/lmtp/Makefile.in b/postfix/lmtp/Makefile.in
new file mode 100644 (file)
index 0000000..60c904e
--- /dev/null
@@ -0,0 +1,61 @@
+SHELL  = /bin/sh
+SRCS   = lmtp.c quote_821_local.c lmtp_connect.c lmtp_proto.c lmtp_chat.c \
+       lmtp_session.c lmtp_addr.c lmtp_trouble.c lmtp_state.c
+OBJS   = lmtp.o quote_821_local.o lmtp_connect.o lmtp_proto.o lmtp_chat.o \
+       lmtp_session.o lmtp_addr.o lmtp_trouble.o lmtp_state.o
+HDRS   = lmtp.h
+TESTSRC        = 
+WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
+       -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
+       -Wunused
+DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
+CFLAGS = $(DEBUG) $(OPT) $(DEFS)
+TESTPROG= quote_821_local
+PROG   = lmtp
+INC_DIR        = ../include
+LIBS   = ../lib/libmaster.a ../lib/libglobal.a ../lib/libdns.a ../lib/libutil.a
+
+.c.o:; $(CC) $(CFLAGS) -c $*.c
+
+$(PROG):       $(OBJS) $(LIBS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
+
+Makefile: Makefile.in
+       (set -e; echo "# DO NOT EDIT"; $(OPTS) sh ../makedefs; cat $?) >$@
+
+test:  $(TESTPROG)
+
+update: ../libexec/$(PROG)
+
+../libexec/$(PROG): $(PROG)
+       cp $(PROG) ../libexec
+
+printfck: $(OBJS) $(PROG)
+       rm -rf printfck
+       mkdir printfck
+       cp *.h printfck
+       sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
+       set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
+       cd printfck; make "INC_DIR=../../include" `cd ..; ls *.o`
+
+lint:
+       lint $(DEFS) $(SRCS) $(LINTFIX)
+
+clean:
+       rm -f *.o *core $(PROG) $(TESTPROG) junk 
+       rm -rf printfck
+
+tidy:  clean
+
+quote_821_local: quote_821_local.c $(LIBS)
+       $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS) $(SYSLIBS)
+
+depend: $(MAKES)
+       (sed '1,/^# do not edit/!d' Makefile.in; \
+       set -e; for i in [a-z][a-z0-9]*.c; do \
+           $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
+           -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
+       done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
+       @make -f Makefile.in Makefile
+
+# do not edit below this line - it is generated by 'make depend'
diff --git a/postfix/lmtp/README b/postfix/lmtp/README
new file mode 100644 (file)
index 0000000..1d39667
--- /dev/null
@@ -0,0 +1,34 @@
+README
+
+The starting point for this work was the original LMTP patch,
+lmtp-19990427.tar.gz, found in the experimental directory on the
+Postfix mirror ftp sites.  Without this original work by Philip A.
+Prindeville, I probably wouldn't have taken the time to dive into
+this issue.  Fortunately, this individual's work gave me a good 
+starting point to learn about LMTP, and Postfix in general.
+
+First, in the Postfix source directory, apply the following patches:
+
+  patch -p0 < lmtp/makefile-patch
+  patch -p0 < lmtp/global-patch
+  patch -p0 < lmtp/man-patch
+
+Then compile and install Postfix as usual.  There really isn't 
+anything OS specific so it should compile without problems.
+
+NOTE: Previously this patch would do a pipe to an external command
+      to perform local delivery.  That is no longer the case!  This
+      version now requires the "spawn" service be defined.  See
+      README.local for details.
+
+The other way to use this lmtp service is to talk to a remote LMTP
+server.  An example of this would be if an MX host is to insert
+incoming mail directly into a message store that supports the LMTP
+protocol.  This is described in README.inet.
+
+The file CHANGES lists some of the changes that have been made
+since lmtp-19990427.tar.gz, and TODO discusses some thoughts
+that are currently floating around.
+
+Amos
+
diff --git a/postfix/lmtp/README.inet b/postfix/lmtp/README.inet
new file mode 100644 (file)
index 0000000..d52190f
--- /dev/null
@@ -0,0 +1,80 @@
+README.inet
+
+This is an example of how to set up a remote LMTP server.  This can
+be useful if you have a central/firewall mail router that feeds
+incoming mail into the appropriate inbox server(s), the central box
+can stuff the incoming mail directly into the message store on the
+inbox machine using LMTP.  This also means the inbox machine doesn't
+have to have a SMTP server to handle this intermediate step.  Tidy
+all the way around.
+
+
+** Inbox Server:
+
+On the inbox server, in this case a CMU Cyrus imapd/popd server, add 
+the following to /etc/services:
+
+pop3            110/tcp                         # Cyrus POP3
+imap            143/tcp                         # Cyrus IMAP4
+lmtp            24/tcp
+
+
+Next, put the following in /etc/inetd.conf:
+
+lmtp    stream  tcp     nowait  cyrus   /usr/sbin/tcpd  /usr/local/cyrus/bin/deliver -e -l
+
+
+(/usr/sbin/tcpd is from the tcp_wrappers package.  You want this to
+make sure only your central box can do the stuffing.)
+
+
+** Central Server:
+
+Similar changes to /etc/services:
+
+lmtp            24/tcp
+
+
+Now we add this to /etc/postfix/master.cf:
+
+lmtp      unix  -       -       n       -       -       lmtp
+
+
+NOTES:  No arguments are specified to lmtp!
+        Root privs are not necessary!
+
+We put this in /etc/postfix/transport:
+
+inbox.domain.org     lmtp:inbox.domain.org
+
+
+Naturally, this means we also have to have in 
+/etc/postfix/main.cf:
+
+transport_maps      = hash:/etc/postfix/transport
+
+
+Use the map type of your choice.
+
+That's it.
+
+
+Oh, it may be necessary to apply the following patch to deliver so
+that the final "bye" is not lost.  This should not be necessary in
+releases subsequent to 1.6.20 of cyrus-imapd.
+
+*** deliver.c._orig     Tue Dec 21 11:12:47 1999
+--- deliver.c   Wed Dec 22 20:12:54 1999
+***************
+*** 1753,1758 ****
+--- 1753,1759 ----
+        case 'Q':
+            if (!strcasecmp(buf, "quit")) {
+                prot_printf(deliver_out,"221 2.0.0 bye\r\n");
++               prot_flush(deliver_out);
+                exit(0);
+            }
+            goto syntaxerr;
+
+
+
diff --git a/postfix/lmtp/README.local b/postfix/lmtp/README.local
new file mode 100644 (file)
index 0000000..a6286ec
--- /dev/null
@@ -0,0 +1,50 @@
+README.local
+
+This file describes how to use the lmtp service for local delivery.
+You'll need postfix-19991231-pl04 or later for this to work because
+it relies on the "spawn" service.
+
+Configure your Postfix as follows:
+
+/etc/postfix/master.cf:
+
+#local    unix  -       n       n       -       -       local
+local     unix  -       -       n       -       -       lmtp
+    serv=unix:private/lmtpd
+lmtpd     unix  -       n       n       -       -       spawn
+    user=cyrus:cyrus argv=/usr/local/cyrus/bin/deliver -e -l
+
+
+First, we comment out the original "local" service and define
+a new one based on the "lmtp" client.  The "serv=" argument says
+what LMTP server we're to talk to, in this case the "lmtpd"
+service.
+
+The `-l' option to deliver tells it to go into LMTP mode, and the
+`-e' tells it to use the duplicate delivery database, which is
+required in order to use the vacation features of Sieve, the
+filtering language in Cyrus 1.6.X.
+
+A note about spawn, this is a new experimental service.  The
+makefile-patch included with this bundle will add spawn to the
+compile targets.  However, you may need to check that it actually
+gets installed.
+
+A note about local delivery and the number of recipients.  Starting
+with postfix-19991231-pl04, it is now possible to specify the
+maximum number of recipients per message for local delivery.  By 
+default, this is set to 1 as follows:
+
+   local_destination_recipient_limit = 1
+
+You can set it to zero (means no limit) or, safer, set it to some
+reasonable number so that your machine doesn't risk running out of
+resources on a message with an inordinate number of recipients.
+
+Why is this of interest?  Well, if a message contains multiple
+recipients, and all these recipients happen to be on the same Cyrus
+partition, then recent (1.6.X) releases of deliver will hard link
+the message to each recipient instead of each recipient getting a
+copy.  So you'll probably want to set the above mail.cf value to
+something reasonable to take advantage of this feature in Cyrus.
+
diff --git a/postfix/lmtp/fixnames b/postfix/lmtp/fixnames
new file mode 100644 (file)
index 0000000..e6545ff
--- /dev/null
@@ -0,0 +1,5 @@
+sed '
+       s/LMTP/SMTP/g
+       s/lmtp/smtp/g
+       s/host/namaddr/g
+' $*
diff --git a/postfix/lmtp/global-patch b/postfix/lmtp/global-patch
new file mode 100644 (file)
index 0000000..cf604b9
--- /dev/null
@@ -0,0 +1,65 @@
+*** ../../orig/global/mail_params.h    Thu Jan 27 20:05:29 2000
+--- global/mail_params.h       Wed Feb 23 01:26:01 2000
+***************
+*** 624,629 ****
+--- 624,683 ----
+  extern int var_smtpd_err_sleep;
+  
+   /*
++   * LMTP client. Timeouts inspired by RFC 1123. The LMTP recipient limit
++   * determines how many recipient addresses the LMTP client sends along with
++   * each message. Unfortunately, some mailers misbehave and disconnect (smap)
++   * when given more recipients than they are willing to handle.
++   */
++ #define VAR_LMTP_TCP_PORT    "lmtp_tcp_port"
++ #define DEF_LMTP_TCP_PORT    24
++ extern int var_lmtp_tcp_port;
++ 
++ #define VAR_LMTP_CACHE_CONN  "lmtp_cache_connection"
++ #define DEF_LMTP_CACHE_CONN  1
++ extern bool var_lmtp_cache_conn;
++ 
++ #define VAR_LMTP_SKIP_QUIT_RESP      "lmtp_skip_quit_response"
++ #define DEF_LMTP_SKIP_QUIT_RESP      0
++ extern bool var_lmtp_skip_quit_resp;
++ 
++ #define VAR_LMTP_CONN_TMOUT  "lmtp_connect_timeout"
++ #define DEF_LMTP_CONN_TMOUT  0
++ extern int var_lmtp_conn_tmout;
++ 
++ #define VAR_LMTP_RSET_TMOUT  "lmtp_rset_timeout"
++ #define DEF_LMTP_RSET_TMOUT  300
++ extern int var_lmtp_rset_tmout;
++ 
++ #define VAR_LMTP_LHLO_TMOUT  "lmtp_lhlo_timeout"
++ #define DEF_LMTP_LHLO_TMOUT  300
++ extern int var_lmtp_lhlo_tmout;
++ 
++ #define VAR_LMTP_MAIL_TMOUT  "lmtp_mail_timeout"
++ #define DEF_LMTP_MAIL_TMOUT  300
++ extern int var_lmtp_mail_tmout;
++ 
++ #define VAR_LMTP_RCPT_TMOUT  "lmtp_rcpt_timeout"
++ #define DEF_LMTP_RCPT_TMOUT  300
++ extern int var_lmtp_rcpt_tmout;
++ 
++ #define VAR_LMTP_DATA0_TMOUT "lmtp_data_init_timeout"
++ #define DEF_LMTP_DATA0_TMOUT 120
++ extern int var_lmtp_data0_tmout;
++ 
++ #define VAR_LMTP_DATA1_TMOUT "lmtp_data_xfer_timeout"
++ #define DEF_LMTP_DATA1_TMOUT 180
++ extern int var_lmtp_data1_tmout;
++ 
++ #define VAR_LMTP_DATA2_TMOUT "lmtp_data_done_timeout"
++ #define DEF_LMTP_DATA2_TMOUT 600
++ extern int var_lmtp_data2_tmout;
++ 
++ #define VAR_LMTP_QUIT_TMOUT  "lmtp_quit_timeout"
++ #define DEF_LMTP_QUIT_TMOUT  300
++ extern int var_lmtp_quit_tmout;
++ 
++  /*
+    * Cleanup service. Header info that exceeds $header_size_limit bytes forces
+    * the start of the message body.
+    */
diff --git a/postfix/lmtp/lmtp.c b/postfix/lmtp/lmtp.c
new file mode 100644 (file)
index 0000000..3ed78e8
--- /dev/null
@@ -0,0 +1,608 @@
+/*++
+/* NAME
+/*     lmtp 8
+/* SUMMARY
+/*     Postfix local delivery via LMTP
+/* SYNOPSIS
+/*     \fBlmtp\fR [generic Postfix daemon options] [server attributes...]
+/* DESCRIPTION
+/*     The LMTP client processes message delivery requests from
+/*     the queue manager. Each request specifies a queue file, a sender
+/*     address, a domain or host to deliver to, and recipient information.
+/*     This program expects to be run from the \fBmaster\fR(8) process
+/*     manager.
+/*
+/*     The LMTP client updates the queue file and marks recipients
+/*     as finished, or it informs the queue manager that delivery should
+/*     be tried again at a later time. Delivery problem reports are sent
+/*     to the \fBbounce\fR(8) or \fBdefer\fR(8) daemon as appropriate.
+/*
+/*     There are two basic modes of operation for the LMTP client:
+/* .IP \(bu
+/*     Communication with a local LMTP server via UNIX domain sockets.
+/* .IP \(bu
+/*     Communication with a (possibly remote) LMTP server via
+/*     Internet sockets.
+/* .PP
+/*     If no server attributes are specified, the LMTP client will contact
+/*     the destination host derived from the message delivery request using
+/*     the TCP port defined as \fBlmtp\fR in \fBservices\fR(4).  If no such
+/*     service is found, the \fBlmtp_tcp_port\fR configuration parameter
+/*     (default value of 24) will be used.
+/*
+/*     In order to use a local LMTP server, this LMTP server will need to
+/*     be specified via the server attributes described in the following
+/*     section.  Typically, the LMTP client would also be configured as the
+/*     \fBlocal\fR delivery agent in the \fBmaster.cf\fR file.
+/* SERVER ATTRIBUTE SYNTAX
+/* .ad
+/* .fi
+/*     The server attributes are given in the \fBmaster.cf\fR file at
+/*     the end of a service definition.  The syntax is as follows:
+/* .IP "\fBserv\fR=\fItype\fR:\fIserver\fR"
+/*     The LMTP server to connect to for final delivery.  The \fItype\fR
+/*     portion can be either \fBunix\fR or \fBinet\fR. The \fIserver\fR
+/*     portion is the path or address of the LMTP server, depending on the
+/*     value of \fItype\fR, as shown below:
+/* .RS
+/* .IP "\fBserv=unix:\fR\fIclass\fR\fB/\fR\fIservname\fR"
+/*     This specifies that the local LMTP server \fIservname\fR should be
+/*     contacted for final delivery.  Both \fIclass\fR (either \fBpublic\fR
+/*     or \fBprivate\fR) and \fIservname\fR correspond to the LMTP server
+/*     entry in the \fBmaster.cf\fR file.  This LMTP server will likely
+/*     be defined as a \fBspawn\fR(8) service.
+/* .IP "\fBserv=inet:"
+/*     If nothing follows the \fBinet:\fR type specifier, a connection will
+/*     be attempted to the destination host indicated in the delivery request.
+/*     This simplest case is identical to defining the LMTP client without
+/*     any server attributes at all.
+/* .IP "\fBserv=inet:\fR\fIaddress\fR"
+/*     In this case, an Internet socket will be made to the server
+/*     specified by \fIaddress\fR.  The connection will use a destination
+/*     port as described in the previous section.
+/* .IP "\fBserv=inet:\fR\fIaddress\fR\fB:\fR\fIport\fR"
+/*     Connect to the LMTP server at \fIaddress\fR, but this time use port
+/*     \fIport\fR instead of the default \fBlmtp\fR port.
+/* .IP "\fBserv=inet:[\fR\fIipaddr\fR\fB]\fR"
+/*     The LMTP server to contact is specified using an Internet address
+/*     in the "dot notation".  That is, the numeric IP address rather
+/*     than the DNS name for the server.  The default \fBlmtp\fR port
+/*     is used.
+/* .IP "\fBserv=inet:[\fR\fIipaddr\fR\fB]:\fR\fIport\fR"
+/*     The LMTP server to contact is specified using the numeric IP address,
+/*     at the port specified.
+/* .RE
+/* .PP
+/* SECURITY
+/* .ad
+/* .fi
+/*     The LMTP client is moderately security-sensitive. It talks to LMTP
+/*     servers and to DNS servers on the network. The LMTP client can be
+/*     run chrooted at fixed low privilege.
+/* STANDARDS
+/*     RFC 2033 (LMTP protocol)
+/*     RFC 821 (SMTP protocol)
+/*     RFC 1651 (SMTP service extensions)
+/*     RFC 1870 (Message Size Declaration)
+/*     RFC 2197 (Pipelining)
+/* DIAGNOSTICS
+/*     Problems and transactions are logged to \fBsyslogd\fR(8).
+/*     Corrupted message files are marked so that the queue manager can
+/*     move them to the \fBcorrupt\fR queue for further inspection.
+/*
+/*     Depending on the setting of the \fBnotify_classes\fR parameter,
+/*     the postmaster is notified of bounces, protocol problems, and of
+/*     other trouble.
+/* BUGS
+/* CONFIGURATION PARAMETERS
+/* .ad
+/* .fi
+/*     The following \fBmain.cf\fR parameters are especially relevant to
+/*     this program. See the Postfix \fBmain.cf\fR file for syntax details
+/*     and for default values. Use the \fBpostfix reload\fR command after
+/*     a configuration change.
+/* .SH Miscellaneous
+/* .ad
+/* .fi
+/* .IP \fBdebug_peer_level\fR
+/*     Verbose logging level increment for hosts that match a
+/*     pattern in the \fBdebug_peer_list\fR parameter.
+/* .IP \fBdebug_peer_list\fR
+/*     List of domain or network patterns. When a remote host matches
+/*     a pattern, increase the verbose logging level by the amount
+/*     specified in the \fBdebug_peer_level\fR parameter.
+/* .IP \fBerror_notice_recipient\fR
+/*     Recipient of protocol/policy/resource/software error notices.
+/* .IP \fBnotify_classes\fR
+/*     When this parameter includes the \fBprotocol\fR class, send mail to the
+/*     postmaster with transcripts of LMTP sessions with protocol errors.
+/* .IP \fBlmtp_skip_quit_response\fR
+/*     Do not wait for the server response after sending QUIT.
+/* .IP \fBlmtp_tcp_port\fR
+/*     The TCP port to be used when connecting to a LMTP server.  Used as
+/*     backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
+/* .SH "Resource controls"
+/* .ad
+/* .fi
+/* .IP \fBlmtp_cache_connection\fR
+/*     Should we cache the connection to the LMTP server? The effectiveness
+/*     of cached connections will be determined by the number of LMTP servers
+/*     in use, and the concurrency limit specified for the LMTP client.
+/*     Cached connections are closed under any of the following conditions:
+/* .RS
+/* .IP \(bu
+/*     The idle timeout for the LMTP client is reached. This limit is
+/*     enforced by \fBmaster\fR(8).
+/* .IP \(bu
+/*     A message request to a different destination than the one currently
+/*     cached.
+/* .IP \(bu
+/*     The maximum number of requests per session is reached. This limit is
+/*     enforced by \fBmaster\fR(8).
+/* .IP \(bu
+/*     Upon the onset of another delivery request, the LMTP server associated
+/*     with the current session does not respond to the \fBRSET\fR command.
+/* .RE
+/* .IP \fBlmtp_destination_concurrency_limit\fR
+/*     Limit the number of parallel deliveries to the same destination.
+/*     The default limit is taken from the
+/*     \fBdefault_destination_concurrency_limit\fR parameter.
+/* .IP \fBlmtp_destination_recipient_limit\fR
+/*     Limit the number of recipients per message delivery.
+/*     The default limit is taken from the
+/*     \fBdefault_destination_recipient_limit\fR parameter.
+/* .IP \fBlocal_destination_recipient_limit\fR
+/*     Limit the number of recipients per message delivery.
+/*     The default limit is taken from the
+/*     \fBdefault_destination_recipient_limit\fR parameter.
+/*
+/*     This parameter becomes significant if the LMTP client is used
+/*     for local delivery.  Some LMTP servers can optimize final delivery
+/*     if multiple recipients are allowed.  Therefore, it may be advantageous
+/*     to set this to some number greater than one, depending on the capabilities
+/*     of the machine.
+/*
+/*     Setting this parameter to 0 will lead to an unlimited number of
+/*     recipients per delivery.  However, this could be risky since it may
+/*     make the machine vulnerable to running out of resources if messages
+/*     are encountered with an inordinate number of recipients.  Exercise
+/*     care when setting this parameter.
+/* .SH "Timeout controls"
+/* .ad
+/* .fi
+/* .IP \fBlmtp_connect_timeout\fR
+/*     Timeout in seconds for opening a connection to the LMTP server.
+/*     If no connection can be made within the deadline, the message
+/*     is deferred.
+/* .IP \fBlmtp_lhlo_timeout\fR
+/*     Timeout in seconds for sending the \fBLHLO\fR command, and for
+/*     receiving the server response.
+/* .IP \fBlmtp_mail_timeout\fR
+/*     Timeout in seconds for sending the \fBMAIL FROM\fR command, and for
+/*     receiving the server response.
+/* .IP \fBlmtp_rcpt_timeout\fR
+/*     Timeout in seconds for sending the \fBRCPT TO\fR command, and for
+/*     receiving the server response.
+/* .IP \fBlmtp_data_init_timeout\fR
+/*     Timeout in seconds for sending the \fBDATA\fR command, and for
+/*     receiving the server response.
+/* .IP \fBlmtp_data_xfer_timeout\fR
+/*     Timeout in seconds for sending the message content.
+/* .IP \fBlmtp_data_done_timeout\fR
+/*     Timeout in seconds for sending the "\fB.\fR" command, and for
+/*     receiving the server response. When no response is received, a
+/*     warning is logged that the mail may be delivered multiple times.
+/* .IP \fBlmtp_rset_timeout\fR
+/*     Timeout in seconds for sending the \fBRSET\fR command, and for
+/*     receiving the server response.
+/* .IP \fBlmtp_quit_timeout\fR
+/*     Timeout in seconds for sending the \fBQUIT\fR command, and for
+/*     receiving the server response.
+/* SEE ALSO
+/*     bounce(8) non-delivery status reports
+/*     local(8) local mail delivery
+/*     master(8) process manager
+/*     qmgr(8) queue manager
+/*     services(4) Internet services and aliases
+/*     spawn(8) auxiliary command spawner
+/*     syslogd(8) system logging
+/* 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
+/*
+/*     Alterations for LMTP by:
+/*     Philip A. Prindeville
+/*     Mirapoint, Inc.
+/*     USA.
+/*
+/*     Additional work on LMTP by:
+/*     Amos Gouaux
+/*     University of Texas at Dallas
+/*     P.O. Box 830688, MC34
+/*     Richardson, TX 75083, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dict.h>
+#include <pwd.h>
+#include <grp.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <argv.h>
+#include <mymalloc.h>
+#include <name_mask.h>
+
+/* Global library. */
+
+#include <deliver_request.h>
+#include <mail_queue.h>
+#include <mail_params.h>
+#include <mail_conf.h>
+#include <debug_peer.h>
+#include <mail_error.h>
+
+/* Single server skeleton. */
+
+#include <mail_server.h>
+
+/* Application-specific. */
+
+#include "lmtp.h"
+
+ /*
+  * Tunable parameters. These have compiled-in defaults that can be overruled
+  * by settings in the global Postfix configuration file.
+  */
+int     var_lmtp_tcp_port;
+int     var_lmtp_conn_tmout;
+int     var_lmtp_rset_tmout;
+int     var_lmtp_lhlo_tmout;
+int     var_lmtp_mail_tmout;
+int     var_lmtp_rcpt_tmout;
+int     var_lmtp_data0_tmout;
+int     var_lmtp_data1_tmout;
+int     var_lmtp_data2_tmout;
+int     var_lmtp_quit_tmout;
+char   *var_debug_peer_list;
+int     var_debug_peer_level;
+int     var_lmtp_cache_conn;
+int     var_lmtp_skip_quit_resp;
+char   *var_notify_classes;
+char   *var_error_rcpt;
+
+ /*
+  * Global variables.
+  * 
+  * lmtp_errno is set by the address lookup routines and by the connection
+  * management routines.
+  * 
+  * state is global for the connection caching to work.
+  */
+int     lmtp_errno;
+static LMTP_STATE *state = 0;
+
+
+/* get_service_attr - get command-line attributes */
+
+static LMTP_ATTR *get_service_attr(char **argv)
+{
+    char   *myname = "get_service_attr";
+    LMTP_ATTR *attr = (LMTP_ATTR *) mymalloc(sizeof(*attr));
+    char   *type;
+    char   *dest;
+    char   *name;
+
+    /*
+     * Initialize.
+     */
+    attr->type = 0;
+    attr->class = "";
+    attr->name = "";
+
+    /*
+     * Iterate over the command-line attribute list.
+     */
+    if (msg_verbose)
+       msg_info("%s: checking argv for lmtp server", myname);
+
+    for ( /* void */ ; *argv != 0; argv++) {
+
+       /*
+        * Are we configured to speak to a particular LMTP server?
+        */
+       if (strncasecmp("serv=", *argv, sizeof("serv=") - 1) == 0) {
+           type = *argv + sizeof("serv=") - 1;
+           if ((dest = split_at(type, ':')) == 0)      /* XXX clobbers argv */
+               msg_fatal("%s: invalid serv= arguments: %s", myname, *argv);
+
+           /*
+            * What kind of socket connection are we to make?
+            */
+           if (strcasecmp("unix", type) == 0) {
+               attr->type = LMTP_SERV_TYPE_UNIX;
+               attr->class = dest;
+               if ((name = split_at(dest, '/')) == 0)  /* XXX clobbers argv */
+                   msg_fatal("%s: invalid serv= arguments: %s", myname, *argv);
+               attr->name = name;
+           } else if (strcasecmp("inet", type) == 0) {
+               attr->type = LMTP_SERV_TYPE_INET;
+               attr->name = dest;
+           } else
+               msg_fatal("%s: invalid serv= arguments: %s", myname, *argv);
+           break;
+       }
+
+       /*
+        * Bad.
+        */
+       else
+           msg_fatal("%s: unknown attribute name: %s", myname, *argv);
+    }
+
+    /*
+     * Give the poor tester a clue of what is going on.
+     */
+    if (msg_verbose)
+       msg_info("%s: type %d, class \"%s\", name \"%s\".", myname,
+                attr->type, attr->class, attr->name);
+    return (attr);
+}
+
+/* deliver_message - deliver message with extreme prejudice */
+
+static int deliver_message(DELIVER_REQUEST *request, char **argv)
+{
+    char   *myname = "deliver_message";
+    static LMTP_ATTR *attr = 0;
+    VSTRING *why;
+    int     result;
+
+    /*
+     * Macro for readability.  We're going to the same destination if the
+     * destination was specified on the command line (attr->name is not
+     * null), or if the destination of the current session is the same as
+     * request->nexthop.
+     */
+#define SAME_DESTINATION() \
+    (*(attr)->name \
+     || strcasecmp(state->session->destination, request->nexthop) == 0)
+
+    if (msg_verbose)
+       msg_info("%s: from %s", myname, request->sender);
+
+    /*
+     * Sanity checks.
+     */
+    if (attr == 0)
+       attr = get_service_attr(argv);
+    if (request->rcpt_list.len <= 0)
+       msg_fatal("%s: recipient count: %d", myname, request->rcpt_list.len);
+
+    /*
+     * Initialize. Bundle all information about the delivery request, so that
+     * we can produce understandable diagnostics when something goes wrong
+     * many levels below. The alternative would be to make everything global.
+     * 
+     * Note: `state' is global (to this file) so that we can close a cached
+     * connection via the MAIL_SERVER_EXIT function (cleanup). The alloc for
+     * `state' is performed in the MAIL_SERVER_PRE_INIT function (pre_init).
+     * 
+     */
+    why = vstring_alloc(100);
+    state->request = request;
+    state->src = request->fp;
+
+    /*
+     * See if we can reuse an existing connection.
+     */
+    if (state->session != 0) {
+
+       /*
+        * Session already exists from a previous delivery. If we're not
+        * going to the same destination as before, disconnect and establish
+        * a connection to the specified destination.
+        */
+       if (!SAME_DESTINATION()) {
+           lmtp_quit(state);
+           lmtp_chat_reset(state);
+           lmtp_session_reset(state);
+           debug_peer_restore();
+       }
+
+       /*
+        * Probe the session by sending RSET. If the connection is broken,
+        * clean up our side of the connection.
+        */
+       else if (lmtp_rset(state) != 0) {
+           lmtp_chat_reset(state);
+           lmtp_session_reset(state);
+           debug_peer_restore();
+       }
+
+       /*
+        * Ready to go with another load.
+        */
+       else {
+           ++state->reuse;
+           if (msg_verbose)
+               msg_info("%s: reusing (count %d) session with: %s",
+                        myname, state->reuse, state->session->host);
+       }
+    }
+
+    /*
+     * If no LMTP session exists, establish one.
+     */
+    if (state->session == 0) {
+
+       /*
+        * Bounce or defer the recipients if no connection can be made.
+        */
+       state->session = lmtp_connect(attr, request, why);
+       if (state->session == 0) {
+           lmtp_site_fail(state, lmtp_errno == LMTP_RETRY ? 450 : 550,
+                          "%s", vstring_str(why));
+       }
+
+       /*
+        * Further check connection by sending the LHLO greeting. If we
+        * cannot talk LMTP to this destination give up, at least for now.
+        */
+       else {
+           debug_peer_check(state->session->host, state->session->addr);
+           if (lmtp_lhlo(state) != 0) {
+               lmtp_session_reset(state);
+               debug_peer_restore();
+           }
+       }
+
+    }
+
+    /*
+     * If a session exists, deliver this message to all requested recipients.
+     * 
+     */
+    if (state->session != 0)
+       lmtp_xfer(state);
+
+    /*
+     * At the end, notify the postmaster of any protocol errors.
+     */
+    if (state->history != 0
+       && (state->error_mask
+           & name_mask(mail_error_masks, var_notify_classes)))
+       lmtp_chat_notify(state);
+
+    /*
+     * Disconnect if we're not cacheing connections.
+     */
+    if (!var_lmtp_cache_conn && state->session != 0) {
+       lmtp_quit(state);
+       lmtp_session_reset(state);
+       debug_peer_restore();
+    }
+
+    /*
+     * Clean up.
+     */
+    vstring_free(why);
+    result = state->status;
+    lmtp_chat_reset(state);
+
+    return (result);
+}
+
+/* lmtp_service - perform service for client */
+
+static void lmtp_service(VSTREAM *client_stream, char *unused_service, char **argv)
+{
+    DELIVER_REQUEST *request;
+    int     status;
+
+    /*
+     * This routine runs whenever a client connects to the UNIX-domain socket
+     * dedicated to remote LMTP delivery service. What we see below is a
+     * little protocol to (1) tell the queue manager that we are ready, (2)
+     * read a request from the queue manager, and (3) report the completion
+     * status of that request. All connection-management stuff is handled by
+     * the common code in single_server.c.
+     */
+    if ((request = deliver_request_read(client_stream)) != 0) {
+       status = deliver_message(request, argv);
+       deliver_request_done(client_stream, request, status);
+    }
+}
+
+/* pre_init - pre-jail initialization */
+
+static void pre_init(char *unused_name, char **unused_argv)
+{
+    debug_peer_init();
+    state = lmtp_state_alloc();
+}
+
+/* cleanup - close any open connections, etc. */
+
+static void cleanup()
+{
+    if (state == 0)
+       return;
+
+    if (state->session != 0) {
+       lmtp_quit(state);
+       lmtp_chat_reset(state);
+       lmtp_session_free(state->session);
+       debug_peer_restore();
+       if (msg_verbose)
+           msg_info("cleanup: just closed down session");
+    }
+    lmtp_state_free(state);
+}
+
+/* pre_accept - see if tables have changed
+
+static void pre_accept(char *unused_name, char **unused_argv)
+{
+    if (dict_changed()) {
+       msg_info("table has changed -- exiting");
+       cleanup();
+       exit(0);
+    }
+}
+
+
+/*
+   main - pass control to the single-threaded skeleton
+*/
+
+int     main(int argc, char **argv)
+{
+    static CONFIG_STR_TABLE str_table[] = {
+       VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
+       VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
+       VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
+       0,
+    };
+    static CONFIG_INT_TABLE int_table[] = {
+       VAR_LMTP_TCP_PORT, DEF_LMTP_TCP_PORT, &var_lmtp_tcp_port, 0, 0,
+       VAR_LMTP_CONN_TMOUT, DEF_LMTP_CONN_TMOUT, &var_lmtp_conn_tmout, 0, 0,
+       VAR_LMTP_RSET_TMOUT, DEF_LMTP_RSET_TMOUT, &var_lmtp_rset_tmout, 1, 0,
+       VAR_LMTP_LHLO_TMOUT, DEF_LMTP_LHLO_TMOUT, &var_lmtp_lhlo_tmout, 1, 0,
+       VAR_LMTP_MAIL_TMOUT, DEF_LMTP_MAIL_TMOUT, &var_lmtp_mail_tmout, 1, 0,
+       VAR_LMTP_RCPT_TMOUT, DEF_LMTP_RCPT_TMOUT, &var_lmtp_rcpt_tmout, 1, 0,
+       VAR_LMTP_DATA0_TMOUT, DEF_LMTP_DATA0_TMOUT, &var_lmtp_data0_tmout, 1, 0,
+       VAR_LMTP_DATA1_TMOUT, DEF_LMTP_DATA1_TMOUT, &var_lmtp_data1_tmout, 1, 0,
+       VAR_LMTP_DATA2_TMOUT, DEF_LMTP_DATA2_TMOUT, &var_lmtp_data2_tmout, 1, 0,
+       VAR_LMTP_QUIT_TMOUT, DEF_LMTP_QUIT_TMOUT, &var_lmtp_quit_tmout, 1, 0,
+       VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
+       0,
+    };
+    static CONFIG_BOOL_TABLE bool_table[] = {
+       VAR_LMTP_CACHE_CONN, DEF_LMTP_CACHE_CONN, &var_lmtp_cache_conn,
+       VAR_LMTP_SKIP_QUIT_RESP, DEF_LMTP_SKIP_QUIT_RESP, &var_lmtp_skip_quit_resp,
+       0,
+    };
+
+    single_server_main(argc, argv, lmtp_service,
+                      MAIL_SERVER_INT_TABLE, int_table,
+                      MAIL_SERVER_STR_TABLE, str_table,
+                      MAIL_SERVER_BOOL_TABLE, bool_table,
+                      MAIL_SERVER_PRE_INIT, pre_init,
+                      MAIL_SERVER_PRE_ACCEPT, pre_accept,
+                      MAIL_SERVER_EXIT, cleanup,
+                      0);
+}
diff --git a/postfix/lmtp/lmtp.h b/postfix/lmtp/lmtp.h
new file mode 100644 (file)
index 0000000..b93d53e
--- /dev/null
@@ -0,0 +1,155 @@
+/*++
+/* NAME
+/*     lmtp 3h
+/* SUMMARY
+/*     lmtp client program
+/* SYNOPSIS
+/*     #include "lmtp.h"
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <vstream.h>
+#include <vstring.h>
+#include <argv.h>
+
+ /*
+  * Global library.
+  */
+#include <deliver_request.h>
+
+ /*
+  * State information associated with each LMTP delivery. We're bundling the
+  * state so that we can give meaningful diagnostics in case of problems.
+  */
+typedef struct LMTP_STATE {
+    VSTREAM *src;                      /* queue file stream */
+    DELIVER_REQUEST *request;          /* envelope info, offsets */
+    struct LMTP_SESSION *session;      /* network connection */
+    VSTRING *buffer;                   /* I/O buffer */
+    VSTRING *scratch;                  /* scratch buffer */
+    VSTRING *scratch2;                 /* scratch buffer */
+    int     status;                    /* delivery status */
+    int     features;                  /* server features */
+    ARGV   *history;                   /* transaction log */
+    int     error_mask;                        /* error classes */
+    int     sndbufsize;                        /* total window size */
+    int     sndbuffree;                        /* remaining window */
+    int     reuse;                     /* connection being reused */
+} LMTP_STATE;
+
+#define LMTP_FEATURE_ESMTP     (1<<0)
+#define LMTP_FEATURE_8BITMIME  (1<<1)
+#define LMTP_FEATURE_PIPELINING        (1<<2)
+#define LMTP_FEATURE_SIZE      (1<<3)
+
+ /*
+  * lmtp.c
+  */
+extern int lmtp_errno;                 /* XXX can we get rid of this? */
+
+ /*
+  * Structure for connection to LMTP server.
+  */
+typedef struct LMTP_ATTR {
+    int     type;                      /* UNIX-domain, INET, etc. */
+    char   *class;                     /* class ("public" or "private") */
+    char   *name;                      /* service endpoint name */
+} LMTP_ATTR;
+
+ /*
+  * Service types.
+  */
+#define LMTP_SERV_TYPE_UNIX   1                /* AF_UNIX domain socket */
+#define LMTP_SERV_TYPE_INET   2                /* AF_INET domain socket */
+
+ /*
+  * lmtp_session.c
+  */
+typedef struct LMTP_SESSION {
+    VSTREAM *stream;                   /* network connection */
+    char   *host;                      /* mail exchanger */
+    char   *addr;                      /* mail exchanger */
+    char   *destination;               /* domain originally sent to */
+    int     type;                      /* type of connection */
+} LMTP_SESSION;
+
+extern LMTP_SESSION *lmtp_session_alloc(VSTREAM *, char *, char *);
+extern void lmtp_session_free(LMTP_SESSION *);
+extern void lmtp_session_reset(LMTP_STATE *);
+
+ /*
+  * lmtp_connect.c
+  */
+extern LMTP_SESSION *lmtp_connect(LMTP_ATTR *, DELIVER_REQUEST *request, VSTRING *);
+extern LMTP_SESSION *lmtp_connect_host(char *, unsigned, VSTRING *);
+extern LMTP_SESSION *lmtp_connect_local(const char *, const char *, VSTRING *);
+
+ /*
+  * lmtp_proto.c
+  */
+extern int lmtp_lhlo(LMTP_STATE *);
+extern int lmtp_xfer(LMTP_STATE *);
+extern int lmtp_quit(LMTP_STATE *);
+extern int lmtp_rset(LMTP_STATE *);
+
+ /*
+  * lmtp_chat.c
+  */
+typedef struct LMTP_RESP {             /* server response */
+    int     code;                      /* status */
+    char   *str;                       /* text */
+    VSTRING *buf;                      /* origin of text */
+} LMTP_RESP;
+
+extern void lmtp_chat_cmd(LMTP_STATE *, char *,...);
+extern LMTP_RESP *lmtp_chat_resp(LMTP_STATE *);
+extern void lmtp_chat_reset(LMTP_STATE *);
+extern void lmtp_chat_notify(LMTP_STATE *);
+
+ /*
+  * lmtp_trouble.c
+  */
+extern int lmtp_conn_fail(LMTP_STATE *, int, char *,...);
+extern int lmtp_site_fail(LMTP_STATE *, int, char *,...);
+extern int lmtp_mesg_fail(LMTP_STATE *, int, char *,...);
+extern void lmtp_rcpt_fail(LMTP_STATE *, int, RECIPIENT *, char *,...);
+extern int lmtp_stream_except(LMTP_STATE *, int, char *);
+
+ /*
+  * lmtp_state.c
+  */
+extern LMTP_STATE *lmtp_state_alloc(void);
+extern void lmtp_state_free(LMTP_STATE *);
+
+ /*
+  * Status codes. Errors must have negative codes so that they do not
+  * interfere with useful counts of work done.
+  */
+#define LMTP_OK                        0       /* so far, so good */
+#define LMTP_RETRY             (-1)    /* transient error */
+#define LMTP_FAIL              (-2)    /* hard error */
+
+/* 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
+/*
+/*      Alterations for LMTP by:
+/*      Philip A. Prindeville
+/*      Mirapoint, Inc.
+/*      USA.
+/*
+/*      Additional work on LMTP by:
+/*      Amos Gouaux
+/*      University of Texas at Dallas
+/*      P.O. Box 830688, MC34
+/*      Richardson, TX 75083, USA
+/*--*/
diff --git a/postfix/lmtp/lmtp_addr.c b/postfix/lmtp/lmtp_addr.c
new file mode 100644 (file)
index 0000000..69c49a5
--- /dev/null
@@ -0,0 +1,202 @@
+/*++
+/* NAME
+/*     lmtp_addr 3
+/* SUMMARY
+/*     LMTP server address lookup
+/* SYNOPSIS
+/*     #include "lmtp_addr.h"
+/*
+/*     DNS_RR *lmtp_host_addr(name, why)
+/*     char    *name;
+/*     VSTRING *why;
+/* DESCRIPTION
+/*     This module implements Internet address lookups. By default,
+/*     lookups are done via the Internet domain name service (DNS).
+/*     A reasonable number of CNAME indirections is permitted.
+/*
+/*     lmtp_host_addr() looks up all addresses listed for the named
+/*     host.  The host can be specified as a numerical Internet network
+/*     address, or as a symbolic host name.
+/*
+/*      Fortunately, we don't have to worry about MX records because
+/*      those are for SMTP servers, not LMTP servers.
+/*
+/*     Results from lmtp_host_addr() are destroyed by dns_rr_free(),
+/*     including null lists.
+/* DIAGNOSTICS
+/*     This routine either returns a DNS_RR pointer, or return a null
+/*     pointer and sets the \fIlmtp_errno\fR global variable accordingly:
+/* .IP LMTP_RETRY
+/*     The request failed due to a soft error, and should be retried later.
+/* .IP LMTP_FAIL
+/*     The request attempt failed due to a hard error.
+/* .PP
+/*     In addition, a textual description of the problem is made available
+/*     via the \fIwhy\fR argument.
+/* 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
+/*
+/*      Alterations for LMTP by:
+/*      Philip A. Prindeville
+/*      Mirapoint, Inc.
+/*      USA.
+/*
+/*      Additional work on LMTP by:
+/*      Amos Gouaux
+/*      University of Texas at Dallas
+/*      P.O. Box 830688, MC34
+/*      Richardson, TX 75083, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <mymalloc.h>
+#include <inet_addr_list.h>
+#include <stringops.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <own_inet_addr.h>
+
+/* DNS library. */
+
+#include <dns.h>
+
+/* Application-specific. */
+
+#include "lmtp.h"
+#include "lmtp_addr.h"
+
+/* lmtp_print_addr - print address list */
+
+static void lmtp_print_addr(char *what, DNS_RR *addr_list)
+{
+    DNS_RR *addr;
+    struct in_addr in_addr;
+
+    msg_info("begin %s address list", what);
+    for (addr = addr_list; addr; addr = addr->next) {
+       if (addr->data_len > sizeof(addr)) {
+           msg_warn("skipping address length %d", addr->data_len);
+       } else {
+           memcpy((char *) &in_addr, addr->data, sizeof(in_addr));
+           msg_info("pref %4d host %s/%s",
+                    addr->pref, addr->name,
+                    inet_ntoa(in_addr));
+       }
+    }
+    msg_info("end %s address list", what);
+}
+
+/* lmtp_addr_one - address lookup for one host name */
+
+static DNS_RR *lmtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why)
+{
+    char   *myname = "lmtp_addr_one";
+    struct in_addr inaddr;
+    DNS_FIXED fixed;
+    DNS_RR *addr = 0;
+    DNS_RR *rr;
+    struct hostent *hp;
+
+    if (msg_verbose)
+       msg_info("%s: host %s", myname, host);
+
+    /*
+     * Interpret a numerical name as an address.
+     */
+    if (ISDIGIT(host[0]) && (inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
+       memset((char *) &fixed, 0, sizeof(fixed));
+       return (dns_rr_append(addr_list,
+                             dns_rr_create(host, &fixed, pref,
+                                       (char *) &inaddr, sizeof(inaddr))));
+    }
+
+    /*
+     * Use gethostbyname() when DNS is disabled.
+     */
+    if (var_disable_dns) {
+       memset((char *) &fixed, 0, sizeof(fixed));
+       if ((hp = gethostbyname(host)) == 0) {
+           vstring_sprintf(why, "%s: host not found", host);
+           lmtp_errno = LMTP_FAIL;
+       } else if (hp->h_addrtype != AF_INET) {
+           vstring_sprintf(why, "%s: host not found", host);
+           msg_warn("%s: unknown address family %d for %s",
+                    myname, hp->h_addrtype, host);
+           lmtp_errno = LMTP_FAIL;
+       } else {
+           while (hp->h_addr_list[0]) {
+               addr_list = dns_rr_append(addr_list,
+                                         dns_rr_create(host, &fixed, pref,
+                                                       hp->h_addr_list[0],
+                                                       sizeof(inaddr)));
+               hp->h_addr_list++;
+           }
+       }
+       return (addr_list);
+    }
+
+    /*
+     * Append the addresses for this host to the address list.
+     */
+    switch (dns_lookup(host, T_A, 0, &addr, (VSTRING *) 0, why)) {
+    case DNS_OK:
+       for (rr = addr; rr; rr = rr->next)
+           rr->pref = pref;
+       addr_list = dns_rr_append(addr_list, addr);
+       break;
+    default:
+       lmtp_errno = LMTP_RETRY;
+       break;
+    case DNS_NOTFOUND:
+    case DNS_FAIL:
+       lmtp_errno = LMTP_FAIL;
+       break;
+    }
+    return (addr_list);
+}
+
+/* lmtp_host_addr - direct host lookup */
+
+DNS_RR *lmtp_host_addr(char *host, VSTRING *why)
+{
+    DNS_RR *addr_list;
+
+    /*
+     * If the host is specified by numerical address, just convert the
+     * address to internal form. Otherwise, the host is specified by name.
+     */
+#define PREF0  0
+    addr_list = lmtp_addr_one((DNS_RR *) 0, host, PREF0, why);
+    if (msg_verbose)
+       lmtp_print_addr(host, addr_list);
+    return (addr_list);
+}
+
diff --git a/postfix/lmtp/lmtp_addr.h b/postfix/lmtp/lmtp_addr.h
new file mode 100644 (file)
index 0000000..579b7f0
--- /dev/null
@@ -0,0 +1,41 @@
+/*++
+/* NAME
+/*     lmtp_addr 3h
+/* SUMMARY
+/*     LMTP server address lookup
+/* SYNOPSIS
+/*     #include "lmtp_addr.h"
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * DNS library.
+  */
+#include <dns.h>
+
+ /*
+  * Internal interfaces.
+  */
+extern DNS_RR *lmtp_host_addr(char *, VSTRING *);
+
+/* 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
+/*
+/*      Alterations for LMTP by:
+/*      Philip A. Prindeville
+/*      Mirapoint, Inc.
+/*      USA.
+/*
+/*      Additional work on LMTP by:
+/*      Amos Gouaux
+/*      University of Texas at Dallas
+/*      P.O. Box 830688, MC34
+/*      Richardson, TX 75083, USA
+/*--*/
diff --git a/postfix/lmtp/lmtp_chat.c b/postfix/lmtp/lmtp_chat.c
new file mode 100644 (file)
index 0000000..097169b
--- /dev/null
@@ -0,0 +1,285 @@
+/*++
+/* NAME
+/*     lmtp_chat 3
+/* SUMMARY
+/*     LMTP client request/response support
+/* SYNOPSIS
+/*     #include "lmtp.h"
+/*
+/*     typedef struct {
+/* .in +4
+/*             int code;
+/*             char *str;
+/*             VSTRING *buf;
+/* .in -4
+/*     } LMTP_RESP;
+/*
+/*     void    lmtp_chat_cmd(state, format, ...)
+/*     LMTP_STATE *state;
+/*     char    *format;
+/*
+/*     LMTP_RESP *lmtp_chat_resp(state)
+/*     LMTP_STATE *state;
+/*
+/*     void    lmtp_chat_notify(state)
+/*     LMTP_STATE *state;
+/*
+/*     void    lmtp_chat_reset(state)
+/*     LMTP_STATE *state;
+/* DESCRIPTION
+/*     This module implements LMTP client support for request/reply
+/*     conversations, and maintains a limited LMTP transaction log.
+/*
+/*     lmtp_chat_cmd() formats a command and sends it to an LMTP server.
+/*     Optionally, the command is logged.
+/*
+/*     lmtp_chat_resp() read one LMTP server response. It separates the
+/*     numerical status code from the text, and concatenates multi-line
+/*     responses to one string, using a newline as separator.
+/*     Optionally, the server response is logged.
+/*
+/*     lmtp_chat_notify() sends a copy of the LMTP transaction log
+/*     to the postmaster for review. The postmaster notice is sent only
+/*     when delivery is possible immediately. It is an error to call
+/*     lmtp_chat_notify() when no LMTP transaction log exists.
+/*
+/*     lmtp_chat_reset() resets the transaction log. This is
+/*     typically done at the beginning or end of an LMTP session,
+/*     or within a session to discard non-error information.
+/* DIAGNOSTICS
+/*     Fatal errors: memory allocation problem, server response exceeds
+/*     configurable limit.
+/*     All other exceptions are handled by long jumps (see smtp_stream(3)).
+/* SEE ALSO
+/*     smtp_stream(3) LMTP session I/O support
+/*     msg(3) generic logging interface
+/* 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
+/*
+/*      Alterations for LMTP by:
+/*      Philip A. Prindeville
+/*      Mirapoint, Inc.
+/*      USA.
+/*
+/*      Additional work on LMTP by:
+/*      Amos Gouaux
+/*      University of Texas at Dallas
+/*      P.O. Box 830688, MC34
+/*      Richardson, TX 75083, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <argv.h>
+#include <stringops.h>
+#include <line_wrap.h>
+#include <mymalloc.h>
+
+/* Global library. */
+
+#include <recipient_list.h>
+#include <deliver_request.h>
+#include <smtp_stream.h>
+#include <mail_params.h>
+#include <mail_addr.h>
+#include <post_mail.h>
+
+/* Application-specific. */
+
+#include "lmtp.h"
+
+#define STR(x) ((char *) vstring_str(x))
+#define LEN    VSTRING_LEN
+
+/* lmtp_chat_reset - reset LMTP transaction log */
+
+void    lmtp_chat_reset(LMTP_STATE *state)
+{
+    if (state->history) {
+       argv_free(state->history);
+       state->history = 0;
+    }
+
+    /* What's status without history? */
+    state->status = 0;
+    state->error_mask = 0;
+}
+
+/* lmtp_chat_append - append record to LMTP transaction log */
+
+static void lmtp_chat_append(LMTP_STATE *state, char *direction, char *data)
+{
+    char   *line;
+
+    if (state->history == 0)
+       state->history = argv_alloc(10);
+    line = concatenate(direction, data, (char *) 0);
+    argv_add(state->history, line, (char *) 0);
+    myfree(line);
+}
+
+/* lmtp_chat_cmd - send an LMTP command */
+
+void    lmtp_chat_cmd(LMTP_STATE *state, char *fmt,...)
+{
+    LMTP_SESSION *session = state->session;
+    va_list ap;
+
+    /*
+     * Format the command, and update the transaction log.
+     */
+    va_start(ap, fmt);
+    vstring_vsprintf(state->buffer, fmt, ap);
+    va_end(ap);
+    lmtp_chat_append(state, "Out: ", STR(state->buffer));
+
+    /*
+     * Optionally log the command first, so we can see in the log what the
+     * program is trying to do.
+     */
+    if (msg_verbose)
+       msg_info("> %s: %s", session->host, STR(state->buffer));
+
+    /*
+     * Send the command to the LMTP server.
+     */
+    smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream);
+}
+
+/* lmtp_chat_resp - read and process LMTP server response */
+
+LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state)
+{
+    LMTP_SESSION *session = state->session;
+    static LMTP_RESP rdata;
+    int     more;
+    char   *cp;
+    int     last_char;
+
+    /*
+     * Initialize the response data buffer.
+     */
+    if (rdata.buf == 0)
+       rdata.buf = vstring_alloc(100);
+
+    /*
+     * Censor out non-printable characters in server responses. Concatenate
+     * multi-line server responses. Separate the status code from the text.
+     * Leave further parsing up to the application.
+     */
+    VSTRING_RESET(rdata.buf);
+    for (;;) {
+       last_char = smtp_get(state->buffer, session->stream, var_line_limit);
+       cp = printable(STR(state->buffer), '?');
+       if (last_char != '\n')
+           msg_warn("%s: response longer than %d: %.30s...",
+                    session->host, var_line_limit, cp);
+       if (msg_verbose)
+           msg_info("< %s: %s", session->host, cp);
+       while (ISDIGIT(*cp))
+           cp++;
+       rdata.code = (cp - STR(state->buffer) == 3 ?
+                     atoi(STR(state->buffer)) : 0);
+       more = (*cp == '-');
+
+       /*
+        * Defend against a denial of service attack by limiting the amount
+        * of multi-line text that we are willing to store.
+        */
+       if (LEN(rdata.buf) < var_line_limit) {
+           if (VSTRING_LEN(rdata.buf))
+               VSTRING_ADDCH(rdata.buf, '\n');
+           vstring_strcat(rdata.buf, STR(state->buffer));
+           lmtp_chat_append(state, "In:  ", STR(state->buffer));
+       }
+       if (VSTRING_LEN(state->buffer) == 0)    /* XXX remote brain damage */
+           continue;
+       if (!ISDIGIT(STR(state->buffer)[0]))    /* XXX remote brain damage */
+           continue;
+       if (more == 0)
+           break;
+    }
+    VSTRING_TERMINATE(rdata.buf);
+    rdata.str = STR(rdata.buf);
+    return (&rdata);
+}
+
+/* print_line - line_wrap callback */
+
+static void print_line(const char *str, int len, int indent, char *context)
+{
+    VSTREAM *notice = (VSTREAM *) context;
+
+    post_mail_fprintf(notice, " %*s%.*s", indent, "", len, str);
+}
+
+/* lmtp_chat_notify - notify postmaster */
+
+void    lmtp_chat_notify(LMTP_STATE *state)
+{
+    char   *myname = "lmtp_chat_notify";
+    LMTP_SESSION *session = state->session;
+    VSTREAM *notice;
+    char  **cpp;
+
+    /*
+     * Sanity checks.
+     */
+    if (state->history == 0)
+       msg_panic("%s: no conversation history", myname);
+    if (msg_verbose)
+       msg_info("%s: notify postmaster", myname);
+
+    /*
+     * Construct a message for the postmaster, explaining what this is all
+     * about. This is junk mail: don't send it when the mail posting service
+     * is unavailable, and use the double bounce sender address, to prevent
+     * mail bounce wars. Always prepend one space to message content that we
+     * generate from untrusted data.
+     */
+#define NULL_CLEANUP_FLAGS     0
+#define LENGTH 78
+#define INDENT 4
+
+    notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
+                                    var_error_rcpt,
+                                   NULL_CLEANUP_FLAGS, "NOTICE");
+    if (notice == 0) {
+       msg_warn("postmaster notify: %m");
+       return;
+    }
+    post_mail_fprintf(notice, "From: %s (Mail Delivery System)",
+                     mail_addr_mail_daemon());
+    post_mail_fprintf(notice, "To: %s (Postmaster)", var_error_rcpt);
+    post_mail_fprintf(notice, "Subject: %s LMTP client: errors from %s",
+                     var_mail_name, session->host);
+    post_mail_fputs(notice, "");
+    post_mail_fprintf(notice, "Unexpected response from %s.", session->host);
+    post_mail_fputs(notice, "");
+    post_mail_fputs(notice, "Transcript of session follows.");
+    post_mail_fputs(notice, "");
+    argv_terminate(state->history);
+    for (cpp = state->history->argv; *cpp; cpp++)
+       line_wrap(printable(*cpp, '?'), LENGTH, INDENT, print_line,
+                 (char *) notice);
+    (void) post_mail_fclose(notice);
+}
diff --git a/postfix/lmtp/lmtp_connect.c b/postfix/lmtp/lmtp_connect.c
new file mode 100644 (file)
index 0000000..dcf5733
--- /dev/null
@@ -0,0 +1,395 @@
+/*++
+/* NAME
+/*     lmtp_connect 3
+/* SUMMARY
+/*     connect to LMTP server
+/* SYNOPSIS
+/*     #include "lmtp.h"
+/*
+/*     LMTP_SESSION *lmtp_connect(destination, why)
+/*     char    *destination;
+/*     VSTRING *why;
+/* DESCRIPTION
+/*     This module implements LMTP connection management.
+/*
+/*     lmtp_connect() attempts to establish an LMTP session with a host.
+/*
+/*     The destination is either a host name or a numeric address.
+/*     Symbolic or numeric service port information may be appended,
+/*     separated by a colon (":").
+/*
+/*     Numerical address information should always be quoted with `[]'.
+/*
+/* DIAGNOSTICS
+/*     This routine either returns an LMTP_SESSION pointer, or
+/*     returns a null pointer and set the \fIlmtp_errno\fR
+/*     global variable accordingly:
+/* .IP LMTP_RETRY
+/*     The connection attempt failed, but should be retried later.
+/* .IP LMTP_FAIL
+/*     The connection attempt failed.
+/* .PP
+/*     In addition, a textual description of the error is made available
+/*     via the \fIwhy\fR argument.
+/* SEE ALSO
+/*     lmtp_proto(3) LMTP client protocol
+/* 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
+/*
+/*      Alterations for LMTP by:
+/*      Philip A. Prindeville
+/*      Mirapoint, Inc.
+/*      USA.
+/*
+/*      Additional work on LMTP by:
+/*      Amos Gouaux
+/*      University of Texas at Dallas
+/*      P.O. Box 830688, MC34
+/*      Richardson, TX 75083, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <split_at.h>
+#include <mymalloc.h>
+#include <inet_addr_list.h>
+#include <iostuff.h>
+#include <timed_connect.h>
+#include <stringops.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <own_inet_addr.h>
+
+/* DNS library. */
+
+#include <dns.h>
+
+/* Application-specific. */
+
+#include "lmtp.h"
+#include "lmtp_addr.h"
+
+/* lmtp_connect_addr - connect to explicit address */
+
+static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port,
+                                              VSTRING *why)
+{
+    char   *myname = "lmtp_connect_addr";
+    struct sockaddr_in sin;
+    int     sock;
+    INET_ADDR_LIST *addr_list;
+    int     conn_stat;
+    int     saved_errno;
+    VSTREAM *stream;
+    int     ch;
+    unsigned long inaddr;
+
+    /*
+     * Sanity checks.
+     */
+    if (addr->data_len > sizeof(sin.sin_addr)) {
+       msg_warn("%s: skip address with length %d", myname, addr->data_len);
+       lmtp_errno = LMTP_RETRY;
+       return (0);
+    }
+
+    /*
+     * Initialize.
+     */
+    memset((char *) &sin, 0, sizeof(sin));
+    sin.sin_family = AF_INET;
+
+    if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0)
+       msg_fatal("%s: socket: %m", myname);
+
+    /* do we still need this if? */
+    addr_list = own_inet_addr_list();
+    if (addr_list->used == 1) {
+       sin.sin_port = 0;
+       memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr));
+       inaddr = ntohl(sin.sin_addr.s_addr);
+       if (!IN_CLASSA(inaddr)
+           || !(((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) {
+           if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
+               msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr));
+           if (msg_verbose)
+               msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr));
+       }
+    }
+
+    /*
+     * Connect to the LMTP server.
+     */
+    sin.sin_port = port;
+    memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr));
+
+    if (msg_verbose)
+       msg_info("%s: trying: %s[%s] port %d...",
+                myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
+    if (var_lmtp_conn_tmout > 0) {
+       non_blocking(sock, NON_BLOCKING);
+       conn_stat = timed_connect(sock, (struct sockaddr *) & sin,
+                                 sizeof(sin), var_lmtp_conn_tmout);
+       saved_errno = errno;
+       non_blocking(sock, BLOCKING);
+       errno = saved_errno;
+    } else {
+       conn_stat = connect(sock, (struct sockaddr *) & sin, sizeof(sin));
+    }
+    if (conn_stat < 0) {
+       vstring_sprintf(why, "connect to %s[%s]: %m",
+                       addr->name, inet_ntoa(sin.sin_addr));
+       lmtp_errno = LMTP_RETRY;
+       close(sock);
+       return (0);
+    }
+
+    /*
+     * Skip this host if it takes no action within some time limit.
+     */
+    if (read_wait(sock, var_lmtp_lhlo_tmout) < 0) {
+       vstring_sprintf(why, "connect to %s[%s]: read timeout",
+                       addr->name, inet_ntoa(sin.sin_addr));
+       lmtp_errno = LMTP_RETRY;
+       close(sock);
+       return (0);
+    }
+
+    /*
+     * Skip this host if it disconnects without talking to us.
+     */
+    stream = vstream_fdopen(sock, O_RDWR);
+    if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
+       vstring_sprintf(why, "connect to %s[%s]: server dropped connection",
+                       addr->name, inet_ntoa(sin.sin_addr));
+       lmtp_errno = LMTP_RETRY;
+       vstream_fclose(stream);
+       return (0);
+    }
+
+    /*
+     * Skip this host if it sends a 4xx greeting.
+     */
+    if (ch == '4') {
+       vstring_sprintf(why, "connect to %s[%s]: server refused mail service",
+                       addr->name, inet_ntoa(sin.sin_addr));
+       lmtp_errno = LMTP_RETRY;
+       vstream_fclose(stream);
+       return (0);
+    }
+    vstream_ungetc(stream, ch);
+    return (lmtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr)));
+}
+
+/* lmtp_connect_host - direct connection to host */
+
+LMTP_SESSION *lmtp_connect_host(char *host, unsigned port, VSTRING *why)
+{
+    LMTP_SESSION *session = 0;
+    DNS_RR *addr_list;
+    DNS_RR *addr;
+
+    /*
+     * Try each address in the specified order until we find one that works.
+     * The addresses belong to the same A record, so we have no information
+     * on what address is "best".
+     */
+    addr_list = lmtp_host_addr(host, why);
+    for (addr = addr_list; addr; addr = addr->next) {
+       if ((session = lmtp_connect_addr(addr, port, why)) != 0) {
+           break;
+       }
+    }
+    dns_rr_free(addr_list);
+    return (session);
+}
+
+/* lmtp_parse_destination - parse destination */
+
+static char *lmtp_parse_destination(char *destination, char *def_service,
+                                           char **hostp, unsigned *portp)
+{
+    char   *myname = "lmtp_parse_destination";
+    char   *buf = mystrdup(destination);
+    char   *host = buf;
+    char   *service;
+    struct servent *sp;
+    char   *protocol = "tcp";          /* XXX configurable? */
+    unsigned port;
+
+    if (msg_verbose)
+       msg_info("%s: %s %s", myname, destination, def_service);
+
+    /*
+     * Strip quoting. We're working with a copy of the destination argument
+     * so the stripping can be destructive.
+     */
+    if (*host == '[') {
+       host++;
+       host[strcspn(host, "]")] = 0;
+    }
+
+    /*
+     * Separate host and service information, or use the default service
+     * specified by the caller. XXX the ":" character is used in the IPV6
+     * address notation, so using split_at_right() is not sufficient. We'd
+     * have to count the number of ":" instances.
+     */
+    if ((service = split_at_right(host, ':')) == 0)
+       service = def_service;
+    if (*service == 0)
+       msg_fatal("%s: empty service name: %s", myname, destination);
+    *hostp = host;
+
+    /*
+     * Convert service to port number, network byte order.
+     */
+    if ((port = atoi(service)) != 0) {
+       *portp = htons(port);
+    } else {
+        /* 
+         * Since most folks aren't going to have lmtp defined as a service,
+         * use a default value instead of just blowing up.
+         */
+       if ((sp = getservbyname(service, protocol)) == 0)
+            *portp = htons(var_lmtp_tcp_port);
+        else 
+            *portp = sp->s_port;
+    }
+    return (buf);
+}
+
+/* lmtp_connect_local - local connect to unix domain socket */
+
+LMTP_SESSION *lmtp_connect_local(const char *class, const char *name, VSTRING *why)
+{
+    char   *myname = "lmtp_connect_local";
+    VSTREAM *stream;
+    int     ch;
+
+    /*
+     * Connect to the LMTP server.
+     */
+    if (msg_verbose)
+       msg_info("%s: trying: %s/%s...", myname, class, name);
+    if ((stream = mail_connect_wait(class, name)) == 0) {
+        vstring_sprintf(why, "connect to %s: connection failed.", name);
+        lmtp_errno = LMTP_RETRY;
+        return (0);
+    }
+
+    /*
+     * Skip this process if it takes no action within some time limit.
+     */
+    if (read_wait(vstream_fileno(stream), var_lmtp_lhlo_tmout) < 0) {
+        vstring_sprintf(why, "connect to %s: read timeout", name);
+        lmtp_errno = LMTP_RETRY;
+        vstream_fclose(stream);
+        return (0);
+    }
+
+    /*
+     * Skip this process if it disconnects without talking to us.
+     */
+    if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
+       vstring_sprintf(why, "connect to %s: server dropped connection", name);
+       lmtp_errno = LMTP_RETRY;
+       vstream_fclose(stream);
+       return (0);
+    }
+
+    /*
+     * Skip this host if it sends a 4xx greeting.
+     */
+    if (ch == '4') {
+       vstring_sprintf(why, "connect to %s: server refused mail service", name);
+       lmtp_errno = LMTP_RETRY;
+       vstream_fclose(stream);
+       return (0);
+    }
+    vstream_ungetc(stream, ch);
+    return (lmtp_session_alloc(stream, name, ""));
+}
+
+/* lmtp_connect - establish LMTP connection */
+
+LMTP_SESSION *lmtp_connect(LMTP_ATTR *attr, DELIVER_REQUEST *request, VSTRING *why)
+{
+    char   *myname = "lmtp_connect";
+    LMTP_SESSION *session;
+    char   *dest_buf;
+    char   *host;
+    unsigned port;
+    char   *def_service = "lmtp";      /* XXX configurable? */
+
+    /*
+     * Are we connecting to a local or inet socket?
+     */
+    if (attr->type == LMTP_SERV_TYPE_UNIX) {
+        /*
+         * Connect to local LMTP server.
+         */
+        if (msg_verbose)
+            msg_info("%s: connecting to %s", myname, attr->name);
+        session = lmtp_connect_local(attr->class, attr->name, why);
+        if (session != 0) {
+            session->destination = mystrdup(attr->name);
+            session->type = attr->type;
+        }
+    } else {
+        /*
+         * Connect to LMTP server via inet socket, but where?
+         */
+        if (!*(attr)->name) {
+            if (msg_verbose)
+                msg_info("%s: attr->name not set; using request->nexthop", myname);
+            attr->name = request->nexthop;
+        }
+        dest_buf = lmtp_parse_destination(attr->name, def_service, 
+                                          &host, &port);
+        
+        /*
+         * Now that the inet LMTP server has been determined, connect to it.
+         */
+        if (msg_verbose)
+            msg_info("%s: connecting to %s port %d", myname, host, ntohs(port));
+        session = lmtp_connect_host(host, port, why);
+        if (session != 0) {
+            session->destination = mystrdup(attr->name);
+            session->type = attr->type;
+        }
+        myfree(dest_buf);
+    }
+    return (session);
+}
+
diff --git a/postfix/lmtp/lmtp_proto.c b/postfix/lmtp/lmtp_proto.c
new file mode 100644 (file)
index 0000000..76ae380
--- /dev/null
@@ -0,0 +1,686 @@
+/*++
+/* NAME
+/*     lmtp_proto 3
+/* SUMMARY
+/*     client LMTP protocol
+/* SYNOPSIS
+/*     #include "lmtp.h"
+/*
+/*     int     lmtp_lhlo(state)
+/*     LMTP_STATE *state;
+/*
+/*     int     lmtp_xfer(state)
+/*     LMTP_STATE *state;
+/*
+/*     int     lmtp_rset(state)
+/*     LMTP_STATE *state;
+/*
+/*     int     lmtp_quit(state)
+/*     LMTP_STATE *state;
+/* DESCRIPTION
+/*     This module implements the client side of the LMTP protocol.
+/*
+/*     lmtp_lhlo() performs the initial handshake with the LMTP server.
+/*
+/*     lmtp_xfer() sends message envelope information followed by the
+/*     message data, but does not finish the conversation. These operations
+/*     are combined in one function, in order to implement LMTP pipelining.
+/*     Recipients are marked as "done" in the mail queue file when
+/*     bounced or delivered. The message delivery status is updated
+/*     accordingly.
+/*
+/*     lmtp_rset() sends an RSET command and waits for the response.
+/*
+/*     lmtp_quit() sends a QUIT command and waits for the response.
+/* DIAGNOSTICS
+/*     lmtp_lhlo(), lmtp_xfer(), lmtp_rset() and lmtp_quit() return 0 in
+/*     case of success, -1 in case of failure. For lmtp_xfer(), lmtp_rset()
+/*     and lmtp_quit(), success means the ability to perform an LMTP
+/*     conversation, not necessarily OK replies from the server.
+/*
+/*     Warnings: corrupt message file. A corrupt message is marked
+/*     as "corrupt" by changing its queue file permissions.
+/* SEE ALSO
+/*     lmtp(3h) internal data structures
+/*     lmtp_chat(3) query/reply LMTP support
+/*     lmtp_trouble(3) error handlers
+/* 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
+/*
+/*     Pipelining code in cooperation with:
+/*     Jon Ribbens
+/*     Oaktree Internet Solutions Ltd.,
+/*     Internet House,
+/*     Canal Basin,
+/*     Coventry,
+/*     CV1 4LY, United Kingdom.
+/*
+/*     Alterations for LMTP by:
+/*     Philip A. Prindeville
+/*     Mirapoint, Inc.
+/*     USA.
+/*
+/*     Additional work on LMTP by:
+/*     Amos Gouaux
+/*     University of Texas at Dallas
+/*     P.O. Box 830688, MC34
+/*     Richardson, TX 75083, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/stat.h>
+#include <sys/socket.h>                        /* shutdown(2) */
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <vstring_vstream.h>
+#include <stringops.h>
+#include <mymalloc.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <smtp_stream.h>
+#include <mail_queue.h>
+#include <recipient_list.h>
+#include <deliver_request.h>
+#include <deliver_completed.h>
+#include <defer.h>
+#include <bounce.h>
+#include <sent.h>
+#include <record.h>
+#include <rec_type.h>
+#include <off_cvt.h>
+#include <mark_corrupt.h>
+
+/* Application-specific. */
+
+#include "lmtp.h"
+#include "quote_821_local.h"
+
+ /*
+  * Sender and receiver state. A session does not necessarily go through a
+  * linear progression, but states are guaranteed to not jump backwards.
+  * Normal sessions go from MAIL->RCPT->DATA->DOT->LAST. The states MAIL,
+  * RCPT, and DATA may also be followed by ABORT->LAST.
+  * 
+  * In order to support connection cacheing, no QUIT is send at the end of mail
+  * delivery. Instead, at the start of the next mail delivery, the client
+  * sends RSET to find out if the server is still there, and sends QUIT only
+  * when closing a connection. The RSET and QUIT commands are sent all by
+  * themselves in non-pipelining mode. The respective state transitions are
+  * RSET->LAST and QUIT->LAST.
+  * 
+  * For the sake of code reuse, the non-pipelined RSET and QUIT commands are
+  * sent by the same code that implements command pipelining, so that we can
+  * borrow from the existing code for exception handling and error reporting.
+  * 
+  */
+#define LMTP_STATE_MAIL                0
+#define LMTP_STATE_RCPT                1
+#define LMTP_STATE_DATA                2
+#define LMTP_STATE_DOT         3
+#define LMTP_STATE_ABORT       4
+#define LMTP_STATE_RSET                5
+#define LMTP_STATE_QUIT                6
+#define LMTP_STATE_LAST                7
+
+int    *xfer_timeouts[LMTP_STATE_LAST] = {
+    &var_lmtp_mail_tmout,
+    &var_lmtp_rcpt_tmout,
+    &var_lmtp_data0_tmout,
+    &var_lmtp_data2_tmout,
+    &var_lmtp_rset_tmout,
+    &var_lmtp_rset_tmout,
+    &var_lmtp_quit_tmout,
+};
+
+char   *xfer_states[LMTP_STATE_LAST] = {
+    "sending MAIL FROM",
+    "sending RCPT TO",
+    "sending DATA command",
+    "sending end of data -- message may be sent more than once",
+    "sending RSET",
+    "sending RSET",
+    "sending QUIT",
+};
+
+/* lmtp_lhlo - perform initial handshake with LMTP server */
+
+int     lmtp_lhlo(LMTP_STATE *state)
+{
+    char   *myname = "lmtp_lhlo";
+    LMTP_SESSION *session = state->session;
+    DELIVER_REQUEST *request = state->request;
+    LMTP_RESP *resp;
+    int     except;
+    char   *lines;
+    char   *words;
+    char   *word;
+    int     n;
+    SOCKOPT_SIZE optlen = sizeof(state->sndbufsize);
+
+    /*
+     * Prepare for disaster.
+     */
+    smtp_timeout_setup(state->session->stream, var_lmtp_lhlo_tmout);
+    if ((except = vstream_setjmp(state->session->stream)) != 0)
+       return (lmtp_stream_except(state, except, "sending LHLO"));
+
+    /*
+     * Read and parse the server's LMTP greeting banner.
+     */
+    if (((resp = lmtp_chat_resp(state))->code / 100) != 2)
+       return (lmtp_site_fail(state, resp->code,
+                              "%s refused to talk to me: %s",
+                           session->host, translit(resp->str, "\n", " ")));
+
+    /*
+     * See if we are talking to ourself. This should not be possible with the
+     * way we implement DNS lookups. However, people are known to sometimes
+     * screw up the naming service. And, mailer loops are still possible when
+     * our own mailer routing tables are mis-configured.
+     */
+    words = resp->str;
+
+    /*
+     * Return the compliment.
+     */
+    lmtp_chat_cmd(state, "LHLO %s", var_myhostname);
+    if ((resp = lmtp_chat_resp(state))->code / 100 != 2)
+       return (lmtp_site_fail(state, resp->code,
+                              "%s refused to talk to me: %s",
+                              session->host,
+                              translit(resp->str, "\n", " ")));
+
+    /*
+     * Pick up some useful features offered by the LMTP server. XXX Until we
+     * have a portable routine to convert from string to off_t with proper
+     * overflow detection, ignore the message size limit advertised by the
+     * LMTP server. Otherwise, we might do the wrong thing when the server
+     * advertises a really huge message size limit.
+     */
+    lines = resp->str;
+    (void) mystrtok(&lines, "\n");
+    while ((words = mystrtok(&lines, "\n")) != 0) {
+       if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) {
+           if (strcasecmp(word, "8BITMIME") == 0)
+               state->features |= LMTP_FEATURE_8BITMIME;
+           else if (strcasecmp(word, "PIPELINING") == 0)
+               state->features |= LMTP_FEATURE_PIPELINING;
+           else if (strcasecmp(word, "SIZE") == 0)
+               state->features |= LMTP_FEATURE_SIZE;
+       }
+    }
+    if (msg_verbose)
+       msg_info("server features: 0x%x", state->features);
+
+    /*
+     * We use LMTP command pipelining if the server said it supported it.
+     * Since we use blocking I/O, RFC 2197 says that we should inspect the
+     * TCP window size and not send more than this amount of information.
+     * Unfortunately this information is not available using the sockets
+     * interface. However, we *can* get the TCP send buffer size on the local
+     * TCP/IP stack. We should be able to fill this buffer without being
+     * blocked, and then the kernel will effectively do non-blocking I/O for
+     * us by automatically writing out the contents of its send buffer while
+     * we are reading in the responses. In addition to TCP buffering we have
+     * to be aware of application-level buffering by the vstream module,
+     * which is limited to a couple kbytes.
+     * 
+     * Don't worry about command pipelining for local connections.
+     */
+    if (state->features & LMTP_FEATURE_PIPELINING
+       && state->session->type != LMTP_SERV_TYPE_UNIX) {
+       if (getsockopt(vstream_fileno(state->session->stream), SOL_SOCKET,
+                      SO_SNDBUF, (char *) &state->sndbufsize, &optlen) < 0)
+           msg_fatal("%s: getsockopt: %m", myname);
+       if (msg_verbose)
+           msg_info("Using LMTP PIPELINING, TCP send buffer size is %d",
+                    state->sndbufsize);
+    } else
+       state->sndbufsize = 0;
+    state->sndbuffree = state->sndbufsize;
+
+    return (0);
+}
+
+/* lmtp_loop - the LMTP state machine */
+
+static int lmtp_loop(LMTP_STATE *state, int init_state)
+{
+    char   *myname = "lmtp_loop";
+    DELIVER_REQUEST *request = state->request;
+    LMTP_SESSION *session = state->session;
+    LMTP_RESP *resp;
+    RECIPIENT *rcpt;
+    VSTRING *next_command = vstring_alloc(100);
+    int    *survivors = 0;
+    int     next_state;
+    int     next_rcpt;
+    int     send_state;
+    int     recv_state;
+    int     send_rcpt;
+    int     recv_rcpt;
+    int     nrcpt;
+    int     except;
+    int     rec_type;
+    int     prev_type = 0;
+    int     mail_from_rejected;
+    int     recv_dot;
+
+    /*
+     * Macros for readability. XXX Isn't LMTP supposed to be case
+     * insensitive?
+     */
+#define REWRITE_ADDRESS(addr) do { \
+         if (*(addr)) { \
+             quote_821_local(state->scratch, addr); \
+             myfree(addr); \
+             addr = mystrdup(vstring_str(state->scratch)); \
+             lowercase(addr); \
+         } \
+    } while (0)
+
+#define RETURN(x) do { \
+         vstring_free(next_command); \
+         if (survivors) \
+             myfree((char *) survivors); \
+         return (x); \
+    } while (0)
+
+#define SENDER_IS_AHEAD \
+       (recv_state < send_state || recv_rcpt != send_rcpt)
+
+#define SENDER_IN_WAIT_STATE \
+       (send_state == LMTP_STATE_DOT || send_state == LMTP_STATE_LAST)
+
+    /*
+     * Pipelining support requires two loops: one loop for sending and one
+     * for receiving. Each loop has its own independent state. Most of the
+     * time the sender can run ahead of the receiver by as much as the TCP
+     * send buffer permits. There are only two places where the sender must
+     * wait for status information from the receiver: once after sending DATA
+     * and once after sending QUIT.
+     * 
+     * The sender state advances until the TCP send buffer would overflow, or
+     * until the sender needs status information from the receiver. At that
+     * point the receiver starts processing responses. Once the receiver has
+     * caught up with the sender, the sender resumes sending commands. If the
+     * receiver detects a serious problem (MAIL FROM rejected, all RCPT TO
+     * commands rejected, DATA rejected) it forces the sender to abort the
+     * LMTP dialog with RSET.
+     */
+    nrcpt = 0;
+    recv_state = send_state = init_state;
+    next_rcpt = send_rcpt = recv_rcpt = recv_dot = 0;
+    mail_from_rejected = 0;
+
+    while (recv_state != LMTP_STATE_LAST) {
+
+       /*
+        * Build the next command.
+        */
+       switch (send_state) {
+
+           /*
+            * Sanity check.
+            */
+       default:
+           msg_panic("%s: bad sender state %d", myname, send_state);
+
+           /*
+            * Build the MAIL FROM command.
+            */
+       case LMTP_STATE_MAIL:
+           if (*request->sender)
+               REWRITE_ADDRESS(request->sender);
+           vstring_sprintf(next_command, "MAIL FROM:<%s>", request->sender);
+           if (state->features & LMTP_FEATURE_SIZE)
+               vstring_sprintf_append(next_command, " SIZE=%lu",
+                                      request->data_size);
+           next_state = LMTP_STATE_RCPT;
+           break;
+
+           /*
+            * Build one RCPT TO command before we have seen the MAIL FROM
+            * response.
+            */
+       case LMTP_STATE_RCPT:
+           rcpt = request->rcpt_list.info + send_rcpt;
+           REWRITE_ADDRESS(rcpt->address);
+           vstring_sprintf(next_command, "RCPT TO:<%s>", rcpt->address);
+           if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
+               next_state = LMTP_STATE_DATA;
+           break;
+
+           /*
+            * Build the DATA command before we have seen all the RCPT TO
+            * responses.
+            */
+       case LMTP_STATE_DATA:
+           vstring_strcpy(next_command, "DATA");
+           next_state = LMTP_STATE_DOT;
+           break;
+
+           /*
+            * Build the "." command before we have seen the DATA response.
+            */
+       case LMTP_STATE_DOT:
+           vstring_strcpy(next_command, ".");
+           next_state = LMTP_STATE_LAST;
+           break;
+
+           /*
+            * Can't happen. The LMTP_STATE_ABORT sender state is entered by
+            * the receiver and is left before the bottom of the main loop.
+            */
+       case LMTP_STATE_ABORT:
+           msg_panic("%s: sender abort state", myname);
+
+           /*
+            * Build the RSET command. XXX This command does not belong here
+            * because it will be sent in non-pipelining mode. But having it
+            * here means that we can reuse existing code for error handling.
+            */
+       case LMTP_STATE_RSET:
+           vstring_strcpy(next_command, "RSET");
+           next_state = LMTP_STATE_LAST;
+           break;
+
+           /*
+            * Build the QUIT command. XXX This command does not belong here
+            * because it will be sent in non-pipelining mode. But having it
+            * here means that we can reuse existing code for error handling.
+            */
+       case LMTP_STATE_QUIT:
+           vstring_strcpy(next_command, "QUIT");
+           next_state = LMTP_STATE_LAST;
+           break;
+
+           /*
+            * The final sender state has no action associated with it.
+            */
+       case LMTP_STATE_LAST:
+           VSTRING_RESET(next_command);
+           break;
+       }
+       VSTRING_TERMINATE(next_command);
+
+       /*
+        * Process responses until the receiver has caught up. Vstreams
+        * automatically flush buffered output when reading new data.
+        */
+       if (SENDER_IN_WAIT_STATE
+           || (SENDER_IS_AHEAD
+               && VSTRING_LEN(next_command) + 2 > state->sndbuffree)) {
+           while (SENDER_IS_AHEAD) {
+
+               /*
+                * Sanity check.
+                */
+               if (recv_state < LMTP_STATE_MAIL
+                   || recv_state > LMTP_STATE_QUIT)
+                   msg_panic("%s: bad receiver state %d (sender state %d)",
+                             myname, recv_state, send_state);
+
+               /*
+                * Receive the next server response. Use the proper timeout,
+                * and log the proper client state in case of trouble.
+                */
+               smtp_timeout_setup(state->session->stream,
+                                  *xfer_timeouts[recv_state]);
+               if ((except = vstream_setjmp(state->session->stream)) != 0)
+                   RETURN(lmtp_stream_except(state, except,
+                                             xfer_states[recv_state]));
+               resp = lmtp_chat_resp(state);
+
+               /*
+                * Process the response.
+                */
+               switch (recv_state) {
+
+                   /*
+                    * Process the MAIL FROM response. When the server
+                    * rejects the sender, set the mail_from_rejected flag so
+                    * that the receiver may apply a course correction.
+                    */
+               case LMTP_STATE_MAIL:
+                   if (resp->code / 100 != 2) {
+                       lmtp_mesg_fail(state, resp->code,
+                                      "%s said: %s", session->host,
+                                      translit(resp->str, "\n", " "));
+                       mail_from_rejected = 1;
+                   }
+                   recv_state = LMTP_STATE_RCPT;
+                   break;
+
+                   /*
+                    * Process one RCPT TO response. If MAIL FROM was
+                    * rejected, ignore RCPT TO responses: all recipients are
+                    * dead already. When all recipients are rejected the
+                    * receiver may apply a course correction.
+                    */
+               case LMTP_STATE_RCPT:
+                   if (!mail_from_rejected) {
+                       rcpt = request->rcpt_list.info + recv_rcpt;
+                       if (resp->code / 100 == 2) {
+                           if (survivors == 0)
+                               survivors = (int *)
+                                   mymalloc(request->rcpt_list.len
+                                            * sizeof(int));
+                           survivors[nrcpt++] = recv_rcpt;
+                       } else {
+                           lmtp_rcpt_fail(state, resp->code, rcpt,
+                                          "%s said: %s", session->host,
+                                          translit(resp->str, "\n", " "));
+                           rcpt->offset = 0;   /* in case deferred */
+                       }
+                   }
+                   if (++recv_rcpt == request->rcpt_list.len)
+                       recv_state = LMTP_STATE_DATA;
+                   break;
+
+                   /*
+                    * Process the DATA response. When the server rejects
+                    * DATA, set nrcpt to a negative value so that the
+                    * receiver can apply a course correction.
+                    */
+               case LMTP_STATE_DATA:
+                   if (resp->code / 100 != 3) {
+                       if (nrcpt > 0)
+                           lmtp_mesg_fail(state, resp->code,
+                                          "%s said: %s", session->host,
+                                          translit(resp->str, "\n", " "));
+                       nrcpt = -1;
+                   }
+                   recv_state = LMTP_STATE_DOT;
+                   break;
+
+                   /*
+                    * Process the end of message response. Ignore the
+                    * response when no recipient was accepted: all
+                    * recipients are dead already, and the next receiver
+                    * state is LMTP_STATE_LAST regardless. Otherwise, if the
+                    * message transfer fails, bounce all remaining
+                    * recipients, else cross off the recipients that were
+                    * delivered.
+                    */
+               case LMTP_STATE_DOT:
+                   if (nrcpt > 0) {
+                       rcpt = request->rcpt_list.info + survivors[recv_dot];
+                       if (resp->code / 100 == 2) {
+                           if (rcpt->offset) {
+                               sent(request->queue_id, rcpt->address,
+                                    session->host, request->arrival_time,
+                                    "%s", resp->str);
+                               deliver_completed(state->src, rcpt->offset);
+                               rcpt->offset = 0;
+                           }
+                       } else {
+                           lmtp_rcpt_fail(state, resp->code, rcpt,
+                                          "%s said: %s", session->host,
+                                          translit(resp->str, "\n", " "));
+                           rcpt->offset = 0;   /* in case deferred */
+                       }
+                   }
+
+                   /*
+                    * We get one response per valid RCPT TO:
+                    */
+                   if (msg_verbose)
+                       msg_info("%s: recv_dot = %d", myname, recv_dot);
+                   if (++recv_dot >= nrcpt) {
+                       if (msg_verbose)
+                           msg_info("%s: finished . command", myname);
+                       recv_state = LMTP_STATE_LAST;
+                   }
+                   break;
+
+                   /*
+                    * Ignore the RSET response.
+                    */
+               case LMTP_STATE_ABORT:
+                   recv_state = LMTP_STATE_LAST;
+                   break;
+
+                   /*
+                    * Ignore the RSET response.
+                    */
+               case LMTP_STATE_RSET:
+                   recv_state = LMTP_STATE_LAST;
+                   break;
+
+                   /*
+                    * Ignore the QUIT response.
+                    */
+               case LMTP_STATE_QUIT:
+                   recv_state = LMTP_STATE_LAST;
+                   break;
+               }
+           }
+
+           /*
+            * At this point, the sender and receiver are fully synchronized,
+            * so that the entire TCP send buffer becomes available again.
+            */
+           state->sndbuffree = state->sndbufsize;
+
+           /*
+            * We know the server response to every command that was sent.
+            * Apply a course correction if necessary: the sender wants to
+            * send RCPT TO but MAIL FROM was rejected; the sender wants to
+            * send DATA but all recipients were rejected; the sender wants
+            * to deliver the message but DATA was rejected.
+            */
+           if ((send_state == LMTP_STATE_RCPT && mail_from_rejected)
+               || (send_state == LMTP_STATE_DATA && nrcpt == 0)
+               || (send_state == LMTP_STATE_DOT && nrcpt < 0)) {
+               send_state = recv_state = LMTP_STATE_ABORT;
+               send_rcpt = recv_rcpt = 0;
+               vstring_strcpy(next_command, "RSET");
+               next_state = LMTP_STATE_LAST;
+               next_rcpt = 0;
+           }
+       }
+
+       /*
+        * Make the next sender state the current sender state.
+        */
+       if (send_state == LMTP_STATE_LAST)
+           continue;
+
+       /*
+        * Special case if the server accepted the DATA command. If the
+        * server accepted at least one recipient send the entire message.
+        * Otherwise, just send "." as per RFC 2197.
+        */
+       if (send_state == LMTP_STATE_DOT && nrcpt > 0) {
+           smtp_timeout_setup(state->session->stream,
+                              var_lmtp_data1_tmout);
+           if ((except = vstream_setjmp(state->session->stream)) != 0)
+               RETURN(lmtp_stream_except(state, except,
+                                         "sending message body"));
+
+           if (vstream_fseek(state->src, request->data_offset, SEEK_SET) < 0)
+               msg_fatal("seek queue file: %m");
+
+           while ((rec_type = rec_get(state->src, state->scratch, 0)) > 0) {
+               if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
+                   break;
+               if (prev_type != REC_TYPE_CONT)
+                   if (vstring_str(state->scratch)[0] == '.')
+                       smtp_fputc('.', session->stream);
+               if (rec_type == REC_TYPE_CONT)
+                   smtp_fwrite(vstring_str(state->scratch),
+                               VSTRING_LEN(state->scratch),
+                               session->stream);
+               else
+                   smtp_fputs(vstring_str(state->scratch),
+                              VSTRING_LEN(state->scratch),
+                              session->stream);
+               prev_type = rec_type;
+           }
+
+           if (prev_type == REC_TYPE_CONT)     /* missing newline at end */
+               smtp_fputs("", 0, session->stream);
+           if (vstream_ferror(state->src))
+               msg_fatal("queue file read error");
+           if (rec_type != REC_TYPE_XTRA)
+               RETURN(mark_corrupt(state->src));
+       }
+
+       /*
+        * Copy the next command to the buffer and update the sender state.
+        */
+       if (state->sndbuffree > 0)
+           state->sndbuffree -= VSTRING_LEN(next_command) + 2;
+       lmtp_chat_cmd(state, "%s", vstring_str(next_command));
+       send_state = next_state;
+       send_rcpt = next_rcpt;
+    }
+
+    RETURN(0);
+}
+
+/* lmtp_xfer - send a batch of envelope information and the message data */
+
+int     lmtp_xfer(LMTP_STATE *state)
+{
+    return (lmtp_loop(state, LMTP_STATE_MAIL));
+}
+
+/* lmtp_rset - reset dialog with peer */
+
+int     lmtp_rset(LMTP_STATE *state)
+{
+    return (lmtp_loop(state, LMTP_STATE_RSET));
+}
+
+/* lmtp_quit - say goodbye to peer */
+
+int     lmtp_quit(LMTP_STATE *state)
+{
+    return (lmtp_loop(state, LMTP_STATE_QUIT));
+}
diff --git a/postfix/lmtp/lmtp_session.c b/postfix/lmtp/lmtp_session.c
new file mode 100644 (file)
index 0000000..80471df
--- /dev/null
@@ -0,0 +1,105 @@
+/*++
+/* NAME
+/*     lmtp_session 3
+/* SUMMARY
+/*     LMTP_SESSION structure management
+/* SYNOPSIS
+/*     #include "lmtp.h"
+/*
+/*     LMTP_SESSION *lmtp_session_alloc(stream, host, addr)
+/*     VSTREAM *stream;
+/*     char    *host;
+/*     char    *addr;
+/*
+/*     void    lmtp_session_free(session)
+/*     LMTP_SESSION *session;
+/*
+/*     void    lmtp_session_reset(state)
+/*     LMTP_STATE *state;
+/* DESCRIPTION
+/*     lmtp_session_alloc() allocates memory for an LMTP_SESSION structure
+/*     and initializes it with the given stream and host name and address
+/*     information.  The host name and address strings are copied. The code
+/*     assumes that the stream is connected to the "best" alternative.
+/*
+/*     lmtp_session_free() destroys an LMTP_SESSION structure and its
+/*     members, making memory available for reuse.
+/*
+/*      lmtp_session_reset() is just a little helper to make sure everything
+/*      is set to zero after the session has been freed.  This means I don't
+/*      have to keep repeating the same chunks of code for cached connections.
+/* 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
+/*
+/*      Alterations for LMTP by:
+/*      Philip A. Prindeville
+/*      Mirapoint, Inc.
+/*      USA.
+/*
+/*      Additional work on LMTP by:
+/*      Amos Gouaux
+/*      University of Texas at Dallas
+/*      P.O. Box 830688, MC34
+/*      Richardson, TX 75083, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <vstream.h>
+
+/* Application-specific. */
+
+#include "lmtp.h"
+
+/* lmtp_session_alloc - allocate and initialize LMTP_SESSION structure */
+
+LMTP_SESSION *lmtp_session_alloc(VSTREAM *stream, char *host, char *addr)
+{
+    LMTP_SESSION *session;
+
+    session = (LMTP_SESSION *) mymalloc(sizeof(*session));
+    session->stream = stream;
+    session->host = mystrdup(host);
+    session->addr = mystrdup(addr);
+    session->destination = 0;
+    return (session);
+}
+
+/* lmtp_session_free - destroy LMTP_SESSION structure and contents */
+
+void    lmtp_session_free(LMTP_SESSION *session)
+{
+    if (vstream_ispipe(session->stream))
+       vstream_pclose(session->stream);
+    else
+       vstream_fclose(session->stream);
+    myfree(session->host);
+    myfree(session->addr);
+    if (session->destination)
+       myfree(session->destination);
+    myfree((char *) session);
+}
+
+/* lmtp_session_reset - clean things up so a new session can be created */
+
+void    lmtp_session_reset(LMTP_STATE *state)
+{
+    if (state->session) {
+        lmtp_session_free(state->session);
+        state->session = 0;
+    }
+    state->reuse = 0;
+}
+
diff --git a/postfix/lmtp/lmtp_state.c b/postfix/lmtp/lmtp_state.c
new file mode 100644 (file)
index 0000000..c52bfb9
--- /dev/null
@@ -0,0 +1,92 @@
+/*++
+/* NAME
+/*     lmtp_state 8
+/* SUMMARY
+/*     initialize/cleanup shared state
+/* SYNOPSIS
+/*     #include "lmtp.h"
+/*
+/*     LMTP_STATE *lmtp_state_alloc()
+/*
+/*     void    lmtp_state_free(state)
+/*     LMTP_STATE *state;
+/* DESCRIPTION
+/*     lmtp_state_init() initializes the shared state, and allocates
+/*     memory for buffers etc.
+/*
+/*     lmtp_cleanup() destroys memory allocated by lmtp_state_init().
+/* STANDARDS
+/* DIAGNOSTICS
+/* BUGS
+/* SEE ALSO
+/* 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
+/*
+/*      Alterations for LMTP by:
+/*      Philip A. Prindeville
+/*      Mirapoint, Inc.
+/*      USA.
+/*
+/*      Additional work on LMTP by:
+/*      Amos Gouaux
+/*      University of Texas at Dallas
+/*      P.O. Box 830688, MC34
+/*      Richardson, TX 75083, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <vstring.h>
+#include <vstream.h>
+
+/* Global library. */
+
+#include <config.h>
+
+/* Application-specific. */
+
+#include "lmtp.h"
+
+/* lmtp_state_alloc - initialize */
+
+LMTP_STATE *lmtp_state_alloc(void)
+{
+    LMTP_STATE *state = (LMTP_STATE *) mymalloc(sizeof(*state));
+
+    state->src = 0;
+    state->request = 0;
+    state->session = 0;
+    state->buffer = vstring_alloc(100);
+    state->scratch = vstring_alloc(100);
+    state->scratch2 = vstring_alloc(100);
+    state->status = 0;
+    state->features = 0;
+    state->history = 0;
+    state->error_mask = 0;
+    state->sndbufsize = 0;
+    state->sndbuffree = 0;
+    state->reuse = 0;
+    return (state);
+}
+
+/* lmtp_state_free - destroy state */
+
+void    lmtp_state_free(LMTP_STATE *state)
+{
+    vstring_free(state->buffer);
+    vstring_free(state->scratch);
+    vstring_free(state->scratch2);
+    myfree((char *) state);
+}
diff --git a/postfix/lmtp/lmtp_trouble.c b/postfix/lmtp/lmtp_trouble.c
new file mode 100644 (file)
index 0000000..9a13b69
--- /dev/null
@@ -0,0 +1,318 @@
+/*++
+/* NAME
+/*     lmtp_trouble 3
+/* SUMMARY
+/*     error handler policies
+/* SYNOPSIS
+/*     #include "lmtp.h"
+/*
+/*     int     lmtp_site_fail(state, code, format, ...)
+/*     LMTP_STATE *state;
+/*     int     code;
+/*     char    *format;
+/*
+/*     int     lmtp_mesg_fail(state, code, format, ...)
+/*     LMTP_STATE *state;
+/*     int     code;
+/*     char    *format;
+/*
+/*     void    lmtp_rcpt_fail(state, code, recipient, format, ...)
+/*     LMTP_STATE *state;
+/*     int     code;
+/*     RECIPIENT *recipient;
+/*     char    *format;
+/*
+/*     int     lmtp_stream_except(state, exception, description)
+/*     LMTP_STATE *state;
+/*     int     exception;
+/*     char    *description;
+/* DESCRIPTION
+/*     This module handles all non-fatal errors that can happen while
+/*     attempting to deliver mail via LMTP, and implements the policy
+/*     of how to deal with the error. Depending on the nature of
+/*     the problem, delivery of a single message is deferred, delivery
+/*     of all messages to the same domain is deferred, or one or more
+/*     recipients are given up as non-deliverable and a bounce log is
+/*     updated.
+/*
+/*     In addition, when an unexpected response code is seen such
+/*     as 3xx where only 4xx or 5xx are expected, or any error code
+/*     that suggests a syntax error or something similar, the
+/*     protocol error flag is set so that the postmaster receives
+/*     a transcript of the session. No notification is generated for
+/*     what appear to be configuration errors - very likely, they
+/*     would suffer the same problem and just cause more trouble.
+/*
+/*     lmtp_site_fail() handles the case where the program fails to
+/*     complete the initial LMTP handshake: the server is not reachable,
+/*     is not running, does not want talk to us, or we talk to ourselves.
+/*     The \fIcode\fR gives an error status code; the \fIformat\fR
+/*     argument gives a textual description.  The policy is: soft
+/*     error: defer delivery of all messages to this domain; hard
+/*     error: bounce all recipients of this message.
+/*     The result is non-zero.
+/*
+/*     lmtp_mesg_fail() handles the case where the lmtp server
+/*     does not accept the sender address or the message data.
+/*     The policy is: soft errors: defer delivery of this message;
+/*     hard error: bounce all recipients of this message.
+/*     The result is non-zero.
+/*
+/*     lmtp_rcpt_fail() handles the case where a recipient is not
+/*     accepted by the server for reasons other than that the server
+/*     recipient limit is reached. The policy is: soft error: defer
+/*     delivery to this recipient; hard error: bounce this recipient.
+/*
+/*     lmtp_stream_except() handles the exceptions generated by
+/*     the smtp_stream(3) module (i.e. timeouts and I/O errors).
+/*     The \fIexception\fR argument specifies the type of problem.
+/*     The \fIdescription\fR argument describes at what stage of
+/*     the LMTP dialog the problem happened. The policy is to defer
+/*     delivery of all messages to the same domain. The result is non-zero.
+/* DIAGNOSTICS
+/*     Panic: unknown exception code.
+/* SEE ALSO
+/*     lmtp_proto(3) lmtp high-level protocol
+/*     smtp_stream(3) lmtp low-level protocol
+/*     defer(3) basic message defer interface
+/*     bounce(3) basic message bounce interface
+/* 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
+/*
+/*     Alterations for LMTP by:
+/*     Philip A. Prindeville
+/*     Mirapoint, Inc.
+/*     USA.
+/*
+/*     Additional work on LMTP by:
+/*     Amos Gouaux
+/*     University of Texas at Dallas
+/*     P.O. Box 830688, MC34
+/*     Richardson, TX 75083, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <stringops.h>
+#include <mymalloc.h>
+
+/* Global library. */
+
+#include <smtp_stream.h>
+#include <deliver_request.h>
+#include <deliver_completed.h>
+#include <bounce.h>
+#include <defer.h>
+#include <mail_error.h>
+
+/* Application-specific. */
+
+#include "lmtp.h"
+
+#define LMTP_SOFT(code) (((code) / 100) == 4)
+#define LMTP_HARD(code) (((code) / 100) == 5)
+#define KEEP           BOUNCE_FLAG_KEEP
+
+/* lmtp_check_code - check response code */
+
+static void lmtp_check_code(LMTP_STATE *state, int code)
+{
+
+    /*
+     * The intention of this stuff is to alert the postmaster when the local
+     * Postfix LMTP client screws up, protocol wise. RFC 821 says that x0z
+     * replies "refer to syntax errors, syntactically correct commands that
+     * don't fit any functional category, and unimplemented or superfluous
+     * commands". Unfortunately, this also triggers postmaster notices when
+     * remote servers screw up, protocol wise. This is becoming a common
+     * problem now that response codes are configured manually as part of
+     * anti-UCE systems, by people who aren't aware of RFC details.
+     */
+    if ((!LMTP_SOFT(code) && !LMTP_HARD(code))
+       || code == 555                  /* RFC 1869, section 6.1. */
+       || (code >= 500 && code < 510))
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+}
+
+/* lmtp_site_fail - defer site or bounce recipients */
+
+int     lmtp_site_fail(LMTP_STATE *state, int code, char *format,...)
+{
+    DELIVER_REQUEST *request = state->request;
+    LMTP_SESSION *session = state->session;
+    RECIPIENT *rcpt;
+    int     status;
+    int     nrcpt;
+    int     soft_error = LMTP_SOFT(code);
+    va_list ap;
+    VSTRING *why = vstring_alloc(100);
+
+    /*
+     * Initialize.
+     */
+    va_start(ap, format);
+    vstring_vsprintf(why, format, ap);
+    va_end(ap);
+
+    /*
+     * If this is a soft error, postpone further deliveries to this domain.
+     * Otherwise, generate a bounce record for each recipient.
+     */
+    for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+       rcpt = request->rcpt_list.info + nrcpt;
+       if (rcpt->offset == 0)
+           continue;
+       status = (soft_error ? defer_append : bounce_append)
+           (KEEP, request->queue_id, rcpt->address,
+            session ? session->host : "none",
+            request->arrival_time, "%s", vstring_str(why));
+       if (status == 0) {
+           deliver_completed(state->src, rcpt->offset);
+           rcpt->offset = 0;
+       }
+       state->status |= status;
+    }
+    if (soft_error && request->hop_status == 0)
+       request->hop_status = mystrdup(vstring_str(why));
+
+    /*
+     * Cleanup.
+     */
+    vstring_free(why);
+    return (-1);
+}
+
+/* lmtp_mesg_fail - defer message or bounce all recipients */
+
+int     lmtp_mesg_fail(LMTP_STATE *state, int code, char *format,...)
+{
+    DELIVER_REQUEST *request = state->request;
+    LMTP_SESSION *session = state->session;
+    RECIPIENT *rcpt;
+    int     status;
+    int     nrcpt;
+    va_list ap;
+    VSTRING *why = vstring_alloc(100);
+
+    /*
+     * Initialize.
+     */
+    va_start(ap, format);
+    vstring_vsprintf(why, format, ap);
+    va_end(ap);
+
+    /*
+     * If this is a soft error, postpone delivery of this message. Otherwise,
+     * generate a bounce record for each recipient.
+     */
+    for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+       rcpt = request->rcpt_list.info + nrcpt;
+       if (rcpt->offset == 0)
+           continue;
+       status = (LMTP_SOFT(code) ? defer_append : bounce_append)
+           (KEEP, request->queue_id, rcpt->address,
+            session->host, request->arrival_time,
+            "%s", vstring_str(why));
+       if (status == 0) {
+           deliver_completed(state->src, rcpt->offset);
+           rcpt->offset = 0;
+       }
+       state->status |= status;
+    }
+    lmtp_check_code(state, code);
+
+    /*
+     * Cleanup.
+     */
+    vstring_free(why);
+    return (-1);
+}
+
+/* lmtp_rcpt_fail - defer or bounce recipient */
+
+void    lmtp_rcpt_fail(LMTP_STATE *state, int code, RECIPIENT *rcpt,
+                              char *format,...)
+{
+    DELIVER_REQUEST *request = state->request;
+    LMTP_SESSION *session = state->session;
+    int     status;
+    va_list ap;
+
+    /*
+     * If this is a soft error, postpone delivery to this recipient.
+     * Otherwise, generate a bounce record for this recipient.
+     */
+    va_start(ap, format);
+    status = (LMTP_SOFT(code) ? vdefer_append : vbounce_append)
+       (KEEP, request->queue_id, rcpt->address, session->host,
+        request->arrival_time, format, ap);
+    va_end(ap);
+    if (status == 0) {
+       deliver_completed(state->src, rcpt->offset);
+       rcpt->offset = 0;
+    }
+    lmtp_check_code(state, code);
+    state->status |= status;
+}
+
+/* lmtp_stream_except - defer domain after I/O problem */
+
+int     lmtp_stream_except(LMTP_STATE *state, int code, char *description)
+{
+    DELIVER_REQUEST *request = state->request;
+    LMTP_SESSION *session = state->session;
+    RECIPIENT *rcpt;
+    int     nrcpt;
+    VSTRING *why = vstring_alloc(100);
+
+    /*
+     * Initialize.
+     */
+    switch (code) {
+    default:
+       msg_panic("lmtp_stream_except: unknown exception %d", code);
+    case SMTP_ERR_EOF:
+       vstring_sprintf(why, "lost connection with %s while %s",
+                       session->host, description);
+       break;
+    case SMTP_ERR_TIME:
+       vstring_sprintf(why, "conversation with %s timed out while %s",
+                       session->host, description);
+       break;
+    }
+
+    /*
+     * At this point, the status of individual recipients remains unresolved.
+     * All we know is that we should stay away from this host for a while.
+     */
+    for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+       rcpt = request->rcpt_list.info + nrcpt;
+       if (rcpt->offset == 0)
+           continue;
+       state->status |= defer_append(KEEP, request->queue_id,
+                                     rcpt->address, session->host,
+                                     request->arrival_time,
+                                     "%s", vstring_str(why));
+    }
+
+    /*
+     * Cleanup.
+     */
+    vstring_free(why);
+    return (-1);
+}
diff --git a/postfix/lmtp/mail b/postfix/lmtp/mail
new file mode 100644 (file)
index 0000000..35b9743
--- /dev/null
@@ -0,0 +1,753 @@
+From wietse@porcupine.org  Sat Apr 15 10:47:09 2000
+Return-Path: <wietse@porcupine.org>
+Delivered-To: wietse@hades.porcupine.org
+Received: from spike.porcupine.org (spike.porcupine.org [168.100.189.2])
+       by hades.porcupine.org (Postfix) with ESMTP id 567DC18A54
+       for <wietse@hades.porcupine.org>; Sat, 15 Apr 2000 10:47:09 -0400 (EDT)
+Received: by spike.porcupine.org (Postfix, from userid 100)
+       id BE9C14563D; Sat, 15 Apr 2000 10:47:08 -0400 (EDT)
+Delivered-To: wietse@porcupine.org
+Received: from ns0.utdallas.edu (ns0.utdallas.edu [129.110.10.1])
+       by spike.porcupine.org (Postfix) with ESMTP id E91E045630
+       for <wietse@porcupine.org>; Sat, 15 Apr 2000 09:37:17 -0400 (EDT)
+Received: from spartacus.utdallas.edu (spartacus.utdallas.edu [129.110.3.11])
+       by ns0.utdallas.edu (Postfix) with SMTP id 7D0601A00B9
+       for <wietse@porcupine.org>; Sat, 15 Apr 2000 08:36:35 -0500 (CDT)
+To: Wietse Venema <wietse@porcupine.org>
+Subject: [Markku Järvinen <Markku.Jarvinen@tpo.fi>] postfix lmtp
+From: Amos Gouaux <amos@utdallas.edu>
+Date: 15 Apr 2000 08:37:54 -0500
+Message-ID: <q6m66tj32od.fsf@spartacus.utdallas.edu>
+Lines: 73
+User-Agent: Gnus/5.0804 (Gnus v5.8.4) XEmacs/21.1 (Bryce Canyon)
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="=-=-="
+Sender: wietse@porcupine.org
+Status: ROr
+
+--=-=-=
+
+I suspect you've already dealt with this one during the merging, but
+forwarding in case not.
+
+I do recall one reason why I just inserted RSET into the state
+machine as I did--I wanted to check the response.  Though, this is
+easily remedied by having a mini state machine in the lmtp_rset
+function.
+
+I guess I thought that having RSET in the state machine would be
+okay because of this:
+
+            while ((rec_type = rec_get(state->src, state->scratch, 0)) > 0) {
+                if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
+                    break;
+                if (prev_type != REC_TYPE_CONT)
+                    if (vstring_str(state->scratch)[0] == '.')
+                        smtp_fputc('.', session->stream);
+                if (rec_type == REC_TYPE_CONT)
+                    smtp_fwrite(vstring_str(state->scratch),
+                                VSTRING_LEN(state->scratch),
+                                session->stream);
+                else
+                    smtp_fputs(vstring_str(state->scratch),
+                               VSTRING_LEN(state->scratch),
+                               session->stream);
+                prev_type = rec_type;
+            }
+
+Wouldn't this just suck in the entire message text, then put a '.'
+into the dialog?  How would a RSET in the message text jumble up the
+state machine?
+
+Amos
+
+
+
+--=-=-=
+Content-Type: message/rfc822; charset=""
+Content-Disposition: inline
+Content-Transfer-Encoding: quoted-printable
+
+Return-Path: <markku.jarvinen@tpo.fi>
+X-Sieve: cmu-sieve 1.3
+Received: from antivirus.tpo.fi (ns3.tpo.fi [212.63.10.250])
+       by ns0.utdallas.edu (Postfix) with ESMTP id 0700019FFF2
+       for <amos@utdallas.edu>; Fri, 14 Apr 2000 04:14:18 -0500 (CDT)
+Received: from ky.tpo.fi (localhost [127.0.0.1])
+       by antivirus.tpo.fi (8.9.3/8.9.3) with ESMTP id MAA09192
+       for <amos@utdallas.edu>; Fri, 14 Apr 2000 12:14:51 +0300 (EET DST)
+Rec=
+eived: from mtaj (home-f.ttk.tpo.fi [212.63.14.2])
+       by ky.tpo.fi (Postfix) with SMTP id 801AFF568
+       for <amos@utdallas.edu>; Fri, 14 Apr 2000 12:14:50 +0300 (EET DST)
+Mes=
+sage-ID: <05f601bfa5f1$bb2097c0$69fd1fac@ttk.tpo.fi>
+From: Markku J=E4rvinen <Markku.Jarvinen@tpo.fi>
+To: <amos@utdallas.edu>
+Subject: postfix lmtp
+Date: Fri, 14 Apr 2000 12:13:42 +0300
+MIME-Version: 1.0
+Content-Type: text/plain;
+       charset=3D"iso-8859-1"
+Content-Transfer-Encoding: 7bit
+X-Priority: 3
+X-MSMail-Priority: Normal
+X-Mailer: Microsoft Outlook Express 5.00.2919.6600
+X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6600
+
+Hi!
+
+In line 349 of lmtp_proto.c you just print the sender into LMTP-transac=
+tion.
+vstring_sprintf(next_command, "MAIL FROM:<%s>", request->sender);
+This fails when the sender address has spaces in it, you should first r=
+un it
+through quota_821_local to get it into the right format for LMTP (same =
+as
+SMTP).
+
+    - Markku
+
+
+
+--=-=-=--
+
+
+
+
+From wietse@porcupine.org  Sat Feb 26 09:17:05 2000
+Return-Path: <wietse@porcupine.org>
+Delivered-To: wietse@hades.porcupine.org
+Received: from spike.porcupine.org (spike.porcupine.org [168.100.189.2])
+       by hades.porcupine.org (Postfix) with ESMTP id E0D7F1886D
+       for <wietse@hades.porcupine.org>; Sat, 26 Feb 2000 09:17:04 -0500 (EST)
+Received: by spike.porcupine.org (Postfix, from userid 100)
+       id A520145659; Sat, 26 Feb 2000 09:17:04 -0500 (EST)
+Delivered-To: wietse@porcupine.org
+Received: from ns0.utdallas.edu (ns0.utdallas.edu [129.110.10.1])
+       by spike.porcupine.org (Postfix) with ESMTP id 5773F45657
+       for <wietse@porcupine.org>; Fri, 25 Feb 2000 19:41:51 -0500 (EST)
+Received: from spartacus.utdallas.edu (spartacus.utdallas.edu [129.110.3.11])
+       by ns0.utdallas.edu (Postfix) with SMTP id 782F91A00D7
+       for <wietse@porcupine.org>; Fri, 25 Feb 2000 18:04:16 -0600 (CST)
+To: wietse@porcupine.org (Wietse Venema)
+Subject: Re: lmtp update
+References: <20000221181534.11F7C45659@spike.porcupine.org>
+From: Amos Gouaux <amos@utdallas.edu>
+Date: 25 Feb 2000 18:04:54 -0600
+In-Reply-To: wietse@porcupine.org's message of "Mon, 21 Feb 2000 13:15:34 -0500 (EST)"
+Message-ID: <q6mitzcvnfd.fsf@spartacus.utdallas.edu>
+Lines: 6
+User-Agent: Gnus/5.0804 (Gnus v5.8.4) XEmacs/21.1 (Bryce Canyon)
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="=-=-="
+Sender: wietse@porcupine.org
+Status: RO
+
+--=-=-=
+
+How's this?
+
+Amos
+
+
+--=-=-=
+Content-Disposition: attachment; filename=lmtp-man
+Content-Description: lmtp-man
+
+.TH LMTP 8 
+.ad
+.fi
+.SH NAME
+lmtp
+\-
+Postfix local delivery via LMTP
+.SH SYNOPSIS
+.na
+.nf
+\fBlmtp\fR [generic Postfix daemon options] [server attributes...]
+.SH DESCRIPTION
+.ad
+.fi
+The LMTP client processes message delivery requests from
+the queue manager. Each request specifies a queue file, a sender
+address, a domain or host to deliver to, and recipient information.
+This program expects to be run from the \fBmaster\fR(8) process
+manager.
+
+The LMTP client updates the queue file and marks recipients
+as finished, or it informs the queue manager that delivery should
+be tried again at a later time. Delivery problem reports are sent
+to the \fBbounce\fR(8) or \fBdefer\fR(8) daemon as appropriate.
+
+There are two basic modes of operation for the LMTP client:
+.IP \(bu
+Communication with a local LMTP server via UNIX domain sockets.
+.IP \(bu
+Communication with a (possibly remote) LMTP server via
+Internet sockets.
+.PP
+If no server attributes are specified, the LMTP client will contact
+the destination host derived from the message delivery request using
+the TCP port defined as \fBlmtp\fR in \fBservices\fR(4).  If no such
+service is found, the \fBlmtp_tcp_port\fR configuration parameter
+(default value of 24) will be used.
+
+In order to use a local LMTP server, this LMTP server will need to
+be specified via the server attributes described in the following
+section.  Typically, the LMTP client would also be configured as the
+\fBlocal\fR delivery agent in the \fBmaster.cf\fR file.
+.SH SERVER ATTRIBUTE SYNTAX
+.na
+.nf
+.ad
+.fi
+The server attributes are given in the \fBmaster.cf\fR file at
+the end of a service definition.  The syntax is as follows:
+.IP "\fBserv\fR=\fItype\fR:\fIserver\fR"
+The LMTP server to connect to for final delivery.  The \fItype\fR
+portion can be either \fBunix\fR or \fBinet\fR. The \fIserver\fR
+portion is the path or address of the LMTP server, depending on the
+value of \fItype\fR, as shown below:
+.RS
+.IP "\fBserv=unix:\fR\fIclass\fR\fB/\fR\fIservname\fR"
+This specifies that the local LMTP server \fIservname\fR should be
+contacted for final delivery.  Both \fIclass\fR (either \fBpublic\fR
+or \fBprivate\fR) and \fIservname\fR correspond to the LMTP server
+entry in the \fBmaster.cf\fR file.  This LMTP server will likely
+be defined as a \fBspawn\fR(8) service.
+.IP "\fBserv=inet:"
+If nothing follows the \fBinet:\fR type specifier, a connection will
+be attempted to the destination host indicated in the delivery request.
+This simplest case is identical to defining the LMTP client without
+any server attributes at all.
+.IP "\fBserv=inet:\fR\fIaddress\fR"
+In this case, an Internet socket will be made to the server
+specified by \fIaddress\fR.  The connection will use a destination
+port as described in the previous section.
+.IP "\fBserv=inet:\fR\fIaddress\fR\fB:\fR\fIport\fR"
+Connect to the LMTP server at \fIaddress\fR, but this time use port
+\fIport\fR instead of the default \fBlmtp\fR port.
+.IP "\fBserv=inet:[\fR\fIipaddr\fR\fB]\fR"
+The LMTP server to contact is specified using an Internet address
+in the "dot notation".  That is, the numeric IP address rather
+than the DNS name for the server.  The default \fBlmtp\fR port
+is used.
+.IP "\fBserv=inet:[\fR\fIipaddr\fR\fB]:\fR\fIport\fR"
+The LMTP server to contact is specified using the numeric IP address,
+at the port specified.
+.RE
+.PP
+.SH SECURITY
+.na
+.nf
+.ad
+.fi
+The LMTP client is moderately security-sensitive. It talks to LMTP
+servers and to DNS servers on the network. The LMTP client can be
+run chrooted at fixed low privilege.
+.SH STANDARDS
+.na
+.nf
+RFC 2033 (LMTP protocol)
+RFC 821 (SMTP protocol)
+RFC 1651 (SMTP service extensions)
+RFC 1870 (Message Size Declaration)
+RFC 2197 (Pipelining)
+.SH DIAGNOSTICS
+.ad
+.fi
+Problems and transactions are logged to \fBsyslogd\fR(8).
+Corrupted message files are marked so that the queue manager can
+move them to the \fBcorrupt\fR queue for further inspection.
+
+Depending on the setting of the \fBnotify_classes\fR parameter,
+the postmaster is notified of bounces, protocol problems, and of
+other trouble.
+.SH BUGS
+.ad
+.fi
+.SH CONFIGURATION PARAMETERS
+.na
+.nf
+.ad
+.fi
+The following \fBmain.cf\fR parameters are especially relevant to
+this program. See the Postfix \fBmain.cf\fR file for syntax details
+and for default values. Use the \fBpostfix reload\fR command after
+a configuration change.
+.SH Miscellaneous
+.ad
+.fi
+.IP \fBdebug_peer_level\fR
+Verbose logging level increment for hosts that match a
+pattern in the \fBdebug_peer_list\fR parameter.
+.IP \fBdebug_peer_list\fR
+List of domain or network patterns. When a remote host matches
+a pattern, increase the verbose logging level by the amount
+specified in the \fBdebug_peer_level\fR parameter.
+.IP \fBerror_notice_recipient\fR
+Recipient of protocol/policy/resource/software error notices.
+.IP \fBnotify_classes\fR
+When this parameter includes the \fBprotocol\fR class, send mail to the
+postmaster with transcripts of LMTP sessions with protocol errors.
+.IP \fBlmtp_skip_quit_response\fR
+Do not wait for the server response after sending QUIT.
+.IP \fBlmtp_tcp_port\fR
+The TCP port to be used when connecting to a LMTP server.  Used as
+backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
+.SH "Resource controls"
+.ad
+.fi
+.IP \fBlmtp_cache_connection\fR
+Should we cache the connection to the LMTP server? The effectiveness
+of cached connections will be determined by the number of LMTP servers
+in use, and the concurrency limit specified for the LMTP client.
+Cached connections are closed under any of the following conditions:
+.RS
+.IP \(bu
+The idle timeout for the LMTP client is reached. This limit is
+enforced by \fBmaster\fR(8).
+.IP \(bu
+A message request to a different destination than the one currently
+cached.
+.IP \(bu
+The maximum number of requests per session is reached. This limit is
+enforced by \fBmaster\fR(8).
+.IP \(bu
+Upon the onset of another delivery request, the LMTP server associated
+with the current session does not respond to the \fBRSET\fR command.
+.RE
+.IP \fBlmtp_destination_concurrency_limit\fR
+Limit the number of parallel deliveries to the same destination.
+The default limit is taken from the
+\fBdefault_destination_concurrency_limit\fR parameter.
+.IP \fBlmtp_destination_recipient_limit\fR
+Limit the number of recipients per message delivery.
+The default limit is taken from the
+\fBdefault_destination_recipient_limit\fR parameter.
+.IP \fBlocal_destination_recipient_limit\fR
+Limit the number of recipients per message delivery.
+The default limit is taken from the
+\fBdefault_destination_recipient_limit\fR parameter.
+
+This parameter becomes significant if the LMTP client is used
+for local delivery.  Some LMTP servers can optimize final delivery
+if multiple recipients are allowed.  Therefore, it may be advantageous
+to set this to some number greater than one, depending on the capabilities
+of the machine.
+
+Setting this parameter to 0 will lead to an unlimited number of
+recipients per delivery.  However, this could be risky since it may
+make the machine vulnerable to running out of resources if messages
+are encountered with an inordinate number of recipients.  Exercise
+care when setting this parameter.
+.SH "Timeout controls"
+.ad
+.fi
+.IP \fBlmtp_connect_timeout\fR
+Timeout in seconds for opening a connection to the LMTP server.
+If no connection can be made within the deadline, the message
+is deferred.
+.IP \fBlmtp_lhlo_timeout\fR
+Timeout in seconds for sending the \fBLHLO\fR command, and for
+receiving the server response.
+.IP \fBlmtp_mail_timeout\fR
+Timeout in seconds for sending the \fBMAIL FROM\fR command, and for
+receiving the server response.
+.IP \fBlmtp_rcpt_timeout\fR
+Timeout in seconds for sending the \fBRCPT TO\fR command, and for
+receiving the server response.
+.IP \fBlmtp_data_init_timeout\fR
+Timeout in seconds for sending the \fBDATA\fR command, and for
+receiving the server response.
+.IP \fBlmtp_data_xfer_timeout\fR
+Timeout in seconds for sending the message content.
+.IP \fBlmtp_data_done_timeout\fR
+Timeout in seconds for sending the "\fB.\fR" command, and for
+receiving the server response. When no response is received, a
+warning is logged that the mail may be delivered multiple times.
+.IP \fBlmtp_rset_timeout\fR
+Timeout in seconds for sending the \fBRSET\fR command, and for
+receiving the server response.
+.IP \fBlmtp_quit_timeout\fR
+Timeout in seconds for sending the \fBQUIT\fR command, and for
+receiving the server response.
+.SH SEE ALSO
+.na
+.nf
+bounce(8) non-delivery status reports
+local(8) local mail delivery
+master(8) process manager
+qmgr(8) queue manager
+services(4) Internet services and aliases
+spawn(8) auxiliary command spawner
+syslogd(8) system logging
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
+
+Alterations for LMTP by:
+Philip A. Prindeville
+Mirapoint, Inc.
+USA.
+
+Additional work on LMTP by:
+Amos Gouaux
+University of Texas at Dallas
+P.O. Box 830688, MC34
+Richardson, TX 75083, USA
+
+--=-=-=--
+
+
+
+
+From wietse@porcupine.org  Sat Feb  5 09:32:03 2000
+Return-Path: <wietse@porcupine.org>
+Delivered-To: wietse@hades.porcupine.org
+Received: from spike.porcupine.org (spike.porcupine.org [168.100.189.2])
+       by hades.porcupine.org (Postfix) with ESMTP id A7661188A7
+       for <wietse@hades.porcupine.org>; Sat,  5 Feb 2000 09:32:03 -0500 (EST)
+Received: by spike.porcupine.org (Postfix, from userid 100)
+       id 700394563E; Sat,  5 Feb 2000 09:32:03 -0500 (EST)
+Delivered-To: wietse@porcupine.org
+Received: from ns0.utdallas.edu (ns0.utdallas.edu [129.110.10.1])
+       by spike.porcupine.org (Postfix) with ESMTP id 605FE4563C
+       for <wietse@porcupine.org>; Mon, 31 Jan 2000 18:35:02 -0500 (EST)
+Received: from spartacus.utdallas.edu (spartacus.utdallas.edu [129.110.3.11])
+       by ns0.utdallas.edu (Postfix) with SMTP id 02E4C1A005D
+       for <wietse@porcupine.org>; Mon, 31 Jan 2000 17:34:59 -0600 (CST)
+To: wietse@porcupine.org (Wietse Venema)
+Subject: Re: lmtp-20000130.tar.gz
+References: <20000131225228.008114563F@spike.porcupine.org>
+From: Amos Gouaux <amos@utdallas.edu>
+Date: 31 Jan 2000 17:35:34 -0600
+In-Reply-To: wietse@porcupine.org's message of "Mon, 31 Jan 2000 17:52:28 -0500 (EST)"
+Message-ID: <q6mzotlvmpl.fsf@spartacus.utdallas.edu>
+Lines: 119
+User-Agent: Gnus/5.0803 (Gnus v5.8.3) XEmacs/21.1 (Bryce Canyon)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Sender: wietse@porcupine.org
+Status: O
+
+>>>>> On Mon, 31 Jan 2000 17:52:28 -0500 (EST),
+>>>>> Wietse Venema <wietse@porcupine.org> (wv) writes:
+
+wv> For local transports, command pipelining does not have the benefit
+wv> that it has for TCP over non-local connections.
+
+So in other words I was making things too complicated.  
+Figures.  I have a knack for doing that.
+
+I've updated alpha-lmtp.tar.gz again.
+
+Here's the CHANGES file:
+
+
+2000 Jan 31
+
+* lmtp_proto.c:lmtp_lhlo: Don't worry about LMTP_FEATURE_PIPELINING
+  for sessions of type LMTP_SERV_TYPE_UNIX.
+
+
+2000 Jan 30
+
+* BIG changes.  Removed all the pipe stuff from lmtp.c and
+  lmtp_connect.c  Now, lmtp will either do a remote connection much
+  like the smtp client, or it will connect to a UNIX domain socket
+  to an auxiliary service (spawn).  This makes the lmtp patch
+  simpler because it doesn't have to worry at all about exec-ing an
+  external command, and all the resulting security implications.
+  See README.local for details.  
+
+  NOTE: postfix-19991231-pl04 is REQUIRED for this to work!  
+        (Need the "spawn" service.)
+
+* Updated the makefile-patch for postfix-19991231-pl03.
+
+* lmtp.h: changed the LMTP_ATTR structure to contain "type", "class", and
+  "name" fields, reflecting the change from the pipe mechanism to
+  the local sockets connection.  Changed LMTP_SESSION to contain the 
+  "type" field.  The connection type is recorded in this field in
+  case it is needed elsewhere, like in lmtp_proto.
+
+* lmtp.c:get_service_attr altered for new command syntax.  Examples: 
+
+     serv=unix:private/lmtpd
+     serv=inet:public/lmtpd
+
+  After `serv=' is the "type", followed by `:', then the "class",
+  followed by '/', and then finally the "name".
+
+* Added SAME_DESTINATION macro to lmtp.c:deliver_message for
+  readability, and simpler logic.
+
+* lmtp_connect.c: changed lmtp_connect to contain logic to determine 
+  just what kind of connection to make, removing it from lmtp.c;
+  removed lmtp_connect_pipe; and added lmtp_connect_local, which
+  uses mail_connect_wait to connect to the service running the LMTP
+  server (spawn).  In lmtp_connect, the connection type stored in
+  attr.type is saved into session.type, so it can be used later if
+  necessary. 
+
+* lmtp_proto.c:lmtp_lhlo: towards the end of this function we check
+  to see if service->type is LMTP_SERV_TYPE_UNIX so that we don't
+  try to do a getsockopt on a descriptor that doesn't support it.
+  Is this the best way to handle this?  Or maybe we should just try
+  it and if it bombs, check the error code before simply going
+  fatal?
+
+* Snagged the latest quota_821_local.c from the smtp client.
+
+* Updated the README files accordingly.
+
+
+2000 Jan 28
+
+* Well, wondering about using REWRITE_ADDRESS in lmtp_proto.c,
+  putting the lowercase thing in there.  Though, that would also
+  apply to sender address.  Is that okay?
+
+* We shouldn't be doing DNS lookups at this stage, so can get rid
+  of lmtp_unalias.c.  Also cut out the unalias portion in 
+  REWRITE_ADDRESS in lmtp_proto.c
+
+
+2000 Jan 11
+
+* At the suggestion of Rupa Schomaker, added the following to 
+  lmtp_proto.c:
+
+            lowercase(rcpt->address);  /* [AAG] rupa */
+
+
+1999 Dec 1 (or thereabouts)
+
+* Added lmtp_session_reset to make it easier to remember to reset
+  certain things to 0.  Did this to lmtp_chat_reset too.
+
+* Finally, did some work with the connection caching so that an RSET
+  is sent to the LMTP server.  This is done for two reasons: first,
+  to tell the LMTP server to flush out any status information
+  because we're about to feed it another message, and second, to
+  test the link to see if it is still alive.  If the link has died
+  for some reason, it is reestablished.  Changes to lmtp.c and
+  lmtp_proto.c.
+
+* There was also some tidying in lmtp.c so that things were a little
+  clearer as to what was going on.  I added a few more comments as
+  well.
+
+* I tried to make the master.cf argument parsing a little more
+  consistent with the other Postfix services.  Changes to lmtp.c.
+
+* On the postfix-users mailing list, Valery Brasseur pointed out that
+  errors encountered during LMTP delivery were not getting bounced
+  as appropriate.  This lead me to investigate the matter, wanting
+  to put this LMTP capability into service myself.  I then realized
+  that some of the error checking was a tad over zealous, and so
+  simplified things a bit in lmtp_proto.c.
+
+
+
+
+
+
+From wietse@porcupine.org  Wed Dec  8 19:50:01 1999
+Return-Path: <wietse@porcupine.org>
+Delivered-To: wietse@hades.porcupine.org
+Received: from spike.porcupine.org (spike.porcupine.org [168.100.189.2])
+       by hades.porcupine.org (Postfix) with ESMTP id D83EE18868
+       for <wietse@hades.porcupine.org>; Wed,  8 Dec 1999 19:50:00 -0500 (EST)
+Received: by spike.porcupine.org (Postfix, from userid 100)
+       id 827F645AFB; Wed,  8 Dec 1999 10:51:18 -0500 (EST)
+Delivered-To: wietse@porcupine.org
+Received: from ns0.utdallas.edu (ns0.utdallas.edu [129.110.10.1])
+       by spike.porcupine.org (Postfix) with ESMTP id 90E1A457F8
+       for <wietse@porcupine.org>; Tue,  7 Dec 1999 11:37:16 -0500 (EST)
+Received: from spartacus.utdallas.edu (spartacus.utdallas.edu [129.110.3.11])
+       by ns0.utdallas.edu (Postfix) with SMTP id 139E719FFFE
+       for <wietse@porcupine.org>; Tue,  7 Dec 1999 10:37:02 -0600 (CST)
+To: wietse@porcupine.org (Wietse Venema)
+Subject: Re: LMTP stuff
+References: <19991206162939.1C9BB458EB@spike.porcupine.org>
+From: Amos Gouaux <amos+lists.postfix@utdallas.edu>
+Date: 07 Dec 1999 10:37:25 -0600
+In-Reply-To: wietse@porcupine.org's message of "Mon, 6 Dec 1999 11:29:38 -0500 (EST)"
+Message-ID: <q6m7liqiu62.fsf@spartacus.utdallas.edu>
+Lines: 46
+User-Agent: Gnus/5.070099 (Pterodactyl Gnus v0.99) XEmacs/21.1 (Bryce Canyon)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Sender: wietse@porcupine.org
+Status: RO
+
+Okay, I put out the following tar file:
+
+ftp://ftp.utdallas.edu/pub/staff/amos/postfix/lmtp-19990427-02.tar.gz
+
+It's not quite as tidy as I would like it, and hope to eventually
+make it.  I've been making changes gradually, in part because it
+might be fun to play with the connection caching later, and in part
+because I'm new to the internals of Postfix.  Speaking of which, I
+must say it has been a real pleasure poking around this code.  It's
+fascinating to see how you've created this infrastructure by which
+all the various components communicate with one another.  Pretty
+slick stuff.  Very educational too.
+
+Most of the changes are in lmtp_proto.c and lmtp.c.  I noticed in
+the former that he's passing status around a lot, using the
+recv_state and send_state members instead of using local vars for
+these values.  I'm guess that was to keep track of the state
+throughout the connection caching.  I left that as is.
+
+In lmtp.c I removed the for loop he had, and parse the argv in a
+separate function to make it a bit cleaner.  I'm assuming that with
+the lmtp service there won't be much of a need to expand the argv
+like it is with the pipe service, correct?  
+
+After seeing one of your posts yesterday about the nexthop arg to
+pipe, I'm wondering if this lmtp should support that as well.  I
+noticed in the LMTP RFC that this LMTP can either be a local
+program, or communicate to a "Gateway Delivery Agent".  If there was
+a nexthop arg to lmtp, folks could specify this gateway host there.
+Or, they could use the transport map and not define any args to lmtp
+at all.
+
+It's amazing how much time can be consumed just contemplating what
+args should be permissible, and what's the most efficient way to
+process them.  I was even wondering, if no variable expansion should
+take place, if `LMTP_ATTR attr' should be global, and the call to
+get_service_attr placed in a function pointed to by
+MAIL_SERVER_PRE_INIT so it's only invoked once.  Still more things
+to learn.  
+
+Oh well, I've flung quite a bit mail at this thing and it seems to
+be handling it fine.  So perhaps it will at least be sufficient to
+satisfy folks for the time being.
+
+Amos
+
+
+
+
+
+From wietse@porcupine.org  Tue Nov 23 18:09:44 1999
+Return-Path: <wietse@porcupine.org>
+Delivered-To: wietse@hades.porcupine.org
+Received: from spike.porcupine.org (spike.porcupine.org [168.100.189.2])
+       by hades.porcupine.org (Postfix) with ESMTP id BD43F18864
+       for <wietse@hades.porcupine.org>; Tue, 23 Nov 1999 18:09:44 -0500 (EST)
+Received: by spike.porcupine.org (Postfix, from userid 100)
+       id 4CC0445A9B; Tue, 23 Nov 1999 13:24:06 -0500 (EST)
+Delivered-To: wietse@porcupine.org
+Received: from russian-caravan.cloud9.net (russian-caravan.cloud9.net [168.100.1.4])
+       by spike.porcupine.org (Postfix) with ESMTP id 979F145A9A
+       for <wietse@porcupine.org>; Tue, 23 Nov 1999 13:19:06 -0500 (EST)
+Received: by russian-caravan.cloud9.net (Postfix)
+       id AE6E576434; Tue, 23 Nov 1999 13:16:34 -0500 (EST)
+Delivered-To: postfix-users-outgoing@cloud9.net
+Received: by russian-caravan.cloud9.net (Postfix, from userid 54)
+       id 340DA76423; Tue, 23 Nov 1999 13:16:34 -0500 (EST)
+Delivered-To: postfix-users@cloud9.net
+Received: from atn01.axime.com (atn01.axime.com [160.92.1.141])
+       by russian-caravan.cloud9.net (Postfix) with ESMTP id 32BE6763C6
+       for <postfix-users@postfix.org>; Tue, 23 Nov 1999 13:16:32 -0500 (EST)
+Received: from atos-group.com (sys-pc21.segin.com [172.18.2.119])
+       by atn01.axime.com (8.8.8/8.8.8[Atos Multimedia]) with ESMTP id TAA25333;
+       Tue, 23 Nov 1999 19:16:20 +0100 (MET)
+Message-ID: <383AD9F2.8915CCA6@atos-group.com>
+Date: Tue, 23 Nov 1999 18:16:18 +0000
+From: valery brasseur <vbrasseur@atos-group.com>
+Organization: Atos Multimedia
+X-Mailer: Mozilla 4.7 [en] (X11; I; Linux 2.2.12 i686)
+X-Accept-Language: en, fr-FR
+MIME-Version: 1.0
+To: Amos Gouaux <amos+lists.postfix@utdallas.edu>
+Cc: postfix-users@postfix.org
+Subject: Re: LMTP?
+References: <q6memdj3djk.fsf@spartacus.utdallas.edu> <3839189C.C4E94EA1@atos-group.com> <q6mso1yn00k.fsf@spartacus.utdallas.edu>
+Content-Type: text/plain; charset=us-ascii
+Content-Transfer-Encoding: 7bit
+Precedence: bulk
+Sender: wietse@porcupine.org
+Status: RO
+
+Here is the patch a use on the lmtp part of postfix for using LMTP on
+Solaris (note that these diffs are not necessary for Linux !)
+It's seems that the probleme come from the interpretation of the return
+code from cyrus-deliver.
+
+note : they are against lmtp-19990427.tar.gz
+
+--- lmtp/lmtp_proto.c   Tue Apr 20 09:42:45 1999
++++ /postfix-19990906/lmtp/lmtp_proto.c    Thu Sep  2 15:04:57 1999
+@@ -445,12 +445,12 @@
+                        if (resp->code / 100 == 2) {
+                            ++nrcpt;
+                            recipient_list_add(&survivors, rcpt->offset,
+rcpt->address);
+-                       } else if (resp->code == 550
++                       } else /* if (resp->code == 550
+                                  && strncmp(resp->str, "550 5.1.1", 9)
+== 0) {
+                            deliver_completed(state->src, -1);
+                            state->status |= -1;
+                            rcpt->offset = 0;
+-                       } else {
++                       } else */ {o
+                            lmtp_rcpt_fail(state, resp->code, rcpt,
+                                           "host %s said: %s",
+session->host,
+                                           translit(resp->str, "\n", "
+"));
+
+
+Hope it will help.
+
+Amos Gouaux wrote:
+> 
+> >>>>> On Mon, 22 Nov 1999 10:19:08 +0000,
+> >>>>> valery brasseur <vbrasseur@atos-group.com> (vb) writes:
+> 
+> vb> I use it with cyrus, but I have done made some patch to the LMTP code
+> vb> and deliver code because return code where not what the other was
+> vb> expected !!!
+> 
+> Do you think you could submit these patches to the list?
+> 
+> I knew something had to be amiss.  Using the Postfix sendmail
+> command I attempted to send mail to a non-existent user, jdoe.  The
+> syslog from Postfix indicated successful delivery:
+> 
+> Nov 22 07:03:45 area52 postfix/pipe[3082]: 6316124718: to=<jdoe@area52.utdallas.edu>, relay=lmtp, delay=0, status=sent (jdoe@area52.utdallas.edu)
+> 
+> However, when I run deliver by hand, the response isn't so positive:
+> 
+> rcpt to:<jdoe@area52.utdallas.edu>
+> 550 5.1.1 User unknown
+> 
+> Thanks,
+> Amos
+
+-- 
+Valery BRASSEUR                | Phone # +33 320 60 7982 
+Atos Branche Multimedia        | Fax   # +33 320 60 7649
+ "Unix -- where you can do anything in two keystrokes or less..."
+                         -- Unknown
+
+
+
+
diff --git a/postfix/lmtp/makefile-patch b/postfix/lmtp/makefile-patch
new file mode 100644 (file)
index 0000000..0cf80e9
--- /dev/null
@@ -0,0 +1,19 @@
+*** ../../orig/Makefile.in     Fri Dec 31 09:49:41 1999
+--- Makefile.in        Fri Feb 25 16:27:24 2000
+***************
+*** 4,10 ****
+  DIRS = util global dns master postfix smtpstone sendmail error \
+       pickup cleanup smtpd local trivial-rewrite qmgr smtp bounce pipe \
+       showq postalias postcat postconf postdrop postkick postlock postlog \
+!      postmap postsuper # spawn man html
+  
+  default: update
+  
+--- 4,10 ----
+  DIRS = util global dns master postfix smtpstone sendmail error \
+       pickup cleanup smtpd local trivial-rewrite qmgr smtp bounce pipe \
+       showq postalias postcat postconf postdrop postkick postlock postlog \
+!      postmap postsuper lmtp spawn man # html
+  
+  default: update
+  
diff --git a/postfix/lmtp/man-patch b/postfix/lmtp/man-patch
new file mode 100644 (file)
index 0000000..551002f
--- /dev/null
@@ -0,0 +1,218 @@
+*** ../../orig/man/Makefile.in Thu Jun 24 18:39:22 1999
+--- man/Makefile.in    Fri Feb 25 16:35:53 2000
+***************
+*** 2,8 ****
+  
+  DAEMONS      = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
+       man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 man8/showq.8 \
+!      man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8
+  COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
+       man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
+       man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
+--- 2,8 ----
+  
+  DAEMONS      = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
+       man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 man8/showq.8 \
+!      man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 man8/lmtp.8
+  COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
+       man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
+       man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
+***************
+*** 24,99 ****
+       rm -f $(DAEMONS) $(COMMANDS) $(CONFIG)
+  
+  man8/bounce.8: ../bounce/bounce.c
+!      srctoman $? >$@
+  
+  man8/defer.8:
+       echo .so man8/bounce.8 >$@
+  
+  man8/cleanup.8: ../cleanup/cleanup.c
+!      srctoman $? >$@
+  
+  man8/error.8: ../error/error.c
+!      srctoman $? >$@
+  
+  man8/local.8: ../local/local.c
+!      srctoman $? >$@
+  
+  man8/master.8: ../master/master.c
+!      srctoman $? >$@
+  
+  man8/pickup.8: ../pickup/pickup.c
+!      srctoman $? >$@
+  
+  man8/pipe.8: ../pipe/pipe.c
+!      srctoman $? >$@
+  
+  man8/qmgr.8: ../qmgr/qmgr.c
+!      srctoman $? >$@
+  
+  man8/showq.8: ../showq/showq.c
+!      srctoman $? >$@
+  
+  man8/smtp.8: ../smtp/smtp.c
+!      srctoman $? >$@
+  
+  man8/smtpd.8: ../smtpd/smtpd.c
+!      srctoman $? >$@
+  
+  man8/trivial-rewrite.8: ../trivial-rewrite/trivial-rewrite.c
+!      srctoman $? >$@
+  
+  man1/postalias.1: ../postalias/postalias.c
+!      srctoman $? >$@
+  
+  man1/postcat.1: ../postcat/postcat.c
+!      srctoman $? >$@
+  
+  man1/postconf.1: ../postconf/postconf.c
+!      srctoman $? >$@
+  
+  man1/postdrop.1: ../postdrop/postdrop.c
+!      srctoman $? >$@
+  
+  man1/postfix.1: ../postfix/postfix.c
+!      srctoman $? >$@
+  
+  man1/postkick.1: ../postkick/postkick.c
+!      srctoman $? >$@
+  
+  man1/postlock.1: ../postlock/postlock.c
+!      srctoman $? >$@
+  
+  man1/postlog.1: ../postlog/postlog.c
+!      srctoman $? >$@
+  
+  man1/postmap.1: ../postmap/postmap.c
+!      srctoman $? >$@
+  
+  man1/postsuper.1: ../postsuper/postsuper.c
+!      srctoman $? >$@
+  
+  man1/sendmail.1: ../sendmail/sendmail.c
+!      srctoman $? >$@
+  
+  man1/mailq.1:
+       echo .so man1/sendmail.1 >$@
+--- 24,102 ----
+       rm -f $(DAEMONS) $(COMMANDS) $(CONFIG)
+  
+  man8/bounce.8: ../bounce/bounce.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/defer.8:
+       echo .so man8/bounce.8 >$@
+  
+  man8/cleanup.8: ../cleanup/cleanup.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/error.8: ../error/error.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/local.8: ../local/local.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/master.8: ../master/master.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/pickup.8: ../pickup/pickup.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/pipe.8: ../pipe/pipe.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/qmgr.8: ../qmgr/qmgr.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/showq.8: ../showq/showq.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/smtp.8: ../smtp/smtp.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/smtpd.8: ../smtpd/smtpd.c
+!      ../mantools/srctoman $? >$@
+  
+  man8/trivial-rewrite.8: ../trivial-rewrite/trivial-rewrite.c
+!      ../mantools/srctoman $? >$@
+  
++ man8/lmtp.8: ../lmtp/lmtp.c
++      ../mantools/srctoman $? >$@
++ 
+  man1/postalias.1: ../postalias/postalias.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/postcat.1: ../postcat/postcat.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/postconf.1: ../postconf/postconf.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/postdrop.1: ../postdrop/postdrop.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/postfix.1: ../postfix/postfix.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/postkick.1: ../postkick/postkick.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/postlock.1: ../postlock/postlock.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/postlog.1: ../postlog/postlog.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/postmap.1: ../postmap/postmap.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/postsuper.1: ../postsuper/postsuper.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/sendmail.1: ../sendmail/sendmail.c
+!      ../mantools/srctoman $? >$@
+  
+  man1/mailq.1:
+       echo .so man1/sendmail.1 >$@
+***************
+*** 102,120 ****
+       echo .so man1/sendmail.1 >$@
+  
+  man5/access.5: ../conf/access
+!      srctoman - $? >$@
+  
+  man5/aliases.5: ../conf/aliases
+!      srctoman - $? >$@
+  
+  man5/canonical.5: ../conf/canonical
+!      srctoman - $? >$@
+  
+  man5/relocated.5: ../conf/relocated
+!      srctoman - $? >$@
+  
+  man5/transport.5: ../conf/transport
+!      srctoman - $? >$@
+  
+  man5/virtual.5: ../conf/virtual
+!      srctoman - $? >$@
+--- 105,123 ----
+       echo .so man1/sendmail.1 >$@
+  
+  man5/access.5: ../conf/access
+!      ../mantools/srctoman - $? >$@
+  
+  man5/aliases.5: ../conf/aliases
+!      ../mantools/srctoman - $? >$@
+  
+  man5/canonical.5: ../conf/canonical
+!      ../mantools/srctoman - $? >$@
+  
+  man5/relocated.5: ../conf/relocated
+!      ../mantools/srctoman - $? >$@
+  
+  man5/transport.5: ../conf/transport
+!      ../mantools/srctoman - $? >$@
+  
+  man5/virtual.5: ../conf/virtual
+!      ../mantools/srctoman - $? >$@
diff --git a/postfix/lmtp/quote_821_local.c b/postfix/lmtp/quote_821_local.c
new file mode 100644 (file)
index 0000000..49c2772
--- /dev/null
@@ -0,0 +1,170 @@
+/*++
+/* NAME
+/*     quote_821_local 3
+/* SUMMARY
+/*     quote local part of address
+/* SYNOPSIS
+/*     #include "quote_821_local.h"
+/*
+/*     VSTRING *quote_821_local(dst, src)
+/*     VSTRING *dst;
+/*     char    *src;
+/* DESCRIPTION
+/*     quote_821_local() quotes the local part of a mailbox address and
+/*     returns a result that can be used in SMTP commands as specified
+/*     by RFC 821.
+/*
+/*     Arguments:
+/* .IP dst
+/*     The result.
+/* .IP src
+/*     The input address.
+/* STANDARDS
+/*     RFC 821 (SMTP protocol)
+/* BUGS
+/*     The code assumes that the domain is RFC 821 clean.
+/* 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
+/*
+/*      Alterations for LMTP by:
+/*      Philip A. Prindeville
+/*      Mirapoint, Inc.
+/*      USA.
+/*
+/*      Additional work on LMTP by:
+/*      Amos Gouaux
+/*      University of Texas at Dallas
+/*      P.O. Box 830688, MC34
+/*      Richardson, TX 75083, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+#include <ctype.h>
+
+/* Utility library. */
+
+#include <vstring.h>
+
+/* Global library. */
+
+#include "quote_821_local.h"
+
+/* Application-specific. */
+
+#define YES    1
+#define        NO      0
+
+/* is_821_dot_string - is this local-part an rfc 821 dot-string? */
+
+static int is_821_dot_string(char *local_part, char *end)
+{
+    char   *cp;
+    int     ch;
+
+    /*
+     * Detect any deviations from the definition of dot-string. We could use
+     * lookup tables to speed up some of the work, but hey, how large can a
+     * local-part be anyway?
+     */
+    if (local_part[0] == 0 || local_part[0] == '.')
+       return (NO);
+    for (cp = local_part; cp < end && (ch = *cp) != 0; cp++) {
+       if (ch == '.' && cp[1] == '.')
+           return (NO);
+       if (ch > 127)
+           return (NO);
+       if (ch == ' ')
+           return (NO);
+       if (ISCNTRL(ch))
+           return (NO);
+       if (ch == '<' || ch == '>'
+           || ch == '(' || ch == ')'
+           || ch == '[' || ch == ']'
+           || ch == '\\' || ch == ','
+           || ch == ';' || ch == ':'
+           /* || ch == '@' */ || ch == '"')
+           return (NO);
+    }
+    if (cp[-1] == '.')
+       return (NO);
+    return (YES);
+}
+
+/* make_821_quoted_string - make quoted-string from local-part */
+
+static VSTRING *make_821_quoted_string(VSTRING *dst, char *local_part, char *end)
+{
+    char   *cp;
+    int     ch;
+
+    /*
+     * Put quotes around the result, and prepend a backslash to characters
+     * that need quoting when they occur in a quoted-string.
+     */
+    VSTRING_RESET(dst);
+    VSTRING_ADDCH(dst, '"');
+    for (cp = local_part; cp < end && (ch = *cp) != 0; cp++) {
+       if (ch > 127 || ch == '\r' || ch == '\n' || ch == '"' || ch == '\\')
+           VSTRING_ADDCH(dst, '\\');
+       VSTRING_ADDCH(dst, ch);
+    }
+    VSTRING_ADDCH(dst, '"');
+    VSTRING_TERMINATE(dst);
+    return (dst);
+}
+
+/* quote_821_local - quote local part of address according to rfc 821 */
+
+VSTRING *quote_821_local(VSTRING *dst, char *addr)
+{
+    char   *at;
+
+    /*
+     * According to RFC 821, a local-part is a dot-string or a quoted-string.
+     * We first see if the local-part is a dot-string. If it is not, we turn
+     * it into a quoted-string. Anything else would be too painful.
+     */
+    if ((at = strrchr(addr, '@')) == 0)                /* just in case */
+       at = addr + strlen(addr);               /* should not happen */
+    if (is_821_dot_string(addr, at)) {
+       return (vstring_strcpy(dst, addr));
+    } else {
+       make_821_quoted_string(dst, addr, at);
+       return (vstring_strcat(dst, at));
+    }
+}
+
+#ifdef TEST
+
+ /*
+  * Test program for local-part quoting as per rfc 821
+  */
+#include <stdlib.h>
+#include <vstream.h>
+#include <vstring_vstream.h>
+#include "quote_821_local.h"
+
+main(void)
+{
+    VSTRING *src = vstring_alloc(100);
+    VSTRING *dst = vstring_alloc(100);
+
+    while (vstring_fgets_nonl(src, VSTREAM_IN)) {
+       vstream_fprintf(VSTREAM_OUT, "%s\n",
+                       vstring_str(quote_821_local(dst, vstring_str(src))));
+       vstream_fflush(VSTREAM_OUT);
+    }
+    exit(0);
+}
+
+#endif
diff --git a/postfix/lmtp/quote_821_local.h b/postfix/lmtp/quote_821_local.h
new file mode 100644 (file)
index 0000000..17543f2
--- /dev/null
@@ -0,0 +1,41 @@
+/*++
+/* NAME
+/*     quote_821_local 3h
+/* SUMMARY
+/*     quote rfc 821 local part
+/* SYNOPSIS
+/*     #include "quote_821_local.h"
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <vstring.h>
+
+ /*
+  * External interface.
+  */
+extern VSTRING *quote_821_local(VSTRING *, 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
+/*
+/*      Alterations for LMTP by:
+/*      Philip A. Prindeville
+/*      Mirapoint, Inc.
+/*      USA.
+/*
+/*      Additional work on LMTP by:
+/*      Amos Gouaux
+/*      University of Texas at Dallas
+/*      P.O. Box 830688, MC34
+/*      Richardson, TX 75083, USA
+/*--*/
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 3100e71558bccabbda74824dd4f66fff8f6a8adc..ac674188a31489cec84779d5c217da7f333524f9 100644 (file)
@@ -97,6 +97,7 @@
 /* .SH "Authentication controls"
 /* .IP \fBsmtp_enable_sasl_auth\fR
 /*     Enable per-session authentication as per RFC 2554 (SASL).
+/*     By default, Postfix is built without SASL support.
 /* .IP \fBsmtp_sasl_password_maps\fR
 /*     Lookup tables with per-host \fIname\fR:\fIpassword\fR entries.
 /*     No entry for a host means no attempt to authenticate.
 #include <debug_peer.h>
 #include <mail_error.h>
 #include <deliver_pass.h>
-#include <smtp_stream.h>
 
 /* Single server skeleton. */
 
@@ -292,7 +292,6 @@ static int deliver_message(DELIVER_REQUEST *request)
                           "%s", vstring_str(why));
     } else {
        debug_peer_check(state->session->host, state->session->addr);
-       smtp_jump_setup(state->session->stream, state->jbuf);
        if (smtp_helo(state) == 0)
            smtp_xfer(state);
        if (state->history != 0
index b1ff99142ddc5f045d184014f9ab6c1081a3f747..d734948713d3e7a6296999feafd63fd8bd8b3436 100644 (file)
@@ -8,11 +8,6 @@
 /* DESCRIPTION
 /* .nf
 
- /*
-  * System library.
-  */
-#include <setjmp.h>
-
  /*
   * SASL library.
   */
@@ -57,7 +52,6 @@ typedef struct SMTP_STATE {
     VSTRING *sasl_decoded;             /* decoding buffer */
     sasl_callback_t *sasl_callbacks;   /* stateful callbacks */
 #endif
-    jmp_buf jbuf[1];                   /* exception context */
 } SMTP_STATE;
 
 #define SMTP_FEATURE_ESMTP     (1<<0)
index 7e3f2debe44c9c612546171e8197811079550e6b..cc6484d92122f3972fee3cdd3ef42da366919a85 100644 (file)
@@ -64,7 +64,6 @@
 #include <sys_defs.h>
 #include <sys/stat.h>
 #include <sys/socket.h>                        /* shutdown(2) */
-#include <setjmp.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
@@ -158,7 +157,7 @@ int     smtp_helo(SMTP_STATE *state)
      * Prepare for disaster.
      */
     smtp_timeout_setup(state->session->stream, var_smtp_helo_tmout);
-    if ((except = setjmp(state->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(state->session->stream)) != 0)
        return (smtp_stream_except(state, except, "sending HELO"));
 
     /*
@@ -413,6 +412,7 @@ int     smtp_xfer(SMTP_STATE *state)
             * The final sender state has no action associated with it.
             */
        case SMTP_STATE_LAST:
+           VSTRING_RESET(next_command);
            break;
        }
        VSTRING_TERMINATE(next_command);
@@ -439,7 +439,7 @@ int     smtp_xfer(SMTP_STATE *state)
                 */
                smtp_timeout_setup(state->session->stream,
                                   *xfer_timeouts[recv_state]);
-               if ((except = setjmp(state->jbuf[0])) != 0)
+               if ((except = vstream_setjmp(state->session->stream)) != 0)
                    RETURN(smtp_stream_except(state, except,
                                              xfer_states[recv_state]));
                resp = smtp_chat_resp(state);
@@ -591,7 +591,7 @@ int     smtp_xfer(SMTP_STATE *state)
        if (send_state == SMTP_STATE_DOT && nrcpt > 0) {
            smtp_timeout_setup(state->session->stream,
                               var_smtp_data1_tmout);
-           if ((except = setjmp(state->jbuf[0])) != 0)
+           if ((except = vstream_setjmp(state->session->stream)) != 0)
                RETURN(smtp_stream_except(state, except,
                                          "sending message body"));
 
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 5285bcfbd3a5dc7867d8bab2349406b643365729..cea1ab58fd95148bcc205dd20d0a6e9cf7378cb4 100644 (file)
 #include <netdb.h>
 #include <string.h>
 #include <stdio.h>                     /* remove() */
-#include <setjmp.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <time.h>
@@ -1145,10 +1144,9 @@ static void smtpd_proto(SMTPD_STATE *state)
      * cleans up, but no attempt is made to inform the client of the nature
      * of the problem.
      */
-    smtp_jump_setup(state->client, state->jbuf);
     smtp_timeout_setup(state->client, var_smtpd_tmout);
 
-    switch (setjmp(state->jbuf[0])) {
+    switch (vstream_setjmp(state->client)) {
 
     default:
        msg_panic("smtpd_proto: unknown error reading from %s[%s]",
index b39bebab7342e883c28c5a1fdbf403f9f65fdbd6..447ad932ead2298e4c88c3c53521837bad31efaa 100644 (file)
@@ -8,11 +8,6 @@
 /* DESCRIPTION
 /* .nf
 
- /*
-  * System library
-  */
-#include <setjmp.h>
-
  /*
   * SASL library.
   */
@@ -76,7 +71,6 @@ typedef struct SMTPD_STATE {
     VSTRING *sasl_encoded;
     VSTRING *sasl_decoded;
 #endif
-    jmp_buf jbuf[1];
 } SMTPD_STATE;
 
 extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *);
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 8b49d75906f51c81b1b64ab7dd4df64321353b51..701fdf05f85ec638b284f04554e0091fe7367f91 100644 (file)
@@ -41,7 +41,6 @@
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include <unistd.h>
-#include <setjmp.h>
 #include <string.h>
 #include <stdlib.h>
 #include <fcntl.h>
@@ -74,7 +73,6 @@ typedef struct SINK_STATE {
     int     data_state;
     int     (*read) (struct SINK_STATE *);
     int     rcpts;
-    jmp_buf jbuf[1];
 } SINK_STATE;
 
 #define ST_ANY                 0
@@ -285,7 +283,7 @@ static void read_event(int unused_event, char *context)
     SINK_STATE *state = (SINK_STATE *) context;
 
     do {
-       switch (setjmp(state->jbuf[0])) {
+       switch (vstream_setjmp(state->stream)) {
 
        default:
            msg_panic("unknown error reading input");
@@ -335,7 +333,6 @@ static void connect_event(int unused_event, char *context)
        state->stream = vstream_fdopen(fd, O_RDWR);
        state->read = command_read;
        state->data_state = 0;
-       smtp_jump_setup(state->stream, state->jbuf);
        smtp_timeout_setup(state->stream, var_tmout);
        smtp_printf(state->stream, "220 %s ESMTP", var_myhostname);
        event_enable_read(fd, read_event, (char *) state);
index 4ca866e6e3fe61d12504ff5fe76683a9e3491bf6..0fc1ae8f3c43a2050b977169639616cf5a9a96e6 100644 (file)
@@ -65,7 +65,6 @@
 #include <sys/wait.h>
 #include <netinet/in.h>
 #include <stdarg.h>
-#include <setjmp.h>
 #include <string.h>
 #include <ctype.h>
 #include <stdlib.h>
@@ -112,7 +111,6 @@ typedef struct SESSION {
     VSTREAM *stream;                   /* open connection */
     int     connect_count;             /* # of connect()s to retry */
     struct SESSION *next;              /* connect() queue linkage */
-    jmp_buf jbuf[1];                   /* exception handling */
 } SESSION;
 
 static SESSION *last_session;          /* connect() queue tail */
@@ -390,7 +388,6 @@ static void start_connect(SESSION *session)
     (void) non_blocking(fd, NON_BLOCKING);
     session->stream = vstream_fdopen(fd, O_RDWR);
     event_enable_write(fd, connect_done, (char *) session);
-    smtp_jump_setup(session->stream, session->jbuf);
     smtp_timeout_setup(session->stream, var_timeout);
     if (connect(fd, (struct sockaddr *) & sin, sizeof(sin)) < 0
        && errno != EINPROGRESS)
@@ -429,7 +426,7 @@ static void read_banner(int unused_event, char *context)
     /*
      * Prepare for disaster.
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while reading server greeting", exception_text(except));
 
     /*
@@ -452,12 +449,12 @@ static void read_banner(int unused_event, char *context)
 static void send_helo(SESSION *session)
 {
     int     except;
-    char   *protocol = (talk_lmtp ? "LHLO" : "EHLO");
+    char   *protocol = (talk_lmtp ? "LHLO" : "HELO");
 
     /*
      * Send the standard greeting with our hostname
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending HELO", exception_text(except));
 
     command(session->stream, "%s %s", protocol, var_myhostname);
@@ -480,7 +477,7 @@ static void helo_done(int unused_event, char *context)
     /*
      * Get response to HELO command.
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending HELO", exception_text(except));
 
     if ((resp = response(session->stream, buffer))->code / 100 != 2)
@@ -498,7 +495,7 @@ static void send_mail(SESSION *session)
     /*
      * Send the envelope sender address.
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending sender", exception_text(except));
 
     command(session->stream, "MAIL FROM:<%s>", sender);
@@ -521,7 +518,7 @@ static void mail_done(int unused, char *context)
     /*
      * Get response to MAIL command.
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending sender", exception_text(except));
 
     if ((resp = response(session->stream, buffer))->code / 100 != 2)
@@ -542,7 +539,7 @@ static void send_rcpt(int unused_event, char *context)
     /*
      * Send envelope recipient address.
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending recipient", exception_text(except));
 
     if (session->rcpt_count > 1)
@@ -571,7 +568,7 @@ static void rcpt_done(int unused, char *context)
     /*
      * Get response to RCPT command.
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending recipient", exception_text(except));
 
     if ((resp = response(session->stream, buffer))->code / 100 != 2)
@@ -596,7 +593,7 @@ static void send_data(int unused_event, char *context)
     /*
      * Request data transmission.
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending DATA command", exception_text(except));
     command(session->stream, "DATA");
 
@@ -620,7 +617,7 @@ static void data_done(int unused_event, char *context)
     /*
      * Get response to DATA command.
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending DATA command", exception_text(except));
     if ((resp = response(session->stream, buffer))->code != 354)
        msg_fatal("data %d %s", resp->code, resp->str);
@@ -644,7 +641,7 @@ static void data_done(int unused_event, char *context)
     /*
      * Send some garbage.
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending message", exception_text(except));
     if (message_length == 0) {
        smtp_fputs("La de da de da 1.", 17, session->stream);
@@ -687,7 +684,7 @@ static void dot_done(int unused_event, char *context)
     /*
      * Get response to "." command.
      */
-    if ((except = setjmp(session->jbuf[0])) != 0)
+    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending message", exception_text(except));
     do {                                       /* XXX this could block */
        if ((resp = response(session->stream, buffer))->code / 100 != 2)
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index 2139804a4fb8192a0b1bb8585b2a5aa55b4656bd..5fbb816dfa66fee712b7105066d31c289803f23c 100644 (file)
 -TINET_ADDR_LIST
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
+-TLMTP_ATTR
+-TLMTP_RESP
+-TLMTP_SESSION
+-TLMTP_STATE
 -TLOCAL_EXP
 -TLOCAL_STATE
 -TMAC_EXP
index dc8e0546c41bcb459d5135a2d31374ed8502ac0a..dda83a1131a0ac7ce1ddce04fc3172c9ed7f9046 100644 (file)
@@ -21,8 +21,7 @@ SRCS  = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \
        write_buf.c write_wait.c dict_unix.c dict_pcre.c stream_listen.c \
        stream_connect.c stream_trigger.c dict_regexp.c mac_expand.c \
        clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \
-       sane_link.c unescape.c timed_read.c timed_write.c binattr.c \
-       vstream_attr.c
+       sane_link.c unescape.c timed_read.c timed_write.c binattr.c 
 OBJS   = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
        close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
        dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
@@ -45,8 +44,7 @@ OBJS  = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
        write_buf.o write_wait.o dict_unix.o dict_pcre.o stream_listen.o \
        stream_connect.o stream_trigger.o dict_regexp.o mac_expand.o \
        clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \
-       sane_link.o unescape.o timed_read.o timed_write.o binattr.o \
-       vstream_attr.o
+       sane_link.o unescape.o timed_read.o timed_write.o binattr.o 
 HDRS   = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
        dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \
        dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
@@ -951,14 +949,8 @@ vstream.o: vbuf_print.h
 vstream.o: vbuf.h
 vstream.o: iostuff.h
 vstream.o: vstring.h
-vstream.o: binattr.h
 vstream.o: vstream.h
-vstream_attr.o: vstream_attr.c
-vstream_attr.o: sys_defs.h
-vstream_attr.o: vstream.h
-vstream_attr.o: vbuf.h
-vstream_attr.o: binattr.h
-vstream_attr.o: htable.h
+vstream.o: binattr.h
 vstream_popen.o: vstream_popen.c
 vstream_popen.o: sys_defs.h
 vstream_popen.o: msg.h
index ddc621a32f442f15b7045ab2e9cd88e9f3affd12..851c091c8a86fc2fcc3672560aa2ef514ff91e33 100644 (file)
@@ -24,8 +24,8 @@ extern int peekfd(int);
 extern int read_wait(int, int);
 extern int write_wait(int, int);
 extern int write_buf(int, const char *, int, int);
-extern int timed_read(int, void *, unsigned, int);
-extern int timed_write(int, void *, unsigned, int);
+extern int timed_read(int, void *, unsigned, int, void *);
+extern int timed_write(int, void *, unsigned, int, void *);
 extern void doze(unsigned);
 extern int duplex_pipe(int *);
 
index 045d97c94b70203810864dbf93ac6a50cc9c4870..1a29a69f9f52dbe4491c7a0d752a9c8226174ab6 100644 (file)
@@ -6,11 +6,12 @@
 /* SYNOPSIS
 /*     #include <iostuff.h>
 /*
-/*     int     timed_read(fd, buf, buf_len, timeout)
+/*     int     timed_read(fd, buf, buf_len, timeout, context)
 /*     int     fd;
 /*     void    *buf;
 /*     unsigned len;
 /*     int     timeout;
+/*     void    *context;
 /* DESCRIPTION
 /*     timed_read() performs a read() operation when the specified
 /*     descriptor becomes readable within a user-specified deadline.
@@ -25,6 +26,9 @@
 /* .IP timeout
 /*     The deadline in seconds. If this is <= 0, the deadline feature
 /*     is disabled.
+/* .IP context
+/*     Application context. This parameter is unused. It exists only
+/*     for the sake of VSTREAM compatibility.
 /* DIAGNOSTICS
 /*     When the operation does not complete within the deadline, the
 /*     result value is -1, and errno is set to ETIMEDOUT.
@@ -51,7 +55,8 @@
 
 /* timed_read - read with deadline */
 
-int     timed_read(int fd, void *buf, unsigned len, int timeout)
+int     timed_read(int fd, void *buf, unsigned len,
+                          int timeout, void *unused_context)
 {
 
     /*
index 2bc428d1edaf1563208a0e2c3191813ed4bfe622..723bf036d35b9d79d996b862638187dd25a09b44 100644 (file)
@@ -6,11 +6,12 @@
 /* SYNOPSIS
 /*     #include <iostuff.h>
 /*
-/*     int     timed_write(fd, buf, buf_len, timeout)
+/*     int     timed_write(fd, buf, buf_len, timeout, context)
 /*     int     fd;
 /*     const void *buf;
 /*     unsigned len;
 /*     int     timeout;
+/*     void    *context;
 /* DESCRIPTION
 /*     timed_write() performs a write() operation when the specified
 /*     descriptor becomes writable within a user-specified deadline.
@@ -25,6 +26,9 @@
 /* .IP timeout
 /*     The deadline in seconds. If this is <= 0, the deadline feature
 /*     is disabled.
+/* .IP context
+/*     Application context. This parameter is unused. It exists only
+/*     for the sake of VSTREAM compatibility.
 /* DIAGNOSTICS
 /*     When the operation does not complete within the deadline, the
 /*     result value is -1, and errno is set to ETIMEDOUT.
@@ -51,7 +55,8 @@
 
 /* timed_write - write with deadline */
 
-int     timed_write(int fd, void *buf, unsigned len, int timeout)
+int     timed_write(int fd, void *buf, unsigned len,
+                           int timeout, void *unused_context)
 {
 
     /*
index 2274510df7b7a76a238d83943e4258620c190ada..9c845a613ed27b0ec8f1325312bc74c270f3795e 100644 (file)
 /*
 /*     int     vstream_peek(stream)
 /*     VSTREAM *stream;
+/*
+/*     int     vstream_setjmp(stream, buffer)
+/*     VSTREAM *stream;
+/*     jmp_buf *buffer;
+/*
+/*     void    longjmp(stream, val)
+/*     VSTREAM *stream;
+/*     int     val;
 /* DESCRIPTION
 /*     The \fIvstream\fR module implements light-weight buffered I/O
 /*     similar to the standard I/O routines.
 /*     value) pairs, terminated with VSTREAM_CTL_END.
 /*     The following lists the names and the types of the corresponding
 /*     value arguments.
-/* .IP "VSTREAM_CTL_READ_FN (int (*)(int, void *, unsigned))"
+/* .IP "VSTREAM_CTL_READ_FN (int (*)(int, void *, unsigned, int, void *))"
 /*     The argument specifies an alternative for the timed_read(3) function,
 /*     for example, a read function that performs encryption.
-/* .IP "VSTREAM_CTL_WRITE_FN (int (*)(int, void *, unsigned))"
+/* .IP "VSTREAM_CTL_WRITE_FN (int (*)(int, void *, unsigned, int, void *))"
 /*     The argument specifies an alternative for the timed_write(3) function,
 /*     for example, a write function that performs encryption.
+/* .IP "VSTREAM_CTL_CONTEXT (char *)"
+/*     The argument specifies application context that is passed on to
+/*     the application-specified read/write routines. No copy is made.
 /* .IP "VSTREAM_CTL_PATH (char *)"
 /*     Updates the stored pathname of the specified stream. The pathname
 /*     is copied.
 /*     The deadline for a descriptor to become readable in case of a read
 /*     request, or writable in case of a write request. Specify a value
 /*     <= 0 to disable deadlines.
+/* .IP "VSTREAM_CTL_EXCEPT (no value)"
+/*     Enable exception handling with vstream_setjmp() and vstream_longjmp().
+/*     This involves allocation of additional memory that normally isn't
+/*     used.
 /* .PP
 /*     vstream_fileno() gives access to the file handle associated with
 /*     a buffered stream. With streams that have separate read/write
 /*
 /*     vstream_peek() returns the number of characters that can be
 /*     read from the named stream without refilling the read buffer.
+/*
+/*     vstream_setjmp() saves processing context and makes that context
+/*     available for use with vstream_longjmp().  Normally, vstream_setjmp()
+/*     returns zero.  A non-zero result means that vstream_setjmp() returned
+/*     through a vstream_longjmp() call; the result is the \fIval\fR argment
+/*     given to vstream_longjmp().
+/*
+/*     NB: non-local jumps such as vstream_longjmp() are not safe
+/*     for jumping out of any vstream routine.
 /* DIAGNOSTICS
 /*     Panics: interface violations. Fatal errors: out of memory.
 /* SEE ALSO
 /*     timed_read(3) default read routine
 /*     timed_write(3) default write routine
 /*     vbuf_print(3) formatting engine
+/*     setjmp(3) non-local jumps
 /* BUGS
 /*     Should use mmap() on reasonable systems.
 /* LICENSE
 #include "vbuf_print.h"
 #include "iostuff.h"
 #include "vstring.h"
-#include "binattr.h"
 #include "vstream.h"
 
 /* Application-specific. */
@@ -499,7 +523,7 @@ static int vstream_fflush_some(VSTREAM *stream, int to_flush)
      * any.
      */
     for (data = (char *) bp->data, len = to_flush; len > 0; len -= n, data += n) {
-       if ((n = stream->write_fn(stream->fd, data, len, stream->timeout)) <= 0) {
+       if ((n = stream->write_fn(stream->fd, data, len, stream->timeout, stream->context)) <= 0) {
            bp->flags |= VSTREAM_FLAG_ERR;
            if (errno == ETIMEDOUT)
                bp->flags |= VSTREAM_FLAG_TIMEOUT;
@@ -625,7 +649,7 @@ static int vstream_buf_get_ready(VBUF *bp)
      * data as is available right now, whichever is less. Update the cached
      * file seek position, if any.
      */
-    switch (n = stream->read_fn(stream->fd, bp->data, bp->len, stream->timeout)) {
+    switch (n = stream->read_fn(stream->fd, bp->data, bp->len, stream->timeout, stream->context)) {
     case -1:
        bp->flags |= VSTREAM_FLAG_ERR;
        if (errno == ETIMEDOUT)
@@ -874,7 +898,8 @@ VSTREAM *vstream_fdopen(int fd, int flags)
     stream->pid = 0;
     stream->waitpid_fn = 0;
     stream->timeout = 0;
-    stream->attr = 0;
+    stream->context = 0;
+    stream->jbuf = 0;
     return (stream);
 }
 
@@ -929,8 +954,8 @@ int     vstream_fclose(VSTREAM *stream)
     }
     if (stream->path)
        myfree(stream->path);
-    if (stream->attr)
-       binattr_free(stream->attr);
+    if (stream->jbuf)
+       myfree((char *) stream->jbuf);
     if (!VSTREAM_STATIC(stream))
        myfree((char *) stream);
     return (err ? VSTREAM_EOF : 0);
@@ -988,6 +1013,9 @@ void    vstream_control(VSTREAM *stream, int name,...)
        case VSTREAM_CTL_WRITE_FN:
            stream->write_fn = va_arg(ap, VSTREAM_FN);
            break;
+       case VSTREAM_CTL_CONTEXT:
+           stream->context = va_arg(ap, char *);
+           break;
        case VSTREAM_CTL_PATH:
            if (stream->path)
                myfree(stream->path);
@@ -1023,6 +1051,10 @@ void    vstream_control(VSTREAM *stream, int name,...)
        case VSTREAM_CTL_TIMEOUT:
            stream->timeout = va_arg(ap, int);
            break;
+       case VSTREAM_CTL_EXCEPT:
+           if (stream->jbuf == 0)
+               stream->jbuf = (jmp_buf *) mymalloc(sizeof(jmp_buf));
+           break;
        default:
            msg_panic("%s: bad name %d", myname, name);
        }
index 76cb3d25a5f698ef43201393d1b1fcb834baaebe..400eaf9a49bd39d612e27bb63cc7cec2e213a903 100644 (file)
@@ -16,6 +16,7 @@
   */
 #include <fcntl.h>
 #include <stdarg.h>
+#include <setjmp.h>
 
  /*
   * Utility library.
@@ -27,7 +28,7 @@
   * Simple buffered stream. The members of this structure are not part of the
   * official interface and can change without prior notice.
   */
-typedef int (*VSTREAM_FN) (int, void *, unsigned, int);
+typedef int (*VSTREAM_FN) (int, void *, unsigned, int, void *);
 typedef int (*VSTREAM_WAITPID_FN) (pid_t, WAIT_STATUS_T *, int);
 
 typedef struct VSTREAM {
@@ -35,16 +36,17 @@ typedef struct VSTREAM {
     int     fd;                                /* file handle, no 256 limit */
     VSTREAM_FN read_fn;                        /* buffer fill action */
     VSTREAM_FN write_fn;               /* buffer fill action */
+    void   *context;                   /* application context */
     long    offset;                    /* cached seek info */
     char   *path;                      /* give it at least try */
     int     read_fd;                   /* read channel (double-buffered) */
     int     write_fd;                  /* write channel (double-buffered) */
     VBUF    read_buf;                  /* read buffer (double-buffered) */
     VBUF    write_buf;                 /* write buffer (double-buffered) */
-    int     timeout;                   /* read/write timout */
     pid_t   pid;                       /* vstream_popen/close() */
     VSTREAM_WAITPID_FN waitpid_fn;     /* vstream_popen/close() */
-    BINATTR *attr;                     /* optional binary attribute list */
+    int     timeout;                   /* read/write timout */
+    jmp_buf *jbuf;                     /* exception handling */
 } VSTREAM;
 
 extern VSTREAM vstream_fstd[];         /* pre-defined streams */
@@ -104,6 +106,8 @@ extern void vstream_control(VSTREAM *, int,...);
 #define VSTREAM_CTL_WRITE_FD   6
 #define VSTREAM_CTL_WAITPID_FN 7
 #define VSTREAM_CTL_TIMEOUT    8
+#define VSTREAM_CTL_EXCEPT     9
+#define VSTREAM_CTL_CONTEXT    10
 
 extern VSTREAM *vstream_printf(const char *,...);
 extern VSTREAM *vstream_fprintf(VSTREAM *, const char *,...);
@@ -128,14 +132,11 @@ extern VSTREAM *vstream_vfprintf(VSTREAM *, const char *, va_list);
 extern int vstream_peek(VSTREAM *);
 
  /*
-  * Attribute management, a way of tacking on arbitrary information onto a
-  * VSTREAM without destroying the VSTREAM abstraction itself.
+  * Exception handling. We use pointer to jmp_buf to avoid a lot of unused
+  * baggage for streams that don't need this functionality.
   */
-#define VSTREAM_ATTR_FREE_FN BINATTR_FREE_FN
-
-extern void vstream_attr_set(VSTREAM *, const char *, char *, VSTREAM_ATTR_FREE_FN);
-extern char *vstream_attr_get(VSTREAM *, const char *);
-extern void vstream_attr_unset(VSTREAM *, const char *);
+#define vstream_setjmp(stream)         setjmp((stream)->jbuf[0])
+#define vstream_longjmp(stream, val)   longjmp((stream)->jbuf[0], (val))
 
 /* LICENSE
 /* .ad
diff --git a/postfix/util/vstream_attr.c b/postfix/util/vstream_attr.c
deleted file mode 100644 (file)
index 00484b7..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*++
-/* NAME
-/*     vstream_attr 3
-/* SUMMARY
-/*     per-stream attribute list management
-/* SYNOPSIS
-/*     #include <vstream.h>
-/*
-/*     void    vstream_attr_set(stream, name, value, free_fn)
-/*     VSTREAM *stream;
-/*     const char *name;
-/*     char    *value;
-/*     void    (*free_fn)(char *);
-/*
-/*     char    *vstream_attr_get(stream, name)
-/*     VSTREAM *stream;
-/*     const char *name;
-/*
-/*     void    vstream_attr_unset(stream, name)
-/*     VSTREAM *stream;
-/*     const char *name;
-/* DESCRIPTION
-/*     This module maintains an optional per-stream open attribute
-/*     list for arbitrary binary values. It is in fact a convienience
-/*     interface built on top of the binattr(3) module.
-/*
-/*     vstream_attr_set() adds or replaces the named attribute.
-/*
-/*     vstream_attr_get() looks up the named attribute. The result
-/*     is the value stored with vstream_attr_set() or a null pointer
-/*     when the requested information is not found.
-/*
-/*     vstream_attr_unset() removes the named attribute. This operation
-/*     is undefined for attributes that do not exist.
-/*
-/*     Arguments:
-/* .IP stream
-/*     Open VSTREAM.
-/* .IP name
-/*     Attribute name, in the form of a null-terminated list.
-/*     The name is copied.
-/* .IP value
-/*     Arbitrary binary value. The value is not copied.
-/* .IP free_fn
-/*     Null pointer, or pointer to function that destroys the value
-/*     that was stored with vstream_attr_set().
-/* 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 <vstream.h>
-#include <htable.h>
-
-/* vstream_attr_set - add or replace per-stream attribute */
-
-void    vstream_attr_set(VSTREAM *stream, const char *name, char *value, BINATTR_FREE_FN free_fn)
-{
-    if (stream->attr == 0)
-       stream->attr = binattr_create(1);
-    binattr_set(stream->attr, name, value, free_fn);
-}
-
-/* vstream_attr_get - look up per-stream attribute */
-
-char   *vstream_attr_get(VSTREAM *stream, const char *name)
-{
-    if (stream->attr == 0)
-       return (0);
-    else
-       return (binattr_get(stream->attr, name));
-}
-
-/* vstream_attr_unset - unset per-stream attribute */
-
-void    vstream_attr_unset(VSTREAM *stream, const char *name)
-{
-    if (stream->attr)
-       binattr_unset(stream->attr, name);
-}