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

📄 usersmtp.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		**  If putbody() couldn't finish due to a timeout,
		**  rewind it here in the timeout handler.  See
		**  comments at the end of putbody() for reasoning.
		*/

		if (e->e_dfp != NULL)
			(void) bfrewind(e->e_dfp);

		errno = mci->mci_errno;
		syserr("451 4.4.1 timeout writing message to %s", CurHostName);
		smtpquit(m, mci, e);
		return EX_TEMPFAIL;
	}

	if (tTd(18, 101))
	{
		/* simulate a DATA timeout */
		timeout = 1;
	}
	else
		timeout = DATA_PROGRESS_TIMEOUT;

	ev = setevent(timeout, datatimeout, 0);


	if (tTd(18, 101))
	{
		/* simulate a DATA timeout */
		(void) sleep(1);
	}

	/*
	**  Output the actual message.
	*/

	(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
	(*e->e_putbody)(mci, e, NULL);

	/*
	**  Cleanup after sending message.
	*/

	clrevent(ev);

# if _FFR_CATCH_BROKEN_MTAS
	{
		fd_set readfds;
		struct timeval timeout;

		FD_ZERO(&readfds);
		FD_SET(fileno(mci->mci_in), &readfds);
		timeout.tv_sec = 0;
		timeout.tv_usec = 0;
		if (select(fileno(mci->mci_in) + 1, FDSET_CAST &readfds,
			   NULL, NULL, &timeout) > 0 &&
		    FD_ISSET(fileno(mci->mci_in), &readfds))
		{
			/* terminate the message */
			fprintf(mci->mci_out, ".%s", m->m_eol);
			if (TrafficLogFile != NULL)
				fprintf(TrafficLogFile, "%05d >>> .\n",
					(int) getpid());
			if (Verbose)
				nmessage(">>> .");

			mci->mci_errno = EIO;
			mci->mci_state = MCIS_ERROR;
			mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL);
			smtpquit(m, mci, e);
			return EX_PROTOCOL;
		}
	}
# endif /* _FFR_CATCH_BROKEN_MTAS */

	if (ferror(mci->mci_out))
	{
		/* error during processing -- don't send the dot */
		mci->mci_errno = EIO;
		mci->mci_state = MCIS_ERROR;
		mci_setstat(mci, EX_IOERR, "4.4.2", NULL);
		smtpquit(m, mci, e);
		return EX_IOERR;
	}

	/* terminate the message */
	fprintf(mci->mci_out, ".%s", m->m_eol);
	if (TrafficLogFile != NULL)
		fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid());
	if (Verbose)
		nmessage(">>> .");

	/* check for the results of the transaction */
	SmtpPhase = mci->mci_phase = "client DATA status";
	sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
			CurHostName, mci->mci_phase);
	if (bitnset(M_LMTP, m->m_flags))
		return EX_OK;
	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc);
	if (r < 0)
	{
		smtpquit(m, mci, e);
		return EX_TEMPFAIL;
	}
	mci->mci_state = MCIS_OPEN;
	xstat = EX_NOTSTICKY;
	if (r == 452)
		rstat = EX_TEMPFAIL;
	else if (REPLYTYPE(r) == 4)
		rstat = xstat = EX_TEMPFAIL;
	else if (REPLYCLASS(r) != 5)
		rstat = xstat = EX_PROTOCOL;
	else if (REPLYTYPE(r) == 2)
		rstat = xstat = EX_OK;
	else if (REPLYTYPE(r) == 5)
		rstat = EX_UNAVAILABLE;
	else
		rstat = EX_PROTOCOL;
	mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)),
		    SmtpReplyBuffer);
	if (e->e_statmsg != NULL)
		free(e->e_statmsg);
	if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
	    (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
		r += 5;
	else
		r = 4;
	e->e_statmsg = newstr(&SmtpReplyBuffer[r]);
	if (rstat != EX_PROTOCOL)
		return rstat;
	if (LogLevel > 1)
	{
		sm_syslog(LOG_CRIT, e->e_id,
			  "%.100s: SMTP DATA-2 protocol error: %s",
			  CurHostName,
			  shortenstring(SmtpReplyBuffer, 403));
	}
	return rstat;
}


