Annotation of src/usr.bin/calendar/io.c, Revision 1.3
1.3 ! millert 1: /* $OpenBSD: io.c,v 1.2 1997/09/12 04:12:48 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.3 ! millert 46: static char rcsid[] = "$OpenBSD: io.c,v 1.2 1997/09/12 04:12:48 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>
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>
65: #include <unistd.h>
66:
67: #include "pathnames.h"
68: #include "calendar.h"
69:
70:
71: char *calendarFile = "calendar"; /* default calendar file */
72: char *calendarHome = ".calendar"; /* HOME */
73: char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */
74:
75: struct fixs neaster, npaskha;
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:
88: void
89: cal()
90: {
91: register int printing;
92: register char *p;
93: FILE *fp;
94: int ch, l;
95: int month;
96: int day;
97: int var;
98: char buf[2048 + 1];
99:
100: if ((fp = opencal()) == NULL)
101: return;
102: for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) {
103: if ((p = strchr(buf, '\n')) != NULL)
104: *p = '\0';
105: else
106: while ((ch = getchar()) != '\n' && ch != EOF);
107: for (l = strlen(buf);
108: l > 0 && isspace(buf[l - 1]);
109: l--)
110: ;
111: buf[l] = '\0';
112: if (buf[0] == '\0')
113: continue;
114: if (strncmp(buf, "LANG=", 5) == 0) {
115: (void) setlocale(LC_ALL, buf + 5);
116: setnnames();
117: continue;
118: }
119: if (strncasecmp(buf, "Easter=", 7) == 0 && buf[7]) {
120: if (neaster.name != NULL)
121: free(neaster.name);
122: if ((neaster.name = strdup(buf + 7)) == NULL)
123: errx(1, "cannot allocate memory");
124: neaster.len = strlen(buf + 7);
125: continue;
126: }
127: if (strncasecmp(buf, "Paskha=", 7) == 0 && buf[7]) {
128: if (npaskha.name != NULL)
129: free(npaskha.name);
130: if ((npaskha.name = strdup(buf + 7)) == NULL)
131: errx(1, "cannot allocate memory");
132: npaskha.len = strlen(buf + 7);
133: continue;
134: }
135: if (buf[0] != '\t') {
136: printing = isnow(buf, &month, &day, &var) ? 1 : 0;
137: if ((p = strchr(buf, '\t')) == NULL)
138: continue;
139: if (p > buf && p[-1] == '*')
140: var = 1;
141: if (printing) {
142: struct tm tm;
143: char dbuf[30];
144:
145: tm.tm_sec = 0; /* unused */
146: tm.tm_min = 0; /* unused */
147: tm.tm_hour = 0; /* unused */
148: tm.tm_wday = 0; /* unused */
149: tm.tm_mon = month - 1;
150: tm.tm_mday = day;
151: tm.tm_year = tp->tm_year; /* unused */
1.3 ! millert 152: tm.tm_isdst = tp->tm_isdst; /* unused */
! 153: tm.tm_gmtoff = tp->tm_gmtoff; /* unused */
! 154: tm.tm_zone = tp->tm_zone; /* unused */
! 155: (void)strftime(dbuf, sizeof(dbuf), "%a %b %d",
! 156: &tm);
1.1 millert 157: (void)fprintf(fp, "%s%c%s\n",
158: dbuf + 4/* skip weekdays */,
159: var ? '*' : ' ', p);
160: }
161: }
162: else if (printing)
163: fprintf(fp, "%s\n", buf);
164: }
165: closecal(fp);
166: }
167:
168: int
169: getfield(p, endp, flags)
170: char *p, **endp;
171: int *flags;
172: {
173: int val, var;
174: char *start, savech;
175:
176: for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p)
177: ;
178: if (*p == '*') { /* `*' is current month */
179: *flags |= F_ISMONTH;
180: *endp = p+1;
181: return (tp->tm_mon + 1);
182: }
183: if (isdigit(*p)) {
184: val = strtol(p, &p, 10); /* if 0, it's failure */
185: for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p)
186: ;
187: *endp = p;
188: return (val);
189: }
190: for (start = p; isalpha(*++p);)
191: ;
192:
193: /* Sunday-1 */
194: if (*p == '+' || *p == '-')
195: for(; isdigit(*++p);)
196: ;
197:
198: savech = *p;
199: *p = '\0';
200:
201: /* Month */
202: if ((val = getmonth(start)) != 0)
203: *flags |= F_ISMONTH;
204:
205: /* Day */
206: else if ((val = getday(start)) != 0) {
207: *flags |= F_ISDAY;
208:
209: /* variable weekday */
210: if ((var = getdayvar(start)) != 0) {
211: if (var <=5 && var >= -4)
212: val += var * 10;
213: #ifdef DEBUG
214: printf("var: %d\n", var);
215: #endif
216: }
217: }
218:
219: /* Easter */
220: else if ((val = geteaster(start, tp->tm_year + 1900)) != 0)
221: *flags |= F_EASTER;
222:
223: /* Paskha */
224: else if ((val = getpaskha(start, tp->tm_year + 1900)) != 0)
225: *flags |= F_EASTER;
226:
227: /* undefined rest */
228: else {
229: *p = savech;
230: return (0);
231: }
232: for (*p = savech; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p)
233: ;
234: *endp = p;
235: return (val);
236: }
237:
238: char path[MAXPATHLEN];
239:
240: FILE *
241: opencal()
242: {
243: int fd, pdes[2];
244: struct stat sbuf;
245:
246: /* open up calendar file as stdin */
247: if (!freopen(calendarFile, "r", stdin)) {
248: if (doall) {
249: if (chdir(calendarHome) != 0)
250: return (NULL);
251: if (stat(calendarNoMail, &sbuf) == 0)
252: return (NULL);
253: if (!freopen(calendarFile, "r", stdin))
254: return (NULL);
255: } else {
256: chdir(getenv("HOME"));
257: if (!(chdir(calendarHome) == 0 &&
258: freopen(calendarFile, "r", stdin)))
1.2 millert 259: errx(1, "no calendar file: ``%s'' or ``~/%s/%s",
260: calendarFile, calendarHome, calendarFile);
1.1 millert 261: }
262: }
263: if (pipe(pdes) < 0)
264: return (NULL);
265: switch (vfork()) {
266: case -1: /* error */
267: (void)close(pdes[0]);
268: (void)close(pdes[1]);
269: return (NULL);
270: case 0:
271: /* child -- stdin already setup, set stdout to pipe input */
272: if (pdes[1] != STDOUT_FILENO) {
273: (void)dup2(pdes[1], STDOUT_FILENO);
274: (void)close(pdes[1]);
275: }
276: (void)close(pdes[0]);
277: (void)setuid(geteuid());
278: (void)setgid(getegid());
279: execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, NULL);
280: warn(_PATH_CPP);
281: _exit(1);
282: }
283: /* parent -- set stdin to pipe output */
284: (void)dup2(pdes[0], STDIN_FILENO);
285: (void)close(pdes[0]);
286: (void)close(pdes[1]);
287:
288: /* not reading all calendar files, just set output to stdout */
289: if (!doall)
290: return (stdout);
291:
292: /* set output to a temporary file, so if no output don't send mail */
293: (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
294: if ((fd = mkstemp(path)) < 0)
295: return (NULL);
296: return (fdopen(fd, "w+"));
297: }
298:
299: void
300: closecal(fp)
301: FILE *fp;
302: {
303: struct stat sbuf;
304: int nread, pdes[2], status;
305: char buf[1024];
306:
307: if (!doall)
308: return;
309:
310: (void)rewind(fp);
311: if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
312: goto done;
313: if (pipe(pdes) < 0)
314: goto done;
315: switch (vfork()) {
316: case -1: /* error */
317: (void)close(pdes[0]);
318: (void)close(pdes[1]);
319: goto done;
320: case 0:
321: /* child -- set stdin to pipe output */
322: if (pdes[0] != STDIN_FILENO) {
323: (void)dup2(pdes[0], STDIN_FILENO);
324: (void)close(pdes[0]);
325: }
326: (void)close(pdes[1]);
327: (void)setuid(geteuid());
328: (void)setgid(getegid());
329: execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
330: "\"Reminder Service\"", "-f", "root", NULL);
331: warn(_PATH_SENDMAIL);
332: _exit(1);
333: }
334: /* parent -- write to pipe input */
335: (void)close(pdes[0]);
336:
337: header[1].iov_base = header[3].iov_base = pw->pw_name;
338: header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
339: writev(pdes[1], header, 7);
340: while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
341: (void)write(pdes[1], buf, nread);
342: (void)close(pdes[1]);
343: done: (void)fclose(fp);
344: (void)unlink(path);
345: while (wait(&status) >= 0);
346: }