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

📄 headers.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
 * Copyright (c) 1988, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 *
 */

#ifndef lint
static char id[] = "@(#)$Id: headers.c,v 8.203.4.7 2000/08/22 21:50:36 gshapiro Exp $";
#endif /* ! lint */

#include <sendmail.h>

static bool	fix_mime_header __P((char *));
static int	priencode __P((char *));
static void	put_vanilla_header __P((HDR *, char *, MCI *));

/*
**  SETUPHEADERS -- initialize headers in symbol table
**
**	Parameters:
**		none
**
**	Returns:
**		none
*/

void
setupheaders()
{
	struct hdrinfo *hi;
	STAB *s;

	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
	{
		s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
		s->s_header.hi_flags = hi->hi_flags;
		s->s_header.hi_ruleset = NULL;
	}
}
/*
**  CHOMPHEADER -- process and save a header line.
**
**	Called by collect, readcf, and readqf to deal with header lines.
**
**	Parameters:
**		line -- header as a text line.
**		pflag -- flags for chompheader() (from sendmail.h)
**		hdrp -- a pointer to the place to save the header.
**		e -- the envelope including this header.
**
**	Returns:
**		flags for this header.
**
**	Side Effects:
**		The header is saved on the header list.
**		Contents of 'line' are destroyed.
*/

static struct hdrinfo	NormalHeader =	{ NULL, 0, NULL };

