Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Unofficial ESMTP Patch for Smail 3.1.28

1 view
Skip to first unread message

Michael A Meiszl

unread,
Mar 3, 1994, 6:08:45 PM3/3/94
to
Betonung auf "Unofficial"!!!

Note: Unternehmt KEINE Versuche hiermit einen Sendmail 8.6.x anzusprechen!!!!
Das endet mit "554 Mail is lost: died on signal 11" bei Sendmail

(Note 2: ist allerdings eine gute Methode die Eunet Hacker etwas in Trab zu
bringen :-))) )


#!/bin/sh
# This is a shell archive (shar 3.24)
# made 03/03/1994 23:04 UTC by mam@mamunx
# Source directory /u2/src/smail-3.1.28
#
# existing files WILL be overwritten
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 24009 -rw------- patch.ehlo
#
if touch 2>&1 | fgrep '[-amc]' > /dev/null
then TOUCH=touch
else TOUCH=true
fi
# ============= patch.ehlo ==============
echo "x - extracting patch.ehlo (Text)"
sed 's/^X//' << 'SHAR_EOF' > patch.ehlo &&
X SMTP Extensions for Smail 3.1.28
X by Simon Leinen <si...@lia.di.epfl.ch>
X
X DESCRIPTION
X -----------
XThis file contains a patch to the Smail 3.1.28 sources that implements
Xthe RFCs 1425, 1426 and 1427. The following features are implemented:
X
X* The new EHLO command is recognized as mandated by [RFC1425]. The
X list of supported extensions in the reply includes HELP, EXPN and
X optionally 8BITMIME and SIZE. If a message is received from a
X remote mailer that said EHLO, the Received: line that is added to
X the message will contain a sender protocol of "esmtp" rather than
X "stmp" (or "ebsmtp" rather than "bsmtp").
X
X* BODY [RFC1426] and SIZE [RFC1427] clauses are recognized in MAIL
X FROM: SMTP commands on the receiver side. Currently it doesn't
X matter whether the BODY type is 7BIT or 8BITMIME - Smail is always
X 8-bit transparent. If the value passed in a SIZE clause exceeds
X max_message_size, a "552 message too large" error reply is
X generated.
X
X* The sender side tries to greet the receiving SMTP with an EHLO
X command. If this fails, RSET/HELO is sent and no ESMTP capabilities
X are assumed. If the EHLO is accepted, Smail parses the response to
X find out whether the receiver understands SIZE and BODY. A maximum
X message size that is provided by the receiving SMTP is currently
X ignored, but the MAIL FROM: command is decorated with a SIZE
X declaration based on a guess of the spooled message's size. The
X BODY clause is never issued.
X
X INSTALLATION
X ------------
XApply the enclosed patch to the top-level directory of the Smail
Xdistribution (the one that contains the src/ subdirectory). You will
Xneed a fairly recent version of the "patch" program because the patch
Xis in the newer, more compact and more readable Unidiff format.
X
XIn order to enable the extensions, the following symbols have to be
Xadded to the HAVE variable in the EDITME file:
X
X EHLO to enable server-side RFC 1425 support, and
X client-side support for EHLO and SIZE
X ESMTP_8BITMIME
X to enable minimal server-side RFC 1426 support.
X Basically the BODY clause is accepted and ignored.
X ESMTP_SIZE
X to enable server-side RFC 1427 support
X
X CAVEATS
X -------
XHere is a possible problem with ESMTP support: Apparently there are
Xsome non-RFC821-conformant gateways running on legacy systems that
Xreact to the EHLO query by closing down the connection rather than
Xgiving a "500 command unrecognized" error. Smail handles this
Xsituation like a normal link failure, so a message sent via SMTP to
Xsuch a mailer will presumably get bounced after the retry period is
Xover. If you care about interoperatibility with such weird systems,
Xyou probably don't want to use the SMTP extensions, or write some code
Xfor Smail to handle this situation more cleverly (see the TODO section
Xbelow). Personally I think that this is such an extreme case of
Xprotocol incompatibility that I haven't taken the time to support
Xthese mailer daemons.
X
XWhen an ESMTP-capable client Smail talks to a non-ESMTP-capable SMTP
Xserver, there are two additional query/reply pairs for each SMTP
Xconnection. This is because Smail issues EHLO to find out whether the
Xrecipient mailer handles ESMTP, gets an error message and then sends
Xan RSET before retrying with HELO. If you have extremely slow or
Xunreliable SMTP connections, or if your network connections are
Xcharged by the packet this may matter to you.
X
X TODO
X ----
XRight now the SMTP extensions don't really give any new functionality,
Xexcept that max_message_size is *somewhat* enforced, but only for
Xcooperating (RFC 1427-savvy) client mailers. The following
Ximprovements to the code might be useful:
X
X* a SIZE clause should be used to dynamically determine whether the
X incoming message will fit where it will be put next (one of the
X spool directories). If this is the case, a temporary failure
X message should be sent to the client SMTP to avoid sending a lot of
X data in vain.
X
X* Smail should be extended to handle 8-bit text messages in a more
X standard way. Currently it is simply 8-bit transparent, which is
X seen as a feature by most users. However, sending non-7-bit-ASCII
X characters to remote mailer daemons is a violation of RFC 821 and
X can lead to interoperability problems. Even when communicating over
X 8-bit clean SMTP networks, the "Just-Send-8" approach has the
X problem that it is not clear which character set has been used by
X the author [RFC1428].
X
X In principle, all these problems are solved by the MIME standard
X [RFC1341, RFC1342], which is rapidly gaining acceptance. In a world
X where everybody uses MIME-capable mailers, there wouldn't be any
X eighth bits to be transported. But as long as people still send
X 8-bit messages, Smail could convert such messages to 7bit-MIME when
X they are transported over an SMTP network. RFC1428 describes how
X this could be done.
X
X* If the "link broken by EHLO" problem really does occur in the real
X world, it has to be handled by Smail's SMTP client side. For
X instance, once an EHLO command causes a link to be broken, the
X receiving host should be noted in a "black list" by a mechanism
X similar to the retry file mechanism. Hosts should be removed from
X the black list periodically, so that when they are upgraded to
X SMTP-conforming software, the new functionality will be used. It
X would also be nice if the "retry" file could be extended by
X something like "ehlo/noehlo" keyword that would allow specific
X hosts/domains to be excluded from ESMTP trials.
X
X* Some SMTP-based transports may want to use EHLO while others don't.
X In batch SMTP, for example, the EHLO command probably doesn't make
X much sense since the whole idea of "option negociation" doesn't fit
X into the "batch" model. I don't know whether this should be
X hardwired in the SMTP transport or made a configurable parameter of
X transport entries.
X
X ReFerenCes
X
X1341 Borenstein, N.; Freed, N. MIME (Multipurpose Internet Mail Extensions)
X Mechanisms for Specifying and Describing the Format of Internet Message
X Bodies. 1992 June; 80 p. (Format: TXT=211117 PS=347082 bytes)
X
X1342 Moore, K. Representation of Non-ASCII Text in Internet Message
X Headers. 1992 June; 7 p. (Format: TXT=15846 bytes)
X
X1344 Borenstein, N. Implications of MIME for Internet Mail Gateways. 1992
X June; 9 p. (Format: TXT=25873 PS=51812 bytes)
X ----------
X1425 Rose, M.; Stefferud, E.; Crocker, D. SMTP Service Extensions.
X 1993 February; 10 p. (Format: TXT=20933 bytes)
X
X1426 Rose, M.; Stefferud, E.; Crocker, D. SMTP Service Extension for
X 8bit-MIMEtransport. 1993 February; 6 p. (Format: TXT=11662
X bytes)
X
X1427 Moore, K. SMTP Service Extension for Message Size Declaration.
X 1993 February; 8 p. (Format: TXT=17857 bytes)
X
X1428 Vaudreuil, G. Transition of Internet Mail from Just-Send-8 to
X 8bit-SMTP/MIME. 1993 February; 6 p. (Format: TXT=12065 bytes)
X
X--- 1.1 1993/04/02 10:42:48
X+++ src/transports/smtplib.h 1993/04/02 10:45:40
X@@ -18,6 +18,17 @@
X #define SMTP_FAIL (-1)
X #define SMTP_AGAIN (-2)
X
X+#ifdef HAVE_EHLO
X+typedef enum
X+{
X+ ESMTP_none = 0x0000,
X+ ESMTP_basic = 0x0001,
X+ ESMTP_8bitmime = 0x0002,
X+ ESMTP_size = 0x0004,
X+}
X+SMTPExtension, SMTPExtensionFlags;
X+#endif
X+
X /*
X * the following structure is passed around between SMTP functions and
X * should be initialized as necessary to describe the SMTP connection
X@@ -32,6 +43,10 @@
X unsigned long_timeout; /* normal SMTP read timeout period */
X char *nl; /* line terminator string */
X struct transport *tp; /* associated transport */
X+#ifdef HAVE_EHLO
X+ SMTPExtensionFlags smtp_flags; /* SMTP extensions supported by remote */
X+ unsigned long max_message_size; /* message size limit of remote */
X+#endif
X };
X
X /* functions defined in smtplib.c */
X--- 1.1 1993/04/01 14:00:03
X+++ src/transports/smtplib.c 1993/04/04 19:40:01
X@@ -40,6 +40,9 @@
X #endif
X
X /* supported SMTP commands */
X+#ifdef HAVE_EHLO
X+#define EHLO(domain) "EHLO %s", domain
X+#endif
X #define HELO(domain) "HELO %s", domain
X #define MAIL_BEGIN "MAIL FROM:<"
X #define MAIL_END ">"
X@@ -134,11 +137,110 @@
X return SMTP_AGAIN;
X }
X
X+#ifdef HAVE_EHLO
X /*
X * say who we are.
X * Possible responses:
X * 250 - okay (continue conversation)
X * 421 - closing down (try again later)
X+ * 5xx - fatal error (try HELO)
X+ */
X+ smtp_out.i = 0;
X+ (void) str_printf(&smtp_out, EHLO(primary_name));
X+
X+ reply = wait_write_command(smtpb, smtpb->short_timeout,
X+ smtp_out.p, smtp_out.i, &reply_text);
X+
X+ if (REPLY_GROUP(reply) == NEGATIVE_TRY_AGAIN) {
X+ /* remote SMTP closed, try again later */
X+ *error_p = try_again(smtpb->tp, reply_text);
X+ return SMTP_AGAIN;
X+ }
X+ if (reply != REPLY_OK) {
X+ /* fatal error, probably doesn't understand EHLO */
X+ smtp_out.i = 0;
X+ (void) str_printf(&smtp_out, "RSET");
X+
X+ reply = wait_write_command(smtpb, smtpb->short_timeout,
X+ smtp_out.p, smtp_out.i, &reply_text);
X+ if (REPLY_GROUP(reply) == NEGATIVE_TRY_AGAIN) {
X+ /* remote SMTP closed, try again later */
X+ *error_p = try_again(smtpb->tp, reply_text);
X+ return SMTP_AGAIN;
X+ } else if (reply != REPLY_OK) {
X+ return SMTP_FAIL;
X+ }
X+ /* the RSET command has been accepted; try again with HELO */
X+ } else {
X+ char * cp = reply_text;
X+ int on_greet_line = 1;
X+
X+ smtpb->smtp_flags = ESMTP_basic;
X+ /* Parse the EHLO reply to find out
X+ what the remote server supports */
X+ while (*cp != 0) {
X+ int skip;
X+ int keywordlength;
X+
X+ for (skip = 4; *cp != 0 && skip; --skip, ++cp) {
X+ if (skip == 1
X+ ? (*cp != ' ' && *cp != '-')
X+ : (! isdigit (*cp))) {
X+ goto malformed_ehlo_reply;
X+ }
X+ }
X+ if (skip != 0) {
X+ goto malformed_ehlo_reply;
X+ }
X+ if (on_greet_line) {
X+ /*
X+ * Ignore greeting on first line
X+ */
X+ on_greet_line = 0;
X+ goto skip_rest_of_line;
X+ }
X+ for (keywordlength = 0;
X+ *(cp+keywordlength) != 0
X+ && !isspace (*(cp+keywordlength));
X+ ++keywordlength)
X+ ;
X+ if (strncmpic(cp, "SIZE", keywordlength) == 0) {
X+ unsigned long max_message_size = 0;
X+
X+ cp += keywordlength;
X+ while (*cp == ' ' || *cp == '\t')
X+ ++cp;
X+ if (!isdigit(*cp) == '\n')
X+ goto malformed_ehlo_reply;
X+ while (isdigit(*cp)) {
X+ max_message_size *= 10;
X+ max_message_size += *cp - '0';
X+ ++cp;
X+ }
X+ smtpb->smtp_flags |= ESMTP_size;
X+ smtpb->max_message_size = max_message_size;
X+ } else if (strncmpic(cp, "8BITMIME", keywordlength) == 0) {
X+ smtpb->smtp_flags |= ESMTP_8bitmime;
X+ } else {
X+ }
X+ skip_rest_of_line:
X+ while (*cp != 0 && *cp != '\n')
X+ ++cp;
X+ if (*cp == '\n')
X+ ++cp;
X+ }
X+ return SMTP_SUCCEED;
X+ malformed_ehlo_reply:
X+ /* This seems to be a reasonable way
X+ to handle malformed EHLO replies: */
X+ return SMTP_SUCCEED;
X+ }
X+#endif
X+ /*
X+ * say who we are.
X+ * Possible responses:
X+ * 250 - okay (continue conversation)
X+ * 421 - closing down (try again later)
X * 5xx - fatal error (return message to sender)
X */
X smtp_out.i = 0;
X@@ -217,6 +319,30 @@
X (error_sender? ((islocal && tp->flags & LOCAL_XFORM)? "+": ""):
X get_sender_addr(tp)),
X MAIL_END);
X+
X+#ifdef HAVE_EHLO
X+ /*
X+ * send (a guess of) the size of the message to be transported.
X+ * Of course the guess could be a bit more educated, but usually
X+ * it doesn't matter if it is slightly incorrect. We simply add
X+ * 2% in order to account for \n -> \r\n conversion.
X+ */
X+ if (smtpb->smtp_flags & ESMTP_size) {
X+ str_printf(&smtp_out, " SIZE %lu",
X+ (unsigned long) (msg_size * 1.02));
X+ }
X+#if 0
X+ /*
X+ * This is commented out because we are not supposed to send a
X+ * non-MIME message on 8BITMIME mode. But sending a non-7bit
X+ * clean message in 7BIT mode isn't a good idea either. Sigh.
X+ * Something more sophisticated is definitely needed here.
X+ */
X+ if (smtpb->smtp_flags & ESMTP_8bitmime) {
X+ str_printf(&smtp_out, " BODY 8BITMIME");
X+ }
X+#endif
X+#endif
X
X reply = wait_write_command(smtpb, smtpb->long_timeout,
X smtp_out.p, smtp_out.i, &reply_text);
X--- 1.1 1993/04/02 10:49:54
X+++ src/transports/tcpsmtp.c 1993/04/02 10:50:47
X@@ -318,7 +318,10 @@
X smtpbuf.nl = "\r\n";
X tp->flags |= PUT_CRLF;
X smtpbuf.tp = tp;
X-
X+#ifdef HAVE_EHLO
X+ smtpbuf.smtp_flags = ESMTP_none;
X+ smtpbuf.max_message_size = 0;
X+#endif
X DEBUG(DBG_DRIVER_LO, "connected\n");
X
X switch (smtp_startup(&smtpbuf, ep)) {
X--- 1.1 1992/10/29 19:05:28
X+++ src/smtprecv.c 1993/04/05 16:32:11
X@@ -34,6 +34,9 @@
X /* types local to this file */
X enum e_smtp_commands {
X HELO_CMD, /* HELO domain */
X+#ifdef HAVE_EHLO
X+ EHLO_CMD, /* EHLO domain */
X+#endif
X MAIL_CMD, /* MAIL FROM:<sender> */
X RCPT_CMD, /* RCPT TO:<recipient> */
X DATA_CMD, /* DATA */
X@@ -69,6 +72,9 @@
X "250-The following SMTP commands are recognized:",
X "250-",
X "250- HELO hostname - startup and give your hostname",
X+#ifdef HAVE_EHLO
X+ "250- EHLO hostname - startup with extension info",
X+#endif
X "250- MAIL FROM:<sender-address> - start transaction from sender",
X "250- RCPT TO:<recipient-address> - name recipient for message",
X "250- VRFY <address> - verify deliverability of address",
X@@ -87,6 +93,19 @@
X "250 Multiple messages may be specified. End the last one with a QUIT."
X };
X
X+#ifdef HAVE_ESMTP_8BITMIME
X+typedef enum {
X+ BF_unspecified,
X+ BF_7bit,
X+ BF_8bitmime
X+}
X+BodyFormat;
X+#endif
X+
X+#ifdef HAVE_ESMTP_SIZE
X+#define BS_UNSPECIFIED -1L
X+typedef long BodySize;
X+#endif
X
X
X /*
X@@ -121,6 +140,10 @@
X FILE *save_errfile = errfile;
X int save_debug = debug;
X int temp, i;
X+ char *rest;
X+#ifdef HAVE_EHLO
X+ int ehlo_p = 0;
X+#endif
X
X /* initialize state */
X initialize_state();
X@@ -165,10 +188,47 @@
X alarm(smtp_receive_command_timeout);
X }
X switch (read_smtp_command(in)) {
X+#ifdef HAVE_EHLO
X+ case EHLO_CMD:
X+ ehlo_p = 1;
X+#endif
X case HELO_CMD:
X strip_rfc822_comments(data);
X if (out && data[0] == '\0') {
X+#ifdef HAVE_EHLO
X+ fprintf(out, "501 %s requires domain name as operand\r\n",
X+ ehlo_p ? "EHLO" : "HELO");
X+#else
X fprintf(out, "501 HELO requires domain name as operand\r\n");
X+#endif
X+ fflush(out);
X+ break;
X+ }
X+ if (sender_host == NULL && data[0] != '\0') {
X+ sender_host = COPY_STRING(data);
X+ }
X+ if (sender_proto == NULL) {
X+#ifdef HAVE_EHLO
X+ sender_proto = (out? ehlo_p? "esmtp": "smtp"
X+ : ehlo_p? "ebsmtp": "bsmtp");
X+#else
X+ sender_proto = (out? "smtp": "bsmtp");
X+#endif
X+ }
X+#ifdef HAVE_EHLO
X+ if (! ehlo_p) {
X+#endif
X+ if (out) {
X+ fprintf(out, "250 %s Hello %s\r\n", primary_name, data);
X+ fflush(out);
X+ }
X+ reset_state();
X+ break;
X+#ifdef HAVE_EHLO
X+ }
X+ strip_rfc822_comments(data);
X+ if (out && data[0] == '\0') {
X+ fprintf(out, "501 EHLO requires domain name as operand\r\n");
X fflush(out);
X break;
X }
X@@ -179,11 +239,21 @@
X sender_proto = (out? "smtp": "bsmtp");
X }
X if (out) {
X- fprintf(out, "250 %s Hello %s\r\n", primary_name, data);
X+ fprintf(out, "250-%s Hello %s, here's what we support:\r\n",
X+ primary_name, data);
X+ fprintf(out, "250-EXPN\r\n");
X+#ifdef HAVE_ESMTP_SIZE
X+ fprintf(out, "250-SIZE %d\r\n", max_message_size);
X+#endif
X+#ifdef HAVE_ESMTP_8BITMIME
X+ fprintf(out, "250-8BITMIME\r\n");
X+#endif
X+ fprintf(out, "250 HELP\r\n");
X fflush(out);
X }
X reset_state();
X break;
X+#endif HAVE_EHLO
X
X case MAIL_CMD:
X strip_rfc822_comments(data);
X@@ -199,15 +269,13 @@
X }
X break;
X }
X- sender = preparse_address(data, &error);
X+ sender = preparse_address_1(data, &error, &rest);
X if (out) {
X- if (sender) {
X- fprintf(out, "250 <%s> ... Sender Okay\r\n",
X- sender);
X- } else {
X+ if (!sender) {
X fprintf(out, "501 <%s> ... %s\r\n", data, error);
X+ fflush(out);
X+ break;
X }
X- fflush(out);
X }
X if (sender && sender[0] == '\0') {
X /* special error sender form <> given */
X@@ -217,6 +285,144 @@
X /* special smail-internal <+> was given */
X sender = COPY_STRING("<+>");
X }
X+#if defined(HAVE_ESMTP_SIZE) || defined(HAVE_ESMTP_8BITMIME)
X+ {
X+ char * format = 0;
X+ int format_length = 0;
X+#ifdef HAVE_ESMTP_8BITMIME
X+ BodyFormat body_format = BF_unspecified;
X+#endif
X+#ifdef HAVE_ESMTP_SIZE
X+ BodySize body_size = BS_UNSPECIFIED;
X+#endif
X+
X+ while (rest && *rest != '\0') {
X+ /* maybe we have an extended MAIL command */
X+ while (*rest != '\0' && isspace (*rest)) {
X+ ++rest;
X+ }
X+ {
X+ int restlen = 0;
X+ while (*(rest+restlen) != 0
X+ && !isspace (*(rest+restlen))) {
X+ ++restlen;
X+ }
X+#ifdef HAVE_ESMTP_SIZE
X+ if (strncmpic(rest, "SIZE", restlen) == 0) {
X+ rest += restlen;
X+ while (*rest != '\0' && isspace (*rest)) {
X+ ++rest;
X+ }
X+ restlen = 0;
X+ body_size = 0;
X+ if (*(rest+restlen) == 0) {
X+ if (out) {
X+ *(rest+restlen) = '\0';
X+ fprintf(out, "555 missing SIZE parameter\r\n",
X+ rest);
X+ fflush(out);
X+ }
X+ goto fail_mail_cmd;
X+ }
X+ while (*(rest+restlen) != 0
X+ && isdigit (*(rest+restlen))
X+ && body_size <= max_message_size) {
X+ body_size = 10*body_size+*(rest+restlen)-'0';
X+ ++restlen;
X+ }
X+ if (body_size > max_message_size) {
X+ if (out) {
X+ fprintf(out, "552 message too large\r\n");
X+ fflush(out);
X+ }
X+ goto fail_mail_cmd;
X+ } else if (*(rest+restlen) != 0
X+ && !isspace (*(rest+restlen))) {
X+ if (out) {
X+ while (*(rest+restlen) != 0
X+ && !isspace (*(rest+restlen))) {
X+ ++restlen;
X+ }
X+ *(rest+restlen) = '\0';
X+ fprintf(out, "555 malformed SIZE clause %s\r\n",
X+ rest);
X+ fflush(out);
X+ }
X+ goto fail_mail_cmd;
X+ }
X+ } else
X+#endif
X+#ifdef HAVE_ESMTP_8BITMIME
X+ if (strncmpic(rest, "BODY", restlen) == 0) {
X+ rest += restlen;
X+ while (*rest != '\0' && isspace (*rest)) {
X+ ++rest;
X+ }
X+ restlen = 0;
X+ while (*(rest+restlen) != 0
X+ && !isspace (*(rest+restlen))) {
X+ ++restlen;
X+ }
X+ if (restlen == 0) {
X+ if (out) {
X+ *(rest+restlen) = '\0';
X+ fprintf(out, "555 missing BODY parameter\r\n",
X+ rest);
X+ fflush(out);
X+ }
X+ goto fail_mail_cmd;
X+ }
X+ if (strncmpic(rest, "7BIT", restlen) == 0) {
X+ body_format = BF_7bit;
X+ } else if (strncmpic(rest, "8BITMIME", restlen) == 0) {
X+ body_format = BF_8bitmime;
X+ } else {
X+ if (out) {
X+ *(rest+restlen) = '\0';
X+ fprintf(out, "555 unknown BODY type %s\r\n",
X+ rest);
X+ fflush(out);
X+ }
X+ goto fail_mail_cmd;
X+ }
X+ } else
X+#endif
X+ {
X+ if (out) {
X+ *(rest+restlen) = '\0';
X+ fprintf(out, "555 Unknown MAIL TO: option %s\r\n", rest);
X+ fflush(out);
X+ }
X+ goto fail_mail_cmd;
X+ }
X+ rest += restlen;
X+ }
X+ }
X+ if (out) {
X+ if (format && *format != '\0') {
X+ *(format+format_length) = '\0';
X+ fprintf(out, "250 <%s> ... Sender Okay, using format %s\r\n",
X+ sender, format);
X+ } else {
X+ fprintf(out, "250 <%s> ... Sender Okay\r\n",
X+ sender);
X+ }
X+ fflush(out);
X+ }
X+ }
X+#else
X+ if (out) {
X+ fprintf(out, "250 <%s> ... Sender Okay\r\n",
X+ sender);
X+ fflush(out);
X+ }
X+#endif
X+ break;
X+ fail_mail_cmd:
X+ if (sender) {
X+ xfree(sender);
X+ sender = NULL;
X+ }
X break;
X
X case RCPT_CMD:
X@@ -514,6 +720,9 @@
X enum e_smtp_commands cmd;
X } smtp_cmd_list[] = {
X "HELO", sizeof("HELO")-1, HELO_CMD,
X+#ifdef HAVE_EHLO
X+ "EHLO", sizeof("EHLO")-1, EHLO_CMD,
X+#endif
X "MAIL FROM:", sizeof("MAIL FROM:")-1, MAIL_CMD,
X "RCPT TO:", sizeof("RCPT TO:")-1, RCPT_CMD,
X "DATA", sizeof("DATA")-1, DATA_CMD,
X--- 1.1 1992/10/29 20:37:26
X+++ src/addr.c 1992/10/29 22:11:04
X@@ -63,6 +63,16 @@
X char *address; /* address to be preparsed */
X char **error; /* return error message here */
X {
X+ char * ignore;
X+ return preparse_address_1(address, error, & ignore);
X+}
X+
X+char *
X+preparse_address_1(address, error, rest)
X+ char *address;
X+ char **error;
X+ char **rest;
X+{
X register char *ap; /* temp for scanning address */
X char *mark_start = NULL; /* marked position of < */
X char *mark_end = NULL; /* marked position of > */
X@@ -125,9 +135,10 @@
X ap = xmalloc((unsigned)(strlen(address) + 1));
X (void) strcpy(ap, address);
X if (mark_end) {
X- *mark_end = '>'; /* widden the original address */
X+ *mark_end++ = '>'; /* widden the original address */
X }
X DEBUG1(DBG_ADDR_HI, "preparse_address returns: %s\n", ap);
X+ *rest = mark_end;
X return ap; /* no transformations */
X }
X
X@@ -144,9 +155,10 @@
X ap = xmalloc((unsigned)(strlen(address) + 1));
X (void) strcpy(ap, address);
X if (mark_end) {
X- *mark_end = '>'; /* widden the original address */
X+ *mark_end++ = '>'; /* widden the original address */
X }
X DEBUG1(DBG_ADDR_HI, "preparse address returns: %s\n", ap);
X+ *rest = mark_end;
X return ap; /* address should be okay */
X }
X ap++;
X@@ -157,7 +169,7 @@
X /* first part already !-route */
X (void) strncpy(p, address, ap-address);
X if (mark_end) {
X- *mark_end = '>'; /* widden the original address */
X+ *mark_end++ = '>'; /* widden the original address */
X }
X ap = build_uucp_route(ap, error); /* build !-route */
X if (ap == NULL) {
X@@ -167,6 +179,7 @@
X (void) strcat(p, ap); /* concatenate together */
X xfree(ap);
X DEBUG1(DBG_ADDR_HI, "preparse_address returns: %s\n", p);
X+ *rest = mark_end;
X return p; /* transformed */
X }
X }
X@@ -173,9 +186,10 @@
X ap = xmalloc((unsigned)(strlen(address) + 1));
X (void) strcpy(ap, address);
X if (mark_end) {
X- *mark_end = '>'; /* widden the original address */
X+ *mark_end++ = '>'; /* widden the original address */
X }
X DEBUG1(DBG_ADDR_HI, "preparse address returns: %s\n", ap);
X+ *rest = mark_end;
X return ap; /* no transformations */
X }
X
X--- 1.1 1992/10/29 20:40:42
X+++ src/extern.h 1992/10/29 20:41:01
X@@ -226,6 +226,7 @@
X */
X /* external functions defined in addr.c */
X extern char *preparse_address();
X+extern char *preparse_address_1();
X extern int parse_address();
X extern char *address_token();
X extern char *back_address_token();
X
XDate: Tue, 30 Nov 93 10:55 MET
XFrom: si...@lia.di.epfl.ch (Simon Leinen)
XTo: ra...@psg.com (Randy Bush)
XCc: smail3...@cs.athabascau.ca (smail3 Users),
X tr...@veritas.com (Ronald S. Karr)
XSubject: Re: max message size
XIn-Reply-To: <m0p4LHY...@rip.psg.com>
XReferences: <m0p49aM...@liasun6.epfl.ch>
X <m0p4LHY...@rip.psg.com>
XContent-Type: text
XContent-Length: 953
X
XIf you applied my ESMTP patches and the additional patch from yesterday
Xto interpret max_message_size==0 as "unlimited", then you also want to
Xapply this missing bit, or max_message_size==0 will cause all messages
Xfrom ESMTP-capabable clients that use SIZE to be rejected. Sorry for
Xthe trouble, and thanks to Randy for finding the bug!
X--
XSimon.
X
X*** src/smtprecv.c 1993/11/29 09:42:52 1.5
X--- src/smtprecv.c 1993/11/30 09:45:41
X***************
X*** 328,334 ****
X body_size = 0;
X while (*(rest+restlen) != 0
X && isdigit (*(rest+restlen))
X! && body_size <= max_message_size) {
X body_size = 10*body_size+*(rest+restlen)-'0';
X ++restlen;
X }
X--- 328,334 ----
X body_size = 0;
X while (*(rest+restlen) != 0
X && isdigit (*(rest+restlen))
X! && (!max_message_size || body_size <= max_message_size)) {
X body_size = 10*body_size+*(rest+restlen)-'0';
X ++restlen;
X }
X
SHAR_EOF
$TOUCH -am 1205003993 patch.ehlo &&
chmod 0600 patch.ehlo ||
echo "restore of patch.ehlo failed"
set `wc -c patch.ehlo`;Wc_c=$1
if test "$Wc_c" != "24009"; then
echo original size 24009, current size $Wc_c
fi
exit 0
--
* /\/\ichael /\ndreas /\/\eiszl | Tomsonstr 25 | 59071 Hamm | Tel+492381980131 *
* m...@mamunx.garmhausen.de <EUNET X.400 EUNET> m...@werries.de *
* \C=US \A=ATTMAIL \P=Garmhausen \O=GuPS \G=Michael \I=A \S=Meiszl *

