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