mail.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,321 行 · 第 1/2 页
C
1,321 行
#ifndef lintstatic char *sccsid = "@(#)mail.c 4.3 (ULTRIX) 4/4/91";#endif lint/************************************************************************ * * * Copyright (c) 1984 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * "binmail" /usr/binmail * * "@(#)mail.c 4.18 (Berkeley) 9/9/83"; * * EDIT HISTORY: * * 19-Jan-89 John Haxby * Having recoded safefile, the code that ensures that the file * created with the right owner and mode turned out to be * somewhat dodgy. Changed MAILMODE to be the mode that the file * is created with rather than the umask and removed the * associated (and somewhat redundant) calls to umask(). Removed * a misleading comment about calling chown() (it wasn't) and * moved the setreuid() call from immediately before fdopen() * (which doesn't open the file) to immediately before the * safefile() which does. Note that this UID swapping is * primarily for the sake of NFS since root doesn't have * sufficient privilege across NFS -- the call to safefile() to * create the dead.letter file is not changed since we don't have * a specific UID to set ourselves to. Note that the code, at * present, requires the spool directory to be world writeable, * we should really have fallback code to try create the maildrop * as root when we can't create it as the user. * * 20-Dec-89 John Haxby/Paul Sharpe * Recoded safefile() to return a file-descriptor, but only when * the file is (hopefully) definitely 'safe': else race * conditions may allow unauthorised mailbox access. * * 15-Jun-88 John Haxby * Increased size of 'truename' to prevent SIGSEGV * (which, incidentally, causes endless looping through * the signal) * * 08-Jun-88 Mark Parenti * Changed signal handlers to void. * * 22-Jan-88 John Haxby * Added -e flag for X/OPEN. * * 27-Feb-1987 Ray Glaser * Added logic to extend the wait time on stale lock * files to be a function of the system load ave. * * 12-Feb-1987 Ray Glaser * Massive revision to the file locking logic for NFS. * * 15-Dec-1986 Marc Teitelbaum - 0001 * Only chown spool mailfile if we created it. * Security reasons. Also, bump timeout on * waiting for lock to 60 seconds. 30 seems * too low. Flock would be preferable, but no * time right now and much gastric distress. * * aps00 10/26/83 -- added check for UID of uucp otherwise, would * fail if mail is comming from off system, * via uucp. * 02-Apr-84 mah. Fix for gethostname for queued file. This * is to reflect 4.21 (Berkeley). * */#include <ctype.h>#include <stdio.h>#include <errno.h>#include <pwd.h>#include <utmp.h>#include <signal.h>#include <syslog.h>#include <sys/types.h>#include <sys/stat.h>#include <setjmp.h>#include <sysexits.h>#include <sys/file.h>#include <sys/ioctl.h>#include <sys/param.h>#include <nlist.h>#define SENDMAIL "/usr/lib/sendmail"int OVERRIDE = 0; /* Flag set if lock file overridden */int FIRSTSLEEP = 1;int LOCKSLEEP = 9; /* Basic # seconds to sleep between checks for * name.lock file existance and to ck the * peak load ave. */#define OLOCKSLEEPS 19 int LOCKSLEEPS = OLOCKSLEEPS; /* Basic # of times to sleep & wait for * name.lock file to disappear of its' * own accord before we blow it away. */ /*copylet flags */ /*remote mail, add rmtmsg */#define REMOTE 1 /* zap header and trailing empty line */#define ZAP 3#define ORDINARY 2#define FORWARD 4#define LSIZE 256#define MAXLET 300 /* maximum number of letters */#define MAILMODE 0600 /* mode of created mail */struct nlist Nl[] ={ { "_avenrun" },#define X_AVENRUN 0 { 0 },};int load = 0;int peak = 1; /* Peak load ave seen */int oload = 0;char hostname[255];char line[LSIZE];char resp[LSIZE];struct let { long adr; char change;} let[MAXLET];int nlet = 0;char lfil[50];long iop, time();char *getenv();char *index();char lettmp[] = "/tmp/maXXXXX";char maildir[] = "/usr/spool/mail/";char mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";char dead[] = "dead.letter";char *netname = "vax";char forwmsg[] = " forwarded\n";FILE *tmpf;FILE *malf;char *my_name;char *getlogin();struct passwd *getpwuid();int error;int changed;int forward;char from[] = "From ";long ftell();void delete();char *ctime();int flgf;int flgp;int delflg = 1;int hseqno;jmp_buf sjbuf;int rmail;main(argc, argv)char **argv;{ register i; char sobuf[BUFSIZ]; setbuf(stdout, sobuf); mktemp(lettmp); unlink(lettmp); my_name = getlogin(); if (my_name == NULL || strlen(my_name) == 0) { struct passwd *pwent; pwent = getpwuid(getuid()); if (pwent==NULL) my_name = "???"; else my_name = pwent->pw_name; } if(setjmp(sjbuf)) done(); for (i=SIGHUP; i<=SIGTERM; i++) setsig(i, delete); tmpf = fopen(lettmp, "w"); if (tmpf == NULL) { fprintf(stderr, "mail: cannot open %s for writing\n", lettmp); done(); } if (argv[0][0] == 'r') rmail++; if (argv[0][0] != 'r' && /* no favors for rmail*/ (argc == 1 || argv[1][0] == '-' && !any(argv[1][1], "rhd"))) printmail(argc, argv); else bulkmail(argc, argv); done();}setsig(i, f)int i;void (*f)();{ if(signal(i, SIG_IGN)!=SIG_IGN) signal(i, f);}any(c, str) register int c; register char *str;{ while (*str) if (c == *str++) return(1); return(0);}printmail(argc, argv)char **argv;{ int flg, i, j, print, check = 0; char *p, *getarg(); struct stat statb; setuid(getuid()); cat(mailfile, maildir, my_name); if (stat(mailfile, &statb) >= 0 && (statb.st_mode & S_IFMT) == S_IFDIR) { strcat(mailfile, "/"); strcat(mailfile, my_name); } for (; argc>1; argv++, argc--) { if (argv[1][0]=='-') { if (argv[1][1]=='q') delflg = 0; else if (argv[1][1]=='p') { flgp++; delflg = 0; } else if (argv[1][1]=='f') { if (argc>=3) { strcpy(mailfile, argv[2]); argv++; argc--; } } else if (argv[1][1]=='r') { forward = 1; } else if (argv[1][1]=='h') { forward = 1; } else if (argv[1][1]=='e') { check = 1; } else { fprintf(stderr, "mail: unknown option %c\n", argv[1][1]); done(); } } else break; } malf = fopen(mailfile, "r"); if (malf == NULL) { if (check) { error = 1; done(); } else { fprintf(stdout, "No mail.\n"); return; } } lock(mailfile); copymt(malf, tmpf); fclose(malf);/* PJS: Signal an error on failing to fclose. */ if (fclose(tmpf) == EOF) { perror("mail"); done(); } unlock(); if (check) { error = nlet == 0; done(); } tmpf = fopen(lettmp, "r"); changed = 0; print = 1; for (i = 0; i < nlet; ) { j = forward ? i : nlet - i - 1; if(setjmp(sjbuf)) { print=0; } else { if (print) copylet(j, stdout, ORDINARY); print = 1; } if (flgp) { i++; continue; } setjmp(sjbuf); fprintf(stdout, "? "); fflush(stdout); if (fgets(resp, LSIZE, stdin) == NULL) break; switch (resp[0]) { default: fprintf(stderr, "usage\n"); case '?': print = 0; fprintf(stderr, "q\tquit\n"); fprintf(stderr, "x\texit without changing mail\n"); fprintf(stderr, "p\tprint\n"); fprintf(stderr, "s[file]\tsave (default mbox)\n"); fprintf(stderr, "w[file]\tsame without header\n"); fprintf(stderr, "-\tprint previous\n"); fprintf(stderr, "d\tdelete\n"); fprintf(stderr, "+\tnext (no delete)\n"); fprintf(stderr, "m user\tmail to user\n"); fprintf(stderr, "! cmd\texecute cmd\n"); break; case '+': case 'n': case '\n': i++; break; case 'x': changed = 0; case 'q': goto donep; case 'p': break; case '^': case '-': if (--i < 0) i = 0; break; case 'y': case 'w': case 's': flg = 0; if (resp[1] != '\n' && resp[1] != ' ') { printf("illegal\n"); flg++; print = 0; continue; } if (resp[1] == '\n' || resp[1] == '\0') { p = getenv("HOME"); if(p != 0) cat(resp+1, p, "/mbox"); else cat(resp+1, "", "mbox"); } for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) { malf = fopen(lfil, "a"); if (malf == NULL) { fprintf(stdout, "mail: cannot append to %s\n", lfil); flg++; continue; } copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY);/* PJS: Signal an error on failing to fclose. */ if (fclose(malf) == EOF) { perror("mail"); done(); } } if (flg) print = 0; else { let[j].change = 'd'; changed++; i++; } break; case 'm': flg = 0; if (resp[1] == '\n' || resp[1] == '\0') { i++; continue; } if (resp[1] != ' ') { printf("invalid command\n"); flg++; print = 0; continue; } for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) if (!sendrmt(j, lfil, "/bin/mail")) /* couldn't send it */ flg++; if (flg) print = 0; else { let[j].change = 'd'; changed++; i++; } break; case '!': system(resp+1); printf("!\n"); print = 0; break; case 'd': let[j].change = 'd'; changed++; i++; if (resp[1] == 'q') goto donep; break; } } donep: if (changed) copyback();}copyback() /* copy temp or whatever back to /usr/spool/mail */{ register i, n, c; int new = 0; struct stat stbuf; signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGQUIT, SIG_IGN); lock(mailfile); stat(mailfile, &stbuf); if (stbuf.st_size != let[nlet].adr) { /* new mail has arrived */ malf = fopen(mailfile, "r"); if (malf == NULL) { fprintf(stdout, "mail: can't re-read %s\n", mailfile); done(); } fseek(malf, let[nlet].adr, 0); fclose(tmpf); tmpf = fopen(lettmp, "a"); fseek(tmpf, let[nlet].adr, 0);/* PJS: Test the putc, in case there is no more file space... */ while ((c = fgetc(malf)) != EOF) if (fputc(c, tmpf) != c) { perror("mail"); done(); }/* PJS: Test the closing of the file, in case there is no more file space. */ if (fclose(malf) == EOF) { perror("mail"); done(); } if (fclose(tmpf) == EOF) { perror("mail"); done(); } tmpf = fopen(lettmp, "r"); let[++nlet].adr = stbuf.st_size; new = 1; } malf = fopen(mailfile, "w"); if (malf == NULL) { fprintf(stderr, "mail: can't rewrite %s\n", lfil); done(); } n = 0; for (i = 0; i < nlet; i++) if (let[i].change != 'd') { copylet(i, malf, ORDINARY); n++; }/* PJS: test closing of mailfile, in case there is no more file space. */ if (fclose(malf) == EOF) { fprintf(stderr,"mail: can't close copied mailfile '%s'\n", mailfile); done(); } if (new) fprintf(stdout, "new mail arrived\n"); unlock();}copymt(f1, f2) /* copy mail (f1) to temp (f2) */FILE *f1, *f2;{ long nextadr; nlet = nextadr = 0; let[0].adr = 0; while (fgets(line, LSIZE, f1) != NULL) { if (isfrom(line)) let[nlet++].adr = nextadr; nextadr += strlen(line);/* PJS: Test for output, in case there is no more file space. */ if (fputs(line, f2) < 0) { perror("mail"); done(); } } let[nlet].adr = nextadr; /* last plus 1 */}copylet(n, f, type) FILE *f;{ int ch; long k; fseek(tmpf, let[n].adr, 0); k = let[n+1].adr - let[n].adr; while(k-- > 1 && (ch=fgetc(tmpf))!='\n') if(type!=ZAP)/* PJS: Test for output, in case there is no more file space. */ if (fputc(ch,f) != ch) { perror("mail"); done(); } if(type==REMOTE) { char hostname[32]; gethostname(hostname, sizeof (hostname)); fprintf(f, " remote from %s\n", hostname); } else if (type==FORWARD) fprintf(f, forwmsg); else if(type==ORDINARY)/* PJS: Test for output, in case there is no more file space. */ if (fputc(ch,f) != ch) { perror("mail"); done(); }/* PJS: Test for output, in case there is no more file space. */ while(k-->1) { ch=fgetc(tmpf); if (fputc(ch, f) != ch) { perror("mail"); done(); } }/* PJS: Test for output, in case there is no more file space. */ if(type!=ZAP || ch!= '\n') { ch = fgetc(tmpf); if (fputc(ch, f) != ch) { perror("mail"); done(); } }}isfrom(lp)register char *lp;{ register char *p; for (p = from; *p; ) if (*lp++ != *p++) return(0); return(1);}bulkmail(argc, argv)char **argv;{ char truename[1024]; /* maximum permitted by sendmail */ int first; register char *cp; int gaver = 0; char *newargv[1000]; register char **ap; register char **vp; int dflag; int mald; /* 'safe' file desc returned for mail spool */ dflag = 0; if (argc < 1) fprintf(stderr, "puke\n"); for (vp = argv, ap = newargv + 1; (*ap = *vp++) != 0; ap++) { if (ap[0][0] == '-' && ap[0][1] == 'd') dflag++; } if (!dflag) { /* give it to sendmail, rah rah! */ unlink(lettmp); ap = newargv+1; if (rmail) *ap-- = "-s"; *ap = "-sendmail"; setuid(getuid()); execv(SENDMAIL, ap); perror(SENDMAIL); exit(EX_UNAVAILABLE); } truename[0] = 0; line[0] = '\0'; /* * When we fall out of this, argv[1] should be first name, * argc should be number of names + 1. */ while (argc > 1 && *argv[1] == '-') { cp = *++argv; argc--; switch (cp[1]) { case 'r': if (argc <= 0) { fprintf(stderr, "r flag needs more argument\n"); usage(); done(); } gaver++; strcpy(truename, argv[1]); fgets(line, LSIZE, stdin); if (strcmpn("From", line, 4) == 0) line[0] = '\0'; argv++; argc--; break; case 'h': if (argc <= 0) { fprintf(stderr, "h flag needs more arguments\n"); usage(); done(); } hseqno = atoi(argv[1]); argv++; argc--; break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?