BSD 3 development
[unix-history] / usr / src / cmd / mail.c
index 41bdafa..5dce570 100644 (file)
@@ -1,3 +1,4 @@
+#include <ctype.h>
 #include <stdio.h>
 #include <pwd.h>
 #include <utmp.h>
 #include <stdio.h>
 #include <pwd.h>
 #include <utmp.h>
@@ -5,6 +6,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <setjmp.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <setjmp.h>
+#include <whoami.h>
 
 /*copylet flags */
        /*remote mail, add rmtmsg */
 
 /*copylet flags */
        /*remote mail, add rmtmsg */
 #define        LSIZE   256
 #define        MAXLET  300     /* maximum number of letters */
 #define        MAILMODE (~0644)                /* mode of created mail */
 #define        LSIZE   256
 #define        MAXLET  300     /* maximum number of letters */
 #define        MAILMODE (~0644)                /* mode of created mail */
+#define        RMAIL   "/usr/net/bin/sendberkmail"
+#define LOCNAM1        "csvax"
+#define LOCNAM2        "ucbvax"
+#define LOCNAM3        "vax"
+#define LOCNAM4        "v"
 
 char   line[LSIZE];
 char   resp[LSIZE];
 
 char   line[LSIZE];
 char   resp[LSIZE];
@@ -26,22 +33,21 @@ struct let {
 int    nlet    = 0;
 char   lfil[50];
 long   iop, time();
 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/xxxxxxxxxxxxxxxxxxxxxxx";
 char   dead[] = "dead.letter";
 char   lettmp[] = "/tmp/maXXXXX";
 char   maildir[] = "/usr/spool/mail/";
 char   mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxx";
 char   dead[] = "dead.letter";
-char   *rmtmsg = " remote from vax135\n";              /*LOCAL*/
-char   *thissys = "vax135";            /*LOCAL*/
+char   *thissys = sysname;
+char   *netname = "vax";
 char   forwmsg[] = " forwarded\n";
 char   forwmsg[] = " forwarded\n";
-char   *curlock;
-int    lockerror;
 FILE   *tmpf;
 FILE   *malf;
 char   *my_name;
 char   *getlogin();
 struct passwd  *getpwuid();
 int    error;
 FILE   *tmpf;
 FILE   *malf;
 char   *my_name;
 char   *getlogin();
 struct passwd  *getpwuid();
 int    error;
-int    locked;
 int    changed;
 int    forward;
 char   from[] = "From ";
 int    changed;
 int    forward;
 char   from[] = "From ";
@@ -51,6 +57,7 @@ char  *ctime();
 int    flgf;
 int    flgp;
 int    delflg = 1;
 int    flgf;
 int    flgp;
 int    delflg = 1;
+int    hseqno;
 jmp_buf        sjbuf;
 
 main(argc, argv)
 jmp_buf        sjbuf;
 
 main(argc, argv)
@@ -63,7 +70,7 @@ char **argv;
        mktemp(lettmp);
        unlink(lettmp);
        my_name = getlogin();
        mktemp(lettmp);
        unlink(lettmp);
        my_name = getlogin();
-       if (my_name == NULL) {
+       if (my_name == NULL || strlen(my_name) == 0) {
                struct passwd *pwent;
                pwent = getpwuid(getuid());
                if (pwent==NULL)
                struct passwd *pwent;
                pwent = getpwuid(getuid());
                if (pwent==NULL)
@@ -80,7 +87,7 @@ char **argv;
                done();
        }
        if (argv[0][0] != 'r' &&        /* no favors for rmail*/
                done();
        }
        if (argv[0][0] != 'r' &&        /* no favors for rmail*/
-          (argc == 1 || argv[1][0] == '-'))
+          (argc == 1 || argv[1][0] == '-' && !any(argv[1][1], "rh")))
                printmail(argc, argv);
        else
                sendmail(argc, argv);
                printmail(argc, argv);
        else
                sendmail(argc, argv);
@@ -95,6 +102,17 @@ int (*f)();
                signal(i, f);
 }
 
                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;
 {
 printmail(argc, argv)
 char **argv;
 {
@@ -118,6 +136,8 @@ char **argv;
                                }
                        } else if (argv[1][1]=='r') {
                                forward = 1;
                                }
                        } else if (argv[1][1]=='r') {
                                forward = 1;
+                       } else if (argv[1][1]=='h') {
+                               forward = 1;
                        } else {
                                fprintf(stderr, "mail: unknown option %c\n", argv[1][1]);
                                done();
                        } else {
                                fprintf(stderr, "mail: unknown option %c\n", argv[1][1]);
                                done();
@@ -201,8 +221,13 @@ char **argv;
                                print = 0;
                                continue;
                        }
                                print = 0;
                                continue;
                        }
