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