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

⟦3bdbf1e73⟧ TextFile

    Length: 12618 (0x314a)
    Types: TextFile
    Names: »smtp.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/smtp.c« 

TextFile

/* smtp: as invoked by qmgr to deliver smtp stuff*/

# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/smtp/RCS/smtp.c,v 5.0 90/09/20 15:54:26 pp Exp Locker: pp $";
# endif

/*
 * $Header: /cs/research/pp/hubris/pp-beta/Chans/smtp/RCS/smtp.c,v 5.0 90/09/20 15:54:26 pp Exp Locker: pp $
 *
 * $Log:	smtp.c,v $
 * Revision 5.0  90/09/20  15:54:26  pp
 * rcsforce : 5.0 public release
 * 
 */



#include "head.h"
#include "chan.h"
#include "prm.h"
#include "q.h"
#include "dr.h"
#include "qmgr.h"
#include <pwd.h>
#include <sys/file.h>
#include <signal.h>

extern  char    *aquedir,
		*mquedir,
		*quedfldir;
extern void	rd_end(), chan_init(), err_abrt(), timer_start(), timer_end();
FILE            *msg_fp;
CHAN            *mychan;
char            *this_msg;
int		smtpport = 0;

extern struct sm_rstruct {              /* save last reply obtained */
	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 : "")

extern time_t time();


#define SM_RTIME        15              /* Time allowed for a RSET command */
#define SM_DTIME        120             /* Time allowed for a DATA command */
#define SM_PTIME        600             /* Time allowed for the "." command */
#define SM_TTIME        180             /* Time allowed for a block of text */


static struct type_Qmgr_DeliveryStatus *process();
static void dirinit();
static int chaninit();
static int endproc ();
static int dotext ();
static int copy ();


/* ---------------------  Begin  Routines  -------------------------------- */




main (argc, argv)
int     argc;
char    **argv;
{
	char    *p;
	int	opt;
	extern char *optarg;

	if (p = rindex (argv[0], '/'))
		p ++;
	if (p == NULLCP || *p == NULL)
		p = argv[0];

	chan_init (p);   /* init the channel - and find out who we are */

	while ((opt = getopt (argc, argv, "p:")) != EOF) {
		switch (opt) {
		    case 'p':
			smtpport = htons (atoi (optarg));
			break;

		    default:
			PP_LOG (LLOG_EXCEPTIONS,
				("Bad argument -%c", opt));
			break;
		}
	}


	dirinit();              /* get to the right directory */
	(void) signal (SIGPIPE, SIG_IGN);
#ifdef PP_DEBUG
	if (argc > 1 && strcmp (argv[1], "debug") == 0)
		debug_channel_control (argc, argv, chaninit, process, endproc);
	else
#endif
		channel_control (argc, argv, chaninit, process, endproc);
	exit (0);
}



static int chaninit (arg)
struct type_Qmgr_Channel *arg;
{
	char    *p = qb2str (arg);

	if ((mychan = ch_nm2struct (p)) == (CHAN *)0)
		err_abrt (RP_PARM, "Channel '%s' not known", p);

	rename_log(p); 
	sm_init (mychan);
	PP_NOTICE (("starting %s (%s)", mychan -> ch_name, mychan -> ch_show));
	free (p);
	return OK;
}

char    *cur_host;
char    *open_host;
int	open_state;		/* defines meaning of open_host */
#define STATE_INITIAL 	0
#define STATE_OPEN    	1
#define STATE_BAD_HOST	2
#define STATE_TIMED_OUT	3
char    *sender;
char    *formatdir;

static int endproc ()
{
	if (cur_host)
		sm_nclose (OK);
}

static struct type_Qmgr_DeliveryStatus *process (arg)
struct type_Qmgr_ProcMsg *arg;
{
	struct prm_vars prm;
	struct type_Qmgr_UserList *up;
	Q_struct        Qstruct, *qp = &Qstruct;
	int     retval;
	ADDR    *ap,
		*ad_sendr = NULLADDR,
		*ad_recip = NULLADDR,
		*alp = NULLADDR,
		*ad_list = NULLADDR;
	int     ad_count;

