io.c revision 170447
113840Swosch/* 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 170447 2007-06-09 05:54:13Z grog $"); 4887628Sdwmalone 4987235Smarkm#include <sys/types.h> 5013840Swosch#include <sys/param.h> 5187235Smarkm#include <sys/stat.h> 5287235Smarkm#include <sys/time.h> 5387235Smarkm#include <sys/uio.h> 5487235Smarkm#include <sys/wait.h> 5513840Swosch#include <ctype.h> 5613840Swosch#include <err.h> 5713840Swosch#include <errno.h> 5874583Sache#include <langinfo.h> 5915714Sache#include <locale.h> 6087235Smarkm#include <pwd.h> 6187235Smarkm#include <stdio.h> 6287235Smarkm#include <stdlib.h> 6313840Swosch#include <string.h> 6487235Smarkm#include <unistd.h> 6513840Swosch 6613840Swosch#include "pathnames.h" 6713840Swosch#include "calendar.h" 6813840Swosch 6913840Swosch 7087235Smarkmconst char *calendarFile = "calendar"; /* default calendar file */ 71100811Sjmallettconst char *calendarHomes[] = { ".calendar", _PATH_INCLUDE }; /* HOME */ 7287235Smarkmconst char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */ 7313840Swosch 7415720Sachestruct fixs neaster, npaskha; 7515720Sache 7613840Swoschstruct iovec header[] = { 7715714Sache {"From: ", 6}, 7815714Sache {NULL, 0}, 7915714Sache {" (Reminder Service)\nTo: ", 24}, 8015714Sache {NULL, 0}, 8115714Sache {"\nSubject: ", 10}, 8215714Sache {NULL, 0}, 8315714Sache {"'s Calendar\nPrecedence: bulk\n\n", 30}, 8413840Swosch}; 8513840Swosch 8613840Swosch 8713840Swoschvoid 88169343Sdwmalonecal(void) 8913840Swosch{ 9087235Smarkm int printing; 9187235Smarkm char *p; 9213840Swosch FILE *fp; 9315714Sache int ch, l; 9415066Smpp int month; 9515066Smpp int day; 9615066Smpp int var; 9774583Sache static int d_first = -1; 9813840Swosch char buf[2048 + 1]; 99170447Sgrog struct event *events = NULL; 10013840Swosch 10113840Swosch if ((fp = opencal()) == NULL) 10213840Swosch return; 10313840Swosch for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) { 10413840Swosch if ((p = strchr(buf, '\n')) != NULL) 10513840Swosch *p = '\0'; 10613840Swosch else 10713840Swosch while ((ch = getchar()) != '\n' && ch != EOF); 10815714Sache for (l = strlen(buf); 10915714Sache l > 0 && isspace((unsigned char)buf[l - 1]); 11015714Sache l--) 11115714Sache ; 11215714Sache buf[l] = '\0'; 11313840Swosch if (buf[0] == '\0') 11413840Swosch continue; 11515714Sache if (strncmp(buf, "LANG=", 5) == 0) { 11615714Sache (void) setlocale(LC_ALL, buf + 5); 11774583Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 11815714Sache setnnames(); 11915714Sache continue; 12015714Sache } 12115720Sache if (strncasecmp(buf, "Easter=", 7) == 0 && buf[7]) { 12215720Sache if (neaster.name != NULL) 12315720Sache free(neaster.name); 12426839Scharnier if ((neaster.name = strdup(buf + 7)) == NULL) 12526839Scharnier errx(1, "cannot allocate memory"); 12615720Sache neaster.len = strlen(buf + 7); 12715720Sache continue; 12815720Sache } 12915720Sache if (strncasecmp(buf, "Paskha=", 7) == 0 && buf[7]) { 13015720Sache if (npaskha.name != NULL) 13115720Sache free(npaskha.name); 13226839Scharnier if ((npaskha.name = strdup(buf + 7)) == NULL) 13326839Scharnier errx(1, "cannot allocate memory"); 13415720Sache npaskha.len = strlen(buf + 7); 13515720Sache continue; 13615720Sache } 13715066Smpp if (buf[0] != '\t') { 13815066Smpp printing = isnow(buf, &month, &day, &var) ? 1 : 0; 13915066Smpp if ((p = strchr(buf, '\t')) == NULL) 14015066Smpp continue; 14115066Smpp if (p > buf && p[-1] == '*') 14215066Smpp var = 1; 14315723Sache if (printing) { 14415723Sache struct tm tm; 14574583Sache char dbuf[80]; 14615723Sache 14774583Sache if (d_first < 0) 14874583Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 14915723Sache tm.tm_sec = 0; /* unused */ 15015723Sache tm.tm_min = 0; /* unused */ 15115723Sache tm.tm_hour = 0; /* unused */ 15215723Sache tm.tm_wday = 0; /* unused */ 15315723Sache tm.tm_mon = month - 1; 15415723Sache tm.tm_mday = day; 15515723Sache tm.tm_year = tp->tm_year; /* unused */ 15674583Sache (void)strftime(dbuf, sizeof(dbuf), 15774583Sache d_first ? "%e %b" : "%b %e", 15874583Sache &tm); 159170447Sgrog events = event_add(events, month, day, dbuf, var, p); 16015723Sache } 16115066Smpp } 16215066Smpp else if (printing) 163170447Sgrog event_continue(events, buf); 16413840Swosch } 165170447Sgrog 166170447Sgrog event_print_all(fp, events); 16713840Swosch closecal(fp); 16813840Swosch} 16913840Swosch 170170447Sgrog/* 171170447Sgrog * Functions to handle buffered calendar events. 172170447Sgrog */ 173170447Sgrogstruct event * 174170447Sgrogevent_add(struct event *events, int month, int day, char *date, int var, char *txt) 175170447Sgrog{ 176170447Sgrog struct event *e; 177170447Sgrog 178170447Sgrog e = (struct event *)calloc(1, sizeof(struct event)); 179170447Sgrog if (e == NULL) 180170447Sgrog errx(1, "event_add: cannot allocate memory"); 181170447Sgrog e->month = month; 182170447Sgrog e->day = day; 183170447Sgrog e->var = var; 184170447Sgrog e->date = strdup(date); 185170447Sgrog if (e->date == NULL) 186170447Sgrog errx(1, "event_add: cannot allocate memory"); 187170447Sgrog e->text = strdup(txt); 188170447Sgrog if (e->text == NULL) 189170447Sgrog errx(1, "event_add: cannot allocate memory"); 190170447Sgrog e->next = events; 191170447Sgrog 192170447Sgrog return e; 193170447Sgrog} 194170447Sgrog 195170447Sgrogvoid 196170447Sgrogevent_continue(struct event *e, char *txt) 197170447Sgrog{ 198170447Sgrog char *text; 199170447Sgrog 200170447Sgrog text = strdup(e->text); 201170447Sgrog if (text == NULL) 202170447Sgrog errx(1, "event_continue: cannot allocate memory"); 203170447Sgrog 204170447Sgrog free(e->text); 205170447Sgrog e->text = (char *)malloc(strlen(text) + strlen(txt) + 3); 206170447Sgrog if (e->text == NULL) 207170447Sgrog errx(1, "event_continue: cannot allocate memory"); 208170447Sgrog strcpy(e->text, text); 209170447Sgrog strcat(e->text, "\n"); 210170447Sgrog strcat(e->text, txt); 211170447Sgrog free(text); 212170447Sgrog 213170447Sgrog return; 214170447Sgrog} 215170447Sgrog 216170447Sgrogvoid 217170447Sgrogevent_print_all(FILE *fp, struct event *events) 218170447Sgrog{ 219170447Sgrog struct event *e, *e_next; 220170447Sgrog int daycount = f_dayAfter + f_dayBefore; 221170447Sgrog int daycounter; 222170447Sgrog int day, month; 223170447Sgrog 224170447Sgrog for (daycounter = 0; daycounter <= daycount; daycounter++) { 225170447Sgrog day = tp->tm_yday - f_dayBefore + daycounter; 226170447Sgrog if (day < 0) day += yrdays; 227170447Sgrog if (day >= yrdays) day -= yrdays; 228170447Sgrog 229170447Sgrog month = 1; 230170447Sgrog while (month <= 12) { 231170447Sgrog if (day <= cumdays[month]) 232170447Sgrog break; 233170447Sgrog month++; 234170447Sgrog } 235170447Sgrog month--; 236170447Sgrog day -= cumdays[month]; 237170447Sgrog 238170447Sgrog#ifdef DEBUG 239170447Sgrog fprintf(stderr,"event_print_allmonth: %d, day: %d\n",month,day); 240170447Sgrog#endif 241170447Sgrog 242170447Sgrog for (e = events; e != NULL; e = e_next ) { 243170447Sgrog e_next = e->next; 244170447Sgrog 245170447Sgrog if (month != e->month || day != e->day) 246170447Sgrog continue; 247170447Sgrog 248170447Sgrog (void)fprintf(fp, "%s%c%s\n", e->date, 249170447Sgrog e->var ? '*' : ' ', e->text); 250170447Sgrog } 251170447Sgrog } 252170447Sgrog} 253170447Sgrog 25413840Swoschint 255169343Sdwmalonegetfield(char *p, char **endp, int *flags) 25613840Swosch{ 25713840Swosch int val, var; 25813840Swosch char *start, savech; 25913840Swosch 260170447Sgrog for (; !isdigit((unsigned char)*p) && !isalpha((unsigned char)*p) 261170447Sgrog && *p != '*'; ++p); 26213840Swosch if (*p == '*') { /* `*' is current month */ 26313840Swosch *flags |= F_ISMONTH; 26413840Swosch *endp = p+1; 26513840Swosch return (tp->tm_mon + 1); 26613840Swosch } 26715714Sache if (isdigit((unsigned char)*p)) { 26813840Swosch val = strtol(p, &p, 10); /* if 0, it's failure */ 269170447Sgrog for (; !isdigit((unsigned char)*p) 270170447Sgrog && !isalpha((unsigned char)*p) && *p != '*'; ++p); 27113840Swosch *endp = p; 27213840Swosch return (val); 27313840Swosch } 27415714Sache for (start = p; isalpha((unsigned char)*++p);); 275170447Sgrog 27613840Swosch /* Sunday-1 */ 277170447Sgrog if (*p == '+' || *p == '-') 27815714Sache for(; isdigit((unsigned char)*++p);); 279170447Sgrog 28013840Swosch savech = *p; 28113840Swosch *p = '\0'; 28213840Swosch 28313840Swosch /* Month */ 28413840Swosch if ((val = getmonth(start)) != 0) 28513840Swosch *flags |= F_ISMONTH; 28613840Swosch 28713840Swosch /* Day */ 28813840Swosch else if ((val = getday(start)) != 0) { 28913840Swosch *flags |= F_ISDAY; 29013840Swosch 29113840Swosch /* variable weekday */ 29213840Swosch if ((var = getdayvar(start)) != 0) { 29313840Swosch if (var <=5 && var >= -4) 29413840Swosch val += var * 10; 29513840Swosch#ifdef DEBUG 29613840Swosch printf("var: %d\n", var); 29713840Swosch#endif 298170447Sgrog } 29913840Swosch } 30013840Swosch 30113840Swosch /* Easter */ 30213840Swosch else if ((val = geteaster(start, tp->tm_year + 1900)) != 0) 30313840Swosch *flags |= F_EASTER; 30413840Swosch 30515714Sache /* Paskha */ 30615714Sache else if ((val = getpaskha(start, tp->tm_year + 1900)) != 0) 30715714Sache *flags |= F_EASTER; 30815714Sache 30913840Swosch /* undefined rest */ 31013840Swosch else { 31113840Swosch *p = savech; 31213840Swosch return (0); 31313840Swosch } 314170447Sgrog for (*p = savech; !isdigit((unsigned char)*p) 315170447Sgrog && !isalpha((unsigned char)*p) && *p != '*'; ++p); 31613840Swosch *endp = p; 31713840Swosch return (val); 31813840Swosch} 31913840Swosch 32073257Simpchar path[MAXPATHLEN]; 32113840Swosch 32213840SwoschFILE * 323169343Sdwmaloneopencal(void) 32413840Swosch{ 32522473Smpp uid_t uid; 326100811Sjmallett size_t i; 327100811Sjmallett int fd, found, pdes[2]; 32813840Swosch struct stat sbuf; 32913840Swosch 33013840Swosch /* open up calendar file as stdin */ 33113840Swosch if (!freopen(calendarFile, "r", stdin)) { 33213840Swosch if (doall) { 333100811Sjmallett if (chdir(calendarHomes[0]) != 0) 33413840Swosch return (NULL); 33513840Swosch if (stat(calendarNoMail, &sbuf) == 0) 33613840Swosch return (NULL); 33713840Swosch if (!freopen(calendarFile, "r", stdin)) 33813840Swosch return (NULL); 33913840Swosch } else { 34013840Swosch chdir(getenv("HOME")); 341100811Sjmallett for (found = i = 0; i < sizeof(calendarHomes) / 342100811Sjmallett sizeof(calendarHomes[0]); i++) 343100811Sjmallett if (chdir(calendarHomes[i]) == 0 && 344100811Sjmallett freopen(calendarFile, "r", stdin)) { 345100811Sjmallett found = 1; 346100811Sjmallett break; 347100811Sjmallett } 348100811Sjmallett if (!found) 349100811Sjmallett errx(1, "no calendar file: ``%s''", calendarFile); 35013840Swosch } 35113840Swosch } 35213840Swosch if (pipe(pdes) < 0) 35313840Swosch return (NULL); 35440302Sdes switch (fork()) { 35513840Swosch case -1: /* error */ 35613840Swosch (void)close(pdes[0]); 35713840Swosch (void)close(pdes[1]); 35813840Swosch return (NULL); 35913840Swosch case 0: 36013840Swosch /* child -- stdin already setup, set stdout to pipe input */ 36113840Swosch if (pdes[1] != STDOUT_FILENO) { 36213840Swosch (void)dup2(pdes[1], STDOUT_FILENO); 36313840Swosch (void)close(pdes[1]); 36413840Swosch } 36513840Swosch (void)close(pdes[0]); 36622473Smpp uid = geteuid(); 36722473Smpp if (setuid(getuid()) < 0) { 36826839Scharnier warnx("first setuid failed"); 36922473Smpp _exit(1); 37022473Smpp }; 37122473Smpp if (setgid(getegid()) < 0) { 37226839Scharnier warnx("setgid failed"); 37322473Smpp _exit(1); 37422473Smpp } 37522473Smpp if (setuid(uid) < 0) { 37626839Scharnier warnx("setuid failed"); 37722473Smpp _exit(1); 37822473Smpp } 37955716Sobrien execl(_PATH_CPP, "cpp", "-P", 38055716Sobrien "-traditional", "-nostdinc", /* GCC specific opts */ 38179452Sbrian "-I.", "-I", _PATH_INCLUDE, (char *)NULL); 38226839Scharnier warn(_PATH_CPP); 38313840Swosch _exit(1); 38413840Swosch } 38513840Swosch /* parent -- set stdin to pipe output */ 38613840Swosch (void)dup2(pdes[0], STDIN_FILENO); 38713840Swosch (void)close(pdes[0]); 38813840Swosch (void)close(pdes[1]); 38913840Swosch 39013840Swosch /* not reading all calendar files, just set output to stdout */ 39113840Swosch if (!doall) 39213840Swosch return (stdout); 39313840Swosch 39413840Swosch /* set output to a temporary file, so if no output don't send mail */ 39513840Swosch (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP); 39613840Swosch if ((fd = mkstemp(path)) < 0) 39713840Swosch return (NULL); 39813840Swosch return (fdopen(fd, "w+")); 39913840Swosch} 40013840Swosch 40113840Swoschvoid 402169343Sdwmaloneclosecal(FILE *fp) 40313840Swosch{ 40422473Smpp uid_t uid; 40513840Swosch struct stat sbuf; 40613840Swosch int nread, pdes[2], status; 40713840Swosch char buf[1024]; 40813840Swosch 40913840Swosch if (!doall) 41013840Swosch return; 41113840Swosch 41213840Swosch (void)rewind(fp); 41313840Swosch if (fstat(fileno(fp), &sbuf) || !sbuf.st_size) 41413840Swosch goto done; 41513840Swosch if (pipe(pdes) < 0) 41613840Swosch goto done; 41740302Sdes switch (fork()) { 41813840Swosch case -1: /* error */ 41913840Swosch (void)close(pdes[0]); 42013840Swosch (void)close(pdes[1]); 42113840Swosch goto done; 42213840Swosch case 0: 42313840Swosch /* child -- set stdin to pipe output */ 42413840Swosch if (pdes[0] != STDIN_FILENO) { 42513840Swosch (void)dup2(pdes[0], STDIN_FILENO); 42613840Swosch (void)close(pdes[0]); 42713840Swosch } 42813840Swosch (void)close(pdes[1]); 42922473Smpp uid = geteuid(); 43022473Smpp if (setuid(getuid()) < 0) { 43126839Scharnier warnx("setuid failed"); 43222473Smpp _exit(1); 43322473Smpp }; 43422473Smpp if (setgid(getegid()) < 0) { 43526839Scharnier warnx("setgid failed"); 43622473Smpp _exit(1); 43722473Smpp } 43822473Smpp if (setuid(uid) < 0) { 43926839Scharnier warnx("setuid failed"); 44022473Smpp _exit(1); 44122473Smpp } 44213840Swosch execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F", 44379452Sbrian "\"Reminder Service\"", (char *)NULL); 44426839Scharnier warn(_PATH_SENDMAIL); 44513840Swosch _exit(1); 44613840Swosch } 44713840Swosch /* parent -- write to pipe input */ 44813840Swosch (void)close(pdes[0]); 44913840Swosch 45013840Swosch header[1].iov_base = header[3].iov_base = pw->pw_name; 45113840Swosch header[1].iov_len = header[3].iov_len = strlen(pw->pw_name); 45213840Swosch writev(pdes[1], header, 7); 45313840Swosch while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) 45413840Swosch (void)write(pdes[1], buf, nread); 45513840Swosch (void)close(pdes[1]); 45613840Swoschdone: (void)fclose(fp); 45713840Swosch (void)unlink(path); 45813840Swosch while (wait(&status) >= 0); 45913840Swosch} 460