FullName = full = newstr(denlstring(FullName, TRUE, TRUE)); }
full = newstr(denlstring(FullName, TRUE, TRUE)); FullName = full; }
main(argc, argv, envp)	int argc;	char **argv;	char **envp;{	register char *p;	char **av;	extern char Version[];	char *ep, *from;	STAB *st;	register int i;	int j;	int dp;	bool safecf = TRUE;	BITMAP256 *p_flags = NULL;	/* daemon flags */	bool warn_C_flag = FALSE;	bool auth = TRUE;		/* whether to set e_auth_param */	char warn_f_flag = '\0';	bool run_in_foreground = FALSE;	/* -bD mode */	static bool reenter = FALSE;	struct passwd *pw;	struct hostent *hp;	char *nullserver = NULL;	char *authinfo = NULL;	char *sysloglabel = NULL;	/* label for syslog */	bool forged;	struct stat traf_st;		/* for TrafficLog FIFO check */	char jbuf[MAXHOSTNAMELEN];	/* holds MyHostName */	static char rnamebuf[MAXNAME];	/* holds RealUserName */	char *emptyenviron[1];# if STARTTLS	bool tls_ok;# endif /* STARTTLS */	QUEUE_CHAR *new;	extern int DtableSize;	extern int optind;	extern int opterr;	extern char *optarg;	extern char **environ;	/*	**  Check to see if we reentered.	**	This would normally happen if e_putheader or e_putbody	**	were NULL when invoked.	*/	if (reenter)	{		syserr("main: reentered!");		abort();	}	reenter = TRUE;	/* avoid null pointer dereferences */	TermEscape.te_rv_on = TermEscape.te_rv_off = "";	/* do machine-dependent initializations */	init_md(argc, argv);	/* in 4.4BSD, the table can be huge; impose a reasonable limit */	DtableSize = getdtsize();	if (DtableSize > 256)		DtableSize = 256;	/*	**  Be sure we have enough file descriptors.	**	But also be sure that 0, 1, & 2 are open.	*/	fill_fd(STDIN_FILENO, NULL);	fill_fd(STDOUT_FILENO, NULL);	fill_fd(STDERR_FILENO, NULL);	i = DtableSize;	while (--i > 0)	{		if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)			(void) close(i);	}	errno = 0;#if LOG#  ifdef LOG_MAIL	openlog("sendmail", LOG_PID, LOG_MAIL);#  else /* LOG_MAIL */	openlog("sendmail", LOG_PID);#  endif /* LOG_MAIL */#endif /* LOG */	if (MissingFds != 0)	{		char mbuf[MAXLINE];		mbuf[0] = '\0';		if (bitset(1 << STDIN_FILENO, MissingFds))			(void) strlcat(mbuf, ", stdin", sizeof mbuf);		if (bitset(1 << STDOUT_FILENO, MissingFds))			(void) strlcat(mbuf, ", stdout", sizeof mbuf);		if (bitset(1 << STDERR_FILENO, MissingFds))			(void) strlcat(mbuf, ", stderr", sizeof mbuf);		syserr("File descriptors missing on startup: %s", &mbuf[2]);	}	/* reset status from syserr() calls for missing file descriptors */	Errors = 0;	ExitStat = EX_OK;	SubmitMode = SUBMIT_UNKNOWN;#if XDEBUG	checkfd012("after openlog");#endif /* XDEBUG */	/*	**  Seed the random number generator.	**  Used for queue file names, picking a queue directory, and	**  MX randomization.	*/	seed_random();	tTsetup(tTdvect, sizeof tTdvect, "0-99.1");#ifdef NGROUPS_MAX	/* save initial group set for future checks */	i = getgroups(NGROUPS_MAX, InitialGidSet);	if (i == 0)		InitialGidSet[0] = (GID_T) -1;	while (i < NGROUPS_MAX)		InitialGidSet[i++] = InitialGidSet[0];#endif /* NGROUPS_MAX */	/* drop group id privileges (RunAsUser not yet set) */	dp = drop_privileges(FALSE);	setstat(dp);# ifdef SIGUSR1	/* arrange to dump state on user-1 signal */	(void) setsignal(SIGUSR1, sigusr1);# endif /* SIGUSR1 */	/* initialize for setproctitle */	initsetproctitle(argc, argv, envp);	/* Handle any non-getoptable constructions. */	obsolete(argv);	/*	**  Do a quick prescan of the argument list.	*/#if defined(__osf__) || defined(_AIX3)# define OPTIONS	"B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:x"#endif /* defined(__osf__) || defined(_AIX3) */#if defined(sony_news)# define OPTIONS	"B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtUV:vX:"#endif /* defined(sony_news) */#ifndef OPTIONS# define OPTIONS	"B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:"#endif /* ! OPTIONS */	opterr = 0;	while ((j = getopt(argc, argv, OPTIONS)) != -1)	{		switch (j)		{		  case 'd':			/* hack attack -- see if should use ANSI mode */			if (strcmp(optarg, "ANSI") == 0)			{				TermEscape.te_rv_on = "\033[7m";				TermEscape.te_rv_off = "\033[0m";				break;			}			tTflag(optarg);			setbuf(stdout, (char *) NULL);			break;		  case 'G':	/* relay (gateway) submission */			SubmitMode |= SUBMIT_MTA;			break;		  case 'L':			j = min(strlen(optarg), 24) + 1;			sysloglabel = xalloc(j);			(void) strlcpy(sysloglabel, optarg, j);			break;		  case 'U':	/* initial (user) submission */			SubmitMode |= SUBMIT_MSA;			break;		}	}	opterr = 1;	if (sysloglabel != NULL)	{#if LOG		closelog();#  ifdef LOG_MAIL		openlog(sysloglabel, LOG_PID, LOG_MAIL);#  else /* LOG_MAIL */		openlog(sysloglabel, LOG_PID);#  endif /* LOG_MAIL */#endif /* LOG */	}	/* set up the blank envelope */	BlankEnvelope.e_puthdr = putheader;	BlankEnvelope.e_putbody = putbody;	BlankEnvelope.e_xfp = NULL;	STRUCTCOPY(NullAddress, BlankEnvelope.e_from);	CurEnv = &BlankEnvelope;	STRUCTCOPY(NullAddress, MainEnvelope.e_from);	/*	**  Set default values for variables.	**	These cannot be in initialized data space.	*/	setdefaults(&BlankEnvelope);	RealUid = getuid();	RealGid = getgid();	pw = sm_getpwuid(RealUid);	if (pw != NULL)		(void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);	else		(void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",				(int) RealUid);	RealUserName = rnamebuf;	if (tTd(0, 101))	{		dprintf("Version %s\n", Version);		finis(FALSE, EX_OK);	}	/*	**  if running non-setuid binary as non-root, pretend	**  we are the RunAsUid	*/	if (RealUid != 0 && geteuid() == RealUid)	{		if (tTd(47, 1))			dprintf("Non-setuid binary: RunAsUid = RealUid = %d\n",				(int)RealUid);		RunAsUid = RealUid;	}	else if (geteuid() != 0)		RunAsUid = geteuid();	if (RealUid != 0 && getegid() == RealGid)		RunAsGid = RealGid;	if (tTd(47, 5))	{		dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n",			(int)geteuid(), (int)getuid(),			(int)getegid(), (int)getgid());		dprintf("main: RunAsUser = %d:%d\n",			(int)RunAsUid, (int)RunAsGid);	}	/* save command line arguments */	j = 0;	for (av = argv; *av != NULL; )		j += strlen(*av++) + 1;	SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));	CommandLineArgs = xalloc(j);	p = CommandLineArgs;	for (av = argv, i = 0; *av != NULL; )	{		int h;		SaveArgv[i++] = newstr(*av);		if (av != argv)			*p++ = ' ';		(void) strlcpy(p, *av++, j);		h = strlen(p);		p += h;		j -= h + 1;	}	SaveArgv[i] = NULL;	if (tTd(0, 1))	{		int ll;		extern char *CompileOptions[];		dprintf("Version %s\n Compiled with:", Version);		av = CompileOptions;		ll = 7;		while (*av != NULL)		{			if (ll + strlen(*av) > 63)			{				dprintf("\n");				ll = 0;			}			if (ll == 0)				dprintf("\t\t");			else				dprintf(" ");			dprintf("%s", *av);			ll += strlen(*av++) + 1;		}		dprintf("\n");	}	if (tTd(0, 10))	{		int ll;		extern char *OsCompileOptions[];		dprintf("    OS Defines:");		av = OsCompileOptions;		ll = 7;		while (*av != NULL)		{			if (ll + strlen(*av) > 63)			{				dprintf("\n");				ll = 0;			}			if (ll == 0)				dprintf("\t\t");			else				dprintf(" ");			dprintf("%s", *av);			ll += strlen(*av++) + 1;		}		dprintf("\n");#ifdef _PATH_UNIX		dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);#endif /* _PATH_UNIX */		dprintf(" Def Conf file:\t%s\n", getcfname());		dprintf("  Def Pid file:\t%s\n", PidFile);	}	InChannel = stdin;	OutChannel = stdout;	/* clear sendmail's environment */	ExternalEnviron = environ;	emptyenviron[0] = NULL;	environ = emptyenviron;	/*	**  restore any original TZ setting until TimeZoneSpec has been	**  determined - or early log messages may get bogus time stamps	*/	if ((p = getextenv("TZ")) != NULL)	{		char *tz;		int tzlen;		tzlen = strlen(p) + 4;		tz = xalloc(tzlen);		(void) snprintf(tz, tzlen, "TZ=%s", p);		(void) putenv(tz);	}	/* prime the child environment */	setuserenv("AGENT", "sendmail");	if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)		(void) setsignal(SIGINT, intsig);	(void) setsignal(SIGTERM, intsig);	(void) setsignal(SIGPIPE, SIG_IGN);	OldUmask = umask(022);	OpMode = MD_DELIVER;	FullName = getextenv("NAME");	/*	**  Initialize name server if it is going to be used.	*/#if NAMED_BIND	if (!bitset(RES_INIT, _res.options))		(void) res_init();	/*	**  hack to avoid crashes when debugging for the resolver is	**  turned on and sfio is used	*/	if (tTd(8, 8))# if !SFIO || SFIO_STDIO_COMPAT		_res.options |= RES_DEBUG;# else /* !SFIO || SFIO_STDIO_COMPAT */		dprintf("RES_DEBUG not available due to SFIO\n");# endif /* !SFIO || SFIO_STDIO_COMPAT */	else		_res.options &= ~RES_DEBUG;# ifdef RES_NOALIASES	_res.options |= RES_NOALIASES;# endif /* RES_NOALIASES */	TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;	TimeOuts.res_retry[RES_TO_FIRST] = _res.retry;	TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry;	TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans;	TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans;	TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans;#endif /* NAMED_BIND */	errno = 0;	from = NULL;	/* initialize some macros, etc. */	initmacros(CurEnv);	init_vendor_macros(CurEnv);	/* version */	define('v', Version, CurEnv);	/* hostname */	hp = myhostname(jbuf, sizeof jbuf);	if (jbuf[0] != '\0')	{		struct	utsname	utsname;		if (tTd(0, 4))			dprintf("canonical name: %s\n", jbuf);		define('w', newstr(jbuf), CurEnv);	/* must be new string */		define('j', newstr(jbuf), CurEnv);		setclass('w', jbuf);		p = strchr(jbuf, '.');		if (p != NULL)		{			if (p[1] != '\0')			{				define('m', newstr(&p[1]), CurEnv);			}			while (p != NULL && strchr(&p[1], '.') != NULL)			{				*p = '\0';				if (tTd(0, 4))					dprintf("\ta.k.a.: %s\n", jbuf);				setclass('w', jbuf);				*p++ = '.';				p = strchr(p, '.');			}		}		if (uname(&utsname) >= 0)			p = utsname.nodename;		else		{			if (tTd(0, 22))				dprintf("uname failed (%s)\n",					errstring(errno));			makelower(jbuf);			p = jbuf;		}		if (tTd(0, 4))			dprintf(" UUCP nodename: %s\n", p);		p = newstr(p);		define('k', p, CurEnv);		setclass('k', p);		setclass('w', p);	}	if (hp != NULL)	{		for (av = hp->h_aliases; av != NULL && *av != NULL; av++)		{			if (tTd(0, 4))				dprintf("\ta.k.a.: %s\n", *av);			setclass('w', *av);		}#if NETINET || NETINET6		for (i = 0; hp->h_addr_list[i] != NULL; i++)		{# if NETINET6			char *addr;			char buf6[INET6_ADDRSTRLEN];			struct in6_addr ia6;# endif /* NETINET6 */# if NETINET			struct in_addr ia;# endif /* NETINET */			char ipbuf[103];			ipbuf[0] = '\0';			switch (hp->h_addrtype)			{# if NETINET			  case AF_INET:				if (hp->h_length != INADDRSZ)					break;				memmove(&ia, hp->h_addr_list[i], INADDRSZ);				(void) snprintf(ipbuf,	 sizeof ipbuf,						"[%.100s]", inet_ntoa(ia));				break;# endif /* NETINET */# if NETINET6			  case AF_INET6:				if (hp->h_length != IN6ADDRSZ)					break;				memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ);				addr = anynet_ntop(&ia6, buf6, sizeof buf6);				if (addr != NULL)					(void) snprintf(ipbuf, sizeof ipbuf,							"[%.100s]", addr);				break;# endif /* NETINET6 */			}			if (ipbuf[0] == '\0')				break;			if (tTd(0, 4))				dprintf("\ta.k.a.: %s\n", ipbuf);			setclass('w', ipbuf);		}#endif /* NETINET || NETINET6 */#if _FFR_FREEHOSTENT && NETINET6		freehostent(hp);		hp = NULL;#endif /* _FFR_FREEHOSTENT && NETINET6 */	}	/* current time */	define('b', arpadate((char *) NULL), CurEnv);	/* current load average */	CurrentLA = sm_getla(CurEnv);	QueueLimitRecipient = (QUEUE_CHAR *) NULL;	QueueLimitSender = (QUEUE_CHAR *) NULL;	QueueLimitId = (QUEUE_CHAR *) NULL;	/*	**  Crack argv.	*/	av = argv;	p = strrchr(*av, '/');	if (p++ == NULL)		p = *av;	if (strcmp(p, "newaliases") == 0)		OpMode = MD_INITALIAS;	else if (strcmp(p, "mailq") == 0)		OpMode = MD_PRINT;	else if (strcmp(p, "smtpd") == 0)		OpMode = MD_DAEMON;	else if (strcmp(p, "hoststat") == 0)		OpMode = MD_HOSTSTAT;	else if (strcmp(p, "purgestat") == 0)		OpMode = MD_PURGESTAT;	optind = 1;	while ((j = getopt(argc, argv, OPTIONS)) != -1)	{		switch (j)		{		  case 'b':	/* operations mode */			switch (j = *optarg)			{			  case MD_DAEMON:			  case MD_FGDAEMON:#if !DAEMON				usrerr("Daemon mode not implemented");				ExitStat = EX_USAGE;				break;#endif /* !DAEMON */			  case MD_SMTP:#if !SMTP				usrerr("I don't speak SMTP");				ExitStat = EX_USAGE;				break;#endif /* !SMTP */			  case MD_INITALIAS:			  case MD_DELIVER:			  case MD_VERIFY:			  case MD_TEST:			  case MD_PRINT:			  case MD_HOSTSTAT:			  case MD_PURGESTAT:			  case MD_ARPAFTP:				OpMode = j;				break;			  case MD_FREEZE:				usrerr("Frozen configurations unsupported");				ExitStat = EX_USAGE;				break;			  default:				usrerr("Invalid operation mode %c", j);				ExitStat = EX_USAGE;				break;			}			break;		  case 'B':	/* body type */			CurEnv->e_bodytype = newstr(optarg);			break;		  case 'C':	/* select configuration file (already done) */			if (RealUid != 0)				warn_C_flag = TRUE;			ConfFile = newstr(optarg);			dp = drop_privileges(TRUE);			setstat(dp);			safecf = FALSE;			break;		  case 'd':	/* debugging -- already done */			break;		  case 'f':	/* from address */		  case 'r':	/* obsolete -f flag */			if (from != NULL)			{				usrerr("More than one \"from\" person");				ExitStat = EX_USAGE;				break;			}			from = newstr(denlstring(optarg, TRUE, TRUE));			if (strcmp(RealUserName, from) != 0)				warn_f_flag = j;			break;		  case 'F':	/* set full name */			FullName = newstr(optarg);			break;		  case 'G':	/* relay (gateway) submission */			/* already set */			break;		  case 'h':	/* hop count */			CurEnv->e_hopcount = (short) strtol(optarg, &ep, 10);			if (*ep)			{				usrerr("Bad hop count (%s)", optarg);				ExitStat = EX_USAGE;			}			break;		  case 'L':	/* program label */			/* already set */			break;		  case 'n':	/* don't alias */			NoAlias = TRUE;			break;		  case 'N':	/* delivery status notifications */			DefaultNotify |= QHASNOTIFY;			define(macid("{dsn_notify}", NULL),			       newstr(optarg), CurEnv);			if (strcasecmp(optarg, "never") == 0)				break;			for (p = optarg; p != NULL; optarg = p)			{				p = strchr(p, ',');				if (p != NULL)					*p++ = '\0';				if (strcasecmp(optarg, "success") == 0)					DefaultNotify |= QPINGONSUCCESS;				else if (strcasecmp(optarg, "failure") == 0)					DefaultNotify |= QPINGONFAILURE;				else if (strcasecmp(optarg, "delay") == 0)					DefaultNotify |= QPINGONDELAY;				else				{					usrerr("Invalid -N argument");					ExitStat = EX_USAGE;				}			}			break;		  case 'o':	/* set option */			setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);			break;		  case 'O':	/* set option (long form) */			setoption(' ', optarg, FALSE, TRUE, CurEnv);			break;		  case 'p':	/* set protocol */			p = strchr(optarg, ':');			if (p != NULL)			{				*p++ = '\0';				if (*p != '\0')				{					ep = xalloc(strlen(p) + 1);					cleanstrcpy(ep, p, MAXNAME);					define('s', ep, CurEnv);				}			}			if (*optarg != '\0')			{				ep = xalloc(strlen(optarg) + 1);				cleanstrcpy(ep, optarg, MAXNAME);				define('r', ep, CurEnv);			}			break;		  case 'q':	/* run queue files at intervals */#if QUEUE			/* sanity check */			if (OpMode != MD_DELIVER &&			    OpMode != MD_DAEMON &&			    OpMode != MD_FGDAEMON &&			    OpMode != MD_PRINT &&			    OpMode != MD_QUEUERUN)			{				usrerr("Can not use -q with -b%c", OpMode);				ExitStat = EX_USAGE;				break;			}			/* don't override -bd, -bD or -bp */			if (OpMode == MD_DELIVER)				OpMode = MD_QUEUERUN;			FullName = NULL;			switch (optarg[0])			{			  case 'I':				new = (QUEUE_CHAR *) xalloc(sizeof *new);				new->queue_match = newstr(&optarg[1]);				new->queue_next = QueueLimitId;				QueueLimitId = new;				break;			  case 'R':				new = (QUEUE_CHAR *) xalloc(sizeof *new);				new->queue_match = newstr(&optarg[1]);				new->queue_next = QueueLimitRecipient;				QueueLimitRecipient = new;				break;			  case 'S':				new = (QUEUE_CHAR *) xalloc(sizeof *new);				new->queue_match = newstr(&optarg[1]);				new->queue_next = QueueLimitSender;				QueueLimitSender = new;				break;			  default:				i = Errors;				QueueIntvl = convtime(optarg, 'm');				/* check for bad conversion */				if (i < Errors)					ExitStat = EX_USAGE;				break;			}#else /* QUEUE */			usrerr("I don't know about queues");			ExitStat = EX_USAGE;#endif /* QUEUE */			break;		  case 'R':	/* DSN RET: what to return */			if (bitset(EF_RET_PARAM, CurEnv->e_flags))			{				usrerr("Duplicate -R flag");				ExitStat = EX_USAGE;				break;			}			CurEnv->e_flags |= EF_RET_PARAM;			if (strcasecmp(optarg, "hdrs") == 0)				CurEnv->e_flags |= EF_NO_BODY_RETN;			else if (strcasecmp(optarg, "full") != 0)			{				usrerr("Invalid -R value");				ExitStat = EX_USAGE;			}			define(macid("{dsn_ret}", NULL),			       newstr(optarg), CurEnv);			break;		  case 't':	/* read recipients from message */			GrabTo = TRUE;			break;		  case 'U':	/* initial (user) submission */			/* already set */			break;		  case 'V':	/* DSN ENVID: set "original" envelope id */			if (!xtextok(optarg))			{				usrerr("Invalid syntax in -V flag");				ExitStat = EX_USAGE;			}			else			{				CurEnv->e_envid = newstr(optarg);				define(macid("{dsn_envid}", NULL),				       newstr(optarg), CurEnv);			}			break;		  case 'X':	/* traffic log file */			dp = drop_privileges(TRUE);			setstat(dp);			if (stat(optarg, &traf_st) == 0 &&			    S_ISFIFO(traf_st.st_mode))				TrafficLogFile = fopen(optarg, "w");			else				TrafficLogFile = fopen(optarg, "a");			if (TrafficLogFile == NULL)			{				syserr("cannot open %s", optarg);				ExitStat = EX_CANTCREAT;				break;			}#if HASSETVBUF			(void) setvbuf(TrafficLogFile, NULL, _IOLBF, 0);#else /* HASSETVBUF */			(void) setlinebuf(TrafficLogFile);#endif /* HASSETVBUF */			break;			/* compatibility flags */		  case 'c':	/* connect to non-local mailers */		  case 'i':	/* don't let dot stop me */		  case 'm':	/* send to me too */		  case 'T':	/* set timeout interval */		  case 'v':	/* give blow-by-blow description */			setoption(j, "T", FALSE, TRUE, CurEnv);			break;		  case 'e':	/* error message disposition */		  case 'M':	/* define macro */			setoption(j, optarg, FALSE, TRUE, CurEnv);			break;		  case 's':	/* save From lines in headers */			setoption('f', "T", FALSE, TRUE, CurEnv);			break;#ifdef DBM		  case 'I':	/* initialize alias DBM file */			OpMode = MD_INITALIAS;			break;#endif /* DBM */#if defined(__osf__) || defined(_AIX3)		  case 'x':	/* random flag that OSF/1 & AIX mailx passes */			break;#endif /* defined(__osf__) || defined(_AIX3) */#if defined(sony_news)		  case 'E':		  case 'J':	/* ignore flags for Japanese code conversion				   implemented on Sony NEWS */			break;#endif /* defined(sony_news) */		  default:			finis(TRUE, EX_USAGE);			break;		}	}	av += optind;	if (bitset(SUBMIT_MTA, SubmitMode) &&	    bitset(SUBMIT_MSA, SubmitMode))	{		/* sanity check */		errno = 0;	/* reset to avoid bogus error messages */		syserr("Cannot use both -G and -U together");	}	else if (bitset(SUBMIT_MTA, SubmitMode))		define(macid("{daemon_flags}", NULL), "CC f", CurEnv);	else if (bitset(SUBMIT_MSA, SubmitMode))	{		define(macid("{daemon_flags}", NULL), "c u", CurEnv);		/* check for wrong OpMode */		if (OpMode != MD_DELIVER && OpMode != MD_SMTP)		{			errno = 0;	/* reset to avoid bogus error msgs */			syserr("Cannot use -U and -b%c", OpMode);		}	}	else	{#if _FFR_DEFAULT_SUBMIT_TO_MSA		define(macid("{daemon_flags}", NULL), "c u", CurEnv);#else /* _FFR_DEFAULT_SUBMIT_TO_MSA */		/* EMPTY */#endif /* _FFR_DEFAULT_SUBMIT_TO_MSA */	}	/*	**  Do basic initialization.	**	Read system control file.	**	Extract special fields for local use.	*/	/* set up ${opMode} for use in config file */	{		char mbuf[2];		mbuf[0] = OpMode;		mbuf[1] = '\0';		define(MID_OPMODE, newstr(mbuf), CurEnv);	}#if XDEBUG	checkfd012("before readcf");#endif /* XDEBUG */	vendor_pre_defaults(CurEnv);	readcf(getcfname(), safecf, CurEnv);	ConfigFileRead = TRUE;	vendor_post_defaults(CurEnv);	/* Enforce use of local time (null string overrides this) */	if (TimeZoneSpec == NULL)		unsetenv("TZ");	else if (TimeZoneSpec[0] != '\0')		setuserenv("TZ", TimeZoneSpec);	else		setuserenv("TZ", NULL);	tzset();	/* avoid denial-of-service attacks */	resetlimits();	if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)	{		/* drop privileges -- daemon mode done after socket/bind */		dp = drop_privileges(FALSE);		setstat(dp);	}#if NAMED_BIND	_res.retry = TimeOuts.res_retry[RES_TO_DEFAULT];	_res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT];#endif /* NAMED_BIND */	/*	**  Find our real host name for future logging.	*/	authinfo = getauthinfo(STDIN_FILENO, &forged);	define('_', authinfo, CurEnv);	/* suppress error printing if errors mailed back or whatever */	if (CurEnv->e_errormode != EM_PRINT)		HoldErrs = TRUE;	/* set up the $=m class now, after .cf has a chance to redefine $m */	expand("\201m", jbuf, sizeof jbuf, CurEnv);	setclass('m', jbuf);	/* probe interfaces and locate any additional names */	if (!DontProbeInterfaces)		load_if_names();	if (tTd(0, 1))	{		dprintf("\n============ SYSTEM IDENTITY (after readcf) ============");		dprintf("\n      (short domain name) $w = ");		xputs(macvalue('w', CurEnv));		dprintf("\n  (canonical domain name) $j = ");		xputs(macvalue('j', CurEnv));		dprintf("\n         (subdomain name) $m = ");		xputs(macvalue('m', CurEnv));		dprintf("\n              (node name) $k = ");		xputs(macvalue('k', CurEnv));		dprintf("\n========================================================\n\n");	}	/*	**  Do more command line checking -- these are things that	**  have to modify the results of reading the config file.	*/	/* process authorization warnings from command line */	if (warn_C_flag)		auth_warning(CurEnv, "Processed by %s with -C %s",			RealUserName, ConfFile);	if (Warn_Q_option && !wordinclass(RealUserName, 't'))		auth_warning(CurEnv, "Processed from queue %s", QueueDir);	/* check body type for legality */	if (CurEnv->e_bodytype == NULL)		/* EMPTY */		/* nothing */ ;	else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0)		SevenBitInput = TRUE;	else if (strcasecmp(CurEnv->e_bodytype, "8BITMIME") == 0)		SevenBitInput = FALSE;	else	{		usrerr("Illegal body type %s", CurEnv->e_bodytype);		CurEnv->e_bodytype = NULL;	}	/* tweak default DSN notifications */	if (DefaultNotify == 0)		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;	/* be sure we don't pick up bogus HOSTALIASES environment variable */	if (OpMode == MD_QUEUERUN && RealUid != 0)		(void) unsetenv("HOSTALIASES");	/* check for sane configuration level */	if (ConfigLevel > MAXCONFIGLEVEL)	{		syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",			ConfigLevel, Version, MAXCONFIGLEVEL);	}	/* need MCI cache to have persistence */	if (HostStatDir != NULL && MaxMciCache == 0)	{		HostStatDir = NULL;		printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");	}	/* need HostStatusDir in order to have SingleThreadDelivery */	if (SingleThreadDelivery && HostStatDir == NULL)	{		SingleThreadDelivery = FALSE;		printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n");	}	/* check for permissions */	if ((OpMode == MD_DAEMON ||	     OpMode == MD_FGDAEMON ||	     OpMode == MD_PURGESTAT) &&	    RealUid != 0 &&	    RealUid != TrustedUid)	{		if (LogLevel > 1)			sm_syslog(LOG_ALERT, NOQID,				  "user %d attempted to %s",				  RealUid,				  OpMode != MD_PURGESTAT ? "run daemon"							 : "purge host status");		usrerr("Permission denied");		finis(FALSE, EX_USAGE);	}	if (OpMode == MD_INITALIAS &&	    RealUid != 0 &&	    RealUid != TrustedUid &&	    !wordinclass(RealUserName, 't'))	{		if (LogLevel > 1)			sm_syslog(LOG_ALERT, NOQID,				  "user %d attempted to rebuild the alias map",				  RealUid);		usrerr("Permission denied");		finis(FALSE, EX_USAGE);	}	if (MeToo)		BlankEnvelope.e_flags |= EF_METOO;	switch (OpMode)	{	  case MD_TEST:		/* don't have persistent host status in test mode */		HostStatDir = NULL;		if (Verbose == 0)			Verbose = 2;		CurEnv->e_errormode = EM_PRINT;		HoldErrs = FALSE;		break;	  case MD_VERIFY:		CurEnv->e_errormode = EM_PRINT;		HoldErrs = FALSE;		/* arrange to exit cleanly on hangup signal */		if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)			(void) setsignal(SIGHUP, intsig);		break;	  case MD_FGDAEMON:		run_in_foreground = TRUE;		OpMode = MD_DAEMON;		/* FALLTHROUGH */	  case MD_DAEMON:		vendor_daemon_setup(CurEnv);		/* remove things that don't make sense in daemon mode */		FullName = NULL;		GrabTo = FALSE;		/* arrange to restart on hangup signal */		if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')			sm_syslog(LOG_WARNING, NOQID,				  "daemon invoked without full pathname; kill -1 won't work");		(void) setsignal(SIGHUP, sighup);		/* workaround: can't seem to release the signal in the parent */		(void) releasesignal(SIGHUP);		break;	  case MD_INITALIAS:		Verbose = 2;		CurEnv->e_errormode = EM_PRINT;		HoldErrs = FALSE;		/* FALLTHROUGH */	  default:		/* arrange to exit cleanly on hangup signal */		if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)			(void) setsignal(SIGHUP, intsig);		break;	}	/* special considerations for FullName */	if (FullName != NULL)	{		char *full = NULL;		/* full names can't have newlines */		if (strchr(FullName, '\n') != NULL)		{			FullName = full = newstr(denlstring(FullName, TRUE, TRUE));		}		/* check for characters that may have to be quoted */		if (!rfc822_string(FullName))		{			/*			**  Quote a full name with special characters			**  as a comment so crackaddr() doesn't destroy			**  the name portion of the address.			*/			FullName = addquotes(FullName);			if (full != NULL)				free(full);		}	}	/* do heuristic mode adjustment */	if (Verbose)	{		/* turn off noconnect option */		setoption('c', "F", TRUE, FALSE, CurEnv);		/* turn on interactive delivery */		setoption('d', "", TRUE, FALSE, CurEnv);	}#ifdef VENDOR_CODE	/* check for vendor mismatch */	if (VendorCode != VENDOR_CODE)	{		message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",			getvendor(VENDOR_CODE), getvendor(VendorCode));	}#endif /* VENDOR_CODE */	/* check for out of date configuration level */	if (ConfigLevel < MAXCONFIGLEVEL)	{		message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",			Version, MAXCONFIGLEVEL, ConfigLevel);	}	if (ConfigLevel < 3)		UseErrorsTo = TRUE;	/* set options that were previous macros */	if (SmtpGreeting == NULL)	{		if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL)			SmtpGreeting = newstr(p);		else			SmtpGreeting = "\201j Sendmail \201v ready at \201b";	}	if (UnixFromLine == NULL)	{		if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL)			UnixFromLine = newstr(p);		else			UnixFromLine = "From \201g  \201d";	}	SmtpError[0] = '\0';	/* our name for SMTP codes */	expand("\201j", jbuf, sizeof jbuf, CurEnv);	MyHostName = jbuf;	if (strchr(jbuf, '.') == NULL)		message("WARNING: local host name (%s) is not qualified; fix $j in config file",			jbuf);	/* make certain that this name is part of the $=w class */	setclass('w', MyHostName);	/* the indices of built-in mailers */	st = stab("local", ST_MAILER, ST_FIND);	if (st != NULL)		LocalMailer = st->s_mailer;	else if (OpMode != MD_TEST || !warn_C_flag)		syserr("No local mailer defined");	st = stab("prog", ST_MAILER, ST_FIND);	if (st == NULL)		syserr("No prog mailer defined");	else	{		ProgMailer = st->s_mailer;		clrbitn(M_MUSER, ProgMailer->m_flags);	}	st = stab("*file*", ST_MAILER, ST_FIND);	if (st == NULL)		syserr("No *file* mailer defined");	else	{		FileMailer = st->s_mailer;		clrbitn(M_MUSER, FileMailer->m_flags);	}	st = stab("*include*", ST_MAILER, ST_FIND);	if (st == NULL)		syserr("No *include* mailer defined");	else		InclMailer = st->s_mailer;	if (ConfigLevel < 6)	{		/* heuristic tweaking of local mailer for back compat */		if (LocalMailer != NULL)		{			setbitn(M_ALIASABLE, LocalMailer->m_flags);			setbitn(M_HASPWENT, LocalMailer->m_flags);			setbitn(M_TRYRULESET5, LocalMailer->m_flags);			setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);			setbitn(M_CHECKPROG, LocalMailer->m_flags);			setbitn(M_CHECKFILE, LocalMailer->m_flags);			setbitn(M_CHECKUDB, LocalMailer->m_flags);		}		if (ProgMailer != NULL)			setbitn(M_RUNASRCPT, ProgMailer->m_flags);		if (FileMailer != NULL)			setbitn(M_RUNASRCPT, FileMailer->m_flags);	}	if (ConfigLevel < 7)	{		if (LocalMailer != NULL)			setbitn(M_VRFY250, LocalMailer->m_flags);		if (ProgMailer != NULL)			setbitn(M_VRFY250, ProgMailer->m_flags);		if (FileMailer != NULL)			setbitn(M_VRFY250, FileMailer->m_flags);	}	/* MIME Content-Types that cannot be transfer encoded */	setclass('n', "multipart/signed");	/* MIME message/xxx subtypes that can be treated as messages */	setclass('s', "rfc822");	/* MIME Content-Transfer-Encodings that can be encoded */	setclass('e', "7bit");	setclass('e', "8bit");	setclass('e', "binary");#ifdef USE_B_CLASS	/* MIME Content-Types that should be treated as binary */	setclass('b', "image");	setclass('b', "audio");	setclass('b', "video");	setclass('b', "application/octet-stream");#endif /* USE_B_CLASS */	/* MIME headers which have fields to check for overflow */	setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition");	setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type");	/* MIME headers to check for length overflow */	setclass(macid("{checkMIMETextHeaders}", NULL), "content-description");	/* MIME headers to check for overflow and rebalance */	setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition");	setclass(macid("{checkMIMEHeaders}", NULL), "content-id");	setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding");	setclass(macid("{checkMIMEHeaders}", NULL), "content-type");	setclass(macid("{checkMIMEHeaders}", NULL), "mime-version");	/* Macros to save in the qf file -- don't remove any */	setclass(macid("{persistentMacros}", NULL), "r");	setclass(macid("{persistentMacros}", NULL), "s");	setclass(macid("{persistentMacros}", NULL), "_");	setclass(macid("{persistentMacros}", NULL), "{if_addr}");	setclass(macid("{persistentMacros}", NULL), "{daemon_flags}");	setclass(macid("{persistentMacros}", NULL), "{client_flags}");	/* operate in queue directory */	if (QueueDir == NULL)	{		if (OpMode != MD_TEST)		{			syserr("QueueDirectory (Q) option must be set");			ExitStat = EX_CONFIG;		}	}	else	{		/*		**  If multiple queues wildcarded, use one for		**  the daemon's home. Note that this preconditions		**  a wildcarded QueueDir to a real pathname.		*/		if (OpMode != MD_TEST)			multiqueue_cache();	}	/* check host status directory for validity */	if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE))	{		/* cannot use this value */		if (tTd(0, 2))			dprintf("Cannot use HostStatusDirectory = %s: %s\n",				HostStatDir, errstring(errno));		HostStatDir = NULL;	}#if QUEUE	if (OpMode == MD_QUEUERUN && RealUid != 0 &&	    bitset(PRIV_RESTRICTQRUN, PrivacyFlags))	{		struct stat stbuf;		/* check to see if we own the queue directory */		if (stat(".", &stbuf) < 0)			syserr("main: cannot stat %s", QueueDir);		if (stbuf.st_uid != RealUid)		{			/* nope, really a botch */			usrerr("You do not have permission to process the queue");			finis(FALSE, EX_NOPERM);		}	}#endif /* QUEUE */#if _FFR_MILTER	/* sanity checks on milter filters */	if (OpMode == MD_DAEMON || OpMode == MD_SMTP)		milter_parse_list(InputFilterList, InputFilters, MAXFILTERS);#endif /* _FFR_MILTER */	/* if we've had errors so far, exit now */	if (ExitStat != EX_OK && OpMode != MD_TEST)		finis(FALSE, ExitStat);#if XDEBUG	checkfd012("before main() initmaps");#endif /* XDEBUG */	/*	**  Do operation-mode-dependent initialization.	*/	switch (OpMode)	{	  case MD_PRINT:		/* print the queue */#if QUEUE		dropenvelope(CurEnv, TRUE);		(void) setsignal(SIGPIPE, quiesce);		printqueue();		finis(FALSE, EX_OK);#else /* QUEUE */		usrerr("No queue to print");		finis(FALSE, EX_UNAVAILABLE);#endif /* QUEUE */		break;	  case MD_HOSTSTAT:		(void) setsignal(SIGPIPE, quiesce);		(void) mci_traverse_persistent(mci_print_persistent, NULL);		finis(FALSE, EX_OK);		break;	  case MD_PURGESTAT:		(void) mci_traverse_persistent(mci_purge_persistent, NULL);		finis(FALSE, EX_OK);		break;	  case MD_INITALIAS:		/* initialize maps */		initmaps();		finis(FALSE, ExitStat);		break;	  case MD_SMTP:	  case MD_DAEMON:		/* reset DSN parameters */		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;		define(macid("{dsn_notify}", NULL), NULL, CurEnv);		CurEnv->e_envid = NULL;		define(macid("{dsn_envid}", NULL), NULL, CurEnv);		CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);		define(macid("{dsn_ret}", NULL), NULL, CurEnv);		/* don't open maps for daemon -- done below in child */		break;	}	if (tTd(0, 15))	{		/* print configuration table (or at least part of it) */		if (tTd(0, 90))			printrules();		for (i = 0; i < MAXMAILERS; i++)		{			if (Mailer[i] != NULL)				printmailer(Mailer[i]);		}	}	/*	**  Switch to the main envelope.	*/	CurEnv = newenvelope(&MainEnvelope, CurEnv);	MainEnvelope.e_flags = BlankEnvelope.e_flags;	/*	**  If test mode, read addresses from stdin and process.	*/	if (OpMode == MD_TEST)	{		char buf[MAXLINE];#if _FFR_TESTMODE_DROP_PRIVS		dp = drop_privileges(TRUE);		if (dp != EX_OK)		{			CurEnv->e_id = NULL;			finis(TRUE, dp);		}#endif /* _FFR_TESTMODE_DROP_PRIVS */		if (isatty(fileno(stdin)))			Verbose = 2;		if (Verbose)		{			printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");			printf("Enter <ruleset> <address>\n");		}		if (setjmp(TopFrame) > 0)			printf("\n");		(void) setsignal(SIGINT, intindebug);		for (;;)		{			if (Verbose == 2)				printf("> ");			(void) fflush(stdout);			if (fgets(buf, sizeof buf, stdin) == NULL)				testmodeline("/quit", CurEnv);			p = strchr(buf, '\n');			if (p != NULL)				*p = '\0';			if (Verbose < 2)				printf("> %s\n", buf);			testmodeline(buf, CurEnv);		}	}#if SMTP# if STARTTLS	/*	**  basic TLS initialization	**  ignore result for now	*/	SSL_library_init();	SSL_load_error_strings();#  if 0	/* this is currently a macro for SSL_library_init */	SSLeay_add_ssl_algorithms();#  endif /* 0 */	/* initialize PRNG */	tls_ok = tls_rand_init(RandFile, 7);# endif /* STARTTLS */#endif /* SMTP */#if QUEUE	/*	**  If collecting stuff from the queue, go start doing that.	*/	if (OpMode == MD_QUEUERUN && QueueIntvl == 0)	{# if SMTP#  if STARTTLS		if (tls_ok		   )		{			/* init TLS for client, ignore result for now */			(void) initclttls();		}#  endif /* STARTTLS */# endif /* SMTP */		(void) runqueue(FALSE, Verbose);		finis(TRUE, ExitStat);	}#endif /* QUEUE */# if SASL	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)	{		/* give a syserr or just disable AUTH ? */		if ((i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK)			syserr("!sasl_server_init failed! [%s]",			       sasl_errstring(i, NULL, NULL));	}# endif /* SASL */	/*	**  If a daemon, wait for a request.	**	getrequests will always return in a child.	**	If we should also be processing the queue, start	**		doing it in background.	**	We check for any errors that might have happened	**		during startup.	*/	if (OpMode == MD_DAEMON || QueueIntvl != 0)	{		char dtype[200];		if (!run_in_foreground && !tTd(99, 100))		{			/* put us in background */			i = fork();			if (i < 0)				syserr("daemon: cannot fork");			if (i != 0)				finis(FALSE, EX_OK);			/* disconnect from our controlling tty */			disconnect(2, CurEnv);		}		dtype[0] = '\0';		if (OpMode == MD_DAEMON)			(void) strlcat(dtype, "+SMTP", sizeof dtype);		if (QueueIntvl != 0)		{			(void) strlcat(dtype, "+queueing@", sizeof dtype);			(void) strlcat(dtype, pintvl(QueueIntvl, TRUE),				       sizeof dtype);		}		if (tTd(0, 1))			(void) strlcat(dtype, "+debugging", sizeof dtype);		sm_syslog(LOG_INFO, NOQID,			  "starting daemon (%s): %s", Version, dtype + 1);#ifdef XLA		xla_create_file();#endif /* XLA */		/* save daemon type in a macro for possible PidFile use */		define(macid("{daemon_info}", NULL),		       newstr(dtype + 1), &BlankEnvelope);		/* save queue interval in a macro for possible PidFile use */		define(macid("{queue_interval}", NULL),		       newstr(pintvl(QueueIntvl, TRUE)), CurEnv);#if QUEUE		if (QueueIntvl != 0)		{			(void) runqueue(TRUE, FALSE);			if (OpMode != MD_DAEMON)			{				/* write the pid to file */				log_sendmail_pid(CurEnv);				for (;;)				{					(void) pause();					if (DoQueueRun)						(void) runqueue(TRUE, FALSE);				}			}		}#endif /* QUEUE */		dropenvelope(CurEnv, TRUE);#if DAEMON# if STARTTLS		/* init TLS for server, ignore result for now */		(void) initsrvtls();# endif /* STARTTLS */		p_flags = getrequests(CurEnv);		/* drop privileges */		(void) drop_privileges(FALSE);		/* at this point we are in a child: reset state */		(void) newenvelope(CurEnv, CurEnv);		/*		**  Get authentication data		*/		authinfo = getauthinfo(fileno(InChannel), &forged);		define('_', authinfo, &BlankEnvelope);#endif /* DAEMON */	}	if (LogLevel > 9)	{		/* log connection information */		sm_syslog(LOG_INFO, NULL, "connect from %.100s", authinfo);	}#if SMTP	/*	**  If running SMTP protocol, start collecting and executing	**  commands.  This will never return.	*/	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)	{		char pbuf[20];		/*		**  Save some macros for check_* rulesets.		*/		if (forged)		{			char ipbuf[103];			(void) snprintf(ipbuf, sizeof ipbuf, "[%.100s]",					anynet_ntoa(&RealHostAddr));			define(macid("{client_name}", NULL),			       newstr(ipbuf), &BlankEnvelope);			define(macid("{client_resolve}", NULL),			       "FORGED", &BlankEnvelope);		}		else			define(macid("{client_name}", NULL), RealHostName,			       &BlankEnvelope);		define(macid("{client_addr}", NULL),		       newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);		(void)sm_getla(&BlankEnvelope);		switch(RealHostAddr.sa.sa_family)		{# if NETINET		  case AF_INET:			(void) snprintf(pbuf, sizeof pbuf, "%d",					RealHostAddr.sin.sin_port);			break;# endif /* NETINET */# if NETINET6		  case AF_INET6:			(void) snprintf(pbuf, sizeof pbuf, "%d",					RealHostAddr.sin6.sin6_port);			break;# endif /* NETINET6 */		  default:			(void) snprintf(pbuf, sizeof pbuf, "0");			break;		}		define(macid("{client_port}", NULL),		       newstr(pbuf), &BlankEnvelope);		if (OpMode == MD_DAEMON)		{			/* validate the connection */			HoldErrs = TRUE;			nullserver = validate_connection(&RealHostAddr,							 RealHostName, CurEnv);			HoldErrs = FALSE;		}		else if (p_flags == NULL)		{			p_flags = (BITMAP256 *) xalloc(sizeof *p_flags);			clrbitmap(p_flags);		}# if STARTTLS		if (OpMode == MD_SMTP)			(void) initsrvtls();# endif /* STARTTLS */		smtp(nullserver, *p_flags, CurEnv);	}#endif /* SMTP */	clearenvelope(CurEnv, FALSE);	if (OpMode == MD_VERIFY)	{		set_delivery_mode(SM_VERIFY, CurEnv);		PostMasterCopy = NULL;	}	else	{		/* interactive -- all errors are global */		CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;	}	/*	**  Do basic system initialization and set the sender	*/	initsys(CurEnv);	define(macid("{ntries}", NULL), "0", CurEnv);	setsender(from, CurEnv, NULL, '\0', FALSE);	if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') &&	    (!bitnset(M_LOCALMAILER, CurEnv->e_from.q_mailer->m_flags) ||	     strcmp(CurEnv->e_from.q_user, RealUserName) != 0))	{		auth_warning(CurEnv, "%s set sender to %s using -%c",			RealUserName, from, warn_f_flag);#if SASL		auth = FALSE;#endif /* SASL */	}	if (auth)	{		char *fv;		/* set the initial sender for AUTH= to $f@$j */		fv = macvalue('f', CurEnv);		if (fv == NULL || *fv == '\0')			CurEnv->e_auth_param = NULL;		else		{			if (strchr(fv, '@') == NULL)			{				i = strlen(fv) + strlen(macvalue('j', CurEnv))				    + 2;				p = xalloc(i);				(void) snprintf(p, i, "%s@%s", fv,						macvalue('j', CurEnv));			}			else				p = newstr(fv);			CurEnv->e_auth_param = newstr(xtextify(p, NULL));		}	}	if (macvalue('s', CurEnv) == NULL)		define('s', RealHostName, CurEnv);	if (*av == NULL && !GrabTo)	{		CurEnv->e_to = NULL;		CurEnv->e_flags |= EF_GLOBALERRS;		HoldErrs = FALSE;		usrerr("Recipient names must be specified");		/* collect body for UUCP return */		if (OpMode != MD_VERIFY)			collect(InChannel, FALSE, NULL, CurEnv);		finis(TRUE, EX_USAGE);	}	/*	**  Scan argv and deliver the message to everyone.	*/	sendtoargv(av, CurEnv);	/* if we have had errors sofar, arrange a meaningful exit stat */	if (Errors > 0 && ExitStat == EX_OK)		ExitStat = EX_USAGE;#if _FFR_FIX_DASHT	/*	**  If using -t, force not sending to argv recipients, even	**  if they are mentioned in the headers.	*/	if (GrabTo)	{		ADDRESS *q;		for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)			q->q_state = QS_REMOVED;	}#endif /* _FFR_FIX_DASHT */	/*	**  Read the input mail.	*/	CurEnv->e_to = NULL;	if (OpMode != MD_VERIFY || GrabTo)	{		int savederrors = Errors;		long savedflags = CurEnv->e_flags & EF_FATALERRS;		CurEnv->e_flags |= EF_GLOBALERRS;		CurEnv->e_flags &= ~EF_FATALERRS;		Errors = 0;		buffer_errors();		collect(InChannel, FALSE, NULL, CurEnv);		/* header checks failed */		if (Errors > 0)		{			/* Log who the mail would have gone to */			if (LogLevel > 8 && CurEnv->e_message != NULL &&			    !GrabTo)			{				ADDRESS *a;				for (a = CurEnv->e_sendqueue;				     a != NULL;				     a = a->q_next)				{					if (!QS_IS_UNDELIVERED(a->q_state))						continue;					CurEnv->e_to = a->q_paddr;					logdelivery(NULL, NULL, NULL,						    CurEnv->e_message,						    NULL, (time_t) 0, CurEnv);				}				CurEnv->e_to = NULL;			}			flush_errors(TRUE);			finis(TRUE, ExitStat);			/* NOTREACHED */			return -1;		}		/* bail out if message too large */		if (bitset(EF_CLRQUEUE, CurEnv->e_flags))		{			finis(TRUE, ExitStat != EX_OK ? ExitStat : EX_DATAERR);			/* NOTREACHED */			return -1;		}		Errors = savederrors;		CurEnv->e_flags |= savedflags;	}	errno = 0;	if (tTd(1, 1))		dprintf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);	/*	**  Actually send everything.	**	If verifying, just ack.	*/	CurEnv->e_from.q_state = QS_SENDER;	if (tTd(1, 5))	{		dprintf("main: QS_SENDER ");		printaddr(&CurEnv->e_from, FALSE);	}	CurEnv->e_to = NULL;	CurrentLA = sm_getla(CurEnv);	GrabTo = FALSE;#if NAMED_BIND	_res.retry = TimeOuts.res_retry[RES_TO_FIRST];	_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];#endif /* NAMED_BIND */	sendall(CurEnv, SM_DEFAULT);	/*	**  All done.	**	Don't send return error message if in VERIFY mode.	*/	finis(TRUE, ExitStat);	/* NOTREACHED */	return ExitStat;}