Simon Leinen

unread,
Mar 4, 1994, 5:15:19 AM3/4/94
to
> Note: Unternehmt KEINE Versuche hiermit einen Sendmail 8.6.x
> anzusprechen!!!! Das endet mit "554 Mail is lost: died on
> signal 11" bei Sendmail

Dann nehmt doch einfach die neueste Version. Mit der hatte ich bis
jetzt keine Interoperabilitaetsprobleme. Ansonsten meldet Euch bitte
einfach bei mir, wenn es Schwierigkeiten mit anderen Mailern gibt!

Diesen Patch gibt es auch ueber anonymous FTP auf
liasun3.epfl.ch:/pub/mail/smail-3.1.28-esmtp.diff.

Schoene Gruesse,
--
Simon.

SMTP Extensions for Smail 3.1.28

Version 6
by Simon Leinen <si...@lia.di.epfl.ch>

DESCRIPTION
-----------


This file contains a patch to the Smail 3.1.28 sources that implements

the RFCs 1425, 1426 and 1427. The following features are implemented:

* The new EHLO command is recognized as mandated by [RFC1425]. The


list of supported extensions in the reply includes HELP, EXPN and

optionally 8BITMIME and SIZE. If a message is received from a

remote mailer that said EHLO, the Received: line that is added to

