new copyright; att/bsd/shared
[unix-history] / usr / src / usr.bin / calendar / calendar.c
CommitLineData
f85e7486
KB
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
f15db449 5 * %sccs.include.redist.c%
f85e7486 6 */
96287344 7
f85e7486
KB
8#ifndef lint
9char copyright[] =
10"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
11 All rights reserved.\n";
12#endif /* not lint */
13
14#ifndef lint
0034085e 15static char sccsid[] = "@(#)calendar.c 4.11 (Berkeley) %G%";
f85e7486
KB
16#endif /* not lint */
17
18#include <sys/param.h>
e22d6501 19#include <sys/time.h>
f85e7486
KB
20#include <sys/stat.h>
21#include <sys/file.h>
71795d0a 22#include <sys/uio.h>
f85e7486
KB
23#include <pwd.h>
24#include <errno.h>
25#include <tzfile.h>
26#include <stdio.h>
27#include <ctype.h>
28#include <unistd.h>
29#include <string.h>
f85e7486
KB
30#include "pathnames.h"
31
71795d0a 32extern int errno;
f85e7486
KB
33struct passwd *pw;
34int doall;
35
36main(argc, argv)
37 int argc;
38 char **argv;
39{
71795d0a 40 extern int optind;
f85e7486
KB
41 int ch;
42
43 while ((ch = getopt(argc, argv, "-a")) != EOF)
44 switch(ch) {
45 case '-': /* backward contemptible */
46 case 'a':
47 if (getuid()) {
48 (void)fprintf(stderr,
49 "calendar: %s\n", strerror(EPERM));
50 exit(1);
51 }
52 doall = 1;
53 break;
54 case '?':
55 default:
56 usage();
57 }
58 argc -= optind;
59 argv += optind;
96287344 60
f85e7486
KB
61 if (argc)
62 usage();
63
64 settime();
65 if (doall)
66 while (pw = getpwent()) {
67 (void)setegid(pw->pw_gid);
68 (void)seteuid(pw->pw_uid);
69 if (!chdir(pw->pw_dir))
70 cal();
71 (void)seteuid(0);
72 }
73 else
74 cal();
75 exit(0);
76}
77
78cal()
79{
80 register int printing;
81 register char *p;
82 FILE *fp, *opencal();
83 int ch;
84 char buf[2048 + 1];
85
86 if (!(fp = opencal()))
87 return;
88 for (printing = 0; fgets(buf, sizeof(buf), stdin);) {
89 if (p = index(buf, '\n'))
90 *p = '\0';
91 else
92 while ((ch = getchar()) != '\n' && ch != EOF);
93 if (buf[0] == '\0')
94 continue;
49ada5ac 95 if (buf[0] != '\t')
f85e7486
KB
96 printing = isnow(buf) ? 1 : 0;
97 if (printing)
98 (void)fprintf(fp, "%s\n", buf);
99 }
100 closecal(fp);
101}
102
71795d0a
KB
103struct iovec header[] = {
104 "From: ", 6,
105 NULL, 0,
106 " (Reminder Service)\nTo: ", 24,
107 NULL, 0,
108 "\nSubject: ", 10,
109 NULL, 0,
110 "'s Calendar\nPrecedence: bulk\n\n", 30,
111};
112
f85e7486
KB
113/* 1-based month, 0-based days, cumulative */
114int daytab[][14] = {
115 0, 0, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364,
116 0, 0, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365,
96287344 117};
f85e7486
KB
118struct tm *tp;
119int *cumdays, offset, yrdays;
120char dayname[10];
121
122settime()
123{
124 time_t now, time();
125
126 (void)time(&now);
127 tp = localtime(&now);
128 if (isleap(tp->tm_year + 1900)) {
129 yrdays = DAYSPERLYEAR;
130 cumdays = daytab[1];
131 } else {
132 yrdays = DAYSPERNYEAR;
133 cumdays = daytab[0];
134 }
135 /* Friday displays Monday's events */
0034085e 136 offset = tp->tm_wday == 5 ? 3 : 1;
71795d0a
KB
137 header[5].iov_base = dayname;
138 header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp);
f85e7486
KB
139}
140
141/*
142 * Possible date formats include any combination of:
143 * 3-charmonth (January, Jan, Jan)
144 * 3-charweekday (Friday, Monday, mon.)
145 * numeric month or day (1, 2, 04)
146 *
147 * Any character may separate them, or they may not be separated. Any line,
148 * following a line that is matched, that starts with "whitespace", is shown
149 * along with the matched line.
150 */
151isnow(endp)
152 char *endp;
153{
154 int day, flags, month, v1, v2;
155
156#define F_ISMONTH 0x01
157#define F_ISDAY 0x02
158 flags = 0;
159 /* didn't recognize anything, skip it */
160 if (!(v1 = getfield(endp, &endp, &flags)))
161 return(0);
162 if (flags&F_ISDAY || v1 > 12) {
163 /* found a day */
164 day = v1;
165 /* if no recognizable month, assume just a day alone */
166 if (!(month = getfield(endp, &endp, &flags)))
167 month = tp->tm_mon;
168 } else if (flags&F_ISMONTH) {
169 month = v1;
170 /* if no recognizable day, assume the first */
171 if (!(day = getfield(endp, &endp, &flags)))
172 day = 1;
173 } else {
174 v2 = getfield(endp, &endp, &flags);
175 if (flags&F_ISMONTH) {
176 day = v1;
177 month = v2;
178 } else {
179 /* F_ISDAY set, v2 > 12, or no way to tell */
180 month = v1;
181 /* if no recognizable day, assume the first */
182 day = v2 ? v2 : 1;
183 }
184 }
185 day = cumdays[month] + day;
186
187 /* if today or today + offset days */
188 if (day >= tp->tm_yday && day <= tp->tm_yday + offset)
189 return(1);
190 /* if number of days left in this year + days to event in next year */
191 if (yrdays - tp->tm_yday + day <= offset)
192 return(1);
193 return(0);
194}
195
196getfield(p, endp, flags)
197 char *p, **endp;
198 int *flags;
199{
200 int val;
201 char *start, savech;
202
203 if (*p == '*') { /* `*' is current month */
204 *flags |= F_ISMONTH;
205 return(tp->tm_mon);
206 }
207 if (isdigit(*p)) {
208 val = strtol(p, &p, 10); /* if 0, it's failure */
209 for (; !isdigit(*p) && !isalpha(*p); ++p);
210 *endp = p;
211 return(val);
96287344 212 }
f85e7486
KB
213 for (start = p; isalpha(*++p););
214 savech = *p;
215 *p = '\0';
216 if (val = getmonth(start))
217 *flags |= F_ISMONTH;
218 else if (val = getday(start))
219 *flags |= F_ISDAY;
220 else
221 return(0);
222 for (*p = savech; !isdigit(*p) && !isalpha(*p); ++p);
223 *endp = p;
224 return(val);
225}
226
227char path[MAXPATHLEN + 1];
228
229FILE *
230opencal()
231{
232 int fd, pdes[2];
233 char *mktemp();
234
235 /* open up calendar file as stdin */
236 if (!freopen("calendar", "r", stdin)) {
237 if (doall)
238 return((FILE *)NULL);
239 (void)fprintf(stderr, "calendar: no calendar file.\n");
240 exit(1);
241 }
242 if (pipe(pdes) < 0)
243 return(NULL);
244 switch (vfork()) {
245 case -1: /* error */
246 (void)close(pdes[0]);
247 (void)close(pdes[1]);
248 return(NULL);
249 case 0:
250 /* child -- stdin already setup, set stdout to pipe input */
251 if (pdes[1] != STDOUT_FILENO) {
252 (void)dup2(pdes[1], STDOUT_FILENO);
253 (void)close(pdes[1]);
254 }
255 (void)close(pdes[0]);
256 execl(_PATH_CPP, "cpp", "-I.", _PATH_INCLUDE, NULL);
257 _exit(1);
258 }
259 /* parent -- set stdin to pipe output */
260 (void)dup2(pdes[0], STDIN_FILENO);
71795d0a 261 (void)close(pdes[0]);
f85e7486
KB
262 (void)close(pdes[1]);
263
264 /* not reading all calendar files, just set output to stdout */
265 if (!doall)
266 return(stdout);
267
268 /* set output to a temporary file, so if no output don't send mail */
269 (void)sprintf(path, "%s/_calXXXXXX", _PATH_TMP);
270 if ((fd = mkstemp(path)) < 0)
271 return(NULL);
272 return(fdopen(fd, "w+"));
273}
274
275closecal(fp)
276 FILE *fp;
277{
278 struct stat sbuf;
f85e7486
KB
279 int nread, pdes[2], status;
280 char buf[1024], *mktemp();
281
282 if (!doall)
283 return;
284
285 (void)rewind(fp);
286 if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
287 goto done;
288 if (pipe(pdes) < 0)
289 goto done;
290 switch (vfork()) {
291 case -1: /* error */
292 (void)close(pdes[0]);
293 (void)close(pdes[1]);
294 goto done;
295 case 0:
296 /* child -- set stdin to pipe output */
297 if (pdes[0] != STDIN_FILENO) {
298 (void)dup2(pdes[0], STDIN_FILENO);
299 (void)close(pdes[0]);
300 }
301 (void)close(pdes[1]);
71795d0a
KB
302 execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
303 "\"Reminder Service\"", "-f", "root", NULL);
304 (void)fprintf(stderr, "calendar: %s: %s.\n",
305 _PATH_SENDMAIL, strerror(errno));
f85e7486
KB
306 _exit(1);
307 }
71795d0a 308 /* parent -- write to pipe input */
f85e7486
KB
309 (void)close(pdes[0]);
310
71795d0a
KB
311 header[1].iov_base = header[3].iov_base = pw->pw_name;
312 header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
313 writev(pdes[1], header, 7);
f85e7486
KB
314 while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
315 (void)write(pdes[1], buf, nread);
316 (void)close(pdes[1]);
317done: (void)fclose(fp);
318 (void)unlink(path);
319 while (wait(&status) >= 0);
320}
321
322static char *months[] = {
323 "jan", "feb", "mar", "apr", "may", "jun",
324 "jul", "aug", "sep", "oct", "nov", "dec", NULL,
325};
326getmonth(s)
327 register char *s;
328{
329 register char **p;
330
331 for (p = months; *p; ++p)
332 if (!strncasecmp(s, *p, 3))
333 return((p - months) + 1);
334 return(0);
335}
336
337static char *days[] = {
338 "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
339};
340getday(s)
341 register char *s;
342{
343 register char **p;
344
345 for (p = days; *p; ++p)
346 if (!strncasecmp(s, *p, 3))
347 return((p - days) + 1);
348 return(0);
349}
350
351usage()
352{
353 (void)fprintf(stderr, "usage: calendar [-a]\n");
354 exit(1);
96287344 355}