|
|
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: register char *cp, *cp2;
232:
233: for (;;) {
234: if (rem <= 0)
235: return(-1);
236: if (readline(f, linebuf) < 0)
237: return(-1);
238: rem--;
239: if (strlen(linebuf) == 0)
240: return(-1);
241: if (isspace(linebuf[0]))
242: return(-1);
243: if (linebuf[0] == '>')
244: continue;
245: cp = index(linebuf, ':');
246: if (cp == NOSTR)
247: return(-1);
248: for (cp2 = linebuf; cp2 < cp; cp2++)
249: if (isdigit(*cp2))
250: continue;
251:
252: /*
253: * I guess we got a headline.
254: * Handle \ wraparounding
255: */
256:
257: for (;;) {
258: cp = &linebuf[strlen(linebuf) - 1];
259: if (*cp != '\\')
260: break;
261: if (rem < 0)
262: break;
263: if (readline(f, line2) < 0)
264: break;
265: rem--;
266: if (strlen(linebuf) + strlen(line2) >= LINESIZE-2)
267: break;
268: if (cp > linebuf)
269: --cp;
270: if (!isspace(*cp))
271: *++cp = ' ';
272: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
273: ;
274: strcpy(++cp, cp2);
275: }
276: return(rem);
277: }
278: /* NOTREACHED */
279: }
280:
281: /*
282: * Check whether the passed line is a header line of
283: * the desired breed.
284: */
285:
286: ishfield(linebuf, field)
287: char linebuf[], field[];
288: {
289: register char *cp;
290: register int c;
291:
292: if ((cp = index(linebuf, ':')) == NOSTR)
293: return(0);
294: if (cp == linebuf)
295: return(0);
296: cp--;
297: while (cp > linebuf && isspace(*cp))
298: cp--;
299: c = *++cp;
300: *cp = 0;
301: if (icequal(linebuf ,field)) {
302: *cp = c;
303: return(1);
304: }
305: *cp = c;
306: return(0);
307: }
308:
309: /*
310: * Extract the non label information from the given header field
311: * and return it.
312: */
313:
314: char *
315: hcontents(hfield)
316: char hfield[];
317: {
318: register char *cp;
319:
320: if ((cp = index(hfield, ':')) == NOSTR)
321: return(NOSTR);
322: cp++;
323: while (*cp && isspace(*cp))
324: cp++;
325: return(cp);
326: }
327:
328: /*
329: * Compare two strings, ignoring case.
330: */
331:
332: icequal(s1, s2)
333: register char *s1, *s2;
334: {
335:
336: while (raise(*s1++) == raise(*s2))
337: if (*s2++ == 0)
338: return(1);
339: return(0);
340: }
341:
342: /*
343: * The following code deals with input stacking to do source
344: * commands. All but the current file pointer are saved on
345: * the stack.
346: */
347:
348: static int ssp = -1; /* Top of file stack */
349: static FILE *sstack[_NFILE]; /* Saved input files */
350:
351: /*
352: * Pushdown current input file and switch to a new one.
353: * Set the global flag "sourcing" so that others will realize
354: * that they are no longer reading from a tty (in all probability).
355: */
356:
357: source(name)
358: char name[];
359: {
360: register FILE *fi;
361:
362: if ((fi = fopen(name, "r")) == NULL) {
363: perror(name);
364: return(1);
365: }
366: if (ssp >= _NFILE-2) {
367: printf("Too much \"sourcing\" going on.\n");
368: fclose(fi);
369: return(1);
370: }
371: sstack[++ssp] = input;
372: input = fi;
373: sourcing++;
374: return(0);
375: }
376:
377: /*
378: * Source a file, but do nothing if the file cannot be opened.
379: */
380:
381: source1(name)
382: char name[];
383: {
384: register int f;
385:
386: if ((f = open(name, 0)) < 0)
387: return(0);
388: close(f);
389: source(name);
390: }
391:
392: /*
393: * Pop the current input back to the previous level.
394: * Update the "sourcing" flag as appropriate.
395: */
396:
397: unstack()
398: {
399: if (ssp < 0) {
400: printf("\"Source\" stack over-pop.\n");
401: sourcing = 0;
402: return(1);
403: }
404: fclose(input);
405: input = sstack[ssp--];
406: if (ssp < 0)
407: sourcing = 0;
408: return(0);
409: }
410:
411: /*
412: * Touch the indicated file.
413: * This is nifty for the shell.
414: */
415:
416: alter(name)
417: char name[];
418: {
419: register int pid, f;
420: char w;
421:
422: if ((pid = fork()) != 0)
423: return;
424: clrbuf(stdout);
425: clrbuf(stderr);
426: clrbuf(stdin);
427: sleep(1);
428: if ((f = open(name, 0)) < 0)
429: exit(1);
430: read(f, &w, 1);
431: exit(0);
432: }
433:
434: /*
435: * Examine the passed line buffer and
436: * return true if it is all blanks and tabs.
437: */
438:
439: blankline(linebuf)
440: char linebuf[];
441: {
442: register char *cp;
443:
444: for (cp = linebuf; *cp; cp++)
445: if (!any(*cp, " \t"))
446: return(0);
447: return(1);
448: }
449:
450: /*
451: * Fetch the sender's name from the passed message.
452: */
453:
454: char *
455: nameof(mp)
456: register struct message *mp;
457: {
458: static char namebuf[NAMESIZE];
459: char linebuf[LINESIZE];
460: register char *cp, *cp2;
461: register FILE *ibuf;
462: int first = 1;
463:
464: if ((cp = hfield("from", mp)) != NOSTR) {
465: strcpy(namebuf, cp);
466: return(namebuf);
467: }
468: ibuf = setinput(mp);
469: copy("", namebuf);
470: if (readline(ibuf, linebuf) <= 0)
471: return(namebuf);
472: newname:
473: for (cp = linebuf; *cp != ' '; cp++)
474: ;
475: while (any(*cp, " \t"))
476: cp++;
477: for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") &&
478: cp2-namebuf < NAMESIZE-1; *cp2++ = *cp++)
479: ;
480: *cp2 = '\0';
481: if (readline(ibuf, linebuf) <= 0)
482: return(namebuf);
483: if ((cp = index(linebuf, 'F')) == NULL)
484: return(namebuf);
485: if (strncmp(cp, "From", 4) != 0)
486: return(namebuf);
487: while ((cp = index(cp, 'r')) != NULL) {
488: if (strncmp(cp, "remote", 6) == 0) {
489: if ((cp = index(cp, 'f')) == NULL)
490: break;
491: if (strncmp(cp, "from", 4) != 0)
492: break;
493: if ((cp = index(cp, ' ')) == NULL)
494: break;
495: cp++;
496: if (first) {
497: copy(cp, namebuf);
498: first = 0;
499: } else
500: strcpy(rindex(namebuf, '!')+1, cp);
501: strcat(namebuf, "!");
502: goto newname;
503: }
504: cp++;
505: }
506: return(namebuf);
507: }
508:
509: /*
510: * Find the rightmost pointer to an instance of the
511: * character in the string and return it.
512: */
513:
514: char *
515: rindex(str, c)
516: char str[];
517: register int c;
518: {
519: register char *cp, *cp2;
520:
521: for (cp = str, cp2 = NOSTR; *cp; cp++)
522: if (c == *cp)
523: cp2 = cp;
524: return(cp2);
525: }
526:
527: /*
528: * See if the string is a number.
529: */
530:
531: numeric(str)
532: char str[];
533: {
534: register char *cp = str;
535:
536: while (*cp)
537: if (!isdigit(*cp++))
538: return(0);
539: return(1);
540: }
541:
542: /*
543: * Are any of the characters in the two strings the same?
544: */
545:
546: anyof(s1, s2)
547: register char *s1, *s2;
548: {
549: register int c;
550:
551: while (c = *s1++)
552: if (any(c, s2))
553: return(1);
554: return(0);
555: }
556:
557: /*
558: * Determine the leftmost index of the character
559: * in the string.
560: */
561:
562: char *
563: index(str, ch)
564: char *str;
565: {
566: register char *cp;
567: register int c;
568:
569: for (c = ch, cp = str; *cp; cp++)
570: if (*cp == c)
571: return(cp);
572: return(NOSTR);
573: }
574:
575: /*
576: * String compare two strings of bounded length.
577: */
578:
579: strncmp(as1, as2, an)
580: char *as1, *as2;
581: {
582: register char *s1, *s2;
583: register int n;
584:
585: s1 = as1;
586: s2 = as2;
587: n = an;
588: while (--n >= 0 && *s1 == *s2++)
589: if (*s1++ == '\0')
590: return(0);
591: return(n<0 ? 0 : *s1 - *--s2);
592: }
593:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.