the message will contain a sender protocol of "esmtp" rather than

"stmp" (or "ebsmtp" rather than "bsmtp").

* BODY [RFC1426] and SIZE [RFC1427] clauses are recognized in MAIL


FROM: SMTP commands on the receiver side. Currently it doesn't

matter whether the BODY type is 7BIT or 8BITMIME - Smail is always

8-bit transparent. If the value passed in a SIZE clause exceeds

max_message_size, a "552 message too large" error reply is

generated.

* The sender side tries to greet the receiving SMTP with an EHLO

command. If this fails, we send the standard HELO greeting. If
this also fails, we try RSET to clear up the remote mailer and then
HELO. If the EHLO is accepted, Smail parses the response to find


out whether the receiver understands SIZE and BODY. A maximum

message size that is provided by the receiving SMTP is currently

ignored, but the MAIL FROM: command is decorated with a SIZE

declaration based on a guess of the spooled message's size. The

BODY clause is never issued.

INSTALLATION
------------


Apply the enclosed patch to the top-level directory of the Smail

distribution (the one that contains the src/ subdirectory). You will

need a fairly recent version of the "patch" program because the patch

is in the newer, more compact and more readable Unidiff format.

The server side of the extensions cannot be disabled in this version.
This means that EHLO is always accepted as an SMTP greeting, and the
SIZE parameter is accepted.

