Deleted Added
full compact
io.c (200628) io.c (205821)
1/*
1/*-
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.

--- 29 unchanged lines hidden (view full) ---

39
40#if 0
41#ifndef lint
42static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
43#endif
44#endif
45
46#include <sys/cdefs.h>
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.

--- 29 unchanged lines hidden (view full) ---

39
40#if 0
41#ifndef lint
42static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
43#endif
44#endif
45
46#include <sys/cdefs.h>
47__FBSDID("$FreeBSD: head/usr.bin/calendar/io.c 200628 2009-12-17 08:42:44Z rse $");
47__FBSDID("$FreeBSD: head/usr.bin/calendar/io.c 205821 2010-03-29 06:49:20Z edwin $");
48
48
49#include <sys/types.h>
50#include <sys/param.h>
51#include <sys/stat.h>
49#include <sys/param.h>
50#include <sys/stat.h>
52#include <sys/time.h>
53#include <sys/uio.h>
54#include <sys/wait.h>
55#include <ctype.h>
56#include <err.h>
57#include <errno.h>
58#include <langinfo.h>
59#include <locale.h>
60#include <pwd.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <string.h>
64#include <unistd.h>
65
66#include "pathnames.h"
67#include "calendar.h"
68
51#include <sys/wait.h>
52#include <ctype.h>
53#include <err.h>
54#include <errno.h>
55#include <langinfo.h>
56#include <locale.h>
57#include <pwd.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include <unistd.h>
62
63#include "pathnames.h"
64#include "calendar.h"
65
69/*
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
74 */
75static struct event *event_add(struct event *, int, int, char *, int, char *);
76static void event_continue(struct event *events, char *txt);
77static void event_print_all(FILE *fp, struct event *events);
78struct event {
79 int month;
80 int day;
81 int var;
82 char *date;
83 char *text;
84 struct event *next;
85};
86
87const char *calendarFile = "calendar"; /* default calendar file */
88const char *calendarHomes[] = {".calendar", _PATH_INCLUDE}; /* HOME */
89const char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */
90
91char path[MAXPATHLEN];
92
66const char *calendarFile = "calendar"; /* default calendar file */
67const char *calendarHomes[] = {".calendar", _PATH_INCLUDE}; /* HOME */
68const char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */
69
70char path[MAXPATHLEN];
71
93struct fixs neaster, npaskha;
72struct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon;
73struct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice;
94
74
95struct iovec header[] = {
96 {"From: ", 6},
97 {NULL, 0},
98 {" (Reminder Service)\nTo: ", 24},
99 {NULL, 0},
100 {"\nSubject: ", 10},
101 {NULL, 0},
102 {"'s Calendar\nPrecedence: bulk\n\n", 30},
103};
104
75#define REPLACE(string, slen, struct_) \
76 if (strncasecmp(buf, (string), (slen)) == 0 && buf[(slen)]) { \
77 if (struct_.name != NULL) \
78 free(struct_.name); \
79 if ((struct_.name = strdup(buf + (slen))) == NULL) \
80 errx(1, "cannot allocate memory"); \
81 struct_.len = strlen(buf + (slen)); \
82 continue; \
83 }
105void
106cal(void)
107{
84void
85cal(void)
86{
108 int printing;
109 char *p;
87 char *pp, p;
110 FILE *fp;
111 int ch, l;
88 FILE *fp;
89 int ch, l;
112 int month;
113 int day;
114 int var;
90 int count, i;
91 int month[MAXCOUNT];
92 int day[MAXCOUNT];
93 int year[MAXCOUNT];
94 char **extradata; /* strings of 20 length */
95 int flags;
115 static int d_first = -1;
116 char buf[2048 + 1];
96 static int d_first = -1;
97 char buf[2048 + 1];
117 struct event *events = NULL;
98 struct event *events[MAXCOUNT];
99 struct tm tm;
100 char dbuf[80];
118
101
102 extradata = (char **)calloc(MAXCOUNT, sizeof(char *));
103 for (i = 0; i < MAXCOUNT; i++) {
104 extradata[i] = (char *)calloc(1, 20);
105 }
106
107 /* Unused */
108 tm.tm_sec = 0;
109 tm.tm_min = 0;
110 tm.tm_hour = 0;
111 tm.tm_wday = 0;
112
113 count = 0;
119 if ((fp = opencal()) == NULL)
120 return;
114 if ((fp = opencal()) == NULL)
115 return;
121 for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) {
122 if ((p = strchr(buf, '\n')) != NULL)
123 *p = '\0';
116 while (fgets(buf, sizeof(buf), stdin) != NULL) {
117 if ((pp = strchr(buf, '\n')) != NULL)
118 *pp = '\0';
124 else
119 else
120 /* Flush this line */
125 while ((ch = getchar()) != '\n' && ch != EOF);
126 for (l = strlen(buf);
127 l > 0 && isspace((unsigned char)buf[l - 1]);
128 l--)
129 ;
130 buf[l] = '\0';
131 if (buf[0] == '\0')
132 continue;
121 while ((ch = getchar()) != '\n' && ch != EOF);
122 for (l = strlen(buf);
123 l > 0 && isspace((unsigned char)buf[l - 1]);
124 l--)
125 ;
126 buf[l] = '\0';
127 if (buf[0] == '\0')
128 continue;
129
130 /* Parse special definitions: LANG, Easter, Paskha etc */
133 if (strncmp(buf, "LANG=", 5) == 0) {
134 (void)setlocale(LC_ALL, buf + 5);
135 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
136 setnnames();
137 continue;
138 }
131 if (strncmp(buf, "LANG=", 5) == 0) {
132 (void)setlocale(LC_ALL, buf + 5);
133 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
134 setnnames();
135 continue;
136 }
139 if (strncasecmp(buf, "Easter=", 7) == 0 && buf[7]) {
140 if (neaster.name != NULL)
141 free(neaster.name);
142 if ((neaster.name = strdup(buf + 7)) == NULL)
143 errx(1, "cannot allocate memory");
144 neaster.len = strlen(buf + 7);
137 REPLACE("Easter=", 7, neaster);
138 REPLACE("Paskha=", 7, npaskha);
139 REPLACE("ChineseNewYear=", 15, ncny);
140 REPLACE("NewMoon=", 8, nnewmoon);
141 REPLACE("FullMoon=", 9, nfullmoon);
142 REPLACE("MarEquinox=", 11, nmarequinox);
143 REPLACE("SepEquinox=", 11, nsepequinox);
144 REPLACE("JunSolstice=", 12, njunsolstice);
145 REPLACE("DecSolstice=", 12, ndecsolstice);
146 if (strncmp(buf, "SEQUENCE=", 9) == 0) {
147 setnsequences(buf + 9);
145 continue;
146 }
148 continue;
149 }
147 if (strncasecmp(buf, "Paskha=", 7) == 0 && buf[7]) {
148 if (npaskha.name != NULL)
149 free(npaskha.name);
150 if ((npaskha.name = strdup(buf + 7)) == NULL)
151 errx(1, "cannot allocate memory");
152 npaskha.len = strlen(buf + 7);
153 continue;
154 }
155 if (buf[0] != '\t') {
156 printing = isnow(buf, &month, &day, &var) ? 1 : 0;
157 if ((p = strchr(buf, '\t')) == NULL)
158 continue;
159 if (p > buf && p[-1] == '*')
160 var = 1;
161 if (printing) {
162 struct tm tm;
163 char dbuf[80];
164
150
165 if (d_first < 0)
166 d_first =
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;
173 tm.tm_mday = day;
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,
178 var, p);
179 }
180 } else {
181 if (printing)
182 event_continue(events, buf);
183 }
184 }
185
186 event_print_all(fp, events);
187 closecal(fp);
188}
189
190static struct event *
191event_add(struct event *events, int month, int day,
192 char *date, int var, char *txt)
193{
194 struct event *e;
195
196 /*
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
202 */
203 e = (struct event *)calloc(1, sizeof(struct event));
204 if (e == NULL)
205 errx(1, "event_add: cannot allocate memory");
206 e->month = month;
207 e->day = day;
208 e->var = var;
209 e->date = strdup(date);
210 if (e->date == NULL)
211 errx(1, "event_add: cannot allocate memory");
212 e->text = strdup(txt);
213 if (e->text == NULL)
214 errx(1, "event_add: cannot allocate memory");
215 e->next = events;
216
217 return e;
218}
219
220static void
221event_continue(struct event *e, char *txt)
222{
223 char *text;
224
225 /*
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.
231 */
232 text = strdup(e->text);
233 if (text == NULL)
234 errx(1, "event_continue: cannot allocate memory");
235
236 free(e->text);
237 e->text = (char *)malloc(strlen(text) + strlen(txt) + 3);
238 if (e->text == NULL)
239 errx(1, "event_continue: cannot allocate memory");
240 strcpy(e->text, text);
241 strcat(e->text, "\n");
242 strcat(e->text, txt);
243 free(text);
244
245 return;
246}
247
248static void
249event_print_all(FILE *fp, struct event *events)
250{
251 struct event *e, *e_next;
252 int daycounter;
253 int day, month;
254
255 /*
256 * Print all events:
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
263 */
264 for (daycounter = 0; daycounter <= f_dayAfter + f_dayBefore;
265 daycounter++) {
266 day = tp->tm_yday - f_dayBefore + daycounter;
267 if (day < 0)
268 day += yrdays;
269 if (day >= yrdays)
270 day -= yrdays;
271
272 /*
151 /*
273 * When we know the day of the year, we can determine the day
274 * of the month and the month.
152 * If the line starts with a tab, the data has to be
153 * added to the previous line
275 */
154 */
276 month = 1;
277 while (month <= 12) {
278 if (day <= cumdays[month])
279 break;
280 month++;
155 if (buf[0] == '\t') {
156 for (i = 0; i < count; i++)
157 event_continue(events[i], buf);
158 continue;
281 }
159 }
282 month--;
283 day -= cumdays[month];
284
160
285#ifdef DEBUG
286 fprintf(stderr, "event_print_allmonth: %d, day: %d\n",
287 month, day);
288#endif
161 /* Get rid of leading spaces (non-standard) */
162 while (isspace(buf[0]))
163 memcpy(buf, buf + 1, strlen(buf) - 1);
289
164
290 /*
291 * Go through all events and print the text of the matching
292 * dates
293 */
294 for (e = events; e != NULL; e = e_next) {
295 e_next = e->next;
165 /* No tab in the line, then not a valid line */
166 if ((pp = strchr(buf, '\t')) == NULL)
167 continue;
296
168
297 if (month != e->month || day != e->day)
298 continue;
169 /* Trim spaces in front of the tab */
170 while (isspace(pp[-1]))
171 pp--;
299
172
300 (void)fprintf(fp, "%s%c%s\n", e->date,
301 e->var ? '*' : ' ', e->text);
173 p = *pp;
174 *pp = '\0';
175 if ((count = parsedaymonth(buf, year, month, day, &flags,
176 extradata)) == 0)
177 continue;
178 *pp = p;
179 if (count < 0) {
180 /* Show error status based on return value */
181 fprintf(stderr, "Ignored: %s\n", buf);
182 if (count == -1)
183 continue;
184 count = -count + 1;
302 }
185 }
303 }
304}
305
186
306int
307getfield(char *p, char **endp, int *flags)
308{
309 int val, var;
310 char *start, savech;
187 /* Find the last tab */
188 while (pp[1] == '\t')
189 pp++;
311
190
312 for (; !isdigit((unsigned char)*p) && !isalpha((unsigned char)*p)
313 && *p != '*'; ++p)
314 ;
315 if (*p == '*') { /* `*' is current month */
316 *flags |= F_ISMONTH;
317 *endp = p + 1;
318 return (tp->tm_mon + 1);
319 }
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);
324 *endp = p;
325 return (val);
326 }
327 for (start = p; isalpha((unsigned char)*++p););
191 if (d_first < 0)
192 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
328
193
329 /* Sunday-1 */
330 if (*p == '+' || *p == '-')
331 for(; isdigit((unsigned char)*++p);)
332 ;
333
334 savech = *p;
335 *p = '\0';
336
337 /* Month */
338 if ((val = getmonth(start)) != 0)
339 *flags |= F_ISMONTH;
340
341 /* Day */
342 else if ((val = getday(start)) != 0) {
343 *flags |= F_ISDAY;
344
345 /* variable weekday */
346 if ((var = getdayvar(start)) != 0) {
347 if (var <= 5 && var >= -4)
348 val += var * 10;
349#ifdef DEBUG
350 printf("var: %d\n", var);
351#endif
194 for (i = 0; i < count; i++) {
195 tm.tm_mon = month[i] - 1;
196 tm.tm_mday = day[i];
197 tm.tm_year = year[i] - 1900;
198 (void)strftime(dbuf, sizeof(dbuf),
199 d_first ? "%e %b" : "%b %e", &tm);
200 if (debug)
201 fprintf(stderr, "got %s\n", pp);
202 events[i] = event_add(year[i], month[i], day[i], dbuf,
203 ((flags &= F_VARIABLE) != 0) ? 1 : 0, pp,
204 extradata[i]);
352 }
353 }
354
205 }
206 }
207
355 /* Easter */
356 else if ((val = geteaster(start, tp->tm_year + 1900)) != 0)
357 *flags |= F_EASTER;
358
359 /* Paskha */
360 else if ((val = getpaskha(start, tp->tm_year + 1900)) != 0)
361 *flags |= F_EASTER;
362
363 /* undefined rest */
364 else {
365 *p = savech;
366 return (0);
367 }
368 for (*p = savech; !isdigit((unsigned char)*p)
369 && !isalpha((unsigned char)*p) && *p != '*'; ++p)
370 ;
371 *endp = p;
372 return (val);
208 event_print_all(fp);
209 closecal(fp);
373}
374
375FILE *
376opencal(void)
377{
378 uid_t uid;
379 size_t i;
380 int fd, found, pdes[2];

--- 119 unchanged lines hidden (view full) ---

500 execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
501 "\"Reminder Service\"", (char *)NULL);
502 warn(_PATH_SENDMAIL);
503 _exit(1);
504 }
505 /* parent -- write to pipe input */
506 (void)close(pdes[0]);
507
210}
211
212FILE *
213opencal(void)
214{
215 uid_t uid;
216 size_t i;
217 int fd, found, pdes[2];

--- 119 unchanged lines hidden (view full) ---

337 execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
338 "\"Reminder Service\"", (char *)NULL);
339 warn(_PATH_SENDMAIL);
340 _exit(1);
341 }
342 /* parent -- write to pipe input */
343 (void)close(pdes[0]);
344
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);
345 write(pdes[1], "From: \"Reminder Service\" <", 26);
346 write(pdes[1], pw->pw_name, strlen(pw->pw_name));
347 write(pdes[1], ">\nTo: <", 7);
348 write(pdes[1], pw->pw_name, strlen(pw->pw_name));
349 write(pdes[1], ">\nSubject: ", 12);
350 write(pdes[1], dayname, strlen(dayname));
351 write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30);
352
511 while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
512 (void)write(pdes[1], buf, nread);
513 (void)close(pdes[1]);
514done: (void)fclose(fp);
515 (void)unlink(path);
516 while (wait(&status) >= 0);
517}
353 while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
354 (void)write(pdes[1], buf, nread);
355 (void)close(pdes[1]);
356done: (void)fclose(fp);
357 (void)unlink(path);
358 while (wait(&status) >= 0);
359}