|
|
1.1 root 1: /*
2: * print mail
3: */
4: #include <stdio.h>
5: #include <setjmp.h>
6: #include <ctype.h>
7: #include <signal.h>
8: #include <regexp.h>
9: #include "mail.h"
10: #include "string.h"
11: #include "message.h"
12: #include "aux.h"
13: #include <sys/stat.h>
14:
15: /* global to this file */
16: static int reverse=0; /* ordering of mail messages */
17: static jmp_buf sjbuf;
18: int fflg;
19: int mflg;
20: int pflg;
21: int eflg;
22: SIG_TYP fint; /* what to do in case of int */
23: SIG_TYP fquit; /* what to do in case of quit */
24: SIG_TYP fpipe; /* what to do in case of sigpipe */
25:
26: /* predeclared */
27: message *addr();
28: message *grange();
29: message *range();
30: message *research();
31: message *bresearch();
32: message *incraddr();
33: char *getre();
34: char *header();
35: int edmail();
36: char *doargs();
37: void dumpmail();
38:
39: /* imported */
40: char *getlog();
41: FILE *lockopen();
42: FILE *lockreopen();
43:
44: SIGRETURN
45: done(s)
46: int s;
47: {
48: cleanlocks();
49: V();
50: exit(1);
51: }
52:
53: main(ac, av)
54: int ac;
55: char *av[];
56: {
57: char outbuf[BUFSIZ];
58: int writeable;
59: string *user = s_new();
60: char *mailfile;
61: char *logname;
62:
63: /* set signals - make sure we don't override some previous setting */
64: if ((fint=signal(SIGINT, SIG_IGN))!=SIG_DFL)
65: signal(SIGINT, fint);
66: else
67: signal(SIGINT, fint = (SIG_TYP)done);
68: if ((fquit=signal(SIGQUIT, SIG_IGN))!=SIG_DFL)
69: signal(SIGQUIT, fquit);
70: else
71: signal(SIGQUIT, fquit = (SIG_TYP)done);
72: if ((fpipe=signal(SIGPIPE, SIG_IGN))!=SIG_DFL)
73: signal(SIGPIPE, fpipe);
74: else
75: signal(SIGPIPE, fpipe = (SIG_TYP)done);
76:
77: logname = getlog();
78: if (logname == NULL) {
79: printf ("mail: cannot determine login name\n");
80: return 0;
81: }
82: s_append(user, logname);
83: setbuf(stdout, outbuf);
84: mailfile = doargs(ac, av, s_to_c(user));
85: if (!fflg)
86: writeable = P()==0;
87: else
88: writeable = 1;
89: if (eflg) {
90: int r = check_mbox(mailfile);
91: V();
92: return r;
93: }
94: if (read_mbox(mailfile, reverse)<0 || mlist == NULL) {
95: printf("No mail\n");
96: V();
97: return 0;
98: }
99: printf("%d messages\n", mlast->pos);
100: if (pflg)
101: dumpmail();
102: else{
103: while (edmail(mailfile, reverse) && writeable){
104: if(!write_mbox(mailfile, reverse))
105: break;
106: }
107: }
108: V();
109: return 0;
110: }
111:
112: /* parse arguments */
113: char *
114: doargs(ac, av, user)
115: int ac;
116: char *av[];
117: char *user;
118: {
119: int i;
120: string *mailfile;
121: char *cp;
122:
123: /* process args */
124: mailfile = s_new();
125: abspath(user, MAILROOT, mailfile);
126: for (i = 1; i<ac; i++) {
127: if (av[i][0]!='-') {
128: fprintf(stderr, "usage: mail [-mpre] [-f mbox]\n");
129: exit(1);
130: }
131: for (cp = av[i]+1; *cp; cp++) {
132: switch(*cp) {
133: case 'r':
134: reverse = 1;
135: break;
136: case 'm':
137: mflg = 1;
138: break;
139: case 'p':
140: pflg = 1;
141: break;
142: case 'e':
143: eflg = 1;
144: break;
145: case 'f':
146: fflg = 1;
147: if (i+1 >= ac) {
148: fprintf(stderr,"mail: missing filename\n");
149: exit(1);
150: }
151: s_append(s_restart(mailfile), av[++i]);
152: break;
153: default:
154: fprintf(stderr, "usage: mail [-mpre] [-f mbox]\n");
155: exit(1);
156: }
157: }
158: }
159: return s_to_c(mailfile);
160: }
161:
162: /* is the mailbox empty? 1 if yes, 0 if no */
163: int
164: check_mbox (mf)
165: char *mf;
166: {
167: int n, r;
168: char mbuf[1000];
169: string *line;
170: FILE *fp;
171:
172: /* if file doesn't exist, no mail */
173: if ((fp = fopen(mf, "r")) == NULL)
174: return 1;
175:
176: /* if we can't read it, no mail */
177: if (fgets(mbuf, sizeof(mbuf)-2, fp)==NULL){
178: fclose(fp);
179: return 1;
180: }
181: fclose(fp);
182:
183: /* it is empty iff delivery status is abnormal */
184: n = strlen(mbuf);
185: mbuf[n++] = '\n';
186: mbuf[n++] = '\0';
187: line = s_array(mbuf, n);
188: r = delivery_status(s_restart(line)) != MF_NORMAL;
189:
190: s_free (line);
191: return r;
192: }
193:
194: /* mesage dump */
195: void
196: dumpmail()
197: {
198: message *mp;
199:
200: for (mp=mlist; mp!=NULL; mp=mp->next) {
201: m_print(mp, stdout, 1, 1);
202: }
203: }
204:
205: SIGRETURN
206: catchint(s)
207: int s;
208: {
209: signal(SIGINT, catchint);
210: clearerr(stdin);
211: clearerr(stdout);
212: longjmp(sjbuf, 1);
213: }
214:
215: notatnl(cp)
216: char *cp;
217: {
218: if (*cp=='\n') {
219: fprintf(stderr, "!argument expected\n");
220: return -1;
221: }
222: return 0;
223: }
224:
225: int
226: atblank(cp)
227: char *cp;
228: {
229: if (*cp!='\n' && *(cp-1)!=' ' && *(cp-1)!='\t') {
230: fprintf(stderr, "newline or space expected\n");
231: return -1;
232: }
233: return 0;
234: }
235:
236: atnl(cp)
237: char *cp;
238: {
239: if (*cp!='\n') {
240: fprintf(stderr, "!newline expected\n");
241: return -1;
242: }
243: return 0;
244: }
245:
246: zero(mp)
247: message *mp;
248: {
249: if (mp==mzero) {
250: fprintf(stderr, "!message 0\n");
251: return -1;
252: }
253: return 0;
254: }
255:
256: #define s_skipwhite(s) for (; *s->ptr==' ' || *s->ptr=='\t'; s->ptr++);
257:
258: /* ed style interface */
259: edmail(mailfile, reverse)
260: char *mailfile;
261: int reverse;
262: {
263: message *dot;
264: message *extent;
265: string *cmd=s_new();
266: char *cp;
267: int cmdc;
268: int i, abort=0, nopr, change=1;
269: int del;
270:
271: extent = dot = mzero;
272: nopr = mflg;
273: for(;;) {
274: extent = dot; /* in case of interrupt */
275: if (!nopr) {
276: /* advance only if we want to print next message */
277: if(dot->next!=NULL)
278: dot = dot->next;
279: else
280: nopr = 1;
281: }
282: if (setjmp(sjbuf)) {
283: /* come here after interrupt */
284: if (extent!=NULL)
285: dot = extent;
286: nopr = 1;
287: printf("\n");
288: }
289: if (fint==(SIG_TYP)done)
290: signal(SIGINT, catchint);
291: if (!nopr&&dot!=mzero) {
292: /* print next message */
293: extent = dot; /* in case of interrupt */
294: print(dot);
295: nopr = 1;
296: }
297: abort = 0;
298: nopr = 1;
299: change = 1;
300: printf("?");
301: fflush(stdout);
302: if(s_read_line(stdin, s_restart(cmd)) == NULL) {
303: signal(SIGINT, fint); /* bacause of the setjmp */
304: return 1;
305: }
306: s_restart(cmd);
307: s_skipwhite(cmd);
308: if (!mflg && *cmd->ptr=='\n' && dot==mlast) {
309: signal(SIGINT, fint); /* bacause of the setjmp */
310: return 1;
311: }
312: extent = range(dot, cmd);
313: s_skipwhite(cmd);
314: del = 0;
315: compoundcmd:
316: /* hack to catch a common mistake */
317: if (strncmp(cmd->ptr, "mail", 4)==0)
318: cmdc = -1;
319: else
320: cmdc = *cmd->ptr++;
321: s_skipwhite(cmd);
322: cp = cmd->ptr;
323: for(; extent!=NULL && !abort; extent=extent->extent) {
324: switch(cmdc){
325: case 'b':
326: abort = atnl(cp)||(del&&delete(extent));
327: if (!abort)
328: if (extent!=mzero)
329: prheader(extent);
330: for(i=0; extent->next!=NULL&&i<9; i++){
331: extent = extent->next;
332: prheader(extent);
333: }
334: break;
335: case 'h':
336: abort = atnl(cp)||zero(extent)
337: ||(del&&delete(extent))
338: ||prheader(extent);
339: break;
340: case 'd':
341: if(*cp=='\n' || *cp==0){
342: abort = zero(extent)||delete(extent);
343: nopr = abort||mflg;
344: break;
345: }
346: del = 1;
347: goto compoundcmd;
348: case 's':
349: abort = atblank(cp)||zero(extent)||store(extent, cp, 1)
350: ||(del&&delete(extent));
351: nopr = abort||mflg||!del;
352: break;
353: case 'w':
354: abort = atblank(cp)||zero(extent)||notatnl(cp)
355: ||store(extent, cp, 0)
356: ||(del&&delete(extent));
357: nopr = abort||mflg||!del;
358: break;
359: case 'm':
360: abort = atblank(cp)||zero(extent)||notatnl(cp)
361: ||remail(extent, cp, 0)
362: ||(del&&delete(extent));
363: nopr = abort||mflg||!del;
364: break;
365: case 'M':
366: abort = atblank(cp)||zero(extent)||notatnl(cp)
367: ||remail(extent, cp, 1)
368: ||(del&&delete(extent));
369: nopr = abort||mflg||!del;
370: break;
371: case '\n':
372: abort = zero(extent)||print(extent);
373: break;
374: case 'p':
375: if(del){
376: nopr = abort = atnl(cp)||zero(extent)
377: ||(del&&delete(extent));
378: break;
379: }
380: abort = atnl(cp)||zero(extent)||print(extent);
381: break;
382: case 'r':
383: abort = zero(extent)||atnl(cp)||reply(extent, 0)
384: ||(del&&delete(extent));
385: nopr = abort||mflg||!del;
386: break;
387: case 'R':
388: abort = zero(extent)||atnl(cp)||reply(extent, 1)
389: ||(del&&delete(extent));
390: nopr = abort||mflg||!del;
391: break;
392: case 'q':
393: abort=atnl(cp)
394: ||(del&&(zero(extent)||delete(extent)));
395: if(abort)
396: break;
397: signal(SIGINT, fint); /* bacause of the setjmp */
398: return 1;
399: case '|':
400: abort = zero(extent)||notatnl(cp)
401: ||pipemail(extent, cp, 0)
402: ||(del&&delete(extent));
403: nopr = abort||mflg||!del;
404: break;
405: case '=':
406: abort = atnl(cp)||(del&&delete(extent))
407: ||whereis(extent);
408: change = 0;
409: break;
410: case '!':
411: abort=del&&(zero(extent)||delete(extent));
412: if(abort)
413: break;
414: escape(cp);
415: break;
416: case 'u':
417: abort = zero(extent)||atnl(cp)||undelete(extent);
418: break;
419: case 'x':
420: signal(SIGINT, fint); /* bacause of the setjmp */
421: return 0;
422: case '?':
423: abort = atnl(cp)
424: ||del&&(zero(extent)||delete(extent));
425: if(abort)
426: break;
427: help();
428: nopr = abort = 1;
429: break;
430: case 'i':
431: abort = atnl(cp)
432: ||(del&&(zero(extent)||delete(extent)));
433: if(abort)
434: break;
435: reread_mbox(mailfile, reverse);
436: nopr = abort = 1;
437: break;
438: default:
439: printf("!unknown command (type ? for help)\n");
440: nopr = abort = 1;
441: break;
442: }
443: if (!abort&&change&&extent!=NULL)
444: dot = extent;
445: }
446: }
447: }
448:
449: /* parse an address range */
450: message *
451: range(dot, cmd)
452: message *dot;
453: string *cmd;
454: {
455: message *first, *last;
456:
457: s_skipwhite(cmd);
458:
459: /* get first address in range */
460: switch(*cmd->ptr) {
461: case 'g':
462: cmd->ptr++;
463: return grange(cmd);
464: case ',':
465: first = mlist;
466: break;
467: case '0': case '1': case '2': case '3': case '4':
468: case '5': case '6': case '7': case '8': case '9':
469: first = addr((message *)NULL, cmd);
470: break;
471: case '?':
472: if (*(cmd->ptr+1)=='\n') {
473: if(dot!=NULL)
474: dot->extent = NULL;
475: return dot;
476: }
477: case '\\': case '/': case '+': case '-': case '$': case '.':
478: first = addr(dot, cmd);
479: break;
480: case '\n':
481: first = dot->next;
482: if (first==NULL)
483: fprintf(stderr, "!address\n");
484: break;
485: default:
486: if(dot!=NULL)
487: dot->extent = NULL;
488: return dot;
489: }
490: if (first == NULL)
491: return NULL;
492: while(*cmd->ptr == ' ' || *cmd->ptr == '\t')
493: cmd->ptr++;
494: if (*cmd->ptr != ',') {
495: first->extent = NULL;
496: return first;
497: }
498:
499: /* get second address in range */
500: cmd->ptr++;
501: while(*cmd->ptr == ' ' || *cmd->ptr == '\t')
502: cmd->ptr++;
503: switch(*cmd->ptr) {
504: case '\\': case '/': case '?': case '+': case '-': case '$':
505: last = addr(first, cmd);
506: break;
507: case '.':
508: last = addr(dot, cmd);
509: break;
510: case '0': case '1': case '2': case '3': case '4':
511: case '5': case '6': case '7': case '8': case '9':
512: last = addr((message *)NULL, cmd);
513: break;
514: default:
515: last = mlast;
516: break;
517: }
518: if (last==NULL)
519: return NULL;
520:
521: /* fill in the range */
522: for(dot=first; dot!=last && dot!=NULL; dot=dot->next)
523: dot->extent = dot->next;
524: if (dot==NULL) {
525: fprintf(stderr, "!addresses out of order\n");
526: return NULL;
527: }
528: last->extent = NULL;
529: return first;
530: }
531:
532: /* parse a global range */
533: message *
534: grange(cmd)
535: string *cmd;
536: {
537: char *re;
538: message *first, *last, *next;
539: regexp *pp;
540:
541: if (*cmd->ptr == '/') {
542: re = getre(cmd);
543: if (re == NULL)
544: return NULL;
545: if ((pp = regcomp(re))==NULL)
546: return NULL;
547: first = NULL;
548: for(next=mlist; next!=NULL; next=next->next)
549: if (regexec(pp, header(next), 0, 0)) {
550: if (first==NULL)
551: first = last = next;
552: else {
553: last->extent = next;
554: last = next;
555: }
556: last->extent = NULL;
557: }
558: if (first==NULL)
559: fprintf(stderr, "!match\n");
560: free((char *)pp);
561: return first;
562: } else if (*cmd->ptr == '\\') {
563: re = getre(cmd);
564: if (re == NULL)
565: return NULL;
566: if ((pp = regcomp(re))==NULL)
567: return NULL;
568: first = NULL;
569: for(next=mlist; next!=NULL; next=next->next){
570: s_to_c(next->body)[next->size-1]='\0';
571: if (regexec(pp, s_to_c(next->body), 0, 0)) {
572: if (first==NULL)
573: first = last = next;
574: else {
575: last->extent = next;
576: last = next;
577: }
578: last->extent = NULL;
579: }
580: }
581: if (first==NULL)
582: fprintf(stderr, "!match\n");
583: free((char *)pp);
584: return first;
585: } else {
586: /* fill in the range */
587: for(next=mlist; next!=NULL; next=next->next)
588: next->extent = next->next;
589: mlast->extent = NULL;
590: return mlist;
591: }
592: }
593:
594: /* parse an address */
595: message *
596: addr(base, cmd)
597: message *base; /* where to compute +/- from */
598: string *cmd;
599: {
600: int forward = -1;
601:
602: /* get direction */
603: switch(*cmd->ptr) {
604: case '+':
605: forward = 1;
606: cmd->ptr++;
607: break;
608: case '-':
609: forward = 0;
610: cmd->ptr++;
611: break;
612: }
613: while(*cmd->ptr == ' ' || *cmd->ptr == '\t')
614: cmd->ptr++;
615: switch(*cmd->ptr) {
616: case '0': case '1': case '2': case '3': case '4':
617: case '5': case '6': case '7': case '8': case '9':
618: base = incraddr(base, getnumb(cmd), forward);
619: if (base==NULL)
620: break;
621: return addr(base, cmd);
622: case '?':
623: forward = !forward;
624: case '/':
625: base = research(base, getre(cmd), forward);
626: if (base==NULL) {
627: fprintf(stderr, "!search\n");
628: return NULL;
629: }
630: return addr(base, cmd);
631: case '\\':
632: base = bresearch(base, getre(cmd), forward);
633: if (base==NULL) {
634: fprintf(stderr, "!search\n");
635: return NULL;
636: }
637: return addr(base, cmd);
638: case '.':
639: cmd->ptr++;
640: return addr(base, cmd);;
641: case '$':
642: cmd->ptr++;
643: return addr(mlast, cmd);
644: default:
645: /* default increment is 1 */
646: if (forward != -1) {
647: base = incraddr(base, 1, forward);
648: return addr(base, cmd);
649: }
650: break;
651: }
652: if (base==NULL)
653: fprintf(stderr, "!address\n");
654: return base;
655: }
656:
657: /* increment the base address by offset */
658: message *
659: incraddr(base, offset, forward)
660: message *base;
661: int offset;
662: int forward;
663: {
664: if (base==NULL) {
665: base = mzero;
666: }
667: for(; offset > 0 && base != NULL; offset--)
668: base = forward?(base->next):(base->prev);
669: return base;
670: }
671:
672: /* look for the message header after base that matches the reg exp */
673: message *
674: research(base, rp, forward)
675: message *base;
676: char *rp;
677: int forward;
678: {
679: regexp *pp;
680: message *mp;
681:
682: if (rp == NULL)
683: return NULL;
684: if ((pp = regcomp(rp))==NULL)
685: return NULL;
686: mp = base;
687: base = (base==mzero)?(forward?(mp->prev):(mp->next)):base;
688: do {
689: mp = forward?(mp->next):(mp->prev);
690: if (mp==NULL)
691: mp = forward?mlist:mlast;
692: if (regexec(pp, header(mp), 0, 0)) {
693: free((char *)pp);
694: return mp;
695: }
696: } while (mp!=base);
697: free((char *)pp);
698: return NULL;
699: }
700:
701: /* look for the message after base that matches the reg exp */
702: message *
703: bresearch(base, rp, forward)
704: message *base;
705: char *rp;
706: int forward;
707: {
708: regexp *pp;
709: message *mp;
710:
711: if (rp == NULL)
712: return NULL;
713: if ((pp = regcomp(rp))==NULL)
714: return NULL;
715: mp = base = (base==mzero)?mzero->next:base;
716: do {
717: mp = forward?(mp->next):(mp->prev);
718: if (mp==NULL)
719: mp = forward?mlist:mlast;
720: s_to_c(mp->body)[mp->size-1]='\0';
721: if (regexec(pp, s_to_c(mp->body), 0, 0)) {
722: free((char *)pp);
723: return mp;
724: }
725: } while (mp!=base);
726: free((char *)pp);
727: return NULL;
728: }
729:
730: /* get a number out of the command */
731: int
732: getnumb(cmd)
733: string *cmd;
734: {
735: int offset=0;
736: while (isdigit(*cmd->ptr))
737: offset = offset*10 + *cmd->ptr++ - '0';
738: return offset;
739: }
740:
741: /* get a regular exression out of the command */
742: char *
743: getre(cmd)
744: string *cmd;
745: {
746: static char re[80];
747: char *cp=re;
748: char term = *cmd->ptr++;
749:
750: while (*cmd->ptr!='\0' && *cmd->ptr!='\n' && *cmd->ptr!=term)
751: *cp++ = *cmd->ptr++;
752: if (*cmd->ptr == term)
753: cmd->ptr++;
754: if (cp == re) {
755: if (*re == '\0') {
756: fprintf(stderr, "!no previous regular expression\n");
757: return NULL;
758: }
759: } else
760: *cp = '\0';
761: return re;
762: }
763:
764: regerror(msg)
765: char *msg;
766: {
767: fprintf(stderr, "!illegal address: %s\n", msg);
768: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.