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]; 781462201cSStefan Eßer static const char *cal_home; 791462201cSStefan Eßer static const char *cal_dir; 801462201cSStefan Eßer static const char *cal_file; 811462201cSStefan Eßer static int cal_line; 82fd1efedcSConrad Meyer 83fd1efedcSConrad Meyer struct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon; 84fd1efedcSConrad Meyer struct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice; 85fd1efedcSConrad Meyer 86fd1efedcSConrad Meyer static int cal_parse(FILE *in, FILE *out); 87fd1efedcSConrad Meyer 88fd1efedcSConrad Meyer static StringList *definitions = NULL; 89fd1efedcSConrad Meyer static struct event *events[MAXCOUNT]; 90fd1efedcSConrad Meyer static char *extradata[MAXCOUNT]; 91fd1efedcSConrad Meyer 92fd1efedcSConrad Meyer static void 93fd1efedcSConrad Meyer trimlr(char **buf) 94fd1efedcSConrad Meyer { 95fd1efedcSConrad Meyer char *walk = *buf; 96fd1efedcSConrad Meyer char *last; 97fd1efedcSConrad Meyer 98fd1efedcSConrad Meyer while (isspace(*walk)) 99fd1efedcSConrad Meyer walk++; 100fd1efedcSConrad Meyer if (*walk != '\0') { 101fd1efedcSConrad Meyer last = walk + strlen(walk) - 1; 102fd1efedcSConrad Meyer while (last > walk && isspace(*last)) 103fd1efedcSConrad Meyer last--; 104fd1efedcSConrad Meyer *(last+1) = 0; 105fd1efedcSConrad Meyer } 106fd1efedcSConrad Meyer 107fd1efedcSConrad Meyer *buf = walk; 108fd1efedcSConrad Meyer } 109fd1efedcSConrad Meyer 110fd1efedcSConrad Meyer static FILE * 111fd1efedcSConrad Meyer cal_fopen(const char *file) 112fd1efedcSConrad Meyer { 113fd1efedcSConrad Meyer FILE *fp; 114fd1efedcSConrad Meyer char *home = getenv("HOME"); 115fd1efedcSConrad Meyer unsigned int i; 116d20d6550SWarner Losh struct stat sb; 117d20d6550SWarner Losh static bool warned = false; 118fd1efedcSConrad Meyer 119fd1efedcSConrad Meyer if (home == NULL || *home == '\0') { 120fd1efedcSConrad Meyer warnx("Cannot get home directory"); 121fd1efedcSConrad Meyer return (NULL); 122fd1efedcSConrad Meyer } 123fd1efedcSConrad Meyer 124fd1efedcSConrad Meyer if (chdir(home) != 0) { 1251462201cSStefan Eßer warnx("Cannot enter home directory \"%s\"", home); 126fd1efedcSConrad Meyer return (NULL); 127fd1efedcSConrad Meyer } 128fd1efedcSConrad Meyer 129fd1efedcSConrad Meyer for (i = 0; i < nitems(calendarHomes); i++) { 130fd1efedcSConrad Meyer if (chdir(calendarHomes[i]) != 0) 131fd1efedcSConrad Meyer continue; 132fd1efedcSConrad Meyer 1331462201cSStefan Eßer if ((fp = fopen(file, "r")) != NULL) { 1341462201cSStefan Eßer cal_home = home; 1351462201cSStefan Eßer cal_dir = calendarHomes[i]; 1361462201cSStefan Eßer cal_file = file; 137fd1efedcSConrad Meyer return (fp); 138fd1efedcSConrad Meyer } 1391462201cSStefan Eßer } 140fd1efedcSConrad Meyer 141fd1efedcSConrad Meyer warnx("can't open calendar file \"%s\"", file); 142d20d6550SWarner Losh if (!warned && stat(_PATH_INCLUDE_LOCAL, &sb) != 0) { 143d20d6550SWarner Losh warnx("calendar data files now provided by calendar-data pkg."); 144d20d6550SWarner Losh warned = true; 145d20d6550SWarner Losh } 146fd1efedcSConrad Meyer 147fd1efedcSConrad Meyer return (NULL); 148fd1efedcSConrad Meyer } 149fd1efedcSConrad Meyer 1501462201cSStefan Eßer #define WARN0(format) \ 1511462201cSStefan Eßer warnx(format " in %s/%s/%s line %d", cal_home, cal_dir, cal_file, cal_line) 1521462201cSStefan Eßer #define WARN1(format, arg1) \ 1531462201cSStefan Eßer warnx(format " in %s/%s/%s line %d", arg1, cal_home, cal_dir, cal_file, cal_line) 1541462201cSStefan Eßer 155fd1efedcSConrad Meyer static int 15619b5c307SStefan Eßer token(char *line, FILE *out, int *skip) 157fd1efedcSConrad Meyer { 158fd1efedcSConrad Meyer char *walk, c, a; 1591462201cSStefan Eßer const char *this_cal_home; 1601462201cSStefan Eßer const char *this_cal_dir; 1611462201cSStefan Eßer const char *this_cal_file; 1621462201cSStefan Eßer int this_cal_line; 163fd1efedcSConrad Meyer 164fd1efedcSConrad Meyer if (strncmp(line, "endif", 5) == 0) { 16519b5c307SStefan Eßer if (*skip > 0) 16619b5c307SStefan Eßer --*skip; 167fd1efedcSConrad Meyer return (T_OK); 168fd1efedcSConrad Meyer } 169fd1efedcSConrad Meyer 17019b5c307SStefan Eßer if (strncmp(line, "ifdef", 5) == 0) { 17119b5c307SStefan Eßer walk = line + 5; 17219b5c307SStefan Eßer trimlr(&walk); 17319b5c307SStefan Eßer 17419b5c307SStefan Eßer if (*walk == '\0') { 1751462201cSStefan Eßer WARN0("Expecting arguments after #ifdef"); 17619b5c307SStefan Eßer return (T_ERR); 17719b5c307SStefan Eßer } 17819b5c307SStefan Eßer 17919b5c307SStefan Eßer if (*skip != 0 || definitions == NULL || sl_find(definitions, walk) == NULL) 18019b5c307SStefan Eßer ++*skip; 18119b5c307SStefan Eßer 18219b5c307SStefan Eßer return (T_OK); 18319b5c307SStefan Eßer } 18419b5c307SStefan Eßer 18519b5c307SStefan Eßer if (strncmp(line, "ifndef", 6) == 0) { 18619b5c307SStefan Eßer walk = line + 6; 18719b5c307SStefan Eßer trimlr(&walk); 18819b5c307SStefan Eßer 18919b5c307SStefan Eßer if (*walk == '\0') { 1901462201cSStefan Eßer WARN0("Expecting arguments after #ifndef"); 19119b5c307SStefan Eßer return (T_ERR); 19219b5c307SStefan Eßer } 19319b5c307SStefan Eßer 19419b5c307SStefan Eßer if (*skip != 0 || (definitions != NULL && sl_find(definitions, walk) != NULL)) 19519b5c307SStefan Eßer ++*skip; 19619b5c307SStefan Eßer 19719b5c307SStefan Eßer return (T_OK); 19819b5c307SStefan Eßer } 19919b5c307SStefan Eßer 20019b5c307SStefan Eßer if (strncmp(line, "else", 4) == 0) { 20119b5c307SStefan Eßer walk = line + 4; 20219b5c307SStefan Eßer trimlr(&walk); 20319b5c307SStefan Eßer 20419b5c307SStefan Eßer if (*walk != '\0') { 2051462201cSStefan Eßer WARN0("Expecting no arguments after #else"); 20619b5c307SStefan Eßer return (T_ERR); 20719b5c307SStefan Eßer } 20819b5c307SStefan Eßer 20919b5c307SStefan Eßer if (*skip == 0) 21019b5c307SStefan Eßer *skip = 1; 21119b5c307SStefan Eßer else if (*skip == 1) 21219b5c307SStefan Eßer *skip = 0; 21319b5c307SStefan Eßer 21419b5c307SStefan Eßer return (T_OK); 21519b5c307SStefan Eßer } 21619b5c307SStefan Eßer 21719b5c307SStefan Eßer if (*skip != 0) 218fd1efedcSConrad Meyer return (T_OK); 219fd1efedcSConrad Meyer 220fd1efedcSConrad Meyer if (strncmp(line, "include", 7) == 0) { 221fd1efedcSConrad Meyer walk = line + 7; 222fd1efedcSConrad Meyer 223fd1efedcSConrad Meyer trimlr(&walk); 224fd1efedcSConrad Meyer 225fd1efedcSConrad Meyer if (*walk == '\0') { 2261462201cSStefan Eßer WARN0("Expecting arguments after #include"); 227fd1efedcSConrad Meyer return (T_ERR); 228fd1efedcSConrad Meyer } 229fd1efedcSConrad Meyer 230fd1efedcSConrad Meyer if (*walk != '<' && *walk != '\"') { 2311462201cSStefan Eßer WARN0("Excecting '<' or '\"' after #include"); 232fd1efedcSConrad Meyer return (T_ERR); 233fd1efedcSConrad Meyer } 234fd1efedcSConrad Meyer 235ac04cf18SStefan Eßer a = *walk == '<' ? '>' : '\"'; 236fd1efedcSConrad Meyer walk++; 237fd1efedcSConrad Meyer c = walk[strlen(walk) - 1]; 238fd1efedcSConrad Meyer 239ac04cf18SStefan Eßer if (a != c) { 2401462201cSStefan Eßer WARN1("Unterminated include expecting '%c'", a); 241fd1efedcSConrad Meyer return (T_ERR); 242fd1efedcSConrad Meyer } 243fd1efedcSConrad Meyer walk[strlen(walk) - 1] = '\0'; 244fd1efedcSConrad Meyer 2451462201cSStefan Eßer this_cal_home = cal_home; 2461462201cSStefan Eßer this_cal_dir = cal_dir; 2471462201cSStefan Eßer this_cal_file = cal_file; 2481462201cSStefan Eßer this_cal_line = cal_line; 249fd1efedcSConrad Meyer if (cal_parse(cal_fopen(walk), out)) 250fd1efedcSConrad Meyer return (T_ERR); 2511462201cSStefan Eßer cal_home = this_cal_home; 2521462201cSStefan Eßer cal_dir = this_cal_dir; 2531462201cSStefan Eßer cal_file = this_cal_file; 2541462201cSStefan Eßer cal_line = this_cal_line; 255fd1efedcSConrad Meyer 256fd1efedcSConrad Meyer return (T_OK); 257fd1efedcSConrad Meyer } 258fd1efedcSConrad Meyer 259fd1efedcSConrad Meyer if (strncmp(line, "define", 6) == 0) { 260fd1efedcSConrad Meyer if (definitions == NULL) 261fd1efedcSConrad Meyer definitions = sl_init(); 262fd1efedcSConrad Meyer walk = line + 6; 263fd1efedcSConrad Meyer trimlr(&walk); 264fd1efedcSConrad Meyer 265fd1efedcSConrad Meyer if (*walk == '\0') { 2661462201cSStefan Eßer WARN0("Expecting arguments after #define"); 267fd1efedcSConrad Meyer return (T_ERR); 268fd1efedcSConrad Meyer } 269fd1efedcSConrad Meyer 270fd1efedcSConrad Meyer sl_add(definitions, strdup(walk)); 271fd1efedcSConrad Meyer return (T_OK); 272fd1efedcSConrad Meyer } 273fd1efedcSConrad Meyer 274fd1efedcSConrad Meyer return (T_PROCESS); 275fd1efedcSConrad Meyer 276fd1efedcSConrad Meyer } 277fd1efedcSConrad Meyer 278fd1efedcSConrad Meyer #define REPLACE(string, slen, struct_) \ 279fd1efedcSConrad Meyer if (strncasecmp(buf, (string), (slen)) == 0 && buf[(slen)]) { \ 280fd1efedcSConrad Meyer if (struct_.name != NULL) \ 281fd1efedcSConrad Meyer free(struct_.name); \ 282fd1efedcSConrad Meyer if ((struct_.name = strdup(buf + (slen))) == NULL) \ 283fd1efedcSConrad Meyer errx(1, "cannot allocate memory"); \ 284fd1efedcSConrad Meyer struct_.len = strlen(buf + (slen)); \ 285fd1efedcSConrad Meyer continue; \ 286fd1efedcSConrad Meyer } 287fd1efedcSConrad Meyer static int 288fd1efedcSConrad Meyer cal_parse(FILE *in, FILE *out) 289fd1efedcSConrad Meyer { 290fd1efedcSConrad Meyer char *line = NULL; 291fd1efedcSConrad Meyer char *buf; 292fd1efedcSConrad Meyer size_t linecap = 0; 293fd1efedcSConrad Meyer ssize_t linelen; 294fd1efedcSConrad Meyer ssize_t l; 295fd1efedcSConrad Meyer static int d_first = -1; 296fd1efedcSConrad Meyer static int count = 0; 297fd1efedcSConrad Meyer int i; 298fd1efedcSConrad Meyer int month[MAXCOUNT]; 299fd1efedcSConrad Meyer int day[MAXCOUNT]; 300fd1efedcSConrad Meyer int year[MAXCOUNT]; 30119b5c307SStefan Eßer int skip = 0; 302fd1efedcSConrad Meyer char dbuf[80]; 303fd1efedcSConrad Meyer char *pp, p; 304fd1efedcSConrad Meyer struct tm tm; 305fd1efedcSConrad Meyer int flags; 3060f352f4eSStefan Eßer char *c, *cc; 3070f352f4eSStefan Eßer bool incomment = false; 308fd1efedcSConrad Meyer 309fd1efedcSConrad Meyer /* Unused */ 310fd1efedcSConrad Meyer tm.tm_sec = 0; 311fd1efedcSConrad Meyer tm.tm_min = 0; 312fd1efedcSConrad Meyer tm.tm_hour = 0; 313fd1efedcSConrad Meyer tm.tm_wday = 0; 314fd1efedcSConrad Meyer 315fd1efedcSConrad Meyer if (in == NULL) 316fd1efedcSConrad Meyer return (1); 317fd1efedcSConrad Meyer 3181462201cSStefan Eßer cal_line = 0; 319fd1efedcSConrad Meyer while ((linelen = getline(&line, &linecap, in)) > 0) { 3201462201cSStefan Eßer cal_line++; 3210f352f4eSStefan Eßer buf = line; 3220f352f4eSStefan Eßer if (buf[linelen - 1] == '\n') 3230f352f4eSStefan Eßer buf[--linelen] = '\0'; 3240f352f4eSStefan Eßer 3250f352f4eSStefan Eßer if (incomment) { 3260f352f4eSStefan Eßer c = strstr(buf, "*/"); 3270f352f4eSStefan Eßer if (c) { 3280f352f4eSStefan Eßer c += 2; 3290f352f4eSStefan Eßer linelen -= c - buf; 3300f352f4eSStefan Eßer buf = c; 3310f352f4eSStefan Eßer incomment = false; 3320f352f4eSStefan Eßer } else { 3330f352f4eSStefan Eßer continue; 3340f352f4eSStefan Eßer } 3350f352f4eSStefan Eßer } 3360f352f4eSStefan Eßer if (!incomment) { 3370f352f4eSStefan Eßer do { 3380f352f4eSStefan Eßer c = strstr(buf, "//"); 3390f352f4eSStefan Eßer cc = strstr(buf, "/*"); 3400f352f4eSStefan Eßer if (c != NULL && (cc == NULL || c - cc < 0)) { 3416bdb89a8SStefan Eßer /* single line comment */ 3420f352f4eSStefan Eßer *c = '\0'; 3430f352f4eSStefan Eßer linelen = c - buf; 3440f352f4eSStefan Eßer break; 3450f352f4eSStefan Eßer } else if (cc != NULL) { 3460f352f4eSStefan Eßer c = strstr(cc + 2, "*/"); 3470f352f4eSStefan Eßer if (c != NULL) { 3486bdb89a8SStefan Eßer /* multi-line comment ending on same line */ 3490f352f4eSStefan Eßer c += 2; 3506bdb89a8SStefan Eßer memmove(cc, c, buf + linelen + 1 - c); 3510f352f4eSStefan Eßer linelen -= c - cc; 3520f352f4eSStefan Eßer } else { 3536bdb89a8SStefan Eßer /* multi-line comment */ 3540f352f4eSStefan Eßer *cc = '\0'; 3550f352f4eSStefan Eßer linelen = cc - buf; 3560f352f4eSStefan Eßer incomment = true; 3570f352f4eSStefan Eßer break; 3580f352f4eSStefan Eßer } 3590f352f4eSStefan Eßer } 3600f352f4eSStefan Eßer } while (c != NULL || cc != NULL); 3610f352f4eSStefan Eßer } 3620f352f4eSStefan Eßer 3630f352f4eSStefan Eßer for (l = linelen; 3640f352f4eSStefan Eßer l > 0 && isspace((unsigned char)buf[l - 1]); 3650f352f4eSStefan Eßer l--) 3660f352f4eSStefan Eßer ; 3670f352f4eSStefan Eßer buf[l] = '\0'; 3680f352f4eSStefan Eßer if (buf[0] == '\0') 3690f352f4eSStefan Eßer continue; 3700f352f4eSStefan Eßer 3710f352f4eSStefan Eßer if (buf == line && *buf == '#') { 3720f352f4eSStefan Eßer switch (token(buf+1, out, &skip)) { 373fd1efedcSConrad Meyer case T_ERR: 374fd1efedcSConrad Meyer free(line); 375fd1efedcSConrad Meyer return (1); 376fd1efedcSConrad Meyer case T_OK: 377fd1efedcSConrad Meyer continue; 378fd1efedcSConrad Meyer case T_PROCESS: 379fd1efedcSConrad Meyer break; 380fd1efedcSConrad Meyer default: 381fd1efedcSConrad Meyer break; 382fd1efedcSConrad Meyer } 383fd1efedcSConrad Meyer } 384fd1efedcSConrad Meyer 38519b5c307SStefan Eßer if (skip != 0) 386fd1efedcSConrad Meyer continue; 387fd1efedcSConrad Meyer 388fd1efedcSConrad Meyer /* 389fd1efedcSConrad Meyer * Setting LANG in user's calendar was an old workaround 390fd1efedcSConrad Meyer * for 'calendar -a' being run with C locale to properly 391fd1efedcSConrad Meyer * print user's calendars in their native languages. 392fd1efedcSConrad Meyer * Now that 'calendar -a' does fork with setusercontext(), 393fd1efedcSConrad Meyer * and does not run iconv(), this variable has little use. 394fd1efedcSConrad Meyer */ 395fd1efedcSConrad Meyer if (strncmp(buf, "LANG=", 5) == 0) { 396fd1efedcSConrad Meyer (void)setlocale(LC_ALL, buf + 5); 397fd1efedcSConrad Meyer d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 398fd1efedcSConrad Meyer #ifdef WITH_ICONV 399fd1efedcSConrad Meyer if (!doall) 400fd1efedcSConrad Meyer set_new_encoding(); 401fd1efedcSConrad Meyer #endif 402fd1efedcSConrad Meyer setnnames(); 403fd1efedcSConrad Meyer continue; 404fd1efedcSConrad Meyer } 405fd1efedcSConrad Meyer /* Parse special definitions: Easter, Paskha etc */ 406fd1efedcSConrad Meyer REPLACE("Easter=", 7, neaster); 407fd1efedcSConrad Meyer REPLACE("Paskha=", 7, npaskha); 408fd1efedcSConrad Meyer REPLACE("ChineseNewYear=", 15, ncny); 409fd1efedcSConrad Meyer REPLACE("NewMoon=", 8, nnewmoon); 410fd1efedcSConrad Meyer REPLACE("FullMoon=", 9, nfullmoon); 411fd1efedcSConrad Meyer REPLACE("MarEquinox=", 11, nmarequinox); 412fd1efedcSConrad Meyer REPLACE("SepEquinox=", 11, nsepequinox); 413fd1efedcSConrad Meyer REPLACE("JunSolstice=", 12, njunsolstice); 414fd1efedcSConrad Meyer REPLACE("DecSolstice=", 12, ndecsolstice); 415fd1efedcSConrad Meyer if (strncmp(buf, "SEQUENCE=", 9) == 0) { 416fd1efedcSConrad Meyer setnsequences(buf + 9); 417fd1efedcSConrad Meyer continue; 418fd1efedcSConrad Meyer } 419fd1efedcSConrad Meyer 420fd1efedcSConrad Meyer /* 421fd1efedcSConrad Meyer * If the line starts with a tab, the data has to be 422fd1efedcSConrad Meyer * added to the previous line 423fd1efedcSConrad Meyer */ 424fd1efedcSConrad Meyer if (buf[0] == '\t') { 425fd1efedcSConrad Meyer for (i = 0; i < count; i++) 426fd1efedcSConrad Meyer event_continue(events[i], buf); 427fd1efedcSConrad Meyer continue; 428fd1efedcSConrad Meyer } 429fd1efedcSConrad Meyer 430fd1efedcSConrad Meyer /* Get rid of leading spaces (non-standard) */ 431fd1efedcSConrad Meyer while (isspace((unsigned char)buf[0])) 432fd1efedcSConrad Meyer memcpy(buf, buf + 1, strlen(buf)); 433fd1efedcSConrad Meyer 434fd1efedcSConrad Meyer /* No tab in the line, then not a valid line */ 435fd1efedcSConrad Meyer if ((pp = strchr(buf, '\t')) == NULL) 436fd1efedcSConrad Meyer continue; 437fd1efedcSConrad Meyer 438fd1efedcSConrad Meyer /* Trim spaces in front of the tab */ 439fd1efedcSConrad Meyer while (isspace((unsigned char)pp[-1])) 440fd1efedcSConrad Meyer pp--; 441fd1efedcSConrad Meyer 442fd1efedcSConrad Meyer p = *pp; 443fd1efedcSConrad Meyer *pp = '\0'; 444fd1efedcSConrad Meyer if ((count = parsedaymonth(buf, year, month, day, &flags, 445fd1efedcSConrad Meyer extradata)) == 0) 446fd1efedcSConrad Meyer continue; 447fd1efedcSConrad Meyer *pp = p; 448fd1efedcSConrad Meyer if (count < 0) { 449fd1efedcSConrad Meyer /* Show error status based on return value */ 450fd1efedcSConrad Meyer if (debug) 451fd1efedcSConrad Meyer fprintf(stderr, "Ignored: %s\n", buf); 452fd1efedcSConrad Meyer if (count == -1) 453fd1efedcSConrad Meyer continue; 454fd1efedcSConrad Meyer count = -count + 1; 455fd1efedcSConrad Meyer } 456fd1efedcSConrad Meyer 457fd1efedcSConrad Meyer /* Find the last tab */ 458fd1efedcSConrad Meyer while (pp[1] == '\t') 459fd1efedcSConrad Meyer pp++; 460fd1efedcSConrad Meyer 461fd1efedcSConrad Meyer if (d_first < 0) 462fd1efedcSConrad Meyer d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 463fd1efedcSConrad Meyer 464fd1efedcSConrad Meyer for (i = 0; i < count; i++) { 465fd1efedcSConrad Meyer tm.tm_mon = month[i] - 1; 466fd1efedcSConrad Meyer tm.tm_mday = day[i]; 467fd1efedcSConrad Meyer tm.tm_year = year[i] - 1900; 468fd1efedcSConrad Meyer (void)strftime(dbuf, sizeof(dbuf), 469fd1efedcSConrad Meyer d_first ? "%e %b" : "%b %e", &tm); 470fd1efedcSConrad Meyer if (debug) 471fd1efedcSConrad Meyer fprintf(stderr, "got %s\n", pp); 472fd1efedcSConrad Meyer events[i] = event_add(year[i], month[i], day[i], dbuf, 473fd1efedcSConrad Meyer ((flags &= F_VARIABLE) != 0) ? 1 : 0, pp, 474fd1efedcSConrad Meyer extradata[i]); 475fd1efedcSConrad Meyer } 476fd1efedcSConrad Meyer } 477fd1efedcSConrad Meyer 478fd1efedcSConrad Meyer free(line); 479fd1efedcSConrad Meyer fclose(in); 480fd1efedcSConrad Meyer 481fd1efedcSConrad Meyer return (0); 482fd1efedcSConrad Meyer } 483fd1efedcSConrad Meyer 484fd1efedcSConrad Meyer void 485fd1efedcSConrad Meyer cal(void) 486fd1efedcSConrad Meyer { 487fd1efedcSConrad Meyer FILE *fpin; 488fd1efedcSConrad Meyer FILE *fpout; 489fd1efedcSConrad Meyer int i; 490fd1efedcSConrad Meyer 491fd1efedcSConrad Meyer for (i = 0; i < MAXCOUNT; i++) 492fd1efedcSConrad Meyer extradata[i] = (char *)calloc(1, 20); 493fd1efedcSConrad Meyer 494fd1efedcSConrad Meyer 495fd1efedcSConrad Meyer if ((fpin = opencalin()) == NULL) 496fd1efedcSConrad Meyer return; 497fd1efedcSConrad Meyer 498fd1efedcSConrad Meyer if ((fpout = opencalout()) == NULL) { 499fd1efedcSConrad Meyer fclose(fpin); 500fd1efedcSConrad Meyer return; 501fd1efedcSConrad Meyer } 502fd1efedcSConrad Meyer 503fd1efedcSConrad Meyer if (cal_parse(fpin, fpout)) 504fd1efedcSConrad Meyer return; 505fd1efedcSConrad Meyer 506fd1efedcSConrad Meyer event_print_all(fpout); 507fd1efedcSConrad Meyer closecal(fpout); 508fd1efedcSConrad Meyer } 509fd1efedcSConrad Meyer 510fd1efedcSConrad Meyer FILE * 511fd1efedcSConrad Meyer opencalin(void) 512fd1efedcSConrad Meyer { 513fd1efedcSConrad Meyer struct stat sbuf; 514fd1efedcSConrad Meyer FILE *fpin; 515fd1efedcSConrad Meyer 516fd1efedcSConrad Meyer /* open up calendar file */ 517fd1efedcSConrad Meyer if ((fpin = fopen(calendarFile, "r")) == NULL) { 518fd1efedcSConrad Meyer if (doall) { 519fd1efedcSConrad Meyer if (chdir(calendarHomes[0]) != 0) 520fd1efedcSConrad Meyer return (NULL); 521fd1efedcSConrad Meyer if (stat(calendarNoMail, &sbuf) == 0) 522fd1efedcSConrad Meyer return (NULL); 523fd1efedcSConrad Meyer if ((fpin = fopen(calendarFile, "r")) == NULL) 524fd1efedcSConrad Meyer return (NULL); 525fd1efedcSConrad Meyer } else { 526fd1efedcSConrad Meyer fpin = cal_fopen(calendarFile); 527fd1efedcSConrad Meyer } 528fd1efedcSConrad Meyer } 529fd1efedcSConrad Meyer return (fpin); 530fd1efedcSConrad Meyer } 531fd1efedcSConrad Meyer 532fd1efedcSConrad Meyer FILE * 533fd1efedcSConrad Meyer opencalout(void) 534fd1efedcSConrad Meyer { 535fd1efedcSConrad Meyer int fd; 536fd1efedcSConrad Meyer 537fd1efedcSConrad Meyer /* not reading all calendar files, just set output to stdout */ 538fd1efedcSConrad Meyer if (!doall) 539fd1efedcSConrad Meyer return (stdout); 540fd1efedcSConrad Meyer 541fd1efedcSConrad Meyer /* set output to a temporary file, so if no output don't send mail */ 542fd1efedcSConrad Meyer snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP); 543fd1efedcSConrad Meyer if ((fd = mkstemp(path)) < 0) 544fd1efedcSConrad Meyer return (NULL); 545fd1efedcSConrad Meyer return (fdopen(fd, "w+")); 546fd1efedcSConrad Meyer } 547fd1efedcSConrad Meyer 548fd1efedcSConrad Meyer void 549fd1efedcSConrad Meyer closecal(FILE *fp) 550fd1efedcSConrad Meyer { 551fd1efedcSConrad Meyer struct stat sbuf; 552fd1efedcSConrad Meyer int nread, pdes[2], status; 553fd1efedcSConrad Meyer char buf[1024]; 554fd1efedcSConrad Meyer 555fd1efedcSConrad Meyer if (!doall) 556fd1efedcSConrad Meyer return; 557fd1efedcSConrad Meyer 558fd1efedcSConrad Meyer rewind(fp); 559fd1efedcSConrad Meyer if (fstat(fileno(fp), &sbuf) || !sbuf.st_size) 560fd1efedcSConrad Meyer goto done; 561fd1efedcSConrad Meyer if (pipe(pdes) < 0) 562fd1efedcSConrad Meyer goto done; 563fd1efedcSConrad Meyer switch (fork()) { 564fd1efedcSConrad Meyer case -1: /* error */ 565fd1efedcSConrad Meyer (void)close(pdes[0]); 566fd1efedcSConrad Meyer (void)close(pdes[1]); 567fd1efedcSConrad Meyer goto done; 568fd1efedcSConrad Meyer case 0: 569fd1efedcSConrad Meyer /* child -- set stdin to pipe output */ 570fd1efedcSConrad Meyer if (pdes[0] != STDIN_FILENO) { 571fd1efedcSConrad Meyer (void)dup2(pdes[0], STDIN_FILENO); 572fd1efedcSConrad Meyer (void)close(pdes[0]); 573fd1efedcSConrad Meyer } 574fd1efedcSConrad Meyer (void)close(pdes[1]); 575fd1efedcSConrad Meyer execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F", 576fd1efedcSConrad Meyer "\"Reminder Service\"", (char *)NULL); 577fd1efedcSConrad Meyer warn(_PATH_SENDMAIL); 578fd1efedcSConrad Meyer _exit(1); 579fd1efedcSConrad Meyer } 580fd1efedcSConrad Meyer /* parent -- write to pipe input */ 581fd1efedcSConrad Meyer (void)close(pdes[0]); 582fd1efedcSConrad Meyer 583fd1efedcSConrad Meyer write(pdes[1], "From: \"Reminder Service\" <", 26); 584fd1efedcSConrad Meyer write(pdes[1], pw->pw_name, strlen(pw->pw_name)); 585fd1efedcSConrad Meyer write(pdes[1], ">\nTo: <", 7); 586fd1efedcSConrad Meyer write(pdes[1], pw->pw_name, strlen(pw->pw_name)); 587fd1efedcSConrad Meyer write(pdes[1], ">\nSubject: ", 11); 588fd1efedcSConrad Meyer write(pdes[1], dayname, strlen(dayname)); 589fd1efedcSConrad Meyer write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30); 590fd1efedcSConrad Meyer 591fd1efedcSConrad Meyer while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) 592fd1efedcSConrad Meyer (void)write(pdes[1], buf, nread); 593fd1efedcSConrad Meyer (void)close(pdes[1]); 594fd1efedcSConrad Meyer done: (void)fclose(fp); 595fd1efedcSConrad Meyer (void)unlink(path); 596fd1efedcSConrad Meyer while (wait(&status) >= 0); 597fd1efedcSConrad Meyer } 598