In order to enable the extensions, the following symbols have to be

added to the HAVE variable in the EDITME file:

EHLO to enable client-side support for EHLO and SIZE
ESMTP_8BITMIME


to enable minimal server-side RFC 1426 support.

Basically the BODY clause is accepted and ignored.

CAVEATS
-------


Here is a possible problem with ESMTP support: Apparently there are

some non-RFC821-conformant gateways running on legacy systems that

react to the EHLO query by closing down the connection rather than

giving a "500 command unrecognized" error. Smail handles this

situation like a normal link failure, so a message sent via SMTP to

such a mailer will presumably get bounced after the retry period is

over. If you care about interoperatibility with such weird systems,

you probably don't want to use the SMTP extensions, or write some code

for Smail to handle this situation more cleverly (see the TODO section

below). Personally I think that this is such an extreme case of

protocol incompatibility that I haven't taken the time to support

these mailer daemons.

When an ESMTP-capable client Smail talks to a non-ESMTP-capable SMTP

server, there are two additional query/reply pairs for each SMTP

connection. This is because Smail issues EHLO to find out whether the

recipient mailer handles ESMTP, gets an error message and then sends

an RSET before retrying with HELO. If you have extremely slow or

unreliable SMTP connections, or if your network connections are

charged by the packet this may matter to you.

