|
|
1.1 root 1: #include <ctype.h>
2: #include <stdio.h>
3: #include <pwd.h>
4: #include <utmp.h>
5: #include <signal.h>
6: #include <sys/types.h>
7: #include <sys/stat.h>
8: #include <setjmp.h>
9: #include <whoami.h>
10: #include <sysexits.h>
11:
12: static char SccsId[] = "@(#)mail.c 4.1 10/1/80";
13:
14: #define DELIVERMAIL "/etc/delivermail"
15:
16:
17: /*copylet flags */
18: /*remote mail, add rmtmsg */
19: #define REMOTE 1
20: /* zap header and trailing empty line */
21: #define ZAP 3
22: #define ORDINARY 2
23: #define FORWARD 4
24: #define LSIZE 256
25: #define MAXLET 300 /* maximum number of letters */
26: #define MAILMODE (~0644) /* mode of created mail */
27: # ifndef DELIVERMAIL
28: #define RMAIL "/usr/net/bin/sendberkmail"
29: #define LOCNAM1 "csvax"
30: #define LOCNAM2 "ucbvax"
31: #define LOCNAM3 "vax"
32: #define LOCNAM4 "v"
33: # endif
34:
35: char line[LSIZE];
36: char resp[LSIZE];
37: struct let {
38: long adr;
39: char change;
40: } let[MAXLET];
41: int nlet = 0;
42: char lfil[50];
43: long iop, time();
44: char *getenv();
45: char *index();
46: char lettmp[] = "/tmp/maXXXXX";
47: char maildir[] = "/usr/spool/mail/";
48: char mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
49: char dead[] = "dead.letter";
50: char *thissys = sysname;
51: char *netname = "vax";
52: char forwmsg[] = " forwarded\n";
53: FILE *tmpf;
54: FILE *malf;
55: char *my_name;
56: char *getlogin();
57: struct passwd *getpwuid();
58: int error;
59: int changed;
60: int forward;
61: char from[] = "From ";
62: long ftell();
63: int delete();
64: char *ctime();
65: int flgf;
66: int flgp;
67: int delflg = 1;
68: int hseqno;
69: jmp_buf sjbuf;
70: int rmail;
71:
72: main(argc, argv)
73: char **argv;
74: {
75: register i;
76: char sobuf[BUFSIZ];
77:
78: setbuf(stdout, sobuf);
79: mktemp(lettmp);
80: unlink(lettmp);
81: my_name = getlogin();
82: if (my_name == NULL || strlen(my_name) == 0) {
83: struct passwd *pwent;
84: pwent = getpwuid(getuid());
85: if (pwent==NULL)
86: my_name = "???";
87: else
88: my_name = pwent->pw_name;
89: }
90: if(setjmp(sjbuf)) done();
91: for (i=0; i<20; i++)
92: setsig(i, delete);
93: tmpf = fopen(lettmp, "w");
94: if (tmpf == NULL) {
95: fprintf(stderr, "mail: cannot open %s for writing\n", lettmp);
96: done();
97: }
98: if (argv[0][0] == 'r')
99: rmail++;
100: if (argv[0][0] != 'r' && /* no favors for rmail*/
101: (argc == 1 || argv[1][0] == '-' && !any(argv[1][1], "rhd")))
102: printmail(argc, argv);
103: else
104: sendmail(argc, argv);
105: done();
106: }
107:
108: setsig(i, f)
109: int i;
110: int (*f)();
111: {
112: if(signal(i, SIG_IGN)!=SIG_IGN)
113: signal(i, f);
114: }
115:
116: any(c, str)
117: register int c;
118: register char *str;
119: {
120:
121: while (*str)
122: if (c == *str++)
123: return(1);
124: return(0);
125: }
126:
127: printmail(argc, argv)
128: char **argv;
129: {
130: int flg, i, j, print;
131: char *p, *getarg();
132: struct stat statb;
133:
134: setuid(getuid());
135: cat(mailfile, maildir, my_name);
136: if (stat(mailfile, &statb) >= 0
137: && (statb.st_mode & S_IFMT) == S_IFDIR) {
138: strcat(mailfile, "/");
139: strcat(mailfile, my_name);
140: }
141: for (; argc>1; argv++, argc--) {
142: if (argv[1][0]=='-') {
143: if (argv[1][1]=='q')
144: delflg = 0;
145: else if (argv[1][1]=='p') {
146: flgp++;
147: delflg = 0;
148: } else if (argv[1][1]=='f') {
149: if (argc>=3) {
150: strcpy(mailfile, argv[2]);
151: argv++;
152: argc--;
153: }
154: } else if (argv[1][1]=='r') {
155: forward = 1;
156: } else if (argv[1][1]=='h') {
157: forward = 1;
158: } else {
159: fprintf(stderr, "mail: unknown option %c\n", argv[1][1]);
160: done();
161: }
162: } else
163: break;
164: }
165: malf = fopen(mailfile, "r");
166: if (malf == NULL) {
167: fprintf(stdout, "No mail.\n");
168: return;
169: }
170: lock(mailfile);
171: copymt(malf, tmpf);
172: fclose(malf);
173: fclose(tmpf);
174: unlock();
175: tmpf = fopen(lettmp, "r");
176:
177: changed = 0;
178: print = 1;
179: for (i = 0; i < nlet; ) {
180: j = forward ? i : nlet - i - 1;
181: if(setjmp(sjbuf)) {
182: print=0;
183: } else {
184: if (print)
185: copylet(j, stdout, ORDINARY);
186: print = 1;
187: }
188: if (flgp) {
189: i++;
190: continue;
191: }
192: setjmp(sjbuf);
193: fprintf(stdout, "? ");
194: fflush(stdout);
195: if (fgets(resp, LSIZE, stdin) == NULL)
196: break;
197: switch (resp[0]) {
198:
199: default:
200: fprintf(stderr, "usage\n");
201: case '?':
202: print = 0;
203: fprintf(stderr, "q\tquit\n");
204: fprintf(stderr, "x\texit without changing mail\n");
205: fprintf(stderr, "p\tprint\n");
206: fprintf(stderr, "s[file]\tsave (default mbox)\n");
207: fprintf(stderr, "w[file]\tsame without header\n");
208: fprintf(stderr, "-\tprint previous\n");
209: fprintf(stderr, "d\tdelete\n");
210: fprintf(stderr, "+\tnext (no delete)\n");
211: fprintf(stderr, "m user\tmail to user\n");
212: fprintf(stderr, "! cmd\texecute cmd\n");
213: break;
214:
215: case '+':
216: case 'n':
217: case '\n':
218: i++;
219: break;
220: case 'x':
221: changed = 0;
222: case 'q':
223: goto donep;
224: case 'p':
225: break;
226: case '^':
227: case '-':
228: if (--i < 0)
229: i = 0;
230: break;
231: case 'y':
232: case 'w':
233: case 's':
234: flg = 0;
235: if (resp[1] != '\n' && resp[1] != ' ') {
236: printf("illegal\n");
237: flg++;
238: print = 0;
239: continue;
240: }
241: if (resp[1] == '\n' || resp[1] == '\0') {
242: p = getenv("HOME");
243: if(p != 0)
244: cat(resp+1, p, "/mbox");
245: else
246: cat(resp+1, "", "mbox");
247: }
248: for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) {
249: malf = fopen(lfil, "a");
250: if (malf == NULL) {
251: fprintf(stdout, "mail: cannot append to %s\n", lfil);
252: flg++;
253: continue;
254: }
255: copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY);
256: fclose(malf);
257: }
258: if (flg)
259: print = 0;
260: else {
261: let[j].change = 'd';
262: changed++;
263: i++;
264: }
265: break;
266: case 'm':
267: flg = 0;
268: if (resp[1] == '\n' || resp[1] == '\0') {
269: i++;
270: continue;
271: }
272: if (resp[1] != ' ') {
273: printf("invalid command\n");
274: flg++;
275: print = 0;
276: continue;
277: }
278: for (p = resp+1; (p = getarg(lfil, p)) != NULL; )
279: if (!sendrmt(j, lfil, "/bin/mail")) /* couldn't send it */
280: flg++;
281: if (flg)
282: print = 0;
283: else {
284: let[j].change = 'd';
285: changed++;
286: i++;
287: }
288: break;
289: case '!':
290: system(resp+1);
291: printf("!\n");
292: print = 0;
293: break;
294: case 'd':
295: let[j].change = 'd';
296: changed++;
297: i++;
298: if (resp[1] == 'q')
299: goto donep;
300: break;
301: }
302: }
303: donep:
304: if (changed)
305: copyback();
306: }
307:
308: copyback() /* copy temp or whatever back to /usr/spool/mail */
309: {
310: register i, n, c;
311: int new = 0;
312: struct stat stbuf;
313:
314: signal(SIGINT, SIG_IGN);
315: signal(SIGHUP, SIG_IGN);
316: signal(SIGQUIT, SIG_IGN);
317: lock(mailfile);
318: stat(mailfile, &stbuf);
319: if (stbuf.st_size != let[nlet].adr) { /* new mail has arrived */
320: malf = fopen(mailfile, "r");
321: if (malf == NULL) {
322: fprintf(stdout, "mail: can't re-read %s\n", mailfile);
323: done();
324: }
325: fseek(malf, let[nlet].adr, 0);
326: fclose(tmpf);
327: tmpf = fopen(lettmp, "a");
328: fseek(tmpf, let[nlet].adr, 0);
329: while ((c = fgetc(malf)) != EOF)
330: fputc(c, tmpf);
331: fclose(malf);
332: fclose(tmpf);
333: tmpf = fopen(lettmp, "r");
334: let[++nlet].adr = stbuf.st_size;
335: new = 1;
336: }
337: malf = fopen(mailfile, "w");
338: if (malf == NULL) {
339: fprintf(stderr, "mail: can't rewrite %s\n", lfil);
340: done();
341: }
342: n = 0;
343: for (i = 0; i < nlet; i++)
344: if (let[i].change != 'd') {
345: copylet(i, malf, ORDINARY);
346: n++;
347: }
348: fclose(malf);
349: if (new)
350: fprintf(stdout, "new mail arrived\n");
351: unlock();
352: }
353:
354: copymt(f1, f2) /* copy mail (f1) to temp (f2) */
355: FILE *f1, *f2;
356: {
357: long nextadr;
358:
359: nlet = nextadr = 0;
360: let[0].adr = 0;
361: while (fgets(line, LSIZE, f1) != NULL) {
362: if (isfrom(line))
363: let[nlet++].adr = nextadr;
364: nextadr += strlen(line);
365: fputs(line, f2);
366: }
367: let[nlet].adr = nextadr; /* last plus 1 */
368: }
369:
370: copylet(n, f, type) FILE *f;
371: { int ch, k;
372: fseek(tmpf, let[n].adr, 0);
373: k = let[n+1].adr - let[n].adr;
374: while(k-- > 1 && (ch=fgetc(tmpf))!='\n')
375: if(type!=ZAP) fputc(ch,f);
376: if(type==REMOTE)
377: fprintf(f, " remote from %s\n", thissys);
378: else if (type==FORWARD)
379: fprintf(f, forwmsg);
380: else if(type==ORDINARY)
381: fputc(ch,f);
382: while(k-->1)
383: fputc(ch=fgetc(tmpf), f);
384: if(type!=ZAP || ch!= '\n')
385: fputc(fgetc(tmpf), f);
386: }
387:
388: isfrom(lp)
389: register char *lp;
390: {
391: register char *p;
392:
393: for (p = from; *p; )
394: if (*lp++ != *p++)
395: return(0);
396: return(1);
397: }
398:
399: sendmail(argc, argv)
400: char **argv;
401: {
402: char truename[100];
403: int first;
404: register char *cp;
405: int gaver = 0;
406: # ifdef DELIVERMAIL
407: char *newargv[1000];
408: register char **ap;
409: register char **vp;
410: int dflag;
411:
412: dflag = 0;
413: if (argc < 1)
414: fprintf(stderr, "puke\n");
415: for (vp = argv, ap = newargv + 1; (*ap = *vp++) != 0; ap++)
416: {
417: if (ap[0][0] == '-' && ap[0][1] == 'd')
418: dflag++;
419: }
420: if (!dflag)
421: {
422: /* give it to delivermail, rah rah! */
423: unlink(lettmp);
424: ap = newargv+1;
425: if (rmail)
426: *ap-- = "-s";
427: *ap = "-delivermail";
428: execv(DELIVERMAIL, ap);
429: perror(DELIVERMAIL);
430: exit(EX_UNAVAILABLE);
431: }
432: # endif DELIVERMAIL
433:
434: truename[0] = 0;
435: line[0] = '\0';
436:
437: /*
438: * When we fall out of this, argv[1] should be first name,
439: * argc should be number of names + 1.
440: */
441:
442: while (argc > 1 && *argv[1] == '-') {
443: cp = *++argv;
444: argc--;
445: switch (cp[1]) {
446: case 'r':
447: if (argc <= 0) {
448: usage();
449: done();
450: }
451: gaver++;
452: strcpy(truename, argv[1]);
453: fgets(line, LSIZE, stdin);
454: if (strcmpn("From", line, 4) == 0)
455: line[0] = '\0';
456: argv++;
457: argc--;
458: break;
459:
460: case 'h':
461: if (argc <= 0) {
462: usage();
463: done();
464: }
465: hseqno = atoi(argv[1]);
466: argv++;
467: argc--;
468: break;
469:
470: # ifdef DELIVERMAIL
471: case 'd':
472: break;
473: # endif DELIVERMAIL
474:
475: default:
476: usage();
477: done();
478: }
479: }
480: if (argc <= 1) {
481: usage();
482: done();
483: }
484: if (gaver == 0)
485: strcpy(truename, my_name);
486: /*
487: if (argc > 4 && strcmp(argv[1], "-r") == 0) {
488: strcpy(truename, argv[2]);
489: argc -= 2;
490: argv += 2;
491: fgets(line, LSIZE, stdin);
492: if (strcmpn("From", line, 4) == 0)
493: line[0] = '\0';
494: } else
495: strcpy(truename, my_name);
496: */
497: time(&iop);
498: fprintf(tmpf, "%s%s %s", from, truename, ctime(&iop));
499: iop = ftell(tmpf);
500: flgf = 1;
501: for (first = 1;; first = 0) {
502: if (first && line[0] == '\0' && fgets(line, LSIZE, stdin) == NULL)
503: break;
504: if (!first && fgets(line, LSIZE, stdin) == NULL)
505: break;
506: if (line[0] == '.' && line[1] == '\n' && isatty(fileno(stdin)))
507: break;
508: if (isfrom(line))
509: fputs(">", tmpf);
510: fputs(line, tmpf);
511: flgf = 0;
512: }
513: fputs("\n", tmpf);
514: nlet = 1;
515: let[0].adr = 0;
516: let[1].adr = ftell(tmpf);
517: fclose(tmpf);
518: if (flgf)
519: return;
520: tmpf = fopen(lettmp, "r");
521: if (tmpf == NULL) {
522: fprintf(stderr, "mail: cannot reopen %s for reading\n", lettmp);
523: return;
524: }
525: while (--argc > 0)
526: if (!send(0, *++argv, truename))
527: error++;
528: if (error) {
529: setuid(getuid());
530: malf = fopen(dead, "w");
531: if (malf == NULL) {
532: fprintf(stdout, "mail: cannot open %s\n", dead);
533: fclose(tmpf);
534: return;
535: }
536: copylet(0, malf, ZAP);
537: fclose(malf);
538: fprintf(stdout, "Mail saved in %s\n", dead);
539: }
540: fclose(tmpf);
541: }
542:
543: sendrmt(n, name, rcmd)
544: char *name;
545: char *rcmd;
546: {
547: FILE *rmf, *popen();
548: register char *p;
549: char rsys[64], cmd[64];
550: register local, pid;
551: int sts;
552:
553: local = 0;
554: if (index(name, '^')) {
555: while (p = index(name, '^'))
556: *p = '!';
557: if (strncmp(name, "researc", 7)) {
558: strcpy(rsys, "research");
559: if (*name != '!')
560: --name;
561: goto skip;
562: }
563: }
564: if (*name=='!')
565: name++;
566: for(p=rsys; *name!='!'; *p++ = *name++)
567: if (*name=='\0') {
568: local++;
569: break;
570: }
571: *p = '\0';
572: if ((!local && *name=='\0') || (local && *rsys=='\0')) {
573: fprintf(stdout, "null name\n");
574: return(0);
575: }
576: skip:
577: if ((pid = fork()) == -1) {
578: fprintf(stderr, "mail: can't create proc for remote\n");
579: return(0);
580: }
581: if (pid) {
582: while (wait(&sts) != pid) {
583: if (wait(&sts)==-1)
584: return(0);
585: }
586: return(!sts);
587: }
588: setuid(getuid());
589: if (local)
590: sprintf(cmd, "%s %s", rcmd, rsys);
591: else {
592: if (index(name+1, '!'))
593: sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1);
594: else
595: sprintf(cmd, "uux - %s!rmail %s", rsys, name+1);
596: }
597: if ((rmf=popen(cmd, "w")) == NULL)
598: exit(1);
599: copylet(n, rmf, local ? !strcmp(rcmd, "/bin/mail") ? FORWARD : ORDINARY : REMOTE);
600: pclose(rmf);
601: exit(0);
602: }
603:
604: # ifndef DELIVERMAIL
605: /*
606: * Send mail on the Berkeley network.
607: * Sorry Bill, sendrmt() is so awful we just gave up.
608: */
609:
610: sendberkmail(n, name, fromaddr)
611: char name[];
612: char fromaddr[];
613: {
614: char cmd[200];
615: register FILE *cmdf;
616:
617: sprintf(cmd, "%s -h %d -f %s -t %s", RMAIL, hseqno, fromaddr, name);
618: if ((cmdf = popen(cmd, "w")) == NULL) {
619: perror(RMAIL);
620: return(0);
621: }
622: copylet(n, cmdf, ORDINARY);
623: pclose(cmdf);
624: return(9);
625: }
626: # endif
627:
628: usage()
629: {
630:
631: fprintf(stderr, "Usage: mail [ -f ] people . . .\n");
632: }
633:
634: send(n, name, fromaddr)
635: int n;
636: char *name;
637: char *fromaddr;
638: {
639: char file[100];
640: register char *p;
641: register mask;
642: struct passwd *pw, *getpwnam();
643: struct stat statb;
644:
645: # ifndef DELIVERMAIL
646: stripfx(LOCNAM1, &name);
647: stripfx(LOCNAM2, &name);
648: stripfx(LOCNAM3, &name);
649: stripfx(LOCNAM4, &name);
650: if(*name == ':')name++; /* skip colon in to-name */
651: for(p=name; *p!=':' && *p!='!' && *p!='^' &&*p!='\0'; p++);
652: /* if(*p == ':') return(sendrmt(n, name, RMAIL)); */
653: if (*p == ':')
654: return(sendberkmail(n, name, fromaddr));
655: else if (*p=='\0' && strcmp(name, "msgs") == 0)
656: return(sendrmt(n, "-s", "/usr/ucb/msgs"));
657: # endif
658: for(p=name; *p!='!'&&*p!='^' &&*p!='\0'; p++)
659: ;
660: if (*p == '!'|| *p=='^')
661: return(sendrmt(n, name, 0));
662: if ((pw = getpwnam(name)) == NULL) {
663: fprintf(stdout, "mail: can't send to %s\n", name);
664: return(0);
665: }
666: cat(file, maildir, name);
667: if (stat(file, &statb) >= 0 && (statb.st_mode & S_IFMT) == S_IFDIR) {
668: strcat(file, "/");
669: strcat(file, name);
670: }
671: mask = umask(MAILMODE);
672: malf = fopen(file, "a");
673: umask(mask);
674: if (malf == NULL) {
675: fprintf(stdout, "mail: cannot append to %s\n", file);
676: return(0);
677: }
678: lock(file);
679: chown(file, pw->pw_uid, pw->pw_gid);
680: copylet(n, malf, ORDINARY);
681: fclose(malf);
682: unlock();
683: return(1);
684: }
685:
686: delete(i)
687: {
688: setsig(i, delete);
689: fprintf(stderr, "\n");
690: if(delflg)
691: longjmp(sjbuf, 1);
692: done();
693: }
694:
695: /*
696: * Lock the specified mail file by setting the file mailfile.lock.
697: * We must, of course, be careful to unlink the lock file by a call
698: * to unlock before we stop. The algorithm used here is to see if
699: * the lock exists, and if it does, to check its modify time. If it
700: * is older than 30 seconds, we assume error and set our own file.
701: * Otherwise, we wait for 5 seconds and try again.
702: */
703:
704: char *maillock = ".lock"; /* Lock suffix for mailname */
705: char *lockname = "/usr/spool/mail/tmXXXXXX";
706: char locktmp[30]; /* Usable lock temporary */
707: char curlock[50]; /* Last used name of lock */
708: int locked; /* To note that we locked it */
709:
710: lock(file)
711: char *file;
712: {
713: register int f;
714: struct stat sbuf;
715: long curtime;
716: int statfailed;
717:
718: if (locked || flgf)
719: return(0);
720: strcpy(curlock, file);
721: strcat(curlock, maillock);
722: strcpy(locktmp, lockname);
723: mktemp(locktmp);
724: unlink(locktmp);
725: statfailed = 0;
726: for (;;) {
727: f = lock1(locktmp, curlock);
728: if (f == 0) {
729: locked = 1;
730: return(0);
731: }
732: if (stat(curlock, &sbuf) < 0) {
733: if (statfailed++ > 5)
734: return(-1);
735: sleep(5);
736: continue;
737: }
738: statfailed = 0;
739: time(&curtime);
740: if (curtime < sbuf.st_ctime + 30) {
741: sleep(5);
742: continue;
743: }
744: unlink(curlock);
745: }
746: }
747:
748: /*
749: * Remove the mail lock, and note that we no longer
750: * have it locked.
751: */
752:
753: unlock()
754: {
755:
756: unlink(curlock);
757: locked = 0;
758: }
759:
760: /*
761: * Attempt to set the lock by creating the temporary file,
762: * then doing a link/unlink. If it fails, return -1 else 0
763: */
764:
765: lock1(tempfile, name)
766: char tempfile[], name[];
767: {
768: register int fd;
769:
770: fd = creat(tempfile, 0);
771: if (fd < 0)
772: return(-1);
773: close(fd);
774: if (link(tempfile, name) < 0) {
775: unlink(tempfile);
776: return(-1);
777: }
778: unlink(tempfile);
779: return(0);
780: }
781:
782: done()
783: {
784: if(locked)
785: unlock();
786: unlink(lettmp);
787: unlink(locktmp);
788: exit(error);
789: }
790:
791: cat(to, from1, from2)
792: char *to, *from1, *from2;
793: {
794: int i, j;
795:
796: j = 0;
797: for (i=0; from1[i]; i++)
798: to[j++] = from1[i];
799: for (i=0; from2[i]; i++)
800: to[j++] = from2[i];
801: to[j] = 0;
802: }
803:
804: char *getarg(s, p) /* copy p... into s, update p */
805: register char *s, *p;
806: {
807: while (*p == ' ' || *p == '\t')
808: p++;
809: if (*p == '\n' || *p == '\0')
810: return(NULL);
811: while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
812: *s++ = *p++;
813: *s = '\0';
814: return(p);
815: }
816: # ifndef DELIVERMAIL
817: /*
818: stripfx(prefix string, pointer to string)
819:
820: takes a ptr to string and compares it to prefix string.
821: may be called multiple times
822: */
823: stripfx(pfx, name)
824: char *pfx;
825: char **name;
826: {
827: register char *cp = *name;
828:
829: while (*pfx && (*cp == *pfx || *cp == toupper(*pfx)))
830: cp++, pfx++;
831: if (*cp != ':' || *pfx != 0)
832: return;
833: *name = cp;
834: }
835: # endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.