Commit | Line | Data |
---|---|---|
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 | |
9 | char 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 | 15 | static 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 |
49 | typedef struct alias { |
50 | struct alias *next; | |
72d85c41 | 51 | char *name; |
de4d1f2e | 52 | } ALIAS; |
72d85c41 | 53 | ALIAS *names; |
351c396d | 54 | |
72d85c41 KB |
55 | static DBM *db; |
56 | ||
57 | extern int errno; | |
58 | ||
c7a6495b | 59 | static char *VIT = "__VACATION__INTERVAL__TIMER__"; |
72d85c41 | 60 | static char from[MAXLINE]; |
351c396d | 61 | |
d34d58b1 | 62 | main(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 |
109 | usage: 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 |
159 | getfrom(shortp) |
160 | char **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 | } | |
209 | findme: 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 | 227 | junkmail() |
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 | 269 | char *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 | |
281 | bcopy(from, to, size) | |
282 | register char *to, *from; | |
283 | register 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 | */ | |
294 | setinterval(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 | 310 | setreply() |
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 |
327 | sendmessage(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 |
343 | initialize() |
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 | */ | |
363 | myexit(eval) | |
364 | int eval; | |
365 | { | |
366 | if (db) | |
367 | dbm_close(db); | |
368 | exit(eval); | |
351c396d | 369 | } |