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