Annotation of src/usr.bin/calendar/io.c, Revision 1.9
1.9 ! millert 1: /* $OpenBSD: io.c,v 1.8 1999/11/25 03:46:47 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.9 ! millert 46: static char rcsid[] = "$OpenBSD: io.c,v 1.8 1999/11/25 03:46:47 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:
1.8 pjanzen 210: for (; !isdigit(*p) && !isalpha(*p) && *p != '*' && *p != '\t'; ++p)
1.1 millert 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: }
1.8 pjanzen 289: for (*p = savech; !isdigit(*p) && !isalpha(*p) && *p != '*' && *p != '\t'; ++p)
1.1 millert 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 {
1.9 ! millert 313: char *home = getenv("HOME");
! 314: if (home == NULL || *home == '\0')
! 315: errx(1, "cannot get home directory");
! 316: chdir(home);
1.1 millert 317: if (!(chdir(calendarHome) == 0 &&
318: freopen(calendarFile, "r", stdin)))
1.2 millert 319: errx(1, "no calendar file: ``%s'' or ``~/%s/%s",
320: calendarFile, calendarHome, calendarFile);
1.1 millert 321: }
322: }
323: if (pipe(pdes) < 0)
324: return (NULL);
325: switch (vfork()) {
326: case -1: /* error */
327: (void)close(pdes[0]);
328: (void)close(pdes[1]);
329: return (NULL);
330: case 0:
331: /* child -- stdin already setup, set stdout to pipe input */
332: if (pdes[1] != STDOUT_FILENO) {
333: (void)dup2(pdes[1], STDOUT_FILENO);
334: (void)close(pdes[1]);
335: }
336: (void)close(pdes[0]);
337: (void)setuid(geteuid());
338: (void)setgid(getegid());
339: execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, NULL);
340: warn(_PATH_CPP);
341: _exit(1);
342: }
343: /* parent -- set stdin to pipe output */
344: (void)dup2(pdes[0], STDIN_FILENO);
345: (void)close(pdes[0]);
346: (void)close(pdes[1]);
347:
348: /* not reading all calendar files, just set output to stdout */
349: if (!doall)
350: return (stdout);
351:
352: /* set output to a temporary file, so if no output don't send mail */
353: (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
354: if ((fd = mkstemp(path)) < 0)
355: return (NULL);
356: return (fdopen(fd, "w+"));
357: }
358:
359: void
360: closecal(fp)
361: FILE *fp;
362: {
363: struct stat sbuf;
364: int nread, pdes[2], status;
365: char buf[1024];
366:
367: if (!doall)
368: return;
369:
370: (void)rewind(fp);
371: if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
372: goto done;
373: if (pipe(pdes) < 0)
374: goto done;
375: switch (vfork()) {
376: case -1: /* error */
377: (void)close(pdes[0]);
378: (void)close(pdes[1]);
379: goto done;
380: case 0:
381: /* child -- set stdin to pipe output */
382: if (pdes[0] != STDIN_FILENO) {
383: (void)dup2(pdes[0], STDIN_FILENO);
384: (void)close(pdes[0]);
385: }
386: (void)close(pdes[1]);
387: (void)setuid(geteuid());
388: (void)setgid(getegid());
389: execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
1.7 pjanzen 390: "\"Reminder Service\"", NULL);
1.1 millert 391: warn(_PATH_SENDMAIL);
392: _exit(1);
393: }
394: /* parent -- write to pipe input */
395: (void)close(pdes[0]);
396:
397: header[1].iov_base = header[3].iov_base = pw->pw_name;
398: header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
399: writev(pdes[1], header, 7);
400: while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
401: (void)write(pdes[1], buf, nread);
402: (void)close(pdes[1]);
403: done: (void)fclose(fp);
404: (void)unlink(path);
405: while (wait(&status) >= 0);
1.5 pjanzen 406: }
407:
408:
409: void
410: insert(head, cur_evt)
411: struct event **head;
412: struct event *cur_evt;
413: {
414: struct event *tmp, *tmp2;
415:
416: if (*head) {
417: /* Insert this one in order */
418: tmp = *head;
419: tmp2 = NULL;
420: while (tmp->next &&
421: tmp->when <= cur_evt->when) {
422: tmp2 = tmp;
423: tmp = tmp->next;
424: }
425: if (tmp->when > cur_evt->when) {
426: cur_evt->next = tmp;
427: if (tmp2)
428: tmp2->next = cur_evt;
429: else
430: *head = cur_evt;
431: } else {
432: cur_evt->next = tmp->next;
433: tmp->next = cur_evt;
434: }
435: } else {
436: *head = cur_evt;
437: cur_evt->next = NULL;
438: }
1.1 millert 439: }