|
|
1.1 root 1: /*
2: * print mail
3: */
4: #include <stdio.h>
5: #include <sys/types.h>
6: #include <sys/stat.h>
7: #include <setjmp.h>
8: #include <ctype.h>
9: #include "mail.h"
10: #include "letter.h"
11: #include "string.h"
12:
13: /* globals */
14: static int flgp;
15: static int manual;
16: static int forward;
17: static int nlet;
18: static int error;
19: static int otherfile;
20: static jmp_buf sjbuf;
21: #define seq(i) (forward ? i-1 : nlet-i)
22: static int changed; /* true if mail file has been changed */
23:
24: /* exported */
25: char *thissys;
26:
27: /* imported */
28: extern void lock();
29: extern void unlock();
30: extern char *getlogin();
31: extern char *getenv();
32: extern char *getarg();
33: extern FILE *popen();
34: extern char *mailpath();
35: extern long getunix();
36: extern char *getsysname();
37: extern char *P();
38: extern void V();
39:
40: /* predefined */
41: static char *doargs();
42: static long copymt();
43: static void domanual();
44: static void doauto();
45: static int docommand();
46: static int copyback();
47: static int done();
48: static int special_mailfile();
49: static int doprint();
50: static void dohelp();
51: static void print_from();
52: static int reply();
53: static int remail();
54: static int squirrel_away();
55:
56: main(argc, argv)
57: char **argv;
58: {
59: struct stat stbuf;
60: char *mp, *tp;
61: long mailsize;
62: FILE *malf;
63:
64: mp = doargs(argc, argv);
65: if (stat(mp, &stbuf) < 0 || stbuf.st_size == 0L) {
66: printf("No mail.\n");
67: return 0;
68: }
69: thissys = getsysname();
70: (void)signal(SIGINT, done);
71: (void)signal(SIGHUP, done);
72: lock(mp);
73: tp = otherfile ? NULL : P();
74: if (tp != NULL)
75: fprintf(stderr, "You are already reading mail on %s!\n\n", tp);
76: malf = fopen(mp, "r");
77: if (malf == NULL) {
78: fprintf(stderr, "mail: cannot read %s.\n", mp);
79: error++;
80: (void)done();
81: }
82:
83: /* see if we're piping or forwarding */
84: if(special_mailfile(mp))
85: (void)done();
86:
87: /* make temporary */
88: inittmp();
89:
90: /* read mbox */
91: mailsize = copymt(malf);
92: fclose(malf);
93: unlock();
94:
95: /* print the mail */
96: if (flgp)
97: printall();
98: else {
99: if (manual)
100: domanual();
101: else
102: doauto();
103: }
104: if (changed)
105: copyback(mailsize, mp);
106: (void)done();
107:
108: return 0;
109: }
110:
111: /* Output all messages */
112: printall()
113: {
114: int i, current;
115:
116: for (i = 0; i < nlet; i++) {
117: current = forward ? i : nlet - i - 1;
118: doprint(current);
119: }
120: }
121:
122: /* remember an interrupt happened */
123: rememberint()
124: {
125: signal(SIGINT, rememberint);
126: clearerr(stdin);
127: clearerr(stdout);
128: longjmp(sjbuf, 1);
129: }
130:
131: #define eatwhite(p) while(*p==' '||*p=='\t') p++
132:
133: /*
134: * Return a letter number
135: */
136: static int
137: lnumber(pp, dot, def)
138: char **pp;
139: {
140: eatwhite(*pp);
141: switch(**pp) {
142: case '$':
143: (*pp)++;
144: dot = nlet;
145: break;
146: case 'n':
147: case '+':
148: (*pp)++;
149: dot = dot + 1;
150: break;
151: case '^':
152: case '-':
153: (*pp)++;
154: dot = dot - 1;
155: break;
156: case '.':
157: (*pp)++;
158: break;
159: case '0': case '1': case '2': case '3': case '4':
160: case '5': case '6': case '7': case '8': case '9':
161: dot = 0;
162: while (isdigit(**pp))
163: dot = dot*10 + *(*pp)++ - '0';
164: break; /* first letter is 1 */
165: default:
166: dot = def;
167: break;
168: }
169: if (dot <= 0)
170: dot = 1;
171: return dot;
172: }
173:
174: /*
175: * Read and parse a command line. A command consists of an optional
176: * range, a single letter command, and optional arguments.
177: */
178: static char *
179: parse(cmdp, firstp, lastp, dot)
180: char *cmdp; /* the 1 letter command */
181: int *firstp; /* first command in a range */
182: int *lastp; /* last command in a range */
183: int dot; /* current letter */
184: {
185: static char resp[CMDSIZE];
186: char *p = resp;
187:
188: /* get command and dump trailing newline */
189: printf("? ");
190: fflush(stdout);
191: if (fgets(resp, CMDSIZE, stdin) == NULL)
192: return NULL;
193: p[strlen(p) - 1] = '\0';
194:
195: /* get range */
196: eatwhite(p);
197: if (*p != '\0') {
198: if (*p == ',')
199: *firstp = 1;
200: else
201: *firstp = lnumber(&p, dot, dot);
202: eatwhite(p);
203: if (*p != ',')
204: *lastp = *firstp;
205: else {
206: p++;
207: *lastp = lnumber(&p, dot, nlet);
208: }
209: } else
210: *firstp = *lastp = dot+1;
211:
212: /* get command */
213: eatwhite(p);
214: if (*p != '\0')
215: *cmdp = *p++;
216: else
217: *cmdp = 'p';
218:
219: /* compound command */
220: if (*cmdp == 'd' && (*p == 'q' || *p == 'p'))
221: *(cmdp+1) = *p++;
222: else
223: *(cmdp+1) = '\0';
224: eatwhite(p);
225: return p;
226: }
227:
228: /* Process user commands in the new style.
229: * All actions are prompted for.
230: */
231: static void
232: domanual()
233: {
234: int dot=1, print, i;
235: int first, last;
236: char cmd[2], *args;
237:
238: printf("%d letters\n", nlet);
239: while (1) {
240: /* in case of interrupt, come back here but don't print */
241: if (setjmp(sjbuf)) /* after long jump */
242: printf("\n");
243: signal(SIGINT, rememberint);
244: args = parse(cmd, &first, &last, dot);
245: if (args == NULL)
246: break;
247: for (i = first; i <= last && i <= nlet; i++) {
248: dot = i; /* must be here in case of interrupt */
249: if (docommand(cmd[0], args, i, &print) < 0)
250: return;
251: }
252: switch (cmd[1]) {
253: case 'q':
254: return;
255: case 'p':
256: doprint(seq(++dot));
257: break;
258: }
259: }
260: }
261:
262: /* Process user commands in the old style.
263: * This implies printing the next message
264: * without prompting for it
265: */
266: static void
267: doauto()
268: {
269: int print=1, dot=1, i;
270: int first, last;
271: char cmd[2], *args;
272:
273: while (dot <= nlet && dot >= 0) {
274: /* in case of interrupt, come back here but don't print */
275: if (setjmp(sjbuf)) /* after long jump */
276: printf("\n");
277: else { /* here normally */
278: signal(SIGINT, rememberint);
279: if (print)
280: doprint(seq(dot));
281: }
282: print = 0;
283: args = parse(cmd, &first, &last, dot);
284: if (args == NULL)
285: break;
286: for (i = first; i <= last && i <= nlet; i++) {
287: dot = i; /* in case of interrupt while printing */
288: dot = docommand(cmd[0], args, i, &print);
289: }
290: if (dot > 0 && dot < last)
291: dot = last;
292: switch (cmd[1]) {
293: case 'q':
294: return;
295: case 'p':
296: print++;
297: break;
298: }
299: }
300: }
301:
302: /*
303: * Perform a command.
304: */
305: static int
306: docommand(cmd, args, dot, pflag)
307: char cmd; /* command to perform */
308: char *args; /* arguments to the command */
309: int dot; /* the message to apply it to */
310: int *pflag; /* (returned) true if next message to be printed */
311: {
312: switch (cmd) {
313: default:
314: printf("usage\n");
315: case '?':
316: dohelp();
317: break;
318: case 'h':
319: print_from(seq(dot));
320: break;
321: case '=':
322: printf("at letter %d\n", dot);
323: break;
324: case 'p':
325: doprint(seq(dot));
326: break;
327: case 'x':
328: changed = 0;
329: dot = -1;
330: break;
331: case 'y':
332: case 'w':
333: case 's':
334: if (squirrel_away(seq(dot), args) == 0) {
335: (void)ldelete(seq(dot));
336: changed++;
337: (*pflag)++;
338: dot++;
339: }
340: break;
341: case 'm':
342: if (remail(seq(dot), args) == 0) {
343: (void)ldelete(seq(dot));
344: changed++;
345: (*pflag)++;
346: dot++;
347: }
348: break;
349: case 'r':
350: if (*args != '\0') {
351: fprintf(stderr, "invalid: r takes no arguments\n");
352: break;
353: }
354: (void)reply(seq(dot));
355: printf("!\n");
356: break;
357: case '!':
358: system(args);
359: printf("!\n");
360: break;
361: case 'd':
362: if (*args != '\0') {
363: fprintf(stderr,"invalid: d takes no arguments\n");
364: break;
365: }
366: (void)ldelete(seq(dot));
367: changed++;
368: (*pflag)++;
369: dot++;
370: break;
371: case 'u':
372: if (*args != '\0') {
373: fprintf(stderr,"invalid: u takes no arguments\n");
374: break;
375: }
376: (void)lundelete(seq(dot));
377: (*pflag)++;
378: dot++;
379: break;
380: case 'q':
381: dot = -1;
382: break;
383: }
384: return dot;
385: }
386:
387: /* copy mail to temp file, returns size of mail file */
388: static long
389: copymt(mfp)
390: FILE *mfp;
391: {
392: letter *lp=NULL;
393: char line[FROMLINESIZE];
394:
395: /* read in letters */
396: while (fgets(line, FROMLINESIZE, mfp) != NULL) {
397: if (strncmp(line, FROM, FSIZE)==0 || lp==NULL) {
398: lp = lopen(nlet++, "w");
399: }
400: lputs(line, lp);
401: }
402:
403: /* remember where end of file is */
404: return ftell(mfp);
405: }
406:
407: /* copy temp or whatever back to /usr/spool/mail */
408: static int
409: copyback(oldsize, mp)
410: long oldsize;
411: char *mp;
412: {
413: register i;
414: register int new = 0;
415: struct stat stbuf;
416: letter *lp;
417: FILE *malf;
418:
419: lock(mp);
420:
421: /* read new mail that arrived while we were printing */
422: stat(mp, &stbuf);
423: if (stbuf.st_size != oldsize) { /* new mail has arrived */
424: malf = fopen(mp, "r");
425: if (malf == NULL) {
426: fprintf(stderr, "mail: can't re-read %s\n", mp);
427: (void)done();
428: }
429: fseek(malf, oldsize, 0);
430: (void)copymt(malf);
431: fclose(malf);
432: new++;
433: }
434:
435: /* turn off interrupts while writing back */
436: signal(SIGHUP, SIG_IGN);
437: signal(SIGINT, SIG_IGN);
438: signal(SIGQUIT, SIG_IGN);
439: signal(SIGTERM, SIG_IGN);
440:
441: /* write the sucker back */
442: malf = fopen(mp, "w");
443: if (malf == NULL) {
444: fprintf(stderr, "mail: can't rewrite %s\n", mp);
445: (void)done();
446: }
447: for (i = 0; i < nlet; i++)
448: if ((lp=lopen(i, "ru")) != NULL) {
449: copyfrom(lp, malf);
450: }
451: fclose(malf);
452: unlock();
453: if (new)
454: printf("new mail arrived\n");
455: }
456:
457: /* come here to finish up */
458: static int
459: done()
460: {
461: unlock();
462: V();
463: releasetmp();
464: exit(error);
465: return 0;
466: }
467:
468: static char *
469: doargs(argc, argv)
470: int argc;
471: char *argv[];
472: {
473: static char mailfile[256];
474:
475: (void)strcpy(mailfile, mailpath(getlogin()));
476:
477: for (; argc>1; argv++, argc--) {
478: if (argv[1][0]=='-') {
479: if (argv[1][1]=='p') {
480: flgp++;
481: } else if (argv[1][1]=='f') {
482: if (argc>=3) {
483: strcpy(mailfile, argv[2]);
484: argv++;
485: argc--;
486: otherfile = 1;
487: }
488: } else if (argv[1][1]=='r') {
489: forward = 1;
490: } else if (argv[1][1]=='m') {
491: manual = 1;
492: } else {
493: fprintf(stderr, "mail: unknown option %c\n", argv[1][1]);
494: done();
495: }
496: } else
497: break;
498: }
499: return mailfile;
500: }
501:
502: /* return non-zero if this is not a normal mail file */
503: static int
504: special_mailfile(mp)
505: char *mp; /* mail file */
506: {
507: char fbuf[256];
508: char *sp1, *sp2;
509: int stat;
510:
511: sp2 = "";
512:
513: /* if something is being done to the mail, go away */
514: stat = delivery_status(mp, fbuf);
515: switch(stat & MFTYPE) {
516: case MF_FORWARD:
517: sp1 = "Your mail is being forwarded to";
518: break;
519: case MF_PIPE:
520: sp1 = "Your mail is being piped to";
521: break;
522: default:
523: return 0;
524: }
525:
526: if (stat & MFEXTRA)
527: sp2 = "and your mailbox contains extra stuff\n";
528: printf("%s %s %s\n", sp1, fbuf, sp2);
529: return stat & MFTYPE;
530: }
531:
532: static void
533: dohelp()
534: {
535: printf("Commands are of the form '[range] command [args]'.\n");
536: printf("The command can be:\n");
537: printf("d\tdelete\n");
538: printf("u\tundelete\n");
539: printf("h\tprint from lines of all messages\n");
540: printf("m user\tmail to user\n");
541: printf("p\tprint\n");
542: printf("r\treply to last message\n");
543: printf("q\tquit\n");
544: printf("s[file]\tsave (default mbox)\n");
545: printf("x\texit without changing mail\n");
546: printf("=\tprint current message number\n");
547: printf("! cmd\texecute cmd\n");
548: }
549:
550: /* print the from line (and status) of each message */
551: static void
552: print_from(let)
553: int let;
554: {
555: int deleted;
556: char from[FROMLINESIZE];
557: letter *lp;
558:
559: lp = lopen(let, "ru");
560: if (lp == NULL) {
561: deleted = 1;
562: lp = lopen(let, "r");
563: } else
564: deleted = 0;
565: lgets(from, FROMLINESIZE, lp);
566: printf("%3d %c %4d %s", seq(let), deleted?'d':' ',
567: lsize(lp), from+FSIZE);
568: }
569:
570: /* save a letter in a file, return 0 if successful */
571: static int
572: squirrel_away(let, resp)
573: int let;
574: char *resp;
575: {
576: char *p;
577: letter *lp;
578: char path[PATHSIZE];
579: int problems=0;
580: FILE *malf;
581:
582: if (*resp == '\0') {
583: p = getenv("HOME");
584: if(p != 0) {
585: strcpy(resp, p);
586: strcat(resp, "/mbox");
587: } else
588: strcpy(resp, "mbox");
589: }
590: for (p = resp; (p = getarg(path, p)) != NULL; ) {
591: malf = fopen(path, "a");
592: if (malf == NULL) {
593: fprintf(stderr, "mail: cannot append to %s\n", path);
594: problems++;
595: continue;
596: }
597: lp = lopen(let, "r");
598: copyfrom(lp, malf);
599: fclose(malf);
600: }
601: return problems;
602: }
603:
604: /* reply to mail, return 0 if no problems */
605: static char replyline[FROMLINESIZE];
606: static char replycmd[CMDSIZE];
607: static int
608: reply(let)
609: int let;
610: {
611: char *sp;
612: letter *lp;
613:
614: lp = lopen(let, "r");
615: lgets(replyline, FROMLINESIZE, lp);
616: sp = strchr(replyline+FSIZE, ' ');
617: if (sp != NULL)
618: *sp = '\0';
619: strcpy(replycmd, "/bin/mail ");
620: strcat(replycmd, replyline+FSIZE);
621: printf("!%s\n", replycmd);
622: system(replycmd);
623: return 0;
624: }
625:
626: /* pass mail onto someone else, return 0 if no problems */
627: static int
628: remail(let, resp)
629: int let;
630: char *resp;
631: {
632: char cmd[CMDSIZE];
633: FILE *pipf;
634: letter *lp;
635:
636: if (*resp == '\0') {
637: fprintf(stderr, "invalid: m requires a destination\n");
638: return -1;
639: }
640: strcpy(cmd, "mail ");
641: strcat(cmd, resp);
642:
643: /* fork so that mail becomes super-user again */
644: pipf = popen(cmd, "w");
645: if(pipf == NULL) {
646: fprintf(stderr, "mail: can't fork to remail\n");
647: return -1;
648: }
649: lp = lopen(let, "r");
650: copyfrom(lp, pipf);
651: return pclose(pipf);
652: }
653:
654: /* output the letter */
655: static int
656: doprint(let)
657: int let;
658: {
659: letter *lp;
660:
661: lp = lopen(let, "r");
662: if (lp == NULL)
663: return -1;
664: copyfrom(lp, stdout);
665: return 0;
666: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.