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