	if (this_msg) free (this_msg);

	this_msg = qb2str (arg -> qid);

	bzero ((char *)&prm, sizeof prm);
	bzero ((char *)qp, sizeof *qp);

	(void) delivery_init (arg -> users);

	retval = rd_msg (this_msg, &prm, qp, &ad_sendr, &ad_recip, &ad_count);

	if (rp_isbad (retval)) {
		PP_LOG (LLOG_EXCEPTIONS, ("rd_msg err: %s", this_msg));
		return delivery_setallstate (int_Qmgr_status_messageFailure,
					     "Can't read message");
	}

	sender = ad_sendr -> ad_r822adr;

	for (ap = ad_recip; ap; ap = ap -> ad_next) {
		for (up = arg ->users; up; up = up -> next) {
			if (up -> RecipientId -> parm != ap -> ad_no)
				continue;

			switch (chan_acheck (ap, mychan,
					     ad_list == NULLADDR, &cur_host)) {
			    default:
			    case NOTOK:
				continue;

			    case OK:
				break;
			}
			break;
		}
		if (up == NULL)
			continue;

		if (ad_list == NULLADDR)
			ad_list = alp = (ADDR *) calloc (1, sizeof *alp);
		else {
			alp -> ad_next = (ADDR *) calloc (1, sizeof *alp);
			alp = alp -> ad_next;
		}
		*alp = *ap;
		alp -> ad_next = NULLADDR;
	}

	if (ad_list == NULLADDR) {
		PP_LOG (LLOG_EXCEPTIONS, ("No recipients in user list"));
		rd_end ();
		q_free (qp);
		return deliverystate;
	}

	PP_NOTICE (("processing msg %s to %s", this_msg, cur_host));

	deliver (ad_list, qp);

	q_free (qp);
	rd_end();

	return deliverystate;
}

static void dirinit()       /* Change into pp queue space */
{
	if (chdir (quedfldir) < 0)
		err_abrt (RP_LIO, "Unable to change directory to '%s'",
						quedfldir);
}

deliver (ad_list, qp)
ADDR    *ad_list;
Q_struct *qp;
{
	ADDR    *ap;
	int     naddrs;
	char	buf [LINESIZE];

	PP_TRACE (("deliver ()"));


	if (lexequ (cur_host, open_host) != 0) { 
					/* Brand new host */

		if (open_host != NULLCP) {
			free (open_host);	
			if (open_state == STATE_OPEN) 
				sm_nclose (OK);
		}
		open_host = strdup (cur_host);

		switch (sm_nopen (cur_host, buf))
		{
			case RP_OK:
				open_state = STATE_OPEN;
				break;
			case RP_NO:
				open_state = STATE_BAD_HOST;
				break;
			default:
				open_state = STATE_TIMED_OUT;
				break;
		}
	}

	switch (open_state)
	{
		case STATE_OPEN:
			break;		/* just carry on */
		case STATE_BAD_HOST:
			PP_NOTICE ((buf));
			set_all_dr (qp, ad_list, 
				 DRR_UNABLE_TO_TRANSFER,
				 DRD_UNRECOGNISED_OR,
				 buf);
			wr_q2dr (qp, this_msg);
			(void) delivery_setall (int_Qmgr_status_negativeDR);
			return;
		case STATE_TIMED_OUT:
			PP_NOTICE (("Connection failed to '%s': %s",
				    cur_host, buf));
			(void) delivery_setallstate
				(int_Qmgr_status_mtaFailure,
				 buf);
			return;
	}

	naddrs = 0;

	if (do_sender (sender) == NOTOK) 
		return;

	for (ap = ad_list; ap; ap = ap -> ad_next) {
		switch (do_recip (ap, qp) ){
		    case OK:
			naddrs ++;
			break;

		    case NOTOK:
			break;

		    default:
			return;
		}
	}

	if (naddrs == 0) {
		(void) reset ();
		wr_q2dr (qp, this_msg);
		PP_NOTICE ((">>> Message %s transfered to no recipients",
			    this_msg, naddrs));
		delivery_setall (int_Qmgr_status_negativeDR);
		return;
	}

	if (dotext (ad_list, naddrs) == NOTOK)
		return;

	for (ap = ad_list; ap; ap = ap -> ad_next) {
		if (ap -> ad_resp) {
			if (ap -> ad_usrreq == AD_USR_CONFIRM ||
			    ap -> ad_mtarreq == AD_MTA_CONFIRM ||
			    ap -> ad_mtarreq == AD_MTA_AUDIT_CONFIRM) {
				set_1dr (qp, ap -> ad_no,
					 DRR_NO_REASON, -1, NULLCP);
				delivery_set (ap -> ad_no,
					      int_Qmgr_status_positiveDR);
			}
			else {
				(void) wr_ad_status (ap, AD_STAT_DONE);
				delivery_set (ap -> ad_no,
					      int_Qmgr_status_success);
			}
		}
	}
	wr_q2dr (qp, this_msg);
	PP_NOTICE ((">>> Message %s transfered to %d recipients",
		    this_msg, naddrs));
}       

