/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1989, 1993, 19944* The Regents of the University of California. All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14* 3. Neither the name of the University nor the names of its contributors15* may be used to endorse or promote products derived from this software16* without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND19* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE22* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL23* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS24* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)25* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT26* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY27* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF28* SUCH DAMAGE.29*/3031#include <sys/types.h>32#include <err.h>33#include <errno.h>34#include <locale.h>35#include <login_cap.h>36#include <langinfo.h>37#include <pwd.h>38#include <stdio.h>39#include <stdlib.h>40#include <string.h>41#include <time.h>42#include <unistd.h>4344#include "calendar.h"4546#define UTCOFFSET_NOTSET 100 /* Expected between -24 and +24 */47#define LONGITUDE_NOTSET 1000 /* Expected between -360 and +360 */4849struct passwd *pw;50int doall = 0;51int debug = 0;52static char *DEBUG = NULL;53static time_t f_time = 0;54double UTCOffset = UTCOFFSET_NOTSET;55int EastLongitude = LONGITUDE_NOTSET;56#ifdef WITH_ICONV57const char *outputEncoding = NULL;58#endif5960static void usage(void) __dead2;6162int63main(int argc, char *argv[])64{65int f_dayAfter = 0; /* days after current date */66int f_dayBefore = 0; /* days before current date */67int Friday = 5; /* day before weekend */6869int ch;70struct tm tp1, tp2;7172(void)setlocale(LC_ALL, "");7374while ((ch = getopt(argc, argv, "-A:aB:D:dF:f:l:t:U:W:?")) != -1)75switch (ch) {76case '-': /* backward contemptible */77case 'a':78if (getuid()) {79errno = EPERM;80err(1, NULL);81}82doall = 1;83break;8485case 'W': /* we don't need no steenking Fridays */86Friday = -1;87/* FALLTHROUGH */8889case 'A': /* days after current date */90f_dayAfter = atoi(optarg);91if (f_dayAfter < 0)92errx(1, "number of days must be positive");93break;9495case 'B': /* days before current date */96f_dayBefore = atoi(optarg);97if (f_dayBefore < 0)98errx(1, "number of days must be positive");99break;100101case 'D': /* debug output of sun and moon info */102DEBUG = optarg;103break;104105case 'd': /* debug output of current date */106debug = 1;107break;108109case 'F': /* Change the time: When does weekend start? */110Friday = atoi(optarg);111break;112113case 'f': /* other calendar file */114calendarFile = optarg;115break;116117case 'l': /* Change longitudal position */118EastLongitude = strtol(optarg, NULL, 10);119break;120121case 't': /* other date, for tests */122f_time = Mktime(optarg);123break;124125case 'U': /* Change UTC offset */126UTCOffset = strtod(optarg, NULL);127break;128129case '?':130default:131usage();132}133134argc -= optind;135argv += optind;136137if (argc)138usage();139140/* use current time */141if (f_time <= 0)142(void)time(&f_time);143144/* if not set, determine where I could be */145{146if (UTCOffset == UTCOFFSET_NOTSET &&147EastLongitude == LONGITUDE_NOTSET) {148/* Calculate on difference between here and UTC */149time_t t;150struct tm tm;151long utcoffset, hh, mm, ss;152double uo;153154time(&t);155localtime_r(&t, &tm);156utcoffset = tm.tm_gmtoff;157/* seconds -> hh:mm:ss */158hh = utcoffset / SECSPERHOUR;159utcoffset %= SECSPERHOUR;160mm = utcoffset / SECSPERMINUTE;161utcoffset %= SECSPERMINUTE;162ss = utcoffset;163164/* hh:mm:ss -> hh.mmss */165uo = mm + (100.0 * (ss / 60.0));166uo /= 60.0 / 100.0;167uo = hh + uo / 100;168169UTCOffset = uo;170EastLongitude = UTCOffset * 15;171} else if (UTCOffset == UTCOFFSET_NOTSET) {172/* Base on information given */173UTCOffset = EastLongitude / 15;174} else if (EastLongitude == LONGITUDE_NOTSET) {175/* Base on information given */176EastLongitude = UTCOffset * 15;177}178}179180settimes(f_time, f_dayBefore, f_dayAfter, Friday, &tp1, &tp2);181generatedates(&tp1, &tp2);182183/*184* FROM now on, we are working in UTC.185* This will only affect moon and sun related events anyway.186*/187if (setenv("TZ", "UTC", 1) != 0)188errx(1, "setenv: %s", strerror(errno));189tzset();190191if (debug)192dumpdates();193194if (DEBUG != NULL) {195dodebug(DEBUG);196exit(0);197}198199if (doall)200while ((pw = getpwent()) != NULL) {201pid_t pid;202203if (chdir(pw->pw_dir) == -1)204continue;205pid = fork();206if (pid < 0)207err(1, "fork");208if (pid == 0) {209login_cap_t *lc;210211lc = login_getpwclass(pw);212if (setusercontext(lc, pw, pw->pw_uid,213LOGIN_SETALL & ~LOGIN_SETLOGIN) != 0)214errx(1, "setusercontext");215setenv("HOME", pw->pw_dir, 1);216cal();217exit(0);218}219}220else {221#ifdef WITH_ICONV222/* Save the information about the encoding used in the terminal. */223outputEncoding = strdup(nl_langinfo(CODESET));224if (outputEncoding == NULL)225errx(1, "cannot allocate memory");226#endif227cal();228}229exit(0);230}231232233static void __dead2234usage(void)235{236237fprintf(stderr, "%s\n%s\n%s\n",238"usage: calendar [-A days] [-a] [-B days] [-D sun|moon] [-d]",239" [-F friday] [-f calendarfile] [-l longitude]",240" [-t dd[.mm[.year]]] [-U utcoffset] [-W days]"241);242exit(1);243}244245246