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