1fd1efedcSConrad Meyer /*- 2fd1efedcSConrad Meyer * SPDX-License-Identifier: BSD-3-Clause 3fd1efedcSConrad Meyer * 4fd1efedcSConrad Meyer * Copyright (c) 1989, 1993, 1994 5fd1efedcSConrad Meyer * The Regents of the University of California. All rights reserved. 6fd1efedcSConrad Meyer * 7fd1efedcSConrad Meyer * Redistribution and use in source and binary forms, with or without 8fd1efedcSConrad Meyer * modification, are permitted provided that the following conditions 9fd1efedcSConrad Meyer * are met: 10fd1efedcSConrad Meyer * 1. Redistributions of source code must retain the above copyright 11fd1efedcSConrad Meyer * notice, this list of conditions and the following disclaimer. 12fd1efedcSConrad Meyer * 2. Redistributions in binary form must reproduce the above copyright 13fd1efedcSConrad Meyer * notice, this list of conditions and the following disclaimer in the 14fd1efedcSConrad Meyer * documentation and/or other materials provided with the distribution. 15fd1efedcSConrad Meyer * 3. Neither the name of the University nor the names of its contributors 16fd1efedcSConrad Meyer * may be used to endorse or promote products derived from this software 17fd1efedcSConrad Meyer * without specific prior written permission. 18fd1efedcSConrad Meyer * 19fd1efedcSConrad Meyer * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20fd1efedcSConrad Meyer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21fd1efedcSConrad Meyer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22fd1efedcSConrad Meyer * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23fd1efedcSConrad Meyer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24fd1efedcSConrad Meyer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25fd1efedcSConrad Meyer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26fd1efedcSConrad Meyer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27fd1efedcSConrad Meyer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28fd1efedcSConrad Meyer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29fd1efedcSConrad Meyer * SUCH DAMAGE. 30fd1efedcSConrad Meyer */ 31fd1efedcSConrad Meyer 32fd1efedcSConrad Meyer #ifndef lint 33fd1efedcSConrad Meyer static const char copyright[] = 34fd1efedcSConrad Meyer "@(#) Copyright (c) 1989, 1993\n\ 35fd1efedcSConrad Meyer The Regents of the University of California. All rights reserved.\n"; 36fd1efedcSConrad Meyer #endif 37fd1efedcSConrad Meyer 38fd1efedcSConrad Meyer #if 0 39fd1efedcSConrad Meyer #ifndef lint 40fd1efedcSConrad Meyer static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; 41fd1efedcSConrad Meyer #endif 42fd1efedcSConrad Meyer #endif 43fd1efedcSConrad Meyer 44fd1efedcSConrad Meyer #include <sys/cdefs.h> 45fd1efedcSConrad Meyer __FBSDID("$FreeBSD$"); 46fd1efedcSConrad Meyer 47fd1efedcSConrad Meyer #include <sys/param.h> 48fd1efedcSConrad Meyer #include <sys/stat.h> 49fd1efedcSConrad Meyer #include <sys/wait.h> 50fd1efedcSConrad Meyer #include <ctype.h> 51fd1efedcSConrad Meyer #include <err.h> 52fd1efedcSConrad Meyer #include <errno.h> 53fd1efedcSConrad Meyer #include <langinfo.h> 54fd1efedcSConrad Meyer #include <locale.h> 55fd1efedcSConrad Meyer #include <pwd.h> 56fd1efedcSConrad Meyer #include <stdbool.h> 57fd1efedcSConrad Meyer #include <stdio.h> 58fd1efedcSConrad Meyer #include <stdlib.h> 59fd1efedcSConrad Meyer #include <string.h> 60fd1efedcSConrad Meyer #include <stringlist.h> 61fd1efedcSConrad Meyer #include <time.h> 62fd1efedcSConrad Meyer #include <unistd.h> 63fd1efedcSConrad Meyer 64fd1efedcSConrad Meyer #include "pathnames.h" 65fd1efedcSConrad Meyer #include "calendar.h" 66fd1efedcSConrad Meyer 67fd1efedcSConrad Meyer enum { 68fd1efedcSConrad Meyer T_OK = 0, 69fd1efedcSConrad Meyer T_ERR, 70fd1efedcSConrad Meyer T_PROCESS, 71fd1efedcSConrad Meyer }; 72fd1efedcSConrad Meyer 73fd1efedcSConrad Meyer const char *calendarFile = "calendar"; /* default calendar file */ 7434b38e12SStefan Eßer static const char *calendarHomes[] = {".calendar", _PATH_INCLUDE_LOCAL, _PATH_INCLUDE}; /* HOME */ 75fd1efedcSConrad Meyer static const char *calendarNoMail = "nomail";/* don't sent mail if file exist */ 76fd1efedcSConrad Meyer 77fd1efedcSConrad Meyer static char path[MAXPATHLEN]; 78fd1efedcSConrad Meyer 79fd1efedcSConrad Meyer struct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon; 80fd1efedcSConrad Meyer struct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice; 81fd1efedcSConrad Meyer 82fd1efedcSConrad Meyer static int cal_parse(FILE *in, FILE *out); 83fd1efedcSConrad Meyer 84fd1efedcSConrad Meyer static StringList *definitions = NULL; 85fd1efedcSConrad Meyer static struct event *events[MAXCOUNT]; 86fd1efedcSConrad Meyer static char *extradata[MAXCOUNT]; 87fd1efedcSConrad Meyer 88fd1efedcSConrad Meyer static void 89fd1efedcSConrad Meyer trimlr(char **buf) 90fd1efedcSConrad Meyer { 91fd1efedcSConrad Meyer char *walk = *buf; 92fd1efedcSConrad Meyer char *last; 93fd1efedcSConrad Meyer 94fd1efedcSConrad Meyer while (isspace(*walk)) 95fd1efedcSConrad Meyer walk++; 96fd1efedcSConrad Meyer if (*walk != '\0') { 97fd1efedcSConrad Meyer last = walk + strlen(walk) - 1; 98fd1efedcSConrad Meyer while (last > walk && isspace(*last)) 99fd1efedcSConrad Meyer last--; 100fd1efedcSConrad Meyer *(last+1) = 0; 101fd1efedcSConrad Meyer } 102fd1efedcSConrad Meyer 103fd1efedcSConrad Meyer *buf = walk; 104fd1efedcSConrad Meyer } 105fd1efedcSConrad Meyer 106fd1efedcSConrad Meyer static FILE * 107fd1efedcSConrad Meyer cal_fopen(const char *file) 108fd1efedcSConrad Meyer { 109fd1efedcSConrad Meyer FILE *fp; 110fd1efedcSConrad Meyer char *home = getenv("HOME"); 111fd1efedcSConrad Meyer unsigned int i; 112d20d6550SWarner Losh struct stat sb; 113d20d6550SWarner Losh static bool warned = false; 114fd1efedcSConrad Meyer 115fd1efedcSConrad Meyer if (home == NULL || *home == '\0') { 116fd1efedcSConrad Meyer warnx("Cannot get home directory"); 117fd1efedcSConrad Meyer return (NULL); 118fd1efedcSConrad Meyer } 119fd1efedcSConrad Meyer 120fd1efedcSConrad Meyer if (chdir(home) != 0) { 121fd1efedcSConrad Meyer warnx("Cannot enter home directory"); 122fd1efedcSConrad Meyer return (NULL); 123fd1efedcSConrad Meyer } 124fd1efedcSConrad Meyer 125fd1efedcSConrad Meyer for (i = 0; i < nitems(calendarHomes); i++) { 126fd1efedcSConrad Meyer if (chdir(calendarHomes[i]) != 0) 127fd1efedcSConrad Meyer continue; 128fd1efedcSConrad Meyer 129fd1efedcSConrad Meyer if ((fp = fopen(file, "r")) != NULL) 130fd1efedcSConrad Meyer return (fp); 131fd1efedcSConrad Meyer } 132fd1efedcSConrad Meyer 133fd1efedcSConrad Meyer warnx("can't open calendar file \"%s\"", file); 134d20d6550SWarner Losh if (!warned && stat(_PATH_INCLUDE_LOCAL, &sb) != 0) { 135d20d6550SWarner Losh warnx("calendar data files now provided by calendar-data pkg."); 136d20d6550SWarner Losh warned = true; 137d20d6550SWarner Losh } 138fd1efedcSConrad Meyer 139fd1efedcSConrad Meyer return (NULL); 140fd1efedcSConrad Meyer } 141fd1efedcSConrad Meyer 142fd1efedcSConrad Meyer static int 14319b5c307SStefan Eßer token(char *line, FILE *out, int *skip) 144fd1efedcSConrad Meyer { 145fd1efedcSConrad Meyer char *walk, c, a; 146fd1efedcSConrad Meyer 147fd1efedcSConrad Meyer if (strncmp(line, "endif", 5) == 0) { 14819b5c307SStefan Eßer if (*skip > 0) 14919b5c307SStefan Eßer --*skip; 150fd1efedcSConrad Meyer return (T_OK); 151fd1efedcSConrad Meyer } 152fd1efedcSConrad Meyer 15319b5c307SStefan Eßer if (strncmp(line, "ifdef", 5) == 0) { 15419b5c307SStefan Eßer walk = line + 5; 15519b5c307SStefan Eßer trimlr(&walk); 15619b5c307SStefan Eßer 15719b5c307SStefan Eßer if (*walk == '\0') { 15819b5c307SStefan Eßer warnx("Expecting arguments after #ifdef"); 15919b5c307SStefan Eßer return (T_ERR); 16019b5c307SStefan Eßer } 16119b5c307SStefan Eßer 16219b5c307SStefan Eßer if (*skip != 0 || definitions == NULL || sl_find(definitions, walk) == NULL) 16319b5c307SStefan Eßer ++*skip; 16419b5c307SStefan Eßer 16519b5c307SStefan Eßer return (T_OK); 16619b5c307SStefan Eßer } 16719b5c307SStefan Eßer 16819b5c307SStefan Eßer if (strncmp(line, "ifndef", 6) == 0) { 16919b5c307SStefan Eßer walk = line + 6; 17019b5c307SStefan Eßer trimlr(&walk); 17119b5c307SStefan Eßer 17219b5c307SStefan Eßer if (*walk == '\0') { 17319b5c307SStefan Eßer warnx("Expecting arguments after #ifndef"); 17419b5c307SStefan Eßer return (T_ERR); 17519b5c307SStefan Eßer } 17619b5c307SStefan Eßer 17719b5c307SStefan Eßer if (*skip != 0 || (definitions != NULL && sl_find(definitions, walk) != NULL)) 17819b5c307SStefan Eßer ++*skip; 17919b5c307SStefan Eßer 18019b5c307SStefan Eßer return (T_OK); 18119b5c307SStefan Eßer } 18219b5c307SStefan Eßer 18319b5c307SStefan Eßer if (strncmp(line, "else", 4) == 0) { 18419b5c307SStefan Eßer walk = line + 4; 18519b5c307SStefan Eßer trimlr(&walk); 18619b5c307SStefan Eßer 18719b5c307SStefan Eßer if (*walk != '\0') { 18819b5c307SStefan Eßer warnx("Expecting no arguments after #else"); 18919b5c307SStefan Eßer return (T_ERR); 19019b5c307SStefan Eßer } 19119b5c307SStefan Eßer 19219b5c307SStefan Eßer if (*skip == 0) 19319b5c307SStefan Eßer *skip = 1; 19419b5c307SStefan Eßer else if (*skip == 1) 19519b5c307SStefan Eßer *skip = 0; 19619b5c307SStefan Eßer 19719b5c307SStefan Eßer return (T_OK); 19819b5c307SStefan Eßer } 19919b5c307SStefan Eßer 20019b5c307SStefan Eßer if (*skip != 0) 201fd1efedcSConrad Meyer return (T_OK); 202fd1efedcSConrad Meyer 203fd1efedcSConrad Meyer if (strncmp(line, "include", 7) == 0) { 204fd1efedcSConrad Meyer walk = line + 7; 205fd1efedcSConrad Meyer 206fd1efedcSConrad Meyer trimlr(&walk); 207fd1efedcSConrad Meyer 208fd1efedcSConrad Meyer if (*walk == '\0') { 209fd1efedcSConrad Meyer warnx("Expecting arguments after #include"); 210fd1efedcSConrad Meyer return (T_ERR); 211fd1efedcSConrad Meyer } 212fd1efedcSConrad Meyer 213fd1efedcSConrad Meyer if (*walk != '<' && *walk != '\"') { 214fd1efedcSConrad Meyer warnx("Excecting '<' or '\"' after #include"); 215fd1efedcSConrad Meyer return (T_ERR); 216fd1efedcSConrad Meyer } 217fd1efedcSConrad Meyer 218ac04cf18SStefan Eßer a = *walk == '<' ? '>' : '\"'; 219fd1efedcSConrad Meyer walk++; 220fd1efedcSConrad Meyer c = walk[strlen(walk) - 1]; 221fd1efedcSConrad Meyer 222ac04cf18SStefan Eßer if (a != c) { 223ac04cf18SStefan Eßer warnx("Unterminated include expecting '%c'", a); 224fd1efedcSConrad Meyer return (T_ERR); 225fd1efedcSConrad Meyer } 226fd1efedcSConrad Meyer walk[strlen(walk) - 1] = '\0'; 227fd1efedcSConrad Meyer 228fd1efedcSConrad Meyer if (cal_parse(cal_fopen(walk), out)) 229fd1efedcSConrad Meyer return (T_ERR); 230fd1efedcSConrad Meyer 231fd1efedcSConrad Meyer return (T_OK); 232fd1efedcSConrad Meyer } 233fd1efedcSConrad Meyer 234fd1efedcSConrad Meyer if (strncmp(line, "define", 6) == 0) { 235fd1efedcSConrad Meyer if (definitions == NULL) 236fd1efedcSConrad Meyer definitions = sl_init(); 237fd1efedcSConrad Meyer walk = line + 6; 238fd1efedcSConrad Meyer trimlr(&walk); 239fd1efedcSConrad Meyer 240fd1efedcSConrad Meyer if (*walk == '\0') { 241fd1efedcSConrad Meyer warnx("Expecting arguments after #define"); 242fd1efedcSConrad Meyer return (T_ERR); 243fd1efedcSConrad Meyer } 244fd1efedcSConrad Meyer 245fd1efedcSConrad Meyer sl_add(definitions, strdup(walk)); 246fd1efedcSConrad Meyer return (T_OK); 247fd1efedcSConrad Meyer } 248fd1efedcSConrad Meyer 249fd1efedcSConrad Meyer return (T_PROCESS); 250fd1efedcSConrad Meyer 251fd1efedcSConrad Meyer } 252fd1efedcSConrad Meyer 253fd1efedcSConrad Meyer #define REPLACE(string, slen, struct_) \ 254fd1efedcSConrad Meyer if (strncasecmp(buf, (string), (slen)) == 0 && buf[(slen)]) { \ 255fd1efedcSConrad Meyer if (struct_.name != NULL) \ 256fd1efedcSConrad Meyer free(struct_.name); \ 257fd1efedcSConrad Meyer if ((struct_.name = strdup(buf + (slen))) == NULL) \ 258fd1efedcSConrad Meyer errx(1, "cannot allocate memory"); \ 259fd1efedcSConrad Meyer struct_.len = strlen(buf + (slen)); \ 260fd1efedcSConrad Meyer continue; \ 261fd1efedcSConrad Meyer } 262fd1efedcSConrad Meyer static int 263fd1efedcSConrad Meyer cal_parse(FILE *in, FILE *out) 264fd1efedcSConrad Meyer { 265fd1efedcSConrad Meyer char *line = NULL; 266fd1efedcSConrad Meyer char *buf; 267fd1efedcSConrad Meyer size_t linecap = 0; 268fd1efedcSConrad Meyer ssize_t linelen; 269fd1efedcSConrad Meyer ssize_t l; 270fd1efedcSConrad Meyer static int d_first = -1; 271fd1efedcSConrad Meyer static int count = 0; 272fd1efedcSConrad Meyer int i; 273fd1efedcSConrad Meyer int month[MAXCOUNT]; 274fd1efedcSConrad Meyer int day[MAXCOUNT]; 275fd1efedcSConrad Meyer int year[MAXCOUNT]; 27619b5c307SStefan Eßer int skip = 0; 277fd1efedcSConrad Meyer char dbuf[80]; 278fd1efedcSConrad Meyer char *pp, p; 279fd1efedcSConrad Meyer struct tm tm; 280fd1efedcSConrad Meyer int flags; 281fd1efedcSConrad Meyer 282fd1efedcSConrad Meyer /* Unused */ 283fd1efedcSConrad Meyer tm.tm_sec = 0; 284fd1efedcSConrad Meyer tm.tm_min = 0; 285fd1efedcSConrad Meyer tm.tm_hour = 0; 286fd1efedcSConrad Meyer tm.tm_wday = 0; 287fd1efedcSConrad Meyer 288fd1efedcSConrad Meyer if (in == NULL) 289fd1efedcSConrad Meyer return (1); 290fd1efedcSConrad Meyer 291fd1efedcSConrad Meyer while ((linelen = getline(&line, &linecap, in)) > 0) { 292fd1efedcSConrad Meyer if (*line == '#') { 293fd1efedcSConrad Meyer switch (token(line+1, out, &skip)) { 294fd1efedcSConrad Meyer case T_ERR: 295fd1efedcSConrad Meyer free(line); 296fd1efedcSConrad Meyer return (1); 297fd1efedcSConrad Meyer case T_OK: 298fd1efedcSConrad Meyer continue; 299fd1efedcSConrad Meyer case T_PROCESS: 300fd1efedcSConrad Meyer break; 301fd1efedcSConrad Meyer default: 302fd1efedcSConrad Meyer break; 303fd1efedcSConrad Meyer } 304fd1efedcSConrad Meyer } 305fd1efedcSConrad Meyer 30619b5c307SStefan Eßer if (skip != 0) 307fd1efedcSConrad Meyer continue; 308fd1efedcSConrad Meyer 309fd1efedcSConrad Meyer buf = line; 310fd1efedcSConrad Meyer for (l = linelen; 311fd1efedcSConrad Meyer l > 0 && isspace((unsigned char)buf[l - 1]); 312fd1efedcSConrad Meyer l--) 313fd1efedcSConrad Meyer ; 314fd1efedcSConrad Meyer buf[l] = '\0'; 315fd1efedcSConrad Meyer if (buf[0] == '\0') 316fd1efedcSConrad Meyer continue; 317fd1efedcSConrad Meyer 318fd1efedcSConrad Meyer /* 319fd1efedcSConrad Meyer * Setting LANG in user's calendar was an old workaround 320fd1efedcSConrad Meyer * for 'calendar -a' being run with C locale to properly 321fd1efedcSConrad Meyer * print user's calendars in their native languages. 322fd1efedcSConrad Meyer * Now that 'calendar -a' does fork with setusercontext(), 323fd1efedcSConrad Meyer * and does not run iconv(), this variable has little use. 324fd1efedcSConrad Meyer */ 325fd1efedcSConrad Meyer if (strncmp(buf, "LANG=", 5) == 0) { 326fd1efedcSConrad Meyer (void)setlocale(LC_ALL, buf + 5); 327fd1efedcSConrad Meyer d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 328fd1efedcSConrad Meyer #ifdef WITH_ICONV 329fd1efedcSConrad Meyer if (!doall) 330fd1efedcSConrad Meyer set_new_encoding(); 331fd1efedcSConrad Meyer #endif 332fd1efedcSConrad Meyer setnnames(); 333fd1efedcSConrad Meyer continue; 334fd1efedcSConrad Meyer } 335fd1efedcSConrad Meyer /* Parse special definitions: Easter, Paskha etc */ 336fd1efedcSConrad Meyer REPLACE("Easter=", 7, neaster); 337fd1efedcSConrad Meyer REPLACE("Paskha=", 7, npaskha); 338fd1efedcSConrad Meyer REPLACE("ChineseNewYear=", 15, ncny); 339fd1efedcSConrad Meyer REPLACE("NewMoon=", 8, nnewmoon); 340fd1efedcSConrad Meyer REPLACE("FullMoon=", 9, nfullmoon); 341fd1efedcSConrad Meyer REPLACE("MarEquinox=", 11, nmarequinox); 342fd1efedcSConrad Meyer REPLACE("SepEquinox=", 11, nsepequinox); 343fd1efedcSConrad Meyer REPLACE("JunSolstice=", 12, njunsolstice); 344fd1efedcSConrad Meyer REPLACE("DecSolstice=", 12, ndecsolstice); 345fd1efedcSConrad Meyer if (strncmp(buf, "SEQUENCE=", 9) == 0) { 346fd1efedcSConrad Meyer setnsequences(buf + 9); 347fd1efedcSConrad Meyer continue; 348fd1efedcSConrad Meyer } 349fd1efedcSConrad Meyer 350fd1efedcSConrad Meyer /* 351fd1efedcSConrad Meyer * If the line starts with a tab, the data has to be 352fd1efedcSConrad Meyer * added to the previous line 353fd1efedcSConrad Meyer */ 354fd1efedcSConrad Meyer if (buf[0] == '\t') { 355fd1efedcSConrad Meyer for (i = 0; i < count; i++) 356fd1efedcSConrad Meyer event_continue(events[i], buf); 357fd1efedcSConrad Meyer continue; 358fd1efedcSConrad Meyer } 359fd1efedcSConrad Meyer 360fd1efedcSConrad Meyer /* Get rid of leading spaces (non-standard) */ 361fd1efedcSConrad Meyer while (isspace((unsigned char)buf[0])) 362fd1efedcSConrad Meyer memcpy(buf, buf + 1, strlen(buf)); 363fd1efedcSConrad Meyer 364fd1efedcSConrad Meyer /* No tab in the line, then not a valid line */ 365fd1efedcSConrad Meyer if ((pp = strchr(buf, '\t')) == NULL) 366fd1efedcSConrad Meyer continue; 367fd1efedcSConrad Meyer 368fd1efedcSConrad Meyer /* Trim spaces in front of the tab */ 369fd1efedcSConrad Meyer while (isspace((unsigned char)pp[-1])) 370fd1efedcSConrad Meyer pp--; 371fd1efedcSConrad Meyer 372fd1efedcSConrad Meyer p = *pp; 373fd1efedcSConrad Meyer *pp = '\0'; 374fd1efedcSConrad Meyer if ((count = parsedaymonth(buf, year, month, day, &flags, 375fd1efedcSConrad Meyer extradata)) == 0) 376fd1efedcSConrad Meyer continue; 377fd1efedcSConrad Meyer *pp = p; 378fd1efedcSConrad Meyer if (count < 0) { 379fd1efedcSConrad Meyer /* Show error status based on return value */ 380fd1efedcSConrad Meyer if (debug) 381fd1efedcSConrad Meyer fprintf(stderr, "Ignored: %s\n", buf); 382fd1efedcSConrad Meyer if (count == -1) 383fd1efedcSConrad Meyer continue; 384fd1efedcSConrad Meyer count = -count + 1; 385fd1efedcSConrad Meyer } 386fd1efedcSConrad Meyer 387fd1efedcSConrad Meyer /* Find the last tab */ 388fd1efedcSConrad Meyer while (pp[1] == '\t') 389fd1efedcSConrad Meyer pp++; 390fd1efedcSConrad Meyer 391fd1efedcSConrad Meyer if (d_first < 0) 392fd1efedcSConrad Meyer d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 393fd1efedcSConrad Meyer 394fd1efedcSConrad Meyer for (i = 0; i < count; i++) { 395fd1efedcSConrad Meyer tm.tm_mon = month[i] - 1; 396fd1efedcSConrad Meyer tm.tm_mday = day[i]; 397fd1efedcSConrad Meyer tm.tm_year = year[i] - 1900; 398fd1efedcSConrad Meyer (void)strftime(dbuf, sizeof(dbuf), 399fd1efedcSConrad Meyer d_first ? "%e %b" : "%b %e", &tm); 400fd1efedcSConrad Meyer if (debug) 401fd1efedcSConrad Meyer fprintf(stderr, "got %s\n", pp); 402fd1efedcSConrad Meyer events[i] = event_add(year[i], month[i], day[i], dbuf, 403fd1efedcSConrad Meyer ((flags &= F_VARIABLE) != 0) ? 1 : 0, pp, 404fd1efedcSConrad Meyer extradata[i]); 405fd1efedcSConrad Meyer } 406fd1efedcSConrad Meyer } 407fd1efedcSConrad Meyer 408fd1efedcSConrad Meyer free(line); 409fd1efedcSConrad Meyer fclose(in); 410fd1efedcSConrad Meyer 411fd1efedcSConrad Meyer return (0); 412fd1efedcSConrad Meyer } 413fd1efedcSConrad Meyer 414fd1efedcSConrad Meyer void 415fd1efedcSConrad Meyer cal(void) 416fd1efedcSConrad Meyer { 417fd1efedcSConrad Meyer FILE *fpin; 418fd1efedcSConrad Meyer FILE *fpout; 419fd1efedcSConrad Meyer int i; 420fd1efedcSConrad Meyer 421fd1efedcSConrad Meyer for (i = 0; i < MAXCOUNT; i++) 422fd1efedcSConrad Meyer extradata[i] = (char *)calloc(1, 20); 423fd1efedcSConrad Meyer 424fd1efedcSConrad Meyer 425fd1efedcSConrad Meyer if ((fpin = opencalin()) == NULL) 426fd1efedcSConrad Meyer return; 427fd1efedcSConrad Meyer 428fd1efedcSConrad Meyer if ((fpout = opencalout()) == NULL) { 429fd1efedcSConrad Meyer fclose(fpin); 430fd1efedcSConrad Meyer return; 431fd1efedcSConrad Meyer } 432fd1efedcSConrad Meyer 433fd1efedcSConrad Meyer if (cal_parse(fpin, fpout)) 434fd1efedcSConrad Meyer return; 435fd1efedcSConrad Meyer 436fd1efedcSConrad Meyer event_print_all(fpout); 437fd1efedcSConrad Meyer closecal(fpout); 438fd1efedcSConrad Meyer } 439fd1efedcSConrad Meyer 440fd1efedcSConrad Meyer FILE * 441fd1efedcSConrad Meyer opencalin(void) 442fd1efedcSConrad Meyer { 443fd1efedcSConrad Meyer struct stat sbuf; 444fd1efedcSConrad Meyer FILE *fpin; 445fd1efedcSConrad Meyer 446fd1efedcSConrad Meyer /* open up calendar file */ 447fd1efedcSConrad Meyer if ((fpin = fopen(calendarFile, "r")) == NULL) { 448fd1efedcSConrad Meyer if (doall) { 449fd1efedcSConrad Meyer if (chdir(calendarHomes[0]) != 0) 450fd1efedcSConrad Meyer return (NULL); 451fd1efedcSConrad Meyer if (stat(calendarNoMail, &sbuf) == 0) 452fd1efedcSConrad Meyer return (NULL); 453fd1efedcSConrad Meyer if ((fpin = fopen(calendarFile, "r")) == NULL) 454fd1efedcSConrad Meyer return (NULL); 455fd1efedcSConrad Meyer } else { 456fd1efedcSConrad Meyer fpin = cal_fopen(calendarFile); 457fd1efedcSConrad Meyer } 458fd1efedcSConrad Meyer } 459fd1efedcSConrad Meyer return (fpin); 460fd1efedcSConrad Meyer } 461fd1efedcSConrad Meyer 462fd1efedcSConrad Meyer FILE * 463fd1efedcSConrad Meyer opencalout(void) 464fd1efedcSConrad Meyer { 465fd1efedcSConrad Meyer int fd; 466fd1efedcSConrad Meyer 467fd1efedcSConrad Meyer /* not reading all calendar files, just set output to stdout */ 468fd1efedcSConrad Meyer if (!doall) 469fd1efedcSConrad Meyer return (stdout); 470fd1efedcSConrad Meyer 471fd1efedcSConrad Meyer /* set output to a temporary file, so if no output don't send mail */ 472fd1efedcSConrad Meyer snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP); 473fd1efedcSConrad Meyer if ((fd = mkstemp(path)) < 0) 474fd1efedcSConrad Meyer return (NULL); 475fd1efedcSConrad Meyer return (fdopen(fd, "w+")); 476fd1efedcSConrad Meyer } 477fd1efedcSConrad Meyer 478fd1efedcSConrad Meyer void 479fd1efedcSConrad Meyer closecal(FILE *fp) 480fd1efedcSConrad Meyer { 481fd1efedcSConrad Meyer struct stat sbuf; 482fd1efedcSConrad Meyer int nread, pdes[2], status; 483fd1efedcSConrad Meyer char buf[1024]; 484fd1efedcSConrad Meyer 485fd1efedcSConrad Meyer if (!doall) 486fd1efedcSConrad Meyer return; 487fd1efedcSConrad Meyer 488fd1efedcSConrad Meyer rewind(fp); 489fd1efedcSConrad Meyer if (fstat(fileno(fp), &sbuf) || !sbuf.st_size) 490fd1efedcSConrad Meyer goto done; 491fd1efedcSConrad Meyer if (pipe(pdes) < 0) 492fd1efedcSConrad Meyer goto done; 493fd1efedcSConrad Meyer switch (fork()) { 494fd1efedcSConrad Meyer case -1: /* error */ 495fd1efedcSConrad Meyer (void)close(pdes[0]); 496fd1efedcSConrad Meyer (void)close(pdes[1]); 497fd1efedcSConrad Meyer goto done; 498fd1efedcSConrad Meyer case 0: 499fd1efedcSConrad Meyer /* child -- set stdin to pipe output */ 500fd1efedcSConrad Meyer if (pdes[0] != STDIN_FILENO) { 501fd1efedcSConrad Meyer (void)dup2(pdes[0], STDIN_FILENO); 502fd1efedcSConrad Meyer (void)close(pdes[0]); 503fd1efedcSConrad Meyer } 504fd1efedcSConrad Meyer (void)close(pdes[1]); 505fd1efedcSConrad Meyer execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F", 506fd1efedcSConrad Meyer "\"Reminder Service\"", (char *)NULL); 507fd1efedcSConrad Meyer warn(_PATH_SENDMAIL); 508fd1efedcSConrad Meyer _exit(1); 509fd1efedcSConrad Meyer } 510fd1efedcSConrad Meyer /* parent -- write to pipe input */ 511fd1efedcSConrad Meyer (void)close(pdes[0]); 512fd1efedcSConrad Meyer 513fd1efedcSConrad Meyer write(pdes[1], "From: \"Reminder Service\" <", 26); 514fd1efedcSConrad Meyer write(pdes[1], pw->pw_name, strlen(pw->pw_name)); 515fd1efedcSConrad Meyer write(pdes[1], ">\nTo: <", 7); 516fd1efedcSConrad Meyer write(pdes[1], pw->pw_name, strlen(pw->pw_name)); 517fd1efedcSConrad Meyer write(pdes[1], ">\nSubject: ", 11); 518fd1efedcSConrad Meyer write(pdes[1], dayname, strlen(dayname)); 519fd1efedcSConrad Meyer write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30); 520fd1efedcSConrad Meyer 521fd1efedcSConrad Meyer while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) 522fd1efedcSConrad Meyer (void)write(pdes[1], buf, nread); 523fd1efedcSConrad Meyer (void)close(pdes[1]); 524fd1efedcSConrad Meyer done: (void)fclose(fp); 525fd1efedcSConrad Meyer (void)unlink(path); 526fd1efedcSConrad Meyer while (wait(&status) >= 0); 527fd1efedcSConrad Meyer } 528