Commit | Line | Data |
---|---|---|
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 | |
19 | char 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 | 25 | static 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 |
59 | typedef struct alias { |
60 | struct alias *next; | |
72d85c41 | 61 | char *name; |
de4d1f2e | 62 | } ALIAS; |
72d85c41 | 63 | ALIAS *names; |
351c396d | 64 | |
72d85c41 KB |
65 | static DBM *db; |
66 | ||
67 | extern int errno; | |
68 | ||
69 | #define VIT "__VACATION__INTERVAL__TIMER__" | |
70 | static char from[MAXLINE]; | |
351c396d | 71 | |
d34d58b1 | 72 | main(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 |
119 | usage: 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 |
169 | getfrom(shortp) |
170 | char **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 | } | |
219 | findme: 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 | 237 | junkmail() |
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 | 279 | char *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 | |
291 | bcopy(from, to, size) | |
292 | register char *to, *from; | |
293 | register 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 | */ | |
304 | setinterval(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 | 320 | setreply() |
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 |
337 | sendmessage(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 |
353 | initialize() |
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 | */ | |
373 | myexit(eval) | |
374 | int eval; | |
375 | { | |
376 | if (db) | |
377 | dbm_close(db); | |
378 | exit(eval); | |
351c396d | 379 | } |