-                       if (resp[1] == '\n' || resp[1] == '\0')
-                               cat(resp+1, "mbox", "");
+                       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) {
                        for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) {
                                malf = fopen(lfil, "a");
                                if (malf == NULL) {
@@ -234,7 +259,7 @@ char **argv;
                                continue;
                        }
                        for (p = resp+1; (p = getarg(lfil, p)) != NULL; )
                                continue;
                        }
                        for (p = resp+1; (p = getarg(lfil, p)) != NULL; )
-                               if (!sendrmt(j, lfil))  /* couldn't send it */
+                               if (!sendrmt(j, lfil, "/bin/mail"))     /* couldn't send it */
                                        flg++;
                        if (flg)
                                print = 0;
                                        flg++;
                        if (flg)
                                print = 0;
@@ -332,7 +357,7 @@ copylet(n, f, type) FILE *f;
        while(k-- > 1 && (ch=fgetc(tmpf))!='\n')
                if(type!=ZAP) fputc(ch,f);
        if(type==REMOTE)
        while(k-- > 1 && (ch=fgetc(tmpf))!='\n')
                if(type!=ZAP) fputc(ch,f);
        if(type==REMOTE)
-               fprintf(f, rmtmsg);
+               fprintf(f, " remote from %s\n", thissys);
        else if (type==FORWARD)
                fprintf(f, forwmsg);
        else if(type==ORDINARY)
        else if (type==FORWARD)
                fprintf(f, forwmsg);
        else if(type==ORDINARY)
@@ -357,13 +382,79 @@ register char *lp;
 sendmail(argc, argv)
 char **argv;
 {
 sendmail(argc, argv)
 char **argv;
 {
+       char truename[100];
+       int first;
+       register char *cp;
+       int gaver = 0;
+
+       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) {
+                               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) {
+                               usage();
+                               done();
+                       }
+                       hseqno = atoi(argv[1]);
+                       argv++;
+                       argc--;
+                       break;
+
+               default:
+                       usage();
+                       done();
+               }
+       }
+       if (argc <= 1) {
+               usage();
+               done();
+       }
+       if (gaver == 0)
+               strcpy(truename, my_name);
+       /*
+       if (argc > 4 && strcmp(argv[1], "-r") == 0) {
+               strcpy(truename, argv[2]);
+               argc -= 2;
+               argv += 2;
+               fgets(line, LSIZE, stdin);
+               if (strcmpn("From", line, 4) == 0)
+                       line[0] = '\0';
+       } else
+               strcpy(truename, my_name);
+       */
        time(&iop);
        time(&iop);
-       fprintf(tmpf, "%s%s %s", from, my_name, ctime(&iop));
+       fprintf(tmpf, "%s%s %s", from, truename, ctime(&iop));
        iop = ftell(tmpf);
        flgf = 1;
        iop = ftell(tmpf);
        flgf = 1;
-       while (fgets(line, LSIZE, stdin) != NULL) {
-               if (line[0] == '.' && line[1] == '\n')
+       for (first = 1;; first = 0) {
+               if (first && line[0] == '\0' && fgets(line, LSIZE, stdin) == NULL)
+                       break;
+               if (!first && fgets(line, LSIZE, stdin) == NULL)
+                       break;
+               if (line[0] == '.' && line[1] == '\n' && isatty(fileno(stdin)))
                        break;
                if (isfrom(line))
                        fputs(">", tmpf);
                        break;
                if (isfrom(line))
                        fputs(">", tmpf);
@@ -383,7 +474,7 @@ char **argv;
                return;
        }
        while (--argc > 0)
                return;
        }
        while (--argc > 0)
-               if (!send(0, *++argv))  /* couldn't send to him */
+               if (!send(0, *++argv, truename))
                        error++;
        if (error) {
                setuid(getuid());
                        error++;
        if (error) {
                setuid(getuid());
@@ -400,8 +491,9 @@ char **argv;
        fclose(tmpf);
 }
 
        fclose(tmpf);
 }
 