TODO
----


Right now the SMTP extensions don't really give any new functionality,

except that max_message_size is *somewhat* enforced, but only for

cooperating (RFC 1427-savvy) client mailers. The following

improvements to the code might be useful:

* a SIZE clause should be used to dynamically determine whether the


incoming message will fit where it will be put next (one of the

spool directories). If this is the case, a temporary failure

message should be sent to the client SMTP to avoid sending a lot of

data in vain.

* Smail should be extended to handle 8-bit text messages in a more

standard way. Currently it is simply 8-bit transparent, which is

seen as a feature by most users. However, sending non-7-bit-ASCII

characters to remote mailer daemons is a violation of RFC 821 and

can lead to interoperability problems. Even when communicating over

8-bit clean SMTP networks, the "Just-Send-8" approach has the

problem that it is not clear which character set has been used by

the author [RFC1428].

In principle, all these problems are solved by the MIME standard

[RFC1341, RFC1342], which is rapidly gaining acceptance. In a world

where everybody uses MIME-capable mailers, there wouldn't be any

eighth bits to be transported. But as long as people still send

8-bit messages, Smail could convert such messages to 7bit-MIME when

they are transported over an SMTP network. RFC1428 describes how

this could be done.

* If the "link broken by EHLO" problem really does occur in the real

world, it has to be handled by Smail's SMTP client side. For

instance, once an EHLO command causes a link to be broken, the

receiving host should be noted in a "black list" by a mechanism

similar to the retry file mechanism. Hosts should be removed from

the black list periodically, so that when they are upgraded to

SMTP-conforming software, the new functionality will be used. It

would also be nice if the "retry" file could be extended by

something like "ehlo/noehlo" keyword that would allow specific

hosts/domains to be excluded from ESMTP trials.

* Some SMTP-based transports may want to use EHLO while others don't.


In batch SMTP, for example, the EHLO command probably doesn't make

much sense since the whole idea of "option negociation" doesn't fit

into the "batch" model. I don't know whether this should be

hardwired in the SMTP transport or made a configurable parameter of

transport entries.

ReFerenCes

1344 N. Borenstein, "Implications of MIME for Internet Mail Gateways",
06/11/1992. (Pages=9) (Format=.txt, .ps)

