2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 static const char copyright[] =
36 "@(#) Copyright (c) 1989, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
42 static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
46 #include <sys/cdefs.h>
47 __FBSDID("$FreeBSD$");
49 #include <sys/types.h>
50 #include <sys/param.h>
66 #include "pathnames.h"
70 * Event sorting related functions:
71 * - Use event_add() to create a new event
72 * - Use event_continue() to add more text to the last added event
73 * - Use event_print_all() to display them in time chronological order
75 static struct event *event_add(struct event *, int, int, char *, int, char *);
76 static void event_continue(struct event *events, char *txt);
77 static void event_print_all(FILE *fp, struct event *events);
87 const char *calendarFile = "calendar"; /* default calendar file */
88 const char *calendarHomes[] = {".calendar", _PATH_INCLUDE}; /* HOME */
89 const char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */
91 char path[MAXPATHLEN];
93 struct fixs neaster, npaskha;
95 struct iovec header[] = {
98 {" (Reminder Service)\nTo: ", 24},
102 {"'s Calendar\nPrecedence: bulk\n\n", 30},
115 static int d_first = -1;
117 struct event *events = NULL;
119 if ((fp = opencal()) == NULL)
121 for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) {
122 if ((p = strchr(buf, '\n')) != NULL)
125 while ((ch = getchar()) != '\n' && ch != EOF);
126 for (l = strlen(buf);
127 l > 0 && isspace((unsigned char)buf[l - 1]);
133 if (strncmp(buf, "LANG=", 5) == 0) {
134 (void)setlocale(LC_ALL, buf + 5);
135 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
139 if (strncasecmp(buf, "Easter=", 7) == 0 && buf[7]) {
140 if (neaster.name != NULL)
142 if ((neaster.name = strdup(buf + 7)) == NULL)
143 errx(1, "cannot allocate memory");
144 neaster.len = strlen(buf + 7);
147 if (strncasecmp(buf, "Paskha=", 7) == 0 && buf[7]) {
148 if (npaskha.name != NULL)
150 if ((npaskha.name = strdup(buf + 7)) == NULL)
151 errx(1, "cannot allocate memory");
152 npaskha.len = strlen(buf + 7);
155 if (buf[0] != '\t') {
156 printing = isnow(buf, &month, &day, &var) ? 1 : 0;
157 if ((p = strchr(buf, '\t')) == NULL)
159 if (p > buf && p[-1] == '*')
167 (*nl_langinfo(D_MD_ORDER) == 'd');
168 tm.tm_sec = 0; /* unused */
169 tm.tm_min = 0; /* unused */
170 tm.tm_hour = 0; /* unused */
171 tm.tm_wday = 0; /* unused */
172 tm.tm_mon = month - 1;
174 tm.tm_year = tp->tm_year; /* unused */
175 (void)strftime(dbuf, sizeof(dbuf),
176 d_first ? "%e %b" : "%b %e", &tm);
177 events = event_add(events, month, day, dbuf,
182 event_continue(events, buf);
186 event_print_all(fp, events);
190 static struct event *
191 event_add(struct event *events, int month, int day,
192 char *date, int var, char *txt)
197 * Creating a new event:
198 * - Create a new event
199 * - Copy the machine readable day and month
200 * - Copy the human readable and language specific date
201 * - Copy the text of the event
203 e = (struct event *)calloc(1, sizeof(struct event));
205 errx(1, "event_add: cannot allocate memory");
209 e->date = strdup(date);
211 errx(1, "event_add: cannot allocate memory");
212 e->text = strdup(txt);
214 errx(1, "event_add: cannot allocate memory");
221 event_continue(struct event *e, char *txt)
226 * Adding text to the event:
227 * - Save a copy of the old text (unknown length, so strdup())
228 * - Allocate enough space for old text + \n + new text + 0
229 * - Store the old text + \n + new text
230 * - Destroy the saved copy.
232 text = strdup(e->text);
234 errx(1, "event_continue: cannot allocate memory");
237 e->text = (char *)malloc(strlen(text) + strlen(txt) + 3);
239 errx(1, "event_continue: cannot allocate memory");
240 strcpy(e->text, text);
241 strcat(e->text, "\n");
242 strcat(e->text, txt);
249 event_print_all(FILE *fp, struct event *events)
251 struct event *e, *e_next;
257 * - We know the number of days to be counted (f_dayAfter + f_dayBefore)
258 * - We know the current day of the year ("now" - f_dayBefore + counter)
259 * - We know the number of days in the year (yrdays, set in settime())
260 * - So we know the date on which the current daycounter is on the
261 * calendar in days and months.
262 * - Go through the list of events, and print all matching dates
264 for (daycounter = 0; daycounter <= f_dayAfter + f_dayBefore;
266 day = tp->tm_yday - f_dayBefore + daycounter;
273 * When we know the day of the year, we can determine the day
274 * of the month and the month.
277 while (month <= 12) {
278 if (day <= cumdays[month])
283 day -= cumdays[month];
286 fprintf(stderr, "event_print_allmonth: %d, day: %d\n",
291 * Go through all events and print the text of the matching
294 for (e = events; e != NULL; e = e_next) {
297 if (month != e->month || day != e->day)
300 (void)fprintf(fp, "%s%c%s\n", e->date,
301 e->var ? '*' : ' ', e->text);
307 getfield(char *p, char **endp, int *flags)
312 for (; !isdigit((unsigned char)*p) && !isalpha((unsigned char)*p)
315 if (*p == '*') { /* `*' is current month */
318 return (tp->tm_mon + 1);
320 if (isdigit((unsigned char)*p)) {
321 val = strtol(p, &p, 10); /* if 0, it's failure */
322 for (; !isdigit((unsigned char)*p)
323 && !isalpha((unsigned char)*p) && *p != '*'; ++p);
327 for (start = p; isalpha((unsigned char)*++p););
330 if (*p == '+' || *p == '-')
331 for(; isdigit((unsigned char)*++p);)
338 if ((val = getmonth(start)) != 0)
342 else if ((val = getday(start)) != 0) {
345 /* variable weekday */
346 if ((var = getdayvar(start)) != 0) {
347 if (var <= 5 && var >= -4)
350 printf("var: %d\n", var);
356 else if ((val = geteaster(start, tp->tm_year + 1900)) != 0)
360 else if ((val = getpaskha(start, tp->tm_year + 1900)) != 0)
368 for (*p = savech; !isdigit((unsigned char)*p)
369 && !isalpha((unsigned char)*p) && *p != '*'; ++p)
380 int fd, found, pdes[2];
383 /* open up calendar file as stdin */
384 if (!freopen(calendarFile, "r", stdin)) {
386 if (chdir(calendarHomes[0]) != 0)
388 if (stat(calendarNoMail, &sbuf) == 0)
390 if (!freopen(calendarFile, "r", stdin))
393 char *home = getenv("HOME");
394 if (home == NULL || *home == '\0')
395 errx(1, "cannot get home directory");
397 for (found = i = 0; i < sizeof(calendarHomes) /
398 sizeof(calendarHomes[0]); i++)
399 if (chdir(calendarHomes[i]) == 0 &&
400 freopen(calendarFile, "r", stdin)) {
406 "can't open calendar file \"%s\": %s (%d)",
407 calendarFile, strerror(errno), errno);
414 (void)close(pdes[0]);
415 (void)close(pdes[1]);
418 /* child -- stdin already setup, set stdout to pipe input */
419 if (pdes[1] != STDOUT_FILENO) {
420 (void)dup2(pdes[1], STDOUT_FILENO);
421 (void)close(pdes[1]);
423 (void)close(pdes[0]);
425 if (setuid(getuid()) < 0) {
426 warnx("first setuid failed");
429 if (setgid(getegid()) < 0) {
430 warnx("setgid failed");
433 if (setuid(uid) < 0) {
434 warnx("setuid failed");
437 execl(_PATH_CPP, "cpp", "-P",
438 "-traditional", "-nostdinc", /* GCC specific opts */
439 "-I.", "-I", _PATH_INCLUDE, (char *)NULL);
443 /* parent -- set stdin to pipe output */
444 (void)dup2(pdes[0], STDIN_FILENO);
445 (void)close(pdes[0]);
446 (void)close(pdes[1]);
448 /* not reading all calendar files, just set output to stdout */
452 /* set output to a temporary file, so if no output don't send mail */
453 (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
454 if ((fd = mkstemp(path)) < 0)
456 return (fdopen(fd, "w+"));
464 int nread, pdes[2], status;
471 if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
477 (void)close(pdes[0]);
478 (void)close(pdes[1]);
481 /* child -- set stdin to pipe output */
482 if (pdes[0] != STDIN_FILENO) {
483 (void)dup2(pdes[0], STDIN_FILENO);
484 (void)close(pdes[0]);
486 (void)close(pdes[1]);
488 if (setuid(getuid()) < 0) {
489 warnx("setuid failed");
492 if (setgid(getegid()) < 0) {
493 warnx("setgid failed");
496 if (setuid(uid) < 0) {
497 warnx("setuid failed");
500 execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
501 "\"Reminder Service\"", (char *)NULL);
502 warn(_PATH_SENDMAIL);
505 /* parent -- write to pipe input */
506 (void)close(pdes[0]);
508 header[1].iov_base = header[3].iov_base = pw->pw_name;
509 header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
510 writev(pdes[1], header, 7);
511 while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
512 (void)write(pdes[1], buf, nread);
513 (void)close(pdes[1]);
514 done: (void)fclose(fp);
516 while (wait(&status) >= 0);