u_long
chompheader(line, pflag, hdrp, e)
	char *line;
	int pflag;
	HDR **hdrp;
	register ENVELOPE *e;
{
	u_char mid = '\0';
	register char *p;
	register HDR *h;
	HDR **hp;
	char *fname;
	char *fvalue;
	bool cond = FALSE;
	bool dropfrom;
	bool headeronly;
	STAB *s;
	struct hdrinfo *hi;
	bool nullheader = FALSE;
	BITMAP256 mopts;

	if (tTd(31, 6))
	{
		dprintf("chompheader: ");
		xputs(line);
		dprintf("\n");
	}

	headeronly = hdrp != NULL;
	if (!headeronly)
		hdrp = &e->e_header;

	/* strip off options */
	clrbitmap(mopts);
	p = line;
	if (!bitset(pflag, CHHDR_USER) && *p == '?')
	{
		int c;
		register char *q;

		q = strchr(++p, '?');
		if (q == NULL)
			goto hse;

		*q = '\0';
		c = *p & 0377;

		/* possibly macro conditional */
		if (c == MACROEXPAND)
		{
			/* catch ?$? */
			if (*++p == '\0')
			{
				*q = '?';
				goto hse;
			}

			mid = (u_char) *p++;

			/* catch ?$abc? */
			if (*p != '\0')
			{
				*q = '?';
				goto hse;
			}
		}
		else if (*p == '$')
		{
			/* catch ?$? */
			if (*++p == '\0')
			{
				*q = '?';
				goto hse;
			}

			mid = (u_char)macid(p, NULL);
			if (bitset(0200, mid))
				p += strlen(macname(mid)) + 2;
			else
				p++;

			/* catch ?$abc? */
			if (*p != '\0')
			{
				*q = '?';
				goto hse;
			}

		}
		else
		{
			while (*p != '\0')
			{
				if (!isascii(*p))
				{
					*q = '?';
					goto hse;
				}

				setbitn(*p, mopts);
				cond = TRUE;
				p++;
			}
		}
		p = q + 1;
	}

	/* find canonical name */
	fname = p;
	while (isascii(*p) && isgraph(*p) && *p != ':')
		p++;
	fvalue = p;
	while (isascii(*p) && isspace(*p))
		p++;
	if (*p++ != ':' || fname == fvalue)
	{
hse:
		syserr("553 5.3.0 header syntax error, line \"%s\"", line);
		return 0;
	}
	*fvalue = '\0';

	/* strip field value on front */
	if (*p == ' ')
		p++;
	fvalue = p;

	/* if the field is null, go ahead and use the default */
	while (isascii(*p) && isspace(*p))
		p++;
	if (*p == '\0')
		nullheader = TRUE;

	/* security scan: long field names are end-of-header */
	if (strlen(fname) > 100)
		return H_EOH;

	/* check to see if it represents a ruleset call */
	if (bitset(pflag, CHHDR_DEF))
	{
		char hbuf[50];

		(void) expand(fvalue, hbuf, sizeof hbuf, e);
		for (p = hbuf; isascii(*p) && isspace(*p); )
			p++;
		if ((*p++ & 0377) == CALLSUBR)
		{
			auto char *endp;
			bool strc;

			strc = *p == '+';	/* strip comments? */
			if (strc)
				++p;
			if (strtorwset(p, &endp, ST_ENTER) > 0)
			{
				*endp = '\0';
				s = stab(fname, ST_HEADER, ST_ENTER);
				s->s_header.hi_ruleset = newstr(p);
				if (!strc)
					s->s_header.hi_flags |= H_STRIPCOMM;
			}
			return 0;
		}
	}

	/* see if it is a known type */
	s = stab(fname, ST_HEADER, ST_FIND);
	if (s != NULL)
		hi = &s->s_header;
	else
		hi = &NormalHeader;

	if (tTd(31, 9))
	{
		if (s == NULL)
			dprintf("no header flags match\n");
		else
			dprintf("header match, flags=%lx, ruleset=%s\n",
				hi->hi_flags,
				hi->hi_ruleset == NULL ? "<NULL>" : hi->hi_ruleset);
	}

	/* see if this is a resent message */
	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
	    bitset(H_RESENT, hi->hi_flags))
		e->e_flags |= EF_RESENT;

	/* if this is an Errors-To: header keep track of it now */
	if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
	    bitset(H_ERRORSTO, hi->hi_flags))
		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);

	/* if this means "end of header" quit now */
	if (!headeronly && bitset(H_EOH, hi->hi_flags))
		return hi->hi_flags;

	/*
	**  Horrible hack to work around problem with Lotus Notes SMTP
	**  mail gateway, which generates From: headers with newlines in
	**  them and the <address> on the second line.  Although this is
	**  legal RFC 822, many MUAs don't handle this properly and thus
	**  never find the actual address.
	*/

	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
	{
		while ((p = strchr(fvalue, '\n')) != NULL)
			*p = ' ';
	}

	/*
	**  If there is a check ruleset, verify it against the header.
	*/

	if (bitset(pflag, CHHDR_CHECK))
	{
		bool stripcom = FALSE;
		char *rs;

		/* no ruleset? look for default */
		rs = hi->hi_ruleset;
		if (rs == NULL)
		{
			s = stab("*", ST_HEADER, ST_FIND);
			if (s != NULL)
			{
				rs = (&s->s_header)->hi_ruleset;
				stripcom = bitset((&s->s_header)->hi_flags,
						  H_STRIPCOMM);
			}
		}
		else
			stripcom = bitset(hi->hi_flags, H_STRIPCOMM);
		if (rs != NULL)
		{
			int l;
			char qval[MAXNAME];
			char hlen[16];
			char *sp, *dp;

			dp = qval;
			l = 0;
			dp[l++] = '"';
			for (sp = fvalue; *sp != '\0' && l < MAXNAME - 2; sp++)
			{
				switch(*sp)
				{
				  case '\011': /* ht */
				  case '\012': /* nl */
				  case '\013': /* vt */
				  case '\014': /* np */
				  case '\015': /* cr */
					dp[l++] = ' ';
					break;
				  case '"':
					dp[l++] = '\\';
					/* FALLTHROUGH */
				  default:
					dp[l++] = *sp;
					break;
				}
			}
			dp[l++] = '"';
			dp[l++] = '\0';
			l = strlen(fvalue);
			snprintf(hlen, sizeof hlen, "%d", l);
			define(macid("{hdrlen}", NULL), newstr(hlen), e);
			if (l >= MAXNAME)
			{
				if (LogLevel > 9)
					sm_syslog(LOG_WARNING, e->e_id,
						  "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
						  fname, rs, l, MAXNAME);
			}
			if ((sp = macvalue(macid("{currHeader}", NULL), e)) !=
			    NULL)
				free(sp);
			define(macid("{currHeader}", NULL), newstr(qval), e);
			define(macid("{hdr_name}", NULL), newstr(fname), e);
			(void) rscheck(rs, fvalue, NULL, e, stripcom, TRUE, 4);
		}
	}

	/*
	**  Drop explicit From: if same as what we would generate.
	**  This is to make MH (which doesn't always give a full name)
	**  insert the full name information in all circumstances.
	*/

	dropfrom = FALSE;
	p = "resent-from";
	if (!bitset(EF_RESENT, e->e_flags))
		p += 7;
	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
	    !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0)
	{
		if (tTd(31, 2))
		{
			dprintf("comparing header from (%s) against default (%s or %s)\n",
				fvalue, e->e_from.q_paddr, e->e_from.q_user);
		}
		if (e->e_from.q_paddr != NULL &&
		    e->e_from.q_mailer != NULL &&
		    bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
		     strcmp(fvalue, e->e_from.q_user) == 0))
			dropfrom = TRUE;
	}

	/* delete default value for this header */
	for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
	{
		if (strcasecmp(fname, h->h_field) == 0 &&
		    !bitset(H_USER, h->h_flags) &&
		    !bitset(H_FORCE, h->h_flags))
		{
			if (nullheader)
			{
				/* user-supplied value was null */
				return 0;
			}
			if (dropfrom)
			{
				/* make this look like the user entered it */
				h->h_flags |= H_USER;
				return hi->hi_flags;
			}
			h->h_value = NULL;
			if (!cond)
			{
				/* copy conditions from default case */
				memmove((char *)mopts, (char *)h->h_mflags,
					sizeof mopts);
			}
			h->h_macro = mid;
		}
	}

	/* create a new node */
	h = (HDR *) xalloc(sizeof *h);
	h->h_field = newstr(fname);
	h->h_value = newstr(fvalue);
	h->h_link = NULL;
	memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts);
	h->h_macro = mid;
	*hp = h;
	h->h_flags = hi->hi_flags;
	if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
		h->h_flags |= H_USER;

	/* strip EOH flag if parsing MIME headers */
	if (headeronly)
		h->h_flags &= ~H_EOH;
	if (bitset(pflag, CHHDR_DEF))
		h->h_flags |= H_DEFAULT;
	if (cond || mid != '\0')
		h->h_flags |= H_CHECK;

	/* hack to see if this is a new format message */
	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
	    bitset(H_RCPT|H_FROM, h->h_flags) &&
	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
	{
		e->e_flags &= ~EF_OLDSTYLE;
	}

	return h->h_flags;
}
/*
**  ADDHEADER -- add a header entry to the end of the queue.
**
**	This bypasses the special checking of chompheader.
**
**	Parameters:
**		field -- the name of the header field.
**		value -- the value of the field.
**		flags -- flags to add to h_flags.
**		hdrlist -- an indirect pointer to the header structure list.
**
**	Returns:
**		none.
**
**	Side Effects:
**		adds the field on the list of headers for this envelope.
*/

