io.c revision 255715
1205821Sedwin/*-
213840Swosch * Copyright (c) 1989, 1993, 1994
313840Swosch *	The Regents of the University of California.  All rights reserved.
413840Swosch *
513840Swosch * Redistribution and use in source and binary forms, with or without
613840Swosch * modification, are permitted provided that the following conditions
713840Swosch * are met:
813840Swosch * 1. Redistributions of source code must retain the above copyright
913840Swosch *    notice, this list of conditions and the following disclaimer.
1013840Swosch * 2. Redistributions in binary form must reproduce the above copyright
1113840Swosch *    notice, this list of conditions and the following disclaimer in the
1213840Swosch *    documentation and/or other materials provided with the distribution.
1313840Swosch * 4. Neither the name of the University nor the names of its contributors
1413840Swosch *    may be used to endorse or promote products derived from this software
1513840Swosch *    without specific prior written permission.
1613840Swosch *
1713840Swosch * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1813840Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1913840Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2013840Swosch * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2113840Swosch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2213840Swosch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2313840Swosch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2413840Swosch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2513840Swosch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2613840Swosch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2713840Swosch * SUCH DAMAGE.
2813840Swosch */
2913840Swosch
3013840Swosch#ifndef lint
3115714Sachestatic const char copyright[] =
3213840Swosch"@(#) Copyright (c) 1989, 1993\n\
3313840Swosch	The Regents of the University of California.  All rights reserved.\n";
3487235Smarkm#endif
3513840Swosch
3687628Sdwmalone#if 0
3713840Swosch#ifndef lint
3887628Sdwmalonestatic char sccsid[] = "@(#)calendar.c  8.3 (Berkeley) 3/25/94";
3987235Smarkm#endif
4087628Sdwmalone#endif
4113840Swosch
4287628Sdwmalone#include <sys/cdefs.h>
4387628Sdwmalone__FBSDID("$FreeBSD: head/usr.bin/calendar/io.c 255715 2013-09-19 20:17:50Z db $");
4487628Sdwmalone
4513840Swosch#include <sys/param.h>
4687235Smarkm#include <sys/stat.h>
4787235Smarkm#include <sys/wait.h>
4813840Swosch#include <ctype.h>
4913840Swosch#include <err.h>
5013840Swosch#include <errno.h>
5174583Sache#include <langinfo.h>
5215714Sache#include <locale.h>
5387235Smarkm#include <pwd.h>
5487235Smarkm#include <stdio.h>
5587235Smarkm#include <stdlib.h>
5613840Swosch#include <string.h>
5787235Smarkm#include <unistd.h>
5813840Swosch
5913840Swosch#include "pathnames.h"
6013840Swosch#include "calendar.h"
6113840Swosch
62181322Sedwinconst char *calendarFile = "calendar";	/* default calendar file */
63241737Sedstatic const char *calendarHomes[] = {".calendar", _PATH_INCLUDE}; /* HOME */
64241737Sedstatic const char *calendarNoMail = "nomail";/* don't sent mail if file exist */
6513840Swosch
66241737Sedstatic char path[MAXPATHLEN];
67181322Sedwin
68205821Sedwinstruct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon;
69205821Sedwinstruct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice;
7015720Sache
71205821Sedwin#define	REPLACE(string, slen, struct_) \
72205821Sedwin		if (strncasecmp(buf, (string), (slen)) == 0 && buf[(slen)]) { \
73205821Sedwin			if (struct_.name != NULL)			      \
74205821Sedwin				free(struct_.name);			      \
75205821Sedwin			if ((struct_.name = strdup(buf + (slen))) == NULL)    \
76205821Sedwin				errx(1, "cannot allocate memory");	      \
77205821Sedwin			struct_.len = strlen(buf + (slen));		      \
78205821Sedwin			continue;					      \
79205821Sedwin		}
8013840Swoschvoid
81169343Sdwmalonecal(void)
8213840Swosch{
83205821Sedwin	char *pp, p;
84255715Sdb	FILE *fpin;
85255715Sdb	FILE *fpout;
86255715Sdb	int l;
87205821Sedwin	int count, i;
88205821Sedwin	int month[MAXCOUNT];
89205821Sedwin	int day[MAXCOUNT];
90205821Sedwin	int year[MAXCOUNT];
91205821Sedwin	char **extradata;	/* strings of 20 length */
92205821Sedwin	int flags;
9374583Sache	static int d_first = -1;
9413840Swosch	char buf[2048 + 1];
95205821Sedwin	struct event *events[MAXCOUNT];
96205821Sedwin	struct tm tm;
97205821Sedwin	char dbuf[80];
9813840Swosch
99255715Sdb	initcpp();
100205821Sedwin	extradata = (char **)calloc(MAXCOUNT, sizeof(char *));
101205821Sedwin	for (i = 0; i < MAXCOUNT; i++) {
102205821Sedwin		extradata[i] = (char *)calloc(1, 20);
103205821Sedwin	}
104205821Sedwin
105205821Sedwin	/* Unused */
106205821Sedwin	tm.tm_sec = 0;
107205821Sedwin	tm.tm_min = 0;
108205821Sedwin	tm.tm_hour = 0;
109205821Sedwin	tm.tm_wday = 0;
110205821Sedwin
111205821Sedwin	count = 0;
112255715Sdb	if ((fpin = opencalin()) == NULL) {
113208826Sedwin		free(extradata);
11413840Swosch		return;
115208826Sedwin	}
116255715Sdb	if ((fpout = opencalout()) == NULL) {
117255715Sdb		fclose(fpin);
118255715Sdb		free(extradata);
119255715Sdb		return;
120255715Sdb	}
121255715Sdb	while ((fpin = fincludegets(buf, sizeof(buf), fpin)) != NULL) {
122255715Sdb		if (*buf == '\0')
123255715Sdb			continue;
12415714Sache		for (l = strlen(buf);
12515714Sache		     l > 0 && isspace((unsigned char)buf[l - 1]);
12615714Sache		     l--)
12715714Sache			;
12815714Sache		buf[l] = '\0';
12913840Swosch		if (buf[0] == '\0')
13013840Swosch			continue;
131205821Sedwin
132205821Sedwin		/* Parse special definitions: LANG, Easter, Paskha etc */
13315714Sache		if (strncmp(buf, "LANG=", 5) == 0) {
134181322Sedwin			(void)setlocale(LC_ALL, buf + 5);
13574583Sache			d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
13615714Sache			setnnames();
13715714Sache			continue;
13815714Sache		}
139205821Sedwin		REPLACE("Easter=", 7, neaster);
140205821Sedwin		REPLACE("Paskha=", 7, npaskha);
141205821Sedwin		REPLACE("ChineseNewYear=", 15, ncny);
142205821Sedwin		REPLACE("NewMoon=", 8, nnewmoon);
143205821Sedwin		REPLACE("FullMoon=", 9, nfullmoon);
144205821Sedwin		REPLACE("MarEquinox=", 11, nmarequinox);
145205821Sedwin		REPLACE("SepEquinox=", 11, nsepequinox);
146205821Sedwin		REPLACE("JunSolstice=", 12, njunsolstice);
147205821Sedwin		REPLACE("DecSolstice=", 12, ndecsolstice);
148205821Sedwin		if (strncmp(buf, "SEQUENCE=", 9) == 0) {
149205821Sedwin			setnsequences(buf + 9);
15015720Sache			continue;
15115720Sache		}
15215723Sache
153181322Sedwin		/*
154205821Sedwin		 * If the line starts with a tab, the data has to be
155205821Sedwin		 * added to the previous line
156181322Sedwin		 */
157205821Sedwin		if (buf[0] == '\t') {
158205821Sedwin			for (i = 0; i < count; i++)
159205821Sedwin				event_continue(events[i], buf);
160205821Sedwin			continue;
161170447Sgrog		}
162170447Sgrog
163205821Sedwin		/* Get rid of leading spaces (non-standard) */
164207701Sache		while (isspace((unsigned char)buf[0]))
165207701Sache			memcpy(buf, buf + 1, strlen(buf));
166170447Sgrog
167205821Sedwin		/* No tab in the line, then not a valid line */
168205821Sedwin		if ((pp = strchr(buf, '\t')) == NULL)
169205821Sedwin			continue;
170170447Sgrog
171205821Sedwin		/* Trim spaces in front of the tab */
172207703Sache		while (isspace((unsigned char)pp[-1]))
173205821Sedwin			pp--;
174205821Sedwin
175205821Sedwin		p = *pp;
176205821Sedwin		*pp = '\0';
177205821Sedwin		if ((count = parsedaymonth(buf, year, month, day, &flags,
178205821Sedwin		    extradata)) == 0)
179205821Sedwin			continue;
180205821Sedwin		*pp = p;
181205821Sedwin		if (count < 0) {
182205821Sedwin			/* Show error status based on return value */
183227370Sgrog			if (debug)
184227370Sgrog				fprintf(stderr, "Ignored: %s\n", buf);
185205821Sedwin			if (count == -1)
186170447Sgrog				continue;
187205821Sedwin			count = -count + 1;
188170447Sgrog		}
189170447Sgrog
190205821Sedwin		/* Find the last tab */
191205821Sedwin		while (pp[1] == '\t')
192205821Sedwin			pp++;
19313840Swosch
194205821Sedwin		if (d_first < 0)
195205821Sedwin			d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
196170447Sgrog
197205821Sedwin		for (i = 0; i < count; i++) {
198205821Sedwin			tm.tm_mon = month[i] - 1;
199205821Sedwin			tm.tm_mday = day[i];
200205821Sedwin			tm.tm_year = year[i] - 1900;
201205821Sedwin			(void)strftime(dbuf, sizeof(dbuf),
202205821Sedwin			    d_first ? "%e %b" : "%b %e", &tm);
203205821Sedwin			if (debug)
204205821Sedwin				fprintf(stderr, "got %s\n", pp);
205205821Sedwin			events[i] = event_add(year[i], month[i], day[i], dbuf,
206205821Sedwin			    ((flags &= F_VARIABLE) != 0) ? 1 : 0, pp,
207205821Sedwin			    extradata[i]);
208181322Sedwin		}
20913840Swosch	}
21013840Swosch
211255715Sdb	event_print_all(fpout);
212255715Sdb	closecal(fpout);
213208826Sedwin	free(extradata);
21413840Swosch}
21513840Swosch
21613840SwoschFILE *
217255715Sdbopencalin(void)
21813840Swosch{
219100811Sjmallett	size_t i;
220255715Sdb	int found;
22113840Swosch	struct stat sbuf;
222255715Sdb	FILE *fpin;
22313840Swosch
224255715Sdb	/* open up calendar file */
225255715Sdb	if ((fpin = fopen(calendarFile, "r")) == NULL) {
22613840Swosch		if (doall) {
227181322Sedwin			if (chdir(calendarHomes[0]) != 0)
228181322Sedwin				return (NULL);
229181322Sedwin			if (stat(calendarNoMail, &sbuf) == 0)
230181322Sedwin				return (NULL);
231255715Sdb			if ((fpin = fopen(calendarFile, "r")) == NULL)
232181322Sedwin				return (NULL);
23313840Swosch		} else {
234173169Skevlo			char *home = getenv("HOME");
235173169Skevlo			if (home == NULL || *home == '\0')
236173169Skevlo				errx(1, "cannot get home directory");
237208825Sedwin			if (chdir(home) != 0)
238208825Sedwin				errx(1, "cannot enter home directory");
239100811Sjmallett			for (found = i = 0; i < sizeof(calendarHomes) /
240100811Sjmallett			    sizeof(calendarHomes[0]); i++)
241181322Sedwin				if (chdir(calendarHomes[i]) == 0 &&
242255715Sdb				    (fpin = fopen(calendarFile, "r")) != NULL) {
243181322Sedwin					found = 1;
244181322Sedwin					break;
245181322Sedwin				}
246100811Sjmallett			if (!found)
247181322Sedwin				errx(1,
248181322Sedwin				    "can't open calendar file \"%s\": %s (%d)",
249181322Sedwin				    calendarFile, strerror(errno), errno);
25013840Swosch		}
25113840Swosch	}
252255715Sdb	return (fpin);
253255715Sdb}
25413840Swosch
255255715SdbFILE *
256255715Sdbopencalout(void)
257255715Sdb{
258255715Sdb	int fd;
259255715Sdb
26013840Swosch	/* not reading all calendar files, just set output to stdout */
26113840Swosch	if (!doall)
26213840Swosch		return (stdout);
26313840Swosch
26413840Swosch	/* set output to a temporary file, so if no output don't send mail */
265255715Sdb	snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
26613840Swosch	if ((fd = mkstemp(path)) < 0)
26713840Swosch		return (NULL);
26813840Swosch	return (fdopen(fd, "w+"));
26913840Swosch}
27013840Swosch
27113840Swoschvoid
272169343Sdwmaloneclosecal(FILE *fp)
27313840Swosch{
27422473Smpp	uid_t uid;
27513840Swosch	struct stat sbuf;
27613840Swosch	int nread, pdes[2], status;
27713840Swosch	char buf[1024];
27813840Swosch
27913840Swosch	if (!doall)
28013840Swosch		return;
28113840Swosch
282200628Srse	rewind(fp);
28313840Swosch	if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
28413840Swosch		goto done;
28513840Swosch	if (pipe(pdes) < 0)
28613840Swosch		goto done;
28740302Sdes	switch (fork()) {
28813840Swosch	case -1:			/* error */
28913840Swosch		(void)close(pdes[0]);
29013840Swosch		(void)close(pdes[1]);
29113840Swosch		goto done;
29213840Swosch	case 0:
29313840Swosch		/* child -- set stdin to pipe output */
29413840Swosch		if (pdes[0] != STDIN_FILENO) {
29513840Swosch			(void)dup2(pdes[0], STDIN_FILENO);
29613840Swosch			(void)close(pdes[0]);
29713840Swosch		}
29813840Swosch		(void)close(pdes[1]);
29922473Smpp		uid = geteuid();
30022473Smpp		if (setuid(getuid()) < 0) {
30126839Scharnier			warnx("setuid failed");
30222473Smpp			_exit(1);
30322473Smpp		};
30422473Smpp		if (setgid(getegid()) < 0) {
30526839Scharnier			warnx("setgid failed");
30622473Smpp			_exit(1);
30722473Smpp		}
30822473Smpp		if (setuid(uid) < 0) {
30926839Scharnier			warnx("setuid failed");
31022473Smpp			_exit(1);
31122473Smpp		}
31213840Swosch		execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
31379452Sbrian		    "\"Reminder Service\"", (char *)NULL);
31426839Scharnier		warn(_PATH_SENDMAIL);
31513840Swosch		_exit(1);
31613840Swosch	}
31713840Swosch	/* parent -- write to pipe input */
31813840Swosch	(void)close(pdes[0]);
31913840Swosch
320205821Sedwin	write(pdes[1], "From: \"Reminder Service\" <", 26);
321205821Sedwin	write(pdes[1], pw->pw_name, strlen(pw->pw_name));
322205821Sedwin	write(pdes[1], ">\nTo: <", 7);
323205821Sedwin	write(pdes[1], pw->pw_name, strlen(pw->pw_name));
324222755Sjh	write(pdes[1], ">\nSubject: ", 11);
325205821Sedwin	write(pdes[1], dayname, strlen(dayname));
326205821Sedwin	write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30);
327205821Sedwin
32813840Swosch	while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
32913840Swosch		(void)write(pdes[1], buf, nread);
33013840Swosch	(void)close(pdes[1]);
33113840Swoschdone:	(void)fclose(fp);
33213840Swosch	(void)unlink(path);
33313840Swosch	while (wait(&status) >= 0);
33413840Swosch}
335