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