|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The 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: (1) source distributions retain this entire copyright
7: * notice and comment, and (2) distributions including binaries display
8: * the following acknowledgement: ``This product includes software
9: * developed by the University of California, Berkeley and its contributors''
10: * in the documentation or other materials provided with the distribution
11: * and in all advertising materials mentioning features or use of this
12: * software. Neither the name of the University nor the names of its
13: * contributors may be used to endorse or promote products derived
14: * from this software without specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: char copyright[] =
22: "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
23: All rights reserved.\n";
24: #endif /* not lint */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)calendar.c 4.10 (Berkeley) 6/1/90";
28: #endif /* not lint */
29:
30: #include <sys/param.h>
31: #include <sys/time.h>
32: #include <sys/stat.h>
33: #include <sys/file.h>
34: #include <sys/uio.h>
35: #include <pwd.h>
36: #include <errno.h>
37: #include <tzfile.h>
38: #include <stdio.h>
39: #include <ctype.h>
40: #include <unistd.h>
41: #include <string.h>
42: #include "pathnames.h"
43:
44: extern int errno;
45: struct passwd *pw;
46: int doall;
47:
48: main(argc, argv)
49: int argc;
50: char **argv;
51: {
52: extern int optind;
53: int ch;
54:
55: while ((ch = getopt(argc, argv, "-a")) != EOF)
56: switch(ch) {
57: case '-': /* backward contemptible */
58: case 'a':
59: if (getuid()) {
60: (void)fprintf(stderr,
61: "calendar: %s\n", strerror(EPERM));
62: exit(1);
63: }
64: doall = 1;
65: break;
66: case '?':
67: default:
68: usage();
69: }
70: argc -= optind;
71: argv += optind;
72:
73: if (argc)
74: usage();
75:
76: settime();
77: if (doall)
78: while (pw = getpwent()) {
79: (void)setegid(pw->pw_gid);
80: (void)seteuid(pw->pw_uid);
81: if (!chdir(pw->pw_dir))
82: cal();
83: (void)seteuid(0);
84: }
85: else
86: cal();
87: exit(0);
88: }
89:
90: cal()
91: {
92: register int printing;
93: register char *p;
94: FILE *fp, *opencal();
95: int ch;
96: char buf[2048 + 1];
97:
98: if (!(fp = opencal()))
99: return;
100: for (printing = 0; fgets(buf, sizeof(buf), stdin);) {
101: if (p = index(buf, '\n'))
102: *p = '\0';
103: else
104: while ((ch = getchar()) != '\n' && ch != EOF);
105: if (buf[0] == '\0')
106: continue;
107: if (buf[0] != '\t')
108: printing = isnow(buf) ? 1 : 0;
109: if (printing)
110: (void)fprintf(fp, "%s\n", buf);
111: }
112: closecal(fp);
113: }
114:
115: struct iovec header[] = {
116: "From: ", 6,
117: NULL, 0,
118: " (Reminder Service)\nTo: ", 24,
119: NULL, 0,
120: "\nSubject: ", 10,
121: NULL, 0,
122: "'s Calendar\nPrecedence: bulk\n\n", 30,
123: };
124:
125: /* 1-based month, 0-based days, cumulative */
126: int daytab[][14] = {
127: 0, 0, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364,
128: 0, 0, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365,
129: };
130: struct tm *tp;
131: int *cumdays, offset, yrdays;
132: char dayname[10];
133:
134: settime()
135: {
136: time_t now, time();
137:
138: (void)time(&now);
139: tp = localtime(&now);
140: if (isleap(tp->tm_year + 1900)) {
141: yrdays = DAYSPERLYEAR;
142: cumdays = daytab[1];
143: } else {
144: yrdays = DAYSPERNYEAR;
145: cumdays = daytab[0];
146: }
147: /* Friday displays Monday's events */
148: offset = tp->tm_wday == 6 ? 3 : 1;
149: header[5].iov_base = dayname;
150: header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp);
151: }
152:
153: /*
154: * Possible date formats include any combination of:
155: * 3-charmonth (January, Jan, Jan)
156: * 3-charweekday (Friday, Monday, mon.)
157: * numeric month or day (1, 2, 04)
158: *
159: * Any character may separate them, or they may not be separated. Any line,
160: * following a line that is matched, that starts with "whitespace", is shown
161: * along with the matched line.
162: */
163: isnow(endp)
164: char *endp;
165: {
166: int day, flags, month, v1, v2;
167:
168: #define F_ISMONTH 0x01
169: #define F_ISDAY 0x02
170: flags = 0;
171: /* didn't recognize anything, skip it */
172: if (!(v1 = getfield(endp, &endp, &flags)))
173: return(0);
174: if (flags&F_ISDAY || v1 > 12) {
175: /* found a day */
176: day = v1;
177: /* if no recognizable month, assume just a day alone */
178: if (!(month = getfield(endp, &endp, &flags)))
179: month = tp->tm_mon;
180: } else if (flags&F_ISMONTH) {
181: month = v1;
182: /* if no recognizable day, assume the first */
183: if (!(day = getfield(endp, &endp, &flags)))
184: day = 1;
185: } else {
186: v2 = getfield(endp, &endp, &flags);
187: if (flags&F_ISMONTH) {
188: day = v1;
189: month = v2;
190: } else {
191: /* F_ISDAY set, v2 > 12, or no way to tell */
192: month = v1;
193: /* if no recognizable day, assume the first */
194: day = v2 ? v2 : 1;
195: }
196: }
197: day = cumdays[month] + day;
198:
199: /* if today or today + offset days */
200: if (day >= tp->tm_yday && day <= tp->tm_yday + offset)
201: return(1);
202: /* if number of days left in this year + days to event in next year */
203: if (yrdays - tp->tm_yday + day <= offset)
204: return(1);
205: return(0);
206: }
207:
208: getfield(p, endp, flags)
209: char *p, **endp;
210: int *flags;
211: {
212: int val;
213: char *start, savech;
214:
215: if (*p == '*') { /* `*' is current month */
216: *flags |= F_ISMONTH;
217: return(tp->tm_mon);
218: }
219: if (isdigit(*p)) {
220: val = strtol(p, &p, 10); /* if 0, it's failure */
221: for (; !isdigit(*p) && !isalpha(*p); ++p);
222: *endp = p;
223: return(val);
224: }
225: for (start = p; isalpha(*++p););
226: savech = *p;
227: *p = '\0';
228: if (val = getmonth(start))
229: *flags |= F_ISMONTH;
230: else if (val = getday(start))
231: *flags |= F_ISDAY;
232: else
233: return(0);
234: for (*p = savech; !isdigit(*p) && !isalpha(*p); ++p);
235: *endp = p;
236: return(val);
237: }
238:
239: char path[MAXPATHLEN + 1];
240:
241: FILE *
242: opencal()
243: {
244: int fd, pdes[2];
245: char *mktemp();
246:
247: /* open up calendar file as stdin */
248: if (!freopen("calendar", "r", stdin)) {
249: if (doall)
250: return((FILE *)NULL);
251: (void)fprintf(stderr, "calendar: no calendar file.\n");
252: exit(1);
253: }
254: if (pipe(pdes) < 0)
255: return(NULL);
256: switch (vfork()) {
257: case -1: /* error */
258: (void)close(pdes[0]);
259: (void)close(pdes[1]);
260: return(NULL);
261: case 0:
262: /* child -- stdin already setup, set stdout to pipe input */
263: if (pdes[1] != STDOUT_FILENO) {
264: (void)dup2(pdes[1], STDOUT_FILENO);
265: (void)close(pdes[1]);
266: }
267: (void)close(pdes[0]);
268: execl(_PATH_CPP, "cpp", "-I.", _PATH_INCLUDE, NULL);
269: _exit(1);
270: }
271: /* parent -- set stdin to pipe output */
272: (void)dup2(pdes[0], STDIN_FILENO);
273: (void)close(pdes[0]);
274: (void)close(pdes[1]);
275:
276: /* not reading all calendar files, just set output to stdout */
277: if (!doall)
278: return(stdout);
279:
280: /* set output to a temporary file, so if no output don't send mail */
281: (void)sprintf(path, "%s/_calXXXXXX", _PATH_TMP);
282: if ((fd = mkstemp(path)) < 0)
283: return(NULL);
284: return(fdopen(fd, "w+"));
285: }
286:
287: closecal(fp)
288: FILE *fp;
289: {
290: struct stat sbuf;
291: int nread, pdes[2], status;
292: char buf[1024], *mktemp();
293:
294: if (!doall)
295: return;
296:
297: (void)rewind(fp);
298: if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
299: goto done;
300: if (pipe(pdes) < 0)
301: goto done;
302: switch (vfork()) {
303: case -1: /* error */
304: (void)close(pdes[0]);
305: (void)close(pdes[1]);
306: goto done;
307: case 0:
308: /* child -- set stdin to pipe output */
309: if (pdes[0] != STDIN_FILENO) {
310: (void)dup2(pdes[0], STDIN_FILENO);
311: (void)close(pdes[0]);
312: }
313: (void)close(pdes[1]);
314: execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
315: "\"Reminder Service\"", "-f", "root", NULL);
316: (void)fprintf(stderr, "calendar: %s: %s.\n",
317: _PATH_SENDMAIL, strerror(errno));
318: _exit(1);
319: }
320: /* parent -- write to pipe input */
321: (void)close(pdes[0]);
322:
323: header[1].iov_base = header[3].iov_base = pw->pw_name;
324: header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
325: writev(pdes[1], header, 7);
326: while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
327: (void)write(pdes[1], buf, nread);
328: (void)close(pdes[1]);
329: done: (void)fclose(fp);
330: (void)unlink(path);
331: while (wait(&status) >= 0);
332: }
333:
334: static char *months[] = {
335: "jan", "feb", "mar", "apr", "may", "jun",
336: "jul", "aug", "sep", "oct", "nov", "dec", NULL,
337: };
338: getmonth(s)
339: register char *s;
340: {
341: register char **p;
342:
343: for (p = months; *p; ++p)
344: if (!strncasecmp(s, *p, 3))
345: return((p - months) + 1);
346: return(0);
347: }
348:
349: static char *days[] = {
350: "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
351: };
352: getday(s)
353: register char *s;
354: {
355: register char **p;
356:
357: for (p = days; *p; ++p)
358: if (!strncasecmp(s, *p, 3))
359: return((p - days) + 1);
360: return(0);
361: }
362:
363: usage()
364: {
365: (void)fprintf(stderr, "usage: calendar [-a]\n");
366: exit(1);
367: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.