|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)aux.c 5.20 (Berkeley) 6/25/90";
22: #endif /* not lint */
23:
24: #include "rcv.h"
25: #include <sys/stat.h>
26: #include <sys/time.h>
27:
28: /*
29: * Mail -- a mail program
30: *
31: * Auxiliary functions.
32: */
33:
34: /*
35: * Return a pointer to a dynamic copy of the argument.
36: */
37: char *
38: savestr(str)
39: char *str;
40: {
41: char *new;
42: int size = strlen(str) + 1;
43:
44: if ((new = salloc(size)) != NOSTR)
45: bcopy(str, new, size);
46: return new;
47: }
48:
49: /*
50: * Announce a fatal error and die.
51: */
52:
53: /*VARARGS1*/
54: panic(fmt, a, b)
55: char *fmt;
56: {
57: fprintf(stderr, "panic: ");
58: fprintf(stderr, fmt, a, b);
59: putc('\n', stderr);
60: fflush(stdout);
61: abort();
62: }
63:
64: /*
65: * Touch the named message by setting its MTOUCH flag.
66: * Touched messages have the effect of not being sent
67: * back to the system mailbox on exit.
68: */
69: touch(mp)
70: register struct message *mp;
71: {
72:
73: mp->m_flag |= MTOUCH;
74: if ((mp->m_flag & MREAD) == 0)
75: mp->m_flag |= MREAD|MSTATUS;
76: }
77:
78: /*
79: * Test to see if the passed file name is a directory.
80: * Return true if it is.
81: */
82: isdir(name)
83: char name[];
84: {
85: struct stat sbuf;
86:
87: if (stat(name, &sbuf) < 0)
88: return(0);
89: return((sbuf.st_mode & S_IFMT) == S_IFDIR);
90: }
91:
92: /*
93: * Count the number of arguments in the given string raw list.
94: */
95: argcount(argv)
96: char **argv;
97: {
98: register char **ap;
99:
100: for (ap = argv; *ap++ != NOSTR;)
101: ;
102: return ap - argv - 1;
103: }
104:
105: /*
106: * Return the desired header line from the passed message
107: * pointer (or NOSTR if the desired header field is not available).
108: */
109: char *
110: hfield(field, mp)
111: char field[];
112: struct message *mp;
113: {
114: register FILE *ibuf;
115: char linebuf[LINESIZE];
116: register int lc;
117: register char *hfield;
118: char *colon;
119:
120: ibuf = setinput(mp);
121: if ((lc = mp->m_lines - 1) < 0)
122: return NOSTR;
123: if (readline(ibuf, linebuf, LINESIZE) < 0)
124: return NOSTR;
125: while (lc > 0) {
126: if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
127: return NOSTR;
128: if (hfield = ishfield(linebuf, colon, field))
129: return savestr(hfield);
130: }
131: return NOSTR;
132: }
133:
134: /*
135: * Return the next header field found in the given message.
136: * Return >= 0 if something found, < 0 elsewise.
137: * "colon" is set to point to the colon in the header.
138: * Must deal with \ continuations & other such fraud.
139: */
140: gethfield(f, linebuf, rem, colon)
141: register FILE *f;
142: char linebuf[];
143: register int rem;
144: char **colon;
145: {
146: char line2[LINESIZE];
147: register char *cp, *cp2;
148: register int c;
149:
150: for (;;) {
151: if (--rem < 0)
152: return -1;
153: if ((c = readline(f, linebuf, LINESIZE)) <= 0)
154: return -1;
155: for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
156: cp++)
157: ;
158: if (*cp != ':' || cp == linebuf)
159: continue;
160: /*
161: * I guess we got a headline.
162: * Handle wraparounding
163: */
164: *colon = cp;
165: cp = linebuf + c;
166: for (;;) {
167: while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
168: ;
169: cp++;
170: if (rem <= 0)
171: break;
172: ungetc(c = getc(f), f);
173: if (c != ' ' && c != '\t')
174: break;
175: if ((c = readline(f, line2, LINESIZE)) < 0)
176: break;
177: rem--;
178: for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
179: ;
180: c -= cp2 - line2;
181: if (cp + c >= linebuf + LINESIZE - 2)
182: break;
183: *cp++ = ' ';
184: bcopy(cp2, cp, c);
185: cp += c;
186: }
187: *cp = 0;
188: return rem;
189: }
190: /* NOTREACHED */
191: }
192:
193: /*
194: * Check whether the passed line is a header line of
195: * the desired breed. Return the field body, or 0.
196: */
197:
198: char*
199: ishfield(linebuf, colon, field)
200: char linebuf[], field[];
201: char *colon;
202: {
203: register char *cp = colon;
204:
205: *cp = 0;
206: if (strcasecmp(linebuf, field) != 0) {
207: *cp = ':';
208: return 0;
209: }
210: *cp = ':';
211: for (cp++; *cp == ' ' || *cp == '\t'; cp++)
212: ;
213: return cp;
214: }
215:
216: /*
217: * Copy a string, lowercasing it as we go.
218: */
219: istrcpy(dest, src)
220: register char *dest, *src;
221: {
222:
223: do {
224: if (isupper(*src))
225: *dest++ = tolower(*src);
226: else
227: *dest++ = *src;
228: } while (*src++ != 0);
229: }
230:
231: /*
232: * The following code deals with input stacking to do source
233: * commands. All but the current file pointer are saved on
234: * the stack.
235: */
236:
237: static int ssp; /* Top of file stack */
238: struct sstack {
239: FILE *s_file; /* File we were in. */
240: int s_cond; /* Saved state of conditionals */
241: int s_loading; /* Loading .mailrc, etc. */
242: } sstack[NOFILE];
243:
244: /*
245: * Pushdown current input file and switch to a new one.
246: * Set the global flag "sourcing" so that others will realize
247: * that they are no longer reading from a tty (in all probability).
248: */
249: source(arglist)
250: char **arglist;
251: {
252: FILE *fi;
253: char *cp;
254:
255: if ((cp = expand(*arglist)) == NOSTR)
256: return(1);
257: if ((fi = Fopen(cp, "r")) == NULL) {
258: perror(cp);
259: return(1);
260: }
261: if (ssp >= NOFILE - 1) {
262: printf("Too much \"sourcing\" going on.\n");
263: Fclose(fi);
264: return(1);
265: }
266: sstack[ssp].s_file = input;
267: sstack[ssp].s_cond = cond;
268: sstack[ssp].s_loading = loading;
269: ssp++;
270: loading = 0;
271: cond = CANY;
272: input = fi;
273: sourcing++;
274: return(0);
275: }
276:
277: /*
278: * Pop the current input back to the previous level.
279: * Update the "sourcing" flag as appropriate.
280: */
281: unstack()
282: {
283: if (ssp <= 0) {
284: printf("\"Source\" stack over-pop.\n");
285: sourcing = 0;
286: return(1);
287: }
288: Fclose(input);
289: if (cond != CANY)
290: printf("Unmatched \"if\"\n");
291: ssp--;
292: cond = sstack[ssp].s_cond;
293: loading = sstack[ssp].s_loading;
294: input = sstack[ssp].s_file;
295: if (ssp == 0)
296: sourcing = loading;
297: return(0);
298: }
299:
300: /*
301: * Touch the indicated file.
302: * This is nifty for the shell.
303: */
304: alter(name)
305: char *name;
306: {
307: struct stat sb;
308: struct timeval tv[2];
309: time_t time();
310:
311: if (stat(name, &sb))
312: return;
313: tv[0].tv_sec = time((time_t *)0) + 1;
314: tv[1].tv_sec = sb.st_mtime;
315: tv[0].tv_usec = tv[1].tv_usec = 0;
316: (void)utimes(name, tv);
317: }
318:
319: /*
320: * Examine the passed line buffer and
321: * return true if it is all blanks and tabs.
322: */
323: blankline(linebuf)
324: char linebuf[];
325: {
326: register char *cp;
327:
328: for (cp = linebuf; *cp; cp++)
329: if (*cp != ' ' && *cp != '\t')
330: return(0);
331: return(1);
332: }
333:
334: /*
335: * Get sender's name from this message. If the message has
336: * a bunch of arpanet stuff in it, we may have to skin the name
337: * before returning it.
338: */
339: char *
340: nameof(mp, reptype)
341: register struct message *mp;
342: {
343: register char *cp, *cp2;
344:
345: cp = skin(name1(mp, reptype));
346: if (reptype != 0 || charcount(cp, '!') < 2)
347: return(cp);
348: cp2 = rindex(cp, '!');
349: cp2--;
350: while (cp2 > cp && *cp2 != '!')
351: cp2--;
352: if (*cp2 == '!')
353: return(cp2 + 1);
354: return(cp);
355: }
356:
357: /*
358: * Start of a "comment".
359: * Ignore it.
360: */
361: char *
362: skip_comment(cp)
363: register char *cp;
364: {
365: register nesting = 1;
366:
367: for (; nesting > 0 && *cp; cp++) {
368: switch (*cp) {
369: case '\\':
370: if (cp[1])
371: cp++;
372: break;
373: case '(':
374: nesting++;
375: break;
376: case ')':
377: nesting--;
378: break;
379: }
380: }
381: return cp;
382: }
383:
384: /*
385: * Skin an arpa net address according to the RFC 822 interpretation
386: * of "host-phrase."
387: */
388: char *
389: skin(name)
390: char *name;
391: {
392: register int c;
393: register char *cp, *cp2;
394: char *bufend;
395: int gotlt, lastsp;
396: char nbuf[BUFSIZ];
397:
398: if (name == NOSTR)
399: return(NOSTR);
400: if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
401: && index(name, ' ') == NOSTR)
402: return(name);
403: gotlt = 0;
404: lastsp = 0;
405: bufend = nbuf;
406: for (cp = name, cp2 = bufend; c = *cp++; ) {
407: switch (c) {
408: case '(':
409: cp = skip_comment(cp);
410: lastsp = 0;
411: break;
412:
413: case '"':
414: /*
415: * Start of a "quoted-string".
416: * Copy it in its entirety.
417: */
418: while (c = *cp) {
419: cp++;
420: if (c == '"')
421: break;
422: if (c != '\\')
423: *cp2++ = c;
424: else if (c = *cp) {
425: *cp2++ = c;
426: cp++;
427: }
428: }
429: lastsp = 0;
430: break;
431:
432: case ' ':
433: if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
434: cp += 3, *cp2++ = '@';
435: else
436: if (cp[0] == '@' && cp[1] == ' ')
437: cp += 2, *cp2++ = '@';
438: else
439: lastsp = 1;
440: break;
441:
442: case '<':
443: cp2 = bufend;
444: gotlt++;
445: lastsp = 0;
446: break;
447:
448: case '>':
449: if (gotlt) {
450: gotlt = 0;
451: while ((c = *cp) && c != ',') {
452: cp++;
453: if (c == '(')
454: cp = skip_comment(cp);
455: else if (c == '"')
456: while (c = *cp) {
457: cp++;
458: if (c == '"')
459: break;
460: if (c == '\\' && *cp)
461: cp++;
462: }
463: }
464: lastsp = 0;
465: break;
466: }
467: /* Fall into . . . */
468:
469: default:
470: if (lastsp) {
471: lastsp = 0;
472: *cp2++ = ' ';
473: }
474: *cp2++ = c;
475: if (c == ',' && !gotlt) {
476: *cp2++ = ' ';
477: for (; *cp == ' '; cp++)
478: ;
479: lastsp = 0;
480: bufend = cp2;
481: }
482: }
483: }
484: *cp2 = 0;
485:
486: return(savestr(nbuf));
487: }
488:
489: /*
490: * Fetch the sender's name from the passed message.
491: * Reptype can be
492: * 0 -- get sender's name for display purposes
493: * 1 -- get sender's name for reply
494: * 2 -- get sender's name for Reply
495: */
496: char *
497: name1(mp, reptype)
498: register struct message *mp;
499: {
500: char namebuf[LINESIZE];
501: char linebuf[LINESIZE];
502: register char *cp, *cp2;
503: register FILE *ibuf;
504: int first = 1;
505:
506: if ((cp = hfield("from", mp)) != NOSTR)
507: return cp;
508: if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
509: return cp;
510: ibuf = setinput(mp);
511: namebuf[0] = 0;
512: if (readline(ibuf, linebuf, LINESIZE) < 0)
513: return(savestr(namebuf));
514: newname:
515: for (cp = linebuf; *cp && *cp != ' '; cp++)
516: ;
517: for (; *cp == ' ' || *cp == '\t'; cp++)
518: ;
519: for (cp2 = &namebuf[strlen(namebuf)];
520: *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
521: *cp2++ = *cp++;
522: *cp2 = '\0';
523: if (readline(ibuf, linebuf, LINESIZE) < 0)
524: return(savestr(namebuf));
525: if ((cp = index(linebuf, 'F')) == NULL)
526: return(savestr(namebuf));
527: if (strncmp(cp, "From", 4) != 0)
528: return(savestr(namebuf));
529: while ((cp = index(cp, 'r')) != NULL) {
530: if (strncmp(cp, "remote", 6) == 0) {
531: if ((cp = index(cp, 'f')) == NULL)
532: break;
533: if (strncmp(cp, "from", 4) != 0)
534: break;
535: if ((cp = index(cp, ' ')) == NULL)
536: break;
537: cp++;
538: if (first) {
539: strcpy(namebuf, cp);
540: first = 0;
541: } else
542: strcpy(rindex(namebuf, '!')+1, cp);
543: strcat(namebuf, "!");
544: goto newname;
545: }
546: cp++;
547: }
548: return(savestr(namebuf));
549: }
550:
551: /*
552: * Count the occurances of c in str
553: */
554: charcount(str, c)
555: char *str;
556: {
557: register char *cp;
558: register int i;
559:
560: for (i = 0, cp = str; *cp; cp++)
561: if (*cp == c)
562: i++;
563: return(i);
564: }
565:
566: /*
567: * Are any of the characters in the two strings the same?
568: */
569: anyof(s1, s2)
570: register char *s1, *s2;
571: {
572:
573: while (*s1)
574: if (index(s2, *s1++))
575: return 1;
576: return 0;
577: }
578:
579: /*
580: * Convert c to upper case
581: */
582: raise(c)
583: register c;
584: {
585:
586: if (islower(c))
587: return toupper(c);
588: return c;
589: }
590:
591: /*
592: * Copy s1 to s2, return pointer to null in s2.
593: */
594: char *
595: copy(s1, s2)
596: register char *s1, *s2;
597: {
598:
599: while (*s2++ = *s1++)
600: ;
601: return s2 - 1;
602: }
603:
604: /*
605: * See if the given header field is supposed to be ignored.
606: */
607: isign(field, ignore)
608: char *field;
609: struct ignoretab ignore[2];
610: {
611: char realfld[BUFSIZ];
612:
613: if (ignore == ignoreall)
614: return 1;
615: /*
616: * Lower-case the string, so that "Status" and "status"
617: * will hash to the same place.
618: */
619: istrcpy(realfld, field);
620: if (ignore[1].i_count > 0)
621: return (!member(realfld, ignore + 1));
622: else
623: return (member(realfld, ignore));
624: }
625:
626: member(realfield, table)
627: register char *realfield;
628: struct ignoretab *table;
629: {
630: register struct ignore *igp;
631:
632: for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
633: if (*igp->i_field == *realfield &&
634: equal(igp->i_field, realfield))
635: return (1);
636: return (0);
637: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.