collect.c

来自「< linux网络编程工具>>配套源码」· C语言 代码 · 共 887 行 · 第 1/2 页

C
887
字号
				bp[0] == '\r' && bp[1] == '\n') ||
			    (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
				bp[0] == '\n'))
			{
				break;
			}

			/* if not a blank separator, write it out */
			if (!bitset(EF_TOOBIG, e->e_flags))
			{
				while (*bp != '\0')
					(void) putc(*bp++, df);
			}
			break;
		}
		bp = buf;
	}

readerr:
	if ((feof(fp) && smtpmode) || ferror(fp))
	{
		const char *errmsg = errstring(errno);

		if (tTd(30, 1))
			dprintf("collect: premature EOM: %s\n", errmsg);
		if (LogLevel >= 2)
			sm_syslog(LOG_WARNING, e->e_id,
				"collect: premature EOM: %s", errmsg);
		inputerr = TRUE;
	}

	/* reset global timer */
	clrevent(CollectTimeout);

	if (headeronly)
		return;

	if (df == NULL)
	{
		/* skip next few clauses */
		/* EMPTY */
	}
	else if (fflush(df) != 0 || ferror(df))
	{
		dferror(df, "fflush||ferror", e);
		flush_errors(TRUE);
		finis(TRUE, ExitStat);
		/* NOTREACHED */
	}
	else if (!SuperSafe)
	{
		/* skip next few clauses */
		/* EMPTY */
	}
	else if ((afd = fileno(df)) >= 0 && fsync(afd) < 0)
	{
		dferror(df, "fsync", e);
		flush_errors(TRUE);
		finis(TRUE, ExitStat);
		/* NOTREACHED */
	}
	else if (bfcommit(df) < 0)
	{
		int save_errno = errno;

		if (save_errno == EEXIST)
		{
			char *dfile;
			struct stat st;

			dfile = queuename(e, 'd');
			if (stat(dfile, &st) < 0)
				st.st_size = -1;
			errno = EEXIST;
			syserr("collect: bfcommit(%s): already on disk, size = %ld",
			       dfile, (long) st.st_size);
			dfd = fileno(df);
			if (dfd >= 0)
				dumpfd(dfd, TRUE, TRUE);
		}
		errno = save_errno;
		dferror(df, "bfcommit", e);
		flush_errors(TRUE);
		finis(save_errno != EEXIST, ExitStat);
	}
	else if (bfclose(df) < 0)
	{
		dferror(df, "bfclose", e);
		flush_errors(TRUE);
		finis(TRUE, ExitStat);
		/* NOTREACHED */
	}
	else
	{
		/* everything is happily flushed to disk */
		df = NULL;
	}

	/* An EOF when running SMTP is an error */
	if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
	{
		char *host;
		char *problem;

		host = RealHostName;
		if (host == NULL)
			host = "localhost";

		if (feof(fp))
			problem = "unexpected close";
		else if (ferror(fp))
			problem = "I/O error";
		else
			problem = "read timeout";
		if (LogLevel > 0 && feof(fp))
			sm_syslog(LOG_NOTICE, e->e_id,
			    "collect: %s on connection from %.100s, sender=%s: %s",
			    problem, host,
			    shortenstring(e->e_from.q_paddr, MAXSHORTSTR),
			    errstring(errno));
		if (feof(fp))
			usrerr("451 4.4.1 collect: %s on connection from %s, from=%s",
				problem, host,
				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
		else
			syserr("451 4.4.1 collect: %s on connection from %s, from=%s",
				problem, host,
				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));

		/* don't return an error indication */
		e->e_to = NULL;
		e->e_flags &= ~EF_FATALERRS;
		e->e_flags |= EF_CLRQUEUE;

		/* and don't try to deliver the partial message either */
		if (InChild)
			ExitStat = EX_QUIT;
		finis(TRUE, ExitStat);
		/* NOTREACHED */
	}

	/*
	**  Find out some information from the headers.
	**	Examples are who is the from person & the date.
	*/

	eatheader(e, TRUE);

	if (GrabTo && e->e_sendqueue == NULL)
		usrerr("No recipient addresses found in header");

	/* collect statistics */
	if (OpMode != MD_VERIFY)
		markstats(e, (ADDRESS *) NULL, FALSE);

	/*
	**  If we have a Return-Receipt-To:, turn it into a DSN.
	*/

	if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
	{
		ADDRESS *q;

		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
			if (!bitset(QHASNOTIFY, q->q_flags))
				q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
	}

	/*
	**  Add an Apparently-To: line if we have no recipient lines.
	*/

	if (hvalue("to", e->e_header) != NULL ||
	    hvalue("cc", e->e_header) != NULL ||
	    hvalue("apparently-to", e->e_header) != NULL)
	{
		/* have a valid recipient header -- delete Bcc: headers */
		e->e_flags |= EF_DELETE_BCC;
	}
	else if (hvalue("bcc", e->e_header) == NULL)
	{
		/* no valid recipient headers */
		register ADDRESS *q;
		char *hdr = NULL;

		/* create an Apparently-To: field */
		/*    that or reject the message.... */
		switch (NoRecipientAction)
		{
		  case NRA_ADD_APPARENTLY_TO:
			hdr = "Apparently-To";
			break;

		  case NRA_ADD_TO:
			hdr = "To";
			break;

		  case NRA_ADD_BCC:
			addheader("Bcc", " ", 0, &e->e_header);
			break;

		  case NRA_ADD_TO_UNDISCLOSED:
			addheader("To", "undisclosed-recipients:;", 0, &e->e_header);
			break;
		}

		if (hdr != NULL)
		{
			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
			{
				if (q->q_alias != NULL)
					continue;
				if (tTd(30, 3))
					dprintf("Adding %s: %s\n",
						hdr, q->q_paddr);
				addheader(hdr, q->q_paddr, 0, &e->e_header);
			}
		}
	}

	/* check for message too large */
	if (bitset(EF_TOOBIG, e->e_flags))
	{
		e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE;
		e->e_status = "5.2.3";
		usrerrenh(e->e_status,
			  "552 Message exceeds maximum fixed size (%ld)",
			  MaxMessageSize);
		if (LogLevel > 6)
			sm_syslog(LOG_NOTICE, e->e_id,
				"message size (%ld) exceeds maximum (%ld)",
				e->e_msgsize, MaxMessageSize);
	}

	/* check for illegal 8-bit data */
	if (HasEightBits)
	{
		e->e_flags |= EF_HAS8BIT;
		if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) &&
		    !bitset(EF_IS_MIME, e->e_flags))
		{
			e->e_status = "5.6.1";
			usrerrenh(e->e_status, "554 Eight bit data not allowed");
		}
	}
	else
	{
		/* if it claimed to be 8 bits, well, it lied.... */
		if (e->e_bodytype != NULL &&
		    strcasecmp(e->e_bodytype, "8BITMIME") == 0)
			e->e_bodytype = "7BIT";
	}

	if (SuperSafe)
	{
		if ((e->e_dfp = fopen(dfname, "r")) == NULL)
		{
			/* we haven't acked receipt yet, so just chuck this */
			syserr("Cannot reopen %s", dfname);
			finis(TRUE, ExitStat);
			/* NOTREACHED */
		}
	}
	else
		e->e_dfp = df;
	if (e->e_dfp == NULL)
		syserr("!collect: no e_dfp");
}


