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