1425 J. Klensin, N. Freed, M. Rose, E. Stefferud, D. Crocker, "SMTP
Service Extensions", 02/10/1993. (Pages=10) (Format=.txt)

1426 J. Klensin, N. Freed, M. Rose, E. Stefferud, D. Crocker, "SMTP
Service Extension for 8bit-MIMEtransport", 02/10/1993. (Pages=6)
(Format=.txt)

1427 K. Moore, N. Freed, J. Klensin, "SMTP Service Extension for
Message Size Declaration", 02/10/1993. (Pages=8) (Format=.txt)

1428 G. Vaudreuil, "Transition of Internet Mail from Just-Send-8 to
8Bit-SMTP/MIME", 02/10/1993. (Pages=6) (Format=.txt)

1521 N. Borenstein, N. Freed, "MIME (Multipurpose Internet Mail
Extensions) Part One: Mechanisms for Specifying and Describing
the Format of Internet Message Bodies", 09/23/1993. (Pages=81)
(Format=.txt) (Obsoletes RFC1341)

1522 K. Moore, "MIME (Multipurpose Internet Mail Extensions) Part Two:
Message Header Extensions for Non-ASCII Text",
09/23/1993. (Pages=10) (Format=.txt) (Obsoletes RFC1342)

--- src/addr.c 1992/10/29 20:37:26 1.1


+++ src/addr.c 1992/10/29 22:11:04

@@ -63,6 +63,16 @@


char *address; /* address to be preparsed */

char **error; /* return error message here */

{
+ char * ignore;


+ return preparse_address_1(address, error, & ignore);

+}
+
+char *
+preparse_address_1(address, error, rest)
+ char *address;
+ char **error;
+ char **rest;
+{


register char *ap; /* temp for scanning address */

char *mark_start = NULL; /* marked position of < */

char *mark_end = NULL; /* marked position of > */

@@ -125,9 +135,10 @@


ap = xmalloc((unsigned)(strlen(address) + 1));

(void) strcpy(ap, address);
if (mark_end) {


- *mark_end = '>'; /* widden the original address */

+ *mark_end++ = '>'; /* widden the original address */
}

DEBUG1(DBG_ADDR_HI, "preparse_address returns: %s\n", ap);

+ *rest = mark_end;


return ap; /* no transformations */
}

@@ -144,9 +155,10 @@


ap = xmalloc((unsigned)(strlen(address) + 1));

(void) strcpy(ap, address);
if (mark_end) {


- *mark_end = '>'; /* widden the original address */

+ *mark_end++ = '>'; /* widden the original address */
}

DEBUG1(DBG_ADDR_HI, "preparse address returns: %s\n", ap);

+ *rest = mark_end;


return ap; /* address should be okay */
}

ap++;
@@ -157,7 +169,7 @@


/* first part already !-route */

(void) strncpy(p, address, ap-address);
if (mark_end) {


- *mark_end = '>'; /* widden the original address */

+ *mark_end++ = '>'; /* widden the original address */
}

ap = build_uucp_route(ap, error); /* build !-route */

if (ap == NULL) {
@@ -167,15 +179,17 @@


(void) strcat(p, ap); /* concatenate together */

xfree(ap);


DEBUG1(DBG_ADDR_HI, "preparse_address returns: %s\n", p);

+ *rest = mark_end;


return p; /* transformed */
}
}

ap = xmalloc((unsigned)(strlen(address) + 1));

(void) strcpy(ap, address);
if (mark_end) {


- *mark_end = '>'; /* widden the original address */

+ *mark_end++ = '>'; /* widden the original address */
}

DEBUG1(DBG_ADDR_HI, "preparse address returns: %s\n", ap);

+ *rest = mark_end;


return ap; /* no transformations */
}

--- src/extern.h 1992/10/29 20:40:42 1.1


+++ src/extern.h 1992/10/29 20:41:01

@@ -226,6 +226,7 @@
*/


/* external functions defined in addr.c */

extern char *preparse_address();
+extern char *preparse_address_1();
extern int parse_address();
extern char *address_token();
extern char *back_address_token();
--- src/smtprecv.c 1992/10/29 19:05:28 1.1
+++ src/smtprecv.c 1993/12/04 14:51:38
@@ -34,6 +34,7 @@


/* types local to this file */

enum e_smtp_commands {


HELO_CMD, /* HELO domain */

+ EHLO_CMD, /* EHLO domain */

MAIL_CMD, /* MAIL FROM:<sender> */

RCPT_CMD, /* RCPT TO:<recipient> */

DATA_CMD, /* DATA */
@@ -69,6 +70,7 @@


"250-The following SMTP commands are recognized:",

"250-",


"250- HELO hostname - startup and give your hostname",

+ "250- EHLO hostname - startup with extension info",

"250- MAIL FROM:<sender-address> - start transaction from sender",

"250- RCPT TO:<recipient-address> - name recipient for message",

"250- VRFY <address> - verify deliverability of address",

@@ -87,6 +89,15 @@


"250 Multiple messages may be specified. End the last one with a QUIT."

};

+typedef enum {
+ BF_unspecified,
+ BF_7bit,
+ BF_8bitmime
+}
+BodyFormat;
+
+#define BS_UNSPECIFIED -1L
+typedef long BodySize;


/*
@@ -121,6 +132,8 @@
FILE *save_errfile = errfile;
int save_debug = debug;
int temp, i;
+ char *rest;
+ int ehlo_p = 0;

/* initialize state */
initialize_state();
@@ -165,10 +178,34 @@
alarm(smtp_receive_command_timeout);
}
switch (read_smtp_command(in)) {
+ case EHLO_CMD:
+ ehlo_p = 1;
case HELO_CMD:
strip_rfc822_comments(data);


if (out && data[0] == '\0') {

- fprintf(out, "501 HELO requires domain name as operand\r\n");


+ fprintf(out, "501 %s requires domain name as operand\r\n",

+ ehlo_p ? "EHLO" : "HELO");

+ fflush(out);
+ break;
+ }


+ if (sender_host == NULL && data[0] != '\0') {

+ sender_host = COPY_STRING(data);
+ }
+ if (sender_proto == NULL) {


+ sender_proto = (out? ehlo_p? "esmtp": "smtp"

+ : ehlo_p? "ebsmtp": "bsmtp");
+ }
+ if (! ehlo_p) {
+ if (out) {


+ fprintf(out, "250 %s Hello %s\r\n", primary_name, data);

+ fflush(out);
+ }
+ reset_state();
+ break;
+ }
+ strip_rfc822_comments(data);
+ if (out && data[0] == '\0') {


+ fprintf(out, "501 EHLO requires domain name as operand\r\n");

fflush(out);
break;
}
@@ -179,7 +216,17 @@


sender_proto = (out? "smtp": "bsmtp");
}

if (out) {
- fprintf(out, "250 %s Hello %s\r\n", primary_name, data);


+ fprintf(out, "250-%s Hello %s, here's what we support:\r\n",

+ primary_name, data);


+ fprintf(out, "250-EXPN\r\n");

+ if (max_message_size)


+ fprintf(out, "250-SIZE %d\r\n", max_message_size);

+ else
+ fprintf(out, "250-SIZE\r\n");
+#ifdef HAVE_ESMTP_8BITMIME


+ fprintf(out, "250-8BITMIME\r\n");

+#endif


+ fprintf(out, "250 HELP\r\n");

fflush(out);
}
reset_state();
@@ -199,15 +246,13 @@
}
break;
}
- sender = preparse_address(data, &error);