void
addheader(field, value, flags, hdrlist)
	char *field;
	char *value;
	int flags;
	HDR **hdrlist;
{
	register HDR *h;
	STAB *s;
	HDR **hp;

	/* find info struct */
	s = stab(field, ST_HEADER, ST_FIND);

	/* find current place in list -- keep back pointer? */
	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
	{
		if (strcasecmp(field, h->h_field) == 0)
			break;
	}

	/* allocate space for new header */
	h = (HDR *) xalloc(sizeof *h);
	h->h_field = field;
	h->h_value = newstr(value);
	h->h_link = *hp;
	h->h_flags = flags;
	if (s != NULL)
		h->h_flags |= s->s_header.hi_flags;
	clrbitmap(h->h_mflags);
	h->h_macro = '\0';
	*hp = h;
}
/*
**  HVALUE -- return value of a header.
**
**	Only "real" fields (i.e., ones that have not been supplied
**	as a default) are used.
**
**	Parameters:
**		field -- the field name.
**		header -- the header list.
**
**	Returns:
**		pointer to the value part.
**		NULL if not found.
**
**	Side Effects:
**		none.
*/

char *
hvalue(field, header)
	char *field;
	HDR *header;
{
	register HDR *h;

	for (h = header; h != NULL; h = h->h_link)
	{
		if (!bitset(H_DEFAULT, h->h_flags) &&
		    strcasecmp(h->h_field, field) == 0)
			return h->h_value;
	}
	return NULL;
}
/*
**  ISHEADER -- predicate telling if argument is a header.
**
**	A line is a header if it has a single word followed by
**	optional white space followed by a colon.
**
**	Header fields beginning with two dashes, although technically
**	permitted by RFC822, are automatically rejected in order
**	to make MIME work out.  Without this we could have a technically
**	legal header such as ``--"foo:bar"'' that would also be a legal
**	MIME separator.
**
**	Parameters:
**		h -- string to check for possible headerness.
**
**	Returns:
**		TRUE if h is a header.
**		FALSE otherwise.
**
**	Side Effects:
**		none.
*/

bool
isheader(h)
	char *h;
{
	register char *s = h;

	if (s[0] == '-' && s[1] == '-')
		return FALSE;

	while (*s > ' ' && *s != ':' && *s != '\0')
		s++;

	if (h == s)
		return FALSE;

	/* following technically violates RFC822 */
	while (isascii(*s) && isspace(*s))
		s++;

	return (*s == ':');
}
/*
**  EATHEADER -- run through the stored header and extract info.
**
**	Parameters:
**		e -- the envelope to process.
**		full -- if set, do full processing (e.g., compute
**			message priority).  This should not be set
**			when reading a queue file because some info
**			needed to compute the priority is wrong.
**
**	Returns:
**		none.
**
**	Side Effects:
**		Sets a bunch of global variables from information
**			in the collected header.
**		Aborts the message if the hop count is exceeded.
*/

void
eatheader(e, full)
	register ENVELOPE *e;
	bool full;
{
	register HDR *h;
	register char *p;
	int hopcnt = 0;
	char *msgid;
	char buf[MAXLINE];

	/*
	**  Set up macros for possible expansion in headers.
	*/

	define('f', e->e_sender, e);
	define('g', e->e_sender, e);
	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
		define('u', e->e_origrcpt, e);
	else
		define('u', NULL, e);

	/* full name of from person */
	p = hvalue("full-name", e->e_header);
	if (p != NULL)
	{
		if (!rfc822_string(p))
		{
			/*
			**  Quote a full name with special characters
			**  as a comment so crackaddr() doesn't destroy
			**  the name portion of the address.
			*/
			p = addquotes(p);
		}
		define('x', p, e);
	}

	if (tTd(32, 1))
		dprintf("----- collected header -----\n");
	msgid = NULL;
	for (h = e->e_header; h != NULL; h = h->h_link)

⌨️ 快捷键说明

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