14796Seric # include <ctype.h>
24684Seric # include <sysexits.h>
34865Seric # include "sendmail.h"
44684Seric 
55182Seric # ifndef SMTP
6*9341Seric SCCSID(@(#)usersmtp.c	3.27		11/24/82	(no SMTP));
75182Seric # else SMTP
84684Seric 
9*9341Seric SCCSID(@(#)usersmtp.c	3.27		11/24/82);
105182Seric 
114684Seric /*
124865Seric **  SMTPINIT -- initialize SMTP.
134684Seric **
144865Seric **	Opens the connection and sends the initial protocol.
154684Seric **
164684Seric **	Parameters:
174865Seric **		m -- mailer to create connection to.
184865Seric **		pvp -- pointer to parameter vector to pass to
194865Seric **			the mailer.
204865Seric **		ctladdr -- controlling address for this mailer.
214684Seric **
224684Seric **	Returns:
234865Seric **		appropriate exit status -- EX_OK on success.
244684Seric **
254684Seric **	Side Effects:
264865Seric **		creates connection and sends initial protocol.
274684Seric */
284684Seric 
294865Seric # define REPLYTYPE(r)	((r) / 100)
307963Seric # define REPLYCLASS(r)	(((r) / 10) % 10)
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];
447356Seric 	extern tick();
457685Seric 	extern char *canonname();
464684Seric 
474865Seric 	/*
484865Seric 	**  Open the connection to the mailer.
494865Seric 	*/
504684Seric 
516051Seric 	SmtpIn = SmtpOut = NULL;
524865Seric 	SmtpPid = openmailer(m, pvp, ctladdr, TRUE, &SmtpOut, &SmtpIn);
536051Seric 	if (SmtpPid < 0)
546051Seric 	{
556051Seric 		SmtpErrstat = ExitStat;
566051Seric # ifdef DEBUG
577677Seric 		if (tTd(18, 1))
586051Seric 			printf("smtpinit: cannot open: Errstat %d errno %d\n",
596051Seric 			   SmtpErrstat, errno);
606051Seric # endif DEBUG
616051Seric 		return (ExitStat);
626051Seric 	}
634796Seric 
644865Seric 	/*
654865Seric 	**  Get the greeting message.
664865Seric 	**	This should appear spontaneously.
674865Seric 	*/
684797Seric 
694865Seric 	r = reply();
708005Seric 	if (r < 0 || REPLYTYPE(r) != 2)
714865Seric 		return (EX_TEMPFAIL);
724684Seric 
734865Seric 	/*
744976Seric 	**  Send the HELO command.
757963Seric 	**	My mother taught me to always introduce myself.
764976Seric 	*/
774976Seric 
784976Seric 	smtpmessage("HELO %s", HostName);
794976Seric 	r = reply();
808005Seric 	if (r < 0)
818005Seric 		return (EX_TEMPFAIL);
828005Seric 	else if (REPLYTYPE(r) == 5)
834976Seric 		return (EX_UNAVAILABLE);
847963Seric 	else if (REPLYTYPE(r) != 2)
854976Seric 		return (EX_TEMPFAIL);
864976Seric 
874976Seric 	/*
889315Seric 	**  If this is expected to be another sendmail, send some internal
899315Seric 	**  commands.
909315Seric 	*/
919315Seric 
929315Seric 	if (bitset(M_INTERNAL, m->m_flags))
939315Seric 	{
949315Seric 		/* tell it to be verbose */
959315Seric 		smtpmessage("VERB");
969315Seric 		r = reply();
979315Seric 		if (r < 0)
989315Seric 			return (EX_TEMPFAIL);
999315Seric 
1009315Seric 		/* tell it we will be sending one transaction only */
1019315Seric 		smtpmessage("ONEX");
1029315Seric 		r = reply();
1039315Seric 		if (r < 0)
1049315Seric 			return (EX_TEMPFAIL);
1059315Seric 	}
1069315Seric 
1079315Seric 	/*
1084865Seric 	**  Send the MAIL command.
1094865Seric 	**	Designates the sender.
1104865Seric 	*/
1114796Seric 
1126980Seric 	expand("$g", buf, &buf[sizeof buf - 1], CurEnv);
1138436Seric 	if (CurEnv->e_from.q_mailer == LocalMailer ||
1148436Seric 	    !bitset(M_FULLSMTP, m->m_flags))
1158436Seric 	{
1168436Seric 		smtpmessage("MAIL From:<%s>", canonname(buf, 1));
1178436Seric 	}
1188436Seric 	else
1198436Seric 	{
1208436Seric 		smtpmessage("MAIL From:<@%s%c%s>", HostName,
1218436Seric 			    buf[0] == '@' ? ',' : ':', canonname(buf, 1));
1228436Seric 	}
1234865Seric 	r = reply();
1248005Seric 	if (r < 0 || REPLYTYPE(r) == 4)
1254865Seric 		return (EX_TEMPFAIL);
1267963Seric 	else if (r == 250)
1277963Seric 		return (EX_OK);
1287963Seric 	else if (r == 552)
1297963Seric 		return (EX_UNAVAILABLE);
1307964Seric 	return (EX_PROTOCOL);
1314684Seric }
1324684Seric /*
1334976Seric **  SMTPRCPT -- designate recipient.
1344797Seric **
1354797Seric **	Parameters:
1364865Seric **		to -- address of recipient.
1374797Seric **
1384797Seric **	Returns:
1394865Seric **		exit status corresponding to recipient status.
1404797Seric **
1414797Seric **	Side Effects:
1424865Seric **		Sends the mail via SMTP.
1434797Seric */
1444797Seric 
1454976Seric smtprcpt(to)
1464865Seric 	ADDRESS *to;
1474797Seric {
1484797Seric 	register int r;
1497685Seric 	extern char *canonname();
1504797Seric 
1516051Seric 	if (SmtpPid < 0)
1526051Seric 		return (SmtpErrstat);
1536051Seric 
1548354Seric 	smtpmessage("RCPT To:<%s>", canonname(to->q_user, 2));
1554865Seric 
1564797Seric 	r = reply();
1578005Seric 	if (r < 0 || REPLYTYPE(r) == 4)
1584865Seric 		return (EX_TEMPFAIL);
1597963Seric 	else if (REPLYTYPE(r) == 2)
1607963Seric 		return (EX_OK);
1617964Seric 	else if (r == 550 || r == 551 || r == 553)
1627964Seric 		return (EX_NOUSER);
1637964Seric 	else if (r == 552 || r == 554)
1647964Seric 		return (EX_UNAVAILABLE);
1657964Seric 	return (EX_PROTOCOL);
1664797Seric }
1674797Seric /*
1684865Seric **  SMTPFINISH -- finish up sending all the SMTP protocol.
1694684Seric **
1704684Seric **	Parameters:
1714865Seric **		m -- mailer being sent to.
1726980Seric **		e -- the envelope for this message.
1734684Seric **
1744684Seric **	Returns:
1754976Seric **		exit status corresponding to DATA command.
1764684Seric **
1774684Seric **	Side Effects:
1784865Seric **		none.
1794684Seric */
1804684Seric 
1816980Seric smtpfinish(m, e)
1824865Seric 	struct mailer *m;
1836980Seric 	register ENVELOPE *e;
1844684Seric {
1854684Seric 	register int r;
1864684Seric 
1876051Seric 	if (SmtpPid < 0)
1886051Seric 		return (SmtpErrstat);
1896051Seric 
1904797Seric 	/*
1914797Seric 	**  Send the data.
1924797Seric 	**	Dot hiding is done here.
1934797Seric 	*/
1944797Seric 
1954865Seric 	smtpmessage("DATA");
1964796Seric 	r = reply();
1978005Seric 	if (r < 0 || REPLYTYPE(r) == 4)
1984797Seric 		return (EX_TEMPFAIL);
1997963Seric 	else if (r == 554)
2007963Seric 		return (EX_UNAVAILABLE);
2017963Seric 	else if (r != 354)
2027964Seric 		return (EX_PROTOCOL);
2036980Seric 	(*e->e_puthdr)(SmtpOut, m, CurEnv);
2046980Seric 	fprintf(SmtpOut, "\n");
2056980Seric 	(*e->e_putbody)(SmtpOut, m, TRUE);
2064865Seric 	smtpmessage(".");
2074796Seric 	r = reply();
2088005Seric 	if (r < 0 || REPLYTYPE(r) == 4)
2094797Seric 		return (EX_TEMPFAIL);
2107963Seric 	else if (r == 250)
2117963Seric 		return (EX_OK);
2127963Seric 	else if (r == 552 || r == 554)
2137963Seric 		return (EX_UNAVAILABLE);
2147964Seric 	return (EX_PROTOCOL);
2154684Seric }
2164684Seric /*
2174865Seric **  SMTPQUIT -- close the SMTP connection.
2184865Seric **
2194865Seric **	Parameters:
2204865Seric **		name -- name of mailer we are quitting.
2217229Seric **		showresp -- if set, give a response message.
2224865Seric **
2234865Seric **	Returns:
2244865Seric **		none.
2254865Seric **
2264865Seric **	Side Effects:
2274865Seric **		sends the final protocol and closes the connection.
2284865Seric */
2294865Seric 
2307229Seric smtpquit(name, showresp)
2314865Seric 	char *name;
2327229Seric 	bool showresp;
2334865Seric {
2344865Seric 	register int i;
2354865Seric 
2366051Seric 	if (SmtpPid < 0)
2377229Seric 		return;
2387229Seric 	smtpmessage("QUIT");
2397229Seric 	(void) reply();
2407229Seric 	(void) fclose(SmtpIn);
2417229Seric 	(void) fclose(SmtpOut);
2427229Seric 	i = endmailer(SmtpPid, name);
2437229Seric 	if (showresp)
2447229Seric 		giveresponse(i, TRUE, LocalMailer);
2454865Seric }
2464865Seric /*
2474684Seric **  REPLY -- read arpanet reply
2484684Seric **
2494684Seric **	Parameters:
2504796Seric **		none.
2514684Seric **
2524684Seric **	Returns:
2534684Seric **		reply code it reads.
2544684Seric **
2554684Seric **	Side Effects:
2564684Seric **		flushes the mail file.
2574684Seric */
2584684Seric 
2594796Seric reply()
2604684Seric {
2614865Seric 	(void) fflush(SmtpOut);
2624684Seric 
2637677Seric 	if (tTd(18, 1))
2644796Seric 		printf("reply\n");
2654796Seric 
2667356Seric 	/*
2677356Seric 	**  Read the input line, being careful not to hang.
2687356Seric 	*/
2697356Seric 
2704684Seric 	for (;;)
2714684Seric 	{
2724684Seric 		char buf[MAXLINE];
2734684Seric 		register int r;
2747356Seric 		register char *p;
2754684Seric 
2767685Seric 		/* actually do the read */
277*9341Seric 		if (Xscript != NULL)
278*9341Seric 			(void) fflush(Xscript);		/* for debugging */
2797685Seric 		p = sfgets(buf, sizeof buf, SmtpIn);
2807356Seric 		if (p == NULL)
2817356Seric 			return (-1);
2828237Seric 		fixcrlf(buf, TRUE);
2837356Seric 
2847356Seric 		/* log the input in the transcript for future error returns */
2857229Seric 		if (Verbose && !HoldErrs)
2868237Seric 			nmessage(Arpa_Info, "%s", buf);
287*9341Seric 		if (Xscript != NULL)
288*9341Seric 			fprintf(Xscript, "%s\n", buf);
2897356Seric 
2907356Seric 		/* if continuation is required, we can go on */
2914796Seric 		if (buf[3] == '-' || !isdigit(buf[0]))
2924684Seric 			continue;
2937356Seric 
2947356Seric 		/* decode the reply code */
2954684Seric 		r = atoi(buf);
2967356Seric 
2977356Seric 		/* extra semantics: 0xx codes are "informational" */
2984684Seric 		if (r < 100)
2994684Seric 			continue;
3007356Seric 
3014684Seric 		return (r);
3024684Seric 	}
3034684Seric }
3044796Seric /*
3054865Seric **  SMTPMESSAGE -- send message to server
3064796Seric **
3074796Seric **	Parameters:
3084796Seric **		f -- format
3094796Seric **		a, b, c -- parameters
3104796Seric **
3114796Seric **	Returns:
3124796Seric **		none.
3134796Seric **
3144796Seric **	Side Effects:
3154865Seric **		writes message to SmtpOut.
3164796Seric */
3174796Seric 
3184865Seric /*VARARGS1*/
3194865Seric smtpmessage(f, a, b, c)
3204796Seric 	char *f;
3214796Seric {
3224796Seric 	char buf[100];
3234796Seric 
3244865Seric 	(void) sprintf(buf, f, a, b, c);
3257677Seric 	if (tTd(18, 1) || (Verbose && !HoldErrs))
3268237Seric 		nmessage(Arpa_Info, ">>> %s", buf);
327*9341Seric 	if (Xscript != NULL)
328*9341Seric 		fprintf(Xscript, ">>> %s\n", buf);
3297229Seric 	fprintf(SmtpOut, "%s\r\n", buf);
3304796Seric }
3315182Seric 
3325182Seric # endif SMTP
333