BSD 4_3_Net_1 release
[unix-history] / sendmail / src / util.c
CommitLineData
b2a81223 1/*
bee79b64
KB
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of California at Berkeley. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
11 *
12 * Sendmail
13 * Copyright (c) 1983 Eric P. Allman
14 * Berkeley, California
15 */
b2a81223
DF
16
17#ifndef lint
e3419641 18static char sccsid[] = "@(#)util.c 5.14 (Berkeley) 12/5/88";
bee79b64 19#endif /* not lint */
b2a81223 20
d6a28dd8 21# include <stdio.h>
f6a0cc15
EA
22# include <sys/types.h>
23# include <sys/stat.h>
b3cbe40f 24# include <sysexits.h>
5c373723 25# include <errno.h>
5c373723 26# include "sendmail.h"
b3cbe40f
EA
27
28/*
b3cbe40f
EA
29** STRIPQUOTES -- Strip quotes & quote bits from a string.
30**
31** Runs through a string and strips off unquoted quote
32** characters and quote bits. This is done in place.
33**
34** Parameters:
35** s -- the string to strip.
cdb17311
EA
36** qf -- if set, remove actual `` " '' characters
37** as well as the quote bits.
b3cbe40f
EA
38**
39** Returns:
40** none.
41**
42** Side Effects:
43** none.
44**
b3cbe40f
EA
45** Called By:
46** deliver
b3cbe40f
EA
47*/
48
cdb17311 49stripquotes(s, qf)
b3cbe40f 50 char *s;
cdb17311 51 bool qf;
b3cbe40f
EA
52{
53 register char *p;
54 register char *q;
55 register char c;
56
cdb17311
EA
57 if (s == NULL)
58 return;
59
b3cbe40f
EA
60 for (p = q = s; (c = *p++) != '\0'; )
61 {
cdb17311 62 if (c != '"' || !qf)
b3cbe40f
EA
63 *q++ = c & 0177;
64 }
65 *q = '\0';
66}
67\f/*
1744384a
EA
68** QSTRLEN -- give me the string length assuming 0200 bits add a char
69**
70** Parameters:
71** s -- the string to measure.
72**
73** Reurns:
74** The length of s, including space for backslash escapes.
75**
76** Side Effects:
77** none.
78*/
79
80qstrlen(s)
81 register char *s;
82{
83 register int l = 0;
84 register char c;
85
86 while ((c = *s++) != '\0')
87 {
88 if (bitset(0200, c))
89 l++;
90 l++;
91 }
92 return (l);
93}
94\f/*
1a12c7d6
EA
95** CAPITALIZE -- return a copy of a string, properly capitalized.
96**
97** Parameters:
98** s -- the string to capitalize.
99**
100** Returns:
101** a pointer to a properly capitalized string.
102**
103** Side Effects:
104** none.
105*/
106
107char *
108capitalize(s)
109 register char *s;
110{
111 static char buf[50];
112 register char *p;
113
114 p = buf;
115
116 for (;;)
117 {
118 while (!isalpha(*s) && *s != '\0')
119 *p++ = *s++;
120 if (*s == '\0')
121 break;
122 *p++ = toupper(*s++);
123 while (isalpha(*s))
124 *p++ = *s++;
125 }
126
127 *p = '\0';
128 return (buf);
129}
130\f/*
b3cbe40f
EA
131** XALLOC -- Allocate memory and bitch wildly on failure.
132**
133** THIS IS A CLUDGE. This should be made to give a proper
134** error -- but after all, what can we do?
135**
136** Parameters:
137** sz -- size of area to allocate.
138**
139** Returns:
140** pointer to data region.
141**
142** Side Effects:
143** Memory is allocated.
b3cbe40f
EA
144*/
145
146char *
147xalloc(sz)
f9566d23 148 register int sz;
b3cbe40f
EA
149{
150 register char *p;
17a67c62 151 extern char *malloc();
b3cbe40f 152
17a67c62 153 p = malloc((unsigned) sz);
b3cbe40f
EA
154 if (p == NULL)
155 {
156 syserr("Out of memory!!");
1dbda134
EA
157 abort();
158 /* exit(EX_UNAVAILABLE); */
b3cbe40f
EA
159 }
160 return (p);
161}
162\f/*
d6a28dd8
EA
163** COPYPLIST -- copy list of pointers.
164**
165** This routine is the equivalent of newstr for lists of
166** pointers.
167**
168** Parameters:
169** list -- list of pointers to copy.
170** Must be NULL terminated.
171** copycont -- if TRUE, copy the contents of the vector
172** (which must be a string) also.
173**
174** Returns:
175** a copy of 'list'.
176**
177** Side Effects:
178** none.
179*/
180
181char **
182copyplist(list, copycont)
183 char **list;
184 bool copycont;
185{
186 register char **vp;
187 register char **newvp;
d6a28dd8
EA
188
189 for (vp = list; *vp != NULL; vp++)
190 continue;
191
192 vp++;
193
34fe0a9b
EA
194 newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
195 bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
d6a28dd8
EA
196
197 if (copycont)
198 {
199 for (vp = newvp; *vp != NULL; vp++)
200 *vp = newstr(*vp);
201 }
202
203 return (newvp);
204}
205\f/*
206** PRINTAV -- print argument vector.
207**
208** Parameters:
209** av -- argument vector.
210**
211** Returns:
212** none.
213**
214** Side Effects:
215** prints av.
216*/
217
d6a28dd8
EA
218printav(av)
219 register char **av;
220{
221 while (*av != NULL)
222 {
aa4ef64d
EA
223 if (tTd(0, 44))
224 printf("\n\t%08x=", *av);
225 else
03388044 226 (void) putchar(' ');
d6a28dd8 227 xputs(*av++);
d6a28dd8 228 }
03388044 229 (void) putchar('\n');
d6a28dd8 230}
d6a28dd8
EA
231\f/*
232** LOWER -- turn letter into lower case.
233**
234** Parameters:
235** c -- character to turn into lower case.
236**
237** Returns:
238** c, in lower case.
239**
240** Side Effects:
241** none.
242*/
243
244char
245lower(c)
246 register char c;
247{
0c5ea243 248 return(isascii(c) && isupper(c) ? tolower(c) : c);
d6a28dd8
EA
249}
250\f/*
251** XPUTS -- put string doing control escapes.
252**
253** Parameters:
254** s -- string to put.
255**
256** Returns:
257** none.
258**
259** Side Effects:
260** output to stdout
261*/
262
d6a28dd8
EA
263xputs(s)
264 register char *s;
265{
266 register char c;
267
04d7cb3d
EA
268 if (s == NULL)
269 {
270 printf("<null>");
271 return;
272 }
03388044 273 (void) putchar('"');
d6a28dd8
EA
274 while ((c = *s++) != '\0')
275 {
276 if (!isascii(c))
277 {
03388044 278 (void) putchar('\\');
d6a28dd8
EA
279 c &= 0177;
280 }
e9b10d8d 281 if (c < 040 || c >= 0177)
d6a28dd8 282 {
03388044 283 (void) putchar('^');
e9b10d8d 284 c ^= 0100;
d6a28dd8 285 }
03388044 286 (void) putchar(c);
d6a28dd8 287 }
03388044 288 (void) putchar('"');
29871fef 289 (void) fflush(stdout);
d6a28dd8 290}
d6a28dd8
EA
291\f/*
292** MAKELOWER -- Translate a line into lower case
293**
294** Parameters:
295** p -- the string to translate. If NULL, return is
296** immediate.
297**
298** Returns:
299** none.
300**
301** Side Effects:
302** String pointed to by p is translated to lower case.
303**
304** Called By:
305** parse
306*/
307
308makelower(p)
309 register char *p;
310{
311 register char c;
312
313 if (p == NULL)
314 return;
315 for (; (c = *p) != '\0'; p++)
316 if (isascii(c) && isupper(c))
0c5ea243 317 *p = tolower(c);
15fc0ec5 318}
29871fef 319\f/*
e804469b
C
320** BUILDFNAME -- build full name from gecos style entry.
321**
322** This routine interprets the strange entry that would appear
323** in the GECOS field of the password file.
2b5e3c25
EA
324**
325** Parameters:
e804469b
C
326** p -- name to build.
327** login -- the login name of this user (for &).
328** buf -- place to put the result.
2b5e3c25
EA
329**
330** Returns:
331** none.
332**
333** Side Effects:
334** none.
335*/
336
e804469b
C
337buildfname(p, login, buf)
338 register char *p;
339 char *login;
2b5e3c25
EA
340 char *buf;
341{
342 register char *bp = buf;
343
b14547d5
EA
344 if (*p == '*')
345 p++;
48ae2358 346 while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
2b5e3c25
EA
347 {
348 if (*p == '&')
349 {
e804469b 350 (void) strcpy(bp, login);
2b5e3c25
EA
351 *bp = toupper(*bp);
352 while (*bp != '\0')
353 bp++;
354 p++;
355 }
356 else
357 *bp++ = *p++;
358 }
359 *bp = '\0';
360}
361\f/*
f6a0cc15
EA
362** SAFEFILE -- return true if a file exists and is safe for a user.
363**
364** Parameters:
365** fn -- filename to check.
366** uid -- uid to compare against.
367** mode -- mode bits that must match.
368**
369** Returns:
370** TRUE if fn exists, is owned by uid, and matches mode.
371** FALSE otherwise.
372**
373** Side Effects:
374** none.
375*/
376
377bool
378safefile(fn, uid, mode)
379 char *fn;
380 int uid;
381 int mode;
382{
383 struct stat stbuf;
384
385 if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
386 (stbuf.st_mode & mode) == mode)
387 return (TRUE);
70faa7c8 388 errno = 0;
f6a0cc15
EA
389 return (FALSE);
390}
391\f/*
2768afe3
EA
392** FIXCRLF -- fix <CR><LF> in line.
393**
394** Looks for the <CR><LF> combination and turns it into the
395** UNIX canonical <NL> character. It only takes one line,
396** i.e., it is assumed that the first <NL> found is the end
397** of the line.
398**
399** Parameters:
400** line -- the line to fix.
401** stripnl -- if true, strip the newline also.
402**
403** Returns:
404** none.
405**
406** Side Effects:
407** line is changed in place.
408*/
409
410fixcrlf(line, stripnl)
411 char *line;
412 bool stripnl;
413{
414 register char *p;
415
416 p = index(line, '\n');
417 if (p == NULL)
418 return;
f90b4150 419 if (p > line && p[-1] == '\r')
2768afe3
EA
420 p--;
421 if (!stripnl)
422 *p++ = '\n';
423 *p = '\0';
424}
425\f/*
5c373723
EA
426** DFOPEN -- determined file open
427**
428** This routine has the semantics of fopen, except that it will
429** keep trying a few times to make this happen. The idea is that
430** on very loaded systems, we may run out of resources (inodes,
431** whatever), so this tries to get around it.
432*/
433
434FILE *
435dfopen(filename, mode)
436 char *filename;
437 char *mode;
438{
439 register int tries;
440 register FILE *fp;
5c373723
EA
441
442 for (tries = 0; tries < 10; tries++)
443 {
901911f8 444 sleep((unsigned) (10 * tries));
5c373723
EA
445 errno = 0;
446 fp = fopen(filename, mode);
7338e3d4
EA
447 if (fp != NULL)
448 break;
449 if (errno != ENFILE && errno != EINTR)
5c373723
EA
450 break;
451 }
70faa7c8 452 errno = 0;
5c373723
EA
453 return (fp);
454}
b85ad418
EA
455\f/*
456** PUTLINE -- put a line like fputs obeying SMTP conventions
457**
d08bed81
EA
458** This routine always guarantees outputing a newline (or CRLF,
459** as appropriate) at the end of the string.
460**
b85ad418
EA
461** Parameters:
462** l -- line to put.
463** fp -- file to put it onto.
4db45bf1 464** m -- the mailer used to control output.
b85ad418
EA
465**
466** Returns:
467** none
468**
469** Side Effects:
470** output of l to fp.
471*/
472
d08bed81 473# define SMTPLINELIM 990 /* maximum line length */
b85ad418 474
4db45bf1 475putline(l, fp, m)
d08bed81 476 register char *l;
b85ad418 477 FILE *fp;
4db45bf1 478 MAILER *m;
b85ad418
EA
479{
480 register char *p;
d08bed81 481 char svchar;
b85ad418 482
f3e66638
EA
483 /* strip out 0200 bits -- these can look like TELNET protocol */
484 if (bitnset(M_LIMITS, m->m_flags))
485 {
486 p = l;
487 while ((*p++ &= ~0200) != 0)
488 continue;
489 }
490
d08bed81 491 do
b85ad418 492 {
d08bed81
EA
493 /* find the end of the line */
494 p = index(l, '\n');
495 if (p == NULL)
496 p = &l[strlen(l)];
b85ad418 497
d08bed81 498 /* check for line overflow */
f3e66638 499 while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags))
d08bed81
EA
500 {
501 register char *q = &l[SMTPLINELIM - 1];
502
503 svchar = *q;
504 *q = '\0';
1dbda134 505 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
03388044 506 (void) putc('.', fp);
d08bed81 507 fputs(l, fp);
03388044 508 (void) putc('!', fp);
e9b10d8d 509 fputs(m->m_eol, fp);
d08bed81
EA
510 *q = svchar;
511 l = q;
512 }
b85ad418 513
d08bed81
EA
514 /* output last part */
515 svchar = *p;
516 *p = '\0';
1dbda134 517 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
03388044 518 (void) putc('.', fp);
b85ad418 519 fputs(l, fp);
e9b10d8d 520 fputs(m->m_eol, fp);
d08bed81
EA
521 *p = svchar;
522 l = p;
523 if (*l == '\n')
524 l++;
525 } while (l[0] != '\0');
b85ad418 526}
9678c96d
EA
527\f/*
528** XUNLINK -- unlink a file, doing logging as appropriate.
529**
530** Parameters:
531** f -- name of file to unlink.
532**
533** Returns:
534** none.
535**
536** Side Effects:
537** f is unlinked.
538*/
539
540xunlink(f)
541 char *f;
542{
543 register int i;
544
545# ifdef LOG
546 if (LogLevel > 20)
2cce0c26 547 syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
9678c96d
EA
548# endif LOG
549
550 i = unlink(f);
551# ifdef LOG
552 if (i < 0 && LogLevel > 21)
6d06102a 553 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
9678c96d
EA
554# endif LOG
555}
2439b900 556\f/*
e4581b86 557** SFGETS -- "safe" fgets -- times out and ignores random interrupts.
2439b900
EA
558**
559** Parameters:
560** buf -- place to put the input line.
561** siz -- size of buf.
562** fp -- file to read from.
563**
564** Returns:
e009f4f4
EA
565** NULL on error (including timeout). This will also leave
566** buf containing a null string.
2439b900
EA
567** buf otherwise.
568**
569** Side Effects:
570** none.
571*/
572
e4581b86 573static jmp_buf CtxReadTimeout;
2439b900
EA
574
575char *
576sfgets(buf, siz, fp)
577 char *buf;
578 int siz;
579 FILE *fp;
580{
6d06102a 581 register EVENT *ev = NULL;
2439b900
EA
582 register char *p;
583 extern readtimeout();
584
e4581b86 585 /* set the timeout */
6d06102a 586 if (ReadTimeout != 0)
e4581b86
EA
587 {
588 if (setjmp(CtxReadTimeout) != 0)
589 {
2e15a2d8 590# ifdef LOG
ab4889ea
MK
591 syslog(LOG_NOTICE,
592 "timeout waiting for input from %s\n",
593 RealHostName);
2e15a2d8 594# endif
ab4889ea
MK
595 errno = 0;
596 usrerr("timeout waiting for input");
77872b93 597 buf[0] = '\0';
e4581b86
EA
598 return (NULL);
599 }
ce7cfd4c 600 ev = setevent((time_t) ReadTimeout, readtimeout, 0);
e4581b86
EA
601 }
602
603 /* try to read */
e009f4f4
EA
604 p = NULL;
605 while (p == NULL && !feof(fp) && !ferror(fp))
6d06102a
EA
606 {
607 errno = 0;
608 p = fgets(buf, siz, fp);
e009f4f4
EA
609 if (errno == EINTR)
610 clearerr(fp);
611 }
e4581b86
EA
612
613 /* clear the event if it has not sprung */
2439b900 614 clrevent(ev);
e4581b86
EA
615
616 /* clean up the books and exit */
04d7cb3d 617 LineNumber++;
e009f4f4 618 if (p == NULL)
4ed73359 619 {
e009f4f4 620 buf[0] = '\0';
4ed73359
EA
621 return (NULL);
622 }
623 for (p = buf; *p != '\0'; p++)
624 *p &= ~0200;
625 return (buf);
2439b900
EA
626}
627
628static
629readtimeout()
630{
e4581b86 631 longjmp(CtxReadTimeout, 1);
2439b900 632}
6a86d693
EA
633\f/*
634** FGETFOLDED -- like fgets, but know about folded lines.
635**
636** Parameters:
637** buf -- place to put result.
638** n -- bytes available.
639** f -- file to read from.
640**
641** Returns:
642** buf on success, NULL on error or EOF.
643**
644** Side Effects:
645** buf gets lines from f, with continuation lines (lines
646** with leading white space) appended. CRLF's are mapped
647** into single newlines. Any trailing NL is stripped.
648*/
649
650char *
651fgetfolded(buf, n, f)
652 char *buf;
653 register int n;
654 FILE *f;
655{
656 register char *p = buf;
657 register int i;
658
659 n--;
2975cf68 660 while ((i = getc(f)) != EOF)
6a86d693 661 {
2975cf68
EA
662 if (i == '\r')
663 {
664 i = getc(f);
665 if (i != '\n')
666 {
667 if (i != EOF)
03388044 668 (void) ungetc(i, f);
2975cf68
EA
669 i = '\r';
670 }
671 }
672 if (--n > 0)
673 *p++ = i;
674 if (i == '\n')
675 {
676 LineNumber++;
677 i = getc(f);
678 if (i != EOF)
03388044 679 (void) ungetc(i, f);
2975cf68
EA
680 if (i != ' ' && i != '\t')
681 {
682 *--p = '\0';
683 return (buf);
684 }
685 }
6a86d693
EA
686 }
687 return (NULL);
688}
96476cab 689\f/*
88039044
EA
690** CURTIME -- return current time.
691**
692** Parameters:
693** none.
694**
695** Returns:
696** the current time.
697**
698** Side Effects:
699** none.
700*/
701
702time_t
703curtime()
704{
705 auto time_t t;
706
707 (void) time(&t);
708 return (t);
709}
fbd53483
EA
710\f/*
711** ATOBOOL -- convert a string representation to boolean.
712**
713** Defaults to "TRUE"
714**
715** Parameters:
716** s -- string to convert. Takes "tTyY" as true,
717** others as false.
718**
719** Returns:
720** A boolean representation of the string.
721**
722** Side Effects:
723** none.
724*/
725
726bool
727atobool(s)
728 register char *s;
729{
730 if (*s == '\0' || index("tTyY", *s) != NULL)
731 return (TRUE);
732 return (FALSE);
733}
6db97a2f
EA
734\f/*
735** ATOOCT -- convert a string representation to octal.
736**
737** Parameters:
738** s -- string to convert.
739**
740** Returns:
741** An integer representing the string interpreted as an
742** octal number.
743**
744** Side Effects:
745** none.
746*/
747
748atooct(s)
749 register char *s;
750{
751 register int i = 0;
752
753 while (*s >= '0' && *s <= '7')
754 i = (i << 3) | (*s++ - '0');
755 return (i);
756}
7338e3d4
EA
757\f/*
758** WAITFOR -- wait for a particular process id.
759**
760** Parameters:
761** pid -- process id to wait for.
762**
763** Returns:
764** status of pid.
765** -1 if pid never shows up.
766**
767** Side Effects:
768** none.
769*/
770
771waitfor(pid)
772 int pid;
773{
774 auto int st;
775 int i;
776
777 do
778 {
779 errno = 0;
780 i = wait(&st);
781 } while ((i >= 0 || errno == EINTR) && i != pid);
782 if (i < 0)
783 st = -1;
784 return (st);
785}
786\f/*
1dbda134
EA
787** BITINTERSECT -- tell if two bitmaps intersect
788**
789** Parameters:
790** a, b -- the bitmaps in question
791**
792** Returns:
793** TRUE if they have a non-null intersection
794** FALSE otherwise
795**
796** Side Effects:
797** none.
798*/
799
800bool
801bitintersect(a, b)
802 BITMAP a;
803 BITMAP b;
804{
805 int i;
806
807 for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
808 if ((a[i] & b[i]) != 0)
809 return (TRUE);
810 return (FALSE);
811}
812\f/*
813** BITZEROP -- tell if a bitmap is all zero
814**
815** Parameters:
816** map -- the bit map to check
817**
818** Returns:
819** TRUE if map is all zero.
820** FALSE if there are any bits set in map.
821**
822** Side Effects:
823** none.
824*/
825
826bool
827bitzerop(map)
828 BITMAP map;
829{
830 int i;
831
832 for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
833 if (map[i] != 0)
834 return (FALSE);
835 return (TRUE);
836}