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

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

/***************************************************************/
/*                                                             */
/*  QUEUE.C                                                    */
/*                                                             */
/*  Queue up reminders for subsequent execution.               */
/*                                                             */
/*  This file is part of REMIND.                               */
/*  Copyright (C) 1992, 1993, 1994 by David F. Skoll           */
/*                                                             */
/***************************************************************/
#include "config.h"

/* We only want object code generated if we have queued reminders */
#ifdef HAVE_QUEUED
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#ifdef HAVE_UNISTD
#include <unistd.h>
#endif

#if defined(__OS2__) || defined(__MSDOS__)
#include <io.h>
#if defined(__BORLANDC__)
#include <dos.h>
#endif
#include <process.h>
#endif

#include "globals.h"
#include "err.h"
#include "types.h"
#include "protos.h"
#include "expr.h"

/* List structure for holding queued reminders */
typedef struct queuedrem {
   struct queuedrem *next;
   int typ;
   int RunDisabled;
   int ntrig;
   char *text;
   char sched[VAR_NAME_LEN+1];
   TimeTrig tt;
} QueuedRem;

/* Global variables */

static QueuedRem *QueueHead;
static time_t FileModTime;
static struct stat StatBuf;

PRIVATE void CheckInitialFile ARGS ((void));
PRIVATE int CalculateNextTime ARGS ((QueuedRem *q));
PRIVATE QueuedRem *FindNextReminder ARGS ((void));
PRIVATE int CalculateNextTimeUsingSched ARGS ((QueuedRem *q));

/***************************************************************/
/*                                                             */
/*  QueueReminder                                              */
/*                                                             */
/*  Put the reminder on a queue for later, if queueing is      */
/*  enabled.                                                   */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int QueueReminder(ParsePtr p, int typ, TimeTrig *tim, const char *sched)
#else
int QueueReminder(p, typ, tim, sched)
ParsePtr p;
int typ;
TimeTrig *tim;
char *sched;
#endif
{
   QueuedRem *qelem;

   if (DontQueue ||
       tim->ttime == NO_TIME ||
       typ == CAL_TYPE ||
       tim->ttime < SystemTime(0) / 60 ||
       ((typ == RUN_TYPE) && RunDisabled)) return OK;

   qelem = NEW(QueuedRem);
   if (!qelem) {
      return E_NO_MEM;
   }
   qelem->text = StrDup(p->pos);  /* Guaranteed that parser is not nested. */
   if (!qelem->text) {
      free(qelem);
      return E_NO_MEM;
   }
   qelem->typ = typ;
   qelem->tt = *tim;
   qelem->next = QueueHead;
   qelem->RunDisabled = RunDisabled;
   qelem->ntrig = 0;
   strcpy(qelem->sched, sched);
   QueueHead = qelem;
   NumQueued++;
   return OK;
}