static void
datatimeout()
{
	if (DataProgress)
	{
		time_t timeout;
		register EVENT *ev;

		/* check back again later */
		if (tTd(18, 101))
		{
			/* simulate a DATA timeout */
			timeout = 1;
		}
		else
			timeout = DATA_PROGRESS_TIMEOUT;

		DataProgress = FALSE;
		ev = setevent(timeout, datatimeout, 0);
	}
	else
	{
		/* no progress, give up */
		longjmp(CtxDataTimeout, 1);
	}
}
/*
**  SMTPGETSTAT -- get status code from DATA in LMTP
**
**	Parameters:
**		m -- the mailer to which we are sending the message.
**		mci -- the mailer connection structure.
**		e -- the current envelope.
**
**	Returns:
**		The exit status corresponding to the reply code.
*/

int
smtpgetstat(m, mci, e)
	MAILER *m;
	MCI *mci;
	ENVELOPE *e;
{
	int r;
	int status;
	char *enhsc;

	enhsc = NULL;
	/* check for the results of the transaction */
	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc);
	if (r < 0)
	{
		smtpquit(m, mci, e);
		return EX_TEMPFAIL;
	}
	if (REPLYTYPE(r) == 4)
		status = EX_TEMPFAIL;
	else if (REPLYCLASS(r) != 5)
		status = EX_PROTOCOL;
	else if (REPLYTYPE(r) == 2)
		status = EX_OK;
	else if (REPLYTYPE(r) == 5)
		status = EX_UNAVAILABLE;
	else
		status = EX_PROTOCOL;
	if (e->e_statmsg != NULL)
		free(e->e_statmsg);
	if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
	    (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
		r += 5;
	else
		r = 4;
	e->e_statmsg = newstr(&SmtpReplyBuffer[r]);
	mci_setstat(mci, status, ENHSCN(enhsc, smtptodsn(r)),
		    SmtpReplyBuffer);
	if (LogLevel > 1 && status == EX_PROTOCOL)
	{
		sm_syslog(LOG_CRIT, e->e_id,
			  "%.100s: SMTP DATA-3 protocol error: %s",
			  CurHostName,
			  shortenstring(SmtpReplyBuffer, 403));
	}
	return status;
}
/*
**  SMTPQUIT -- close the SMTP connection.
**
**	Parameters:
**		m -- a pointer to the mailer.
**		mci -- the mailer connection information.
**		e -- the current envelope.
**
**	Returns:
**		none.
**
**	Side Effects:
**		sends the final protocol and closes the connection.
*/

void
smtpquit(m, mci, e)
	register MAILER *m;
	register MCI *mci;
	ENVELOPE *e;
{
	bool oldSuprErrs = SuprErrs;
	int rcode;

	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
	if (CurHostName == NULL)
		CurHostName = MyHostName;

	/*
	**	Suppress errors here -- we may be processing a different
	**	job when we do the quit connection, and we don't want the
	**	new job to be penalized for something that isn't it's
	**	problem.
	*/

	SuprErrs = TRUE;

	/* send the quit message if we haven't gotten I/O error */
	if (mci->mci_state != MCIS_ERROR &&
	    mci->mci_state != MCIS_QUITING)
	{
		int origstate = mci->mci_state;

		SmtpPhase = "client QUIT";
		mci->mci_state = MCIS_QUITING;
		smtpmessage("QUIT", m, mci);
		(void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL);
		SuprErrs = oldSuprErrs;
		if (mci->mci_state == MCIS_CLOSED ||
		    origstate == MCIS_CLOSED)
			return;
	}

	/* now actually close the connection and pick up the zombie */
	rcode = endmailer(mci, e, NULL);
	if (rcode != EX_OK)
	{
		char *mailer = NULL;

		if (mci->mci_mailer != NULL &&
		    mci->mci_mailer->m_name != NULL)
			mailer = mci->mci_mailer->m_name;

		/* look for naughty mailers */
		sm_syslog(LOG_ERR, e->e_id,
			  "smtpquit: mailer%s%s exited with exit value %d\n",
			  mailer == NULL ? "" : " ",
			  mailer == NULL ? "" : mailer,
			  rcode);
	}

	SuprErrs = oldSuprErrs;
}
/*
**  SMTPRSET -- send a RSET (reset) command
*/

