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

📄 deliver.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	     bitnset(M_ROPT, m->m_flags)))
	{
		if (bitnset(M_FOPT, m->m_flags))
			*pvp++ = "-f";
		else
			*pvp++ = "-r";
		*pvp++ = newstr(rpathbuf);
	}

	/*
	**  Append the other fixed parts of the argv.  These run
	**  up to the first entry containing "$u".  There can only
	**  be one of these, and there are only a few more slots
	**  in the pv after it.
	*/

	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
	{
		/* can't use strchr here because of sign extension problems */
		while (*p != '\0')
		{
			if ((*p++ & 0377) == MACROEXPAND)
			{
				if (*p == 'u')
					break;
			}
		}

		if (*p != '\0')
			break;

		/* this entry is safe -- go ahead and process it */
		expand(*mvp, buf, sizeof buf, e);
		*pvp++ = newstr(buf);
		if (pvp >= &pv[MAXPV - 3])
		{
			syserr("554 5.3.5 Too many parameters to %s before $u",
			       pv[0]);
			return -1;
		}
	}

	/*
	**  If we have no substitution for the user name in the argument
	**  list, we know that we must supply the names otherwise -- and
	**  SMTP is the answer!!
	*/

	if (*mvp == NULL)
	{
		/* running SMTP */
#if SMTP
		clever = TRUE;
		*pvp = NULL;
#else /* SMTP */
		/* oops!  we don't implement SMTP */
		syserr("554 5.3.5 SMTP style mailer not implemented");
		return EX_SOFTWARE;
#endif /* SMTP */
	}

	/*
	**  At this point *mvp points to the argument with $u.  We
	**  run through our address list and append all the addresses
	**  we can.  If we run out of space, do not fret!  We can
	**  always send another copy later.
	*/

#if _FFR_DYNAMIC_TOBUF
	e->e_to = NULL;
	strsize = 2;
	rcptcount = 0;
#else /* _FFR_DYNAMIC_TOBUF */
	tobuf[0] = '\0';
	e->e_to = tobuf;
#endif /* _FFR_DYNAMIC_TOBUF */

	ctladdr = NULL;
	firstsig = hostsignature(firstto->q_mailer, firstto->q_host);
	for (; to != NULL; to = to->q_next)
	{
		/* avoid sending multiple recipients to dumb mailers */
#if _FFR_DYNAMIC_TOBUF
		if (tochain != NULL && !bitnset(M_MUSER, m->m_flags))
			break;
#else /* _FFR_DYNAMIC_TOBUF */
		if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))
			break;
#endif /* _FFR_DYNAMIC_TOBUF */

		/* if already sent or not for this host, don't send */
		if (!QS_IS_OK(to->q_state) ||
		    to->q_mailer != firstto->q_mailer ||
		    strcmp(hostsignature(to->q_mailer, to->q_host),
			   firstsig) != 0)
			continue;

		/* avoid overflowing tobuf */
#if _FFR_DYNAMIC_TOBUF
		strsize += strlen(to->q_paddr) + 1;
		if (!clever && strsize > TOBUFSIZE)
			break;

		if (++rcptcount > to->q_mailer->m_maxrcpt)
			break;
#else /* _FFR_DYNAMIC_TOBUF */
		if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2))
			break;
#endif /* _FFR_DYNAMIC_TOBUF */

		if (tTd(10, 1))
		{
			dprintf("\nsend to ");
			printaddr(to, FALSE);
		}

		/* compute effective uid/gid when sending */
		if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
			contextaddr = ctladdr = getctladdr(to);

		if (tTd(10, 2))
		{
			dprintf("ctladdr=");
			printaddr(ctladdr, FALSE);
		}

		user = to->q_user;
		e->e_to = to->q_paddr;

		/*
		**  Check to see that these people are allowed to
		**  talk to each other.
		**  Check also for overflow of e_msgsize.
		*/

		if (m->m_maxsize != 0 &&
		    (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0))
		{
			e->e_flags |= EF_NO_BODY_RETN;
			if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags))
				to->q_status = "5.2.3";
			else
				to->q_status = "5.3.4";
			/* set to->q_rstatus = NULL; or to the following? */
			usrerrenh(to->q_status,
				  "552 Message is too large; %ld bytes max",
				  m->m_maxsize);
			markfailure(e, to, NULL, EX_UNAVAILABLE, FALSE);
			giveresponse(EX_UNAVAILABLE, to->q_status, m,
				     NULL, ctladdr, xstart, e);
			continue;
		}
