⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usersmtp.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
字号:
/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. * *  Sendmail *  Copyright (c) 1983  Eric P. Allman *  Berkeley, California */# include <ctype.h># include <sysexits.h># include <errno.h># include "sendmail.h"SCCSID(@(#)usersmtp.c 1.1 92/07/30 SMI (no SMTP)); /* from UCB 5.9 3/13/88  */# ifdef SMTP/***  USERSMTP -- run SMTP protocol from the user end.****	This protocol is described in RFC821.*/#define REPLYTYPE(r)	((r) / 100)		/* first digit of reply code */#define REPLYCLASS(r)	(((r) / 10) % 10)	/* second digit of reply code */#define SMTPCLOSING	421			/* "Service Shutting Down" */char	SmtpMsgBuffer[MAXLINE];		/* buffer for commands */char	SmtpReplyBuffer[MAXLINE];	/* buffer for replies */char	SmtpError[MAXLINE] = "";	/* save failure error messages */bool	SmtpLogged;			/* set when logged "connected to" */FILE	*SmtpOut;			/* output file */FILE	*SmtpIn;			/* input file */int	SmtpPid;			/* pid of mailer */int	SmtpFirstErrno;			/* Meaningful error number *//* following represents the state of the SMTP connection */int	SmtpState;			/* connection state, see below */#define SMTP_CLOSED	0		/* connection is closed */#define SMTP_OPEN	1		/* connection is open for business */#define SMTP_SSD	2		/* service shutting down */#define SMTP_TIMEDOUT	3		/* never got greeting *//***  SMTPINIT -- initialize SMTP.****	Opens the connection and sends the initial protocol.****	Parameters:**		m -- mailer to create connection to.**		pvp -- pointer to parameter vector to pass to**			the mailer.****	Returns:**		appropriate exit status -- EX_OK on success.**		If not EX_OK, it should close the connection.****	Side Effects:**		creates connection and sends initial protocol.*/smtpinit(m, pvp)	struct mailer *m;	char **pvp;{	register int r;	EVENT *gte;	char buf[MAXNAME];	time_t tempTimeout;	/*	**  Open the connection to the mailer.	*/#ifdef DEBUG	if (SmtpState == SMTP_OPEN)		syserr("smtpinit: already open");#endif DEBUG	SmtpIn = SmtpOut = NULL;	SmtpFirstErrno = 0;		SmtpState = SMTP_CLOSED;	SmtpError[0] = '\0';	SmtpPhase = "user open";	SmtpLogged = FALSE;	SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn);	if (SmtpPid < 0)	{# ifdef DEBUG		if (tTd(18, 1))			printf("smtpinit: cannot open %s: stat %d errno %d\n",			   pvp[0], ExitStat, errno);# endif DEBUG		if (CurEnv->e_xfp != NULL)		{			register char *p;			extern char *errstring();			extern char *statstring();			extern char *pintvl();			long timeleft;			if (ExitStat==EX_NOHOST) {				fprintf(CurEnv->e_xfp,			"421 Host %s not found for mailer %s.\n",					pvp[1], m->m_name);				return (ExitStat);			}			if (errno == 0)			{				p = statstring(ExitStat);				fprintf(CurEnv->e_xfp,					"%.3s %s via %s... %s",					p, pvp[1], m->m_name, p);			}			else			{				fprintf(CurEnv->e_xfp,					"421 %s: %s",					pvp[1], errstring(errno));			}			timeleft = CurEnv->e_ctime + TimeOut - curtime();			timeleft = (timeleft+1800)/3600;			if (timeleft > 0)			       fprintf(CurEnv->e_xfp,			         ", will keep trying for %s",				 pintvl(timeleft*3600,FALSE) );			fprintf(CurEnv->e_xfp,"\n");		}		return (ExitStat);	}	SmtpState = SMTP_OPEN;	/*	**  Get the greeting message.	**	This should appear spontaneously.  Give it less time to	**	happen than the normal read timeout since it is more	**	common, and we have less to lose since we have not started	**	the SMTP conversation yet.	*/	SmtpPhase = "greeting wait";	tempTimeout = ReadTimeout;	ReadTimeout = (time_t) 120;	r = reply(m);	ReadTimeout = tempTimeout;	if (r < 0 || REPLYTYPE(r) != 2) {		SmtpState = SMTP_TIMEDOUT;		goto tempfail;	}	/*	**  Send the HELO command.	**	My mother taught me to always introduce myself.	*/	smtpmessage("HELO %s", m, MyHostName);	SmtpPhase = "HELO wait";	r = reply(m);	if (r < 0)		goto tempfail;	else if (REPLYTYPE(r) == 5)		goto unavailable;	else if (REPLYTYPE(r) != 2)		goto tempfail;	/*	**  If this is expected to be another sendmail, send some internal	**  commands.	*/	if (bitnset(M_INTERNAL, m->m_flags))	{		/* tell it to be verbose */		smtpmessage("VERB", m);		r = reply(m);		if (r < 0)			goto tempfail;		/* tell it we will be sending one transaction only */		smtpmessage("ONEX", m);		r = reply(m);		if (r < 0)			goto tempfail;	}	/*	**  Send the MAIL command.	**	Designates the sender.	*/	expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);	if (CurEnv->e_from.q_mailer == LocalMailer ||	    !bitnset(M_FROMPATH, m->m_flags))	{		smtpmessage("MAIL From:<%s>", m, buf);	}	else	{		smtpmessage("MAIL From:<@%s%c%s>", m, MyHostName,			buf[0] == '@' ? ',' : ':', buf);	}	SmtpPhase = "MAIL wait";	r = reply(m);	if (r < 0 || REPLYTYPE(r) == 4)		goto tempfail;	else if (r == 250)		return (EX_OK);	else if (r == 552)		goto unavailable;	/* protocol error -- close up */	smtpquit(m);	return (EX_PROTOCOL);	/* signal a temporary failure */  tempfail:	smtpquit(m);	if (SmtpFirstErrno) errno = SmtpFirstErrno;	return (EX_TEMPFAIL);	/* signal service unavailable */  unavailable:	smtpquit(m);	return (EX_UNAVAILABLE);}/***  SMTPRCPT -- designate recipient.****	Parameters:**		to -- address of recipient.**		m -- the mailer we are sending to.****	Returns:**		exit status corresponding to recipient status.****	Side Effects:**		Sends the mail via SMTP.*/smtprcpt(to, m)	ADDRESS *to;	register MAILER *m;{	register int r;	extern char *remotename();	smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE));	SmtpPhase = "RCPT wait";	r = reply(m);	if (r < 0 || REPLYTYPE(r) == 4)	  {		if (SmtpFirstErrno) errno = SmtpFirstErrno;		return (EX_TEMPFAIL);	  }	else if (REPLYTYPE(r) == 2)		return (EX_OK);	else if (r == 550 || r == 551 || r == 553)		return (EX_NOUSER);	else if (r == 552 || r == 554)		return (EX_UNAVAILABLE);	return (EX_PROTOCOL);}/***  SMTPDATA -- send the data and clean up the transaction.****	Parameters:**		m -- mailer being sent to.**		e -- the envelope for this message.****	Returns:**		exit status corresponding to DATA command.****	Side Effects:**		none.*/smtpdata(m, e)	struct mailer *m;	register ENVELOPE *e;{	register int r;	/*	**  Send the data.	**	First send the command and check that it is ok.	**	Then send the data.	**	Follow it up with a dot to terminate.	**	Finally get the results of the transaction.	*/	/* send the command and check ok to proceed */	smtpmessage("DATA", m);	SmtpPhase = "DATA wait";	r = reply(m);	if (r < 0 || REPLYTYPE(r) == 4)	  {		if (SmtpFirstErrno) errno = SmtpFirstErrno;		return (EX_TEMPFAIL);	  }	else if (r == 554)		return (EX_UNAVAILABLE);	else if (r != 354)		return (EX_PROTOCOL);	/* now output the actual message */	(*e->e_puthdr)(SmtpOut, m, CurEnv);	putline("\n", SmtpOut, m);	(*e->e_putbody)(SmtpOut, m, CurEnv);	/* terminate the message */	fprintf(SmtpOut, ".%s", m->m_eol);	if (Verbose && !HoldErrs)		nmessage(Arpa_Info, ">>> .");	/* check for the results of the transaction */	SmtpPhase = "result wait";	r = reply(m);	if (r < 0 || REPLYTYPE(r) == 4)	  {		if (SmtpFirstErrno) errno = SmtpFirstErrno;		return (EX_TEMPFAIL);	  }	else if (r == 250)		return (EX_OK);	else if (r == 552 || r == 554)		return (EX_UNAVAILABLE);	return (EX_PROTOCOL);}/***  SMTPQUIT -- close the SMTP connection.****	Parameters:**		m -- a pointer to the mailer.****	Returns:**		none.****	Side Effects:**		sends the final protocol and closes the connection.*/smtpquit(m)	register MAILER *m;{	int i;	/* if the connection is already closed, don't bother */	if (SmtpIn == NULL)		return;	/* send the quit message if not a forced quit */	if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD)	{		SmtpPhase = "final wait";		smtpmessage("QUIT", m);		(void) reply(m);		if (SmtpState == SMTP_CLOSED)			return;	}	/* now actually close the connection */	closeconnection(fileno(SmtpIn));	/* Mark closed in stab */	(void) fclose(SmtpIn);	(void) fclose(SmtpOut);	SmtpIn = SmtpOut = NULL;	SmtpState = SMTP_CLOSED;	/* and pick up the zombie */	i = endmailer(SmtpPid, m->m_argv[0]);	if (i != EX_OK)		syserr("smtpquit %s: stat %d", m->m_argv[0], i);}/***  REPLY -- read arpanet reply****	Parameters:**		m -- the mailer we are reading the reply from.****	Returns:**		reply code it reads.****	Side Effects:**		flushes the mail file.*/reply(m)	MAILER *m;{	if (SmtpOut == NULL || SmtpIn == NULL) 		return(SMTPCLOSING);	(void) fflush(SmtpOut);	if (tTd(18, 1))		printf("reply\n");	/*	**  Read the input line, being careful not to hang.	*/	for (;;)	{		register int r;		register char *p;		/* actually do the read */		if (CurEnv->e_xfp != NULL)			(void) fflush(CurEnv->e_xfp);	/* for debugging */		/* if we are in the process of closing just give the code */		if (SmtpState == SMTP_CLOSED)			return (SMTPCLOSING);		/* get the line from the other side */		p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn);		if (p == NULL)		{			  /*			   * Make sure we produce a temporary error			   * if the remote end just closed early.			   */			 if (errno==0)			 	errno = ECONNRESET;			if (SmtpFirstErrno==0)				SmtpFirstErrno = errno;			if (errno != ECONNRESET && errno != ETIMEDOUT)				syserr("network read error");# ifdef DEBUG			/* if debugging, pause so we can see state */			if (tTd(18, 100))				pause();# endif DEBUG			SmtpState = SMTP_CLOSED;			smtpquit(m);			return (-1);		}		fixcrlf(SmtpReplyBuffer, TRUE);		if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL)		{			  /*			   * serious error -- log the previous command 			   * and connection message if needed.			   */			if (SmtpLogged == FALSE && RealHostName) {				SmtpLogged = TRUE;				fprintf(CurEnv->e_xfp, 				  "Connected to %s:\n", RealHostName);			}			if (SmtpMsgBuffer[0] != '\0')				fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer);			SmtpMsgBuffer[0] = '\0';			/* now log the message as from the other side */			fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer);		}		/* display the input for verbose mode */		if (Verbose && !HoldErrs)			nmessage(Arpa_Info, "%s", SmtpReplyBuffer);		/* if continuation is required, we can go on */		if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0]))			continue;		/* decode the reply code */		r = atoi(SmtpReplyBuffer);		/* extra semantics: 0xx codes are "informational" */		if (r < 100)			continue;		/* save temporary failure messages for posterity */		if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')			(void) strcpy(SmtpError, SmtpReplyBuffer+4);		/* reply code 421 is "Service Shutting Down" */		if (r == SMTPCLOSING && SmtpState != SMTP_SSD)		{			/* send the quit protocol */			SmtpState = SMTP_SSD;			smtpquit(m);		}		return (r);	}}/***  SMTPMESSAGE -- send message to server****	Parameters:**		f -- format**		m -- the mailer to control formatting.**		a, b, c -- parameters****	Returns:**		none.****	Side Effects:**		writes message to SmtpOut.*//*VARARGS1*/smtpmessage(f, m, a, b, c)	char *f;	MAILER *m;{	(void) sprintf(SmtpMsgBuffer, f, a, b, c);	setproctitle("%s To %s: %s", CurEnv->e_id, 			RealHostName, SmtpMsgBuffer);	if (tTd(18, 1) || (Verbose && !HoldErrs))		nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer);	if (SmtpOut != NULL)		fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol);}# endif SMTP

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -