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