xref: /csrg-svn/usr.sbin/sendmail/src/readcf.c (revision 10343)
1 # include "sendmail.h"
2 
3 SCCSID(@(#)readcf.c	3.51		01/16/83);
4 
5 /*
6 **  READCF -- read control file.
7 **
8 **	This routine reads the control file and builds the internal
9 **	form.
10 **
11 **	The file is formatted as a sequence of lines, each taken
12 **	atomically.  The first character of each line describes how
13 **	the line is to be interpreted.  The lines are:
14 **		Dxval		Define macro x to have value val.
15 **		Cxword		Put word into class x.
16 **		Fxfile [fmt]	Read file for lines to put into
17 **				class x.  Use scanf string 'fmt'
18 **				or "%s" if not present.  Fmt should
19 **				only produce one string-valued result.
20 **		Hname: value	Define header with field-name 'name'
21 **				and value as specified; this will be
22 **				macro expanded immediately before
23 **				use.
24 **		Sn		Use rewriting set n.
25 **		Rlhs rhs	Rewrite addresses that match lhs to
26 **				be rhs.
27 **		Mn p f s r a	Define mailer.  n - internal name,
28 **				p - pathname, f - flags, s - rewriting
29 **				ruleset for sender, s - rewriting ruleset
30 **				for recipients, a - argument vector.
31 **		Oxvalue		Set option x to value.
32 **		Pname=value	Set precedence name to value.
33 **
34 **	Parameters:
35 **		cfname -- control file name.
36 **		safe -- set if this is a system configuration file.
37 **			Non-system configuration files can not do
38 **			certain things (e.g., leave the SUID bit on
39 **			when executing mailers).
40 **
41 **	Returns:
42 **		none.
43 **
44 **	Side Effects:
45 **		Builds several internal tables.
46 */
47 
48 readcf(cfname, safe)
49 	char *cfname;
50 	bool safe;
51 {
52 	FILE *cf;
53 	int class;
54 	int ruleset = 0;
55 	char *q;
56 	char **pv;
57 	struct rewrite *rwp = NULL;
58 	char buf[MAXLINE];
59 	register char *p;
60 	extern char **prescan();
61 	extern char **copyplist();
62 	char exbuf[MAXLINE];
63 	extern char *fgetfolded();
64 
65 	cf = fopen(cfname, "r");
66 	if (cf == NULL)
67 	{
68 		syserr("cannot open %s", cfname);
69 		exit(EX_OSFILE);
70 	}
71 
72 	FileName = cfname;
73 	LineNumber = 0;
74 	while (fgetfolded(buf, sizeof buf, cf) != NULL)
75 	{
76 		switch (buf[0])
77 		{
78 		  case '\0':
79 		  case '#':		/* comment */
80 			break;
81 
82 		  case 'R':		/* rewriting rule */
83 			for (p = &buf[1]; *p != '\0' && *p != '\t'; p++)
84 				continue;
85 
86 			if (*p == '\0')
87 			{
88 				syserr("invalid rewrite line \"%s\"", buf);
89 				break;
90 			}
91 
92 			/* allocate space for the rule header */
93 			if (rwp == NULL)
94 			{
95 				RewriteRules[ruleset] = rwp =
96 					(struct rewrite *) xalloc(sizeof *rwp);
97 			}
98 			else
99 			{
100 				rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
101 				rwp = rwp->r_next;
102 			}
103 			rwp->r_next = NULL;
104 
105 			/* expand and save the LHS */
106 			*p = '\0';
107 			expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv);
108 			rwp->r_lhs = prescan(exbuf, '\t');
109 			if (rwp->r_lhs != NULL)
110 				rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
111 
112 			/* expand and save the RHS */
113 			while (*++p == '\t')
114 				continue;
115 			q = p;
116 			while (*p != '\0' && *p != '\t')
117 				p++;
118 			*p = '\0';
119 			expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv);
120 			rwp->r_rhs = prescan(exbuf, '\t');
121 			if (rwp->r_rhs != NULL)
122 				rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
123 			break;
124 
125 		  case 'S':		/* select rewriting set */
126 			ruleset = atoi(&buf[1]);
127 			if (ruleset >= MAXRWSETS || ruleset < 0)
128 			{
129 				syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS);
130 				ruleset = 0;
131 			}
132 			rwp = NULL;
133 			break;
134 
135 		  case 'D':		/* macro definition */
136 			define(buf[1], newstr(&buf[2]), CurEnv);
137 			break;
138 
139 		  case 'H':		/* required header line */
140 			(void) chompheader(&buf[1], TRUE);
141 			break;
142 
143 		  case 'C':		/* word class */
144 		  case 'F':		/* word class from file */
145 			class = buf[1];
146 			if (!isalpha(class))
147 			{
148 				syserr("illegal class name %c", class);
149 				break;
150 			}
151 			if (isupper(class))
152 				class -= 'A';
153 			else
154 				class -= 'a';
155 
156 			/* read list of words from argument or file */
157 			if (buf[0] == 'F')
158 			{
159 				/* read from file */
160 				for (p = &buf[2]; *p != '\0' && !isspace(*p); p++)
161 					continue;
162 				if (*p == '\0')
163 					p = "%s";
164 				else
165 				{
166 					*p = '\0';
167 					while (isspace(*++p))
168 						continue;
169 				}
170 				fileclass(class, &buf[2], p);
171 				break;
172 			}
173 
174 			/* scan the list of words and set class for all */
175 			for (p = &buf[2]; *p != '\0'; )
176 			{
177 				register char *wd;
178 				char delim;
179 				register STAB *s;
180 
181 				while (*p != '\0' && isspace(*p))
182 					p++;
183 				wd = p;
184 				while (*p != '\0' && !isspace(*p))
185 					p++;
186 				delim = *p;
187 				*p = '\0';
188 				if (wd[0] != '\0')
189 				{
190 					s = stab(wd, ST_CLASS, ST_ENTER);
191 					s->s_class |= 1L << class;
192 				}
193 				*p = delim;
194 			}
195 			break;
196 
197 		  case 'M':		/* define mailer */
198 			makemailer(&buf[1], safe);
199 			break;
200 
201 		  case 'O':		/* set option */
202 			setoption(buf[1], &buf[2], safe, FALSE);
203 			break;
204 
205 		  case 'P':		/* set precedence */
206 			if (NumPriorities >= MAXPRIORITIES)
207 			{
208 				toomany('P', MAXPRIORITIES);
209 				break;
210 			}
211 			for (p = &buf[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
212 				continue;
213 			if (*p == '\0')
214 				goto badline;
215 			*p = '\0';
216 			Priorities[NumPriorities].pri_name = newstr(&buf[1]);
217 			Priorities[NumPriorities].pri_val = atoi(++p);
218 			NumPriorities++;
219 			break;
220 
221 		  case 'T':		/* trusted user(s) */
222 			p = &buf[1];
223 			while (*p != '\0')
224 			{
225 				while (isspace(*p))
226 					p++;
227 				q = p;
228 				while (*p != '\0' && !isspace(*p))
229 					p++;
230 				if (*p != '\0')
231 					*p++ = '\0';
232 				if (*q == '\0')
233 					continue;
234 				for (pv = TrustedUsers; *pv != NULL; pv++)
235 					continue;
236 				if (pv >= &TrustedUsers[MAXTRUST])
237 				{
238 					toomany('T', MAXTRUST);
239 					break;
240 				}
241 				*pv = newstr(q);
242 			}
243 			break;
244 
245 		  default:
246 		  badline:
247 			syserr("unknown control line \"%s\"", buf);
248 		}
249 	}
250 	FileName = NULL;
251 }
252 /*
253 **  TOOMANY -- signal too many of some option
254 **
255 **	Parameters:
256 **		id -- the id of the error line
257 **		maxcnt -- the maximum possible values
258 **
259 **	Returns:
260 **		none.
261 **
262 **	Side Effects:
263 **		gives a syserr.
264 */
265 
266 toomany(id, maxcnt)
267 	char id;
268 	int maxcnt;
269 {
270 	syserr("too many %c lines, %d max", id, maxcnt);
271 }
272 /*
273 **  FILECLASS -- read members of a class from a file
274 **
275 **	Parameters:
276 **		class -- class to define.
277 **		filename -- name of file to read.
278 **		fmt -- scanf string to use for match.
279 **
280 **	Returns:
281 **		none
282 **
283 **	Side Effects:
284 **
285 **		puts all lines in filename that match a scanf into
286 **			the named class.
287 */
288 
289 fileclass(class, filename, fmt)
290 	int class;
291 	char *filename;
292 	char *fmt;
293 {
294 	register FILE *f;
295 	char buf[MAXLINE];
296 
297 	f = fopen(filename, "r");
298 	if (f == NULL)
299 	{
300 		syserr("cannot open %s", filename);
301 		return;
302 	}
303 
304 	while (fgets(buf, sizeof buf, f) != NULL)
305 	{
306 		register STAB *s;
307 		char wordbuf[MAXNAME+1];
308 
309 		if (sscanf(buf, fmt, wordbuf) != 1)
310 			continue;
311 		s = stab(wordbuf, ST_CLASS, ST_ENTER);
312 		s->s_class |= 1L << class;
313 	}
314 
315 	(void) fclose(f);
316 }
317 /*
318 **  MAKEMAILER -- define a new mailer.
319 **
320 **	Parameters:
321 **		line -- description of mailer.  This is in labeled
322 **			fields.  The fields are:
323 **			   P -- the path to the mailer
324 **			   F -- the flags associated with the mailer
325 **			   A -- the argv for this mailer
326 **			   S -- the sender rewriting set
327 **			   R -- the recipient rewriting set
328 **			   E -- the eol string
329 **			The first word is the canonical name of the mailer.
330 **		safe -- set if this is a safe configuration file.
331 **
332 **	Returns:
333 **		none.
334 **
335 **	Side Effects:
336 **		enters the mailer into the mailer table.
337 */
338 
339 makemailer(line, safe)
340 	char *line;
341 	bool safe;
342 {
343 	register char *p;
344 	register struct mailer *m;
345 	register STAB *s;
346 	int i;
347 	char fcode;
348 	extern u_long mfencode();
349 	extern int NextMailer;
350 	extern char **makeargv();
351 	extern char *munchstring();
352 	extern char *DelimChar;
353 
354 	/* allocate a mailer and set up defaults */
355 	m = (struct mailer *) xalloc(sizeof *m);
356 	bzero((char *) m, sizeof *m);
357 	m->m_mno = NextMailer;
358 	m->m_eol = "\n";
359 
360 	/* collect the mailer name */
361 	for (p = line; *p != '\0' && *p != ',' && !isspace(*p); p++)
362 		continue;
363 	if (*p != '\0')
364 		*p++ = '\0';
365 	m->m_name = newstr(line);
366 
367 	/* now scan through and assign info from the fields */
368 	while (*p != '\0')
369 	{
370 		while (*p != '\0' && (*p == ',' || isspace(*p)))
371 			p++;
372 
373 		/* p now points to field code */
374 		fcode = *p;
375 		while (*p != '\0' && *p != '=' && *p != ',')
376 			p++;
377 		if (*p++ != '=')
378 		{
379 			syserr("`=' expected");
380 			return;
381 		}
382 		while (isspace(*p))
383 			p++;
384 
385 		/* p now points to the field body */
386 		p = munchstring(p);
387 
388 		/* install the field into the mailer struct */
389 		switch (fcode)
390 		{
391 		  case 'P':		/* pathname */
392 			m->m_mailer = newstr(p);
393 			break;
394 
395 		  case 'F':		/* flags */
396 			m->m_flags = mfencode(p);
397 			if (!safe)
398 				m->m_flags &= ~M_RESTR;
399 			break;
400 
401 		  case 'S':		/* sender rewriting ruleset */
402 		  case 'R':		/* recipient rewriting ruleset */
403 			i = atoi(p);
404 			if (i < 0 || i >= MAXRWSETS)
405 			{
406 				syserr("invalid rewrite set, %d max", MAXRWSETS);
407 				return;
408 			}
409 			if (fcode == 'S')
410 				m->m_s_rwset = i;
411 			else
412 				m->m_r_rwset = i;
413 			break;
414 
415 		  case 'E':		/* end of line string */
416 			m->m_eol = newstr(p);
417 			break;
418 
419 		  case 'A':		/* argument vector */
420 			m->m_argv = makeargv(p);
421 			break;
422 		}
423 
424 		p = DelimChar;
425 	}
426 
427 	/* now store the mailer away */
428 	if (NextMailer >= MAXMAILERS)
429 	{
430 		syserr("too many mailers defined (%d max)", MAXMAILERS);
431 		return;
432 	}
433 	Mailer[NextMailer++] = m;
434 	s = stab(m->m_name, ST_MAILER, ST_ENTER);
435 	s->s_mailer = m;
436 }
437 /*
438 **  MUNCHSTRING -- translate a string into internal form.
439 **
440 **	Parameters:
441 **		p -- the string to munch.
442 **
443 **	Returns:
444 **		the munched string.
445 **
446 **	Side Effects:
447 **		Sets "DelimChar" to point to the string that caused us
448 **		to stop.
449 */
450 
451 char *
452 munchstring(p)
453 	register char *p;
454 {
455 	register char *q;
456 	bool backslash = FALSE;
457 	bool quotemode = FALSE;
458 	static char buf[MAXLINE];
459 	extern char *DelimChar;
460 
461 	for (q = buf; *p != '\0'; p++)
462 	{
463 		if (backslash)
464 		{
465 			/* everything is roughly literal */
466 			switch (*p)
467 			{
468 			  case 'r':		/* carriage return */
469 				*q++ = '\r';
470 				continue;
471 
472 			  case 'n':		/* newline */
473 				*q++ = '\n';
474 				continue;
475 
476 			  case 'f':		/* form feed */
477 				*q++ = '\f';
478 				continue;
479 
480 			  case 'b':		/* backspace */
481 				*q++ = '\b';
482 				continue;
483 			}
484 			*q++ = *p;
485 			backslash = FALSE;
486 		}
487 		else
488 		{
489 			if (*p == '\\')
490 				backslash = TRUE;
491 			else if (*p == '"')
492 				quotemode = !quotemode;
493 			else if (quotemode || *p != ',')
494 				*q++ = *p;
495 			else
496 				break;
497 		}
498 	}
499 
500 	DelimChar = p;
501 	*q++ = '\0';
502 	return (buf);
503 }
504 /*
505 **  MAKEARGV -- break up a string into words
506 **
507 **	Parameters:
508 **		p -- the string to break up.
509 **
510 **	Returns:
511 **		a char **argv (dynamically allocated)
512 **
513 **	Side Effects:
514 **		munges p.
515 */
516 
517 char **
518 makeargv(p)
519 	register char *p;
520 {
521 	char *q;
522 	int i;
523 	char **avp;
524 	char *argv[MAXPV + 1];
525 
526 	/* take apart the words */
527 	i = 0;
528 	while (*p != '\0' && i < MAXPV)
529 	{
530 		q = p;
531 		while (*p != '\0' && !isspace(*p))
532 			p++;
533 		while (isspace(*p))
534 			*p++ = '\0';
535 		argv[i++] = newstr(q);
536 	}
537 	argv[i++] = NULL;
538 
539 	/* now make a copy of the argv */
540 	avp = (char **) xalloc(sizeof *avp * i);
541 	bmove((char *) argv, (char *) avp, sizeof *avp * i);
542 
543 	return (avp);
544 }
545 /*
546 **  PRINTRULES -- print rewrite rules (for debugging)
547 **
548 **	Parameters:
549 **		none.
550 **
551 **	Returns:
552 **		none.
553 **
554 **	Side Effects:
555 **		prints rewrite rules.
556 */
557 
558 # ifdef DEBUG
559 
560 printrules()
561 {
562 	register struct rewrite *rwp;
563 	register int ruleset;
564 
565 	for (ruleset = 0; ruleset < 10; ruleset++)
566 	{
567 		if (RewriteRules[ruleset] == NULL)
568 			continue;
569 		printf("\n----Rule Set %d:", ruleset);
570 
571 		for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
572 		{
573 			printf("\nLHS:");
574 			printav(rwp->r_lhs);
575 			printf("RHS:");
576 			printav(rwp->r_rhs);
577 		}
578 	}
579 }
580 
581 # endif DEBUG
582 /*
583 **  MFENCODE -- crack mailer options
584 **
585 **	These options modify the functioning of the mailer
586 **	from the configuration table.
587 **
588 **	Parameters:
589 **		p -- pointer to vector of options.
590 **
591 **	Returns:
592 **		option list in binary.
593 **
594 **	Side Effects:
595 **		none.
596 */
597 
598 struct optlist
599 {
600 	char	opt_name;	/* external name of option */
601 	u_long	opt_value;	/* internal name of option */
602 };
603 struct optlist	OptList[] =
604 {
605 	'A',	M_ARPAFMT,
606 	'C',	M_CANONICAL,
607 	'D',	M_NEEDDATE,
608 	'e',	M_EXPENSIVE,
609 	'F',	M_NEEDFROM,
610 	'f',	M_FOPT,
611 	'h',	M_HST_UPPER,
612 	'I',	M_INTERNAL,
613 	'L',	M_LIMITS,
614 	'l',	M_LOCAL,
615 	'M',	M_MSGID,
616 	'm',	M_MUSER,
617 	'n',	M_NHDR,
618 	'P',	M_RPATH,
619 	'p',	M_FROMPATH,
620 	'r',	M_ROPT,
621 	'S',	M_RESTR,
622 	's',	M_STRIPQ,
623 	'U',	M_UGLYUUCP,
624 	'u',	M_USR_UPPER,
625 	'x',	M_FULLNAME,
626 	'X',	M_XDOT,
627 	'\0',	0
628 };
629 
630 u_long
631 mfencode(p)
632 	register char *p;
633 {
634 	register struct optlist *o;
635 	register u_long opts = 0;
636 
637 	while (*p != '\0')
638 	{
639 		for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++)
640 			continue;
641 		opts |= o->opt_value;
642 		p++;
643 	}
644 	return (opts);
645 }
646 /*
647 **  MFDECODE -- decode mailer flags into external form.
648 **
649 **	Parameters:
650 **		flags -- value of flags to decode.
651 **		f -- file to write them onto.
652 **
653 **	Returns:
654 **		none.
655 **
656 **	Side Effects:
657 **		none.
658 */
659 
660 mfdecode(flags, f)
661 	u_long flags;
662 	FILE *f;
663 {
664 	register struct optlist *o;
665 
666 	putc('?', f);
667 	for (o = OptList; o->opt_name != '\0'; o++)
668 	{
669 		if ((o->opt_value & flags) == o->opt_value)
670 		{
671 			flags &= ~o->opt_value;
672 			putc(o->opt_name, f);
673 		}
674 	}
675 	putc('?', f);
676 }
677 /*
678 **  SETOPTION -- set global processing option
679 **
680 **	Parameters:
681 **		opt -- option name.
682 **		val -- option value (as a text string).
683 **		safe -- if set, this came from a system configuration file.
684 **		sticky -- if set, don't let other setoptions override
685 **			this value.
686 **
687 **	Returns:
688 **		none.
689 **
690 **	Side Effects:
691 **		Sets options as implied by the arguments.
692 */
693 
694 static int	StickyOpt[128 / sizeof (int)];	/* set if option is stuck */
695 extern char	*WizWord;			/* the stored wizard password */
696 #ifdef DAEMON
697 extern int	MaxConnections;			/* max simult. SMTP conns */
698 #endif DAEMON
699 
700 setoption(opt, val, safe, sticky)
701 	char opt;
702 	char *val;
703 	bool safe;
704 	bool sticky;
705 {
706 	int smask;
707 	int sindex;
708 	extern bool atobool();
709 
710 # ifdef DEBUG
711 	if (tTd(37, 1))
712 		printf("setoption %c=%s", opt, val);
713 # endif DEBUG
714 
715 	/*
716 	**  See if this option is preset for us.
717 	*/
718 
719 	sindex = opt;
720 	smask = 1 << (sindex % sizeof (int));
721 	sindex /= sizeof (int);
722 	if (bitset(smask, StickyOpt[sindex]))
723 	{
724 # ifdef DEBUG
725 		if (tTd(37, 1))
726 			printf(" (ignored)\n");
727 # endif DEBUG
728 		return;
729 	}
730 #ifdef DEBUG
731 	else if (tTd(37, 1))
732 		printf("\n");
733 #endif DEBUG
734 	if (sticky)
735 		StickyOpt[sindex] |= smask;
736 
737 	if (getruid() == 0)
738 		safe = TRUE;
739 
740 	switch (opt)
741 	{
742 	  case 'A':		/* set default alias file */
743 		if (val[0] == '\0')
744 			AliasFile = "aliases";
745 		else
746 			AliasFile = newstr(val);
747 		break;
748 
749 	  case 'a':		/* look for "@:@" in alias file */
750 		SafeAlias = atobool(val);
751 		break;
752 
753 	  case 'c':		/* don't connect to "expensive" mailers */
754 		NoConnect = atobool(val);
755 		break;
756 
757 	  case 'd':		/* delivery mode */
758 		switch (*val)
759 		{
760 		  case '\0':
761 			SendMode = SM_DELIVER;
762 			break;
763 
764 		  case SM_DELIVER:	/* do everything */
765 		  case SM_FORK:		/* fork after verification */
766 		  case SM_QUEUE:	/* queue only */
767 			SendMode = *val;
768 			break;
769 
770 		  default:
771 			syserr("Unknown delivery mode %c", *val);
772 			exit(EX_USAGE);
773 		}
774 		break;
775 
776 	  case 'D':		/* rebuild alias database as needed */
777 		AutoRebuild = atobool(val);
778 		break;
779 
780 	  case 'e':		/* set error processing mode */
781 		switch (*val)
782 		{
783 		  case EM_QUIET:	/* be silent about it */
784 			(void) freopen("/dev/null", "w", stdout);
785 			/* fall through... */
786 
787 		  case EM_MAIL:		/* mail back */
788 		  case EM_BERKNET:	/* do berknet error processing */
789 		  case EM_WRITE:	/* write back (or mail) */
790 			HoldErrs = TRUE;
791 			/* fall through... */
792 
793 		  case EM_PRINT:	/* print errors normally (default) */
794 			ErrorMode = *val;
795 			break;
796 		}
797 		break;
798 
799 	  case 'F':		/* file mode */
800 		FileMode = atooct(val);
801 		break;
802 
803 	  case 'f':		/* save Unix-style From lines on front */
804 		SaveFrom = atobool(val);
805 		break;
806 
807 	  case 'g':		/* default gid */
808 		if (safe)
809 			DefGid = atoi(val);
810 		break;
811 
812 	  case 'H':		/* help file */
813 		if (val[0] == '\0')
814 			HelpFile = "sendmail.hf";
815 		else
816 			HelpFile = newstr(val);
817 		break;
818 
819 	  case 'i':		/* ignore dot lines in message */
820 		IgnrDot = atobool(val);
821 		break;
822 
823 	  case 'L':		/* log level */
824 		LogLevel = atoi(val);
825 		break;
826 
827 	  case 'M':		/* define macro */
828 		define(val[0], newstr(&val[1]), CurEnv);
829 		break;
830 
831 	  case 'm':		/* send to me too */
832 		MeToo = atobool(val);
833 		break;
834 
835 #ifdef DAEMON
836 	  case 'N':		/* maximum simultaneous SMTP connections */
837 		MaxConnections = atoi(val);
838 		break;
839 #endif DAEMON
840 
841 	  case 'o':		/* assume old style headers */
842 		if (atobool(val))
843 			CurEnv->e_flags |= EF_OLDSTYLE;
844 		else
845 			CurEnv->e_flags &= ~EF_OLDSTYLE;
846 		break;
847 
848 	  case 'Q':		/* queue directory */
849 		if (val[0] == '\0')
850 			QueueDir = "mqueue";
851 		else
852 			QueueDir = newstr(val);
853 		break;
854 
855 	  case 'r':		/* read timeout */
856 		ReadTimeout = convtime(val);
857 		break;
858 
859 	  case 'S':		/* status file */
860 		if (val[0] == '\0')
861 			StatFile = "sendmail.st";
862 		else
863 			StatFile = newstr(val);
864 		break;
865 
866 	  case 's':		/* be super safe, even if expensive */
867 		SuperSafe = atobool(val);
868 		break;
869 
870 	  case 'T':		/* queue timeout */
871 		TimeOut = convtime(val);
872 		break;
873 
874 	  case 't':		/* time zone name */
875 # ifdef V6
876 		StdTimezone = newstr(val);
877 		DstTimezone = index(StdTimeZone, ',');
878 		if (DstTimezone == NULL)
879 			syserr("bad time zone spec");
880 		else
881 			*DstTimezone++ = '\0';
882 # endif V6
883 		break;
884 
885 	  case 'u':		/* set default uid */
886 		if (safe)
887 			DefUid = atoi(val);
888 		break;
889 
890 	  case 'v':		/* run in verbose mode */
891 		Verbose = atobool(val);
892 		break;
893 
894 # ifdef DEBUG
895 	  case 'W':		/* set the wizards password */
896 		if (safe)
897 			WizWord = newstr(val);
898 		break;
899 # endif DEBUG
900 
901 	  default:
902 		break;
903 	}
904 	return;
905 }
906