|
|
1.1 root 1: static char *rcsrev = "$Revision: 1.1 $";
2: static char *rcshdr =
3: "$Header: /newbits/bin/mail/mail.c,v 1.1 91/02/04 10:42:40 bin Exp $";
4: /*
5: * $Header: /newbits/bin/mail/mail.c,v 1.1 91/02/04 10:42:40 bin Exp $
6: * $Log: /newbits/bin/mail/mail.c,v $
7: * Revision 1.1 91/02/04 10:42:40 bin
8: * Initial revision
9: *
10: * Revision 2.13 90/03/30 16:16:19 wgl
11: * Correct seek pointer work within readmail.
12: *
13: * Revision 2.12 90/03/12 14:19:08 wgl
14: * New version of send doing aliases in a different place.
15: *
16: * Revision 2.11 90/03/08 16:41:15 wgl
17: * Add code to get signature file.
18: *
19: * Revision 2.10 90/03/02 10:41:59 wgl
20: * Add the -a flag so that uucp does not look like it is coming from
21: * somewhere else.
22: *
23: * Revision 2.9 90/03/01 11:17:19 wgl
24: * Final conversion to rely soley on ^A^A as separators.
25: * Effectively delete concept of m_hsize.
26: *
27: * Revision 2.8 90/03/01 10:14:31 wgl
28: * Go buy separators, not "From_" lines.
29: *
30: * Revision 2.7 90/02/28 17:11:41 wgl
31: * Add version print, add some changes to the message-id field.
32: *
33: * Revision 2.6 90/02/28 16:42:09 wgl
34: * Version number fakeout.
35: *
36: * Revision 2.5 90/02/28 16:19:44 wgl
37: * Try again to get versioin number right.
38: *
39: * Revision 2.4 90/02/28 16:18:56 wgl
40: * Get version number right.
41: *
42: * Revision 2.3 90/02/28 16:04:59 wgl
43: * Many changes; ripped out send.
44: * Changes are to make it work with uucp and internet mail.
45: *
46: * Revision 1.6 89/02/22 05:34:00 bin
47: * Changes by rec to integrate with lauren's uumail.
48: *
49: * Revision 1.5 88/09/01 14:49:01 bin
50: * Source administration: Re-install declaration of getenv.
51: * It was inserted after epstein made his copy.
52: *
53: * Revision 1.4 88/09/01 14:44:49 bin
54: * Mark Epsteins changes for ASKCC and for message scrolling, and interrupt
55: * handling during processing.
56: *
57: * Revision 1.3 88/09/01 14:27:41 bin
58: * declare getenv to get rid of integer pointer pun error message.
59: *
60: * Revision 1.2 88/09/01 11:02:23 bin
61: * Remove extra declaration of header which had rcs stuff in it.
62: *
63: * Revision 1.1 88/09/01 10:55:34 bin
64: * Initial revision
65: *
66: */
67: /*
68: * The mail command.
69: * Coherent electronic postal system.
70: * (NOTE: this command is written in such a way that
71: * it assumed that it is setuid on execution to `root'.
72: * All file accession is checked on this basis).
73: * Modifications by rec january 1986 to include xmail.
74: * by epstein november 1987 to include CC:
75: * by epstein november 1987 to allow ^C exit to leave you in
76: * mail command processor
77: * by epstein november 1987 to substitute /usr/games/fortune
78: * for printing encrypted messages
79: * by rec february 1989 to tail to lauren weinstein's
80: * mail for alias expansion and uucp queuing.
81: * by wgl January 1990 to handle uucp mail more directly.
82: */
83:
84: char isummary[] = "\
85: \
86: Command summary:\n\
87: d Delete current message and print the next message\n\
88: m [user ...] Mail current message to each named 'user'\n\
89: p Print current message again\n\
90: q Quit and update the mailbox\n\
91: r Reverse direction of scan\n\
92: s [file ...] Save message in each named 'file'\n\
93: t [user ...] Mail standard input to each named 'user'\n\
94: w [file ...] Save message in each named 'file' without its header\n\
95: x Exit without updating mailbox\n\
96: newline Print the next message\n\
97: . Print current message again\n\
98: + Print the next message\n\
99: - Print the previous message\n\
100: EOF Put undeleted mail back into mailbox and quit\n\
101: ? Print this command summary\n\
102: !command Pass 'command' to the shell to execute\n\
103: If no 'file' is specified, 'mbox' in user's home directory is default.\n\
104: If no 'user' is specified, the invoking user is default.\n\
105: If the 'm', 'p', 't' commands are followed by an 'x',\n\
106: then the public key cryptosystem is applied to the message.\n\
107: \
108: ";
109:
110: #include <stdio.h>
111: #include <pwd.h>
112: #include <sys/types.h>
113: #include <access.h>
114: #include <signal.h>
115: #include <sys/mdata.h>
116: #include <sys/stat.h>
117: #include "mail.h"
118:
119: #define NARGS 64 /* Maximum # args to interactive command */
120:
121: extern char *getenv();
122: extern int optind;
123: extern char *optarg;
124: extern char getopt();
125: char *revnop();
126:
127: int mflag; /* `You have mail.' message to recipient */
128: int rflag; /* Reverse order of print */
129: int qflag; /* Exit after interrrupts */
130: int pflag; /* Print mail */
131: int verbflag; /* verbose */
132: int callmexmail; /* Xmail modifier present */
133: int callmermail; /* rmail modifier present */
134: struct msg {
135: struct msg *m_next; /* Link to next message */
136: struct msg *m_prev; /* Link to previous message */
137: int m_flag; /* Flags - non-zero if deleted */
138: int m_hsize; /* Size of header of message */
139: fsize_t m_seek; /* Start position of message */
140: fsize_t m_end; /* End of message */
141: };
142: struct msg *m_first = NULL; /* First message */
143: struct msg *m_last = NULL; /* Last message */
144:
145: struct tm *tp;
146:
147: char iusage[] = "Bad command--type '?' for command summary\n";
148: char nombox[] = "No mailbox '%s'.\n";
149: char nomail[] = "No mail.\n";
150: char noperm[] = "Mailbox '%s' access denied.\n";
151: char moerr[] = "Cannot open mailbox '%s'\n";
152: char wrerr[] = "Write error on '%s'\n";
153: char nosave[] = "Cannot save letter in '%s'\n";
154:
155: FILE *mfp; /* Mailbox stream */
156: int myuid; /* User-id of mail user */
157: int mygid; /* Group-id of mail user */
158: char myname[25]; /* User name */
159: char myfullname[50];
160: char mymbox[256]; /* $HOME/mbox */
161: char mydead[256]; /* $HOME/dead.letter */
162: char mysig[256]; /* $HOME/dead.letter */
163: char spoolname[50] = SPOOLDIR;
164: char *mailbox = spoolname;
165: char cmdname[1024]; /* Command for x{en,de}code filter */
166: /* and for tail recursion to uumail */
167: /* and for editor recursion */
168:
169: char *args[NARGS]; /* Interactive command arglist */
170: char msgline[NLINE];
171: char cline[NCLINE] = "+\n";
172: char *temp; /* Currently open temp file */
173: char templ[] = "/tmp/mailXXXXXX"; /* Temp file name template */
174: char *editname; /* name of editor */
175: char *askcc; /* Ask for CC: list? (YES/NO) */
176:
177: fsize_t ftell();
178: char *getlogin();
179: char *mktemp();
180: int catchintr();
181: char *malloc();
182: extern char *rindex();
183: char asuser [32];
184: main(argc, argv)
185: char *argv[];
186: {
187: register char *ap;
188: char c;
189:
190: ap = argv[0];
191: if (rindex (ap, '/') != NULL)
192: ++ap;
193: callmermail = (strcmp(ap, "rmail") == 0);
194: callmexmail = (strcmp(ap, "xmail") == 0);
195: asuser [0] = '\0';
196: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
197: signal(SIGINT, catchintr);
198: while ((c = getopt(argc, argv, "a:f:mpqrv")) != EOF) {
199: switch(c) {
200: case 'f':
201: if (!callmermail)
202: mailbox = optarg;
203: break;
204: case 'a':
205: strcpy(asuser, optarg);
206: break;
207: case 'm':
208: mflag++;
209: break;
210: case 'p':
211: pflag++;
212: break;
213: case 'q':
214: qflag++;
215: break;
216: case 'r':
217: rflag++;
218: break;
219: case 'v':
220: fprintf(stderr, "mail, ver. %s\n", revnop());
221: verbflag++;
222: break;
223: default:
224: usage();
225: }
226: }
227: if (callmermail)
228: verbflag = mflag = pflag = rflag = 0;
229: setname();
230: if (optind < argc) {
231: qflag = 1;
232: send2(stdin, &argv[optind], (fsize_t)0, (fsize_t)MAXLONG, 1);
233: } else {
234: if ( ! pflag)
235: callmexmail = 0;
236: commands();
237: }
238: rmexit(0);
239: }
240:
241: /*
242: * Setup all the identities for the current user.
243: */
244: setname()
245: {
246: register struct passwd *pwp;
247: register char *np;
248: extern struct passwd * getpwnam();
249:
250: if (strlen(asuser) > 0) {
251: if((pwp = getpwnam(asuser)) == NULL)
252: merr("No such user %s.\n", asuser);
253: myuid = pwp -> pw_uid;
254: } else
255: myuid = getuid();
256: if ((pwp = getpwuid(myuid)) == NULL)
257: merr("Who are you?\n");
258: np = pwp->pw_name;
259: mygid = pwp->pw_gid;
260: strcat(spoolname, np);
261: strcpy(myname, np);
262: strcpy(myfullname, pwp->pw_gecos);
263: strcpy(mymbox, pwp->pw_dir);
264: strcat(mymbox, "/mbox");
265: strcpy(mydead, pwp->pw_dir);
266: strcat(mydead, "/dead.letter");
267: strcpy(mysig, pwp->pw_dir);
268: strcat(mysig, "/.sig.mail");
269: mktemp(templ);
270:
271: if ((editname=getenv("EDITOR"))==NULL)
272: editname = "/bin/ed";
273:
274: if ((askcc=getenv("ASKCC")) != NULL)
275: if ( strcmp(askcc, "YES") || !isatty(fileno(stdin)) )
276: askcc = NULL;
277: }
278:
279: /*
280: * Process mail's interactive commands
281: * for reading/deleting/saving mail.
282: */
283: commands()
284: {
285: register struct msg *mp;
286: struct msg *dest;
287: register char **fnp;
288: register FILE *fp;
289: fsize_t seek;
290:
291: readmail();
292: mprint(mp = rflag ? m_last : m_first);
293: for (;;) {
294: readmail();
295: intcheck();
296: if ( ! pflag) {
297: callmexmail = 0;
298: mmsg("? ");
299: if (fgets(cline, sizeof cline, stdin) == NULL) {
300: if (intcheck())
301: continue;
302: break;
303: }
304: }
305: switch (cline[0]) {
306: case 'd':
307: if (cline[1] != '\n')
308: goto usage;
309: mp->m_flag += 1;
310: goto advance;
311:
312: case 'm':
313: case 't':
314: if (csplit(cline, args) == 1) {
315: args[1] = myname;
316: args[2] = NULL;
317: }
318: callmexmail = (cline[1] == 'x');
319: if (cline[0] == 'm') {
320: send2(mfp, args+1, mp->m_seek, mp->m_end - 3, 0);
321: fseek(mfp, mp->m_seek, 0);
322: } else
323: send2(stdin, args+1, 0L, (fsize_t)MAXLONG, 1);
324: break;
325:
326: case '.':
327: case 'p':
328: if (cline[1] == 'x') {
329: callmexmail = 1;
330: if (cline[2] != '\n')
331: goto usage;
332: } else if (cline[1] != '\n')
333: goto usage;
334: if (mprint(mp))
335: break;
336: goto advance;
337:
338: case 'q':
339: if (cline[1] != '\n')
340: goto usage;
341: mquit();
342: /* NOTREACHED */
343:
344: case 'r':
345: if (cline[1] != '\n')
346: goto usage;
347: rflag = ! rflag;
348: break;
349: case 's':
350: case 'w':
351: if (csplit(cline, args) == 1) {
352: args[1] = mymbox;
353: args[2] = NULL;
354: }
355: seek = mp->m_seek;
356: if (cline[0] == 'w')
357: seek += mp->m_hsize;
358: for (fnp = &args[1]; *fnp != NULL; fnp++) {
359: fp = NULL;
360: if (maccess(*fnp) < 0
361: || (fp = fopen(*fnp, "a")) == NULL
362: || mcopy(mfp, fp, seek, mp->m_end - 3, 0))
363: mmsg(nosave, *fnp);
364: if (fp != NULL) {
365: fclose(fp);
366: chown(*fnp, myuid, mygid);
367: }
368: }
369: break;
370:
371: case 'x':
372: if (cline[1] != '\n')
373: goto usage;
374: rmexit(0);
375: /* NOTREACHED */
376:
377: case '!':
378: if (system(cline+1) == 127)
379: mmsg("Try again\n");
380: else
381: mmsg("!\n");
382: break;
383:
384: case '?':
385: mmsg(isummary);
386: break;
387:
388: case '-':
389: if (cline[1] != '\n')
390: goto usage;
391: dest = rflag ? m_last : m_first;
392: goto nextmsg;
393:
394: case '+':
395: if (cline[1] != '\n')
396: goto usage;
397: case '\n':
398: advance:
399: dest = rflag ? m_first : m_last;
400: nextmsg:
401: do {
402: if (mp == dest) {
403: if (pflag)
404: return;
405: mmsg("No more messages.\n");
406: break;
407: }
408: mp = (dest==m_last) ? mp->m_next : mp->m_prev;
409: } while (mprint(mp) == 0);
410: break;
411:
412: default:
413: usage:
414: mmsg(iusage);
415: break;
416: }
417: }
418: putc('\n', stderr);
419: mquit();
420: }
421:
422: /*
423: * Read through the mail-box file
424: * constructing list of letters.
425: * On subsequent calls, append any additional mail
426: * and notify the user.
427: */
428: readmail()
429: {
430: register struct msg *mp;
431: struct stat sb;
432: static long m_last_end;
433: fsize_t first; /* to become ffsize_t */
434: int datasw;
435:
436: if (m_first == NULL) {
437: if (stat(mailbox, &sb) < 0)
438: merr(nombox, mailbox);
439: if (sb.st_size == 0)
440: merr(nomail);
441: if (access(mailbox, AREAD) < 0)
442: merr(noperm, mailbox);
443: if ((mfp = fopen(mailbox, "r")) == NULL)
444: merr(moerr, mailbox);
445: m_last_end = 0;
446: } else {
447: fstat(fileno(mfp), &sb);
448: if (sb.st_size == m_last_end)
449: return;
450: mmsg("More mail received.\n");
451: }
452:
453: for(mlock(myuid);;) {
454: fseek(mfp, m_last_end, 0);
455: first = ftell(mfp);
456: for (datasw = 0;
457: fgets(msgline, sizeof msgline, mfp) != NULL; ) {
458: if(!(datasw = strcmp("\1\1\n", msgline))) {
459: /* found message seperator */
460: mp = (struct msg *)malloc(sizeof(*mp));
461: mp->m_next = NULL;
462: mp->m_prev = m_last;
463: mp->m_flag = mp->m_hsize = 0;
464: mp->m_seek = first;
465: mp->m_end = first = m_last_end = ftell(mfp);
466: if (m_first == NULL)
467: m_last = m_first = mp;
468: else
469: m_last = m_last->m_next = mp;
470: }
471: }
472:
473: if(!datasw)
474: break;
475:
476: /* unterminated data, patch and retry */
477: fclose(mfp);
478: if ((mfp = fopen(mailbox, "a")) == NULL)
479: merr(moerr, mailbox);
480: fprintf(mfp, "\1\1\n"); /* terminate it */
481: fclose(mfp);
482: if ((mfp = fopen(mailbox, "r")) == NULL)
483: merr(moerr, mailbox);
484: mmsg("Incomplete message found.\n");
485: }
486: munlock();
487: }
488:
489: /*
490: * Split a command line up into
491: * argv (passed) and argc (returned).
492: */
493: int
494: csplit(command, args)
495: char *command;
496: char **args;
497: {
498: register char *cp;
499: register char **ap;
500: register int c;
501:
502: cp = command;
503: ap = args;
504: for (;;) {
505: while ((c = *cp)==' ' || c=='\t')
506: *cp++ = '\0';
507: if (*cp == '\n')
508: *cp = '\0';
509: if (*cp == '\0')
510: break;
511: *ap++ = cp;
512: while ((c = *cp)!=' ' && c!='\t' && c!='\n' && c!='\0')
513: cp++;
514: }
515: *ap = NULL;
516: return (ap - args);
517: }
518:
519: /*
520: * Lock the appropriately-numbered mailbox
521: * (numbered by user-number) from multiple
522: * accesses. There is a (small) race here
523: * which will be overlooked for now.
524: */
525: char *lockname;
526:
527: mlock(uid)
528: int uid;
529: {
530: register int fd;
531: static char lock[32];
532:
533: lockname = lock;
534: sprintf(lock, "/tmp/maillock%d", uid);
535: while (access(lockname, 0) == 0)
536: sleep(1);
537: if ((fd = creat(lockname, 0)) >= 0)
538: close(fd);
539: }
540:
541: /*
542: * Unlock the currently-set lock (by `mlock')
543: * also called from rmexit.
544: */
545: munlock()
546: {
547: if (lockname != NULL)
548: unlink(lockname);
549: lockname = NULL;
550: }
551:
552: /*
553: * Exit, after rewriting the
554: * mailbox
555: */
556: mquit()
557: {
558: register struct msg *mp;
559: register FILE *nfp;
560: struct stat sb;
561:
562: readmail();
563: mlock(myuid);
564: if (mailbox != spoolname && maccess(mailbox) < 0)
565: merr(noperm, mailbox);
566: fstat(fileno(mfp), &sb);
567: signal(SIGINT, SIG_IGN);
568: unlink(mailbox);
569: if ((nfp = fopen(mailbox, "w")) == NULL)
570: merr("Cannot re-write '%s'\n", mailbox);
571: chown(mailbox, sb.st_uid, sb.st_gid);
572: chmod(mailbox, sb.st_mode&0777);
573: for (mp = m_first; mp != NULL; mp = mp->m_next) {
574: if (mp->m_flag == 0) {
575: if (mcopy(mfp, nfp, mp->m_seek, mp->m_end, 0))
576: merr(wrerr, mailbox);
577: /* else
578: fprintf(nfp, "\1\1\n"); */
579: }
580: }
581: fclose(nfp);
582: fclose(mfp);
583: munlock();
584: rmexit(0);
585: }
586:
587: /*
588: * Print the current message, given by
589: * the message pointer (`mp').
590: */
591: mprint(mp)
592: register struct msg *mp;
593: {
594: FILE *xfp;
595: if (mp->m_flag)
596: return 0;
597: if (callmexmail) {
598: sprintf(cmdname, "xdecode");
599: if ((xfp = popen(cmdname, "w")) == NULL) {
600: return 0;
601: }
602: mcopy(mfp, xfp, mp->m_seek+mp->m_hsize, mp->m_end, 1);
603: pclose(xfp);
604: } else {
605: fseek(mfp, mp->m_seek, 0);
606: if (fgets(msgline, sizeof msgline, mfp) != NULL &&
607: strncmp(msgline, "From xmail", 10) == 0) {
608: printf("From xmail\n");
609: system("/usr/games/fortune");
610: return(1);
611: }
612: mcopy(mfp, stdout, mp->m_seek, mp->m_end - 3, 1);
613: }
614: return (1);
615: }
616:
617: /*
618: * Get additional users to receive message (CC:)
619: */
620:
621: char **
622: getcc(users)
623: register char **users;
624: {
625: register char **ulist = args;
626: static char names[NCLINE];
627:
628: mmsg("CC: ");
629: if ( fgets(names, sizeof names, stdin) == NULL )
630: return(users);
631:
632: while (*users != NULL)
633: *ulist++ = *users++;
634:
635: csplit(names, ulist);
636: return(args);
637: }
638:
639:
640: /*
641: * Errors, usage, and exit removing
642: * any tempfiles left around.
643: */
644: mmsg(x, s)
645: char *x, *s;
646: {
647: fprintf(stderr, x, s);
648: }
649:
650: merr(x, s)
651: char *x, *s;
652: {
653: mmsg(x, s);
654: rmexit(1);
655: }
656:
657: rmexit(s)
658: int s;
659: {
660: if (temp != NULL)
661: unlink(temp);
662: munlock();
663: exit(s);
664: }
665:
666: /*
667: * Catch interrupts, taking the
668: * appropriate action based on
669: * the `-q' option.
670: */
671: int intflag; /* On when interrupt sent */
672:
673: catchintr()
674: {
675: signal(SIGINT, SIG_IGN);
676: if (qflag)
677: rmexit(1);
678: intflag = 1;
679: signal(SIGINT, catchintr);
680: }
681:
682: intcheck()
683: {
684: if (intflag) {
685: intflag = 0;
686: putc('\n', stderr);
687: return (1);
688: }
689: return (0);
690: }
691:
692: /*
693: * Call the system to execute a command line
694: * which is passed as an argument.
695: * Change the user id and group id.
696: */
697: system(line)
698: char *line;
699: {
700: int status, pid;
701: register wpid;
702: register int (*intfun)(), (*quitfun)();
703:
704: if ((pid = fork()) < 0)
705: return (-1);
706: if (pid == 0) { /* Child */
707: setuid(myuid);
708: setgid(mygid);
709: execl("/bin/sh", "sh", "-c", line, NULL);
710: exit(0177);
711: }
712: intfun = signal(SIGINT, SIG_IGN);
713: quitfun = signal(SIGQUIT, SIG_IGN);
714: while ((wpid = wait(&status))!=pid && wpid>=0)
715: ;
716: if (wpid < 0)
717: status = wpid;
718: signal(SIGINT, intfun);
719: signal(SIGQUIT, quitfun);
720: return (status);
721: }
722:
723: char *
724: revnop()
725: {
726: register char *cp;
727: register char c;
728: static char revnobuf[32];
729:
730: if ((cp = index(rcsrev, ' ')) != NULL) {
731: while (((c = *++cp) == ' ') && (c != '\0'))
732: ;
733: strcpy(revnobuf, cp);
734: if ((cp = index(revnobuf, ' ')) != NULL)
735: *cp = '\0';
736: return (revnobuf);
737: } else
738: return("OOPS");
739: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.