parseaddr.c

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

C
2,770
字号
	{ "software",		EX_SOFTWARE	},
	{ "tempfail",		EX_TEMPFAIL	},
	{ "protocol",		EX_PROTOCOL	},
#ifdef EX_CONFIG
	{ "config",		EX_CONFIG	},
#endif /* EX_CONFIG */
	{ NULL,			EX_UNAVAILABLE	}
};


static ADDRESS *
buildaddr(tv, a, flags, e)
	register char **tv;
	register ADDRESS *a;
	int flags;
	register ENVELOPE *e;
{
	struct mailer **mp;
	register struct mailer *m;
	register char *p;
	char *mname;
	char **hostp;
	char hbuf[MAXNAME + 1];
	static char ubuf[MAXNAME + 2];

	if (tTd(24, 5))
	{
		dprintf("buildaddr, flags=%x, tv=", flags);
		printav(tv);
	}

	if (a == NULL)
		a = (ADDRESS *) xalloc(sizeof *a);
	memset((char *) a, '\0', sizeof *a);
	hbuf[0] = '\0';

	/* set up default error return flags */
	a->q_flags |= DefaultNotify;

	/* figure out what net/mailer to use */
	if (*tv == NULL || (**tv & 0377) != CANONNET)
	{
		syserr("554 5.3.5 buildaddr: no mailer in parsed address");
badaddr:
		if (ExitStat == EX_TEMPFAIL)
			a->q_state = QS_QUEUEUP;
		else
		{
			a->q_state = QS_BADADDR;
			a->q_mailer = &errormailer;
		}
		return a;
	}
	mname = *++tv;

	/* extract host and user portions */
	if (*++tv != NULL && (**tv & 0377) == CANONHOST)
		hostp = ++tv;
	else
		hostp = NULL;
	while (*tv != NULL && (**tv & 0377) != CANONUSER)
		tv++;
	if (*tv == NULL)
	{
		syserr("554 5.3.5 buildaddr: no user");
		goto badaddr;
	}
	if (tv == hostp)
		hostp = NULL;
	else if (hostp != NULL)
		cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0');
	cataddr(++tv, NULL, ubuf, sizeof ubuf, ' ');

	/* save away the host name */
	if (strcasecmp(mname, "error") == 0)
	{
		/* Set up triplet for use by -bv */
		a->q_mailer = &errormailer;
		a->q_user = newstr(ubuf);

		if (hostp != NULL)
		{
			register struct errcodes *ep;

			a->q_host = newstr(hbuf);
			if (strchr(hbuf, '.') != NULL)
			{
				a->q_status = newstr(hbuf);
				setstat(dsntoexitstat(hbuf));
			}
			else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
			{
				setstat(atoi(hbuf));
			}
			else
			{
				for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
					if (strcasecmp(ep->ec_name, hbuf) == 0)
						break;
				setstat(ep->ec_code);
			}
		}
		else
		{
			a->q_host = NULL;
			setstat(EX_UNAVAILABLE);
		}
		stripquotes(ubuf);
		if (ISSMTPCODE(ubuf) && ubuf[3] == ' ')
		{
			char fmt[16];
			int off;

			if ((off = isenhsc(ubuf + 4, ' ')) > 0)
			{
				ubuf[off + 4] = '\0';
				off += 5;
			}
			else
			{
				off = 4;
				ubuf[3] = '\0';
			}
			(void) snprintf(fmt, sizeof fmt, "%s %%s", ubuf);
			if (off > 4)
				usrerr(fmt, ubuf + off);
			else if (isenhsc(hbuf, '\0') > 0)
				usrerrenh(hbuf, fmt, ubuf + off);
			else
				usrerr(fmt, ubuf + off);
			/* XXX ubuf[off - 1] = ' '; */
		}
		else
		{
			usrerr("553 5.3.0 %s", ubuf);
		}
		goto badaddr;
	}

	for (mp = Mailer; (m = *mp++) != NULL; )
	{
		if (strcasecmp(m->m_name, mname) == 0)
			break;
	}
	if (m == NULL)
	{
		syserr("554 5.3.5 buildaddr: unknown mailer %s", mname);
		goto badaddr;
	}
	a->q_mailer = m;

	/* figure out what host (if any) */
	if (hostp == NULL)
	{
		if (!bitnset(M_LOCALMAILER, m->m_flags))
		{
			syserr("554 5.3.5 buildaddr: no host");
			goto badaddr;
		}
		a->q_host = NULL;
	}
	else
		a->q_host = newstr(hbuf);

	/* figure out the user */
	p = ubuf;
	if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
	{
		p++;
		tv++;
		a->q_flags |= QNOTREMOTE;
	}

	/* do special mapping for local mailer */
	if (*p == '"')
		p++;
	if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
		a->q_mailer = m = ProgMailer;
	else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
		a->q_mailer = m = FileMailer;
	else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
	{
		/* may be :include: */
		stripquotes(ubuf);
		if (strncasecmp(ubuf, ":include:", 9) == 0)
		{
			/* if :include:, don't need further rewriting */
			a->q_mailer = m = InclMailer;
			a->q_user = newstr(&ubuf[9]);
			return a;
		}
	}

	/* rewrite according recipient mailer rewriting rules */
	define('h', a->q_host, e);

#if _FFR_ADDR_TYPE
	/*
	**  Note, change the 9 to a 10 before removing #if FFR check
	**  in a future version.
	*/

	if (ConfigLevel >= 9 ||
	    !bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
#else /* _FFR_ADDR_TYPE */
	if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
#endif /* _FFR_ADDR_TYPE */
	{
		/* sender addresses done later */
		(void) rewrite(tv, 2, 0, e);
		if (m->m_re_rwset > 0)
		       (void) rewrite(tv, m->m_re_rwset, 0, e);
	}
	(void) rewrite(tv, 4, 0, e);

	/* save the result for the command line/RCPT argument */
	cataddr(tv, NULL, ubuf, sizeof ubuf, '\0');
	a->q_user = newstr(ubuf);

	/*
	**  Do mapping to lower case as requested by mailer
	*/

	if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
		makelower(a->q_host);
	if (!bitnset(M_USR_UPPER, m->m_flags))
		makelower(a->q_user);

	if (tTd(24, 6))
	{
		dprintf("buildaddr => ");
		printaddr(a, FALSE);
	}
	return a;
}
/*
**  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
**
**	Parameters:
**		pvp -- parameter vector to rebuild.
**		evp -- last parameter to include.  Can be NULL to
**			use entire pvp.
**		buf -- buffer to build the string into.
**		sz -- size of buf.
**		spacesub -- the space separator character; if null,
**			use SpaceSub.
**
**	Returns:
**		none.
**
**	Side Effects:
**		Destroys buf.
*/

void
cataddr(pvp, evp, buf, sz, spacesub)
	char **pvp;
	char **evp;
	char *buf;
	register int sz;
	int spacesub;
{
	bool oatomtok = FALSE;
	bool natomtok = FALSE;
	register int i;
	register char *p;

	if (sz <= 0)
		return;

	if (spacesub == '\0')
		spacesub = SpaceSub;

	if (pvp == NULL)
	{
		*buf = '\0';
		return;
	}
	p = buf;
	sz -= 2;
	while (*pvp != NULL && (i = strlen(*pvp)) < sz - 1)
	{
		natomtok = (TokTypeTab[**pvp & 0xff] == ATM);
		if (oatomtok && natomtok)
		{
			*p++ = spacesub;
			--sz;
		}
		(void) strlcpy(p, *pvp, sz);
		oatomtok = natomtok;
		p += i;
		sz -= i;
		if (pvp++ == evp)
			break;
	}
	*p = '\0';
}
/*
**  SAMEADDR -- Determine if two addresses are the same
**
**	This is not just a straight comparison -- if the mailer doesn't
**	care about the host we just ignore it, etc.
**
**	Parameters:
**		a, b -- pointers to the internal forms to compare.
**
**	Returns:
**		TRUE -- they represent the same mailbox.
**		FALSE -- they don't.
**
**	Side Effects:
**		none.
*/

bool
sameaddr(a, b)
	register ADDRESS *a;
	register ADDRESS *b;
{
	register ADDRESS *ca, *cb;

	/* if they don't have the same mailer, forget it */
	if (a->q_mailer != b->q_mailer)
		return FALSE;

	/* if the user isn't the same, we can drop out */
	if (strcmp(a->q_user, b->q_user) != 0)
		return FALSE;

	/* if we have good uids for both but they differ, these are different */
	if (a->q_mailer == ProgMailer)
	{
		ca = getctladdr(a);
		cb = getctladdr(b);
		if (ca != NULL && cb != NULL &&
		    bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
		    ca->q_uid != cb->q_uid)
			return FALSE;
	}

	/* otherwise compare hosts (but be careful for NULL ptrs) */
	if (a->q_host == b->q_host)
	{
		/* probably both null pointers */
		return TRUE;
	}
	if (a->q_host == NULL || b->q_host == NULL)
	{
		/* only one is a null pointer */
		return FALSE;
	}
	if (strcmp(a->q_host, b->q_host) != 0)
		return FALSE;

	return TRUE;
}
/*
**  PRINTADDR -- print address (for debugging)
**
**	Parameters:
**		a -- the address to print
**		follow -- follow the q_next chain.
**
**	Returns:
**		none.
**
**	Side Effects:
**		none.
*/

struct qflags
{
	char	*qf_name;
	u_long	qf_bit;
};

static struct qflags	AddressFlags[] =
{
	{ "QGOODUID",		QGOODUID	},
	{ "QPRIMARY",		QPRIMARY	},
	{ "QNOTREMOTE",		QNOTREMOTE	},
	{ "QSELFREF",		QSELFREF	},
	{ "QBOGUSSHELL",	QBOGUSSHELL	},
	{ "QUNSAFEADDR",	QUNSAFEADDR	},
	{ "QPINGONSUCCESS",	QPINGONSUCCESS	},
	{ "QPINGONFAILURE",	QPINGONFAILURE	},
	{ "QPINGONDELAY",	QPINGONDELAY	},
	{ "QHASNOTIFY",		QHASNOTIFY	},
	{ "QRELAYED",		QRELAYED	},
	{ "QEXPANDED",		QEXPANDED	},
	{ "QDELIVERED",		QDELIVERED	},
	{ "QDELAYED",		QDELAYED	},
	{ "QTHISPASS",		QTHISPASS	},
	{ "QRCPTOK",		QRCPTOK		},
	{ NULL }
};

void
printaddr(a, follow)
	register ADDRESS *a;
	bool follow;
{
	register MAILER *m;
	MAILER pseudomailer;
	register struct qflags *qfp;
	bool firstone;

	if (a == NULL)
	{
		printf("[NULL]\n");
		return;
	}

	while (a != NULL)
	{
		printf("%lx=", (u_long) a);
		(void) fflush(stdout);

		/* find the mailer -- carefully */
		m = a->q_mailer;
		if (m == NULL)
		{
			m = &pseudomailer;
			m->m_mno = -1;
			m->m_name = "NULL";
		}

		printf("%s:\n\tmailer %d (%s), host `%s'\n",
		       a->q_paddr == NULL ? "<null>" : a->q_paddr,
		       m->m_mno, m->m_name,
		       a->q_host == NULL ? "<null>" : a->q_host);
		printf("\tuser `%s', ruser `%s'\n",
		       a->q_user,
		       a->q_ruser == NULL ? "<null>" : a->q_ruser);
		printf("\tstate=");
		switch (a->q_state)
		{
		  case QS_OK:
			printf("OK");
			break;

		  case QS_DONTSEND:
			printf("DONTSEND");
			break;

		  case QS_BADADDR:
			printf("BADADDR");
			break;

		  case QS_QUEUEUP:
			printf("QUEUEUP");
			break;

		  case QS_SENT:
			printf("SENT");
			break;

		  case QS_VERIFIED:
			printf("VERIFIED");
			break;

		  case QS_EXPANDED:
			printf("EXPANDED");
			break;

		  case QS_SENDER:
			printf("SENDER");
			break;

		  case QS_CLONED:
			printf("CLONED");
			break;

		  case QS_DISCARDED:
			printf("DISCARDED");
			break;

		  case QS_REPLACED:
			printf("REPLACED");
			break;

		  case QS_REMOVED:
			printf("REMOVED");
			break;

		  case QS_DUPLICATE:
			printf("DUPLICATE");
			break;

		  case QS_INCLUDED:
			printf("INCLUDED");
			break;

		  default:
			printf("%d", a->q_state);
			break;
		}
		printf(", next=%lx, alias %lx, uid %d, gid %d\n",
		       (u_long) a->q_next, (u_long) a->q_alias,
		       (int) a->q_uid, (int) a->q_gid);
		printf("\tflags=%lx<", a->q_flags);
		firstone = TRUE;
		for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
		{
			if (!bitset(qfp->qf_bit, a->q_flags))
				continue;
			if (!firstone)
				printf(",");
			firstone = FALSE;
			printf("%s", qfp->qf_name);
		}
		printf(">\n");
		printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
		       a->q_owner == NULL ? "(none)" : a->q_owner,
		       a->q_home == NULL ? "(none)" : a->q_home,
		       a->q_fullname == NULL ? "(none)" : a->q_fullname);
		printf("\torcpt=\"%s\", statmta=%s, status=%s\n",
		       a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
		       a->q_statmta == NULL ? "(none)" : a->q_statmta,
		       a->q_status == NULL ? "(none)" : a->q_status);
		printf("\trstatus=\"%s\"\n",
		       a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
		printf("\tspecificity=%d, statdate=%s\n",
		       a->q_specificity,
		       a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate));

		if (!follow)
			return;
		a = a->q_next;
	}
}
/*
**  EMPTYADDR -- return TRUE if this address is empty (``<>'')
**
**	Parameters:
**		a -- pointer to the address
**
**	Returns:
**		TRUE -- if this address is "empty" (i.e., no one should
**			ever generate replies to it.
**		FALSE -- if it is a "regular" (read: replyable) address.
*/

bool
emptyaddr(a)
	register ADDRESS *a;
{
	return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 ||
	       a->q_user == NULL || strcmp(a->q_user, "<>") == 0;
}
/*
**  REMOTENAME -- return the name relative to the current mailer
**
**	Parameters:

⌨️ 快捷键说明

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