void
smtprset(m, mci, e)
	register MAILER *m;
	register MCI *mci;
	ENVELOPE *e;
{
	int r;

	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
	if (CurHostName == NULL)
		CurHostName = MyHostName;

	SmtpPhase = "client RSET";
	smtpmessage("RSET", m, mci);
	r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL);
	if (r < 0)
		mci->mci_state = MCIS_ERROR;
	else
	{
		/*
		**  Any response is deemed to be acceptable.
		**  The standard does not state the proper action
		**  to take when a value other than 250 is received.
		*/

		mci->mci_state = MCIS_OPEN;
		return;
	}
	smtpquit(m, mci, e);
}
/*
**  SMTPPROBE -- check the connection state
*/

int
smtpprobe(mci)
	register MCI *mci;
{
	int r;
	MAILER *m = mci->mci_mailer;
	ENVELOPE *e;
	extern ENVELOPE BlankEnvelope;

	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
	if (CurHostName == NULL)
		CurHostName = MyHostName;

	e = &BlankEnvelope;
	SmtpPhase = "client probe";
	smtpmessage("RSET", m, mci);
	r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL);
	if (r < 0 || REPLYTYPE(r) != 2)
		smtpquit(m, mci, e);
	return r;
}
/*
**  REPLY -- read arpanet reply
**
**	Parameters:
**		m -- the mailer we are reading the reply from.
**		mci -- the mailer connection info structure.
**		e -- the current envelope.
**		timeout -- the timeout for reads.
**		pfunc -- processing function called on each line of response.
**			If null, no special processing is done.
**
**	Returns:
**		reply code it reads.
**
**	Side Effects:
**		flushes the mail file.
*/