#if NAMED_BIND
		h_errno = 0;
#endif /* NAMED_BIND */

		ovr = TRUE;
		/* do config file checking of compatibility */
		rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr,
				e, TRUE, TRUE, 4);
		if (rcode == EX_OK)
		{
			/* do in-code checking if not discarding */
			if (!bitset(EF_DISCARD, e->e_flags))
			{
				rcode = checkcompat(to, e);
				ovr = FALSE;
			}
		}
		if (rcode != EX_OK)
		{
			markfailure(e, to, NULL, rcode, ovr);
			giveresponse(rcode, to->q_status, m,
				     NULL, ctladdr, xstart, e);
			continue;
		}
		if (bitset(EF_DISCARD, e->e_flags))
		{
			if (tTd(10, 5))
			{
				dprintf("deliver: discarding recipient ");
				printaddr(to, FALSE);
			}

			/* pretend the message was sent */
			/* XXX should we log something here? */
			to->q_state = QS_DISCARDED;

			/*
			**  Remove discard bit to prevent discard of
			**  future recipients.  This is safe because the
			**  true "global discard" has been handled before
			**  we get here.
			*/

			e->e_flags &= ~EF_DISCARD;
			continue;
		}

		/*
		**  Strip quote bits from names if the mailer is dumb
		**	about them.
		*/

		if (bitnset(M_STRIPQ, m->m_flags))
		{
			stripquotes(user);
			stripquotes(host);
		}

		/* hack attack -- delivermail compatibility */
		if (m == ProgMailer && *user == '|')
			user++;

		/*
		**  If an error message has already been given, don't
		**	bother to send to this address.
		**
		**	>>>>>>>>>> This clause assumes that the local mailer
		**	>> NOTE >> cannot do any further aliasing; that
		**	>>>>>>>>>> function is subsumed by sendmail.
		*/

		if (!QS_IS_OK(to->q_state))
			continue;

		/*
		**  See if this user name is "special".
		**	If the user name has a slash in it, assume that this
		**	is a file -- send it off without further ado.  Note
		**	that this type of addresses is not processed along
		**	with the others, so we fudge on the To person.
		*/

		if (strcmp(m->m_mailer, "[FILE]") == 0)
		{
			define('u', user, e);	/* to user */
			p = to->q_home;
			if (p == NULL && ctladdr != NULL)
				p = ctladdr->q_home;
			define('z', p, e);	/* user's home */
			expand(m->m_argv[1], buf, sizeof buf, e);
			if (strlen(buf) > 0)
				rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e);
			else
			{
				syserr("empty filename specification for mailer %s",
				       m->m_name);
				rcode = EX_CONFIG;
			}
			giveresponse(rcode, to->q_status, m, NULL,
				     ctladdr, xstart, e);
			markfailure(e, to, NULL, rcode, TRUE);
			e->e_nsent++;
			if (rcode == EX_OK)
			{
				to->q_state = QS_SENT;
				if (bitnset(M_LOCALMAILER, m->m_flags) &&
				    bitset(QPINGONSUCCESS, to->q_flags))
				{
					to->q_flags |= QDELIVERED;
					to->q_status = "2.1.5";
					fprintf(e->e_xfp, "%s... Successfully delivered\n",
						to->q_paddr);
				}
			}
			to->q_statdate = curtime();
			markstats(e, to, FALSE);
			continue;
		}

		/*
		**  Address is verified -- add this user to mailer
		**  argv, and add it to the print list of recipients.
		*/

		/* link together the chain of recipients */
		to->q_tchain = tochain;
		tochain = to;