do_recip (ap, qp)
ADDR    *ap;
Q_struct *qp;
{
	int     retval;
	char	errbuf[BUFSIZ];

	PP_NOTICE (("Recipient %s", ap -> ad_r822adr));

	if (rp_isbad (retval = sm_wto (ap ->ad_r822adr))) {
		switch (retval) {
		    case RP_DHST:
			PP_LOG (LLOG_EXCEPTIONS, ("Host died"));
			(void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
						"Host died");
			return DONE;

		    case RP_AOK:
			ap -> ad_resp = 1;
			return OK;

		    case RP_AGN:
			(void) delivery_setstate (ap -> ad_no,
				      int_Qmgr_status_messageFailure,
					     smtp_error ());
			PP_LOG (LLOG_EXCEPTIONS, ("Temporary failure: %s",
						  smtp_error ()));
			ap -> ad_resp = 0;
			return NOTOK;

		    case RP_USER:
			(void) delivery_set (ap -> ad_no,
				      int_Qmgr_status_negativeDR);
			(void) sprintf (errbuf,
					"MTA '%s' gives error message %s",
					cur_host, smtp_error ());
			PP_LOG (LLOG_EXCEPTIONS, ("User error: %s", errbuf));
			set_1dr (qp, ap -> ad_no,
				 DRR_UNABLE_TO_TRANSFER,
				 DRD_UNRECOGNISED_OR, 
				 errbuf);
			ap -> ad_resp = 0;
			return NOTOK;

		    case RP_PARM:
			ap -> ad_resp = 0;
			PP_LOG (LLOG_EXCEPTIONS, ("Parameter problem: %s",
						  smtp_error()));
			(void) delivery_setstate (ap -> ad_no,
				      int_Qmgr_status_messageFailure,
					     smtp_error ());
			return NOTOK;

		    case RP_RPLY:
		    default:
			PP_LOG (LLOG_EXCEPTIONS, ("Message failure: %s",
						  smtp_error ()));
			(void) delivery_setallstate (int_Qmgr_status_messageFailure,
						smtp_error ());
			(void) reset ();
			return DONE;
		}
	}
	return OK;
}

do_sender (sndr)
char    *sndr;
{
	int     retval;

	PP_NOTICE (("sender %s", sndr));

	if (rp_isbad (retval = sm_wfrom (sender))) {
		switch (retval) {
		    case RP_DHST:
			PP_LOG (LLOG_EXCEPTIONS, ("Host connection died"));
			(void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
						"host connection failed");
			sm_nclose (NOTOK);
			return NOTOK;

		    case RP_PARM:
			PP_LOG (LLOG_EXCEPTIONS, ("Parameter problem: %s",
						  smtp_error()));
			(void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
						smtp_error ());
			sm_nclose (NOTOK);
			return NOTOK;

		    case RP_AGN:
			(void) delivery_setallstate (int_Qmgr_status_messageFailure,
						smtp_error ());
			PP_LOG (LLOG_EXCEPTIONS, ("Temporary error: %s",
						  smtp_error ()));
			(void) reset ();
			return NOTOK;

		    case RP_OK:
			break;

		    default:
			PP_LOG (LLOG_EXCEPTIONS, ("Protocol error: %s",
						  smtp_error()));
			(void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
						smtp_error ());
			sm_nclose (NOTOK);
			return NOTOK;
		}
	}
	return OK;
}

