io.c revision 205821
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 * 3. All advertising materials mentioning features or use of this software
1413840Swosch *    must display the following acknowledgement:
1513840Swosch *	This product includes software developed by the University of
1613840Swosch *	California, Berkeley and its contributors.
1713840Swosch * 4. Neither the name of the University nor the names of its contributors
1813840Swosch *    may be used to endorse or promote products derived from this software
1913840Swosch *    without specific prior written permission.
2013840Swosch *
2113840Swosch * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2213840Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2313840Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2413840Swosch * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2513840Swosch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2613840Swosch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2713840Swosch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2813840Swosch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2913840Swosch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3013840Swosch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3113840Swosch * SUCH DAMAGE.
3213840Swosch */
3313840Swosch
3413840Swosch#ifndef lint
3515714Sachestatic const char copyright[] =
3613840Swosch"@(#) Copyright (c) 1989, 1993\n\
3713840Swosch	The Regents of the University of California.  All rights reserved.\n";
3887235Smarkm#endif
3913840Swosch
4087628Sdwmalone#if 0
4113840Swosch#ifndef lint
4287628Sdwmalonestatic char sccsid[] = "@(#)calendar.c  8.3 (Berkeley) 3/25/94";
4387235Smarkm#endif
4487628Sdwmalone#endif
4513840Swosch
4687628Sdwmalone#include <sys/cdefs.h>
4787628Sdwmalone__FBSDID("$FreeBSD: head/usr.bin/calendar/io.c 205821 2010-03-29 06:49:20Z edwin $");
4887628Sdwmalone
4913840Swosch#include <sys/param.h>
5087235Smarkm#include <sys/stat.h>
5187235Smarkm#include <sys/wait.h>
5213840Swosch#include <ctype.h>
5313840Swosch#include <err.h>
5413840Swosch#include <errno.h>
5574583Sache#include <langinfo.h>
5615714Sache#include <locale.h>
5787235Smarkm#include <pwd.h>
5887235Smarkm#include <stdio.h>
5987235Smarkm#include <stdlib.h>
6013840Swosch#include <string.h>
6187235Smarkm#include <unistd.h>
6213840Swosch
6313840Swosch#include "pathnames.h"
6413840Swosch#include "calendar.h"
6513840Swosch
66181322Sedwinconst char *calendarFile = "calendar";	/* default calendar file */
67181322Sedwinconst char *calendarHomes[] = {".calendar", _PATH_INCLUDE};	/* HOME */
68181322Sedwinconst char *calendarNoMail = "nomail";	/* don't sent mail if this file exist */
6913840Swosch
70181322Sedwinchar	path[MAXPATHLEN];
71181322Sedwin
72205821Sedwinstruct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon;
73205821Sedwinstruct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice;
7415720Sache
75205821Sedwin#define	REPLACE(string, slen, struct_) \
76205821Sedwin		if (strncasecmp(buf, (string), (slen)) == 0 && buf[(slen)]) { \
77205821Sedwin			if (struct_.name != NULL)			      \
78205821Sedwin				free(struct_.name);			      \
79205821Sedwin			if ((struct_.name = strdup(buf + (slen))) == NULL)    \
80205821Sedwin				errx(1, "cannot allocate memory");	      \
81205821Sedwin			struct_.len = strlen(buf + (slen));		      \
82205821Sedwin			continue;					      \
83205821Sedwin		}
8413840Swoschvoid
85169343Sdwmalonecal(void)
8613840Swosch{
87205821Sedwin	char *pp, p;
8813840Swosch	FILE *fp;
8915714Sache	int ch, l;
90205821Sedwin	int count, i;
91205821Sedwin	int month[MAXCOUNT];
92205821Sedwin	int day[MAXCOUNT];
93205821Sedwin	int year[MAXCOUNT];
94205821Sedwin	char **extradata;	/* strings of 20 length */
95205821Sedwin	int flags;
9674583Sache	static int d_first = -1;
9713840Swosch	char buf[2048 + 1];
98205821Sedwin	struct event *events[MAXCOUNT];
99205821Sedwin	struct tm tm;
100205821Sedwin	char dbuf[80];
10113840Swosch
102205821Sedwin	extradata = (char **)calloc(MAXCOUNT, sizeof(char *));
103205821Sedwin	for (i = 0; i < MAXCOUNT; i++) {
104205821Sedwin		extradata[i] = (char *)calloc(1, 20);
105205821Sedwin	}
106205821Sedwin
107205821Sedwin	/* Unused */
108205821Sedwin	tm.tm_sec = 0;
109205821Sedwin	tm.tm_min = 0;
110205821Sedwin	tm.tm_hour = 0;
111205821Sedwin	tm.tm_wday = 0;
112205821Sedwin
113205821Sedwin	count = 0;
11413840Swosch	if ((fp = opencal()) == NULL)
11513840Swosch		return;
116205821Sedwin	while (fgets(buf, sizeof(buf), stdin) != NULL) {
117205821Sedwin		if ((pp = strchr(buf, '\n')) != NULL)
118205821Sedwin			*pp = '\0';
11913840Swosch		else
120205821Sedwin			/* Flush this line */
12113840Swosch			while ((ch = getchar()) != '\n' && ch != EOF);
12215714Sache		for (l = strlen(buf);
12315714Sache		     l > 0 && isspace((unsigned char)buf[l - 1]);
12415714Sache		     l--)
12515714Sache			;
12615714Sache		buf[l] = '\0';
12713840Swosch		if (buf[0] == '\0')
12813840Swosch			continue;
129205821Sedwin
130205821Sedwin		/* Parse special definitions: LANG, Easter, Paskha etc */
13115714Sache		if (strncmp(buf, "LANG=", 5) == 0) {
132181322Sedwin			(void)setlocale(LC_ALL, buf + 5);
13374583Sache			d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
13415714Sache			setnnames();
13515714Sache			continue;
13615714Sache		}
137205821Sedwin		REPLACE("Easter=", 7, neaster);
138205821Sedwin		REPLACE("Paskha=", 7, npaskha);
139205821Sedwin		REPLACE("ChineseNewYear=", 15, ncny);
140205821Sedwin		REPLACE("NewMoon=", 8, nnewmoon);
141205821Sedwin		REPLACE("FullMoon=", 9, nfullmoon);
142205821Sedwin		REPLACE("MarEquinox=", 11, nmarequinox);
143205821Sedwin		REPLACE("SepEquinox=", 11, nsepequinox);
144205821Sedwin		REPLACE("JunSolstice=", 12, njunsolstice);
145205821Sedwin		REPLACE("DecSolstice=", 12, ndecsolstice);
146205821Sedwin		if (strncmp(buf, "SEQUENCE=", 9) == 0) {
147205821Sedwin			setnsequences(buf + 9);
14815720Sache			continue;
14915720Sache		}
15015723Sache
151181322Sedwin		/*
152205821Sedwin		 * If the line starts with a tab, the data has to be
153205821Sedwin		 * added to the previous line
154181322Sedwin		 */
155205821Sedwin		if (buf[0] == '\t') {
156205821Sedwin			for (i = 0; i < count; i++)
157205821Sedwin				event_continue(events[i], buf);
158205821Sedwin			continue;
159170447Sgrog		}
160170447Sgrog
161205821Sedwin		/* Get rid of leading spaces (non-standard) */
162205821Sedwin		while (isspace(buf[0]))
163205821Sedwin			memcpy(buf, buf + 1, strlen(buf) - 1);
164170447Sgrog
165205821Sedwin		/* No tab in the line, then not a valid line */
166205821Sedwin		if ((pp = strchr(buf, '\t')) == NULL)
167205821Sedwin			continue;
168170447Sgrog
169205821Sedwin		/* Trim spaces in front of the tab */
170205821Sedwin		while (isspace(pp[-1]))
171205821Sedwin			pp--;
172205821Sedwin
173205821Sedwin		p = *pp;
174205821Sedwin		*pp = '\0';
175205821Sedwin		if ((count = parsedaymonth(buf, year, month, day, &flags,
176205821Sedwin		    extradata)) == 0)
177205821Sedwin			continue;
178205821Sedwin		*pp = p;
179205821Sedwin		if (count < 0) {
180205821Sedwin			/* Show error status based on return value */
181205821Sedwin			fprintf(stderr, "Ignored: %s\n", buf);
182205821Sedwin			if (count == -1)
183170447Sgrog				continue;
184205821Sedwin			count = -count + 1;
185170447Sgrog		}
186170447Sgrog
187205821Sedwin		/* Find the last tab */
188205821Sedwin		while (pp[1] == '\t')
189205821Sedwin			pp++;
19013840Swosch
191205821Sedwin		if (d_first < 0)
192205821Sedwin			d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
193170447Sgrog
194205821Sedwin		for (i = 0; i < count; i++) {
195205821Sedwin			tm.tm_mon = month[i] - 1;
196205821Sedwin			tm.tm_mday = day[i];
197205821Sedwin			tm.tm_year = year[i] - 1900;
198205821Sedwin			(void)strftime(dbuf, sizeof(dbuf),
199205821Sedwin			    d_first ? "%e %b" : "%b %e", &tm);
200205821Sedwin			if (debug)
201205821Sedwin				fprintf(stderr, "got %s\n", pp);
202205821Sedwin			events[i] = event_add(year[i], month[i], day[i], dbuf,
203205821Sedwin			    ((flags &= F_VARIABLE) != 0) ? 1 : 0, pp,
204205821Sedwin			    extradata[i]);
205181322Sedwin		}
20613840Swosch	}
20713840Swosch
208205821Sedwin	event_print_all(fp);
209205821Sedwin	closecal(fp);
21013840Swosch}
21113840Swosch
21213840SwoschFILE *
213169343Sdwmaloneopencal(void)
21413840Swosch{
21522473Smpp	uid_t uid;
216100811Sjmallett	size_t i;
217100811Sjmallett	int fd, found, pdes[2];
21813840Swosch	struct stat sbuf;
21913840Swosch
22013840Swosch	/* open up calendar file as stdin */
22113840Swosch	if (!freopen(calendarFile, "r", stdin)) {
22213840Swosch		if (doall) {
223181322Sedwin			if (chdir(calendarHomes[0]) != 0)
224181322Sedwin				return (NULL);
225181322Sedwin			if (stat(calendarNoMail, &sbuf) == 0)
226181322Sedwin				return (NULL);
227181322Sedwin			if (!freopen(calendarFile, "r", stdin))
228181322Sedwin				return (NULL);
22913840Swosch		} else {
230173169Skevlo			char *home = getenv("HOME");
231173169Skevlo			if (home == NULL || *home == '\0')
232173169Skevlo				errx(1, "cannot get home directory");
233173169Skevlo			chdir(home);
234100811Sjmallett			for (found = i = 0; i < sizeof(calendarHomes) /
235100811Sjmallett			    sizeof(calendarHomes[0]); i++)
236181322Sedwin				if (chdir(calendarHomes[i]) == 0 &&
237181322Sedwin				    freopen(calendarFile, "r", stdin)) {
238181322Sedwin					found = 1;
239181322Sedwin					break;
240181322Sedwin				}
241100811Sjmallett			if (!found)
242181322Sedwin				errx(1,
243181322Sedwin				    "can't open calendar file \"%s\": %s (%d)",
244181322Sedwin				    calendarFile, strerror(errno), errno);
24513840Swosch		}
24613840Swosch	}
24713840Swosch	if (pipe(pdes) < 0)
24813840Swosch		return (NULL);
24940302Sdes	switch (fork()) {
25013840Swosch	case -1:			/* error */
25113840Swosch		(void)close(pdes[0]);
25213840Swosch		(void)close(pdes[1]);
25313840Swosch		return (NULL);
25413840Swosch	case 0:
25513840Swosch		/* child -- stdin already setup, set stdout to pipe input */
25613840Swosch		if (pdes[1] != STDOUT_FILENO) {
25713840Swosch			(void)dup2(pdes[1], STDOUT_FILENO);
25813840Swosch			(void)close(pdes[1]);
25913840Swosch		}
26013840Swosch		(void)close(pdes[0]);
26122473Smpp		uid = geteuid();
26222473Smpp		if (setuid(getuid()) < 0) {
26326839Scharnier			warnx("first setuid failed");
26422473Smpp			_exit(1);
26522473Smpp		};
26622473Smpp		if (setgid(getegid()) < 0) {
26726839Scharnier			warnx("setgid failed");
26822473Smpp			_exit(1);
26922473Smpp		}
27022473Smpp		if (setuid(uid) < 0) {
27126839Scharnier			warnx("setuid failed");
27222473Smpp			_exit(1);
27322473Smpp		}
27455716Sobrien		execl(_PATH_CPP, "cpp", "-P",
27555716Sobrien		    "-traditional", "-nostdinc",	/* GCC specific opts */
27679452Sbrian		    "-I.", "-I", _PATH_INCLUDE, (char *)NULL);
27726839Scharnier		warn(_PATH_CPP);
27813840Swosch		_exit(1);
27913840Swosch	}
28013840Swosch	/* parent -- set stdin to pipe output */
28113840Swosch	(void)dup2(pdes[0], STDIN_FILENO);
28213840Swosch	(void)close(pdes[0]);
28313840Swosch	(void)close(pdes[1]);
28413840Swosch
28513840Swosch	/* not reading all calendar files, just set output to stdout */
28613840Swosch	if (!doall)
28713840Swosch		return (stdout);
28813840Swosch
28913840Swosch	/* set output to a temporary file, so if no output don't send mail */
29013840Swosch	(void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
29113840Swosch	if ((fd = mkstemp(path)) < 0)
29213840Swosch		return (NULL);
29313840Swosch	return (fdopen(fd, "w+"));
29413840Swosch}
29513840Swosch
29613840Swoschvoid
297169343Sdwmaloneclosecal(FILE *fp)
29813840Swosch{
29922473Smpp	uid_t uid;
30013840Swosch	struct stat sbuf;
30113840Swosch	int nread, pdes[2], status;
30213840Swosch	char buf[1024];
30313840Swosch
30413840Swosch	if (!doall)
30513840Swosch		return;
30613840Swosch
307200628Srse	rewind(fp);
30813840Swosch	if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
30913840Swosch		goto done;
31013840Swosch	if (pipe(pdes) < 0)
31113840Swosch		goto done;
31240302Sdes	switch (fork()) {
31313840Swosch	case -1:			/* error */
31413840Swosch		(void)close(pdes[0]);
31513840Swosch		(void)close(pdes[1]);
31613840Swosch		goto done;
31713840Swosch	case 0:
31813840Swosch		/* child -- set stdin to pipe output */
31913840Swosch		if (pdes[0] != STDIN_FILENO) {
32013840Swosch			(void)dup2(pdes[0], STDIN_FILENO);
32113840Swosch			(void)close(pdes[0]);
32213840Swosch		}
32313840Swosch		(void)close(pdes[1]);
32422473Smpp		uid = geteuid();
32522473Smpp		if (setuid(getuid()) < 0) {
32626839Scharnier			warnx("setuid failed");
32722473Smpp			_exit(1);
32822473Smpp		};
32922473Smpp		if (setgid(getegid()) < 0) {
33026839Scharnier			warnx("setgid failed");
33122473Smpp			_exit(1);
33222473Smpp		}
33322473Smpp		if (setuid(uid) < 0) {
33426839Scharnier			warnx("setuid failed");
33522473Smpp			_exit(1);
33622473Smpp		}
33713840Swosch		execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
33879452Sbrian		    "\"Reminder Service\"", (char *)NULL);
33926839Scharnier		warn(_PATH_SENDMAIL);
34013840Swosch		_exit(1);
34113840Swosch	}
34213840Swosch	/* parent -- write to pipe input */
34313840Swosch	(void)close(pdes[0]);
34413840Swosch
345205821Sedwin	write(pdes[1], "From: \"Reminder Service\" <", 26);
346205821Sedwin	write(pdes[1], pw->pw_name, strlen(pw->pw_name));
347205821Sedwin	write(pdes[1], ">\nTo: <", 7);
348205821Sedwin	write(pdes[1], pw->pw_name, strlen(pw->pw_name));
349205821Sedwin	write(pdes[1], ">\nSubject: ", 12);
350205821Sedwin	write(pdes[1], dayname, strlen(dayname));
351205821Sedwin	write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30);
352205821Sedwin
35313840Swosch	while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
35413840Swosch		(void)write(pdes[1], buf, nread);
35513840Swosch	(void)close(pdes[1]);
35613840Swoschdone:	(void)fclose(fp);
35713840Swosch	(void)unlink(path);
35813840Swosch	while (wait(&status) >= 0);
35913840Swosch}
360