ftp.nice.ch/pub/next/unix/calendars/remind.3.0.13.N.bs.tar.gz#/remind-3.0.13/init.c

This is init.c in view mode; [Download] [Up]

/***************************************************************/
/*                                                             */
/*  INIT.C                                                     */
/*                                                             */
/*  Initialize remind; perform certain tasks between           */
/*  iterations in calendar mode; do certain checks after end   */
/*  in normal mode.                                            */
/*                                                             */
/*  This file is part of REMIND.                               */
/*  Copyright (C) 1992, 1993, 1994 by David F. Skoll.          */
/*                                                             */
/***************************************************************/
#define L_IN_INIT 1
#include "config.h"
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#ifdef UNIX
#include <sys/types.h>
#include <pwd.h>
#ifdef HAVE_UNISTD
#include <unistd.h>
#endif
#endif
#include <ctype.h>
#include "types.h"
#include "protos.h"
#include "expr.h"
#include "err.h"
#include "version.h"
#include "globals.h"

/***************************************************************
 *
 *  Command line options recognized:
 *
 *  -n       = Output next trigger date of each reminder in
 *             simple calendar format.
 *  -r       = Disallow RUN mode
 *  -c[n]    = Produce a calendar for n months (default = 1)
 *  -w[n,n,n] = Specify output device width, padding and spacing
 *  -s[n]    = Produce calendar in "simple calendar" format
 *  -p[n]    = Produce calendar in format compatible with rem2ps
 *  -v       = Verbose mode
 *  -o       = Ignore ONCE directives
 *  -a       = Don't issue timed reminders which will be queued
 *  -q       = Don't queue timed reminders
 *  -t       = Trigger all reminders (infinite delta)
 *  -h       = Hush mode
 *  -f       = Do not fork
 *  -dchars  = Debugging mode:  Chars are:
 *             e = Echo input lines
 *             x = Display expression evaluation
 *             t = Display trigger dates
 *             v = Dump variables at end
 *             l = Display entire line in error messages
 *  -e       = Send messages normally sent to stderr to stdout instead
 *  -z[n]    = Daemon mode waking up every n (def 5) minutes.
 *  -bn      = Time format for cal (0, 1, or 2)
 *  -xn      = Max. number of iterations for SATISFY
 *  -uname   = Run as user 'name' - only valid when run by root.  If run
 *             by non-root, changes environment but not effective uid.
 *  -kcmd    = Run 'cmd' for MSG-type reminders instead of printing to stdout
 *  -iVAR=EXPR = Initialize and preserve VAR.
 *  -m       = Start calendar with Monday instead of Sunday.
 *  A minus sign alone indicates to take input from stdin
 *
 **************************************************************/

/* For parsing an integer */
#define PARSENUM(var, s)   \
   var = 0;                \
   while (isdigit(*(s))) { \
      var *= 10;           \
      var += *(s) - '0';   \
      s++;                 \
   }

#ifdef UNIX
PRIVATE void ChgUser ARGS((char *uname));
#endif

PRIVATE void InitializeVar ARGS ((char *str));

static char *BadDate = "Illegal date on command line\n";

