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