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 | |
72d85c41 | 25 | static 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 |
58 | typedef struct alias { |
59 | struct alias *next; | |
72d85c41 | 60 | char *name; |
de4d1f2e | 61 | } ALIAS; |
72d85c41 | 62 | ALIAS *names; |
351c396d | 63 | |
72d85c41 KB |
64 | static DBM *db; |
65 | ||
66 | extern int errno; | |
67 | ||
68 | #define VIT "__VACATION__INTERVAL__TIMER__" | |
69 | static char from[MAXLINE]; | |
351c396d | 70 | |
d34d58b1 | 71 | main(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 |
118 | usage: 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 |
168 | getfrom(shortp) |
169 | char **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 | } | |
218 | findme: 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 | 236 | junkmail() |
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 | 278 | char *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 | |
290 | bcopy(from, to, size) | |
291 | register char *to, *from; | |
292 | register 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 | */ | |
303 | setinterval(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 | 319 | setreply() |
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 |
336 | sendmessage(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 |
352 | initialize() |
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 | */ | |
372 | myexit(eval) | |
373 | int eval; | |
374 | { | |
375 | if (db) | |
376 | dbm_close(db); | |
377 | exit(eval); | |
351c396d | 378 | } |