+ sender = preparse_address_1(data, &error, &rest);

if (out) {
- if (sender) {


- fprintf(out, "250 <%s> ... Sender Okay\r\n",

- sender);
- } else {
+ if (!sender) {


fprintf(out, "501 <%s> ... %s\r\n", data, error);

+ fflush(out);
+ break;
}
- fflush(out);


}
if (sender && sender[0] == '\0') {

/* special error sender form <> given */

@@ -217,6 +262,127 @@


/* special smail-internal <+> was given */

sender = COPY_STRING("<+>");
}

+ {


+ char * format = 0;

+ int format_length = 0;
+ BodyFormat body_format = BF_unspecified;
+ BodySize body_size = BS_UNSPECIFIED;
+


+ while (rest && *rest != '\0') {

+ /* maybe we have an extended MAIL command */

+ while (*rest != '\0' && isspace (*rest)) {

+ ++rest;
+ }
+ {
+ int restlen = 0;
+ while (*(rest+restlen) != 0
+ && !isspace (*(rest+restlen))
+ && *(rest+restlen) != '=') {
+ ++restlen;
+ }


+ if (strncmpic(rest, "SIZE", restlen) == 0) {

+ rest += restlen;
+ if (*rest != '=') {
+ if (out) {
+ *(rest+restlen) = '\0';


+ fprintf(out, "555 missing SIZE parameter\r\n",

+ rest);
+ fflush(out);
+ }
+ goto fail_mail_cmd;
+ }
+ ++rest;
+ restlen = 0;
+ body_size = 0;
+ while (*(rest+restlen) != 0
+ && isdigit (*(rest+restlen))
+ && (!max_message_size || body_size <= max_message_size)) {
+ body_size = 10*body_size+*(rest+restlen)-'0';
+ ++restlen;
+ }
+ if (max_message_size && body_size > max_message_size) {
+ if (out) {


+ fprintf(out, "552 message too large\r\n");

+ fflush(out);
+ }
+ goto fail_mail_cmd;


+ } else if (*(rest+restlen) != 0

+ && !isspace (*(rest+restlen))) {
+ if (out) {
+ while (*(rest+restlen) != 0
+ && !isspace (*(rest+restlen))) {
+ ++restlen;
+ }
+ *(rest+restlen) = '\0';


+ fprintf(out, "555 malformed SIZE clause %s\r\n",

+ rest);
+ fflush(out);
+ }
+ goto fail_mail_cmd;
+ }
+ } else
+#ifdef HAVE_ESMTP_8BITMIME


+ if (strncmpic(rest, "BODY", restlen) == 0) {

+ rest += restlen;
+ if (*rest != '=') {
+ if (out) {
+ *(rest+restlen) = '\0';


+ fprintf(out, "555 missing BODY parameter\r\n",

+ rest);
+ fflush(out);
+ }
+ goto fail_mail_cmd;
+ }
+ ++rest;
+ restlen = 0;
+ while (*(rest+restlen) != 0
+ && !isspace (*(rest+restlen))) {
+ ++restlen;
+ }


+ if (strncmpic(rest, "7BIT", restlen) == 0) {

+ body_format = BF_7bit;


+ } else if (strncmpic(rest, "8BITMIME", restlen) == 0) {

+ body_format = BF_8bitmime;
+ } else {
+ if (out) {
+ *(rest+restlen) = '\0';


+ fprintf(out, "555 unknown BODY type %s\r\n",

+ rest);
+ fflush(out);
+ }
+ goto fail_mail_cmd;
+ }
+ } else
+#endif
+ {
+ if (out) {
+ *(rest+restlen) = '\0';


+ fprintf(out, "555 Unknown MAIL TO: option %s\r\n", rest);

+ fflush(out);
+ }
+ goto fail_mail_cmd;
+ }
+ rest += restlen;
+ }
+ }
+ if (out) {


+ if (format && *format != '\0') {

+ *(format+format_length) = '\0';


+ fprintf(out, "250 <%s> ... Sender Okay, using format %s\r\n",

+ sender, format);
+ } else {
+ fprintf(out, "250 <%s> ... Sender Okay\r\n",
+ sender);
+ }
+ fflush(out);
+ }
+ }
+ break;
+ fail_mail_cmd:
+ if (sender) {
+ xfree(sender);
+ sender = NULL;
+ }
break;

case RCPT_CMD:
@@ -514,6 +680,7 @@
enum e_smtp_commands cmd;
} smtp_cmd_list[] = {


"HELO", sizeof("HELO")-1, HELO_CMD,

+ "EHLO", sizeof("EHLO")-1, EHLO_CMD,

"MAIL FROM:", sizeof("MAIL FROM:")-1, MAIL_CMD,

"RCPT TO:", sizeof("RCPT TO:")-1, RCPT_CMD,

"DATA", sizeof("DATA")-1, DATA_CMD,

--- src/transports/smtplib.c 1993/04/01 14:00:03 1.1
+++ src/transports/smtplib.c 1993/12/03 17:17:20
@@ -30,6 +30,9 @@
# include "../error.h"
# include "../debug.h"
#endif
+#if !defined(NO_LOG_EHLO)
+# include "../log.h"
+#endif

#ifdef ANSI_C
# define P_(x) x
@@ -40,6 +43,7 @@
#endif



/* supported SMTP commands */

+#define EHLO(domain) "EHLO %s", domain

#define HELO(domain) "HELO %s", domain

#define MAIL_BEGIN "MAIL FROM:<"
#define MAIL_END ">"
@@ -69,6 +73,8 @@
/* pseudo-reply codes */
#define REPLY_PROTO_ERROR 0x498 /* protocol error on read */
#define REPLY_TIMEOUT 0x499 /* timeout on read, or EOF on read */
+#define REPLY_NOT_ACCEPTABLE 0x501 /* request not acceptable */
+#define REPLY_SEQUENCE_ERROR 0x503 /* Bad sequence of commands */

/* variables local to this file */
static struct str smtp_out; /* region for outgoing commands */
@@ -111,6 +117,9 @@
{
int reply;
char *reply_text;
+#ifdef HAVE_EHLO
+ int tried_rset = 0;
+#endif

if (! smtp_init_flag) {
STR_INIT(&smtp_in);
@@ -134,6 +143,99 @@
return SMTP_AGAIN;
}

+#ifdef HAVE_EHLO
+ /*
+ * say who we are.
+ * Possible responses:
+ * 250 - okay (continue conversation)
+ * 421 - closing down (try again later)


+ * 5xx - fatal error (try HELO)

+ */
+ smtp_out.i = 0;
+ (void) str_printf(&smtp_out, EHLO(primary_name));
+


+ reply = wait_write_command(smtpb, smtpb->short_timeout,

+ smtp_out.p, smtp_out.i, &reply_text);
+
+ if (REPLY_GROUP(reply) == NEGATIVE_TRY_AGAIN) {


+ /* remote SMTP closed, try again later */

+ *error_p = try_again(smtpb->tp, reply_text);

+ return SMTP_AGAIN;
+ }
+ if (reply == REPLY_OK) {


+ char * cp = reply_text;

+ int on_greet_line = 1;
+
+ smtpb->smtp_flags = ESMTP_basic;


+ /* Parse the EHLO reply to find out

+ what the remote server supports */

+ while (*cp != 0) {
+ int skip;
+ int keywordlength;
+


+ for (skip = 4; *cp != 0 && skip; --skip, ++cp) {

+ if (skip == 1


+ ? (*cp != ' ' && *cp != '-')

+ : (! isdigit (*cp))) {
+ goto malformed_ehlo_reply;
+ }
+ }
+ if (skip != 0) {
+ goto malformed_ehlo_reply;
+ }
+ if (on_greet_line) {
+ /*


+ * Ignore greeting on first line

+ */
+ on_greet_line = 0;
+ goto skip_rest_of_line;
+ }
+ for (keywordlength = 0;
+ *(cp+keywordlength) != 0
+ && !isspace (*(cp+keywordlength));
+ ++keywordlength)
+ ;


+ if (strncmpic(cp, "SIZE", keywordlength) == 0) {

+ unsigned long max_message_size = 0;

+
+ cp += keywordlength;


+ while (*cp == ' ' || *cp == '\t')

+ ++cp;
+ if (!isdigit(*cp) && *cp != '\n')
+ goto malformed_ehlo_reply;
+ while (isdigit(*cp)) {
+ max_message_size *= 10;


+ max_message_size += *cp - '0';

+ ++cp;
+ }
+ smtpb->smtp_flags |= ESMTP_size;
+ smtpb->max_message_size = max_message_size;


+ } else if (strncmpic(cp, "8BITMIME", keywordlength) == 0) {

+ smtpb->smtp_flags |= ESMTP_8bitmime;
+ } else {
+ }
+ skip_rest_of_line:


+ while (*cp != 0 && *cp != '\n')

+ ++cp;


+ if (*cp == '\n')

+ ++cp;
+ }
+#ifndef NO_LOG_EHLO
+ write_log(LOG_SYS, "destination supports esmtp%s%s",
+ smtpb->smtp_flags & ESMTP_8bitmime ? " 8BITMIME" : "",
+ smtpb->smtp_flags & ESMTP_size ? " SIZE" : "");
+#endif /* not NO_LOG_EHLO */
+ return SMTP_SUCCEED;
+ malformed_ehlo_reply:


+ /* This seems to be a reasonable way

+ to handle malformed EHLO replies: */

+#ifndef NO_LOG_EHLO
+ write_log(LOG_SYS, "destination supports esmtp, but is buggy (%s)",
+ reply_text);
+#endif /* not NO_LOG_EHLO */
+ return SMTP_SUCCEED;
+ }
+#endif
/*


* say who we are.

* Possible responses:
@@ -141,6 +243,9 @@


* 421 - closing down (try again later)

* 5xx - fatal error (return message to sender)

*/
+#ifdef HAVE_EHLO
+ try_helo:
+#endif
smtp_out.i = 0;
(void) str_printf(&smtp_out, HELO(primary_name));

@@ -152,12 +257,48 @@


*error_p = try_again(smtpb->tp, reply_text);

return SMTP_AGAIN;
}
- if (reply != REPLY_OK) {
- /* fatal error, return message to sender */
- *error_p = fatal_error(smtpb->tp, reply_text);
- return SMTP_FAIL;
+ if (reply == REPLY_SEQUENCE_ERROR) {
+ /* ignore 503 Bad sequence of commands after EHLO/RSET/HELO */
+#ifndef NO_LOG_EHLO
+ write_log(LOG_SYS, "503 after EHLO/RSET/HELO (%s)",
+ reply_text);
+#endif /* not NO_LOG_EHLO */


+ } else if (reply != REPLY_OK) {

+#ifdef HAVE_EHLO
+ if (! tried_rset) {
+ /* The following */


+ /* fatal error, probably doesn't understand EHLO */

+ smtp_out.i = 0;
+ (void) str_printf(&smtp_out, "RSET");
+


+ reply = wait_write_command(smtpb, smtpb->short_timeout,

+ smtp_out.p, smtp_out.i, &reply_text);
+ if (REPLY_GROUP(reply) == NEGATIVE_TRY_AGAIN) {


+ /* remote SMTP closed, try again later */

+ *error_p = try_again(smtpb->tp, reply_text);

+ return SMTP_AGAIN;
+ } else if (reply == REPLY_OK) {
+ } else {
+ /* Some gateways don't accept any commands before they get
+ a HELO, not even RSET. Fortunately it is usually safe
+ to ignore the error messages. */
+#ifndef NO_LOG_EHLO
+ write_log(LOG_SYS, "unexpected response to RSET (%s)",
+ reply_text);
+#endif /* not NO_LOG_EHLO */
+ }


+ /* the RSET command has been accepted; try again with HELO */

+ tried_rset = 1;
+ goto try_helo; /* GASP!!! */
+ } else {
+#endif HAVE_EHLO
+ /* fatal error, return message to sender */
+ *error_p = fatal_error(smtpb->tp, reply_text);
+ return SMTP_FAIL;
+#ifdef HAVE_EHLO
+ }
+#endif
}
-
/* connection established */
return SMTP_SUCCEED;
}
@@ -217,6 +358,28 @@


(error_sender? ((islocal && tp->flags & LOCAL_XFORM)? "+": ""):

get_sender_addr(tp)),
MAIL_END);
+
+ /*


+ * send (a guess of) the size of the message to be transported.

+ * Of course the guess could be a bit more educated, but usually

+ * it doesn't matter if it is slightly incorrect. We simply add

+ * 2% in order to account for \n -> \r\n conversion.

+ */


