|
|
1.1 root 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
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.
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
25: static char sccsid[] = "@(#)vacation.c 5.10 (Berkeley) 6/29/88";
26: #endif /* not lint */
27:
28: /*
29: ** Vacation
30: ** Copyright (c) 1983 Eric P. Allman
31: ** Berkeley, California
32: */
33:
34: #include <sys/param.h>
35: #include <sys/file.h>
36: #include <pwd.h>
37: #include <stdio.h>
38: #include <ctype.h>
39: #include <syslog.h>
40:
41: /*
42: ** VACATION -- return a message to the sender when on vacation.
43: **
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.
48: */
49:
50: #define MAXLINE 500 /* max line from mail header */
51: #define PERIOD (60L*60L*24L*7L) /* week between notifications */
52: #define VMSG ".vacation.msg" /* vacation message */
53: #define VACAT ".vacation" /* dbm's database prefix */
54: #define VDIR ".vacation.dir" /* dbm's DB prefix, part 1 */
55: #define VPAG ".vacation.pag" /* dbm's DB prefix, part 2 */
56:
57: typedef struct alias {
58: struct alias *next;
59: char *name;
60: } ALIAS;
61: ALIAS *names;
62:
63: static char from[MAXLINE]; /* sender's address */
64:
65: main(argc, argv)
66: int argc;
67: char **argv;
68: {
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)
79: switch((char)ch) {
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;
87: case 'i': /* init the database */
88: case 'I': /* backward compatible */
89: iflag = 1;
90: break;
91: case '?':
92: default:
93: goto usage;
94: }
95: argc -= optind;
96: argv += optind;
97:
98: if (argc != 1) {
99: if (!iflag) {
100: usage: syslog(LOG_ERR, "uid %u: usage: vacation [-i] [-a alias] login\n", getuid());
101: exit(1);
102: }
103: if (!(pw = getpwuid(getuid()))) {
104: syslog(LOG_ERR, "vacation: no such user uid %u.\n", getuid());
105: exit(1);
106: }
107: }
108: else if (!(pw = getpwnam(*argv))) {
109: syslog(LOG_ERR, "vacation: no such user %s.\n", *argv);
110: exit(1);
111: }
112: if (chdir(pw->pw_dir)) {
113: syslog(LOG_ERR, "vacation: no such directory %s.\n", pw->pw_dir);
114: exit(1);
115: }
116:
117: if (iflag) {
118: initialize();
119: exit(0);
120: }
121:
122: if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))))
123: exit(1);
124: cur->name = pw->pw_name;
125: cur->next = names;
126: names = cur;
127:
128: readheaders();
129:
130: if (access(VDIR, F_OK))
131: initialize();
132: else
133: dbminit(VACAT);
134:
135: if (!recent()) {
136: setreply();
137: sendmessage(pw->pw_name);
138: }
139: exit(0);
140: }
141:
142: /*
143: * readheaders --
144: * read mail headers
145: */
146: static
147: readheaders()
148: {
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())
164: exit(0);
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))
177: exit(0);
178: break;
179: case 'C': /* "Cc:" */
180: if (strncmp(buf, "Cc:", 3))
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)
198: exit(0);
199: if (!*from) {
200: syslog(LOG_ERR, "vacation: no initial \"From\" line.\n");
201: exit(1);
202: }
203: }
204:
205: /*
206: * nsearch --
207: * do a nice, slow, search of a string for a substring.
208: */
209: static
210: nsearch(name, str)
211: register char *name, *str;
212: {
213: register int len;
214:
215: for (len = strlen(name); *str; ++str)
216: if (*str == *name && !strncasecmp(name, str, len))
217: return(1);
218: return(0);
219: }
220:
221: /*
222: * junkmail --
223: * read the header and return if automagic/junk/bulk mail
224: */
225: static
226: junkmail()
227: {
228: static struct ignore {
229: char *name;
230: int len;
231: } ignore[] = {
232: "-REQUEST", 8, "Postmaster", 10,
233: "uucp", 4, "MAILER-DAEMON", 13,
234: "MAILER", 6, NULL, NULL,
235: };
236: register struct ignore *cur;
237: register int len;
238: register char *p;
239: char *index(), *rindex();
240:
241: /*
242: * This is mildly amusing, and I'm not positive it's right; trying
243: * to find the "real" name of the sender, assuming that addresses
244: * will be some variant of:
245: *
246: * From site!site!SENDER%site.domain%[email protected]
247: */
248: if (!(p = index(from, '%')))
249: if (!(p = index(from, '@'))) {
250: if (p = rindex(from, '!'))
251: ++p;
252: else
253: p = from;
254: for (; *p; ++p);
255: }
256: len = p - from;
257: for (cur = ignore; cur->name; ++cur)
258: if (len >= cur->len && !strncasecmp(cur->name, p - cur->len, cur->len))
259: return(1);
260: return(0);
261: }
262:
263: typedef struct {
264: char *dptr;
265: int dsize;
266: } DATUM;
267:
268: typedef struct {
269: time_t sentdate;
270: } DBREC;
271:
272: /*
273: * recent --
274: * find out if user has gotten a vacation message recently.
275: */
276: static
277: recent()
278: {
279: DATUM k, d, fetch();
280: time_t now, then, time();
281:
282: k.dptr = from;
283: k.dsize = strlen(from) + 1;
284: d = fetch(k);
285: if (d.dptr) {
286: /* be careful on machines with alignment restrictions */
287: bcopy((char *)&((DBREC *)d.dptr)->sentdate, (char *)&then, sizeof(then));
288: (void)time(&now);
289: if (!then || then + PERIOD > now)
290: return(1);
291: }
292: return(0);
293: }
294:
295: /*
296: * setreply --
297: * store that this user knows about the vacation.
298: */
299: static
300: setreply()
301: {
302: DBREC xrec;
303: DATUM k, d;
304: time_t time();
305:
306: k.dptr = from;
307: k.dsize = strlen(from) + 1;
308: (void)time(&xrec.sentdate);
309: d.dptr = (char *)&xrec;
310: d.dsize = sizeof(xrec);
311: store(k, d);
312: }
313:
314: /*
315: * sendmessage --
316: * exec sendmail to send the vacation file to sender
317: */
318: static
319: sendmessage(myname)
320: char *myname;
321: {
322: if (!freopen(VMSG, "r", stdin)) {
323: syslog(LOG_ERR, "vacation: no ~%s/%s file.\n", myname, VMSG);
324: exit(1);
325: }
326: execl("/usr/lib/sendmail", "sendmail", "-f", myname, from, NULL);
327: syslog(LOG_ERR, "vacation: can't exec /usr/lib/sendmail.\n");
328: exit(1);
329: }
330:
331: /*
332: * initialize --
333: * initialize the dbm database
334: */
335: static
336: initialize()
337: {
338: extern int errno;
339: extern char *sys_errlist[];
340: int fd;
341:
342: if ((fd = open(VDIR, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
343: syslog(LOG_ERR, "vacation: %s: %s\n", VDIR, sys_errlist[errno]);
344: exit(1);
345: }
346: (void)close(fd);
347: if ((fd = open(VPAG, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
348: syslog(LOG_ERR, "vacation: %s: %s\n", VPAG, sys_errlist[errno]);
349: exit(1);
350: }
351: (void)close(fd);
352: dbminit(VACAT);
353: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.