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