14796Seric # include <ctype.h>
2*7356Seric # include <signal.h>
34684Seric # include <sysexits.h>
44865Seric # include "sendmail.h"
54684Seric 
65182Seric # ifndef SMTP
7*7356Seric SCCSID(@(#)usersmtp.c	3.13		07/05/82	(no SMTP));
85182Seric # else SMTP
94684Seric 
10*7356Seric SCCSID(@(#)usersmtp.c	3.13		07/05/82);
115182Seric 
124684Seric /*
134865Seric **  SMTPINIT -- initialize SMTP.
144684Seric **
154865Seric **	Opens the connection and sends the initial protocol.
164684Seric **
174684Seric **	Parameters:
184865Seric **		m -- mailer to create connection to.
194865Seric **		pvp -- pointer to parameter vector to pass to
204865Seric **			the mailer.
214865Seric **		ctladdr -- controlling address for this mailer.
224684Seric **
234684Seric **	Returns:
244865Seric **		appropriate exit status -- EX_OK on success.
254684Seric **
264684Seric **	Side Effects:
274865Seric **		creates connection and sends initial protocol.
284684Seric */
294684Seric 
304865Seric # define REPLYTYPE(r)	((r) / 100)
314865Seric 
324865Seric static FILE	*SmtpOut;	/* output file */
334865Seric static FILE	*SmtpIn;	/* input file */
344865Seric static int	SmtpPid;	/* pid of mailer */
356051Seric static int	SmtpErrstat;	/* error status if open fails */
364865Seric 
374865Seric smtpinit(m, pvp, ctladdr)
384865Seric 	struct mailer *m;
394865Seric 	char **pvp;
404865Seric 	ADDRESS *ctladdr;
414684Seric {
424865Seric 	register int r;
434865Seric 	char buf[MAXNAME];
44*7356Seric 	extern tick();
454684Seric 
464865Seric 	/*
474865Seric 	**  Open the connection to the mailer.
484865Seric 	*/
494684Seric 
506051Seric 	SmtpIn = SmtpOut = NULL;
514865Seric 	SmtpPid = openmailer(m, pvp, ctladdr, TRUE, &SmtpOut, &SmtpIn);
526051Seric 	if (SmtpPid < 0)
536051Seric 	{
546051Seric 		SmtpErrstat = ExitStat;
556051Seric # ifdef DEBUG
566051Seric 		if (Debug > 0)
576051Seric 			printf("smtpinit: cannot open: Errstat %d errno %d\n",
586051Seric 			   SmtpErrstat, errno);
596051Seric # endif DEBUG
606051Seric 		return (ExitStat);
616051Seric 	}
62*7356Seric 	(void) signal(SIGALRM, tick);
634796Seric 
644865Seric 	/*
654865Seric 	**  Get the greeting message.
664865Seric 	**	This should appear spontaneously.
674865Seric 	*/
684797Seric 
694865Seric 	r = reply();
704865Seric 	if (REPLYTYPE(r) != 2)
714865Seric 		return (EX_TEMPFAIL);
724684Seric 
734865Seric 	/*
744976Seric 	**  Send the HELO command.
754976Seric 	**	My mother taught me to always introduce myself, even
764976Seric 	**	if it is useless.
774976Seric 	*/
784976Seric 
794976Seric 	smtpmessage("HELO %s", HostName);
804976Seric 	r = reply();
814976Seric 	if (REPLYTYPE(r) == 5)
824976Seric 		return (EX_UNAVAILABLE);
834976Seric 	if (REPLYTYPE(r) != 2)
844976Seric 		return (EX_TEMPFAIL);
854976Seric 
864976Seric 	/*
874865Seric 	**  Send the MAIL command.
884865Seric 	**	Designates the sender.
894865Seric 	*/
904796Seric 
916980Seric 	expand("$g", buf, &buf[sizeof buf - 1], CurEnv);
924865Seric 	smtpmessage("MAIL From:<%s>", buf);
934865Seric 	r = reply();
944865Seric 	if (REPLYTYPE(r) == 4)
954865Seric 		return (EX_TEMPFAIL);
964865Seric 	if (r != 250)
974865Seric 		return (EX_SOFTWARE);
984865Seric 	return (EX_OK);
994684Seric }
1004684Seric /*
1014976Seric **  SMTPRCPT -- designate recipient.
1024797Seric **
1034797Seric **	Parameters:
1044865Seric **		to -- address of recipient.
1054797Seric **
1064797Seric **	Returns:
1074865Seric **		exit status corresponding to recipient status.
1084797Seric **
1094797Seric **	Side Effects:
1104865Seric **		Sends the mail via SMTP.
1114797Seric */
1124797Seric 
1134976Seric smtprcpt(to)
1144865Seric 	ADDRESS *to;
1154797Seric {
1164797Seric 	register int r;
1174797Seric 
1186051Seric 	if (SmtpPid < 0)
1196051Seric 		return (SmtpErrstat);
1206051Seric 
1214976Seric 	smtpmessage("RCPT To:<%s>", to->q_user);
1224865Seric 
1234797Seric 	r = reply();
1244865Seric 	if (REPLYTYPE(r) == 4)
1254865Seric 		return (EX_TEMPFAIL);
1264865Seric 	if (r != 250)
1274865Seric 		return (EX_NOUSER);
1284797Seric 
1294865Seric 	return (EX_OK);
1304797Seric }
1314797Seric /*
1324865Seric **  SMTPFINISH -- finish up sending all the SMTP protocol.
1334684Seric **
1344684Seric **	Parameters:
1354865Seric **		m -- mailer being sent to.
1366980Seric **		e -- the envelope for this message.
1374684Seric **
1384684Seric **	Returns:
1394976Seric **		exit status corresponding to DATA command.
1404684Seric **
1414684Seric **	Side Effects:
1424865Seric **		none.
1434684Seric */
1444684Seric 
1456980Seric smtpfinish(m, e)
1464865Seric 	struct mailer *m;
1476980Seric 	register ENVELOPE *e;
1484684Seric {
1494684Seric 	register int r;
1504684Seric 
1516051Seric 	if (SmtpPid < 0)
1526051Seric 		return (SmtpErrstat);
1536051Seric 
1544797Seric 	/*
1554797Seric 	**  Send the data.
1564797Seric 	**	Dot hiding is done here.
1574797Seric 	*/
1584797Seric 
1594865Seric 	smtpmessage("DATA");
1604796Seric 	r = reply();
1614797Seric 	if (REPLYTYPE(r) == 4)
1624797Seric 		return (EX_TEMPFAIL);
1634684Seric 	if (r != 354)
1644684Seric 		return (EX_SOFTWARE);
1656980Seric 	(*e->e_puthdr)(SmtpOut, m, CurEnv);
1666980Seric 	fprintf(SmtpOut, "\n");
1676980Seric 	(*e->e_putbody)(SmtpOut, m, TRUE);
1684865Seric 	smtpmessage(".");
1694796Seric 	r = reply();
1704797Seric 	if (REPLYTYPE(r) == 4)
1714797Seric 		return (EX_TEMPFAIL);
1724684Seric 	if (r != 250)
1734684Seric 		return (EX_SOFTWARE);
1744684Seric 	return (EX_OK);
1754684Seric }
1764684Seric /*
1774865Seric **  SMTPQUIT -- close the SMTP connection.
1784865Seric **
1794865Seric **	Parameters:
1804865Seric **		name -- name of mailer we are quitting.
1817229Seric **		showresp -- if set, give a response message.
1824865Seric **
1834865Seric **	Returns:
1844865Seric **		none.
1854865Seric **
1864865Seric **	Side Effects:
1874865Seric **		sends the final protocol and closes the connection.
1884865Seric */
1894865Seric 
1907229Seric smtpquit(name, showresp)
1914865Seric 	char *name;
1927229Seric 	bool showresp;
1934865Seric {
1944865Seric 	register int i;
1954865Seric 
1966051Seric 	if (SmtpPid < 0)
1977229Seric 		return;
1987229Seric 	smtpmessage("QUIT");
1997229Seric 	(void) reply();
2007229Seric 	(void) fclose(SmtpIn);
2017229Seric 	(void) fclose(SmtpOut);
2027229Seric 	i = endmailer(SmtpPid, name);
2037229Seric 	if (showresp)
2047229Seric 		giveresponse(i, TRUE, LocalMailer);
2054865Seric }
2064865Seric /*
2074684Seric **  REPLY -- read arpanet reply
2084684Seric **
2094684Seric **	Parameters:
2104796Seric **		none.
2114684Seric **
2124684Seric **	Returns:
2134684Seric **		reply code it reads.
2144684Seric **
2154684Seric **	Side Effects:
2164684Seric **		flushes the mail file.
2174684Seric */
2184684Seric 
2194796Seric reply()
2204684Seric {
2214865Seric 	(void) fflush(SmtpOut);
2224684Seric 
2234796Seric 	if (Debug)
2244796Seric 		printf("reply\n");
2254796Seric 
226*7356Seric 	/*
227*7356Seric 	**  Read the input line, being careful not to hang.
228*7356Seric 	*/
229*7356Seric 
2304684Seric 	for (;;)
2314684Seric 	{
2324684Seric 		char buf[MAXLINE];
2334684Seric 		register int r;
234*7356Seric 		register char *p;
2354684Seric 
236*7356Seric 		/* arrange to time out the read */
237*7356Seric 		if (setjmp(TickFrame) != 0)
2384684Seric 			return (-1);
239*7356Seric 		(void) alarm(ReadTimeout);
240*7356Seric 
241*7356Seric 		/* actually do the read */
242*7356Seric 		p = fgets(buf, sizeof buf, SmtpIn);
243*7356Seric 
244*7356Seric 		/* clean up timeout and check for errors */
245*7356Seric 		(void) alarm(0);
246*7356Seric 		if (p == NULL)
247*7356Seric 			return (-1);
248*7356Seric 
249*7356Seric 		/* log the input in the transcript for future error returns */
2507229Seric 		if (Verbose && !HoldErrs)
2514684Seric 			fputs(buf, stdout);
2527229Seric 		fputs(buf, Xscript);
253*7356Seric 
254*7356Seric 		/* if continuation is required, we can go on */
2554796Seric 		if (buf[3] == '-' || !isdigit(buf[0]))
2564684Seric 			continue;
257*7356Seric 
258*7356Seric 		/* decode the reply code */
2594684Seric 		r = atoi(buf);
260*7356Seric 
261*7356Seric 		/* extra semantics: 0xx codes are "informational" */
2624684Seric 		if (r < 100)
2634684Seric 			continue;
264*7356Seric 
2654684Seric 		return (r);
2664684Seric 	}
2674684Seric }
2684796Seric /*
2694865Seric **  SMTPMESSAGE -- send message to server
2704796Seric **
2714796Seric **	Parameters:
2724796Seric **		f -- format
2734796Seric **		a, b, c -- parameters
2744796Seric **
2754796Seric **	Returns:
2764796Seric **		none.
2774796Seric **
2784796Seric **	Side Effects:
2794865Seric **		writes message to SmtpOut.
2804796Seric */
2814796Seric 
2824865Seric /*VARARGS1*/
2834865Seric smtpmessage(f, a, b, c)
2844796Seric 	char *f;
2854796Seric {
2864796Seric 	char buf[100];
2874796Seric 
2884865Seric 	(void) sprintf(buf, f, a, b, c);
2897229Seric 	if (Debug || (Verbose && !HoldErrs))
2907229Seric 		printf(">>> %s\n", buf);
2917229Seric 	fprintf(Xscript, ">>> %s\n", buf);
2927229Seric 	fprintf(SmtpOut, "%s\r\n", buf);
2934796Seric }
2945182Seric 
2955182Seric # endif SMTP
296