diff options
Diffstat (limited to 'contrib/sendmail/vacation')
-rwxr-xr-x | contrib/sendmail/vacation/Build | 13 | ||||
-rw-r--r-- | contrib/sendmail/vacation/Makefile | 17 | ||||
-rw-r--r-- | contrib/sendmail/vacation/Makefile.m4 | 19 | ||||
-rw-r--r-- | contrib/sendmail/vacation/vacation.1 | 200 | ||||
-rw-r--r-- | contrib/sendmail/vacation/vacation.c | 1015 |
5 files changed, 1264 insertions, 0 deletions
diff --git a/contrib/sendmail/vacation/Build b/contrib/sendmail/vacation/Build new file mode 100755 index 0000000..fbd060c --- /dev/null +++ b/contrib/sendmail/vacation/Build @@ -0,0 +1,13 @@ +#!/bin/sh + +# Copyright (c) 1999 Sendmail, Inc. and its suppliers. +# All rights reserved. +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the sendmail distribution. +# +# +# $Id: Build,v 8.2 1999/03/02 02:35:21 peterh Exp $ + +exec ../devtools/bin/Build $* diff --git a/contrib/sendmail/vacation/Makefile b/contrib/sendmail/vacation/Makefile new file mode 100644 index 0000000..7cc577f --- /dev/null +++ b/contrib/sendmail/vacation/Makefile @@ -0,0 +1,17 @@ +# $Id: Makefile,v 8.5 1999/09/23 22:36:45 ca Exp $ + +SHELL= /bin/sh +BUILD= ./Build +OPTIONS= $(CONFIG) $(FLAGS) + +all: FRC + $(SHELL) $(BUILD) $(OPTIONS) $@ +clean: FRC + $(SHELL) $(BUILD) $(OPTIONS) $@ +install: FRC + $(SHELL) $(BUILD) $(OPTIONS) $@ + +fresh: FRC + $(SHELL) $(BUILD) $(OPTIONS) -c + +FRC: diff --git a/contrib/sendmail/vacation/Makefile.m4 b/contrib/sendmail/vacation/Makefile.m4 new file mode 100644 index 0000000..71430eb --- /dev/null +++ b/contrib/sendmail/vacation/Makefile.m4 @@ -0,0 +1,19 @@ +include(confBUILDTOOLSDIR`/M4/switch.m4') + +# sendmail dir +SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail') +PREPENDDEF(`confENVDEF', `confMAPDEF') +PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ') + +bldPRODUCT_START(`executable', `vacation') +define(`bldSOURCES', `vacation.c ') +bldPUSH_SMLIB(`smutil') +bldPUSH_SMLIB(`smdb') +APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL') +bldPRODUCT_END + +bldPRODUCT_START(`manpage', `vacation') +define(`bldSOURCES', `vacation.1') +bldPRODUCT_END + +bldFINISH diff --git a/contrib/sendmail/vacation/vacation.1 b/contrib/sendmail/vacation/vacation.1 new file mode 100644 index 0000000..54bb674 --- /dev/null +++ b/contrib/sendmail/vacation/vacation.1 @@ -0,0 +1,200 @@ +.\" Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. +.\" All rights reserved. +.\" Copyright (c) 1985, 1987, 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" +.\" By using this file, you agree to the terms and conditions set +.\" forth in the LICENSE file which can be found at the top level of +.\" the sendmail distribution. +.\" +.\" +.\" $Id: vacation.1,v 8.11 2000/03/17 07:32:50 gshapiro Exp $ +.\" +.TH VACATION 1 "$Date: 2000/03/17 07:32:50 $" +.SH NAME +.B vacation +\- return ``I am not here'' indication +.SH SYNOPSIS +.B vacation +.B \-i +.RB [ \-r +.IR interval ] +.RB [ \-x ] +.B vacation +.RB [ \-a +.IR alias ] +.RB [ \-f +.IR database ] +.RB [ \-m +.IR message ] +.RB [ \-s +.IR address ] +.RB [ \-t +.IR time ] +.RB [ \-z ] +.I login +.SH DESCRIPTION +.B Vacation +returns a message to the sender of a message telling them that you +are currently not reading your mail. The intended use is in a +.I .forward +file. For example, your +.I .forward +file might have: +.IP +\eeric, "|/usr/bin/vacation -a allman eric" +.PP +which would send messages to you (assuming your login name was eric) and +reply to any messages for +``eric'' +or +``allman''. +.PP +Available options: +.TP +.BI \-a " alias" +Handle messages for +.Ar alias +in the same manner as those received for the user's +login name. +.TP +.BI \-f " filename" +Use +.I filename +as name of the database instead of +.IR ~/.vacation.db . +Unless the +.I filename +starts with / it is relative to ~. +.TP +.B \-i +Initialize the vacation database files. It should be used +before you modify your +.I .forward +file. +.TP +.BI \-m " filename" +Use +.I filename +as name of the file containing the message to send instead of +.IR ~/.vacation.msg . +Unless the +.I filename +starts with / it is relative to ~. +.TP +.BI \-r " interval" +Set the reply interval to +.I interval +days. The default is one week. +An interval of ``0'' or +``infinite'' +(actually, any non-numeric character) will never send more than +one reply. +.TP +.BI \-s " address" +Use +.I address +instead of the sender address in the +.I From +line to determine the reply address. +.TP +.BI \-t " time" +Ignored, available only for compatibility with Sun's +vacation program. +.TP +.B \-x +reads an exclusion list from stdin (one address per line). +Mails coming from an address +in this exclusion list won't get a reply by +.BR vacation . +It is possible to exclude complete domains by specifying +``@domain'' +as element of the exclusion list. +.TP +.B \-z +Set the sender of the vacation message to +``<>'' +instead of the user. +This probably violates the RFCs since vacation messages are +not required by a standards-track RFC to have a null reverse-path. +.PP +No message will be sent unless +.I login +(or an +.I alias +supplied using the +.B \-a +option) is part of either the +``To:'' +or +``Cc:'' +headers of the mail. +No messages from +``???-REQUEST'', +``Postmaster'', +``UUCP'', +``MAILER'', +or +``MAILER-DAEMON'' +will be replied to (where these strings are +case insensitive) nor is a notification sent if a +``Precedence: bulk'' +or +``Precedence: junk'' +line is included in the mail headers. +The people who have sent you messages are maintained as a +db(3) +database in the file +.I .vacation.db +in your home directory. +.PP +.B Vacation +expects a file +.IR .vacation.msg , +in your home directory, containing a message to be sent back to each +sender. It should be an entire message (including headers). For +example, it might contain: +.IP +.nf +From: eric@CS.Berkeley.EDU (Eric Allman) +Subject: I am on vacation +Delivered-By-The-Graces-Of: The Vacation program +Precedence: bulk + +I am on vacation until July 22. If you have something urgent, +please contact Keith Bostic <bostic@CS.Berkeley.EDU>. +--eric +.fi +.PP +.B Vacation +reads the first line from the standard input for a +UNIX +``From'' +line to determine the sender. +Sendmail(8) +includes this +``From'' +line automatically. +.PP +Fatal errors, such as calling +.B vacation +with incorrect arguments, or with non-existent +.IR login s, +are logged in the system log file, using +syslog(8). +.SH FILES +.TP 1.8i +~/.vacation.db +database file +.TP +~/.vacation.msg +message to send +.SH SEE ALSO +sendmail(8), +syslog(8) +.SH HISTORY +The +.B vacation +command appeared in +4.3BSD. diff --git a/contrib/sendmail/vacation/vacation.c b/contrib/sendmail/vacation/vacation.c new file mode 100644 index 0000000..d1c21e9 --- /dev/null +++ b/contrib/sendmail/vacation/vacation.c @@ -0,0 +1,1015 @@ +/* + * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. + * All rights reserved. + * Copyright (c) 1983, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1983 Eric P. Allman. All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ + All rights reserved.\n\ + Copyright (c) 1983, 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n\ + Copyright (c) 1983 Eric P. Allman. All rights reserved.\n"; +#endif /* ! lint */ + +#ifndef lint +static char id[] = "@(#)$Id: vacation.c,v 8.68.4.4 2000/07/18 05:10:29 gshapiro Exp $"; +#endif /* ! lint */ + +#include <ctype.h> +#include <stdlib.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> +#ifdef EX_OK +# undef EX_OK /* unistd.h may have another use for this */ +#endif /* EX_OK */ +#include <sysexits.h> + +#include "sendmail/sendmail.h" +#include "libsmdb/smdb.h" + +#if defined(__hpux) && !defined(HPUX11) +# undef syslog /* Undo hard_syslog conf.h change */ +#endif /* defined(__hpux) && !defined(HPUX11) */ + +#ifndef _PATH_SENDMAIL +# define _PATH_SENDMAIL "/usr/lib/sendmail" +#endif /* ! _PATH_SENDMAIL */ + +#define ONLY_ONCE ((time_t) 0) /* send at most one reply */ +#define INTERVAL_UNDEF ((time_t) (-1)) /* no value given */ + +uid_t RealUid; +gid_t RealGid; +char *RealUserName; +uid_t RunAsUid; +uid_t RunAsGid; +char *RunAsUserName; +int Verbose = 2; +bool DontInitGroups = FALSE; +uid_t TrustedUid = 0; +BITMAP256 DontBlameSendmail; + +/* +** VACATION -- return a message to the sender when on vacation. +** +** This program is invoked as a message receiver. It returns a +** message specified by the user to whomever sent the mail, taking +** care not to return a message too often to prevent "I am on +** vacation" loops. +*/ + +#define VDB ".vacation" /* vacation database */ +#define VMSG ".vacation.msg" /* vacation message */ +#define SECSPERDAY (60 * 60 * 24) +#define DAYSPERWEEK 7 + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif /* ! TRUE */ + +#ifndef __P +# ifdef __STDC__ +# define __P(protos) protos +# else /* __STDC__ */ +# define __P(protos) () +# define const +# endif /* __STDC__ */ +#endif /* ! __P */ + +typedef struct alias +{ + char *name; + struct alias *next; +} ALIAS; + +ALIAS *Names = NULL; + +SMDB_DATABASE *Db; + +char From[MAXLINE]; + +#if _FFR_DEBUG +void (*msglog)(int, const char *, ...) = &syslog; +static void debuglog __P((int, const char *, ...)); +#else /* _FFR_DEBUG */ +# define msglog syslog +#endif /* _FFR_DEBUG */ + +int +main(argc, argv) + int argc; + char **argv; +{ + bool iflag, emptysender, exclude; +#if _FFR_LISTDB + bool lflag = FALSE; +#endif /* _FFR_LISTDB */ + int mfail = 0, ufail = 0; + int ch; + int result; + time_t interval; + struct passwd *pw; + ALIAS *cur; + char *dbfilename = VDB; + char *msgfilename = VMSG; + char *name; + SMDB_USER_INFO user_info; + static char rnamebuf[MAXNAME]; + extern int optind, opterr; + extern char *optarg; + extern void usage __P((void)); + extern void setinterval __P((time_t)); + extern void readheaders __P((void)); + extern bool recent __P((void)); + extern void setreply __P((char *, time_t)); + extern void sendmessage __P((char *, char *, bool)); + extern void xclude __P((FILE *)); + + /* Vars needed to link with smutil */ + clrbitmap(DontBlameSendmail); + RunAsUid = RealUid = getuid(); + RunAsGid = RealGid = getgid(); + pw = getpwuid(RealUid); + if (pw != NULL) + { + if (strlen(pw->pw_name) > MAXNAME - 1) + pw->pw_name[MAXNAME] = '\0'; + snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); + } + else + snprintf(rnamebuf, sizeof rnamebuf, + "Unknown UID %d", (int) RealUid); + RunAsUserName = RealUserName = rnamebuf; + +#ifdef LOG_MAIL + openlog("vacation", LOG_PID, LOG_MAIL); +#else /* LOG_MAIL */ + openlog("vacation", LOG_PID); +#endif /* LOG_MAIL */ + + opterr = 0; + iflag = FALSE; + emptysender = FALSE; + exclude = FALSE; + interval = INTERVAL_UNDEF; + *From = '\0'; + +#if _FFR_DEBUG && _FFR_LISTDB +# define OPTIONS "a:df:Iilm:r:s:t:xz" +#else /* _FFR_DEBUG && _FFR_LISTDB */ +# if _FFR_DEBUG +# define OPTIONS "a:df:Iim:r:s:t:xz" +# else /* _FFR_DEBUG */ +# if _FFR_LISTDB +# define OPTIONS "a:f:Iilm:r:s:t:xz" +# else /* _FFR_LISTDB */ +# define OPTIONS "a:f:Iim:r:s:t:xz" +# endif /* _FFR_LISTDB */ +# endif /* _FFR_DEBUG */ +#endif /* _FFR_DEBUG && _FFR_LISTDB */ + + while (mfail == 0 && ufail == 0 && + (ch = getopt(argc, argv, OPTIONS)) != -1) + { + switch((char)ch) + { + case 'a': /* alias */ + cur = (ALIAS *)malloc((u_int)sizeof(ALIAS)); + if (cur == NULL) + { + mfail++; + break; + } + cur->name = optarg; + cur->next = Names; + Names = cur; + break; + +#if _FFR_DEBUG + case 'd': /* debug mode */ + msglog = &debuglog; + break; +#endif /* _FFR_DEBUG */ + + + case 'f': /* alternate database */ + dbfilename = optarg; + break; + + case 'I': /* backward compatible */ + case 'i': /* init the database */ + iflag = TRUE; + break; + +#if _FFR_LISTDB + case 'l': + lflag = TRUE; /* list the database */ + break; +#endif /* _FFR_LISTDB */ + + case 'm': /* alternate message file */ + msgfilename = optarg; + break; + + case 'r': + if (isascii(*optarg) && isdigit(*optarg)) + { + interval = atol(optarg) * SECSPERDAY; + if (interval < 0) + ufail++; + } + else + interval = ONLY_ONCE; + break; + + case 's': /* alternate sender name */ + (void) strlcpy(From, optarg, sizeof From); + break; + + case 't': /* SunOS: -t1d (default expire) */ + break; + + case 'x': + exclude = TRUE; + break; + + case 'z': + emptysender = TRUE; + break; + + case '?': + default: + ufail++; + break; + } + } + argc -= optind; + argv += optind; + + if (mfail != 0) + { + msglog(LOG_NOTICE, + "vacation: can't allocate memory for alias.\n"); + exit(EX_TEMPFAIL); + } + if (ufail != 0) + usage(); + + if (argc != 1) + { + if (!iflag && +#if _FFR_LISTDB + !lflag && +#endif /* _FFR_LISTDB */ + !exclude) + usage(); + if ((pw = getpwuid(getuid())) == NULL) + { + msglog(LOG_ERR, + "vacation: no such user uid %u.\n", getuid()); + exit(EX_NOUSER); + } + } +#if _FFR_BLACKBOX + name = *argv; +#else /* _FFR_BLACKBOX */ + else if ((pw = getpwnam(*argv)) == NULL) + { + msglog(LOG_ERR, "vacation: no such user %s.\n", *argv); + exit(EX_NOUSER); + } + name = pw->pw_name; + if (chdir(pw->pw_dir) != 0) + { + msglog(LOG_NOTICE, + "vacation: no such directory %s.\n", pw->pw_dir); + exit(EX_NOINPUT); + } +#endif /* _FFR_BLACKBOX */ + user_info.smdbu_id = pw->pw_uid; + user_info.smdbu_group_id = pw->pw_gid; + (void) strlcpy(user_info.smdbu_name, pw->pw_name, + SMDB_MAX_USER_NAME_LEN); + + result = smdb_open_database(&Db, dbfilename, + O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0), + S_IRUSR|S_IWUSR, SFF_CREAT, + SMDB_TYPE_DEFAULT, &user_info, NULL); + if (result != SMDBE_OK) + { + msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename, + errstring(result)); + exit(EX_DATAERR); + } + +#if _FFR_LISTDB + if (lflag) + { + static void listdb __P((void)); + + listdb(); + (void)Db->smdb_close(Db); + exit(EX_OK); + } +#endif /* _FFR_LISTDB */ + + if (interval != INTERVAL_UNDEF) + setinterval(interval); + + if (iflag) + { + result = Db->smdb_close(Db); + if (!exclude) + exit(EX_OK); + } + + if (exclude) + { + xclude(stdin); + result = Db->smdb_close(Db); + exit(EX_OK); + } + + if ((cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))) == NULL) + { + msglog(LOG_NOTICE, + "vacation: can't allocate memory for username.\n"); + exit(EX_OSERR); + } + cur->name = name; + cur->next = Names; + Names = cur; + + readheaders(); + if (!recent()) + { + time_t now; + + (void) time(&now); + setreply(From, now); + result = Db->smdb_close(Db); + sendmessage(name, msgfilename, emptysender); + } + else + result = Db->smdb_close(Db); + exit(EX_OK); + /* NOTREACHED */ + return EX_OK; +} + +/* +** READHEADERS -- read mail headers +** +** Parameters: +** none. +** +** Returns: +** nothing. +** +*/ +void +readheaders() +{ + bool tome, cont; + register char *p; + register ALIAS *cur; + char buf[MAXLINE]; + extern bool junkmail __P((char *)); + extern bool nsearch __P((char *, char *)); + + cont = tome = FALSE; + while (fgets(buf, sizeof(buf), stdin) && *buf != '\n') + { + switch(*buf) + { + case 'F': /* "From " */ + cont = FALSE; + if (strncmp(buf, "From ", 5) == 0) + { + bool quoted = FALSE; + + p = buf + 5; + while (*p != '\0') + { + /* escaped character */ + if (*p == '\\') + { + p++; + if (*p == '\0') + { + msglog(LOG_NOTICE, + "vacation: badly formatted \"From \" line.\n"); + exit(EX_DATAERR); + } + } + else if (*p == '"') + quoted = !quoted; + else if (*p == '\r' || *p == '\n') + break; + else if (*p == ' ' && !quoted) + break; + p++; + } + if (quoted) + { + msglog(LOG_NOTICE, + "vacation: badly formatted \"From \" line.\n"); + exit(EX_DATAERR); + } + *p = '\0'; + + /* ok since both strings have MAXLINE length */ + if (*From == '\0') + (void)strlcpy(From, buf + 5, + sizeof From); + if ((p = strchr(buf + 5, '\n')) != NULL) + *p = '\0'; + if (junkmail(buf + 5)) + exit(EX_OK); + } + break; + + case 'P': /* "Precedence:" */ + case 'p': + cont = FALSE; + if (strlen(buf) <= 10 || + strncasecmp(buf, "Precedence", 10) != 0 || + (buf[10] != ':' && buf[10] != ' ' && + buf[10] != '\t')) + break; + if ((p = strchr(buf, ':')) == NULL) + break; + while (*++p != '\0' && isascii(*p) && isspace(*p)); + if (*p == '\0') + break; + if (strncasecmp(p, "junk", 4) == 0 || + strncasecmp(p, "bulk", 4) == 0 || + strncasecmp(p, "list", 4) == 0) + exit(EX_OK); + break; + + case 'C': /* "Cc:" */ + case 'c': + if (strncasecmp(buf, "Cc:", 3) != 0) + break; + cont = TRUE; + goto findme; + + case 'T': /* "To:" */ + case 't': + if (strncasecmp(buf, "To:", 3) != 0) + break; + cont = TRUE; + goto findme; + + default: + if (!isascii(*buf) || !isspace(*buf) || !cont || tome) + { + cont = FALSE; + break; + } +findme: + for (cur = Names; + !tome && cur != NULL; + cur = cur->next) + tome = nsearch(cur->name, buf); + } + } + if (!tome) + exit(EX_OK); + if (*From == '\0') + { + msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n"); + exit(EX_DATAERR); + } +} + +/* +** NSEARCH -- +** do a nice, slow, search of a string for a substring. +** +** Parameters: +** name -- name to search. +** str -- string in which to search. +** +** Returns: +** is name a substring of str? +** +*/ +bool +nsearch(name, str) + register char *name, *str; +{ + register size_t len; + register char *s; + + len = strlen(name); + + for (s = str; *s != '\0'; ++s) + { + /* + ** Check to make sure that the string matches and + ** the previous character is not an alphanumeric and + ** the next character after the match is not an alphanumeric. + ** + ** This prevents matching "eric" to "derick" while still + ** matching "eric" to "<eric+detail>". + */ + + if (tolower(*s) == tolower(*name) && + strncasecmp(name, s, len) == 0 && + (s == str || !isascii(*(s - 1)) || !isalnum(*(s - 1))) && + (!isascii(*(s + len)) || !isalnum(*(s + len)))) + return TRUE; + } + return FALSE; +} + +/* +** JUNKMAIL -- +** read the header and return if automagic/junk/bulk/list mail +** +** Parameters: +** from -- sender address. +** +** Returns: +** is this some automated/junk/bulk/list mail? +** +*/ +bool +junkmail(from) + char *from; +{ + register size_t len; + register char *p; + register struct ignore *cur; + static struct ignore + { + char *name; + size_t len; + } ignore[] = + { + { "-request", 8 }, + { "postmaster", 10 }, + { "uucp", 4 }, + { "mailer-daemon", 13 }, + { "mailer", 6 }, + { "-relay", 6 }, + { NULL, 0 } + }; + + /* + * This is mildly amusing, and I'm not positive it's right; trying + * to find the "real" name of the sender, assuming that addresses + * will be some variant of: + * + * From site!site!SENDER%site.domain%site.domain@site.domain + */ + if ((p = strchr(from, '%')) == NULL && + (p = strchr(from, '@')) == NULL) + { + if ((p = strrchr(from, '!')) != NULL) + ++p; + else + p = from; + for (; *p; ++p) + continue; + } + len = p - from; + for (cur = ignore; cur->name != NULL; ++cur) + { + if (len >= cur->len && + strncasecmp(cur->name, p - cur->len, cur->len) == 0) + return TRUE; + } + return FALSE; +} + +#define VIT "__VACATION__INTERVAL__TIMER__" + +/* +** RECENT -- +** find out if user has gotten a vacation message recently. +** +** Parameters: +** none. +** +** Returns: +** TRUE iff user has gotten a vacation message recently. +** +*/ +bool +recent() +{ + SMDB_DBENT key, data; + time_t then, next; + bool trydomain = FALSE; + int st; + char *domain; + + memset(&key, '\0', sizeof key); + memset(&data, '\0', sizeof data); + + /* get interval time */ + key.data.data = VIT; + key.data.size = sizeof(VIT); + + st = Db->smdb_get(Db, &key, &data, 0); + if (st != SMDBE_OK) + next = SECSPERDAY * DAYSPERWEEK; + else + memmove(&next, data.data.data, sizeof(next)); + + memset(&data, '\0', sizeof data); + + /* get record for this address */ + key.data.data = From; + key.data.size = strlen(From); + + do + { + st = Db->smdb_get(Db, &key, &data, 0); + if (st == SMDBE_OK) + { + memmove(&then, data.data.data, sizeof(then)); + if (next == ONLY_ONCE || then == ONLY_ONCE || + then + next > time(NULL)) + return TRUE; + } + if ((trydomain = !trydomain) && + (domain = strchr(From, '@')) != NULL) + { + key.data.data = domain; + key.data.size = strlen(domain); + } + } while (trydomain); + return FALSE; +} + +/* +** SETINTERVAL -- +** store the reply interval +** +** Parameters: +** interval -- time interval for replies. +** +** Returns: +** nothing. +** +** Side Effects: +** stores the reply interval in database. +*/ +void +setinterval(interval) + time_t interval; +{ + SMDB_DBENT key, data; + + memset(&key, '\0', sizeof key); + memset(&data, '\0', sizeof data); + + key.data.data = VIT; + key.data.size = sizeof(VIT); + data.data.data = (char*) &interval; + data.data.size = sizeof(interval); + (void)(Db->smdb_put)(Db, &key, &data, 0); +} + +/* +** SETREPLY -- +** store that this user knows about the vacation. +** +** Parameters: +** from -- sender address. +** when -- last reply time. +** +** Returns: +** nothing. +** +** Side Effects: +** stores user/time in database. +*/ +void +setreply(from, when) + char *from; + time_t when; +{ + SMDB_DBENT key, data; + + memset(&key, '\0', sizeof key); + memset(&data, '\0', sizeof data); + + key.data.data = from; + key.data.size = strlen(from); + data.data.data = (char*) &when; + data.data.size = sizeof(when); + (void)(Db->smdb_put)(Db, &key, &data, 0); +} + +/* +** XCLUDE -- +** add users to vacation db so they don't get a reply. +** +** Parameters: +** f -- file pointer with list of address to exclude +** +** Returns: +** nothing. +** +** Side Effects: +** stores users in database. +*/ +void +xclude(f) + FILE *f; +{ + char buf[MAXLINE], *p; + + if (f == NULL) + return; + while (fgets(buf, sizeof buf, f)) + { + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; + setreply(buf, ONLY_ONCE); + } +} + +/* +** SENDMESSAGE -- +** exec sendmail to send the vacation file to sender +** +** Parameters: +** myname -- user name. +** msgfn -- name of file with vacation message. +** emptysender -- use <> as sender address? +** +** Returns: +** nothing. +** +** Side Effects: +** sends vacation reply. +*/ +void +sendmessage(myname, msgfn, emptysender) + char *myname; + char *msgfn; + bool emptysender; +{ + FILE *mfp, *sfp; + int i; + int pvect[2]; + char buf[MAXLINE]; + + mfp = fopen(msgfn, "r"); + if (mfp == NULL) + { + if (msgfn[0] == '/') + msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn); + else + msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", + myname, msgfn); + exit(EX_NOINPUT); + } + if (pipe(pvect) < 0) + { + msglog(LOG_ERR, "vacation: pipe: %s", errstring(errno)); + exit(EX_OSERR); + } + i = fork(); + if (i < 0) + { + msglog(LOG_ERR, "vacation: fork: %s", errstring(errno)); + exit(EX_OSERR); + } + if (i == 0) + { + (void) dup2(pvect[0], 0); + (void) close(pvect[0]); + (void) close(pvect[1]); + (void) fclose(mfp); + if (emptysender) + myname = "<>"; + (void) execl(_PATH_SENDMAIL, "sendmail", "-f", myname, "--", + From, NULL); + msglog(LOG_ERR, "vacation: can't exec %s: %s", + _PATH_SENDMAIL, errstring(errno)); + exit(EX_UNAVAILABLE); + } + /* check return status of the following calls? XXX */ + (void) close(pvect[0]); + if ((sfp = fdopen(pvect[1], "w")) != NULL) + { + (void) fprintf(sfp, "To: %s\n", From); + (void) fprintf(sfp, "Auto-Submitted: auto-generated\n"); + while (fgets(buf, sizeof buf, mfp)) + (void) fputs(buf, sfp); + (void) fclose(mfp); + (void) fclose(sfp); + } + else + { + (void) fclose(mfp); + msglog(LOG_ERR, "vacation: can't open pipe to sendmail"); + exit(EX_UNAVAILABLE); + } +} + +void +usage() +{ + msglog(LOG_NOTICE, "uid %u: usage: vacation [-i] [-a alias]%s [-f db]%s [-m msg] [-r interval] [-s sender] [-t time] [-x] [-z] login\n", + getuid(), +#if _FFR_DEBUG + " [-d]", +#else /* _FFR_DEBUG */ + "", +#endif /* _FFR_DEBUG */ +#if _FFR_LISTDB + " [-l]" +#else /* _FFR_LISTDB */ + "" +#endif /* _FFR_LISTDB */ + ); + exit(EX_USAGE); +} + +#if _FFR_LISTDB +/* +** LISTDB -- list the contents of the vacation database +** +** Parameters: +** none. +** +** Returns: +** nothing. +*/ + +static void +listdb() +{ + int result; + time_t t; + SMDB_CURSOR *cursor = NULL; + SMDB_DBENT db_key, db_value; + + memset(&db_key, '\0', sizeof db_key); + memset(&db_value, '\0', sizeof db_value); + + result = Db->smdb_cursor(Db, &cursor, 0); + if (result != SMDBE_OK) + { + fprintf(stderr, "vacation: set cursor: %s\n", + errstring(result)); + return; + } + + while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, + SMDB_CURSOR_GET_NEXT)) == SMDBE_OK) + { + /* skip magic VIT entry */ + if ((int)db_key.data.size -1 == strlen(VIT) && + strncmp((char *)db_key.data.data, VIT, + (int)db_key.data.size - 1) == 0) + continue; + + /* skip bogus values */ + if (db_value.data.size != sizeof t) + { + fprintf(stderr, "vacation: %.*s invalid time stamp\n", + (int) db_key.data.size, + (char *) db_key.data.data); + continue; + } + + memcpy(&t, db_value.data.data, sizeof t); + + if (db_key.data.size > 40) + db_key.data.size = 40; + + printf("%-40.*s %-10s", + (int) db_key.data.size, (char *) db_key.data.data, + ctime(&t)); + + memset(&db_key, '\0', sizeof db_key); + memset(&db_value, '\0', sizeof db_value); + } + + if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) + { + fprintf(stderr, "vacation: get value at cursor: %s\n", + errstring(result)); + if (cursor != NULL) + { + (void) cursor->smdbc_close(cursor); + cursor = NULL; + } + return; + } + (void) cursor->smdbc_close(cursor); + cursor = NULL; +} +#endif /* _FFR_LISTDB */ + +#if _FFR_DEBUG +/* +** DEBUGLOG -- write message to standard error +** +** Append a message to the standard error for the convenience of +** end-users debugging without access to the syslog messages. +** +** Parameters: +** i -- syslog log level +** fmt -- string format +** +** Returns: +** nothing. +*/ + +/*VARARGS2*/ +static void +#ifdef __STDC__ +debuglog(int i, const char *fmt, ...) +#else /* __STDC__ */ +debuglog(i, fmt, va_alist) + int i; + const char *fmt; + va_dcl +#endif /* __STDC__ */ + +{ + VA_LOCAL_DECL + + VA_START(fmt); + vfprintf(stderr, fmt, ap); + VA_END; +} +#endif /* _FFR_DEBUG */ + +/*VARARGS1*/ +void +#ifdef __STDC__ +message(const char *msg, ...) +#else /* __STDC__ */ +message(msg, va_alist) + const char *msg; + va_dcl +#endif /* __STDC__ */ +{ + const char *m; + VA_LOCAL_DECL + + m = msg; + if (isascii(m[0]) && isdigit(m[0]) && + isascii(m[1]) && isdigit(m[1]) && + isascii(m[2]) && isdigit(m[2]) && m[3] == ' ') + m += 4; + VA_START(msg); + (void) vfprintf(stderr, m, ap); + VA_END; + (void) fprintf(stderr, "\n"); +} + +/*VARARGS1*/ +void +#ifdef __STDC__ +syserr(const char *msg, ...) +#else /* __STDC__ */ +syserr(msg, va_alist) + const char *msg; + va_dcl +#endif /* __STDC__ */ +{ + const char *m; + VA_LOCAL_DECL + + m = msg; + if (isascii(m[0]) && isdigit(m[0]) && + isascii(m[1]) && isdigit(m[1]) && + isascii(m[2]) && isdigit(m[2]) && m[3] == ' ') + m += 4; + VA_START(msg); + (void) vfprintf(stderr, m, ap); + VA_END; + (void) fprintf(stderr, "\n"); +} + +void +dumpfd(fd, printclosed, logit) + int fd; + bool printclosed; + bool logit; +{ + return; +} |