/***************************************************************/
/*                                                             */
/*  InitRemind                                                 */
/*                                                             */
/*  Initialize the system - called only once at beginning!     */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC void InitRemind(int argc, char *argv[])
#else
void InitRemind(argc, argv)
int argc;
char *argv[];
#endif
{
   char *arg;
   int i;
   int y, m, d, rep;
   Token tok;

   y = NO_YR;
   m = NO_MON;
   d = NO_DAY;
   rep = NO_REP;

   RealToday = SystemDate(&CurYear, &CurMon, &CurDay);
   if (RealToday < 0) {
      fprintf(ErrFp, ErrMsg[M_BAD_SYS_DATE], BASE);
      exit(1);
   }
   JulianToday = RealToday;
   FromJulian(JulianToday, &CurYear, &CurMon, &CurDay);

#if !defined(HAVE_QUEUED)
   DontFork = 1;
   DontQueue = 1;
   NumQueued = 0;
   DontIssueAts = 0;
   Daemon = 0;
#elif defined(_MSC_VER) || defined(__BORLANDC__)
   DontFork = 1;
#elif defined(__OS2__) && defined (__MSDOS__)
   if (DOSMODE)
     DontFork = 1;
#endif

   /* Parse the command-line options */
   i = 1;
   while (i < argc) {
      arg = argv[i];
      if (*arg != '-') break; /* Exit the loop if it's not an option */
      i++;
      arg++;
      if (!*arg) {
         UseStdin = 1;
	 IgnoreOnce = 1;
	 i--;
	 break;
      }
      while (*arg) {
         switch(*arg++) {

            case 'i':
	    case 'I':
	       InitializeVar(arg);
	       while(*arg) arg++;
	       break;
	   
	    case 'n':
	    case 'N':
	       NextMode = 1;
#ifdef HAVE_QUEUED
	       DontQueue = 1;
	       Daemon = 0;
#endif
	       break;

	    case 'r':
	    case 'R':
	       RunDisabled = 1;
	       break;

	    case 'm':
	    case 'M':
	       MondayFirst = 1;
	       break;

	    case 'o':
	    case 'O':
	       IgnoreOnce = 1;
	       break;

	    case 't':
	    case 'T':
	       InfiniteDelta = 1;
	       break;

	    case 'e':
	    case 'E':
	       ErrFp = stdout;
	       break;

	    case 'h':
	    case 'H':
	       Hush = 1;
	       break;

	    case 'g':
	    case 'G':
	       SortByDate = SORT_ASCEND;
	       SortByTime = SORT_ASCEND;
	       SortByPrio = SORT_ASCEND;
	       if (*arg) {
	          if (*arg == 'D' || *arg == 'd')
		     SortByDate = SORT_DESCEND;
		  arg++;
               }
	       if (*arg) {
	          if (*arg == 'D' || *arg == 'd')
		     SortByTime = SORT_DESCEND;
		  arg++;
               }
	       if (*arg) {
	          if (*arg == 'D' || *arg == 'd')
		     SortByPrio = SORT_DESCEND;
		  arg++;
               }
	       break;

#if defined(UNIX) && defined(WANT_U_OPTION)
	    case 'u':
	    case 'U':
	       ChgUser(arg);
	       while (*arg) arg++;
	       break;
#endif	       

#ifdef HAVE_QUEUED
	    case 'z':
	    case 'Z':
	       DontFork = 1;
	       PARSENUM(Daemon, arg);
	       if (Daemon<5) Daemon=5;
	       else if (Daemon>60) Daemon=60;
	       break;

	    case 'a':
	    case 'A':
	       DontIssueAts = 1;
	       break;

	    case 'q':
	    case 'Q':
	       DontQueue = 1;
	       break;

	    case 'f':
	    case 'F':
	       DontFork = 1;
	       break;
#endif
	    case 'c':
	    case 'C':
	       DoCalendar = 1;
	       if (*arg == '+') {
	          arg++;
	          PARSENUM(CalWeeks, arg);
		  if (!CalWeeks) CalWeeks = 1;
               } else {
   	          PARSENUM(CalMonths, arg);
	          if (!CalMonths) CalMonths = 1;
               }
	       break;

	    case 's':
	    case 'S':
	       DoSimpleCalendar = 1;
	       if (*arg == '+') {
	          arg++;
	          PARSENUM(CalWeeks, arg);
		  if (!CalWeeks) CalWeeks = 1;
               } else {
   	          PARSENUM(CalMonths, arg);
	          if (!CalMonths) CalMonths = 1;
               }
	       break;

	    case 'p':
	    case 'P':
	       DoSimpleCalendar = 1;
	       PsCal = 1;
	       PARSENUM(CalMonths, arg);
	       if (!CalMonths) CalMonths = 1;
	       break;

	    case 'w':
	    case 'W':
	       if (*arg != ',') {
	          PARSENUM(CalWidth, arg);
	          if (CalWidth < 80) CalWidth = 80;
	       }
	       if (*arg == ',') {
	          arg++;
		  if (*arg != ',') {
   		     PARSENUM(CalLines, arg);
		     if (CalLines > 20) CalLines = 20;
		  }
		  if (*arg == ',') {
		     arg++;
		     PARSENUM(CalPad, arg);
		     if (CalPad > 20) CalPad = 20;
		  }
	       }
	       break;

	    case 'd':
	    case 'D':
	       while (*arg) {
	          switch(*arg++) {
		     case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break;
		     case 'x': case 'X': DebugFlag |= DB_PRTEXPR;   break;
		     case 't': case 'T': DebugFlag |= DB_PRTTRIG;   break;
		     case 'v': case 'V': DebugFlag |= DB_DUMP_VARS; break;
		     case 'l': case 'L': DebugFlag |= DB_PRTLINE;   break;
		     default:
		        fprintf(ErrFp, ErrMsg[M_BAD_DB_FLAG], *(arg-1));
		  }
               }
	       break;

	    case 'v':
	    case 'V':
	       DebugFlag |= DB_PRTLINE;
	       ShowAllErrors = 1;
	       break;

	    case 'b':
	    case 'B':
	       PARSENUM(ScFormat, arg);
	       if (ScFormat<0 || ScFormat>2) ScFormat=SC_AMPM;
	       break;

	    case 'x':
	    case 'X':
	       PARSENUM(MaxSatIter, arg);
	       if (MaxSatIter < 10) MaxSatIter=10;
	       break;

	    case 'k':
	    case 'K':
	       MsgCommand = arg;
	       while (*arg) arg++;  /* Chew up remaining chars in this arg */
	       break;

	    default:
	       fprintf(ErrFp, ErrMsg[M_BAD_OPTION], *(arg-1));
	 }

      }
   }

   /* Get the filename. */
   if (i >= argc) {
      Usage();
      exit(1);
   }
   InitialFile = argv[i++];

   /* Get the date, if any */
   if (i < argc) {
      while (i < argc) {
         arg = argv[i++];
         FindToken(arg, &tok);
	 switch (tok.type) {
	    case T_Time:
	       if (SysTime != -1L) Usage();
	       else {
		  SysTime = (long) tok.val * 60L;
#ifdef HAVE_QUEUED
		  DontQueue = 1;
		  Daemon = 0;
#endif
	       }
	       break;

	    case T_Month:
	       if (m != NO_MON) Usage();
	       else m = tok.val;
	       break;

	    case T_Day:
	       if (d != NO_DAY) Usage();
	       else d = tok.val;
	       break;

	    case T_Year:
	       if (y != NO_YR) Usage();
	       else y = tok.val;
	       break;

	    case T_Rep:
	       if (rep != NO_REP) Usage();
	       else rep = tok.val;
	       break;

	    default: Usage();
         }
      }

      if (rep > 0) {
         Iterations = rep;
	 DontQueue = 1;
	 Daemon = 0;
      }

/* Must supply date in the form:  day, mon, yr OR mon, yr */
      if (m != NO_MON || y != NO_YR || d != NO_DAY) {
	 if (m == NO_MON || y == NO_YR) {
	    if (rep == NO_REP) Usage();
	    else if (m != NO_MON || y != NO_YR) Usage();
	    else {
	       m = CurMon;
	       y = CurYear;
	       if (d == NO_DAY) d = CurDay;
	    }
	 }
	 if (d == NO_DAY) d=1;
	 if (d > DaysInMonth(m, y)) {
	    fprintf(ErrFp, BadDate);
	    Usage();
	 }
	 JulianToday = Julian(y, m, d);
	 if (JulianToday == -1) {
	    fprintf(ErrFp, BadDate);
	    Usage();
	 }
	 CurYear = y;
	 CurMon = m;
	 CurDay = d;
	 if (JulianToday != RealToday) IgnoreOnce = 1;
      }

   }
/* Figure out the offset from UTC */
   if (CalculateUTC)
      (void) CalcMinsFromUTC(JulianToday, SystemTime(1)/60,
			     &MinsFromUTC, NULL);
}

