DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T s

⟦8e6931ae0⟧ TextFile

    Length: 12187 (0x2f9b)
    Types: TextFile
    Names: »sm_wtmail.c«

Derivation

└─⟦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« 

TextFile

/* 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;
}