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