-sendrmt(n, name)
+sendrmt(n, name, rcmd)
 char *name;
 char *name;
+char *rcmd;
 {
        FILE *rmf, *popen();
        register char *p;
 {
        FILE *rmf, *popen();
        register char *p;
@@ -410,6 +502,16 @@ char *name;
        int sts;
 
        local = 0;
        int sts;
 
        local = 0;
+       if (index(name, '^')) {
+               while (p = index(name, '^'))
+                       *p = '!';
+               if (strncmp(name, "researc", 7)) {
+                       strcpy(rsys, "research");
+                       if (*name != '!')
+                               --name;
+                       goto skip;
+               }
+       }
        if (*name=='!')
                name++;
        for(p=rsys; *name!='!'; *p++ = *name++)
        if (*name=='!')
                name++;
        for(p=rsys; *name!='!'; *p++ = *name++)
@@ -422,6 +524,7 @@ char *name;
                fprintf(stdout, "null name\n");
                return(0);
        }
                fprintf(stdout, "null name\n");
                return(0);
        }
+skip:
        if ((pid = fork()) == -1) {
                fprintf(stderr, "mail: can't create proc for remote\n");
                return(0);
        if ((pid = fork()) == -1) {
                fprintf(stderr, "mail: can't create proc for remote\n");
                return(0);
@@ -435,7 +538,7 @@ char *name;
        }
        setuid(getuid());
        if (local)
        }
        setuid(getuid());
        if (local)
-               sprintf(cmd, "mail %s", rsys);
+               sprintf(cmd, "%s %s", rcmd, rsys);
        else {
                if (index(name+1, '!'))
                        sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1);
        else {
                if (index(name+1, '!'))
                        sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1);
@@ -444,24 +547,63 @@ char *name;
        }
        if ((rmf=popen(cmd, "w")) == NULL)
                exit(1);
        }
        if ((rmf=popen(cmd, "w")) == NULL)
                exit(1);
-       copylet(n, rmf, local? FORWARD: REMOTE);
+       copylet(n, rmf, local ? !strcmp(rcmd, "/bin/mail") ? FORWARD : ORDINARY : REMOTE);
        pclose(rmf);
        exit(0);
 }
 
        pclose(rmf);
        exit(0);
 }
 
-send(n, name)  /* send letter n to name */
+/*
+ * Send mail on the Berkeley network.
+ * Sorry Bill, sendrmt() is so awful we just gave up.
+ */
+
+sendberkmail(n, name, fromaddr)
+       char name[];
+       char fromaddr[];
+{
+       char cmd[200];
+       register FILE *cmdf;
+
+       sprintf(cmd, "%s -h %d -f %s -t %s", RMAIL, hseqno, fromaddr, name);
+       if ((cmdf = popen(cmd, "w")) == NULL) {
+               perror(RMAIL);
+               return(0);
+       }
+       copylet(n, cmdf, ORDINARY);
+       pclose(cmdf);
+       return(9);
+}
+
+usage()
+{
+
+       fprintf(stderr, "Usage: mail [ -f ] people . . .\n");
+}
+
+send(n, name, fromaddr)
 int n;
 char *name;
 int n;
 char *name;