static void
collecttimeout(timeout)
	time_t timeout;
{
	/* if no progress was made, die now */
	if (!CollectProgress)
		longjmp(CtxCollectTimeout, 1);

	/* otherwise reset the timeout */
	CollectTimeout = setevent(timeout, collecttimeout, timeout);
	CollectProgress = FALSE;
}
/*
**  DFERROR -- signal error on writing the data file.
**
**	Parameters:
**		df -- the file pointer for the data file.
**		msg -- detailed message.
**		e -- the current envelope.
**
**	Returns:
**		none.
**
**	Side Effects:
**		Gives an error message.
**		Arranges for following output to go elsewhere.
*/

static void
dferror(df, msg, e)
	FILE *volatile df;
	char *msg;
	register ENVELOPE *e;
{
	char *dfname;

	dfname = queuename(e, 'd');
	setstat(EX_IOERR);
	if (errno == ENOSPC)
	{
#if STAT64 > 0
		struct stat64 st;
#else /* STAT64 > 0 */
		struct stat st;
#endif /* STAT64 > 0 */
		long avail;
		long bsize;

		e->e_flags |= EF_NO_BODY_RETN;

		if (
#if STAT64 > 0
		    fstat64(fileno(df), &st)
#else /* STAT64 > 0 */
		    fstat(fileno(df), &st)
#endif /* STAT64 > 0 */
		    < 0)
		  st.st_size = 0;
		(void) freopen(dfname, "w", df);
		if (st.st_size <= 0)
			fprintf(df, "\n*** Mail could not be accepted");
		/*CONSTCOND*/
		else if (sizeof st.st_size > sizeof (long))
			fprintf(df, "\n*** Mail of at least %s bytes could not be accepted\n",
				quad_to_string(st.st_size));
		else
			fprintf(df, "\n*** Mail of at least %lu bytes could not be accepted\n",
				(unsigned long) st.st_size);
		fprintf(df, "*** at %s due to lack of disk space for temp file.\n",
			MyHostName);
		avail = freediskspace(qid_printqueue(e->e_queuedir), &bsize);
		if (avail > 0)
		{
			if (bsize > 1024)
				avail *= bsize / 1024;
			else if (bsize < 1024)
				avail /= 1024 / bsize;
			fprintf(df, "*** Currently, %ld kilobytes are available for mail temp files.\n",
				avail);
		}
		e->e_status = "4.3.1";
		usrerrenh(e->e_status, "452 Out of disk space for temp file");
	}
	else
		syserr("collect: Cannot write %s (%s, uid=%d)",
			dfname, msg, geteuid());
	if (freopen("/dev/null", "w", df) == NULL)
		sm_syslog(LOG_ERR, e->e_id,
			  "dferror: freopen(\"/dev/null\") failed: %s",
			  errstring(errno));
}
/*
**  EATFROM -- chew up a UNIX style from line and process
**
**	This does indeed make some assumptions about the format
**	of UNIX messages.
**
**	Parameters:
**		fm -- the from line.
**
**	Returns:
**		none.
**
**	Side Effects:
**		extracts what information it can from the header,
**		such as the date.
*/

