fixes from proteon:
[unix-history] / usr / src / usr.bin / vacation / vacation.c
CommitLineData
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
19char 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 25static 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
57typedef struct alias {
58 struct alias *next;
59 char *name;
60} ALIAS;
61ALIAS *names;
351c396d 62
de4d1f2e 63static char from[MAXLINE]; /* sender's address */
351c396d 64
d34d58b1 65main(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) {
100usage: 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
146getfrom(shortp)
147char **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 }
194findme: 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 */
212static
de4d1f2e 213junkmail()
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
250typedef struct {
251 char *dptr;
252 int dsize;
253} DATUM;
351c396d 254
de4d1f2e
KB
255typedef 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 */
263static
c974903d 264char *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
279bcopy(from, to, size)
280register char *to, *from;
281register 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 */
292static
de4d1f2e 293setreply()
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 */
311static
de4d1f2e
KB
312sendmessage(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 */
328static
1f5b97ad
EA
329initialize()
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}