+char *fromaddr;
 {
        char file[50];
        register char *p;
        register mask;
        struct passwd *pw, *getpwnam();
 
 {
        char file[50];
        register char *p;
        register mask;
        struct passwd *pw, *getpwnam();
 
-       for(p=name; *p!='!' &&*p!='\0'; p++)
+       stripfx(LOCNAM1, &name);
+       stripfx(LOCNAM2, &name);
+       stripfx(LOCNAM3, &name);
+       stripfx(LOCNAM4, &name);
+       if(*name == ':')name++;         /* skip colon in to-name */
+       for(p=name; *p!=':' &&*p!='\0'; p++);
+       /* if(*p == ':') return(sendrmt(n, name, RMAIL)); */
+       if (*p == ':')
+               return(sendberkmail(n, name, fromaddr));
+       else if (strcmp(name, "msgs") == 0) return(sendrmt(n, "-s", "/usr/ucb/msgs"));
+       for(p=name; *p!='!'&&*p!='^' &&*p!='\0'; p++)
                ;
                ;
-       if (*p == '!')
-               return(sendrmt(n, name));
+       if (*p == '!'|| *p=='^')
+               return(sendrmt(n, name, 0));
        if ((pw = getpwnam(name)) == NULL) {
                fprintf(stdout, "mail: can't send to %s\n", name);
                return(0);
        if ((pw = getpwnam(name)) == NULL) {
                fprintf(stdout, "mail: can't send to %s\n", name);
                return(0);
@@ -491,42 +633,102 @@ delete(i)
        done();
 }
 
        done();
 }
 
-done()
-{
-       if(!lockerror)
-               unlock();
-       unlink(lettmp);
-       exit(error+lockerror);
-}
+/*
+ * Lock the specified mail file by setting the file mailfile.lock.
+ * We must, of course, be careful to unlink the lock file by a call
+ * to unlock before we stop.  The algorithm used here is to see if
+ * the lock exists, and if it does, to check its modify time.  If it
+ * is older than 30 seconds, we assume error and set our own file.
+ * Otherwise, we wait for 5 seconds and try again.
+ */
+
+char   *maillock       = ".lock";              /* Lock suffix for mailname */
+char   *lockname       = "/usr/spool/mail/tmXXXXXX";
+char   locktmp[30];                            /* Usable lock temporary */
+char   curlock[50];                            /* Last used name of lock */
+int    locked;                                 /* To note that we locked it */
 
 lock(file)
 char *file;
 {
 
 lock(file)
 char *file;
 {
-       struct stat stbuf;
+       register int f;
+       struct stat sbuf;
+       long curtime;
+       int statfailed;
 
        if (locked || flgf)
 
        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();
+               return(0);
+       strcpy(curlock, file);
+       strcat(curlock, maillock);
+       strcpy(locktmp, lockname);
+       mktemp(locktmp);
+       unlink(locktmp);
+       statfailed = 0;
+       for (;;) {
+               f = lock1(locktmp, curlock);
+               if (f == 0) {
+                       locked = 1;
+                       return(0);
                }
                }
+               if (stat(curlock, &sbuf) < 0) {
+                       if (statfailed++ > 5)
+                               return(-1);
+                       sleep(5);
+                       continue;
+               }
+               statfailed = 0;
+               time(&curtime);
+               if (curtime < sbuf.st_ctime + 30) {
+                       sleep(5);
+                       continue;
+               }
+               unlink(curlock);
        }
        }
-       locked = stbuf.st_mode & ~01;
-       curlock = file;
-       chmod(file, stbuf.st_mode|01);
 }
 
 }
 
+/*
+ * Remove the mail lock, and note that we no longer
+ * have it locked.
+ */
+
 unlock()
 {
 unlock()
 {
-       if (locked)
-               chmod(curlock, locked);
+
+       unlink(curlock);
        locked = 0;
 }
 
        locked = 0;
 }
 
+/*
+ * Attempt to set the lock by creating the temporary file,
+ * then doing a link/unlink.  If it fails, return -1 else 0
+ */
+
+lock1(tempfile, name)
+       char tempfile[], name[];
+{
+       register int fd;
+
+       fd = creat(tempfile, 0);
+       if (fd < 0)
+               return(-1);
+       close(fd);
+       if (link(tempfile, name) < 0) {
+               unlink(tempfile);
+               return(-1);
+       }
+       unlink(tempfile);
+       return(0);
+}
+
+done()
+{
+       if(locked)
+               unlock();
+       unlink(lettmp);
+       unlink(locktmp);
+       exit(error);
+}
+
 cat(to, from1, from2)
 char *to, *from1, *from2;
 {
 cat(to, from1, from2)
 char *to, *from1, *from2;
 {
@@ -552,3 +754,21 @@ register char *s, *p;
        *s = '\0';
        return(p);
 }
        *s = '\0';
        return(p);
 }
+/*
+       stripfx(prefix string, pointer to string)
+
+       takes a ptr to string and compares it to prefix string.
+       may be called multiple times
+*/
+stripfx(pfx, name)
+       char *pfx;
+       char **name;
+{
+       register char *cp = *name;
+
+       while (*pfx && (*cp == *pfx || *cp == toupper(*pfx)))
+               cp++, pfx++;
+       if (*cp != ':' || *pfx != 0)
+               return;
+       *name = cp;
+}