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