xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 7356)
1 # include <stdio.h>
2 # include <sys/types.h>
3 # include <sys/stat.h>
4 # include <sysexits.h>
5 # include <errno.h>
6 # include <ctype.h>
7 # include "sendmail.h"
8 
9 SCCSID(@(#)util.c	3.19		07/05/82);
10 
11 /*
12 **  STRIPQUOTES -- Strip quotes & quote bits from a string.
13 **
14 **	Runs through a string and strips off unquoted quote
15 **	characters and quote bits.  This is done in place.
16 **
17 **	Parameters:
18 **		s -- the string to strip.
19 **		qf -- if set, remove actual `` " '' characters
20 **			as well as the quote bits.
21 **
22 **	Returns:
23 **		none.
24 **
25 **	Side Effects:
26 **		none.
27 **
28 **	Called By:
29 **		deliver
30 */
31 
32 stripquotes(s, qf)
33 	char *s;
34 	bool qf;
35 {
36 	register char *p;
37 	register char *q;
38 	register char c;
39 
40 	if (s == NULL)
41 		return;
42 
43 	for (p = q = s; (c = *p++) != '\0'; )
44 	{
45 		if (c != '"' || !qf)
46 			*q++ = c & 0177;
47 	}
48 	*q = '\0';
49 }
50 /*
51 **  CAPITALIZE -- return a copy of a string, properly capitalized.
52 **
53 **	Parameters:
54 **		s -- the string to capitalize.
55 **
56 **	Returns:
57 **		a pointer to a properly capitalized string.
58 **
59 **	Side Effects:
60 **		none.
61 */
62 
63 char *
64 capitalize(s)
65 	register char *s;
66 {
67 	static char buf[50];
68 	register char *p;
69 
70 	p = buf;
71 
72 	for (;;)
73 	{
74 		while (!isalpha(*s) && *s != '\0')
75 			*p++ = *s++;
76 		if (*s == '\0')
77 			break;
78 		*p++ = toupper(*s++);
79 		while (isalpha(*s))
80 			*p++ = *s++;
81 	}
82 
83 	*p = '\0';
84 	return (buf);
85 }
86 /*
87 **  XALLOC -- Allocate memory and bitch wildly on failure.
88 **
89 **	THIS IS A CLUDGE.  This should be made to give a proper
90 **	error -- but after all, what can we do?
91 **
92 **	Parameters:
93 **		sz -- size of area to allocate.
94 **
95 **	Returns:
96 **		pointer to data region.
97 **
98 **	Side Effects:
99 **		Memory is allocated.
100 */
101 
102 char *
103 xalloc(sz)
104 	register int sz;
105 {
106 	register char *p;
107 
108 	p = malloc(sz);
109 	if (p == NULL)
110 	{
111 		syserr("Out of memory!!");
112 		exit(EX_UNAVAILABLE);
113 	}
114 	return (p);
115 }
116 /*
117 **  NEWSTR -- make copy of string.
118 **
119 **	Space is allocated for it using xalloc.
120 **
121 **	Parameters:
122 **		string to copy.
123 **
124 **	Returns:
125 **		pointer to new string.
126 **
127 **	Side Effects:
128 **		none.
129 */
130 
131 char *
132 newstr(s)
133 	register char *s;
134 {
135 	register char *p;
136 
137 	p = xalloc(strlen(s) + 1);
138 	(void) strcpy(p, s);
139 	return (p);
140 }
141 /*
142 **  COPYPLIST -- copy list of pointers.
143 **
144 **	This routine is the equivalent of newstr for lists of
145 **	pointers.
146 **
147 **	Parameters:
148 **		list -- list of pointers to copy.
149 **			Must be NULL terminated.
150 **		copycont -- if TRUE, copy the contents of the vector
151 **			(which must be a string) also.
152 **
153 **	Returns:
154 **		a copy of 'list'.
155 **
156 **	Side Effects:
157 **		none.
158 */
159 
160 char **
161 copyplist(list, copycont)
162 	char **list;
163 	bool copycont;
164 {
165 	register char **vp;
166 	register char **newvp;
167 
168 	for (vp = list; *vp != NULL; vp++)
169 		continue;
170 
171 	vp++;
172 
173 	newvp = (char **) xalloc((vp - list) * sizeof *vp);
174 	bmove((char *) list, (char *) newvp, (vp - list) * sizeof *vp);
175 
176 	if (copycont)
177 	{
178 		for (vp = newvp; *vp != NULL; vp++)
179 			*vp = newstr(*vp);
180 	}
181 
182 	return (newvp);
183 }
184 /*
185 **  PRINTAV -- print argument vector.
186 **
187 **	Parameters:
188 **		av -- argument vector.
189 **
190 **	Returns:
191 **		none.
192 **
193 **	Side Effects:
194 **		prints av.
195 */
196 
197 # ifdef DEBUG
198 printav(av)
199 	register char **av;
200 {
201 	while (*av != NULL)
202 	{
203 		printf("\t%08x=", *av);
204 		xputs(*av++);
205 		putchar('\n');
206 	}
207 }
208 # endif DEBUG
209 /*
210 **  LOWER -- turn letter into lower case.
211 **
212 **	Parameters:
213 **		c -- character to turn into lower case.
214 **
215 **	Returns:
216 **		c, in lower case.
217 **
218 **	Side Effects:
219 **		none.
220 */
221 
222 char
223 lower(c)
224 	register char c;
225 {
226 	if (isascii(c) && isupper(c))
227 		c = c - 'A' + 'a';
228 	return (c);
229 }
230 /*
231 **  XPUTS -- put string doing control escapes.
232 **
233 **	Parameters:
234 **		s -- string to put.
235 **
236 **	Returns:
237 **		none.
238 **
239 **	Side Effects:
240 **		output to stdout
241 */
242 
243 # ifdef DEBUG
244 xputs(s)
245 	register char *s;
246 {
247 	register char c;
248 
249 	while ((c = *s++) != '\0')
250 	{
251 		if (!isascii(c))
252 		{
253 			putchar('\\');
254 			c &= 0177;
255 		}
256 		if (iscntrl(c))
257 		{
258 			putchar('^');
259 			c |= 0100;
260 		}
261 		putchar(c);
262 	}
263 	(void) fflush(stdout);
264 }
265 # endif DEBUG
266 /*
267 **  MAKELOWER -- Translate a line into lower case
268 **
269 **	Parameters:
270 **		p -- the string to translate.  If NULL, return is
271 **			immediate.
272 **
273 **	Returns:
274 **		none.
275 **
276 **	Side Effects:
277 **		String pointed to by p is translated to lower case.
278 **
279 **	Called By:
280 **		parse
281 */
282 
283 makelower(p)
284 	register char *p;
285 {
286 	register char c;
287 
288 	if (p == NULL)
289 		return;
290 	for (; (c = *p) != '\0'; p++)
291 		if (isascii(c) && isupper(c))
292 			*p = c - 'A' + 'a';
293 }
294 /*
295 **  SAMEWORD -- return TRUE if the words are the same
296 **
297 **	Ignores case.
298 **
299 **	Parameters:
300 **		a, b -- the words to compare.
301 **
302 **	Returns:
303 **		TRUE if a & b match exactly (modulo case)
304 **		FALSE otherwise.
305 **
306 **	Side Effects:
307 **		none.
308 */
309 
310 bool
311 sameword(a, b)
312 	register char *a, *b;
313 {
314 	while (lower(*a) == lower(*b))
315 	{
316 		if (*a == '\0')
317 			return (TRUE);
318 		a++;
319 		b++;
320 	}
321 	return (FALSE);
322 }
323 /*
324 **  CLEAR -- clear a block of memory
325 **
326 **	Parameters:
327 **		p -- location to clear.
328 **		l -- number of bytes to clear.
329 **
330 **	Returns:
331 **		none.
332 **
333 **	Side Effects:
334 **		none.
335 */
336 
337 clear(p, l)
338 	register char *p;
339 	register int l;
340 {
341 	while (l-- > 0)
342 		*p++ = 0;
343 }
344 /*
345 **  BUILDFNAME -- build full name from gecos style entry.
346 **
347 **	This routine interprets the strange entry that would appear
348 **	in the GECOS field of the password file.
349 **
350 **	Parameters:
351 **		p -- name to build.
352 **		login -- the login name of this user (for &).
353 **		buf -- place to put the result.
354 **
355 **	Returns:
356 **		none.
357 **
358 **	Side Effects:
359 **		none.
360 */
361 
362 buildfname(p, login, buf)
363 	register char *p;
364 	char *login;
365 	char *buf;
366 {
367 	register char *bp = buf;
368 
369 	if (*p == '*')
370 		p++;
371 	while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
372 	{
373 		if (*p == '&')
374 		{
375 			(void) strcpy(bp, login);
376 			*bp = toupper(*bp);
377 			while (*bp != '\0')
378 				bp++;
379 			p++;
380 		}
381 		else
382 			*bp++ = *p++;
383 	}
384 	*bp = '\0';
385 }
386 /*
387 **  SAFEFILE -- return true if a file exists and is safe for a user.
388 **
389 **	Parameters:
390 **		fn -- filename to check.
391 **		uid -- uid to compare against.
392 **		mode -- mode bits that must match.
393 **
394 **	Returns:
395 **		TRUE if fn exists, is owned by uid, and matches mode.
396 **		FALSE otherwise.
397 **
398 **	Side Effects:
399 **		none.
400 */
401 
402 bool
403 safefile(fn, uid, mode)
404 	char *fn;
405 	int uid;
406 	int mode;
407 {
408 	struct stat stbuf;
409 
410 	if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
411 	    (stbuf.st_mode & mode) == mode)
412 		return (TRUE);
413 	return (FALSE);
414 }
415 /*
416 **  FIXCRLF -- fix <CR><LF> in line.
417 **
418 **	Looks for the <CR><LF> combination and turns it into the
419 **	UNIX canonical <NL> character.  It only takes one line,
420 **	i.e., it is assumed that the first <NL> found is the end
421 **	of the line.
422 **
423 **	Parameters:
424 **		line -- the line to fix.
425 **		stripnl -- if true, strip the newline also.
426 **
427 **	Returns:
428 **		none.
429 **
430 **	Side Effects:
431 **		line is changed in place.
432 */
433 
434 fixcrlf(line, stripnl)
435 	char *line;
436 	bool stripnl;
437 {
438 	register char *p;
439 
440 	p = index(line, '\n');
441 	if (p == NULL)
442 		return;
443 	if (p[-1] == '\r')
444 		p--;
445 	if (!stripnl)
446 		*p++ = '\n';
447 	*p = '\0';
448 }
449 /*
450 **  SYSLOG -- fake entry to fool lint
451 */
452 
453 # ifdef LOG
454 # ifdef lint
455 
456 /*VARARGS2*/
457 syslog(pri, fmt, args)
458 	int pri;
459 	char *fmt;
460 {
461 	pri = *fmt;
462 	args = pri;
463 	pri = args;
464 }
465 
466 # endif lint
467 # endif LOG
468 /*
469 **  DFOPEN -- determined file open
470 **
471 **	This routine has the semantics of fopen, except that it will
472 **	keep trying a few times to make this happen.  The idea is that
473 **	on very loaded systems, we may run out of resources (inodes,
474 **	whatever), so this tries to get around it.
475 */
476 
477 FILE *
478 dfopen(filename, mode)
479 	char *filename;
480 	char *mode;
481 {
482 	register int tries;
483 	register FILE *fp;
484 	extern int errno;
485 
486 	for (tries = 0; tries < 10; tries++)
487 	{
488 		sleep(10 * tries);
489 		errno = 0;
490 		fp = fopen(filename, mode);
491 		if (fp != NULL || errno != ENFILE)
492 			break;
493 	}
494 	return (fp);
495 }
496 /*
497 **  PUTLINE -- put a line like fputs obeying SMTP conventions
498 **
499 **	Parameters:
500 **		l -- line to put.
501 **		fp -- file to put it onto.
502 **		fullsmtp -- if set, obey strictest SMTP conventions.
503 **
504 **	Returns:
505 **		none
506 **
507 **	Side Effects:
508 **		output of l to fp.
509 */
510 
511 # define SMTPLINELIM	120	/* maximum line length */
512 
513 putline(l, fp, fullsmtp)
514 	char *l;
515 	FILE *fp;
516 	bool fullsmtp;
517 {
518 	register char *p;
519 
520 	if (!fullsmtp)
521 	{
522 		fputs(l, fp);
523 		return;
524 	}
525 
526 	/* find the end of the line */
527 	p = index(l, '\n');
528 	if (p == NULL)
529 		p = &l[strlen(l)];
530 
531 	/* check for line overflow */
532 	while (p - l > SMTPLINELIM)
533 	{
534 		register char *q = &l[SMTPLINELIM - 1];
535 		char svchar = *q;
536 
537 		*q = '\0';
538 		fputs(l, fp);
539 		fputs("!\r\n", fp);
540 		*q = svchar;
541 		l = q;
542 	}
543 
544 	/* output last part */
545 	*p = '\0';
546 	fputs(l, fp);
547 	fputs("\r\n", fp);
548 	*p = '\n';
549 }
550 /*
551 **  TICK -- take a clock tick
552 **
553 **	Someday this will have to do more complex event scheduling.
554 **
555 **	Parameters:
556 **		none.
557 **
558 **	Returns:
559 **		non-local through TickFrame.
560 **
561 **	Side Effects:
562 **		none.
563 */
564 
565 tick()
566 {
567 # ifdef DEBUG
568 	if (Debug > 0)
569 		printf("tick\n");
570 # endif DEBUG
571 	longjmp(TickFrame, 1);
572 }
573