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