int
reply(m, mci, e, timeout, pfunc, enhstat)
	MAILER *m;
	MCI *mci;
	ENVELOPE *e;
	time_t timeout;
	void (*pfunc)();
	char **enhstat;
{
	register char *bufp;
	register int r;
	bool firstline = TRUE;
	char junkbuf[MAXLINE];
	static char enhstatcode[ENHSCLEN];
	int save_errno;

	if (mci->mci_out != NULL)
		(void) fflush(mci->mci_out);

	if (tTd(18, 1))
		dprintf("reply\n");

	/*
	**  Read the input line, being careful not to hang.
	*/

	bufp = SmtpReplyBuffer;
	for (;;)
	{
		register char *p;

		/* actually do the read */
		if (e->e_xfp != NULL)
			(void) fflush(e->e_xfp);	/* for debugging */

		/* if we are in the process of closing just give the code */
		if (mci->mci_state == MCIS_CLOSED)
			return SMTPCLOSING;

		if (mci->mci_out != NULL)
			(void) fflush(mci->mci_out);

		/* get the line from the other side */
		p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
		mci->mci_lastuse = curtime();

		if (p == NULL)
		{
			bool oldholderrs;
			extern char MsgBuf[];

			/* if the remote end closed early, fake an error */
			if (errno == 0)
# ifdef ECONNRESET
				errno = ECONNRESET;
# else /* ECONNRESET */
				errno = EPIPE;
# endif /* ECONNRESET */

			mci->mci_errno = errno;
			oldholderrs = HoldErrs;
			HoldErrs = TRUE;
			usrerr("451 4.4.1 reply: read error from %s",
			       CurHostName == NULL ? "NO_HOST" : CurHostName);

			/* errors on QUIT should not be persistent */
			if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0)
				mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);

			/* if debugging, pause so we can see state */
			if (tTd(18, 100))
				(void) pause();
			mci->mci_state = MCIS_ERROR;
			save_errno = errno;
			smtpquit(m, mci, e);
# if XDEBUG
			{
				char wbuf[MAXLINE];
				int wbufleft = sizeof wbuf;

				p = wbuf;
				if (e->e_to != NULL)
				{
					int plen;

					snprintf(p, wbufleft, "%s... ",
						shortenstring(e->e_to, MAXSHORTSTR));
					plen = strlen(p);
					p += plen;
					wbufleft -= plen;
				}
				snprintf(p, wbufleft, "reply(%.100s) during %s",
					 CurHostName == NULL ? "NO_HOST" : CurHostName,
					 SmtpPhase);
				checkfd012(wbuf);
			}
# endif /* XDEBUG */
			errno = save_errno;
			HoldErrs = oldholderrs;
			return -1;
		}
		fixcrlf(bufp, TRUE);

		/* EHLO failure is not a real error */
		if (e->e_xfp != NULL && (bufp[0] == '4' ||
		    (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
		{
			/* serious error -- log the previous command */
			if (SmtpNeedIntro)
			{
				/* inform user who we are chatting with */
				fprintf(CurEnv->e_xfp,
					"... while talking to %s:\n",
					CurHostName == NULL ? "NO_HOST" : CurHostName);
				SmtpNeedIntro = FALSE;
			}
			if (SmtpMsgBuffer[0] != '\0')
				fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
			SmtpMsgBuffer[0] = '\0';

			/* now log the message as from the other side */
			fprintf(e->e_xfp, "<<< %s\n", bufp);
		}

		/* display the input for verbose mode */
		if (Verbose)
			nmessage("050 %s", bufp);

		/* ignore improperly formatted input */
		if (!ISSMTPREPLY(bufp))
			continue;

		if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
		    enhstat != NULL &&
		    extenhsc(bufp + 4, ' ', enhstatcode) > 0)
			*enhstat = enhstatcode;

		/* process the line */
		if (pfunc != NULL)
			(*pfunc)(bufp, firstline, m, mci, e);

		firstline = FALSE;

		/* decode the reply code */
		r = atoi(bufp);

		/* extra semantics: 0xx codes are "informational" */
		if (r < 100)
			continue;

		/* if no continuation lines, return this line */
		if (bufp[3] != '-')
			break;

		/* first line of real reply -- ignore rest */
		bufp = junkbuf;
	}

	/*
	**  Now look at SmtpReplyBuffer -- only care about the first
	**  line of the response from here on out.
	*/

	/* save temporary failure messages for posterity */
	if (SmtpReplyBuffer[0] == '4' &&
	    (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == '\0'))
		snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer);

	/* reply code 421 is "Service Shutting Down" */
	if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
	{
		/* send the quit protocol */
		mci->mci_state = MCIS_SSD;
		smtpquit(m, mci, e);
	}

	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 mci->mci_out.
*/

/*VARARGS1*/
void
# ifdef __STDC__
smtpmessage(char *f, MAILER *m, MCI *mci, ...)
# else /* __STDC__ */
smtpmessage(f, m, mci, va_alist)
	char *f;
	MAILER *m;
	MCI *mci;
	va_dcl
# endif /* __STDC__ */
{
	VA_LOCAL_DECL

	VA_START(mci);
	(void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap);
	VA_END;

	if (tTd(18, 1) || Verbose)
		nmessage(">>> %s", SmtpMsgBuffer);
	if (TrafficLogFile != NULL)
		fprintf(TrafficLogFile, "%05d >>> %s\n",
			(int) getpid(), SmtpMsgBuffer);
	if (mci->mci_out != NULL)
	{
		fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
			m == NULL ? "\r\n" : m->m_eol);
	}
	else if (tTd(18, 1))
	{
		dprintf("smtpmessage: NULL mci_out\n");
	}
}

#endif /* SMTP */

⌨️ 快捷键说明

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