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