/***************************************************************/
/*                                                             */
/*  HandleQueuedReminders                                      */
/*                                                             */
/*  Handle the issuing of queued reminders in the background   */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC void HandleQueuedReminders(void)
#else
void HandleQueuedReminders()
#endif
{
   QueuedRem *q = QueueHead;
   long TimeToSleep;
   unsigned SleepTime;
   Parser p;
   Trigger trig;

   /* Suppress the BANNER from being issued */
   NumTriggered = 1;
   
   /* If we are not connected to a tty, then we must close the
    * standard file descriptors. This is to prevent someone
    * doing:
    *		remind file | <filter> | >log
    * and have <filter> hung because the child (us) is still
    * connected to it. This means the only commands that will be
    * processed correctly are RUN commands, provided they mail
    * the result back or use their own resource (as a window).
    */
   if (!DontFork && (!isatty(1) || !isatty(2))) {
      close(1);
      close(2);
   }

   /* If we're a daemon, get the mod time of initial file */
   if (Daemon) {
      if (stat(InitialFile, &StatBuf)) {
         fprintf(ErrFp, "Cannot stat %s - not running as daemon!\n",
	                  InitialFile);
         Daemon = 0;
      } else FileModTime = StatBuf.st_mtime;
   }
   
   /* Initialize the queue - initialize all the entries time of issue */
   
   while (q) {
      q->tt.nexttime = (int) (SystemTime(0)/60 - 1);
      q->tt.nexttime = CalculateNextTime(q);
      q = q->next;
   }

#ifdef __BORLANDC__
   signal(SIGINT, SigIntHandler);
#else
   if (!DontFork || Daemon) signal(SIGINT, SigIntHandler);
#endif

   /* Sit in a loop, issuing reminders when necessary */
   while(1) {
      q = FindNextReminder();

      /* If no more reminders to issue, we're done unless we're a daemon. */
      if (!q && !Daemon) break;

      if (Daemon && !q)
         TimeToSleep = (long) 60*Daemon;
      else
         TimeToSleep = (long) q->tt.nexttime * 60L - SystemTime(0);

      while (TimeToSleep > 0L) {
         SleepTime = (unsigned) ((TimeToSleep > 30000L) ? 30000 : TimeToSleep);

	 if (Daemon && SleepTime > 60*Daemon) SleepTime = 60*Daemon;

	 sleep(SleepTime);

	 if (Daemon && SleepTime) CheckInitialFile();

	 if (Daemon && !q)
	    TimeToSleep = (long) 60*Daemon;
         else
	    TimeToSleep = (long) q->tt.nexttime * 60L - SystemTime(0);
      }

      /* Trigger the reminder */
      CreateParser(q->text, &p);
      trig.typ = q->typ;
      RunDisabled = q->RunDisabled;
#ifdef OS2_POPUP
      (void) TriggerReminder(&p, &trig, &q->tt, JulianToday, 1);
#else
      (void) TriggerReminder(&p, &trig, &q->tt, JulianToday);
#endif
      fflush(stdout);
      
      /* Calculate the next trigger time */
      q->tt.nexttime = CalculateNextTime(q);
   }
#ifdef __BORLANDC__
   signal(SIGINT, SIG_DFL);
#endif
   exit(0);
}
   

/***************************************************************/
/*                                                             */
/*  CalculateNextTime                                          */
/*                                                             */
/*  Calculate the next time when a reminder should be issued.  */
/*  Return NO_TIME if reminder expired.                        */
/*  Strategy is:  If a sched() function is defined, call it.   */
/*  Otherwise, use AT time with delta and rep.  If sched()     */
/*  fails, revert to AT with delta and rep.                    */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int CalculateNextTime(QueuedRem *q)
#else
static int CalculateNextTime(q)
QueuedRem *q;
#endif
{
   int tim = q->tt.ttime;
   int rep = q->tt.rep;
   int delta = q->tt.delta;
   int curtime = q->tt.nexttime+1;
   int r;

/* Increment number of times this one has been triggered */
   q->ntrig++;
   if (q->sched[0]) {
      r = CalculateNextTimeUsingSched(q);
      if (r != NO_TIME) return r;
   }
   if (delta == NO_DELTA)
      if (tim < curtime) return NO_TIME; else return tim;

   tim -= delta;
   if (rep == NO_REP) rep = delta;
   if (tim < curtime) tim += ((curtime - tim) / rep) * rep;
   if (tim < curtime) tim += rep;
   if (tim > q->tt.ttime) tim = q->tt.ttime;
   if (tim < curtime) return NO_TIME; else return tim;
}

/***************************************************************/
/*                                                             */
/*  FindNextReminder                                           */
/*                                                             */
/*  Find the next reminder to trigger                          */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE QueuedRem *FindNextReminder(void)
#else
static QueuedRem *FindNextReminder()
#endif
{
   QueuedRem *q = QueueHead;
   QueuedRem *ans = NULL;

   while (q) {
      if (q->tt.nexttime != NO_TIME) {
         if (!ans) ans = q;
	 else if (q->tt.nexttime < ans->tt.nexttime) ans = q;
       }
      
      q = q->next;
   }
   return ans;
}
   