#if _FFR_DYNAMIC_TOBUF
		e->e_to = "[CHAIN]";
#else /* _FFR_DYNAMIC_TOBUF */
		/* create list of users for error messages */
		(void) strlcat(tobuf, ",", sizeof tobuf);
		(void) strlcat(tobuf, to->q_paddr, sizeof tobuf);
#endif /* _FFR_DYNAMIC_TOBUF */

		define('u', user, e);		/* to user */
		p = to->q_home;
		if (p == NULL && ctladdr != NULL)
			p = ctladdr->q_home;
		define('z', p, e);	/* user's home */

		/* set the ${dsn_notify} macro if applicable */
		if (bitset(QHASNOTIFY, to->q_flags))
		{
			char notify[MAXLINE];

			notify[0] = '\0';
			if (bitset(QPINGONSUCCESS, to->q_flags))
				(void) strlcat(notify, "SUCCESS,",
					       sizeof notify);
			if (bitset(QPINGONFAILURE, to->q_flags))
				(void) strlcat(notify, "FAILURE,",
					       sizeof notify);
			if (bitset(QPINGONDELAY, to->q_flags))
				(void) strlcat(notify, "DELAY,", sizeof notify);

			/* Set to NEVER or drop trailing comma */
			if (notify[0] == '\0')
				(void) strlcat(notify, "NEVER", sizeof notify);
			else
				notify[strlen(notify) - 1] = '\0';

			define(macid("{dsn_notify}", NULL), newstr(notify), e);
		}
		else
			define(macid("{dsn_notify}", NULL), NULL, e);

		/*
		**  Expand out this user into argument list.
		*/

		if (!clever)
		{
			expand(*mvp, buf, sizeof buf, e);
			*pvp++ = newstr(buf);
			if (pvp >= &pv[MAXPV - 2])
			{
				/* allow some space for trailing parms */
				break;
			}
		}
	}

	/* see if any addresses still exist */
#if _FFR_DYNAMIC_TOBUF
	if (tochain == NULL)
#else /* _FFR_DYNAMIC_TOBUF */
	if (tobuf[0] == '\0')
#endif /* _FFR_DYNAMIC_TOBUF */
	{
		define('g', (char *) NULL, e);
		e->e_to = NULL;
		return 0;
	}

	/* print out messages as full list */
#if _FFR_DYNAMIC_TOBUF
	{
		int l = 1;
		char *tobufptr;

		for (to = tochain; to != NULL; to = to->q_tchain)
			l += strlen(to->q_paddr) + 1;
		if (l < TOBUFSIZE)
			l = TOBUFSIZE;
		if (l > tobufsize)
		{
			if (tobuf != NULL)
				free(tobuf);
			tobufsize = l;
			tobuf = xalloc(tobufsize);
		}
		tobufptr = tobuf;
		*tobufptr = '\0';
		for (to = tochain; to != NULL; to = to->q_tchain)
		{
			snprintf(tobufptr, tobufsize - (tobufptr - tobuf),
				 ",%s", to->q_paddr);
			tobufptr += strlen(tobufptr);
		}
	}
#endif /* _FFR_DYNAMIC_TOBUF */
	e->e_to = tobuf + 1;

	/*
	**  Fill out any parameters after the $u parameter.
	*/

	while (!clever && *++mvp != NULL)
	{
		expand(*mvp, buf, sizeof buf, e);
		*pvp++ = newstr(buf);
		if (pvp >= &pv[MAXPV])
			syserr("554 5.3.0 deliver: pv overflow after $u for %s",
			       pv[0]);
	}
	*pvp++ = NULL;

	/*
	**  Call the mailer.
	**	The argument vector gets built, pipes
	**	are created as necessary, and we fork & exec as
	**	appropriate.
	**	If we are running SMTP, we just need to clean up.
	*/

	/* XXX this seems a bit wierd */
	if (ctladdr == NULL && m != ProgMailer && m != FileMailer &&
	    bitset(QGOODUID, e->e_from.q_flags))
		ctladdr = &e->e_from;

