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