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