/***************************************************************/
/*                                                             */
/*  Usage                                                      */
/*                                                             */
/*  Print the usage info.                                      */
/*                                                             */
/***************************************************************/
#ifndef L_USAGE_OVERRIDE
#ifdef HAVE_PROTOS
PUBLIC void Usage(void)
#else
void Usage()
#endif /* HAVE_PROTOS */
{
   fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1994 by David F. Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
   fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
   fprintf(ErrFp, "Usage: remind [options] filename [date] [time] [*rep]\n");
   fprintf(ErrFp, "Options:\n");
   fprintf(ErrFp, " -n     Output next occurrence of reminders in simple format\n");
   fprintf(ErrFp, " -r     Disable RUN directives\n");
   fprintf(ErrFp, " -c[n]  Produce a calendar for n (default 1) months\n");
   fprintf(ErrFp, " -c+[n] Produce a calendar for n (default 1) weeks\n");
   fprintf(ErrFp, " -w[n[,p[,s]]]  Specify width, padding and spacing of calendar\n");
   fprintf(ErrFp, " -s[+][n] Produce 'simple calendar' for n (1) months (weeks)\n");
   fprintf(ErrFp, " -p[n]  Same as -s, but input compatible with rem2ps\n");
   fprintf(ErrFp, " -v     Verbose mode\n");
   fprintf(ErrFp, " -o     Ignore ONCE directives\n");
   fprintf(ErrFp, " -t     Trigger all future reminders regardless of delta\n");
   fprintf(ErrFp, " -h     'Hush' mode - be very quiet\n");
#ifdef HAVE_QUEUED
   fprintf(ErrFp, " -a     Don't trigger timed reminders immediately - just queue them\n");
   fprintf(ErrFp, " -q     Don't queue timed reminders\n");
   fprintf(ErrFp, " -f     Trigger timed reminders by staying in foreground\n");
   fprintf(ErrFp, " -z[n]  Enter daemon mode, waking every n (5) minutes.\n");
#endif
   fprintf(ErrFp, " -d...  Debug: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
   fprintf(ErrFp, " -e     Divert messages normally sent to stderr to stdout\n");
   fprintf(ErrFp, " -b[n]  Time format for cal: 0=am/pm, 1=24hr, 2=none\n");
   fprintf(ErrFp, " -x[n]  Iteration limit for SATISFY clause (def=150)\n");
   fprintf(ErrFp, " -kcmd  Run 'cmd' for MSG-type reminders\n");
   fprintf(ErrFp, " -g[ddd] Sort reminders by date, time and priority before issuing\n");
   fprintf(ErrFp, " -ivar=val Initialize var to val and preserve var\n");
   fprintf(ErrFp, " -m     Start calendar with Monday rather than Sunday\n");
   exit(1);
}
#endif /* L_USAGE_OVERRIDE */
/***************************************************************/
/*                                                             */
/*  ChgUser                                                    */
/*                                                             */
/*  Run as a specified user.  Can only be used if Remind is    */
/*  started by root.  This changes the real and effective uid, */
/*  the real and effective gid, and sets the HOME, SHELL and   */
/*  USER environment variables.                                */
/*                                                             */
/***************************************************************/
#if defined(UNIX) && defined(WANT_U_OPTION)
#ifdef HAVE_PROTOS
PRIVATE void ChgUser(char *user)
#else
static void ChgUser(user)
char *user;
#endif /* HAVE_PROTOS */
{
#ifdef SYSV
   /* uid_t myuid; This seems to mess up on XENIX, so forget it... */ 
  int myuid;
#else
   int myuid;
#endif

   struct passwd *pwent;
   static char *home, *shell, *username, *logname;

   myuid = getuid();

   pwent = getpwnam(user);

   if (!pwent) {
      fprintf(ErrFp, ErrMsg[M_BAD_USER], user);
      exit(1);
   }

   if (!myuid && setgid(pwent->pw_gid)) {
      fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
      exit(1);
   }

   if (!myuid && setuid(pwent->pw_uid)) {
      fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid);
      exit(1);
   }

   home = malloc(strlen(pwent->pw_dir) + 6);
   if (!home) {
      fprintf(ErrFp, ErrMsg[M_NOMEM_ENV]);
      exit(1);
   }
   sprintf(home, "HOME=%s", pwent->pw_dir);
   putenv(home);

   shell = malloc(strlen(pwent->pw_shell) + 7);
   if (!shell) {
      fprintf(ErrFp, ErrMsg[M_NOMEM_ENV]);
      exit(1);
   }
   sprintf(shell, "SHELL=%s", pwent->pw_shell);
   putenv(shell);

   if (pwent->pw_uid) {
      username = malloc(strlen(pwent->pw_name) + 6);
      if (!username) {
         fprintf(ErrFp, ErrMsg[M_NOMEM_ENV]);
         exit(1);
      }
      sprintf(username, "USER=%s", pwent->pw_name);
      putenv(username);
      logname= malloc(strlen(pwent->pw_name) + 9);
      if (!logname) {
         fprintf(ErrFp, ErrMsg[M_NOMEM_ENV]);
         exit(1);
      }
      sprintf(logname, "LOGNAME=%s", pwent->pw_name);
      putenv(logname);
   }
}
#endif /* UNIX && WANT_U_OPTION */
   
/***************************************************************/
/*                                                             */
/*  InitializeVar                                              */
/*                                                             */
/*  Initialize and preserve a variable                         */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE void InitializeVar(char *str)
#else
static void InitializeVar(str)
char *str;
#endif
{
   char *varname, *expr;

   Value val;

   int r;

   /* Scan for an '=' sign */
   varname = str;
   while (*str && *str != '=') str++;
   if (!*str) {
      fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_EQ]);
      return;
   }
   *str = 0;
   if (!*varname) {
      fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_VAR]);
      return;
   }
   expr = str+1;
   if (!*expr) {
      fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_EXPR]);
      return;
   }

   r=EvalExpr(&expr, &val);
   if (r) {
      fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
      return;
   }

   if (*varname == '$') {
      r=SetSysVar(varname+1, &val);
      if (r) fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
      return;
   }

   r=SetVar(varname, &val);
   if (r) {
      fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
      return;
   }
   r=PreserveVar(varname);
   if (r) fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
   return;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.