Annotation of src/usr.bin/calendar/io.c, Revision 1.5
1.5 ! pjanzen 1: /* $OpenBSD: io.c,v 1.4 1998/03/30 06:59:27 deraadt Exp $ */
1.1 millert 2:
3: /*
4: * Copyright (c) 1989, 1993, 1994
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #ifndef lint
37: static const char copyright[] =
38: "@(#) Copyright (c) 1989, 1993\n\
39: The Regents of the University of California. All rights reserved.\n";
40: #endif /* not lint */
41:
42: #ifndef lint
43: #if 0
44: static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
45: #else
1.5 ! pjanzen 46: static char rcsid[] = "$OpenBSD: io.c,v 1.4 1998/03/30 06:59:27 deraadt Exp $";
1.1 millert 47: #endif
48: #endif /* not lint */
49:
50: #include <sys/param.h>
51: #include <sys/stat.h>
52: #include <sys/time.h>
53: #include <sys/types.h>
54: #include <sys/uio.h>
55: #include <sys/wait.h>
56:
57: #include <ctype.h>
58: #include <err.h>
59: #include <errno.h>
60: #include <locale.h>
61: #include <pwd.h>
62: #include <stdio.h>
63: #include <stdlib.h>
64: #include <string.h>
1.4 deraadt 65: #include <tzfile.h>
1.1 millert 66: #include <unistd.h>
67:
68: #include "pathnames.h"
69: #include "calendar.h"
70:
71:
72: char *calendarFile = "calendar"; /* default calendar file */
73: char *calendarHome = ".calendar"; /* HOME */
74: char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */
75:
76: struct fixs neaster, npaskha;
77:
78: struct iovec header[] = {
79: {"From: ", 6},
80: {NULL, 0},
81: {" (Reminder Service)\nTo: ", 24},
82: {NULL, 0},
83: {"\nSubject: ", 10},
84: {NULL, 0},
85: {"'s Calendar\nPrecedence: bulk\n\n", 30},
86: };
87:
88:
89: void
90: cal()
91: {
92: register int printing;
93: register char *p;
94: FILE *fp;
95: int ch, l;
96: int var;
97: char buf[2048 + 1];
1.5 ! pjanzen 98: struct event *events, *cur_evt, *tmp;
! 99: struct match *m;
1.1 millert 100:
1.5 ! pjanzen 101: events = NULL;
! 102: cur_evt = NULL;
1.1 millert 103: if ((fp = opencal()) == NULL)
104: return;
105: for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) {
106: if ((p = strchr(buf, '\n')) != NULL)
107: *p = '\0';
108: else
109: while ((ch = getchar()) != '\n' && ch != EOF);
110: for (l = strlen(buf);
111: l > 0 && isspace(buf[l - 1]);
112: l--)
113: ;
114: buf[l] = '\0';
115: if (buf[0] == '\0')
116: continue;
117: if (strncmp(buf, "LANG=", 5) == 0) {
118: (void) setlocale(LC_ALL, buf + 5);
119: setnnames();
120: continue;
121: }
122: if (strncasecmp(buf, "Easter=", 7) == 0 && buf[7]) {
123: if (neaster.name != NULL)
124: free(neaster.name);
125: if ((neaster.name = strdup(buf + 7)) == NULL)
126: errx(1, "cannot allocate memory");
127: neaster.len = strlen(buf + 7);
128: continue;
129: }
130: if (strncasecmp(buf, "Paskha=", 7) == 0 && buf[7]) {
131: if (npaskha.name != NULL)
132: free(npaskha.name);
133: if ((npaskha.name = strdup(buf + 7)) == NULL)
134: errx(1, "cannot allocate memory");
135: npaskha.len = strlen(buf + 7);
136: continue;
137: }
138: if (buf[0] != '\t') {
1.5 ! pjanzen 139: printing = (m = isnow(buf)) ? 1 : 0;
1.1 millert 140: if ((p = strchr(buf, '\t')) == NULL)
141: continue;
1.5 ! pjanzen 142: /* Need the following to catch hardwired "variable"
! 143: * dates */
1.1 millert 144: if (p > buf && p[-1] == '*')
145: var = 1;
1.5 ! pjanzen 146: else
! 147: var = 0;
1.1 millert 148: if (printing) {
149: struct tm tm;
1.5 ! pjanzen 150: struct match *foo;
! 151: char *dsc;
! 152:
! 153: dsc = NULL;
! 154: while (m) {
! 155: cur_evt = (struct event *) malloc(sizeof(struct event));
! 156: if (cur_evt == NULL)
! 157: errx(1, "cannot allocate memory");
1.1 millert 158:
159: tm.tm_sec = 0; /* unused */
160: tm.tm_min = 0; /* unused */
1.5 ! pjanzen 161: tm.tm_hour = 12; /* unused */
1.1 millert 162: tm.tm_wday = 0; /* unused */
1.5 ! pjanzen 163: tm.tm_mon = m->month - 1;
! 164: tm.tm_mday = m->day;
! 165: tm.tm_year = m->year;
1.3 millert 166: tm.tm_isdst = tp->tm_isdst; /* unused */
167: tm.tm_gmtoff = tp->tm_gmtoff; /* unused */
168: tm.tm_zone = tp->tm_zone; /* unused */
1.5 ! pjanzen 169: (void)strftime(cur_evt->print_date,
! 170: sizeof(cur_evt->print_date) - 1,
! 171: /* "%a %b %d", &tm); Skip weekdays */
! 172: "%b %d", &tm);
! 173: strcat(cur_evt->print_date,
! 174: (var + m->var) ? "*" : " ");
! 175: cur_evt->when = mktime(&tm);
! 176: if (dsc)
! 177: cur_evt->desc = dsc;
! 178: else {
! 179: if ((cur_evt->desc = strdup(p)) == NULL)
! 180: errx(1, "cannot allocate memory");
! 181: dsc = cur_evt->desc;
! 182: }
! 183: insert(&events, cur_evt);
! 184: foo = m;
! 185: m = m->next;
! 186: free(foo);
! 187: }
1.1 millert 188: }
189: }
1.5 ! pjanzen 190: else if (printing) {
! 191: if ((cur_evt->desc = realloc(cur_evt->desc,
! 192: (2 + strlen(cur_evt->desc) + strlen(buf)))) == NULL)
! 193: errx(1, "cannot allocate memory");
! 194: strcat(cur_evt->desc, "\n");
! 195: strcat(cur_evt->desc, buf);
! 196: }
! 197: }
! 198: tmp = events;
! 199: while (tmp) {
! 200: (void)fprintf(fp, "%s%s\n", tmp->print_date, tmp->desc);
! 201: /* Can't free descriptions since they may be shared */
! 202: (void)realloc(tmp->desc, 0);
! 203: events = tmp;
! 204: tmp = tmp->next;
! 205: free(events);
1.1 millert 206: }
207: closecal(fp);
208: }
209:
210: int
211: getfield(p, endp, flags)
212: char *p, **endp;
213: int *flags;
214: {
215: int val, var;
216: char *start, savech;
217:
218: for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p)
219: ;
220: if (*p == '*') { /* `*' is current month */
221: *flags |= F_ISMONTH;
222: *endp = p+1;
223: return (tp->tm_mon + 1);
224: }
225: if (isdigit(*p)) {
226: val = strtol(p, &p, 10); /* if 0, it's failure */
227: for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p)
228: ;
229: *endp = p;
230: return (val);
231: }
232: for (start = p; isalpha(*++p);)
233: ;
234:
235: /* Sunday-1 */
236: if (*p == '+' || *p == '-')
237: for(; isdigit(*++p);)
238: ;
239:
240: savech = *p;
241: *p = '\0';
242:
243: /* Month */
244: if ((val = getmonth(start)) != 0)
245: *flags |= F_ISMONTH;
246:
247: /* Day */
248: else if ((val = getday(start)) != 0) {
249: *flags |= F_ISDAY;
250:
251: /* variable weekday */
252: if ((var = getdayvar(start)) != 0) {
253: if (var <=5 && var >= -4)
254: val += var * 10;
255: #ifdef DEBUG
256: printf("var: %d\n", var);
257: #endif
258: }
259: }
260:
261: /* Easter */
1.4 deraadt 262: else if ((val = geteaster(start, tp->tm_year + TM_YEAR_BASE)) != 0)
1.1 millert 263: *flags |= F_EASTER;
264:
265: /* Paskha */
1.4 deraadt 266: else if ((val = getpaskha(start, tp->tm_year + TM_YEAR_BASE)) != 0)
1.1 millert 267: *flags |= F_EASTER;
268:
269: /* undefined rest */
270: else {
271: *p = savech;
272: return (0);
273: }
274: for (*p = savech; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p)
275: ;
276: *endp = p;
277: return (val);
278: }
279:
280: char path[MAXPATHLEN];
281:
282: FILE *
283: opencal()
284: {
285: int fd, pdes[2];
286: struct stat sbuf;
287:
288: /* open up calendar file as stdin */
289: if (!freopen(calendarFile, "r", stdin)) {
290: if (doall) {
291: if (chdir(calendarHome) != 0)
292: return (NULL);
293: if (stat(calendarNoMail, &sbuf) == 0)
294: return (NULL);
295: if (!freopen(calendarFile, "r", stdin))
296: return (NULL);
297: } else {
298: chdir(getenv("HOME"));
299: if (!(chdir(calendarHome) == 0 &&
300: freopen(calendarFile, "r", stdin)))
1.2 millert 301: errx(1, "no calendar file: ``%s'' or ``~/%s/%s",
302: calendarFile, calendarHome, calendarFile);
1.1 millert 303: }
304: }
305: if (pipe(pdes) < 0)
306: return (NULL);
307: switch (vfork()) {
308: case -1: /* error */
309: (void)close(pdes[0]);
310: (void)close(pdes[1]);
311: return (NULL);
312: case 0:
313: /* child -- stdin already setup, set stdout to pipe input */
314: if (pdes[1] != STDOUT_FILENO) {
315: (void)dup2(pdes[1], STDOUT_FILENO);
316: (void)close(pdes[1]);
317: }
318: (void)close(pdes[0]);
319: (void)setuid(geteuid());
320: (void)setgid(getegid());
321: execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, NULL);
322: warn(_PATH_CPP);
323: _exit(1);
324: }
325: /* parent -- set stdin to pipe output */
326: (void)dup2(pdes[0], STDIN_FILENO);
327: (void)close(pdes[0]);
328: (void)close(pdes[1]);
329:
330: /* not reading all calendar files, just set output to stdout */
331: if (!doall)
332: return (stdout);
333:
334: /* set output to a temporary file, so if no output don't send mail */
335: (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
336: if ((fd = mkstemp(path)) < 0)
337: return (NULL);
338: return (fdopen(fd, "w+"));
339: }
340:
341: void
342: closecal(fp)
343: FILE *fp;
344: {
345: struct stat sbuf;
346: int nread, pdes[2], status;
347: char buf[1024];
348:
349: if (!doall)
350: return;
351:
352: (void)rewind(fp);
353: if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
354: goto done;
355: if (pipe(pdes) < 0)
356: goto done;
357: switch (vfork()) {
358: case -1: /* error */
359: (void)close(pdes[0]);
360: (void)close(pdes[1]);
361: goto done;
362: case 0:
363: /* child -- set stdin to pipe output */
364: if (pdes[0] != STDIN_FILENO) {
365: (void)dup2(pdes[0], STDIN_FILENO);
366: (void)close(pdes[0]);
367: }
368: (void)close(pdes[1]);
369: (void)setuid(geteuid());
370: (void)setgid(getegid());
371: execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
372: "\"Reminder Service\"", "-f", "root", NULL);
373: warn(_PATH_SENDMAIL);
374: _exit(1);
375: }
376: /* parent -- write to pipe input */
377: (void)close(pdes[0]);
378:
379: header[1].iov_base = header[3].iov_base = pw->pw_name;
380: header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
381: writev(pdes[1], header, 7);
382: while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
383: (void)write(pdes[1], buf, nread);
384: (void)close(pdes[1]);
385: done: (void)fclose(fp);
386: (void)unlink(path);
387: while (wait(&status) >= 0);
1.5 ! pjanzen 388: }
! 389:
! 390:
! 391: void
! 392: insert(head, cur_evt)
! 393: struct event **head;
! 394: struct event *cur_evt;
! 395: {
! 396: struct event *tmp, *tmp2;
! 397:
! 398: if (*head) {
! 399: /* Insert this one in order */
! 400: tmp = *head;
! 401: tmp2 = NULL;
! 402: while (tmp->next &&
! 403: tmp->when <= cur_evt->when) {
! 404: tmp2 = tmp;
! 405: tmp = tmp->next;
! 406: }
! 407: if (tmp->when > cur_evt->when) {
! 408: cur_evt->next = tmp;
! 409: if (tmp2)
! 410: tmp2->next = cur_evt;
! 411: else
! 412: *head = cur_evt;
! 413: } else {
! 414: cur_evt->next = tmp->next;
! 415: tmp->next = cur_evt;
! 416: }
! 417: } else {
! 418: *head = cur_evt;
! 419: cur_evt->next = NULL;
! 420: }
1.1 millert 421: }