+ if (smtpb->smtp_flags & ESMTP_size) {

+ str_printf(&smtp_out, " SIZE=%lu",


+ (unsigned long) (msg_size * 1.02));

+ }
+#if 0
+ /*


+ * This is commented out because we are not supposed to send a

+ * non-MIME message on 8BITMIME mode. But sending a non-7bit

+ * clean message in 7BIT mode isn't a good idea either. Sigh.

+ * Something more sophisticated is definitely needed here.

+ */


+ if (smtpb->smtp_flags & ESMTP_8bitmime) {

+ str_printf(&smtp_out, " BODY 8BITMIME");
+ }
+#endif



reply = wait_write_command(smtpb, smtpb->long_timeout,

smtp_out.p, smtp_out.i, &reply_text);
--- src/transports/smtplib.h 1993/04/02 10:42:48 1.1
+++ src/transports/smtplib.h 1993/11/30 18:25:09
@@ -18,6 +18,15 @@
#define SMTP_FAIL (-1)
#define SMTP_AGAIN (-2)

+typedef enum
+{
+ ESMTP_none = 0x0000,
+ ESMTP_basic = 0x0001,
+ ESMTP_8bitmime = 0x0002,
+ ESMTP_size = 0x0004,
+}
+SMTPExtension, SMTPExtensionFlags;
+
/*


* the following structure is passed around between SMTP functions and

* should be initialized as necessary to describe the SMTP connection

@@ -32,6 +41,8 @@


unsigned long_timeout; /* normal SMTP read timeout period */

char *nl; /* line terminator string */

struct transport *tp; /* associated transport */

+ SMTPExtensionFlags smtp_flags; /* SMTP extensions supported by remote */

+ unsigned long max_message_size; /* message size limit of remote */

};



/* functions defined in smtplib.c */

--- src/transports/tcpsmtp.c 1993/04/02 10:49:54 1.1
+++ src/transports/tcpsmtp.c 1993/11/30 18:25:26
@@ -318,7 +318,8 @@
smtpbuf.nl = "\r\n";
tp->flags |= PUT_CRLF;
smtpbuf.tp = tp;
-
+ smtpbuf.smtp_flags = ESMTP_none;
+ smtpbuf.max_message_size = 0;
DEBUG(DBG_DRIVER_LO, "connected\n");

switch (smtp_startup(&smtpbuf, ep)) {

0 new messages