/***************************************************************/
/*                                                             */
/* GotSigInt						       */
/*                                                             */
/* Split out what's done on a SIGINT from the SIGINT Handler.  */
/* This will be necessary for OS/2 multithreaded.	       */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
void GotSigInt(void)
#else
void GotSigInt()
#endif
{
   QueuedRem *q = QueueHead;

   printf("Contents of AT queue:%s", NL);

   while (q) {
      if (q->tt.nexttime != NO_TIME) {
         printf("Trigger: %02d%c%02d  Activate: %02d%c%02d  Rep: %d  Delta: %d  Sched: %s",
                 q->tt.ttime / 60, TIMESEP, q->tt.ttime % 60,
                 q->tt.nexttime / 60, TIMESEP, q->tt.nexttime % 60,
                 q->tt.rep, q->tt.delta, q->sched);
         if (*q->sched) printf("(%d)", q->ntrig+1);
	 printf("%s", NL);
         printf("Text: %s %s%s%s", ((q->typ == MSG_TYPE) ? "MSG" :
		                    ((q->typ == MSF_TYPE) ? "MSF" :"RUN")),
                 q->text,
                 NL, NL);
      }
      q = q->next;
   }
   printf(NL);
}

/***************************************************************/
/*                                                             */
/*  CheckInitialFile                                           */
/*                                                             */
/*  If the initial file has been modified, then restart the    */
/*  daemon.                                                    */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE void CheckInitialFile(void)
#else
static void CheckInitialFile()
#endif
{
   /* If date has rolled around, or file has changed, spawn a new version. */
   time_t tim = FileModTime;
   int y, m, d;

   if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime;
   if (tim != FileModTime ||
       RealToday != SystemDate(&y, &m, &d))
          execvp(ArgV[0], ArgV);
}

/***************************************************************/
/*                                                             */
/*  CalculateNextTimeUsingSched                                */
/*                                                             */
/*  Call the scheduling function.                              */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int CalculateNextTimeUsingSched(QueuedRem *q)
#else
static int CalculateNextTimeUsingSched(q)
QueuedRem *q;
#endif
{
   /* Use LineBuffer for temp. string storage. */
   int r;
   Value v;
   char *s;
   int LastTime = -1;
   int ThisTime;

   if (UserFuncExists(q->sched) != 1) {
      q->sched[0] = 0;
      return NO_TIME;
   }

   RunDisabled = q->RunDisabled;  /* Don't want weird scheduling functions
				     to be a security hole!                */
   while(1) {
      sprintf(LineBuffer, "%s(%d)", q->sched, q->ntrig);
      s = LineBuffer;
      r = EvalExpr(&s, &v);
      if (r) {
         q->sched[0] = 0;
         return NO_TIME;
      }
      if (v.type == TIM_TYPE) {
         ThisTime = v.v.val;
      } else if (v.type == INT_TYPE) {
         if (v.v.val > 0) 
	    ThisTime = q->tt.nexttime + v.v.val;
         else
	    ThisTime = q->tt.ttime + v.v.val;

      } else {
         DestroyValue(v);
	 q->sched[0] = 0;
	 return NO_TIME;
      }
      if (ThisTime < 0) ThisTime = 0;        /* Can't be less than 00:00 */
      if (ThisTime > 1439) ThisTime = 1439;  /* or greater than 11:59 */
      if (ThisTime > q->tt.nexttime) return ThisTime;
      if (ThisTime <= LastTime) {
         q->sched[0] = 0;
	 return NO_TIME;
      }
      LastTime = ThisTime;
      q->ntrig++;
   }
}

#endif /* HAVE_QUEUED from way at the top */

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