added depend label
[unix-history] / usr / src / usr.bin / vacation / vacation.c
index 534c11e..d1a945e 100644 (file)
@@ -1,11 +1,22 @@
+/*
+**  Vacation
+**  Copyright (c) 1983  Eric P. Allman
+**  Berkeley, California
+**
+**  Copyright (c) 1983 Regents of the University of California.
+**  All rights reserved.  The Berkeley software License Agreement
+**  specifies the terms and conditions for redistribution.
+*/
+
+#ifndef lint
+static char    SccsId[] = "@(#)vacation.c      4.1.1.1 (Berkeley) %G%";
+#endif not lint
+
+# include <sys/types.h>
 # include <pwd.h>
 # include <stdio.h>
 # include <sysexits.h>
 # include <ctype.h>
 # include <pwd.h>
 # include <stdio.h>
 # include <sysexits.h>
 # include <ctype.h>
-# include "useful.h"
-# include "userdbm.h"
-
-SCCSID(@(#)vacation.c  3.9             %G%);
 
 /*
 **  VACATION -- return a message to the sender when on vacation.
 
 /*
 **  VACATION -- return a message to the sender when on vacation.
@@ -16,18 +27,12 @@ SCCSID(@(#)vacation.c       3.9             %G%);
 **     care not to return a message too often to prevent
 **     "I am on vacation" loops.
 **
 **     care not to return a message too often to prevent
 **     "I am on vacation" loops.
 **
-**     For best operation, this program should run setuid to
-**     root or uucp or someone else that sendmail will believe
-**     a -f flag from.  Otherwise, the user must be careful
-**     to include a header on his .vacation.msg file.
-**
 **     Positional Parameters:
 **             the user to collect the vacation message from.
 **
 **     Flag Parameters:
 **             -I      initialize the database.
 **     Positional Parameters:
 **             the user to collect the vacation message from.
 **
 **     Flag Parameters:
 **             -I      initialize the database.
-**             -tT     set the timeout to T.  messages arriving more
-**                     often than T will be ignored to avoid loops.
+**             -d      turn on debugging.
 **
 **     Side Effects:
 **             A message is sent back to the sender.
 **
 **     Side Effects:
 **             A message is sent back to the sender.
@@ -37,18 +42,33 @@ SCCSID(@(#)vacation.c       3.9             %G%);
 **             UCB/INGRES
 */
 
 **             UCB/INGRES
 */
 
+typedef int    bool;
+
+# define TRUE          1
+# define FALSE         0
+
 # define MAXLINE       256     /* max size of a line */
 # define MAXLINE       256     /* max size of a line */
-# define MAXNAME       128     /* max size of one name */
 
 # define ONEWEEK       (60L*60L*24L*7L)
 
 time_t Timeout = ONEWEEK;      /* timeout between notices per user */
 
 
 # define ONEWEEK       (60L*60L*24L*7L)
 
 time_t Timeout = ONEWEEK;      /* timeout between notices per user */
 
-struct dbrec
-{
-       long    sentdate;
+struct dbrec {
+       time_t  sentdate;
 };
 
 };
 
+typedef struct
+{
+       char    *dptr;
+       int     dsize;
+} DATUM;
+
+extern DATUM fetch();
+
+
+
+bool   Debug = FALSE;
+
 main(argc, argv)
        char **argv;
 {
 main(argc, argv)
        char **argv;
 {
@@ -57,11 +77,13 @@ main(argc, argv)
        struct passwd *pw;
        char *homedir;
        char *myname;
        struct passwd *pw;
        char *homedir;
        char *myname;
+       char *shortfrom;
        char buf[MAXLINE];
        extern struct passwd *getpwnam();
        extern char *newstr();
        extern char *getfrom();
        extern bool knows();
        char buf[MAXLINE];
        extern struct passwd *getpwnam();
        extern char *newstr();
        extern char *getfrom();
        extern bool knows();
+       extern bool junkmail();
        extern time_t convtime();
 
        /* process arguments */
        extern time_t convtime();
 
        /* process arguments */
@@ -73,8 +95,8 @@ main(argc, argv)
                        initialize();
                        exit(EX_OK);
 
                        initialize();
                        exit(EX_OK);
 
-                 case 't':     /* set timeout */
-                       Timeout = convtime(++p);
+                 case 'd':     /* debug */
+                       Debug = TRUE;
                        break;
 
                  default:
                        break;
 
                  default:
@@ -105,19 +127,28 @@ main(argc, argv)
        dbminit(buf);
 
        /* read message from standard input (just from line) */
        dbminit(buf);
 
        /* read message from standard input (just from line) */
-       from = getfrom();
-
-       /* check if this person is already informed */
-       if (!knows(from))
+       from = getfrom(&shortfrom);
+#ifdef VDEBUG
+       printf("from='%s'\nshortfrom='%s'\n", from, shortfrom);
+       exit(0);
+#endif
+
+       /* check if junk mail or this person is already informed */
+       if (!junkmail(from) && !knows(from))
        {
                /* mark this person as knowing */
        {
                /* mark this person as knowing */
-               setknows(from);
+               setknows(shortfrom);
 
                /* send the message back */
                (void) strcpy(buf, homedir);
                (void) strcat(buf, "/.vacation.msg");
 
                /* send the message back */
                (void) strcpy(buf, homedir);
                (void) strcat(buf, "/.vacation.msg");
-               sendmessage(buf, from, myname);
-               /* never returns */
+               if (Debug)
+                       printf("Sending %s to %s\n", buf, from);
+               else
+               {
+                       sendmessage(buf, from, myname);
+                       /*NOTREACHED*/
+               }
        }
        exit (EX_OK);
 }
        }
        exit (EX_OK);
 }
@@ -135,10 +166,13 @@ main(argc, argv)
 */
 
 char *
 */
 
 char *
-getfrom()
+getfrom(shortp)
+char **shortp;
 {
        static char line[MAXLINE];
 {
        static char line[MAXLINE];
-       register char *p;
+       register char *p, *start, *at, *bang;
+       char saveat;
+       extern char *index();
 
        /* read the from line */
        if (fgets(line, sizeof line, stdin) == NULL ||
 
        /* read the from line */
        if (fgets(line, sizeof line, stdin) == NULL ||
@@ -149,7 +183,8 @@ getfrom()
        }
 
        /* find the end of the sender address and terminate it */
        }
 
        /* find the end of the sender address and terminate it */
-       p = index(&line[5], ' ');
+       start = &line[5];
+       p = index(start, ' ');
        if (p == NULL)
        {
                usrerr("Funny From line '%s'", line);
        if (p == NULL)
        {
                usrerr("Funny From line '%s'", line);
@@ -157,8 +192,105 @@ getfrom()
        }
        *p = '\0';
 
        }
        *p = '\0';
 
+       /*
+        * Strip all but the rightmost UUCP host
+        * to prevent loops due to forwarding.
+        * Start searching leftward from the leftmost '@'.
+        *      a!b!c!d yields a short name of c!d
+        *      a!b!c!d@e yields a short name of c!d@e
+        *      e@a!b!c yields the same short name
+        */
+#ifdef VDEBUG
+printf("start='%s'\n", start);
+#endif
+       *shortp = start;                        /* assume whole addr */
+       if ((at = index(start, '@')) == NULL)   /* leftmost '@' */
+               at = p;                         /* if none, use end of addr */
+       saveat = *at;
+       *at = '\0';
+       if ((bang = rindex(start, '!')) != NULL) {      /* rightmost '!' */
+               char *bang2;
+
+               *bang = '\0';
+               if ((bang2 = rindex(start, '!')) != NULL) /* 2nd rightmost '!' */
+                       *shortp = bang2 + 1;            /* move past ! */
+               *bang = '!';
+       }
+       *at = saveat;
+#ifdef VDEBUG
+printf("place='%s'\n", *shortp);
+#endif
+
        /* return the sender address */
        /* return the sender address */
-       return (&line[5]);
+       return start;
+}
+\f/*
+**  JUNKMAIL -- read the header and tell us if this is junk/bulk mail.
+**
+**     Parameters:
+**             from -- the Return-Path of the sender.  We assume that
+**                     anything from "*-REQUEST@*" is bulk mail.
+**
+**     Returns:
+**             TRUE -- if this is junk or bulk mail (that is, if the
+**                     sender shouldn't receive a response).
+**             FALSE -- if the sender deserves a response.
+**
+**     Side Effects:
+**             May read the header from standard input.  When this
+**             returns the position on stdin is undefined.
+*/
+
+bool
+junkmail(from)
+       char *from;
+{
+       register char *p;
+       char buf[MAXLINE+1];
+       extern char *index();
+       extern char *rindex();
+       extern bool sameword();
+
+       /* test for inhuman sender */
+       p = rindex(from, '@');
+       if (p != NULL)
+       {
+               *p = '\0';
+               if (sameword(&p[-8],  "-REQUEST") ||
+                   sameword(&p[-10], "Postmaster") ||
+                   sameword(&p[-13], "MAILER-DAEMON"))
+               {
+                       *p = '@';
+                       return (TRUE);
+               }
+               *p = '@';
+       }
+
+       /* read the header looking for a "Precedence:" line */
+       while (fgets(buf, MAXLINE, stdin) != NULL && buf[0] != '\n')
+       {
+               /* should ignore case, but this is reasonably safe */
+               if (strncmp(buf, "Precedence", 10) != 0 ||
+                   !(buf[10] == ':' || buf[10] == ' ' || buf[10] == '\t'))
+               {
+                       continue;
+               }
+
+               /* find the value of this field */
+               p = index(buf, ':');
+               if (p == NULL)
+                       continue;
+               while (*++p != '\0' && isspace(*p))
+                       continue;
+               if (*p == '\0')
+                       continue;
+
+               /* see if it is "junk" or "bulk" */
+               p[4] = '\0';
+               if (sameword(p, "junk") || sameword(p, "bulk"))
+                       return (TRUE);
+       }
+       return (FALSE);
 }
 \f/*
 **  KNOWS -- predicate telling if user has already been informed.
 }
 \f/*
 **  KNOWS -- predicate telling if user has already been informed.
@@ -177,19 +309,30 @@ getfrom()
 
 bool
 knows(user)
 
 bool
 knows(user)
-       char *user;
+char *user;
 {
        DATUM k, d;
 {
        DATUM k, d;
-       long now;
+       struct dbrec ldbrec;
+       auto long then;
 
 
-       time(&now);
        k.dptr = user;
        k.dsize = strlen(user) + 1;
        d = fetch(k);
        k.dptr = user;
        k.dsize = strlen(user) + 1;
        d = fetch(k);
-       if (d.dptr == NULL || ((struct dbrec *) d.dptr)->sentdate + Timeout < now)
-               return (FALSE);
-       return (TRUE);
+       if (d.dptr == NULL)
+               return FALSE;
+       bcopy(d.dptr, (char *)&ldbrec, sizeof ldbrec);  /* realign data */
+       return ldbrec.sentdate + Timeout >= time((time_t *)0);
 }
 }
+
+#ifndef VMUNIX
+bcopy(from, to, size)
+register char *to, *from;
+register unsigned size;
+{
+       while (size-- > 0)
+               *to++ = *from++;
+}
+#endif
 \f/*
 **  SETKNOWS -- set that this user knows about the vacation.
 **
 \f/*
 **  SETKNOWS -- set that this user knows about the vacation.
 **
@@ -267,6 +410,7 @@ initialize()
 {
        char *homedir;
        char buf[MAXLINE];
 {
        char *homedir;
        char buf[MAXLINE];
+       extern char *getenv();
 
        setgid(getgid());
        setuid(getuid());
 
        setgid(getgid());
        setuid(getuid());
@@ -296,6 +440,7 @@ initialize()
 **             none.
 */
 
 **             none.
 */
 
+/* VARARGS 1 */
 usrerr(f, p)
        char *f;
        char *p;
 usrerr(f, p)
        char *f;
        char *p;
@@ -318,6 +463,7 @@ usrerr(f, p)
 **             none.
 */
 
 **             none.
 */
 
+/* VARARGS 1 */
 syserr(f, p)
        char *f;
        char *p;
 syserr(f, p)
        char *f;
        char *p;
@@ -345,13 +491,47 @@ newstr(s)
        char *s;
 {
        char *p;
        char *s;
 {
        char *p;
+       extern char *malloc();
 
 
-       p = malloc(strlen(s) + 1);
+       p = malloc((unsigned)strlen(s) + 1);
        if (p == NULL)
        {
                syserr("newstr: cannot alloc memory");
                exit(EX_OSERR);
        }
        strcpy(p, s);
        if (p == NULL)
        {
                syserr("newstr: cannot alloc memory");
                exit(EX_OSERR);
        }
        strcpy(p, s);
-       return (p);
+       return p;
+}
+\f/*
+**  SAMEWORD -- return TRUE if the words are the same
+**
+**     Ignores case.
+**
+**     Parameters:
+**             a, b -- the words to compare.
+**
+**     Returns:
+**             TRUE if a & b match exactly (modulo case)
+**             FALSE otherwise.
+**
+**     Side Effects:
+**             none.
+*/
+
+bool
+sameword(a, b)
+       register char *a, *b;
+{
+       char ca, cb;
+
+       do
+       {
+               ca = *a++;
+               cb = *b++;
+               if (isascii(ca) && isupper(ca))
+                       ca = ca - 'A' + 'a';
+               if (isascii(cb) && isupper(cb))
+                       cb = cb - 'A' + 'a';
+       } while (ca != '\0' && ca == cb);
+       return (ca == cb);
 }
 }