|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 12187 (0x2f9b)
Types: TextFile
Names: »sm_wtmail.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z«
└─⟦e5a54fb17⟧
└─⟦this⟧ »pp-5.0/Chans/smtp/sm_wtmail.c«
/* sm_wtmail: mail-commands for smtp mail */
# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/smtp/RCS/sm_wtmail.c,v 5.0 90/09/20 15:54:22 pp Exp Locker: pp $";
# endif
/*
* $Header: /cs/research/pp/hubris/pp-beta/Chans/smtp/RCS/sm_wtmail.c,v 5.0 90/09/20 15:54:22 pp Exp Locker: pp $
*
* $Log: sm_wtmail.c,v $
* Revision 5.0 90/09/20 15:54:22 pp
* rcsforce : 5.0 public release
*
*/
#include "util.h"
#include "retcode.h"
#include "chan.h"
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "ap.h"
extern CHAN *chanptr;
extern char *loc_dom_mta;
extern char *strdup();
extern char *open_host;
struct sm_rstruct /* save last reply obtained */
{ /* for holding a net reply */
int sm_rval; /* rp.h value for reply */
int sm_rlen; /* current lengh of reply string */
char sm_rgot; /* true, if have a reply */
char sm_rstr[LINESIZE]; /* human-oriented reply text */
} sm_rp;
#define smtp_error() (sm_rp.sm_rgot ? sm_rp.sm_rstr : "")
static CHAN *sm_chptr; /* structure for channel that we are */
FILE *sm_rfp, *sm_wfp;
static char sm_rnotext[] = "No reply text given";
static int sm_rrec ();
#define SM_HTIME 180 /* Time allowed for HELO command */
#define SM_OTIME 300 /* Time allowed for a netopen */
#define SM_ATIME 120 /* Time allowed for answer after open */
#define SM_STIME 300 /* Time allowed for MAIL command */
#define SM_TTIME 300 /* Time allowed for RCPT command */
/* Should get smaller when list channel is in place */
#define SM_QTIME 60 /* Time allowed for QUIT command */
int data_bytes = 0;
#if sparc && defined(__GNUC__) /* work around bug in gcc 1.37 sparc version */
#define inet_ntoa myinet_ntoa
static char *myinet_ntoa (in)
struct in_addr in;
{
static char buf[80];
(void) sprintf (buf, "%d.%d.%d.%d",
(in.s_addr >> 24) & 0xff,
(in.s_addr >> 16) & 0xff,
(in.s_addr >> 8 ) & 0xff,
(in.s_addr ) & 0xff);
return buf;
}
#else
extern char *inet_ntoa ();
#endif
sm_wfrom (sender)
char *sender;
{
char linebuf[LINESIZE];
(void) sprintf (linebuf, "MAIL FROM:<%s>", sender);
if (rp_isbad (sm_cmd (linebuf, SM_STIME)))
return (RP_DHST);
switch( sm_rp.sm_rval ) {
case 250:
break; /* We're off and running! */
case 500:
case 501:
case 552:
return( sm_rp.sm_rval = RP_PARM );
case 421:
case 450:
case 451:
case 452:
return( sm_rp.sm_rval = RP_AGN);
default:
return( sm_rp.sm_rval = RP_BHST);
}
return( RP_OK );
}
sm_wto (adr) /* send one address spec to local */
char adr[]; /* rest of address */
{
char linebuf[LINESIZE];
if( isstr(adr))
(void) sprintf (linebuf, "RCPT TO:<%s>", adr);
else
(void) strcpy(linebuf, "RCPT TO:<>");
if (rp_isbad (sm_cmd (linebuf, SM_TTIME)))
return (RP_DHST);
switch (sm_rp.sm_rval)
{
case 250:
case 251:
sm_rp.sm_rval = RP_AOK;
break;
case 421:
case 450:
case 451:
case 452:
sm_rp.sm_rval = RP_AGN;
break;
case 550:
case 551:
case 552:
case 553:
case 554: /* BOGUS: sendmail is out of spec! */
sm_rp.sm_rval = RP_USER;
break;
case 500:
case 501:
sm_rp.sm_rval = RP_PARM;
break;
default:
sm_rp.sm_rval = RP_RPLY;
}
if (rp_isbad (sm_rp.sm_rval))
PP_NOTICE (("Address failed, reason '%s'",
smtp_error()));
return (sm_rp.sm_rval);
}
sm_init (curchan) /* session initialization */
CHAN *curchan; /* name of channel */
{
sm_chptr = curchan;
/* phs_note (sm_chptr, PHS_CNSTRT); */
return (RP_OK); /* generally, a no-op */
}
static
sm_irdrply () /* get net reply & stuff into sm_rp */
{
static char sep[] = "; "; /* for sticking multi-lines together */
short len,
tmpreply,
retval;
char linebuf[LINESIZE];
char tmpmore;
register char *linestrt; /* to bypass bad initial chars in buf */
register short i;
register char more; /* are there continuation lines? */
newrply:
for (more = FALSE, sm_rp.sm_rgot = FALSE, sm_rp.sm_rlen = 0;
rp_isgood (retval = sm_rrec (linebuf, &len));)
{
PP_LOG (LLOG_PDUS, ("<- %s", linebuf));
/* 1st col in linebuf gets reply code */
for (linestrt = linebuf; /* skip leading baddies, probably */
len > 0 && /* from a lousy Multics */
(!isascii ((char) *linestrt) ||
!isdigit ((char) *linestrt));
linestrt++, len--);
tmpmore = FALSE; /* start fresh */
tmpreply = atoi (linestrt);
bcopy (linestrt, sm_rp.sm_rstr, 3); /* Grab reply code */
if ((len -= 3) > 0)
{
linestrt += 3;
if (len > 0 && *linestrt == '-')
{
tmpmore = TRUE;
linestrt++;
if (--len > 0)
for (; len > 0 && isspace (*linestrt); linestrt++, len--);
}
}
if (more) /* save reply value from 1st line */
{ /* we at end of continued reply? */
if (tmpreply != sm_rp.sm_rval || tmpmore)
continue;
more = FALSE; /* end of continuation */
}
else /* not in continuation state */
{
sm_rp.sm_rval = tmpreply;
more = tmpmore; /* more lines to follow? */
if (len <= 0)
{ /* fake it, if no text given */
bcopy (sm_rnotext, linestrt = linebuf,
(sizeof sm_rnotext) - 1);
len = (sizeof sm_rnotext) - 1;
}
}
if ((i = MIN (len, (LINESIZE - 1) - sm_rp.sm_rlen)) > 0)
{ /* if room left, save the human text */
bcopy (linestrt, &sm_rp.sm_rstr[sm_rp.sm_rlen], i);
sm_rp.sm_rlen += i;
if (more && sm_rp.sm_rlen < (LINESIZE - 4))
{ /* put a separator between lines */
bcopy (sep, &(sm_rp.sm_rstr[sm_rp.sm_rlen]), (sizeof sep) - 1);
sm_rp.sm_rlen += (sizeof sep) - 1;
}
}
if (!more)
{
if (sm_rp.sm_rval < 100)
goto newrply; /* skip info messages */
sm_rp.sm_rgot = TRUE;
return (RP_OK);
}
}
return (retval); /* error return */
}
static sm_rrec (linebuf, len) /* read a reply record from net */
char *linebuf; /* where to stuff text */
short *len; /* where to stuff length */
{
extern int errno;
*len = 0; /* for clean logging if nothing read */
linebuf[0] = '\0';
fgets (linebuf, LINESIZE, sm_rfp);
*len = strlen (linebuf);
if (ferror (sm_rfp) || feof (sm_rfp))
{ /* error or unexpected eof */
PP_LOG (LLOG_EXCEPTIONS,
("netread: ret=%d, fd=%d", *len, fileno (sm_rfp)));
sm_nclose (NOTOK); /* since it won't work anymore */
return (RP_BHST);
}
if (linebuf[*len - 1] != '\n')
{
PP_LOG (LLOG_EXCEPTIONS, ("net input overflow"));
while (getc (sm_rfp) != '\n'
&& !ferror (sm_rfp) && !feof (sm_rfp));
}
else
if (linebuf[*len - 2] == '\r')
*len -= 1; /* get rid of crlf or just lf */
linebuf[*len - 1] = '\0';
return (RP_OK);
}
sm_cmd (cmd, time) /* Send a command */
char *cmd;
int time; /* Max time for sending and getting reply */
{
short retval;
PP_LOG (LLOG_PDUS, ("-> %s", cmd));
if (sm_wfp == NULL)
return sm_rp.sm_rval = RP_DHST;
if (timeout((time_t)time)) {
PP_TRACE (("sm_cmd(): host died?"));
sm_nclose (NOTOK);
return (sm_rp.sm_rval = RP_DHST);
}
fprintf (sm_wfp, "%s\r\n", cmd);
if (!ferror (sm_wfp))
(void) fflush (sm_wfp);
timeout (0);
if (ferror (sm_wfp))
{
PP_TRACE (("sm_cmd(): host died?"));
sm_nclose (NOTOK);
return (sm_rp.sm_rval = RP_DHST);
}
if (rp_isbad (retval = sm_irdrply ()))
return( sm_rp.sm_rval = retval );
return (RP_OK);
}
sm_wstm (buf, len) /* write some message text out */
char *buf; /* what to write */
register int len; /* how long it is */
{
static char lastchar = 0;
short retval;
register char *bufptr;
register char newline;
if (buf == 0 && len == 0) { /* end of text */
if (lastchar != '\n') { /* make sure it ends cleanly */
fputs ("\r\n", sm_wfp);
data_bytes += 2;
}
if (ferror (sm_wfp))
return (RP_DHST);
lastchar = 0; /* reset for next message */
retval = RP_OK;
}
else
{
newline = (lastchar == '\n') ? TRUE : FALSE;
for (bufptr = buf; len--; bufptr++)
{
switch (*bufptr) /* cycle through the buffer */
{
case '\n': /* Telnet requires crlf */
newline = TRUE;
putc ('\r', sm_wfp);
data_bytes ++;
break;
case '.': /* Insert extra period at beginning */
if (newline) {
putc ('.', sm_wfp);
data_bytes ++;
}
/* DROP ON THROUGH */
default:
newline = FALSE;
}
if (ferror (sm_wfp))
break;
/* finally send the data character */
putc ((lastchar = *bufptr), sm_wfp);
data_bytes ++;
if (ferror (sm_wfp))
break;
}
retval = ferror(sm_wfp) ? RP_DHST : RP_OK;
}
return (retval);
}
static int start_conn (sp, name, errstr)
struct sockaddr_in *sp;
char *name;
char *errstr;
{
int s;
s = socket (AF_INET, SOCK_STREAM, 0);
if( s < 0 ) {
PP_SLOG (LLOG_EXCEPTIONS, "socket",
("Can't get socket"));
return NOTOK;
}
if (timeout(SM_OTIME)) {
PP_LOG (LLOG_EXCEPTIONS,
("[%s] open timeout", name,
inet_ntoa (sp -> sin_addr)));
return NOTOK;
}
if( connect (s, (struct sockaddr *)sp, sizeof *sp) < 0 ) {
(void) close (s);
PP_SLOG (LLOG_EXCEPTIONS, "connect",
("Connection failed to %s [%s]", name,
inet_ntoa (sp -> sin_addr)));
timeout (0);
return NOTOK;
}
timeout (0);
return s;
}
sm_nopen(hostnam, errstr )
char *hostnam;
char *errstr;
{
int fds[2], skt;
short retval;
char linebuf[LINESIZE];
extern int smtpport;
struct hostent *hp, *gethostbyname ();
struct sockaddr_in sin;
char **aptr;
PP_TRACE (("[ %s ]", hostnam));
*errstr = 0;
#ifdef NAMESERVER
if (rp_isbad (retval = ns_gethost (hostnam, &hp))) {
(void) sprintf (errstr, "Nameserver lookup failed");
return (retval);
}
#else NAMESERVER
if ((hp = gethostbyname (hostnam)) == NULL) {
(void) sprintf (errstr, "Host lookup failed");
return RP_BHST;
}
#endif NAMESERVER
if (smtpport == 0) {
struct servent *sp;
if ((sp = getservbyname ("smtp", "tcp")) == NULL) {
(void) sprintf (errstr, "Can't determine smtp port");
return RP_AGN;
}
smtpport = (short)sp->s_port;
}
bzero ((char *)&sin, sizeof sin);
sin.sin_family = AF_INET;
sin.sin_port = smtpport;
/* SEK - try all addresses */
for (aptr = hp -> h_addr_list; *aptr; aptr++)
{
bcopy (*aptr, (char *)&sin.sin_addr, hp -> h_length);
PP_NOTICE (("Attempting open to [%s]",
inet_ntoa (sin.sin_addr)));
if ((skt = start_conn (&sin, hp -> h_name, errstr)) == NOTOK)
continue;
fds[0] = skt;
fds[1] = dup (skt);
if ((sm_rfp = fdopen (fds[0], "r")) == NULL ||
(sm_wfp = fdopen (fds[1], "w")) == NULL) {
return (RP_LIO);
}
if (timeout(SM_ATIME)) {
(void) sprintf (errstr, "Timeout opening %s", hostnam);
sm_nclose (NOTOK);
return( RP_BHST );
}
if (rp_isbad (retval = sm_irdrply ())) {
(void) sprintf (errstr, "Bad response from %s: %s",
hostnam, smtp_error ());
timeout (0);
sm_nclose (NOTOK);
return(retval);
}
timeout (0);
if( sm_rp.sm_rval != 220 ) {
sm_nclose (NOTOK);
return( RP_BHST );
}
/* HELO is part of protocol - all commands are 4 letters long */
(void) sprintf (linebuf, "HELO %s", loc_dom_mta);
if (rp_isbad (sm_cmd( linebuf, SM_HTIME))
|| sm_rp.sm_rval != 250 ) {
(void) sprintf (errstr, "Bad response to helo: %s",
smtp_error());
sm_nclose (NOTOK);
return (RP_RPLY);
}
PP_NOTICE (("Connected to %s [%s]", hostnam,
inet_ntoa (sin.sin_addr)));
return (RP_OK);
}
return (RP_BHST); /* No addresses OK */
}
sm_nclose (type) /* end current connection */
short type; /* clean or dirty ending */
{
if (type == OK && sm_wfp)
sm_cmd ("QUIT", SM_QTIME);
if (sm_rfp == NULL && sm_wfp == NULL)
return;
PP_NOTICE (("Closing connection to %s", open_host));
if (open_host)
free(open_host);
open_host = NULLCP;
if (timeout(15)) {
return;
}
if (sm_rfp != NULL)
(void) fclose (sm_rfp);
if (sm_wfp != NULL)
(void) fclose (sm_wfp);
timeout (0);
sm_rfp = sm_wfp = NULL;
}