|
|
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: #ifdef defined(USGFROM)
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: */
214: if (ishfield(linebuf, field) && strncmp(linebuf, "FROM:", 5))
215: #else !defined(USGFROM)
216: if (ishfield(linebuf, field))
217: #endif defined(USGFROM)
218: return(savestr(hcontents(linebuf)));
219: } while (lc > 0);
220: return(NOSTR);
221: }
222:
223: /*
224: * Return the next header field found in the given message.
225: * Return > 0 if something found, <= 0 elsewise.
226: * Must deal with \ continuations & other such fraud.
227: */
228:
229: gethfield(f, linebuf, rem)
230: register FILE *f;
231: char linebuf[];
232: register int rem;
233: {
234: char line2[LINESIZE];
235: long loc;
236: register char *cp, *cp2;
237: register int c;
238:
239:
240: for (;;) {
241: if (rem <= 0)
242: return(-1);
243: if (readline(f, linebuf) < 0)
244: return(-1);
245: rem--;
246: if (strlen(linebuf) == 0)
247: return(-1);
248: if (isspace(linebuf[0]))
249: continue;
250: if (linebuf[0] == '>')
251: continue;
252: cp = index(linebuf, ':');
253: if (cp == NOSTR)
254: continue;
255: for (cp2 = linebuf; cp2 < cp; cp2++)
256: if (isdigit(*cp2))
257: continue;
258:
259: /*
260: * I guess we got a headline.
261: * Handle wraparounding
262: */
263:
264: for (;;) {
265: if (rem <= 0)
266: break;
267: #ifdef CANTELL
268: loc = ftell(f);
269: if (readline(f, line2) < 0)
270: break;
271: rem--;
272: if (!isspace(line2[0])) {
273: fseek(f, loc, 0);
274: rem++;
275: break;
276: }
277: #else
278: c = getc(f);
279: ungetc(c, f);
280: if (!isspace(c) || c == '\n')
281: break;
282: if (readline(f, line2) < 0)
283: break;
284: rem--;
285: #endif
286: cp2 = line2;
287: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
288: ;
289: if (strlen(linebuf) + strlen(cp2) >= LINESIZE-2)
290: break;
291: cp = &linebuf[strlen(linebuf)];
292: while (cp > linebuf &&
293: (isspace(cp[-1]) || cp[-1] == '\\'))
294: cp--;
295: *cp++ = ' ';
296: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
297: ;
298: strcpy(cp, cp2);
299: }
300: if ((c = strlen(linebuf)) > 0) {
301: cp = &linebuf[c-1];
302: while (cp > linebuf && isspace(*cp))
303: cp--;
304: *++cp = 0;
305: }
306: return(rem);
307: }
308: /* NOTREACHED */
309: }
310:
311: /*
312: * Check whether the passed line is a header line of
313: * the desired breed.
314: */
315:
316: ishfield(linebuf, field)
317: char linebuf[], field[];
318: {
319: register char *cp;
320: register int c;
321:
322: if ((cp = index(linebuf, ':')) == NOSTR)
323: return(0);
324: if (cp == linebuf)
325: return(0);
326: cp--;
327: while (cp > linebuf && isspace(*cp))
328: cp--;
329: c = *++cp;
330: *cp = 0;
331: if (icequal(linebuf ,field)) {
332: *cp = c;
333: return(1);
334: }
335: *cp = c;
336: return(0);
337: }
338:
339: /*
340: * Extract the non label information from the given header field
341: * and return it.
342: */
343:
344: char *
345: hcontents(hfield)
346: char hfield[];
347: {
348: register char *cp;
349:
350: if ((cp = index(hfield, ':')) == NOSTR)
351: return(NOSTR);
352: cp++;
353: while (*cp && isspace(*cp))
354: cp++;
355: return(cp);
356: }
357:
358: /*
359: * Compare two strings, ignoring case.
360: */
361:
362: icequal(s1, s2)
363: register char *s1, *s2;
364: {
365:
366: while (raise(*s1++) == raise(*s2))
367: if (*s2++ == 0)
368: return(1);
369: return(0);
370: }
371:
372: /*
373: * Copy a string, lowercasing it as we go.
374: */
375: istrcpy(dest, src)
376: char *dest, *src;
377: {
378: register char *cp, *cp2;
379:
380: cp2 = dest;
381: cp = src;
382: do {
383: *cp2++ = little(*cp);
384: } while (*cp++ != 0);
385: }
386:
387: /*
388: * The following code deals with input stacking to do source
389: * commands. All but the current file pointer are saved on
390: * the stack.
391: */
392:
393: static int ssp = -1; /* Top of file stack */
394: struct sstack {
395: FILE *s_file; /* File we were in. */
396: int s_cond; /* Saved state of conditionals */
397: int s_loading; /* Loading .mailrc, etc. */
398: } sstack[_NFILE];
399:
400: /*
401: * Pushdown current input file and switch to a new one.
402: * Set the global flag "sourcing" so that others will realize
403: * that they are no longer reading from a tty (in all probability).
404: */
405:
406: source(name)
407: char name[];
408: {
409: register FILE *fi;
410: register char *cp;
411:
412: if ((cp = expand(name)) == NOSTR)
413: return(1);
414: if ((fi = fopen(cp, "r")) == NULL) {
415: perror(cp);
416: return(1);
417: }
418: if (ssp >= _NFILE-2) {
419: printf("Too much \"sourcing\" going on.\n");
420: fclose(fi);
421: return(1);
422: }
423: sstack[++ssp].s_file = input;
424: sstack[ssp].s_cond = cond;
425: sstack[ssp].s_loading = loading;
426: loading = 0;
427: cond = CANY;
428: input = fi;
429: sourcing++;
430: return(0);
431: }
432:
433: /*
434: * Source a file, but do nothing if the file cannot be opened.
435: */
436:
437: source1(name)
438: char name[];
439: {
440: register int f;
441:
442: if ((f = open(name, 0)) < 0)
443: return(0);
444: close(f);
445: source(name);
446: }
447:
448: /*
449: * Pop the current input back to the previous level.
450: * Update the "sourcing" flag as appropriate.
451: */
452:
453: unstack()
454: {
455: if (ssp < 0) {
456: printf("\"Source\" stack over-pop.\n");
457: sourcing = 0;
458: return(1);
459: }
460: fclose(input);
461: if (cond != CANY)
462: printf("Unmatched \"if\"\n");
463: cond = sstack[ssp].s_cond;
464: loading = sstack[ssp].s_loading;
465: input = sstack[ssp--].s_file;
466: if (ssp < 0)
467: sourcing = loading;
468: return(0);
469: }
470:
471: /*
472: * Touch the indicated file.
473: * This is nifty for the shell.
474: * If we have the utime() system call, this is better served
475: * by using that, since it will work for empty files.
476: * On non-utime systems, we must sleep a second, then read.
477: */
478:
479: alter(name)
480: char name[];
481: {
482: #ifdef UTIME
483: struct stat statb;
484: long time();
485: time_t time_p[2];
486: #else
487: register int pid, f;
488: char w;
489: #endif UTIME
490:
491: #ifdef UTIME
492: if (stat(name, &statb) < 0)
493: return;
494: time_p[0] = time((long *) 0) + 1;
495: time_p[1] = statb.st_mtime;
496: utime(name, time_p);
497: #else
498: sleep(1);
499: if ((f = open(name, 0)) < 0)
500: return;
501: read(f, &w, 1);
502: exit(0);
503: #endif
504: }
505:
506: /*
507: * Examine the passed line buffer and
508: * return true if it is all blanks and tabs.
509: */
510:
511: blankline(linebuf)
512: char linebuf[];
513: {
514: register char *cp;
515:
516: for (cp = linebuf; *cp; cp++)
517: if (!any(*cp, " \t"))
518: return(0);
519: return(1);
520: }
521:
522: /*
523: * Get sender's name from this message. If the message has
524: * a bunch of arpanet stuff in it, we may have to skin the name
525: * before returning it.
526: */
527: char *
528: nameof(mp, reptype)
529: register struct message *mp;
530: {
531: register char *cp, *cp2;
532:
533: cp = skin(name1(mp, reptype));
534: if (reptype != 0 || charcount(cp, '!') < 2)
535: return(cp);
536: cp2 = rindex(cp, '!');
537: cp2--;
538: while (cp2 > cp && *cp2 != '!')
539: cp2--;
540: if (*cp2 == '!')
541: return(cp2 + 1);
542: return(cp);
543: }
544:
545: /*
546: * Skin an arpa net address according to the RFC 733 interpretation
547: * of "host-phrase."
548: */
549: char *
550: skin(name)
551: char *name;
552: {
553: register int c;
554: register char *cp, *cp2;
555: int gotlt, lastsp;
556: char nbuf[BUFSIZ];
557:
558: if (name == NOSTR)
559: return(NOSTR);
560: if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
561: && index(name, ' ') == NOSTR)
562: return(name);
563: gotlt = 0;
564: lastsp = 0;
565: for (cp = name, cp2 = nbuf; c = *cp++; ) {
566: switch (c) {
567: case '(':
568: while (*cp != ')' && *cp != 0)
569: cp++;
570: if (*cp)
571: cp++;
572: lastsp = 0;
573: break;
574:
575: case ' ':
576: if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
577: cp += 3, *cp2++ = '@';
578: else
579: if (cp[0] == '@' && cp[1] == ' ')
580: cp += 2, *cp2++ = '@';
581: else
582: lastsp = 1;
583: break;
584:
585: case '<':
586: cp2 = nbuf;
587: gotlt++;
588: lastsp = 0;
589: break;
590:
591: case '>':
592: if (gotlt)
593: goto done;
594:
595: /* Fall into . . . */
596:
597: default:
598: if (lastsp) {
599: lastsp = 0;
600: *cp2++ = ' ';
601: }
602: *cp2++ = c;
603: break;
604: }
605: }
606: done:
607: *cp2 = 0;
608:
609: return(savestr(nbuf));
610: }
611:
612: /*
613: * Fetch the sender's name from the passed message.
614: * Reptype can be
615: * 0 -- get sender's name for display purposes
616: * 1 -- get sender's name for reply
617: * 2 -- get sender's name for Reply
618: * 3 -- get sender's name for back-to-you-bud
619: */
620:
621: char *
622: name1(mp, reptype)
623: register struct message *mp;
624: {
625: char namebuf[LINESIZE];
626: char linebuf[LINESIZE];
627: register char *cp, *cp2;
628: register FILE *ibuf;
629: int first = 1;
630:
631: if (reptype != 3)
632: {
633: if ((cp = hfield("from", mp)) != NOSTR)
634: return(cp);
635: }
636: if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
637: return(cp);
638: ibuf = setinput(mp);
639: copy("", namebuf);
640: if (readline(ibuf, linebuf) <= 0)
641: return(savestr(namebuf));
642: newname:
643: for (cp = linebuf; *cp != ' '; cp++)
644: ;
645: while (any(*cp, " \t"))
646: cp++;
647: for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") &&
648: cp2-namebuf < LINESIZE-1; *cp2++ = *cp++)
649: ;
650: *cp2 = '\0';
651: if (readline(ibuf, linebuf) <= 0)
652: return(savestr(namebuf));
653: if ((cp = index(linebuf, 'F')) == NULL)
654: return(savestr(namebuf));
655: if (strncmp(cp, "From", 4) != 0)
656: return(savestr(namebuf));
657: while ((cp = index(cp, 'r')) != NULL) {
658: if (strncmp(cp, "remote", 6) == 0) {
659: if ((cp = index(cp, 'f')) == NULL)
660: break;
661: if (strncmp(cp, "from", 4) != 0)
662: break;
663: if ((cp = index(cp, ' ')) == NULL)
664: break;
665: cp++;
666: if (first) {
667: copy(cp, namebuf);
668: first = 0;
669: } else
670: strcpy(rindex(namebuf, '!')+1, cp);
671: strcat(namebuf, "!");
672: goto newname;
673: }
674: cp++;
675: }
676: return(savestr(namebuf));
677: }
678:
679: /*
680: * Count the occurances of c in str
681: */
682: charcount(str, c)
683: char *str;
684: {
685: register char *cp;
686: register int i;
687:
688: for (i = 0, cp = str; *cp; cp++)
689: if (*cp == c)
690: i++;
691: return(i);
692: }
693:
694: /*
695: * Find the rightmost pointer to an instance of the
696: * character in the string and return it.
697: */
698: char *
699: rindex(str, c)
700: char str[];
701: register int c;
702: {
703: register char *cp, *cp2;
704:
705: for (cp = str, cp2 = NOSTR; *cp; cp++)
706: if (c == *cp)
707: cp2 = cp;
708: return(cp2);
709: }
710:
711: /*
712: * See if the string is a number.
713: */
714:
715: numeric(str)
716: char str[];
717: {
718: register char *cp = str;
719:
720: while (*cp)
721: if (!isdigit(*cp++))
722: return(0);
723: return(1);
724: }
725:
726: /*
727: * Are any of the characters in the two strings the same?
728: */
729:
730: anyof(s1, s2)
731: register char *s1, *s2;
732: {
733: register int c;
734:
735: while (c = *s1++)
736: if (any(c, s2))
737: return(1);
738: return(0);
739: }
740:
741: /*
742: * Determine the leftmost index of the character
743: * in the string.
744: */
745:
746: char *
747: index(str, ch)
748: char *str;
749: {
750: register char *cp;
751: register int c;
752:
753: for (c = ch, cp = str; *cp; cp++)
754: if (*cp == c)
755: return(cp);
756: return(NOSTR);
757: }
758:
759: /*
760: * String compare two strings of bounded length.
761: */
762:
763: strncmp(as1, as2, an)
764: char *as1, *as2;
765: {
766: register char *s1, *s2;
767: register int n;
768:
769: s1 = as1;
770: s2 = as2;
771: n = an;
772: while (--n >= 0 && *s1 == *s2++)
773: if (*s1++ == '\0')
774: return(0);
775: return(n<0 ? 0 : *s1 - *--s2);
776: }
777:
778: /*
779: * See if the given header field is supposed to be ignored.
780: */
781: isign(field)
782: char *field;
783: {
784: char realfld[BUFSIZ];
785: register int h;
786: register struct ignore *igp;
787:
788: istrcpy(realfld, field);
789: h = hash(realfld);
790: for (igp = ignore[h]; igp != 0; igp = igp->i_link)
791: if (strcmp(igp->i_field, realfld) == 0)
792: return(1);
793: return(0);
794: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.