1N/A * Copyright (c) 1998-2006, 2008-2010 Sendmail, Inc. and its suppliers. 1N/A * All rights reserved. 1N/A * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 1N/A * Copyright (c) 1988, 1993 1N/A * The Regents of the University of California. All rights reserved. 1N/A * By using this file, you agree to the terms and conditions set 1N/A * forth in the LICENSE file which can be found at the top level of 1N/A * the sendmail distribution. 1N/A** USERSMTP -- run SMTP protocol from the user end. 1N/A** This protocol is described in RFC821. 1N/A** SMTPINIT -- initialize SMTP. 1N/A** Opens the connection and sends the initial protocol. 1N/A** m -- mailer to create connection to. 1N/A** mci -- the mailer connection info. 1N/A** e -- the envelope. 1N/A** onlyhelo -- send only helo command? 1N/A** creates connection and sends initial protocol. 1N/A ** Open the connection to the mailer. 1N/A /* need to clear old information */ 1N/A /* shouldn't happen */ 1N/A ** Get the greeting message. 1N/A ** This should appear spontaneously. Give it five minutes to 1N/A ** Send the HELO command. 1N/A ** My mother taught me to always introduce myself. 1N/A#
endif /* _FFR_IGNORE_EXT_ON_HELO */ 1N/A#
endif /* _FFR_IGNORE_EXT_ON_HELO */ 1N/A /* try old SMTP instead */ 1N/A ** Check to see if we actually ended up talking to ourself. 1N/A ** This means we didn't know about an alias or MX, or we managed 1N/A ** to connect to an echo server. 1N/A syserr(
"553 5.3.5 %s config error: mail loops back to me (MX problem?)",
1N/A "553 5.3.5 system config error");
1N/A ** If this is expected to be another sendmail, send some internal 1N/A ** If we're running as MSP, "propagate" -v flag if possible. 1N/A#
endif /* !_FFR_DEPRECATE_MAILER_FLAG_I */ 1N/A /* tell it to be verbose */ 1N/A /* got a 421 error code during startup */ 1N/A /* XXX should use code from other end iff ENHANCEDSTATUSCODES */ 1N/A** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol 1N/A** line -- the response line. 1N/A** firstline -- set if this is the first line of the reply. 1N/A** mci -- the mailer connection info. 1N/A** e -- the envelope. 1N/A ** Dirty hack below. Quoting the author: 1N/A ** This was a response to people who wanted SMTP transmission to be 1N/A ** just-send-8 by default. Essentially, you could put this tag into 1N/A ** your greeting message to behave as though the F=8 flag was set on 1N/A/* specify prototype so compiler can check calls */ 1N/A** STR_UNION -- create the union of two lists 1N/A** s1, s2 -- lists of items (separated by single blanks). 1N/A** rpool -- resource pool from which result is allocated. 1N/A** the union of both lists. 1N/A "str_union: stringlen1=%d, stringlen2=%d, sum=%d, status=overflow",
1N/A /* walk through s2 */ 1N/A /* is there something after the current word? */ 1N/A /* does the current word appear in s1 ? */ 1N/A /* add space as delimiter */ 1N/A /* advance pointer in result list */ 1N/A /* there are more items */ 1N/A** HELO_OPTIONS -- process the options on a HELO line. 1N/A** line -- the response line. 1N/A** firstline -- set if this is the first line of the reply. 1N/A** mci -- the mailer connection info. 1N/A** e -- the envelope (unused). 1N/A#
endif /* _FFR_IGNORE_EXT_ON_HELO */ 1N/A#
endif /* _FFR_IGNORE_EXT_ON_HELO */ 1N/A "server=%s [%s] returned extensions despite HELO command",
1N/A#
endif /* _FFR_IGNORE_EXT_ON_HELO */ 1N/A#
endif /* STARTTLS */ 1N/A ** Create the union with previous auth 1N/A ** offerings because we recognize "auth " 1N/A ** and "auth=" (old format). 1N/A** INIT_SASL_CLIENT -- initialize client side of Cyrus-SASL 1N/A** SASL_OK -- if successful. 1N/A** SASL error code -- otherwise. 1N/A** Callbacks are ignored if sasl_client_init() has 1N/A** been called before (by a library such as libnss_ldap) 1N/A /* should we retry later again or just remember that it failed? */ 1N/A** STOP_SASL_CLIENT -- shutdown client side of Cyrus-SASL 1N/A** GETSASLDATA -- process the challenges from the SASL protocol 1N/A** This gets the relevant sasl response data out of the reply 1N/A** line -- the response line. 1N/A** firstline -- set if this is the first line of the reply. 1N/A** mci -- the mailer connection info. 1N/A** e -- the envelope (unused). 1N/A#
endif /* SASL < 20000 */ 1N/A /* if not a continue we don't care about it */ 1N/A /* forget about "334 " */ 1N/A#
else /* SASL >= 20000 */ 1N/A ** mci_sasl_string is "shared" with Cyrus-SASL library; hence 1N/A ** it can't be in an rpool unless we use the same memory 1N/A ** management mechanism (with same rpool!) for Cyrus SASL. 1N/A#
endif /* SASL >= 20000 */ 1N/A** READAUTH -- read auth values from a file 1N/A** filename -- name of file to read. 1N/A** safe -- if set, this is a safe read. 1N/A** sai -- where to store auth_info. 1N/A** rpool -- resource pool for sai. 1N/A** EX_OK -- data succesfully read. 1N/A** EX_UNAVAILABLE -- no valid filename. 1N/A** EX_TEMPFAIL -- temporary failure. 1N/A "authentication id",
1N/A ** make sure we don't use a program that is not 1N/A ** accesible to the user who specified a different authinfo file. 1N/A ** However, currently we don't pass this info (authinfo file 1N/A ** specified by user) around, so we just turn off program access. 1N/A#
endif /* !_FFR_ALLOW_SASLINFO */ 1N/A#
endif /* _FFR_GROUPREADABLEAUTHINFOFILE */ 1N/A ** XXX: make sure we don't read or open files that are not 1N/A ** accesible to the user who specified a different authinfo 1N/A#
else /* _FFR_ALLOW_SASLINFO */ 1N/A#
endif /* _FFR_ALLOW_SASLINFO */ 1N/A "AUTH=client, error: can't open %s: %s",
1N/A "AUTH=client, error: can't read %s from %s",
1N/A** GETAUTH -- get authinfo from ruleset call 1N/A** {server_name}, {server_addr} must be set 1N/A** mci -- the mailer connection structure. 1N/A** e -- the envelope (including the sender to specify). 1N/A** sai -- pointer to authinfo (result). 1N/A** EX_OK -- ruleset was succesfully called, data may not 1N/A** be available, sai must be checked. 1N/A** EX_UNAVAILABLE -- ruleset unavailable (or failed). 1N/A** EX_TEMPFAIL -- temporary failure (from ruleset). 1N/A** Fills in sai if successful. 1N/A /* other than expected return value: ok (i.e., no auth) */ 1N/A ** parse the data, put it into sai 1N/A ** format: "TDstring" (including the '"' !) 1N/A ** where T is a tag: 'U', ... 1N/A ** D is a delimiter: ':' or '=' 1N/A if (l <=
3 ||
pvp[i +
1][l -
1] !=
'"')
1N/A /* remove closing quote */ 1N/A /* remove "TD and " */ 1N/A /* ':text' (just copy) */ 1N/A else if (
pvp[i +
1][
2] ==
'=')
1N/A /* '=base64' (decode) */ 1N/A#
else /* SASL >= 20000 */ 1N/A#
endif /* SASL >= 20000 */ 1N/A /* did we get the expected data? */ 1N/A /* XXX: EXTERNAL mechanism only requires (and only uses) SASL_USER */ 1N/A /* no authid? copy uid */ 1N/A /* no uid? copy authid */ 1N/A "AUTH=client, relay=%.64s [%.16s], authinfo %sfailed",
1N/A** GETSIMPLE -- callback to get userid or authid 1N/A** result -- (pointer to) result 1N/A** len -- (pointer to) length of result 1N/A** GETSECRET -- callback to get password 1N/A** conn -- connection information 1N/A** psecret -- (pointer to) result 1N/A ** use an rpool because we are responsible for free()ing the secret, 1N/A ** but we can't free() it until after the auth completes 1N/A#
else /* SASL >= 20000 */ 1N/A** GETSIMPLE -- callback to get userid or authid 1N/A** result -- (pointer to) result 1N/A** len -- (pointer to) length of result 1N/A#
endif /* SASL > 10509 */ 1N/A ** Unfortunately it is not clear whether this routine should 1N/A ** return a copy of a string or just a pointer to a string. 1N/A ** The Cyrus-SASL plugins treat these return values differently, e.g., 1N/A ** The best solution to this problem is to fix Cyrus-SASL, but it 1N/A ** seems there is nobody who creates patches... Hello CMU!? 1N/A ** The second best solution is to have flags that tell this routine 1N/A ** whether to return an malloc()ed copy. 1N/A ** The next best solution is to always return an malloc()ed copy, 1N/A ** and suffer from some memory leak, which is ugly for persistent 1N/A ** For now we go with the last solution... 1N/A ** We can't use rpools (which would avoid this particular problem) 1N/A /* XXX maybe other mechanisms too?! */ 1N/A ** Add realm to authentication id unless authid contains 1N/A ** '@' (i.e., a realm) or the default realm is empty. 1N/A /* has this been done before? */ 1N/A /* do not add an empty realm */ 1N/A /* should use rpool, but from where? */ 1N/A#
endif /* SASL > 10509 */ 1N/A** GETSECRET -- callback to get password 1N/A** conn -- connection information 1N/A** psecret -- (pointer to) result 1N/A#
endif /* SASL >= 20000 */ 1N/A** SAFESASLFILE -- callback for sasl: is file safe? 1N/A** context -- pointer to context between invocations (unused) 1N/A** file -- name of file to check 1N/A** type -- type of file to check 1N/A** SASL_OK -- file can be used 1N/A** SASL_CONTINUE -- don't use file 1N/A** SASL_FAIL -- failure (not used here) 1N/A#
else /* SASL > 10515 */ 1N/A#
endif /* SASL > 10515 */ 1N/A#
else /* SASL >= 20000 */ 1N/A#
endif /* SASL >= 20000 */ 1N/A#
else /* SASL >= 20000 */ 1N/A#
endif /* SASL >= 20000 */ 1N/A#
endif /* SASL > 10515 */ 1N/A#
endif /* SASL <= 10515 */ 1N/A /* everything beside libs and .conf files must not be readable */ 1N/A#
else /* SASL <= 10515 */ 1N/A /* files containing passwords should be not readable */ 1N/A#
endif /* SASL <= 10515 */ 1N/A** SASLGETREALM -- return the realm for SASL 1N/A** return the realm for the client 1N/A** context -- context shared between invocations 1N/A** availrealms -- list of available realms 1N/A** {realm, realm, ...} 1N/A** result -- pointer to result 1N/A "AUTH=client, realm=%s, available realms=%s",
1N/A /* check whether context is in list */ 1N/A "AUTH=client, realm=%s not in list=%s",
1N/A** ITEMINLIST -- does item appear in list? 1N/A** Check whether item appears in list (which must be separated by a 1N/A** character in delim) as a "word", i.e. it must appear at the begin 1N/A** of the list or after a space, and it must end with a space or the 1N/A** item -- item to search. 1N/A** list -- list of items. 1N/A** delim -- list of delimiters. 1N/A** pointer to occurrence (NULL if not found). 1N/A** REMOVEMECH -- remove item [rem] from list [list] 1N/A** rem -- item to remove 1N/A** list -- list of items 1N/A** rpool -- resource pool from which result is allocated. 1N/A** pointer to new list (NULL in case of error). 1N/A /* take out what? */ 1N/A /* find the item in the list */ 1N/A /* not in there: return original */ 1N/A /* length of string without rem */ 1N/A /* copy from start to removed item */ 1N/A /* length of rest of string past removed item */ 1N/A /* not last item -- copy into string */ 1N/A** ATTEMPTAUTH -- try to AUTHenticate using one mechanism 1N/A** mci -- the mailer connection structure. 1N/A** e -- the envelope (including the sender to specify). 1N/A** sai - sasl authinfo 1N/A** EX_OK -- authentication was successful. 1N/A** EX_NOPERM -- authentication failed. 1N/A** EX_IOERR -- authentication dialogue failed (I/O problem?). 1N/A** EX_TEMPFAIL -- temporary failure. 1N/A#
else /* SASL >= 20000 */ 1N/A#
endif /* SASL >= 20000 */ 1N/A /* MUST NOT be a multiple of 4: bug in some sasl_encode64() versions */ 1N/A#
endif /* NETINET || (NETINET6 && SASL >= 20000) */ 1N/A /* no mechanism selected (yet) */ 1N/A /* dispose old connection */ 1N/A /* make a new client sasl connection */ 1N/A ** We provide the callbacks again because global callbacks in 1N/A ** sasl_client_init() are ignored if SASL has been initialized 1N/A ** before, for example, by a library such as libnss-ldap. 1N/A#
else /* SASL >= 20000 */ 1N/A#
endif /* SASL >= 20000 */ 1N/A /* set properties */ 1N/A /* XXX should these be options settable via .cf ? */ 1N/A /* external security strength factor, authentication id */ 1N/A#
endif /* STARTTLS */ 1N/A#
endif /* NETINET6 */ 1N/A#
endif /* NETINET6 */ 1N/A#
endif /* NETINET || NETINET6 */ 1N/A /* start client side of sasl */ 1N/A#
else /* SASL >= 20000 */ 1N/A /* external security strength factor, authentication id */ 1N/A#
endif /* STARTTLS */ 1N/A#
endif /* NETINET */ 1N/A /* start client side of sasl */ 1N/A#
endif /* SASL >= 20000 */ 1N/A "AUTH=client, available mechanisms do not fulfill requirements");
1N/A /* just point current mechanism to the data in the sasl library */ 1N/A /* send the info across the wire */ 1N/A /* login and digest-md5 up to 1.5.28 set out="" */ 1N/A /* no initial response */ 1N/A ** zero-length initial response, per RFC 2554 4.: 1N/A ** "Unlike a zero-length client answer to a 334 reply, a zero- 1N/A ** length initial response is sent as a single equals sign" 1N/A "encode64 for AUTH failed");
1N/A#
endif /* SASL < 20000 */ 1N/A /* check return code from server */ 1N/A /* should we fail deliberately, see RFC 2554 4. ? */ 1N/A /* smtpmessage("*", m, mci); */ 1N/A /* fail deliberately, see RFC 2554 4. */ 1N/A ** but we should only fail for this authentication 1N/A ** mechanism; how to do that? 1N/A /* give an error reply to the other side! */ 1N/A#
endif /* SASL < 20000 */ 1N/A** SMTPAUTH -- try to AUTHenticate 1N/A** This will try mechanisms in the order the sasl library decided until: 1N/A** - there are no more mechanisms 1N/A** - a mechanism succeeds 1N/A** - the sasl library fails initializing 1N/A** mci -- the mailer connection info. 1N/A** e -- the envelope. 1N/A** EX_OK -- authentication was successful 1N/A** EX_UNAVAILABLE -- authentication not possible, e.g., 1N/A** no data available. 1N/A** EX_NOPERM -- authentication failed. 1N/A** EX_TEMPFAIL -- temporary failure. 1N/A** Notice: AuthInfo is used for all connections, hence we must 1N/A** return EX_TEMPFAIL only if we really want to retry, i.e., 1N/A** iff getauth() tempfailed or getauth() was used and 1N/A** authentication tempfailed. 1N/A /* no data available: don't try to authenticate */ 1N/A /* read authinfo from file */ 1N/A /* check whether sufficient data is available */ 1N/A /* set the context for the callback function to sai */ 1N/A#
else /* SASL >= 20000 */ 1N/A#
endif /* SASL >= 20000 */ 1N/A /* set default value for realm */ 1N/A /* set default value for list of mechanism to use */ 1N/A /* create list of mechanisms to try */ 1N/A /* initialize sasl client library */ 1N/A** SMTPMAILFROM -- send MAIL command 1N/A** mci -- the mailer connection structure. 1N/A** e -- the envelope (including the sender to specify). 1N/A ** Check if connection is gone, if so 1N/A ** it's a tempfail and we use mci_errno 1N/A /* set up appropriate options to include */ 1N/A /* just pass it through */ 1N/A /* must convert from 8bit MIME format to 7bit encoded */ 1N/A#
endif /* MIME8TO7 */ 1N/A /* cannot just send a 8-bit version */ 1N/A /* RET= parameter */ 1N/A ** 17 is the max length required, we could use log() to compute 1N/A ** the exact length (and check IS_DLVR_TRACE()) 1N/A ** Avoid problems with delays (for R) since the check 1N/A ** in deliver() whether min-deliver-time is sufficient. 1N/A ** Alternatively we could pass the computed time to this 1N/A ** Send the MAIL command. 1N/A ** Designates the sender. 1N/A /* strip off <angle brackets> (put back on below) */ 1N/A /* communications failure */ 1N/A /* service shutting down: handled by reply() */ 1N/A /* syntax error in arguments */ 1N/A /* mailbox name not allowed */ 1N/A /* exceeded storage allocation */ 1N/A "%.100s: SMTP MAIL protocol error: %s",
1N/A /* protocol error -- close up */ 1N/A** SMTPRCPT -- designate recipient. 1N/A** to -- address of recipient. 1N/A** m -- the mailer we are sending to. 1N/A** mci -- the connection info for this transaction. 1N/A** e -- the envelope for this transaction. 1N/A** exit status corresponding to recipient status. 1N/A** Sends the mail via SMTP. 1N/A ** If there is status waiting from the other end, read it. 1N/A ** This should normally happen because of SMTP pipelining. 1N/A#
endif /* PIPELINING */ 1N/A ** Check if connection is gone, if so 1N/A ** it's a tempfail and we use mci_errno 1N/A ** Warning: in the following it is assumed that the free space 1N/A ** in bufp is sizeof(optbuf) 1N/A /* RFC 2852: 4.1.4.2 */ 1N/A /* NOTIFY= parameter */ 1N/A /* ORCPT= parameter */ 1N/A ** If running SMTP pipelining, we will pick up status later 1N/A#
endif /* PIPELINING */ 1N/A** SMTPRCPTSTAT -- get recipient status 1N/A** This is only called during SMTP pipelining 1N/A** to -- address of recipient. 1N/A** m -- mailer being sent to. 1N/A** mci -- the mailer connection information. 1N/A** e -- the envelope for this message. 1N/A** EX_* -- protocol status 1N/A ** Check if connection is gone, if so 1N/A ** it's a tempfail and we use mci_errno 1N/A#
endif /* PIPELINING */ 1N/A "%.100s: SMTP RCPT protocol error: %s",
1N/A** SMTPDATA -- send the data and clean up the transaction. 1N/A** m -- mailer being sent to. 1N/A** mci -- the mailer connection information. 1N/A** e -- the envelope for this message. 1N/A** exit status corresponding to DATA command. 1N/A ** Check if connection is gone, if so 1N/A ** it's a tempfail and we use mci_errno 1N/A ** First send the command and check that it is ok. 1N/A ** Then send the data (if there are valid recipients). 1N/A ** Follow it up with a dot to terminate. 1N/A ** Finally get the results of the transaction. 1N/A /* send the command and check ok to proceed */ 1N/A /* pick up any pending RCPT responses for SMTP pipelining */ 1N/A ** Connection might be closed in response to a RCPT command, 1N/A ** i.e., the server responded with 421. In that case (at 1N/A ** least) one RCPT has a temporary failure, hence we don't 1N/A ** need to check mci_okrcpts (as it is done below) to figure 1N/A ** out which error to return. 1N/A#
endif /* PIPELINING */ 1N/A /* now proceed with DATA phase */ 1N/A#
endif /* PIPELINING */ 1N/A "%.100s: SMTP DATA-1 protocol error: %s",
1N/A#
endif /* PIPELINING */ 1N/A#
endif /* PIPELINING */ 1N/A ** Set timeout around data writes. Make it at least large 1N/A ** enough for DNS timeouts on all recipients plus some fudge 1N/A ** factor. The main thing is that it should not be infinite. 1N/A /* simulate a DATA timeout */ 1N/A ** Output the actual message. 1N/A /* simulate a DATA timeout */ 1N/A ** Cleanup after sending message. 1N/A#
endif /* PIPELINING */ 1N/A /* terminate the message */ 1N/A "%.100s: SMTP DATA-1 protocol error: remote server returned response before final dot",
1N/A#
endif /* _FFR_CATCH_BROKEN_MTAS */ 1N/A /* error during processing -- don't send the dot */ 1N/A /* terminate the message */ 1N/A /* check for the results of the transaction */ 1N/A "%.100s: SMTP DATA-2 protocol error: %s",
1N/A ** If putbody() couldn't finish due to a timeout, 1N/A ** rewind it here in the timeout handler. See 1N/A ** comments at the end of putbody() for reasoning. 1N/A** SMTPGETSTAT -- get status code from DATA in LMTP 1N/A** m -- the mailer to which we are sending the message. 1N/A** mci -- the mailer connection structure. 1N/A** e -- the current envelope. 1N/A** The exit status corresponding to the reply code. 1N/A /* check for the results of the transaction */ 1N/A "%.100s: SMTP DATA-3 protocol error: %s",
1N/A** SMTPQUIT -- close the SMTP connection. 1N/A** m -- a pointer to the mailer. 1N/A** mci -- the mailer connection information. 1N/A** e -- the current envelope. 1N/A** sends the final protocol and closes the connection. 1N/A#
endif /* PIPELINING */ 1N/A ** Suppress errors here -- we may be processing a different 1N/A ** job when we do the quit connection, and we don't want the 1N/A ** new job to be penalized for something that isn't it's 1N/A /* send the quit message if we haven't gotten I/O error */ 1N/A /* now actually close the connection and pick up the zombie */ 1N/A /* look for naughty mailers */ 1N/A "smtpquit: mailer%s%s exited with exit value %d",
1N/A** SMTPRSET -- send a RSET (reset) command 1N/A** m -- a pointer to the mailer. 1N/A** mci -- the mailer connection information. 1N/A** e -- the current envelope. 1N/A** closes the connection if there is no reply to RSET. 1N/A#
endif /* PIPELINING */ 1N/A ** Check if connection is gone, if so 1N/A ** it's a tempfail and we use mci_errno 1N/A ** Any response is deemed to be acceptable. 1N/A ** The standard does not state the proper action 1N/A ** to take when a value other than 250 is received. 1N/A ** However, if 421 is returned for the RSET, leave 1N/A ** mci_state alone (MCIS_SSD can be set in reply() 1N/A ** and MCIS_CLOSED can be set in smtpquit() if 1N/A ** reply() gets a 421 and calls smtpquit()). 1N/A** SMTPPROBE -- check the connection state 1N/A** mci -- the mailer connection information. 1N/A** closes the connection if there is no reply to RSET. 1N/A** REPLY -- read arpanet reply 1N/A** m -- the mailer we are reading the reply from. 1N/A** mci -- the mailer connection info structure. 1N/A** e -- the current envelope. 1N/A** timeout -- the timeout for reads. 1N/A** pfunc -- processing function called on each line of response. 1N/A** If null, no special processing is done. 1N/A** enhstat -- optional, returns enhanced error code string (if set) 1N/A** rtype -- type of SmtpMsgBuffer: does it contains secret data? 1N/A** reply code it reads. 1N/A** flushes the mail file. 1N/A ** Flush the output before reading response. 1N/A ** For SMTP pipelining, it would be better if we didn't do 1N/A ** this if there was already data waiting to be read. But 1N/A ** to do it properly means pushing it to the I/O library, 1N/A ** since it really needs to be done below the buffer layer. 1N/A ** Read the input line, being careful not to hang. 1N/A /* actually do the read */ 1N/A /* if we are in the process of closing just give the code */ 1N/A /* don't try to read from a non-existent fd */ 1N/A /* errors on QUIT should be ignored */ 1N/A /* get the line from the other side */ 1N/A /* errors on QUIT should be ignored */ 1N/A /* if the remote end closed early, fake an error */ 1N/A "421 4.4.1 Connection reset by %s",
1N/A#
else /* ECONNRESET */ 1N/A#
endif /* ECONNRESET */ 1N/A usrerr(
"451 4.4.1 reply: read error from %s",
1N/A /* if debugging, pause so we can see state */ 1N/A "reply(%.100s) during %s",
1N/A /* EHLO failure is not a real error */ 1N/A /* serious error -- log the previous command */ 1N/A /* inform user who we are chatting with */ 1N/A "... while talking to %s:\n",
1N/A ?
"STARTTLS dialogue" 1N/A /* now log the message as from the other side */ 1N/A /* display the input for verbose mode */ 1N/A /* ignore improperly formatted input */ 1N/A /* process the line */ 1N/A /* decode the reply code */ 1N/A /* extra semantics: 0xx codes are "informational" */ 1N/A /* if no continuation lines, return this line */ 1N/A /* first line of real reply -- ignore rest */ 1N/A ** Now look at SmtpReplyBuffer -- only care about the first 1N/A ** line of the response from here on out. 1N/A /* save temporary failure messages for posterity */ 1N/A /* reply code 421 is "Service Shutting Down" */ 1N/A /* send the quit protocol */ 1N/A** SMTPMESSAGE -- send message to server 1N/A** m -- the mailer to control formatting. 1N/A** a, b, c -- parameters 1N/A** writes message to mci->mci_out. 1N/A#
endif /* __STDC__ */