#ifndef NOTUNIX

static char	*DowList[] =
{
	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
};

static char	*MonthList[] =
{
	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
	NULL
};

static void
eatfrom(fm, e)
	char *volatile fm;
	register ENVELOPE *e;
{
	register char *p;
	register char **dt;

	if (tTd(30, 2))
		dprintf("eatfrom(%s)\n", fm);

	/* find the date part */
	p = fm;
	while (*p != '\0')
	{
		/* skip a word */
		while (*p != '\0' && *p != ' ')
			p++;
		while (*p == ' ')
			p++;
		if (!(isascii(*p) && isupper(*p)) ||
		    p[3] != ' ' || p[13] != ':' || p[16] != ':')
			continue;

		/* we have a possible date */
		for (dt = DowList; *dt != NULL; dt++)
			if (strncmp(*dt, p, 3) == 0)
				break;
		if (*dt == NULL)
			continue;

		for (dt = MonthList; *dt != NULL; dt++)
			if (strncmp(*dt, &p[4], 3) == 0)
				break;
		if (*dt != NULL)
			break;
	}

	if (*p != '\0')
	{
		char *q;

		/* we have found a date */
		q = xalloc(25);
		(void) strlcpy(q, p, 25);
		q = arpadate(q);
		define('a', newstr(q), e);
	}
}
#endif /* ! NOTUNIX */

⌨️ 快捷键说明

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