|
|
1.1 root 1: #include <stdio.h>
2: #include <pwd.h>
3: #include <utmp.h>
4: #include <signal.h>
5: #include <sys/types.h>
6: #include <sys/stat.h>
7: #include <time.h>
8: #include <sys/timeb.h>
9: #include <setjmp.h>
10: #include <ctype.h>
11: #include <dir.h>
12:
13:
14: #define SMTP "/usr/lib/uucp/smtp"
15:
16: /*copylet flags */
17: /*remote mail, add rmtmsg */
18: #define REMOTE 1
19: #define INTERNET 4
20: /* zap header and trailing empty line */
21: #define ZAP 3
22: #define ORDINARY 2
23: #define SENDING 5
24: #define LSIZE 256
25: #define MAXLET 1000 /* maximum number of letters */
26: #define MAILMODE (~0644) /* mode of created mail */
27: #define FLIST "/etc/forwardlist"
28: #define TMPNAME "/tmp/maXXXXX"
29:
30: /* definitions for inet gateways */
31: struct igateway {
32: char *id; /* network identifier */
33: char *addr; /* address translation */
34: char *via; /* machine that talks to gateway */
35: char *cmd; /* command for gateway */
36: };
37: struct igateway igates[] = {
38: "arpa_or_csnet", ".csnet-relay", "research", "/usr/mmdf/lib/mail",
39: "csnet", ".csnet.csnet-relay", "research", "/usr/mmdf/lib/mail",
40: "arpa", ".arpa.csnet-relay", "research", "/usr/mmdf/lib/mail",
41: "acsnet", "", "research", "/usr/ACSnet/bin/inject",
42: };
43: #define NIGATES 4
44: unsigned int igate; /* offset into igates (csnet by default) */
45:
46:
47: char line[LSIZE];
48: char resp[LSIZE];
49: struct let {
50: long adr;
51: char change;
52: } let[MAXLET];
53: int nlet = 0;
54: char lfil[50];
55: char *stringin();
56: FILE *popen();
57: char *getenv();
58: char tmpname[] = TMPNAME;
59: char lettmp[sizeof(TMPNAME)];
60: char maildir[] = "/usr/spool/mail/";
61: char mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxx";
62: char dead[] = "dead.letter";
63: char whoami[] = "/etc/whoami";
64: #define FRWRD "Forward to "
65: char *thissys = "";
66: FILE *tmpf;
67: FILE *malf;
68: char *my_name;
69: char real_name[512];
70: char *getlogin();
71: struct passwd *getpwuid();
72: char *strchr();
73: int error;
74: int changed;
75: int forward;
76: int onatty;
77: char from[] = "From ";
78: long ftell();
79: int delete();
80: int savdead();
81: int (*saveint)();
82: int (*setsig())();
83: char *strcpy();
84: char *strcat();
85: char *mktemp();
86: char *ctime();
87: long time();
88: int flgf;
89: int flgp;
90: int delflg = 1;
91: int rflg;
92: int frominet;
93: int normtf;
94: jmp_buf sjbuf;
95: char dev[] = "/dev/";
96:
97: void lock(), unlock();
98:
99: main(argc, argv)
100: char **argv;
101: {
102: static char sobuf[BUFSIZ];
103: char wsysname[32];
104: int f;
105: char *prog;
106: char *basename();
107:
108: if (argc == 2 && (argv[1][0] == '-' && argv[1][1]=='n')) {
109: struct stat s;
110: char *ttyname();
111: char *p;
112:
113: fstat(2,&s);
114: setgid(getgid());
115: setuid(getuid());
116: if ((p = ttyname(2)) && *p)
117: chmod(p, s.st_mode ^ S_IEXEC);
118: exit(0);
119: }
120: prog = basename(argv[0]);
121: normtf = prog[0]=='r';
122: frominet = prog[0]=='c';
123: rflg = prog[0]=='r' || frominet;
124: setbuf(stdout, sobuf);
125: strcpy(lettmp, tmpname);
126: mktemp(lettmp);
127: unlink(lettmp);
128: my_name = getlogin();
129: if (my_name==NULL)
130: my_name = "daemon";
131: f = open(whoami, 0);
132: if (f>=0) {
133: wsysname[0] = '\0';
134: read(f, wsysname, 32);
135: if (strchr(wsysname, '\n')) {
136: *strchr(wsysname, '\n') = '\0';
137: thissys = wsysname;
138: }
139: close(f);
140: }
141: if(*thissys == 0)
142: fprintf(stderr, "mail: bad data from %s\n", whoami);
143: if(setjmp(sjbuf))
144: done();
145: setsig(SIGINT, delete);
146: setsig(SIGHUP, delete);
147: setsig(SIGKILL, delete);
148: tmpf = fopen(lettmp, "w");
149: if (tmpf == NULL) {
150: fprintf(stderr, "mail: cannot open %s for writing\n", lettmp);
151: done();
152: }
153: chmod(lettmp, 0600);
154: chown(lettmp, getuid(), getgid());
155: if( !rflg && /* no favors for rmail*/
156: (argc == 1 || (argv[1][0] == '-' && argv[1][1]!='R')))
157: printmail(argc, argv);
158: else
159: sendmail(argc, argv);
160: done();
161: }
162:
163: char *
164: basename(file)
165: char *file;
166: {
167: char *base;
168: char *strrchr();
169:
170: if ((base = strrchr(file, '/')) != NULL)
171: base++; /* past '/' */
172: else
173: base = file;
174: return (base);
175: }
176:
177: int (*setsig(i, f))()
178: int i;
179: int (*f)();
180: {
181: register int (*rc)();
182:
183: if ((rc = signal(i, SIG_IGN))!=SIG_IGN)
184: signal(i, f);
185: return(rc);
186: }
187:
188: sig_ign()
189: {
190: signal(SIGHUP, SIG_IGN);
191: signal(SIGINT, SIG_IGN);
192: signal(SIGQUIT, SIG_IGN);
193: signal(SIGTERM, SIG_IGN);
194: }
195:
196: printmail(argc, argv)
197: char **argv;
198: {
199: int flg, i, j, print;
200: struct stat stbuf;
201: char *p, *getarg();
202: char fbuf[256];
203: FILE *pipf;
204:
205: setgid(getgid());
206: setuid(getuid());
207: cat(mailfile, maildir, my_name);
208: for (; argc>1; argv++, argc--) {
209: if (argv[1][0]=='-') {
210: if (argv[1][1]=='p') {
211: flgp++;
212: delflg = 0;
213: } else if (argv[1][1]=='f') {
214: if (argc>=3) {
215: strcpy(mailfile, argv[2]);
216: argv++;
217: argc--;
218: }
219: } else if (argv[1][1]=='r') {
220: forward = 1;
221: } else {
222: fprintf(stderr, "mail: unknown option %c\n", argv[1][1]);
223: done();
224: }
225: } else
226: break;
227: }
228: if (stat(mailfile, &stbuf) < 0 || stbuf.st_size == 0L) {
229: printf("No mail.\n");
230: return;
231: }
232: malf = fopen(mailfile, "r");
233: if (malf == NULL) {
234: fprintf(stderr, "mail: cannot read %s.\n", mailfile);
235: return;
236: }
237: lock(mailfile);
238: if(areforwarding(mailfile, fbuf)) {
239: printf("Your mail is being forwarded to ");
240: fseek(malf, (long)(sizeof(FRWRD) - 1), 0);
241: fgets(fbuf, sizeof(fbuf), malf);
242: printf("%s", fbuf);
243: if(getc(malf) != EOF)
244: printf("and your mailbox contains extra stuff\n");
245: unlock();
246: return;
247: }
248: copymt(malf, tmpf);
249: fclose(malf);
250: fclose(tmpf);
251: unlock();
252: tmpf = fopen(lettmp, "r");
253:
254: changed = 0;
255: print = 1;
256: for (i = 0; i < nlet; ) {
257: j = forward ? i : nlet - i - 1;
258: if(setjmp(sjbuf) == 0) {
259: if (print)
260: copylet(j, stdout, ORDINARY, (char *)NULL);
261: print = 1;
262: }
263: if (flgp) {
264: i++;
265: continue;
266: }
267: setjmp(sjbuf);
268: printf("? ");
269: fflush(stdout);
270: if (fgets(resp, LSIZE, stdin) == NULL)
271: break;
272: switch (resp[0]) {
273:
274: default:
275: printf("usage\n");
276: case '?':
277: print = 0;
278: printf("q\tquit\n");
279: printf("x\texit without changing mail\n");
280: printf("p\tprint\n");
281: printf("s[file]\tsave (default mbox)\n");
282: printf("-\tprint previous\n");
283: printf("d\tdelete\n");
284: printf("+\tnext (no delete)\n");
285: printf("m user\tmail to user\n");
286: printf("! cmd\texecute cmd\n");
287: break;
288:
289: case '+':
290: case 'n':
291: case '\n':
292: i++;
293: break;
294: case 'x':
295: changed = 0;
296: case 'q':
297: goto donep;
298: case 'p':
299: break;
300: case '^':
301: case '-':
302: if (--i < 0)
303: i = 0;
304: break;
305: case 'y':
306: case 'w':
307: case 's':
308: flg = 0;
309: if (resp[1] != '\n' && resp[1] != ' ') {
310: printf("invalid\n");
311: flg++;
312: print = 0;
313: continue;
314: }
315: if (resp[1] == '\n' || resp[1] == '\0') {
316: p = getenv("HOME");
317: if(p != 0)
318: cat(resp+1, p, "/mbox");
319: else
320: cat(resp+1, "", "mbox");
321: }
322: for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) {
323: malf = fopen(lfil, "a");
324: if (malf == NULL) {
325: fprintf(stderr, "mail: cannot append to %s\n", lfil);
326: flg++;
327: continue;
328: }
329: copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY,
330: (char *)NULL);
331: fclose(malf);
332: }
333: if (flg)
334: print = 0;
335: else {
336: let[j].change = 'd';
337: changed++;
338: i++;
339: }
340: break;
341: case 'm':
342: flg = 0;
343: if (resp[1] == '\n' || resp[1] == '\0') {
344: i++;
345: continue;
346: }
347: if (resp[1] != ' ') {
348: printf("invalid\n");
349: flg++;
350: print = 0;
351: continue;
352: }
353: strcpy(fbuf, "mail ");
354: strcat(fbuf, resp+1);
355: /* fork so that mail becomes super-user again */
356: pipf = popen(fbuf, "w");
357: if(pipf == NULL) {
358: fprintf(stderr, "mail: can't fork to remail\n");
359: flg++;
360: continue;
361: }
362: copylet(j, pipf, SENDING, (char *)NULL);
363: flg |= pclose(pipf);
364: if (flg)
365: print = 0;
366: else {
367: let[j].change = 'd';
368: changed++;
369: i++;
370: }
371: break;
372: case '!':
373: system(resp+1);
374: printf("!\n");
375: print = 0;
376: break;
377: case 'd':
378: let[j].change = 'd';
379: changed++;
380: i++;
381: if (resp[1] == 'q')
382: goto donep;
383: break;
384: }
385: }
386: donep:
387: if (changed)
388: copyback();
389: }
390:
391: copyback() /* copy temp or whatever back to /usr/spool/mail */
392: {
393: register i, c;
394: register int new = 0;
395: struct stat stbuf;
396:
397: sig_ign();
398: lock(mailfile);
399: stat(mailfile, &stbuf);
400: if (stbuf.st_size != let[nlet].adr) { /* new mail has arrived */
401: malf = fopen(mailfile, "r");
402: if (malf == NULL) {
403: fprintf(stderr, "mail: can't re-read %s\n", mailfile);
404: done();
405: }
406: fseek(malf, let[nlet].adr, 0);
407: fclose(tmpf);
408: tmpf = fopen(lettmp, "a");
409: fseek(tmpf, let[nlet].adr, 0);
410: while ((c = fgetc(malf)) != EOF)
411: fputc(c, tmpf);
412: fclose(malf);
413: fclose(tmpf);
414: tmpf = fopen(lettmp, "r");
415: let[++nlet].adr = stbuf.st_size;
416: new = 1;
417: }
418: malf = fopen(mailfile, "w");
419: if (malf == NULL) {
420: fprintf(stderr, "mail: can't rewrite %s\n", mailfile);
421: done();
422: }
423: for (i = 0; i < nlet; i++)
424: if (let[i].change != 'd') {
425: copylet(i, malf, ORDINARY, (char *)NULL);
426: }
427: fclose(malf);
428: if (new)
429: printf("new mail arrived\n");
430: unlock();
431: }
432:
433: copymt(f1, f2) /* copy mail (f1) to temp (f2) */
434: FILE *f1, *f2;
435: {
436: long nextadr;
437:
438: nlet = nextadr = 0;
439: let[0].adr = 0;
440: while (fgets(line, LSIZE, f1) != NULL) {
441: if (isfrom(line)) {
442: let[nlet++].adr = nextadr;
443: if (nlet > MAXLET) {
444: fprintf (stderr, "mail: too many letters\n");
445: unlock();
446: exit(1);
447: }
448: }
449: nextadr += strlen(line);
450: fputs(line, f2);
451: }
452: let[nlet].adr = nextadr; /* last plus 1 */
453: }
454:
455: copylet(n, f, type, postmark)
456: FILE *f;
457: char *postmark;
458: {
459: long k;
460: register ch;
461: char *inetheader();
462:
463: fseek(tmpf, let[n].adr, 0);
464: k = let[n+1].adr - let[n].adr;
465: if (postmark && type != ZAP) {
466: if (type == INTERNET)
467: postmark = inetheader (postmark);
468: fputs(postmark, f);
469: if (type==REMOTE)
470: fprintf(f, " remote from %s", thissys);
471: fputc('\n', f);
472: }
473: while (k>0) {
474: ch = fgetc(tmpf);
475: if (ch == EOF)
476: break;
477: fputc(ch, f);
478: k--;
479: }
480: }
481:
482: areforwarding(s, sendto)
483: char *s, *sendto;
484: {
485: FILE *fd;
486: char fbuf[64], *p, *sp;
487:
488: fd = fopen(s, "r");
489: if(fd == NULL)
490: return(0);
491: fbuf[0] = '\0';
492: fgets(fbuf, sizeof(fbuf), fd);
493: if (p = stringin(FRWRD, fbuf)) {
494: while (*p == ' ')
495: p++;
496: sp = sendto;
497: while (*p && *p!='\n')
498: *sp++ = *p++;
499: *sp = '\0';
500: fclose(fd);
501: return(*sendto != 0);
502: }
503: fclose(fd);
504: return(0);
505: }
506:
507: isfrom(lp)
508: register char *lp;
509: {
510: return(strncmp(lp, from, 5)==0);
511: }
512:
513: sendmail(argc, argv)
514: char **argv;
515: {
516: char *asctime();
517: struct timeb timbuf;
518: struct tm *bp, *localtime();
519: char *tp, *zp, postmark[512];
520: char *timezone();
521: int rrrflg=0;
522: long newpost();
523:
524: while (argv[1][0]=='-') {
525: switch(argv[1][1]) {
526: case 'R': /* return receipt */
527: rrrflg = 1;
528: }
529: argc--; argv++;
530: }
531: ftime(&timbuf);
532: bp = localtime(&timbuf.time);
533: tp = asctime(bp);
534: zp = timezone(timbuf.timezone, bp->tm_isdst);
535: onatty = isatty(0);
536: sprintf(postmark, "%s%s %.16s %.3s %.4s%s",from, my_name, tp, zp, tp+20,
537: rrrflg?" (RRR)":"");
538: flgf = 1;
539: saveint = setsig(SIGINT, savdead);
540: while (fgets(line, LSIZE, stdin) != NULL) {
541: if (line[0] == '.' && line[1] == '\n' && onatty)
542: break;
543: if (isfrom(line))
544: fputs(">", tmpf);
545: fputs(line, tmpf);
546: flgf = 0;
547: }
548: setsig(SIGINT, saveint);
549: if (line[0]!='\n' && error==0)
550: fputs("\n", tmpf);
551: nlet = 1;
552: let[0].adr = 0;
553: let[1].adr = ftell(tmpf);
554: fclose(tmpf);
555: if (flgf)
556: return;
557: tmpf = fopen(lettmp, "r");
558: if (tmpf == NULL) {
559: fprintf(stderr, "mail: cannot reopen %s for reading\n", lettmp);
560: return;
561: }
562: let[0].adr = newpost(postmark);
563: if (error == 0)
564: while (--argc > 0) {
565: if (!send(0, *++argv, 0, postmark))
566: error++;
567: }
568: if (error && onatty) {
569: setgid(getgid());
570: setuid(getuid());
571: malf = fopen(dead, "w");
572: if (malf == NULL) {
573: fprintf(stderr, "mail: cannot open %s\n", dead);
574: fclose(tmpf);
575: return;
576: }
577: copylet(0, malf, ZAP, (char *)NULL);
578: fclose(malf);
579: printf("Mail saved in %s\n", dead);
580: }
581: fclose(tmpf);
582: }
583:
584: long
585: newpost(pm)
586: char *pm;
587: {
588: long inetpost(), unixpost();
589: if (frominet)
590: return inetpost(pm);
591: else
592: return unixpost(pm);
593: }
594:
595: long
596: inetpost(pm)
597: char *pm;
598: {
599: char line[512], date[64], *lp;
600:
601: /* get default source and date */
602: lp = strchr(pm+5, ' ');
603: strcpy(date, lp);
604:
605: /* RFC 822 (or similar) */
606: /* construct the "From " line from the "From: " line */
607: while (fgets(line, sizeof(line), tmpf) != NULL) {
608: line[strlen(line)-1] = '\0';
609:
610: /* pick up from field */
611: if (strncmp("From: ", line, 6) == 0) {
612: lp = strchr(line+6, ' ');
613: if (lp)
614: *lp = '\0';
615: sprintf(pm, "From %s", line+6);
616: }
617:
618: /* pick up date field */
619: if (strncmp("Date: ", line, 6) == 0)
620: strcpy(date, line+5);
621:
622: /* stop if we're out of header */
623: if (strchr(line, ':') == NULL && line[0] != ' '
624: && line[0] != '\t')
625: break;
626: }
627: strcpy(real_name, pm+5);
628: strcat(pm, date);
629: return(0);
630: }
631:
632: long
633: unixpost(pm)
634: char *pm;
635: {
636: long n = 0;
637: char line[512], *cp, *lp;
638: char rmtlist[512];
639:
640: /* UNIX mail */
641: /* construct the "From " line from the existing ones */
642: rmtlist[0] = '\0';
643: while (fgets(line, sizeof(line), tmpf) != NULL) {
644:
645: /* stop if we run out of header */
646: if (stringin("From ", line)==NULL
647: && stringin(">From ", line)==NULL)
648: break;
649: if ((cp = stringin(" remote from ", line))==NULL)
650: break;
651:
652: /* get name of remote system and add to rmtlist */
653: line[strlen(line)-1] = '\0';
654: if (okrmt(cp) && n==0)
655: normtf = 0;
656: *(cp - sizeof(" remote from ") + 1) = '\0';
657: strcpy(pm, line[0] == '>' ? line + 1 : line);
658: strcat(rmtlist, cp);
659: strcat(rmtlist, "!");
660: n = ftell(tmpf);
661: }
662:
663: /* tack sender's name and date onto the list of remote machines */
664: strcpy(line, pm);
665: sprintf(pm, "From %s%s", rmtlist, line+5);
666: if ((cp = strchr(line+5, ' ')) != NULL)
667: *cp = '\0';
668: sprintf(real_name, "%s%s", rmtlist, line+5);
669: return(n);
670: }
671:
672: char *
673: stringin(str, line)
674: char *str, *line;
675: {
676: register char *sp, *lp;
677:
678: while (*line) {
679: sp = str;
680: lp = line++;
681: for (;;) {
682: if (*sp != *lp) {
683: if (*sp=='\0')
684: return(lp);
685: break;
686: }
687: sp++;
688: lp++;
689: }
690: }
691: return(NULL);
692: }
693:
694: /*
695: * Return nonzero if forwarding is allowed to the system
696: * named in the string at "cp". If we can't read the file
697: * which contains the systems, assume blanket forwarding.
698: */
699: okrmt(cp)
700: char *cp;
701: {
702: register FILE *fp;
703: char buf[20];
704:
705: /* try to open the file; allow forwarding on failure */
706: fp = fopen (FLIST, "r");
707: if (fp == NULL)
708: return 1;
709:
710: /* one iteration per system name in the file */
711: while (fgets (buf, sizeof buf, fp) != NULL) {
712: buf[strlen(buf)-1] = '\0';
713: if (strcmp (buf, cp) == 0) {
714: /* found it, allow forwarding */
715: fclose (fp);
716: return 1;
717: }
718: }
719:
720: /* didn't find it, prohibit forwarding */
721: fclose (fp);
722: return 0;
723: }
724:
725: savdead()
726: {
727: setsig(SIGINT, saveint);
728: error++;
729: }
730:
731: sendrmt(n, name, postmark)
732: char *name, *postmark;
733: {
734: FILE *rmf;
735: register char *p, *q, *rmtid;
736: char cmd[512], buf[512];
737: static forked;
738:
739: strcpy(buf, name);
740: rmtid = strchr(name, '!');
741: if (rmtid == NULL || rmtid[1]=='\0') {
742: fprintf(stderr, "mail: bad remote name\n");
743: return(0);
744: }
745: *rmtid++ = '\0';
746: if (normtf)
747: for (p = q = &buf[0]; (p = strchr(q, '!')) && p[1] != '\0';
748: q = p + 1) {
749: *p = '\0';
750: if (!okrmt(q)) {
751: *--rmtid = '!';
752: refuse(n, name, postmark,
753: "forwarding to this system disallowed");
754: return(1);
755: }
756: }
757: if(onatty & !forked) { /* fork off remote send to avoid user tedium */
758: int p = fork();
759: if(p == 0) {
760: sig_ign();
761: forked = 1;
762: } else if(p != -1)
763: exit(0);
764: }
765: if(access(SMTP, 0) != -1){
766: sprintf(cmd, "exec %s %s %s", SMTP, name, rmtid);
767: if((rmf = popen(cmd, "w")) != NULL){
768: copylet(n, rmf, REMOTE, postmark);
769: if(pclose(rmf) == 0) return(1);
770: }
771: }
772: sprintf(cmd, "exec /usr/bin/uux - -a %s %s!rmail \\(%s\\)",
773: real_name, name, rmtid);
774: if ((rmf=popen(cmd, "w")) == NULL) {
775: fprintf(stderr, "mail: can't pipe to uux\n");
776: exit(1);
777: }
778: copylet(n, rmf, REMOTE, postmark);
779: *--rmtid = '!';
780: logsend(name, postmark, "remote");
781: return(pclose(rmf)==0);
782: }
783:
784:
785:
786: send(n, name, level, postmark) /* send letter n to name */
787: int n;
788: char *name, *postmark;
789: {
790: char file[512];
791: register mask;
792: struct passwd *pw, *getpwnam();
793: struct stat stbuf;
794: char sendto[256];
795: char inetaddr[256];
796: int exists;
797:
798:
799: if(level > 20) {
800: fprintf(stderr, "mail: unbounded forwarding\n");
801: return(0);
802: }
803: if (strcmp(name, "-") == 0)
804: return(1);
805: if (strchr(name, '!'))
806: return(sendrmt(n, name, postmark));
807: if (strchr(name, '/')) {
808: fprintf(stderr, "mail: illegal name %s\n", name);
809: return(0);
810: }
811: cat(file, maildir, name);
812: if(areforwarding(file, sendto)) {
813: int rf, sval;
814: rf = normtf;
815: normtf = 0; /* to permit transshipping */
816: sval = send(n, sendto, level+1, postmark);
817: normtf = rf;
818: return(sval);
819: }
820: exists = stat(file, &stbuf);
821: if ((pw = getpwnam(name)) == NULL) {
822: if (exists < 0) {
823: (void)strcpy (inetaddr, name);
824: if (isinet(inetaddr)) {
825: if (strcmp (thissys, igates[igate].via) == 0) {
826: (void)inetgateaddr(inetaddr);
827: return(sendinet(n,inetaddr,postmark));
828: } else {
829: (void)strcpy (sendto, igates[igate].via);
830: (void)strcat (sendto, "!");
831: (void)strcat (sendto, name);
832: return(sendrmt(n, sendto, postmark));
833: }
834: }
835: if (rflg) {
836: refuse(n, name, postmark,
837: "addressee unknown");
838: return(1);
839: }
840: fprintf(stderr, "mail: can't send to %s\n", name);
841: return(0);
842: }
843: } else {
844: stbuf.st_uid = pw->pw_uid;
845: stbuf.st_gid = pw->pw_gid;
846: }
847: mask = umask(MAILMODE);
848: lock(file);
849: malf = fopen(file, "a");
850: umask(mask);
851: if (malf == NULL) {
852: fprintf(stderr, "mail: cannot append to %s\n", file);
853: return(0);
854: }
855: if (exists < 0)
856: chown(file, stbuf.st_uid, stbuf.st_gid);
857: copylet(n, malf, SENDING, postmark);
858: fclose(malf);
859: unlock();
860: logsend(name, postmark, "delivered");
861: notify(name); /* let him know it right away! */
862: return(1);
863: }
864:
865: notify(name)
866: char *name;
867: {
868: struct utmp entry;
869: FILE *f;
870:
871: if ((f = fopen("/etc/utmp", "r")) == NULL)
872: return;
873: while (fread((char *)&entry, sizeof(entry), 1, f) == 1) {
874: if (strncmp(name, entry.ut_name, sizeof(entry.ut_name)) == 0)
875: blurb(entry.ut_line);
876: }
877: fclose(f);
878: }
879:
880: blurb(tty)
881: char *tty;
882: {
883: FILE *f = NULL;
884: struct stat s;
885: int blurbtime();
886: char devtty[32];
887:
888: cat(devtty, dev, tty);
889: signal(SIGALRM, blurbtime);
890: alarm(30);
891: stat(devtty, &s);
892: if (s.st_mode & S_IEXEC) /* notify only if enabled */
893: if ((f = fopen(devtty, "w")) != NULL) {
894: fprintf(f, "\r\n[%s: mail from %s]\r\n\7", thissys,
895: real_name[0]?real_name: my_name);
896: }
897: if (f)
898: fclose(f);
899: alarm(0);
900: }
901:
902: blurbtime()
903: {
904: }
905:
906: refuse(n, name, postmark, reason)
907: char *name, *postmark, *reason;
908: {
909: FILE *pf;
910: char cbuf[256], *cp;
911:
912: cp = strchr(postmark+5, ' ');
913: if (cp == NULL)
914: return;
915: *cp = '\0';
916: sprintf(cbuf, "PATH=/bin:/usr/bin mail %s", postmark+5);
917: *cp = ' ';
918: if ((pf = popen(cbuf, "w")) == NULL)
919: return;
920: fprintf(pf, "Mail to %s failed: %s. Message was:\n", name, reason);
921: copylet(n, pf, SENDING, postmark);
922: pclose(pf);
923: }
924:
925: delete(i)
926: {
927: setsig(i, delete);
928: fprintf(stderr, "\n");
929: if(delflg)
930: longjmp(sjbuf, 1);
931: done();
932: }
933:
934: done()
935: {
936: unlock();
937: unlink(lettmp);
938: exit(error);
939: }
940:
941:
942: #define LOCKPREFIX "/tmp/L."
943: char lockname[DIRSIZ+sizeof(LOCKPREFIX)];
944:
945: /* Lock the given file. The parameter "file" must contain at least one '/'. */
946: void
947: lock(file)
948: char *file;
949: {
950: # define TMPLNAME "/tmp/mlXXXXX"
951: # define LOCKPREFIX "/tmp/L."
952: char tmplname[sizeof(TMPLNAME)];
953: struct stat stbuf;
954: int fd;
955:
956: /* return if we are already in the middle of a lock */
957: if (*lockname != '\0' || flgf)
958: return;
959:
960: /* create a temporary file */
961: strcpy(tmplname, TMPLNAME);
962: mktemp(tmplname);
963: if ((fd=creat(tmplname, 0444))<0)
964: return;
965: close(fd);
966:
967: /* Make a link to it with the lock file name. This will fail only
968: * if it already exists.
969: */
970: strcpy(lockname, LOCKPREFIX);
971: strcat(lockname, strrchr(file, '/')+1);
972: lockname[DIRSIZ+sizeof("/tmp/")-1] = '\0';
973: while (link(tmplname, lockname) < 0) {
974: long now;
975:
976: /* File is already locked. Break it if the lock is old. */
977: sleep(2);
978: now = time((long *)0);
979: if (stat(lockname, &stbuf)==0 && stbuf.st_ctime+60 < now) {
980: if (stat(file, &stbuf)==0 && stbuf.st_mtime+60 >= now)
981: continue;
982: fprintf(stderr, "mail: breaking lock\n");
983: unlink(lockname);
984: }
985: }
986: unlink(tmplname);
987: return;
988: }
989:
990: void
991: unlock()
992: {
993: if (*lockname != '\0')
994: unlink(lockname);
995: *lockname = '\0';
996: }
997:
998: cat(to, from1, from2)
999: char *to, *from1, *from2;
1000: {
1001: strcpy(to, from1);
1002: strcat(to, from2);
1003: }
1004:
1005: char *getarg(s, p) /* copy p... into s, update p */
1006: register char *s, *p;
1007: {
1008: while (*p == ' ' || *p == '\t')
1009: p++;
1010: if (*p == '\n' || *p == '\0')
1011: return(NULL);
1012: while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
1013: *s++ = *p++;
1014: *s = '\0';
1015: return(p);
1016: }
1017:
1018:
1019: /* is this an internet address (characterized by "@" or ".") */
1020: isinet(string)
1021: char *string;
1022: {
1023: char *rindex();
1024:
1025: return rindex(string, '@') != 0 || rindex(string, '.') != 0;
1026: }
1027:
1028: /* add any gateway info to the address */
1029: inetgateaddr(string)
1030: char *string;
1031: {
1032: char *at, *dot;
1033: char *rindex();
1034:
1035: /* find last "." or "@" */
1036: at = rindex (string, '@');
1037: if (at != 0)
1038: dot = rindex (at + 1, '.');
1039: else
1040: dot = rindex (string, '.');
1041: if (dot != 0)
1042: at = dot;
1043:
1044: for (igate=0; igate<NIGATES; igate++) {
1045: if (istrcmp(at+1, igates[igate].id) == 0) {
1046: strcpy(at, igates[igate].addr);
1047: break;
1048: }
1049: }
1050: if (igate == NIGATES) {
1051: igate = 0; /* csnet or arpa, we really don't know */
1052: strcat(string, igates[igate].addr);
1053: }
1054: }
1055:
1056: /* case insensitive strcmp */
1057: istrcmp(p1, p2)
1058: char *p1, *p2;
1059: {
1060: do {
1061: if (tolower(*p1) != tolower(*p2))
1062: return *p1 - *p2;
1063: p2++;
1064: } while (*p1++ != 0);
1065:
1066: return 0;
1067: }
1068:
1069: /* log a mail transmission */
1070: logsend (to, pm, tag)
1071: char *to; /* receiver */
1072: char *pm; /* the postmark */
1073: char *tag; /* type of mail */
1074: {
1075: # include <grp.h>
1076: # define LOGFILE "/usr/spool/mail/mail.log"
1077: # define LOGTEMP "/usr/spool/mail/mail.tmp"
1078: char buf[BUFSIZ];
1079: int out, in;
1080: long len;
1081: struct stat sbuf;
1082: struct group sysgroup;
1083: struct group *getgrnam();
1084:
1085: lock(LOGFILE);
1086:
1087: /* append to log */
1088: if (stat(LOGFILE, &sbuf) < 0) {
1089: out = creat(LOGFILE, 0660);
1090: } else if (sbuf.st_size < 32000) {
1091: out = open(LOGFILE, 2);
1092: } else {
1093: out = creat(LOGTEMP, 0660);
1094: in = open(LOGFILE, 0);
1095: if (out >= 0 && in >= 0 && lseek(in, -4000L, 2) >= 0) {
1096: while ((len = read(in, buf, BUFSIZ)) > 0)
1097: (void)write(out, buf, len);
1098: close(in);
1099: close(out);
1100: unlink(LOGFILE);
1101: link(LOGTEMP, LOGFILE);
1102: unlink(LOGTEMP);
1103: } else {
1104: close(in);
1105: close(out);
1106: }
1107:
1108: out = open(LOGFILE, 2);
1109: }
1110: sprintf (buf, "%s %s %s\n", tag, to, pm);
1111: (void)lseek(out, 0, 2);
1112: (void)write(out, buf, strlen(buf));
1113: close(out);
1114:
1115: unlock ();
1116: }
1117:
1118: /*
1119: * Stuff for INTERNET headers
1120: */
1121:
1122: char *
1123: inetheader (pm)
1124: char *pm;
1125: {
1126: static char buf[256];
1127: char *sender, *date;
1128: char *field[6];
1129: int i;
1130:
1131: /* skip the old from field */
1132: pm += strlen (from);
1133:
1134: /* skip over the sender */
1135: for(sender=pm; !isspace(*sender) && *sender!=NULL; sender++)
1136: ;
1137: date = *sender == '\0' ? sender : sender+1;
1138:
1139: /* reverse the path and replace '!'s with '.'s */
1140: (void)strcpy (buf, "From: ");
1141: while (sender >= pm) {
1142: for (*sender = NULL; sender >= pm && *sender != '!'; sender--)
1143: ;
1144: (void)strcat (buf, sender + 1);
1145: (void)strcat (buf, ".");
1146: }
1147: (void)strcat (buf, "btl.");
1148:
1149: /* change an asctime date to an INTERNET style one (yech!) */
1150: /* parse the old date */
1151: for (i = 0; i < 6; i++) {
1152: for (; isspace(*date) || *date==',' || *date=='-'; date++)
1153: ;
1154: field[i] = date;
1155: for (; !isspace(*date) && *date!=',' && *date!='-' && *date!='\0'; date++)
1156: ;
1157: if (*date != '\0')
1158: *date++ = '\0';
1159: }
1160:
1161: /* output the arpa type format */
1162: pm = buf + strlen (buf) - 1;
1163: sprintf (pm, "\nDate: %s %s %s %s %s\n", field[2], field[1],
1164: field[5], field[3], field[4]);
1165: return buf;
1166: }
1167:
1168: sendinet(n, name, postmark)
1169: char *name, *postmark;
1170: {
1171: FILE *rmf;
1172: char cmd[512], buf[512];
1173: static forked;
1174:
1175: if (normtf) {
1176: refuse(n, name, postmark, "forwarding to this system disallowed");
1177: return(1);
1178: }
1179: if(onatty & !forked) {
1180: int p = fork();
1181: if(p == 0) {
1182: sig_ign();
1183: forked = 1;
1184: } else if(p != -1)
1185: exit(0);
1186: }
1187: #ifndef DEBUG
1188: sprintf(cmd, "exec %s %s", igates[igate].cmd, name);
1189: #else
1190: sprintf(cmd, "echo %s %s; cat", igates[igate].cmd, name);
1191: #endif DEBUG
1192: if ((rmf=popen(cmd, "w")) == NULL) {
1193: fprintf(stderr, "mail: can't pipe to %s\n", igates[igate].cmd);
1194: exit(1);
1195: }
1196: copylet(n, rmf, INTERNET, postmark);
1197: logsend(name, postmark, igates[igate].id);
1198: return(pclose(rmf)==0);
1199: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.