extern int data_bytes;

static int dotext (ap, naddrs)
ADDR    *ap;
int     naddrs;
{
	extern  FILE    *sm_wfp;
	int     retval;
	char    filename[FILNSIZE];
	struct timeval data_time;
	int	first = 1;

	if (qid2dir (this_msg, ap, TRUE, &formatdir) == NOTOK) {
		PP_LOG (LLOG_EXCEPTIONS, ("Can't locate message %s",
					  this_msg));
		(void) delivery_setallstate (int_Qmgr_status_messageFailure,
					"Cant find message");
		(void) reset ();
		return NOTOK;
	}


	if (rp_isbad (retval = msg_rinit (formatdir))) {
		(void) delivery_setallstate (int_Qmgr_status_messageFailure,
					"Can't read message");
		reset ();
		return NOTOK;
	}

	if (rp_isbad (sm_cmd ("DATA", SM_DTIME))) {
		(void) delivery_setallstate (int_Qmgr_status_messageFailure,
					smtp_error ());
		sm_nclose (NOTOK);
		return (NOTOK);
	}

	data_bytes = 0;
	timer_start (&data_time);

	while ((retval = msg_rfile (filename)) == RP_OK) {
		if (rp_isbad (copy (filename))) {
			(void) delivery_setallstate(int_Qmgr_status_mtaAndMessageFailure,
					       "Can't transfer data");
			sm_nclose (NOTOK);
			return NOTOK;
		}
		if (first) {
			sm_wstm ("\n", 1);
			first = 0;
		}
	}
	if (rp_isbad (retval)) {
		(void) delivery_setallstate (int_Qmgr_status_messageFailure,
					     "Message transfer failed");
		sm_nclose (NOTOK);
		return NOTOK;
	}

	if (rp_isbad (sm_wstm (NULLCP, 0))) {
		(void) delivery_setallstate (int_Qmgr_status_messageFailure,
					"Bad temination of data");
		sm_nclose (NOTOK);
		return NOTOK;
	}

	if (rp_isbad (retval = sm_cmd (".", SM_PTIME + 3 * naddrs))) {
		switch (retval) {
		    case RP_DHST:
			PP_LOG (LLOG_EXCEPTIONS, ("Host connection died"));
			(void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
						"Connection died");

			break;

		    default:
			PP_LOG (LLOG_EXCEPTIONS, ("Temporary failure: %s",
						  smtp_error ()));
			(void) delivery_setallstate (int_Qmgr_status_messageFailure,
						smtp_error ());
			break;
		}
		return NOTOK;
	}
	timer_end (&data_time, data_bytes, "Data Transfered");
	msg_rend();

	return OK;
}

static int copy (fname)
char    *fname;
{
	FILE    *ifp;
	char    buf[BUFSIZ];
	int     n, retval = RP_OK;

	if ((ifp = fopen (fname,"r")) == NULL) {
		PP_LOG (LLOG_EXCEPTIONS, ("Can't read file '%s'", fname));
		return RP_FOPN;
	}

	while ((n = fread (buf, sizeof (char), sizeof (buf), ifp)) > 0)
		if (rp_isbad (retval = sm_wstm (buf, n)))
			break;
	(void) fclose (ifp);
	return retval;
}

reset ()
{
	int     retval;

	if (rp_isbad (retval = sm_cmd ("RSET", SM_RTIME))) {
		switch (retval) {
		    default:
			(void) delivery_setallstate (int_Qmgr_status_mtaFailure,
						smtp_error ());
			sm_nclose (NOTOK);
			return NOTOK;

		    case RP_OK:
			break;
		}
	}
	return OK;
}