Research V7 development
authorKen Thompson <ken@research.uucp>
Sat, 5 May 1979 07:01:15 +0000 (02:01 -0500)
committerKen Thompson <ken@research.uucp>
Sat, 5 May 1979 07:01:15 +0000 (02:01 -0500)
Work on file usr/src/cmd/mail.c

Synthesized-from: v7

usr/src/cmd/mail.c [new file with mode: 0644]

diff --git a/usr/src/cmd/mail.c b/usr/src/cmd/mail.c
new file mode 100644 (file)
index 0000000..b43f498
--- /dev/null
@@ -0,0 +1,554 @@
+#include <stdio.h>
+#include <pwd.h>
+#include <utmp.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <setjmp.h>
+#include <whoami.h>
+
+/*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 (~0644)                /* mode of created mail */
+
+char   line[LSIZE];
+char   resp[LSIZE];
+struct let {
+       long    adr;
+       char    change;
+} let[MAXLET];
+int    nlet    = 0;
+char   lfil[50];
+long   iop, time();
+char   lettmp[] = "/tmp/maXXXXX";
+char   maildir[] = "/usr/spool/mail/";
+char   mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxx";
+char   dead[] = "dead.letter";
+char   *thissys = sysname;
+char   forwmsg[] = " forwarded\n";
+char   *curlock;
+int    lockerror;
+FILE   *tmpf;
+FILE   *malf;
+char   *my_name;
+char   *getlogin();
+struct passwd  *getpwuid();
+int    error;
+int    locked;
+int    changed;
+int    forward;
+char   from[] = "From ";
+long   ftell();
+int    delete();
+char   *ctime();
+int    flgf;
+int    flgp;
+int    delflg = 1;
+jmp_buf        sjbuf;
+
+main(argc, argv)
+char **argv;
+{
+       register i;
+       char sobuf[BUFSIZ];
+
+       setbuf(stdout, sobuf);
+       mktemp(lettmp);
+       unlink(lettmp);
+       my_name = getlogin();
+       if (my_name == NULL) {
+               struct passwd *pwent;
+               pwent = getpwuid(getuid());
+               if (pwent==NULL)
+                       my_name = "???";
+               else
+                       my_name = pwent->pw_name;
+       }
+       if(setjmp(sjbuf)) done();
+       for (i=0; i<20; 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' &&        /* no favors for rmail*/
+          (argc == 1 || argv[1][0] == '-'))
+               printmail(argc, argv);
+       else
+               sendmail(argc, argv);
+       done();
+}
+
+setsig(i, f)
+int i;
+int (*f)();
+{
+       if(signal(i, SIG_IGN)!=SIG_IGN)
+               signal(i, f);
+}
+
+printmail(argc, argv)
+char **argv;
+{
+       int flg, i, j, print;
+       char *p, *getarg();
+
+       setuid(getuid());
+       cat(mailfile, maildir, 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 {
+                               fprintf(stderr, "mail: unknown option %c\n", argv[1][1]);
+                               done();
+                       }
+               } else
+                       break;
+       }
+       malf = fopen(mailfile, "r");
+       if (malf == NULL) {
+               fprintf(stdout, "No mail.\n");
+               return;
+       }
+       lock(mailfile);
+       copymt(malf, tmpf);
+       fclose(malf);
+       fclose(tmpf);
+       unlock();
+       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')
+                               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);
+                               fclose(malf);
+                       }
+                       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))  /* 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);
+               while ((c = fgetc(malf)) != EOF)
+                       fputc(c, tmpf);
+               fclose(malf);
+               fclose(tmpf);
+               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++;
+               }
+       fclose(malf);
+       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);
+               fputs(line, f2);
+       }
+       let[nlet].adr = nextadr;        /* last plus 1 */
+}
+
+copylet(n, f, type) FILE *f;
+{      int ch, 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) fputc(ch,f);
+       if(type==REMOTE)
+               fprintf(f, " remote from %s\n", thissys);
+       else if (type==FORWARD)
+               fprintf(f, forwmsg);
+       else if(type==ORDINARY)
+               fputc(ch,f);
+       while(k-->1)
+               fputc(ch=fgetc(tmpf), f);
+       if(type!=ZAP || ch!= '\n')
+               fputc(fgetc(tmpf), f);
+}
+
+isfrom(lp)
+register char *lp;
+{
+       register char *p;
+
+       for (p = from; *p; )
+               if (*lp++ != *p++)
+                       return(0);
+       return(1);
+}
+
+sendmail(argc, argv)
+char **argv;
+{
+
+       time(&iop);
+       fprintf(tmpf, "%s%s %s", from, my_name, ctime(&iop));
+       iop = ftell(tmpf);
+       flgf = 1;
+       while (fgets(line, LSIZE, stdin) != NULL) {
+               if (line[0] == '.' && line[1] == '\n')
+                       break;
+               if (isfrom(line))
+                       fputs(">", tmpf);
+               fputs(line, tmpf);
+               flgf = 0;
+       }
+       fputs("\n", tmpf);
+       nlet = 1;
+       let[0].adr = 0;
+       let[1].adr = ftell(tmpf);
+       fclose(tmpf);
+       if (flgf)
+               return;
+       tmpf = fopen(lettmp, "r");
+       if (tmpf == NULL) {
+               fprintf(stderr, "mail: cannot reopen %s for reading\n", lettmp);
+               return;
+       }
+       while (--argc > 0)
+               if (!send(0, *++argv))  /* couldn't send to him */
+                       error++;
+       if (error) {
+               setuid(getuid());
+               malf = fopen(dead, "w");
+               if (malf == NULL) {
+                       fprintf(stdout, "mail: cannot open %s\n", dead);
+                       fclose(tmpf);
+                       return;
+               }
+               copylet(0, malf, ZAP);
+               fclose(malf);
+               fprintf(stdout, "Mail saved in %s\n", dead);
+       }
+       fclose(tmpf);
+}
+
+sendrmt(n, name)
+char *name;
+{
+       FILE *rmf, *popen();
+       register char *p;
+       char rsys[64], cmd[64];
+       register local, pid;
+       int sts;
+
+       local = 0;
+       if (*name=='!')
+               name++;
+       for(p=rsys; *name!='!'; *p++ = *name++)
+               if (*name=='\0') {
+                       local++;
+                       break;
+               }
+       *p = '\0';
+       if ((!local && *name=='\0') || (local && *rsys=='\0')) {
+               fprintf(stdout, "null name\n");
+               return(0);
+       }
+       if ((pid = fork()) == -1) {
+               fprintf(stderr, "mail: can't create proc for remote\n");
+               return(0);
+       }
+       if (pid) {
+               while (wait(&sts) != pid) {
+                       if (wait(&sts)==-1)
+                               return(0);
+               }
+               return(!sts);
+       }
+       setuid(getuid());
+       if (local)
+               sprintf(cmd, "mail %s", rsys);
+       else {
+               if (index(name+1, '!'))
+                       sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1);
+               else
+                       sprintf(cmd, "uux - %s!rmail %s", rsys, name+1);
+       }
+       if ((rmf=popen(cmd, "w")) == NULL)
+               exit(1);
+       copylet(n, rmf, local? FORWARD: REMOTE);
+       pclose(rmf);
+       exit(0);
+}
+
+send(n, name)  /* send letter n to name */
+int n;
+char *name;
+{
+       char file[50];
+       register char *p;
+       register mask;
+       struct passwd *pw, *getpwnam();
+
+       for(p=name; *p!='!' &&*p!='\0'; p++)
+               ;
+       if (*p == '!')
+               return(sendrmt(n, name));
+       if ((pw = getpwnam(name)) == NULL) {
+               fprintf(stdout, "mail: can't send to %s\n", name);
+               return(0);
+       }
+       cat(file, maildir, name);
+       mask = umask(MAILMODE);
+       malf = fopen(file, "a");
+       umask(mask);
+       if (malf == NULL) {
+               fprintf(stdout, "mail: cannot append to %s\n", file);
+               return(0);
+       }
+       lock(file);
+       chown(file, pw->pw_uid, pw->pw_gid);
+       copylet(n, malf, ORDINARY);
+       fclose(malf);
+       unlock();
+       return(1);
+}
+
+delete(i)
+{
+       setsig(i, delete);
+       fprintf(stderr, "\n");
+       if(delflg)
+               longjmp(sjbuf, 1);
+       done();
+}
+
+done()
+{
+       if(!lockerror)
+               unlock();
+       unlink(lettmp);
+       exit(error+lockerror);
+}
+
+lock(file)
+char *file;
+{
+       struct stat stbuf;
+
+       if (locked || flgf)
+               return;
+       if (stat(file, &stbuf)<0)
+               return;
+       if (stbuf.st_mode&01) {         /* user x bit is the lock */
+               if (stbuf.st_ctime+60 >= time((long *)0)) {
+                       fprintf(stderr, "%s busy; try again in a minute\n", file);
+                       lockerror++;
+                       done();
+               }
+       }
+       locked = stbuf.st_mode & ~01;
+       curlock = file;
+       chmod(file, stbuf.st_mode|01);
+}
+
+unlock()
+{
+       if (locked)
+               chmod(curlock, locked);
+       locked = 0;
+}
+
+cat(to, from1, from2)
+char *to, *from1, *from2;
+{
+       int i, j;
+
+       j = 0;
+       for (i=0; from1[i]; i++)
+               to[j++] = from1[i];
+       for (i=0; from2[i]; i++)
+               to[j++] = from2[i];
+       to[j] = 0;
+}
+
+char *getarg(s, p)     /* copy p... into s, update p */
+register char *s, *p;
+{
+       while (*p == ' ' || *p == '\t')
+               p++;
+       if (*p == '\n' || *p == '\0')
+               return(NULL);
+       while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
+               *s++ = *p++;
+       *s = '\0';
+       return(p);
+}