Annotation of src/usr.bin/calendar/io.c, Revision 1.7
1.7 ! pjanzen 1: /* $OpenBSD: io.c,v 1.6 1998/12/13 07:31:08 pjanzen 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.7 ! pjanzen 46: static char rcsid[] = "$OpenBSD: io.c,v 1.6 1998/12/13 07:31:08 pjanzen 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 iovec header[] = {
77: {"From: ", 6},
78: {NULL, 0},
79: {" (Reminder Service)\nTo: ", 24},
80: {NULL, 0},
81: {"\nSubject: ", 10},
82: {NULL, 0},
83: {"'s Calendar\nPrecedence: bulk\n\n", 30},
84: };
85:
86:
87: void
88: cal()
89: {
90: register int printing;
91: register char *p;
92: FILE *fp;
1.6 pjanzen 93: int ch, l, i;
1.1 millert 94: int var;
95: char buf[2048 + 1];
1.6 pjanzen 96: struct event *events, *cur_evt, *ev1, *tmp;
1.5 pjanzen 97: struct match *m;
1.1 millert 98:
1.5 pjanzen 99: events = NULL;
100: cur_evt = NULL;
1.1 millert 101: if ((fp = opencal()) == NULL)
102: return;
103: for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) {
104: if ((p = strchr(buf, '\n')) != NULL)
105: *p = '\0';
106: else
107: while ((ch = getchar()) != '\n' && ch != EOF);
108: for (l = strlen(buf);
109: l > 0 && isspace(buf[l - 1]);
110: l--)
111: ;
112: buf[l] = '\0';
113: if (buf[0] == '\0')
114: continue;
115: if (strncmp(buf, "LANG=", 5) == 0) {
116: (void) setlocale(LC_ALL, buf + 5);
117: setnnames();
118: continue;
119: }
1.6 pjanzen 120: /* User defined names for special events */
121: if ((p = strchr(buf, '='))) {
122: for (i = 0; i < NUMEV; i++) {
123: if (strncasecmp(buf, spev[i].name, spev[i].nlen) == 0 &&
124: (p - buf == spev[i].nlen) && buf[spev[i].nlen + 1]) {
125: p++;
126: if (spev[i].uname != NULL)
127: free(spev[i].uname);
128: if ((spev[i].uname = strdup(p)) == NULL)
129: errx(1, "cannot allocate memory");
130: spev[i].ulen = strlen(p);
131: i = NUMEV + 1;
132: }
133: }
134: if (i > NUMEV)
1.1 millert 135: continue;
136: }
137: if (buf[0] != '\t') {
1.5 pjanzen 138: printing = (m = isnow(buf)) ? 1 : 0;
1.6 pjanzen 139: if ((p = strchr(buf, '\t')) == NULL) {
140: printing = 0;
1.1 millert 141: continue;
1.6 pjanzen 142: }
1.5 pjanzen 143: /* Need the following to catch hardwired "variable"
144: * dates */
1.1 millert 145: if (p > buf && p[-1] == '*')
146: var = 1;
1.5 pjanzen 147: else
148: var = 0;
1.1 millert 149: if (printing) {
1.5 pjanzen 150: struct match *foo;
151:
1.6 pjanzen 152: ev1 = NULL;
1.5 pjanzen 153: while (m) {
154: cur_evt = (struct event *) malloc(sizeof(struct event));
155: if (cur_evt == NULL)
156: errx(1, "cannot allocate memory");
1.1 millert 157:
1.6 pjanzen 158: cur_evt->when = m->when;
159: snprintf(cur_evt->print_date,
160: sizeof(cur_evt->print_date), "%s%c",
161: m->print_date, (var + m->var) ? '*' : ' ');
162: if (ev1) {
163: cur_evt->desc = ev1->desc;
164: cur_evt->ldesc = NULL;
165: } else {
166: if ((cur_evt->ldesc = strdup(p)) == NULL)
1.5 pjanzen 167: errx(1, "cannot allocate memory");
1.6 pjanzen 168: cur_evt->desc = &(cur_evt->ldesc);
169: ev1 = cur_evt;
1.5 pjanzen 170: }
171: insert(&events, cur_evt);
172: foo = m;
173: m = m->next;
174: free(foo);
175: }
1.1 millert 176: }
177: }
1.5 pjanzen 178: else if (printing) {
1.6 pjanzen 179: if ((ev1->ldesc = realloc(ev1->ldesc,
180: (2 + strlen(ev1->ldesc) + strlen(buf)))) == NULL)
1.5 pjanzen 181: errx(1, "cannot allocate memory");
1.6 pjanzen 182: strcat(ev1->ldesc, "\n");
183: strcat(ev1->ldesc, buf);
1.5 pjanzen 184: }
185: }
186: tmp = events;
187: while (tmp) {
1.6 pjanzen 188: (void)fprintf(fp, "%s%s\n", tmp->print_date, *(tmp->desc));
189: tmp = tmp->next;
190: }
191: tmp = events;
192: while (tmp) {
1.5 pjanzen 193: events = tmp;
1.6 pjanzen 194: if (tmp->ldesc)
195: free(tmp->ldesc);
1.5 pjanzen 196: tmp = tmp->next;
197: free(events);
1.1 millert 198: }
199: closecal(fp);
200: }
201:
202: int
203: getfield(p, endp, flags)
204: char *p, **endp;
205: int *flags;
206: {
1.6 pjanzen 207: int val, var, i;
1.1 millert 208: char *start, savech;
209:
210: for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p)
211: ;
1.6 pjanzen 212: if (*p == '*') { /* `*' is every month */
1.1 millert 213: *flags |= F_ISMONTH;
214: *endp = p+1;
1.6 pjanzen 215: return (-1); /* means 'every month' */
1.1 millert 216: }
217: if (isdigit(*p)) {
218: val = strtol(p, &p, 10); /* if 0, it's failure */
219: for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p)
220: ;
221: *endp = p;
222: return (val);
223: }
224: for (start = p; isalpha(*++p);)
225: ;
226:
227: /* Sunday-1 */
228: if (*p == '+' || *p == '-')
229: for(; isdigit(*++p);)
230: ;
231:
232: savech = *p;
233: *p = '\0';
234:
235: /* Month */
236: if ((val = getmonth(start)) != 0)
237: *flags |= F_ISMONTH;
238:
239: /* Day */
240: else if ((val = getday(start)) != 0) {
241: *flags |= F_ISDAY;
242:
243: /* variable weekday */
244: if ((var = getdayvar(start)) != 0) {
1.6 pjanzen 245: if (var <= 5 && var >= -4)
1.1 millert 246: val += var * 10;
247: #ifdef DEBUG
248: printf("var: %d\n", var);
249: #endif
250: }
251: }
252:
1.6 pjanzen 253: /* Try specials (Easter, Paskha, ...) */
1.1 millert 254: else {
1.6 pjanzen 255: for (i = 0; i < NUMEV; i++) {
256: if (strncasecmp(start, spev[i].name, spev[i].nlen) == 0) {
257: start += spev[i].nlen;
258: val = i + 1;
259: i = NUMEV + 1;
260: } else if (spev[i].uname != NULL &&
261: strncasecmp(start, spev[i].uname, spev[i].ulen) == 0) {
262: start += spev[i].ulen;
263: val = i + 1;
264: i = NUMEV + 1;
265: }
266: }
267: if (i > NUMEV) {
268: switch(*start) {
269: case '-':
270: case '+':
271: var = atoi(start);
272: if (var > 365 || var < -365)
273: return (0); /* Someone is just being silly */
274: val += (NUMEV + 1) * var;
275: /* We add one to the matching event and multiply by
276: * (NUMEV + 1) so as not to return 0 if there's a match.
277: * val will overflow if there is an obscenely large
278: * number of special events. */
279: break;
280: }
281: *flags |= F_SPECIAL;
282: }
283: if (!(*flags & F_SPECIAL)) {
284: /* undefined rest */
285: *p = savech;
286: return (0);
287: }
1.1 millert 288: }
289: for (*p = savech; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p)
290: ;
291: *endp = p;
292: return (val);
293: }
294:
295: char path[MAXPATHLEN];
296:
297: FILE *
298: opencal()
299: {
300: int fd, pdes[2];
301: struct stat sbuf;
302:
303: /* open up calendar file as stdin */
304: if (!freopen(calendarFile, "r", stdin)) {
305: if (doall) {
306: if (chdir(calendarHome) != 0)
307: return (NULL);
308: if (stat(calendarNoMail, &sbuf) == 0)
309: return (NULL);
310: if (!freopen(calendarFile, "r", stdin))
311: return (NULL);
312: } else {
313: chdir(getenv("HOME"));
314: if (!(chdir(calendarHome) == 0 &&
315: freopen(calendarFile, "r", stdin)))
1.2 millert 316: errx(1, "no calendar file: ``%s'' or ``~/%s/%s",
317: calendarFile, calendarHome, calendarFile);
1.1 millert 318: }
319: }
320: if (pipe(pdes) < 0)
321: return (NULL);
322: switch (vfork()) {
323: case -1: /* error */
324: (void)close(pdes[0]);
325: (void)close(pdes[1]);
326: return (NULL);
327: case 0:
328: /* child -- stdin already setup, set stdout to pipe input */
329: if (pdes[1] != STDOUT_FILENO) {
330: (void)dup2(pdes[1], STDOUT_FILENO);
331: (void)close(pdes[1]);
332: }
333: (void)close(pdes[0]);
334: (void)setuid(geteuid());
335: (void)setgid(getegid());
336: execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, NULL);
337: warn(_PATH_CPP);
338: _exit(1);
339: }
340: /* parent -- set stdin to pipe output */
341: (void)dup2(pdes[0], STDIN_FILENO);
342: (void)close(pdes[0]);
343: (void)close(pdes[1]);
344:
345: /* not reading all calendar files, just set output to stdout */
346: if (!doall)
347: return (stdout);
348:
349: /* set output to a temporary file, so if no output don't send mail */
350: (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
351: if ((fd = mkstemp(path)) < 0)
352: return (NULL);
353: return (fdopen(fd, "w+"));
354: }
355:
356: void
357: closecal(fp)
358: FILE *fp;
359: {
360: struct stat sbuf;
361: int nread, pdes[2], status;
362: char buf[1024];
363:
364: if (!doall)
365: return;
366:
367: (void)rewind(fp);
368: if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
369: goto done;
370: if (pipe(pdes) < 0)
371: goto done;
372: switch (vfork()) {
373: case -1: /* error */
374: (void)close(pdes[0]);
375: (void)close(pdes[1]);
376: goto done;
377: case 0:
378: /* child -- set stdin to pipe output */
379: if (pdes[0] != STDIN_FILENO) {
380: (void)dup2(pdes[0], STDIN_FILENO);
381: (void)close(pdes[0]);
382: }
383: (void)close(pdes[1]);
384: (void)setuid(geteuid());
385: (void)setgid(getegid());
386: execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
1.7 ! pjanzen 387: "\"Reminder Service\"", NULL);
1.1 millert 388: warn(_PATH_SENDMAIL);
389: _exit(1);
390: }
391: /* parent -- write to pipe input */
392: (void)close(pdes[0]);
393:
394: header[1].iov_base = header[3].iov_base = pw->pw_name;
395: header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
396: writev(pdes[1], header, 7);
397: while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
398: (void)write(pdes[1], buf, nread);
399: (void)close(pdes[1]);
400: done: (void)fclose(fp);
401: (void)unlink(path);
402: while (wait(&status) >= 0);
1.5 pjanzen 403: }
404:
405:
406: void
407: insert(head, cur_evt)
408: struct event **head;
409: struct event *cur_evt;
410: {
411: struct event *tmp, *tmp2;
412:
413: if (*head) {
414: /* Insert this one in order */
415: tmp = *head;
416: tmp2 = NULL;
417: while (tmp->next &&
418: tmp->when <= cur_evt->when) {
419: tmp2 = tmp;
420: tmp = tmp->next;
421: }
422: if (tmp->when > cur_evt->when) {
423: cur_evt->next = tmp;
424: if (tmp2)
425: tmp2->next = cur_evt;
426: else
427: *head = cur_evt;
428: } else {
429: cur_evt->next = tmp->next;
430: tmp->next = cur_evt;
431: }
432: } else {
433: *head = cur_evt;
434: cur_evt->next = NULL;
435: }
1.1 millert 436: }