--- src/smtprecv.c 1994/11/30 08:44:04 1.2 +++ src/smtprecv.c 1994/11/30 15:10:34 1.3 @@ -1,4 +1,4 @@ -/* @(#) $Id: smtprecv.c,v 1.2 1994/11/30 08:44:04 logiciel Exp $ */ +/* @(#) $Id: smtprecv.c,v 1.3 1994/11/30 15:10:34 logiciel Exp $ */ /* * Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll @@ -279,7 +279,9 @@ if (out) { fprintf(out, "250-%s Hello %s, here's what we support:\r\n", primary_name, data); +#ifndef NO_VERIFY fprintf(out, "250-EXPN\r\n"); +#endif #ifdef HAVE_DF_SPOOL accepted_msg_size = compute_max_message_size_from_df_spool (); if (accepted_msg_size == -1 --- src/transports/smtplib.c 1994/11/30 08:58:18 1.2 +++ src/transports/smtplib.c 1994/12/13 11:39:28 1.5 @@ -1,4 +1,4 @@ -/* @(#) $Id: smtplib.c,v 1.2 1994/11/30 08:58:18 logiciel Exp $ */ +/* @(#) $Id: smtplib.c,v 1.5 1994/12/13 11:39:28 logiciel Exp $ */ /* * Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll @@ -52,8 +52,10 @@ #define DATA "DATA" #define DATA_END "." #define QUIT "QUIT" +#define VERB "VERB" /* reply code groups, encoded in hex */ +#define POSITIVE_DEBUG 0x000 /* debugging messages */ #define POSITIVE_PRELIM 0x100 /* positive preliminary replies */ #define POSITIVE_COMPLETE 0x200 /* positive completion replies */ #define POSITIVE_INTERMEDIATE 0x300 /* positive intermediate replies */ @@ -84,7 +86,7 @@ /* functions local to this file */ #ifdef __STDC__ -extern int smtp_startup(struct smtp *, struct error **); +extern int smtp_startup(struct smtp *, struct error **, int); extern int smtp_send(struct smtp *, struct addr *, struct addr **, struct addr **, struct addr **, struct error **); extern void smtp_shutdown(struct smtp *); static void do_smtp_shutdown(struct smtp *, int); @@ -130,17 +132,25 @@ * the session for future mail commands. Once the startup has been * acomplished, smtp_send() can be used to send individual messages. * + * If try_ehlo is non-zero and ESMTP support is configured, perform + * ESMTP negotiaition using the EHLO greeting command. + * * return: * SMTP_SUCCEED on successful startup * SMTP_FAIL if the connection should not be retried * SMTP_AGAIN if the connection should be retried later + * SMTP_EHLO_FAIL if the receiver hung up in response + * to an EHLO command. This can only occur when + * try_ehlo is set. * - * For SMTP_FAIL and SMTP_AGAIN, return a filled-in error structure. + * For SMTP_FAIL and SMTP_AGAIN (but not SMTP_EHLO_FAIL), return a + * filled-in error structure. */ int -smtp_startup(smtpb, error_p) +smtp_startup(smtpb, error_p, try_ehlo) struct smtp *smtpb; /* SMTP description block */ struct error **error_p; /* error description */ + int try_ehlo; /* whether to use ESMTP */ { int reply; char *reply_text; @@ -171,101 +181,133 @@ } #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)); + if (try_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); + 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))) { + if (reply == REPLY_TIMEOUT) { + /* Some gateways just terminate the conection when they + receive an EHLO. We handle this case by returning a + special value here. Also write a message to the log + file because it is interesting to know which mailers + expose this problem. */ + write_log(LOG_SYS, "link broken by EHLO!"); + return SMTP_EHLO_FAIL; + } + 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 (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_size = 0; - - cp += keywordlength; - while (*cp == ' ' || *cp == '\t') - ++cp; - if (!isdigit(*cp) && *cp != '\n') - goto malformed_ehlo_reply; - while (isdigit(*cp)) { - max_size *= 10; - max_size += *cp - '0'; - ++cp; + if (on_greet_line) { + /* + * Ignore greeting on first line + */ + on_greet_line = 0; + goto skip_rest_of_line; } - smtpb->smtp_flags |= ESMTP_size; - smtpb->max_size = max_size; - } else if (strncmpic(cp, "8BITMIME", keywordlength) == 0) { - smtpb->smtp_flags |= ESMTP_8bitmime; - } else if (strncmpic(cp, "PIPELINING", keywordlength) == 0) { - smtpb->smtp_flags |= ESMTP_pipelining; - } else { + for (keywordlength = 0; + *(cp+keywordlength) != 0 + && !isspace (*(cp+keywordlength)); + ++keywordlength) + ; + if (strncmpic(cp, "SIZE", keywordlength) == 0) { + unsigned long max_size = 0; + + cp += keywordlength; + while (*cp == ' ' || *cp == '\t') + ++cp; + if (!isdigit(*cp) && *cp != '\n') + goto malformed_ehlo_reply; + while (isdigit(*cp)) { + max_size *= 10; + max_size += *cp - '0'; + ++cp; + } + smtpb->smtp_flags |= ESMTP_size; + smtpb->max_size = max_size; + } else if (strncmpic(cp, "8BITMIME", keywordlength) == 0) { + smtpb->smtp_flags |= ESMTP_8bitmime; + } else if (strncmpic(cp, "PIPELINING", keywordlength) == 0) { + smtpb->smtp_flags |= ESMTP_pipelining; + } else if (strncmpic(cp, "XVRB", keywordlength) == 0) { + smtpb->smtp_flags |= ESMTP_verbose; + } else if (strncmpic(cp, "XONE", keywordlength) == 0) { + smtpb->smtp_flags |= ESMTP_one; + } else if (strncmpic(cp, "XQUE", keywordlength) == 0) { + smtpb->smtp_flags |= ESMTP_queue; + } else { + } + skip_rest_of_line: + while (*cp != 0 && *cp != '\n') + ++cp; + if (*cp == '\n') + ++cp; } - 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%s", - smtpb->smtp_flags & ESMTP_8bitmime ? " 8BITMIME" : "", - smtpb->smtp_flags & ESMTP_size ? " SIZE" : "", - smtpb->smtp_flags & ESMTP_pipelining ? " PIPELINING" : ""); + write_log(LOG_SYS, "destination supports esmtp%s%s%s%s%s%s", + smtpb->smtp_flags & ESMTP_8bitmime ? " 8BITMIME" : "", + smtpb->smtp_flags & ESMTP_size ? " SIZE" : "", + smtpb->smtp_flags & ESMTP_pipelining ? " PIPELINING" : "", + smtpb->smtp_flags & ESMTP_verbose ? " XVRB" : "", + smtpb->smtp_flags & ESMTP_one ? " XONE" : "", + smtpb->smtp_flags & ESMTP_queue ? " XQUE" : ""); #endif /* not NO_LOG_EHLO */ - return SMTP_SUCCEED; - malformed_ehlo_reply: - /* This seems to be a reasonable way - to handle malformed EHLO replies: */ + if (smtpb->smtp_flags & ESMTP_verbose + && debug >= DBG_DRIVER_MID) { + smtp_out.i = 0; + (void) str_printf(&smtp_out, VERB); + 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; + } + } + 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); + write_log(LOG_SYS, "destination supports esmtp, but is buggy (%s)", + reply_text); #endif /* not NO_LOG_EHLO */ - return SMTP_SUCCEED; + return SMTP_SUCCEED; + } } -#endif +#endif /* HAVE_EHLO */ /* * say who we are. * Possible responses: @@ -755,8 +797,12 @@ if (! smtpb->in) { return REPLY_OK; } - result = read_response_internal (smtpb, timeout, reply_text); - DEBUG1(DBG_DRIVER_MID, "SMTP-reply: %s\n", *reply_text); + do + { + result = read_response_internal (smtpb, timeout, reply_text); + DEBUG1(DBG_DRIVER_MID, "SMTP-reply: %s\n", *reply_text); + } + while (REPLY_GROUP (result) == POSITIVE_DEBUG); return result; } --- src/transports/smtplib.h 1994/11/30 08:59:35 1.2 +++ src/transports/smtplib.h 1994/12/13 10:59:53 1.4 @@ -1,4 +1,4 @@ -/* @(#) $Id: smtplib.h,v 1.2 1994/11/30 08:59:35 logiciel Exp $ */ +/* @(#) $Id: smtplib.h,v 1.4 1994/12/13 10:59:53 logiciel Exp $ */ /* * Copyright (C) 1987, 1988 by Ronald S. Karr and Landon Curt Noll @@ -17,6 +17,7 @@ #define SMTP_SUCCEED 0 #define SMTP_FAIL (-1) #define SMTP_AGAIN (-2) +#define SMTP_EHLO_FAIL (-3) typedef enum { @@ -24,7 +25,10 @@ ESMTP_basic = 0x0001, ESMTP_8bitmime = 0x0002, ESMTP_size = 0x0004, - ESMTP_pipelining = 0x0008 + ESMTP_pipelining = 0x0008, + ESMTP_verbose = 0x0010, + ESMTP_one = 0x0020, + ESMTP_queue = 0x0040 } SMTPExtension, SMTPExtensionFlags; --- src/transports/tcpsmtp.c 1994/11/30 09:04:54 1.2 +++ src/transports/tcpsmtp.c 1994/12/13 11:41:04 1.3 @@ -288,6 +288,7 @@ char *error_text; int success; struct addr *ap; + int try_ehlo; priv = (struct tcpsmtp_private *)tp->private; @@ -310,43 +311,53 @@ /* reach out and touch someone */ - s = tcpsmtp_connect(hostname, ipaddr, family, service, &error_text); - if (s >= 0) { - s2 = dup(s); - if (s2 < 0) { - (void) close(s); - s = -1; - } - } - if (s < 0) { - *ep = connect_failure(tp, error_text); - return SMTP_AGAIN; - } - - smtpbuf.in = fdopen(s, "r"); - smtpbuf.out = fdopen(s2, "w"); - smtpbuf.short_timeout = priv->short_timeout; - smtpbuf.long_timeout = priv->long_timeout; - smtpbuf.nl = "\r\n"; - tp->flags |= PUT_CRLF; - smtpbuf.tp = tp; - smtpbuf.smtp_flags = ESMTP_none; - smtpbuf.max_size = 0; - - DEBUG(DBG_DRIVER_LO, "connected\n"); - - switch (smtp_startup(&smtpbuf, ep)) { - - case SMTP_FAIL: - insert_addr_list(addr, fail, *ep); - (void) fclose(smtpbuf.in); - (void) fclose(smtpbuf.out); - return SMTP_FAIL; - - case SMTP_AGAIN: - (void) fclose(smtpbuf.in); - (void) fclose(smtpbuf.out); - return SMTP_AGAIN; + for (try_ehlo = 1, success = 0; !success && try_ehlo >= 0; --try_ehlo) { + s = tcpsmtp_connect(hostname, ipaddr, family, service, &error_text); + if (s >= 0) { + s2 = dup(s); + if (s2 < 0) { + (void) close(s); + s = -1; + } + } + if (s < 0) { + *ep = connect_failure(tp, error_text); + return SMTP_AGAIN; + } + + smtpbuf.in = fdopen(s, "r"); + smtpbuf.out = fdopen(s2, "w"); + smtpbuf.short_timeout = priv->short_timeout; + smtpbuf.long_timeout = priv->long_timeout; + smtpbuf.nl = "\r\n"; + tp->flags |= PUT_CRLF; + smtpbuf.tp = tp; + smtpbuf.smtp_flags = ESMTP_none; + smtpbuf.max_size = 0; + + DEBUG(DBG_DRIVER_LO, "connected\n"); + + switch (smtp_startup(&smtpbuf, ep, try_ehlo)) { + + case SMTP_FAIL: + insert_addr_list(addr, fail, *ep); + (void) fclose(smtpbuf.in); + (void) fclose(smtpbuf.out); + return SMTP_FAIL; + + case SMTP_AGAIN: + (void) fclose(smtpbuf.in); + (void) fclose(smtpbuf.out); + return SMTP_AGAIN; + + case SMTP_EHLO_FAIL: + (void) fclose(smtpbuf.in); + (void) fclose(smtpbuf.out); + break; + + default: + success = 1; + } } if (dont_deliver) {