|
|
1.1 root 1: #
2:
3: #include "rcv.h"
4: #include <sys/stat.h>
5: #include <sgtty.h>
6: #include <ctype.h>
7:
8: /*
9: * Mail -- a mail program
10: *
11: * Auxiliary functions.
12: */
13:
14: /*
15: * Return a pointer to a dynamic copy of the argument.
16: */
17:
18: char *
19: savestr(str)
20: char *str;
21: {
22: register char *cp, *cp2, *top;
23:
24: for (cp = str; *cp; cp++)
25: ;
26: top = salloc(cp-str + 1);
27: if (top == NOSTR)
28: return(NOSTR);
29: for (cp = str, cp2 = top; *cp; cp++)
30: *cp2++ = *cp;
31: *cp2 = 0;
32: return(top);
33: }
34:
35: /*
36: * Copy the name from the passed header line into the passed
37: * name buffer. Null pad the name buffer.
38: */
39:
40: copyname(linebuf, nbuf)
41: char *linebuf, *nbuf;
42: {
43: register char *cp, *cp2;
44:
45: for (cp = linebuf + 5, cp2 = nbuf; *cp != ' ' && cp2-nbuf < 8; cp++)
46: *cp2++ = *cp;
47: while (cp2-nbuf < 8)
48: *cp2++ = 0;
49: }
50:
51: /*
52: * Announce a fatal error and die.
53: */
54:
55: panic(str)
56: char *str;
57: {
58: prs("panic: ");
59: prs(str);
60: prs("\n");
61: exit(1);
62: }
63:
64: /*
65: * Catch stdio errors and report them more nicely.
66: */
67:
68: _error(str)
69: char *str;
70: {
71: prs("Stdio Error: ");
72: prs(str);
73: prs("\n");
74: abort();
75: }
76:
77: /*
78: * Print a string on diagnostic output.
79: */
80:
81: prs(str)
82: char *str;
83: {
84: register char *s;
85:
86: for (s = str; *s; s++)
87: ;
88: write(2, str, s-str);
89: }
90:
91: /*
92: * Touch the named message by setting its MTOUCH flag.
93: * Touched messages have the effect of not being sent
94: * back to the system mailbox on exit.
95: */
96:
97: touch(mesg)
98: {
99: if (mesg >= 1 && mesg <= msgCount)
100: message[mesg-1].m_flag |= MTOUCH;
101: }
102:
103: /*
104: * Test to see if the passed file name is a directory.
105: * Return true if it is.
106: */
107:
108: isdir(name)
109: char name[];
110: {
111: struct stat sbuf;
112:
113: if (stat(name, &sbuf) < 0)
114: return(0);
115: return((sbuf.st_mode & S_IFMT) == S_IFDIR);
116: }
117:
118: /*
119: * Compute the size in characters of the passed message
120: */
121:
122: unsigned int
123: msize(messp)
124: struct message *messp;
125: {
126: register struct message *mp;
127:
128: mp = messp;
129: return(mp->m_size);
130: }
131:
132: /*
133: * Count the number of arguments in the given string raw list.
134: */
135:
136: argcount(argv)
137: char **argv;
138: {
139: register char **ap;
140:
141: for (ap = argv; *ap != NOSTR; ap++)
142: ;
143: return(ap-argv);
144: }
145:
146: /*
147: * Given a file address, determine the
148: * block number it represents.
149: */
150:
151: blockof(off)
152: off_t off;
153: {
154: off_t a;
155:
156: a = off >> 9;
157: a &= 077777;
158: return((int) a);
159: }
160:
161: /*
162: * Take a file address, and determine
163: * its offset in the current block.
164: */
165:
166: offsetof(off)
167: off_t off;
168: {
169: off_t a;
170:
171: a = off & 0777;
172: return((int) a);
173: }
174:
175: /*
176: * Determine if the passed file is actually a tty, via a call to
177: * gtty. This is not totally reliable, but . . .
178: */
179:
180: isatty(f)
181: {
182: struct sgttyb buf;
183:
184: if (gtty(f, &buf) < 0)
185: return(0);
186: return(1);
187: }
188:
189: /*
190: * Return the desired header line from the passed message
191: * pointer (or NOSTR if the desired header field is not available).
192: */
193:
194: char *
195: hfield(field, mp)
196: char field[];
197: struct message *mp;
198: {
199: register FILE *ibuf;
200: char linebuf[LINESIZE];
201: register int lc;
202:
203: ibuf = setinput(mp);
204: if ((lc = mp->m_lines) <= 0)
205: return(NOSTR);
206: if (readline(ibuf, linebuf) < 0)
207: return(NOSTR);
208: lc--;
209: do {
210: lc = gethfield(ibuf, linebuf, lc);
211: if (lc == -1)
212: return(NOSTR);
213: if (ishfield(linebuf, field))
214: return(savestr(hcontents(linebuf)));
215: } while (lc > 0);
216: return(NOSTR);
217: }
218:
219: /*
220: * Return the next header field found in the given message.
221: * Return > 0 if something found, <= 0 elsewise.
222: * Must deal with \ continuations & other such fraud.
223: */
224:
225: gethfield(f, linebuf, rem)
226: register FILE *f;
227: char linebuf[];
228: register int rem;
229: {
230: char line2[LINESIZE];
231: long loc;
232: register char *cp, *cp2;
233: register int c;
234:
235:
236: for (;;) {
237: if (rem <= 0)
238: return(-1);
239: if (readline(f, linebuf) < 0)
240: return(-1);
241: rem--;
242: if (strlen(linebuf) == 0)
243: return(-1);
244: if (isspace(linebuf[0]))
245: continue;
246: if (linebuf[0] == '>')
247: continue;
248: cp = index(linebuf, ':');
249: if (cp == NOSTR)
250: continue;
251: for (cp2 = linebuf; cp2 < cp; cp2++)
252: if (isdigit(*cp2))
253: continue;
254:
255: /*
256: * I guess we got a headline.
257: * Handle wraparounding
258: */
259:
260: for (;;) {
261: if (rem <= 0)
262: break;
263: #ifdef CANTELL
264: loc = ftell(f);
265: if (readline(f, line2) < 0)
266: break;
267: rem--;
268: if (!isspace(line2[0])) {
269: fseek(f, loc, 0);
270: rem++;
271: break;
272: }
273: #else
274: c = getc(f);
275: ungetc(c, f);
276: if (!isspace(c) || c == '\n')
277: break;
278: if (readline(f, line2) < 0)
279: break;
280: rem--;
281: #endif
282: cp2 = line2;
283: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
284: ;
285: if (strlen(linebuf) + strlen(cp2) >= LINESIZE-2)
286: break;
287: cp = &linebuf[strlen(linebuf)];
288: while (cp > linebuf &&
289: (isspace(cp[-1]) || cp[-1] == '\\'))
290: cp--;
291: *cp++ = ' ';
292: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
293: ;
294: strcpy(cp, cp2);
295: }
296: if ((c = strlen(linebuf)) > 0) {
297: cp = &linebuf[c-1];
298: while (cp > linebuf && isspace(*cp))
299: cp--;
300: *++cp = 0;
301: }
302: return(rem);
303: }
304: /* NOTREACHED */
305: }
306:
307: /*
308: * Check whether the passed line is a header line of
309: * the desired breed.
310: */
311:
312: ishfield(linebuf, field)
313: char linebuf[], field[];
314: {
315: register char *cp;
316: register int c;
317:
318: if ((cp = index(linebuf, ':')) == NOSTR)
319: return(0);
320: if (cp == linebuf)
321: return(0);
322: cp--;
323: while (cp > linebuf && isspace(*cp))
324: cp--;
325: c = *++cp;
326: *cp = 0;
327: if (icequal(linebuf ,field)) {
328: *cp = c;
329: return(1);
330: }
331: *cp = c;
332: return(0);
333: }
334:
335: /*
336: * Extract the non label information from the given header field
337: * and return it.
338: */
339:
340: char *
341: hcontents(hfield)
342: char hfield[];
343: {
344: register char *cp;
345:
346: if ((cp = index(hfield, ':')) == NOSTR)
347: return(NOSTR);
348: cp++;
349: while (*cp && isspace(*cp))
350: cp++;
351: return(cp);
352: }
353:
354: /*
355: * Compare two strings, ignoring case.
356: */
357:
358: icequal(s1, s2)
359: register char *s1, *s2;
360: {
361:
362: while (raise(*s1++) == raise(*s2))
363: if (*s2++ == 0)
364: return(1);
365: return(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: static FILE *sstack[_NFILE]; /* Saved input files */
376:
377: /*
378: * Pushdown current input file and switch to a new one.
379: * Set the global flag "sourcing" so that others will realize
380: * that they are no longer reading from a tty (in all probability).
381: */
382:
383: source(name)
384: char name[];
385: {
386: register FILE *fi;
387:
388: if ((fi = fopen(name, "r")) == NULL) {
389: perror(name);
390: return(1);
391: }
392: if (ssp >= _NFILE-2) {
393: printf("Too much \"sourcing\" going on.\n");
394: fclose(fi);
395: return(1);
396: }
397: sstack[++ssp] = input;
398: input = fi;
399: sourcing++;
400: return(0);
401: }
402:
403: /*
404: * Source a file, but do nothing if the file cannot be opened.
405: */
406:
407: source1(name)
408: char name[];
409: {
410: register int f;
411:
412: if ((f = open(name, 0)) < 0)
413: return(0);
414: close(f);
415: source(name);
416: }
417:
418: /*
419: * Pop the current input back to the previous level.
420: * Update the "sourcing" flag as appropriate.
421: */
422:
423: unstack()
424: {
425: if (ssp < 0) {
426: printf("\"Source\" stack over-pop.\n");
427: sourcing = 0;
428: return(1);
429: }
430: fclose(input);
431: input = sstack[ssp--];
432: if (ssp < 0)
433: sourcing = 0;
434: return(0);
435: }
436:
437: /*
438: * Touch the indicated file.
439: * This is nifty for the shell.
440: * If we have the utime() system call, this is better served
441: * by using that, since it will work for empty files.
442: * On non-utime systems, we must sleep a second, then read.
443: */
444:
445: alter(name)
446: char name[];
447: {
448: #ifdef UTIME
449: struct stat statb;
450: long time();
451: time_t time_p[2];
452: #else
453: register int pid, f;
454: char w;
455: #endif UTIME
456:
457: #ifdef UTIME
458: if (stat(name, &statb) < 0)
459: return;
460: time_p[0] = time((long *) 0) + 1;
461: time_p[1] = statb.st_mtime;
462: utime(name, time_p);
463: #else
464: if ((pid = fork()) != 0)
465: return;
466: clrbuf(stdout);
467: clrbuf(stderr);
468: clrbuf(stdin);
469: sleep(1);
470: if ((f = open(name, 0)) < 0)
471: exit(1);
472: read(f, &w, 1);
473: exit(0);
474: #endif
475: }
476:
477: /*
478: * Examine the passed line buffer and
479: * return true if it is all blanks and tabs.
480: */
481:
482: blankline(linebuf)
483: char linebuf[];
484: {
485: register char *cp;
486:
487: for (cp = linebuf; *cp; cp++)
488: if (!any(*cp, " \t"))
489: return(0);
490: return(1);
491: }
492:
493: /*
494: * Fetch the sender's name from the passed message.
495: */
496:
497: char *
498: nameof(mp)
499: register struct message *mp;
500: {
501: char namebuf[LINESIZE];
502: char linebuf[LINESIZE];
503: register char *cp, *cp2;
504: register FILE *ibuf;
505: int first = 1;
506:
507: if ((cp = hfield("reply-to", mp)) != NOSTR) {
508: strcpy(namebuf, cp);
509: return(namebuf);
510: }
511: ibuf = setinput(mp);
512: copy("", namebuf);
513: if (readline(ibuf, linebuf) <= 0)
514: return(savestr(namebuf));
515: newname:
516: for (cp = linebuf; *cp != ' '; cp++)
517: ;
518: while (any(*cp, " \t"))
519: cp++;
520: for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") &&
521: cp2-namebuf < LINESIZE-1; *cp2++ = *cp++)
522: ;
523: *cp2 = '\0';
524: if (readline(ibuf, linebuf) <= 0)
525: return(savestr(namebuf));
526: if ((cp = index(linebuf, 'F')) == NULL)
527: return(savestr(namebuf));
528: if (strncmp(cp, "From", 4) != 0)
529: return(savestr(namebuf));
530: while ((cp = index(cp, 'r')) != NULL) {
531: if (strncmp(cp, "remote", 6) == 0) {
532: if ((cp = index(cp, 'f')) == NULL)
533: break;
534: if (strncmp(cp, "from", 4) != 0)
535: break;
536: if ((cp = index(cp, ' ')) == NULL)
537: break;
538: cp++;
539: if (first) {
540: copy(cp, namebuf);
541: first = 0;
542: } else
543: strcpy(rindex(namebuf, '!')+1, cp);
544: strcat(namebuf, "!");
545: goto newname;
546: }
547: cp++;
548: }
549: return(savestr(namebuf));
550: }
551:
552: /*
553: * Find the rightmost pointer to an instance of the
554: * character in the string and return it.
555: */
556:
557: char *
558: rindex(str, c)
559: char str[];
560: register int c;
561: {
562: register char *cp, *cp2;
563:
564: for (cp = str, cp2 = NOSTR; *cp; cp++)
565: if (c == *cp)
566: cp2 = cp;
567: return(cp2);
568: }
569:
570: /*
571: * See if the string is a number.
572: */
573:
574: numeric(str)
575: char str[];
576: {
577: register char *cp = str;
578:
579: while (*cp)
580: if (!isdigit(*cp++))
581: return(0);
582: return(1);
583: }
584:
585: /*
586: * Are any of the characters in the two strings the same?
587: */
588:
589: anyof(s1, s2)
590: register char *s1, *s2;
591: {
592: register int c;
593:
594: while (c = *s1++)
595: if (any(c, s2))
596: return(1);
597: return(0);
598: }
599:
600: /*
601: * Determine the leftmost index of the character
602: * in the string.
603: */
604:
605: char *
606: index(str, ch)
607: char *str;
608: {
609: register char *cp;
610: register int c;
611:
612: for (c = ch, cp = str; *cp; cp++)
613: if (*cp == c)
614: return(cp);
615: return(NOSTR);
616: }
617:
618: /*
619: * String compare two strings of bounded length.
620: */
621:
622: strncmp(as1, as2, an)
623: char *as1, *as2;
624: {
625: register char *s1, *s2;
626: register int n;
627:
628: s1 = as1;
629: s2 = as2;
630: n = an;
631: while (--n >= 0 && *s1 == *s2++)
632: if (*s1++ == '\0')
633: return(0);
634: return(n<0 ? 0 : *s1 - *--s2);
635: }
636:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.