trivial pathname changes
[unix-history] / usr / src / usr.bin / vacation / vacation.c
CommitLineData
de4d1f2e
KB
1/*
2 * Copyright (c) 1983, 1987 Regents of the University of California.
3 * All rights reserved.
4 *
32ce521f 5 * %sccs.include.redist.c%
de4d1f2e
KB
6 */
7
8#ifndef lint
9char copyright[] =
10"@(#) Copyright (c) 1983, 1987 Regents of the University of California.\n\
11 All rights reserved.\n";
12#endif /* not lint */
13
14#ifndef lint
32ce521f 15static char sccsid[] = "@(#)vacation.c 5.17 (Berkeley) %G%";
de4d1f2e
KB
16#endif /* not lint */
17
d9e2d747
EA
18/*
19** Vacation
20** Copyright (c) 1983 Eric P. Allman
21** Berkeley, California
d9e2d747
EA
22*/
23
87338d3e
KB
24#include <sys/param.h>
25#include <sys/file.h>
26#include <pwd.h>
72d85c41
KB
27#include <ndbm.h>
28#include <syslog.h>
29#include <tzfile.h>
87338d3e
KB
30#include <stdio.h>
31#include <ctype.h>
d3fb15e8 32#include <paths.h>
d34d58b1 33
d34d58b1 34/*
72d85c41
KB
35 * VACATION -- return a message to the sender when on vacation.
36 *
37 * This program is invoked as a message receiver. It returns a
38 * message specified by the user to whomever sent the mail, taking
39 * care not to return a message too often to prevent "I am on
40 * vacation" loops.
41 */
d34d58b1 42
87338d3e 43#define MAXLINE 500 /* max line from mail header */
de4d1f2e 44#define VMSG ".vacation.msg" /* vacation message */
87338d3e
KB
45#define VACAT ".vacation" /* dbm's database prefix */
46#define VDIR ".vacation.dir" /* dbm's DB prefix, part 1 */
87338d3e
KB
47#define VPAG ".vacation.pag" /* dbm's DB prefix, part 2 */
48
de4d1f2e
KB
49typedef struct alias {
50 struct alias *next;
72d85c41 51 char *name;
de4d1f2e 52} ALIAS;
72d85c41 53ALIAS *names;
351c396d 54
72d85c41
KB
55static DBM *db;
56
57extern int errno;
58
c7a6495b 59static char *VIT = "__VACATION__INTERVAL__TIMER__";
72d85c41 60static char from[MAXLINE];
351c396d 61
d34d58b1 62main(argc, argv)
de4d1f2e
KB
63 int argc;
64 char **argv;
d34d58b1 65{
72d85c41 66 extern int optind, opterr;
de4d1f2e
KB
67 extern char *optarg;
68 struct passwd *pw;
69 ALIAS *cur;
72d85c41 70 time_t interval;
de4d1f2e
KB
71 int ch, iflag;
72 char *malloc();
73 uid_t getuid();
72d85c41 74 long atol();
de4d1f2e 75
72d85c41
KB
76 opterr = iflag = 0;
77 interval = -1;
78 while ((ch = getopt(argc, argv, "a:Iir:")) != EOF)
87338d3e 79 switch((char)ch) {
de4d1f2e
KB
80 case 'a': /* alias */
81 if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))))
82 break;
83 cur->name = optarg;
84 cur->next = names;
85 names = cur;
86 break;
ca42b8e8 87 case 'I': /* backward compatible */
72d85c41 88 case 'i': /* init the database */
de4d1f2e 89 iflag = 1;
ca42b8e8 90 break;
72d85c41
KB
91 case 'r':
92 if (isdigit(*optarg)) {
ae8fc90e 93 interval = atol(optarg) * SECSPERDAY;
72d85c41
KB
94 if (interval < 0)
95 goto usage;
96 }
97 else
98 interval = LONG_MAX;
99 break;
87338d3e
KB
100 case '?':
101 default:
de4d1f2e 102 goto usage;
d34d58b1 103 }
87338d3e 104 argc -= optind;
de4d1f2e 105 argv += optind;
d34d58b1 106
ca42b8e8 107 if (argc != 1) {
de4d1f2e 108 if (!iflag) {
72d85c41
KB
109usage: syslog(LOG_NOTICE, "uid %u: usage: vacation [-i] [-a alias] login\n", getuid());
110 myexit(1);
de4d1f2e
KB
111 }
112 if (!(pw = getpwuid(getuid()))) {
ca42b8e8 113 syslog(LOG_ERR, "vacation: no such user uid %u.\n", getuid());
72d85c41 114 myexit(1);
ca42b8e8 115 }
87338d3e 116 }
de4d1f2e 117 else if (!(pw = getpwnam(*argv))) {
ca42b8e8 118 syslog(LOG_ERR, "vacation: no such user %s.\n", *argv);
72d85c41 119 myexit(1);
87338d3e 120 }
de4d1f2e 121 if (chdir(pw->pw_dir)) {
72d85c41
KB
122 syslog(LOG_NOTICE, "vacation: no such directory %s.\n", pw->pw_dir);
123 myexit(1);
de4d1f2e 124 }
1f5b97ad 125
72d85c41 126 if (iflag || access(VDIR, F_OK))
87338d3e 127 initialize();
72d85c41
KB
128 if (!(db = dbm_open(VACAT, O_RDWR, 0))) {
129 syslog(LOG_NOTICE, "vacation: %s: %s\n", VACAT,
130 strerror(errno));
131 myexit(1);
ca42b8e8
KB
132 }
133
72d85c41
KB
134 if (interval != -1)
135 setinterval(interval);
136 if (iflag)
137 myexit(0);
138
de4d1f2e 139 if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))))
72d85c41 140 myexit(1);
de4d1f2e
KB
141 cur->name = pw->pw_name;
142 cur->next = names;
143 names = cur;
ca42b8e8 144
de4d1f2e 145 readheaders();
d34d58b1 146
de4d1f2e
KB
147 if (!recent()) {
148 setreply();
149 sendmessage(pw->pw_name);
d34d58b1 150 }
72d85c41
KB
151 myexit(0);
152 /* NOTREACHED */
d34d58b1 153}
d34d58b1 154
87338d3e 155/*
de4d1f2e
KB
156 * readheaders --
157 * read mail headers
87338d3e 158 */
c974903d
EA
159getfrom(shortp)
160char **shortp;
d34d58b1 161{
de4d1f2e
KB
162 register ALIAS *cur;
163 register char *p;
164 int tome, cont;
165 char buf[MAXLINE], *strcpy(), *index();
166
167 cont = tome = 0;
168 while (fgets(buf, sizeof(buf), stdin) && *buf != '\n')
169 switch(*buf) {
170 case 'F': /* "From " */
171 cont = 0;
172 if (!strncmp(buf, "From ", 5)) {
173 for (p = buf + 5; *p && *p != ' '; ++p);
174 *p = '\0';
175 (void)strcpy(from, buf + 5);
72d85c41
KB
176 if (p = index(from, '\n'))
177 *p = '\0';
de4d1f2e 178 if (junkmail())
72d85c41 179 myexit(0);
de4d1f2e
KB
180 }
181 break;
182 case 'P': /* "Precedence:" */
183 cont = 0;
184 if (strncasecmp(buf, "Precedence", 10) || buf[10] != ':' && buf[10] != ' ' && buf[10] != '\t')
185 break;
186 if (!(p = index(buf, ':')))
187 break;
188 while (*++p && isspace(*p));
189 if (!*p)
190 break;
191 if (!strncasecmp(p, "junk", 4) || !strncasecmp(p, "bulk", 4))
72d85c41 192 myexit(0);
de4d1f2e
KB
193 break;
194 case 'C': /* "Cc:" */
3f225bc3 195 if (strncmp(buf, "Cc:", 3))
de4d1f2e
KB
196 break;
197 cont = 1;
198 goto findme;
199 case 'T': /* "To:" */
200 if (strncmp(buf, "To:", 3))
201 break;
202 cont = 1;
203 goto findme;
204 default:
205 if (!isspace(*buf) || !cont || tome) {
206 cont = 0;
207 break;
208 }
209findme: for (cur = names; !tome && cur; cur = cur->next)
210 tome += nsearch(cur->name, buf);
211 }
212 if (!tome)
72d85c41 213 myexit(0);
de4d1f2e 214 if (!*from) {
72d85c41
KB
215 syslog(LOG_NOTICE, "vacation: no initial \"From\" line.\n");
216 myexit(1);
87338d3e 217 }
de4d1f2e 218}
c974903d 219
c974903d 220 return start;
d34d58b1 221}
351c396d 222
87338d3e
KB
223/*
224 * junkmail --
225 * read the header and return if automagic/junk/bulk mail
226 */
de4d1f2e 227junkmail()
351c396d 228{
87338d3e
KB
229 static struct ignore {
230 char *name;
231 int len;
232 } ignore[] = {
34a2d933
KB
233 "-request", 8, "postmaster", 10, "uucp", 4,
234 "mailer-daemon", 13, "mailer", 6, "-relay", 6,
235 NULL, NULL,
87338d3e 236 };
de4d1f2e
KB
237 register struct ignore *cur;
238 register int len;
239 register char *p;
240 char *index(), *rindex();
87338d3e
KB
241
242 /*
de4d1f2e
KB
243 * This is mildly amusing, and I'm not positive it's right; trying
244 * to find the "real" name of the sender, assuming that addresses
245 * will be some variant of:
87338d3e 246 *
de4d1f2e 247 * From site!site!SENDER%site.domain%site.domain@site.domain
87338d3e
KB
248 */
249 if (!(p = index(from, '%')))
ca42b8e8
KB
250 if (!(p = index(from, '@'))) {
251 if (p = rindex(from, '!'))
252 ++p;
de4d1f2e
KB
253 else
254 p = from;
255 for (; *p; ++p);
ca42b8e8
KB
256 }
257 len = p - from;
de4d1f2e
KB
258 for (cur = ignore; cur->name; ++cur)
259 if (len >= cur->len && !strncasecmp(cur->name, p - cur->len, cur->len))
260 return(1);
261 return(0);
262}
351c396d 263
87338d3e 264/*
de4d1f2e 265 * recent --
87338d3e 266 * find out if user has gotten a vacation message recently.
72d85c41 267 * use bcopy for machines with alignment restrictions
87338d3e 268 */
c974903d 269char *user;
d34d58b1 270{
72d85c41
KB
271 datum key, data;
272 time_t then, next, time();
d34d58b1 273
0fdb1a20 274 if (d.dptr == NULL)
c974903d
EA
275 return FALSE;
276 bcopy(d.dptr, (char *)&ldbrec, sizeof ldbrec); /* realign data */
277 return ldbrec.sentdate + Timeout >= time((time_t *)0);
278}
279
280#ifndef VMUNIX
281bcopy(from, to, size)
282register char *to, *from;
283register unsigned size;
284{
285 while (size-- > 0)
286 *to++ = *from++;
d34d58b1 287}
c974903d 288#endif
d34d58b1 289
72d85c41
KB
290/*
291 * setinterval --
292 * store the reply interval
293 */
294setinterval(interval)
295 time_t interval;
296{
297 datum key, data;
298
299 key.dptr = VIT;
300 key.dsize = sizeof(VIT) - 1;
301 data.dptr = (char *)&interval;
302 data.dsize = sizeof(interval);
303 dbm_store(db, key, data, DBM_REPLACE);
304}
305
87338d3e 306/*
de4d1f2e 307 * setreply --
87338d3e
KB
308 * store that this user knows about the vacation.
309 */
de4d1f2e 310setreply()
d34d58b1 311{
72d85c41
KB
312 datum key, data;
313 time_t now, time();
314
315 key.dptr = from;
316 key.dsize = strlen(from);
317 (void)time(&now);
318 data.dptr = (char *)&now;
319 data.dsize = sizeof(now);
320 dbm_store(db, key, data, DBM_REPLACE);
d34d58b1 321}
d34d58b1 322
87338d3e
KB
323/*
324 * sendmessage --
de4d1f2e 325 * exec sendmail to send the vacation file to sender
87338d3e 326 */
de4d1f2e
KB
327sendmessage(myname)
328 char *myname;
d34d58b1 329{
ca42b8e8 330 if (!freopen(VMSG, "r", stdin)) {
72d85c41
KB
331 syslog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", myname, VMSG);
332 myexit(1);
ca42b8e8 333 }
435e8dff
KB
334 execl(_PATH_SENDMAIL, "sendmail", "-f", myname, from, NULL);
335 syslog(LOG_ERR, "vacation: can't exec %s.\n", _PATH_SENDMAIL);
72d85c41 336 myexit(1);
d34d58b1 337}
1f5b97ad 338
87338d3e
KB
339/*
340 * initialize --
de4d1f2e 341 * initialize the dbm database
87338d3e 342 */
1f5b97ad
EA
343initialize()
344{
de4d1f2e 345 int fd;
d34d58b1 346
87338d3e 347 if ((fd = open(VDIR, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
72d85c41 348 syslog(LOG_NOTICE, "vacation: %s: %s\n", VDIR, strerror(errno));
14ed78ae 349 exit(1);
87338d3e
KB
350 }
351 (void)close(fd);
352 if ((fd = open(VPAG, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
72d85c41 353 syslog(LOG_NOTICE, "vacation: %s: %s\n", VPAG, strerror(errno));
14ed78ae 354 exit(1);
87338d3e
KB
355 }
356 (void)close(fd);
72d85c41
KB
357}
358
359/*
360 * myexit --
361 * we're outta here...
362 */
363myexit(eval)
364 int eval;
365{
366 if (db)
367 dbm_close(db);
368 exit(eval);
351c396d 369}