#if NAMED_BIND
	if (ConfigLevel < 2)
		_res.options &= ~(RES_DEFNAMES | RES_DNSRCH);	/* XXX */
#endif /* NAMED_BIND */

	if (tTd(11, 1))
	{
		dprintf("openmailer:");
		printav(pv);
	}
	errno = 0;
#if NAMED_BIND
	h_errno = 0;
#endif /* NAMED_BIND */

	CurHostName = NULL;

	/*
	**  Deal with the special case of mail handled through an IPC
	**  connection.
	**	In this case we don't actually fork.  We must be
	**	running SMTP for this to work.  We will return a
	**	zero pid to indicate that we are running IPC.
	**  We also handle a debug version that just talks to stdin/out.
	*/

	curhost = NULL;
	SmtpPhase = NULL;
	mci = NULL;

#if XDEBUG
	{
		char wbuf[MAXLINE];

		/* make absolutely certain 0, 1, and 2 are in use */
		snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)",
			shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
		checkfd012(wbuf);
	}
#endif /* XDEBUG */

	/* check for 8-bit available */
	if (bitset(EF_HAS8BIT, e->e_flags) &&
	    bitnset(M_7BITS, m->m_flags) &&
	    (bitset(EF_DONT_MIME, e->e_flags) ||
	     !(bitset(MM_MIME8BIT, MimeMode) ||
	       (bitset(EF_IS_MIME, e->e_flags) &&
		bitset(MM_CVTMIME, MimeMode)))))
	{
		e->e_status = "5.6.3";
		usrerrenh(e->e_status,
		       "554 Cannot send 8-bit data to 7-bit destination");
		rcode = EX_DATAERR;
		goto give_up;
	}

	if (tTd(62, 8))
		checkfds("before delivery");

	/* check for Local Person Communication -- not for mortals!!! */
	if (strcmp(m->m_mailer, "[LPC]") == 0)
	{
		mci = (MCI *) xalloc(sizeof *mci);
		memset((char *) mci, '\0', sizeof *mci);
		mci->mci_in = stdin;
		mci->mci_out = stdout;
		mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;
		mci->mci_mailer = m;
	}
	else if (strcmp(m->m_mailer, "[IPC]") == 0 ||
		 strcmp(m->m_mailer, "[TCP]") == 0)
	{
#if DAEMON
		register int i;

		if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
		{
			syserr("null destination for %s mailer", m->m_mailer);
			rcode = EX_CONFIG;
			goto give_up;
		}

# if NETUNIX
		if (strcmp(pv[0], "FILE") == 0)
		{
			curhost = CurHostName = "localhost";
			mux_path = pv[1];
		}
		else
# endif /* NETUNIX */
		{
			CurHostName = pv[1];
			curhost = hostsignature(m, pv[1]);
		}

		if (curhost == NULL || curhost[0] == '\0')
		{
			syserr("null host signature for %s", pv[1]);
			rcode = EX_CONFIG;
			goto give_up;
		}

		if (!clever)
		{
			syserr("554 5.3.5 non-clever IPC");
			rcode = EX_CONFIG;
			goto give_up;
		}
		if (pv[2] != NULL
# if NETUNIX
		    && mux_path == NULL
# endif /* NETUNIX */
		    )
		{
			port = htons((u_short)atoi(pv[2]));
			if (port == 0)
			{
# ifdef NO_GETSERVBYNAME
				syserr("Invalid port number: %s", pv[2]);
# else /* NO_GETSERVBYNAME */
				struct servent *sp = getservbyname(pv[2], "tcp");

				if (sp == NULL)
					syserr("Service %s unknown", pv[2]);
				else
					port = sp->s_port;
# endif /* NO_GETSERVBYNAME */
			}
		}

		nummxhosts = parse_hostsignature(curhost, mxhosts, m);
tryhost:
		while (hostnum < nummxhosts)
		{
			char sep = ':';
			char *endp;
			static char hostbuf[MAXNAME + 1];

⌨️ 快捷键说明

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