home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / remind / src / queue.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-01  |  12.5 KB  |  405 lines

  1. /***************************************************************/
  2. /*                                                             */
  3. /*  QUEUE.C                                                    */
  4. /*                                                             */
  5. /*  Queue up reminders for subsequent execution.               */
  6. /*                                                             */
  7. /*  This file is part of REMIND.                               */
  8. /*  Copyright (C) 1992, 1993 by David F. Skoll.                */
  9. /*                                                             */
  10. /***************************************************************/
  11. #include "config.h"
  12. #include <stdio.h>
  13. #include <signal.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #ifdef HAVE_STDLIB_H
  17. #include <stdlib.h>
  18. #endif
  19. #ifdef HAVE_MALLOC_H
  20. #include <malloc.h>
  21. #endif
  22. #ifdef HAVE_UNISTD
  23. #include <unistd.h>
  24. #endif
  25.  
  26. #if defined(__OS2__) || defined(__MSDOS__)
  27. #include <string.h>
  28. #include <io.h>
  29. #if defined(__BORLANDC__)
  30. #include <dos.h>
  31. #endif
  32. #include <process.h>
  33. #endif
  34.  
  35. #include "globals.h"
  36. #include "err.h"
  37. #include "types.h"
  38. #include "protos.h"
  39. #include "expr.h"
  40.  
  41. /* List structure for holding queued reminders */
  42. typedef struct queuedrem {
  43.    struct queuedrem *next;
  44.    int typ;
  45.    int RunDisabled;
  46.    int ntrig;
  47.    char *text;
  48.    char sched[VAR_NAME_LEN+1];
  49.    TimeTrig tt;
  50. } QueuedRem;
  51.  
  52. /* Global variables */
  53.  
  54. static QueuedRem *QueueHead;
  55. static time_t FileModTime;
  56. static struct stat StatBuf;
  57.  
  58. PRIVATE void CheckInitialFile ARGS ((void));
  59. PRIVATE int CalculateNextTime ARGS ((QueuedRem *q));
  60. PRIVATE QueuedRem *FindNextReminder ARGS ((void));
  61. PRIVATE int CalculateNextTimeUsingSched ARGS ((QueuedRem *q));
  62.  
  63. #ifdef __BORLANDC__
  64. void (__cdecl SigIntHandler(int));
  65. #else
  66. void SigIntHandler ARGS ((void));
  67. #endif
  68.  
  69. /***************************************************************/
  70. /*                                                             */
  71. /*  QueueReminder                                              */
  72. /*                                                             */
  73. /*  Put the reminder on a queue for later, if queueing is      */
  74. /*  enabled.                                                   */
  75. /*                                                             */
  76. /***************************************************************/
  77. #ifdef HAVE_PROTOS
  78. PUBLIC int QueueReminder(ParsePtr p, int typ, TimeTrig *tim, const char *sched)
  79. #else
  80. int QueueReminder(p, typ, tim, sched)
  81. ParsePtr p;
  82. int typ;
  83. TimeTrig *tim;
  84. char *sched;
  85. #endif
  86. {
  87.    QueuedRem *qelem;
  88.  
  89.    if (DontQueue ||
  90.        tim->ttime == NO_TIME ||
  91.        typ == CAL_TYPE ||
  92.        tim->ttime < SystemTime() / 60 ||
  93.        ((typ == RUN_TYPE) && RunDisabled)) return OK;
  94.  
  95.    qelem = NEW(QueuedRem);
  96.    if (!qelem) {
  97.       return E_NO_MEM;
  98.    }
  99.    qelem->text = StrDup(p->pos);  /* Guaranteed that parser is not nested. */
  100.    if (!qelem->text) {
  101.       free(qelem);
  102.       return E_NO_MEM;
  103.    }
  104.    qelem->typ = typ;
  105.    qelem->tt = *tim;
  106.    qelem->next = QueueHead;
  107.    qelem->RunDisabled = RunDisabled;
  108.    qelem->ntrig = 0;
  109.    strcpy(qelem->sched, sched);
  110.    QueueHead = qelem;
  111.    NumQueued++;
  112.    return OK;
  113. }
  114.  
  115. /***************************************************************/
  116. /*                                                             */
  117. /*  HandleQueuedReminders                                      */
  118. /*                                                             */
  119. /*  Handle the issuing of queued reminders in the background   */
  120. /*                                                             */
  121. /***************************************************************/
  122. #ifdef HAVE_PROTOS
  123. PUBLIC void HandleQueuedReminders(void)
  124. #else
  125. void HandleQueuedReminders()
  126. #endif
  127. {
  128.    QueuedRem *q = QueueHead;
  129.    long TimeToSleep;
  130.    unsigned SleepTime;
  131.    Parser p;
  132.    Trigger trig;
  133.  
  134.    /* Suppress the BANNER from being issued */
  135.    NumTriggered = 1;
  136.    
  137.    /* If we are not connected to a tty, then we must close the
  138.     * standard file descriptors. This is to prevent someone
  139.     * doing:
  140.     *        remind file | <filter> | >log
  141.     * and have <filter> hung because the child (us) is still
  142.     * connected to it. This means the only commands that will be
  143.     * processed correctly are RUN commands, provided they mail
  144.     * the result back or use their own resource (as a window).
  145.     */
  146.    if (!DontFork && (!isatty(1) || !isatty(2))) {
  147.       close(1);
  148.       close(2);
  149.    }
  150.  
  151.    /* If we're a daemon, get the mod time of initial file */
  152.    if (Daemon) {
  153.       if (stat(InitialFile, &StatBuf)) {
  154.          fprintf(ErrFp, "Cannot stat %s - not running as daemon!\n",
  155.                       InitialFile);
  156.          Daemon = 0;
  157.       } else FileModTime = StatBuf.st_mtime;
  158.    }
  159.    
  160.    /* Initialize the queue - initialize all the entries time of issue */
  161.    
  162.    while (q) {
  163.       q->tt.nexttime = (int) (SystemTime()/60 - 1);
  164.       q->tt.nexttime = CalculateNextTime(q);
  165.       q = q->next;
  166.    }
  167.  
  168. #ifdef __BORLANDC__
  169.    signal(SIGINT, SigIntHandler);
  170. #else
  171.    if (!DontFork || Daemon) signal(SIGINT, SigIntHandler);
  172. #endif
  173.  
  174.    /* Sit in a loop, issuing reminders when necessary */
  175.    while(1) {
  176.       q = FindNextReminder();
  177.  
  178.       /* If no more reminders to issue, we're unless we're a daemon. */
  179.       if (!q && !Daemon) break;
  180.  
  181.       if (Daemon && !q)
  182.          TimeToSleep = (long) 60*Daemon;
  183.       else
  184.          TimeToSleep = (long) q->tt.nexttime * 60L - SystemTime();
  185.  
  186.       while (TimeToSleep > 0L) {
  187.          SleepTime = (unsigned) ((TimeToSleep > 30000L) ? 30000 : TimeToSleep);
  188.  
  189.      if (Daemon && SleepTime > 60*Daemon) SleepTime = 60*Daemon;
  190.  
  191.      sleep(SleepTime);
  192.  
  193.      if (Daemon && SleepTime) CheckInitialFile();
  194.  
  195.      if (Daemon && !q)
  196.         TimeToSleep = (long) 60*Daemon;
  197.          else
  198.         TimeToSleep = (long) q->tt.nexttime * 60L - SystemTime();
  199.       }
  200.  
  201.       /* Trigger the reminder */
  202.       CreateParser(q->text, &p);
  203.       trig.typ = q->typ;
  204.       RunDisabled = q->RunDisabled;
  205.       (void) TriggerReminder(&p, &trig, &q->tt, JulianToday, 1);
  206.       fflush(stdout);
  207.       
  208.       /* Calculate the next trigger time */
  209.       q->tt.nexttime = CalculateNextTime(q);
  210.    }
  211. #ifdef __BORLANDC__
  212.    signal(SIGINT, SIG_DFL);
  213. #endif
  214.    exit(0);
  215. }
  216.    
  217.  
  218. /***************************************************************/
  219. /*                                                             */
  220. /*  CalculateNextTime                                          */
  221. /*                                                             */
  222. /*  Calculate the next time when a reminder should be issued.  */
  223. /*  Return NO_TIME if reminder expired.                        */
  224. /*  Strategy is:  If a sched() function is defined, call it.   */
  225. /*  Otherwise, use AT time with delta and rep.  If sched()     */
  226. /*  fails, revert to AT with delta and rep.                    */
  227. /*                                                             */
  228. /***************************************************************/
  229. #ifdef HAVE_PROTOS
  230. PRIVATE int CalculateNextTime(QueuedRem *q)
  231. #else
  232. static int CalculateNextTime(q)
  233. QueuedRem *q;
  234. #endif
  235. {
  236.    int tim = q->tt.ttime;
  237.    int rep = q->tt.rep;
  238.    int delta = q->tt.delta;
  239.    int curtime = q->tt.nexttime+1;
  240.    int r;
  241.  
  242. /* Increment number of times this one has been triggered */
  243.    q->ntrig++;
  244.    if (q->sched[0]) {
  245.       r = CalculateNextTimeUsingSched(q);
  246.       if (r != NO_TIME) return r;
  247.    }
  248.    if (delta == NO_DELTA)
  249.       if (tim < curtime) return NO_TIME; else return tim;
  250.  
  251.    tim -= delta;
  252.    if (rep == NO_REP) rep = delta;
  253.    if (tim < curtime) tim += ((curtime - tim) / rep) * rep;
  254.    if (tim < curtime) tim += rep;
  255.    if (tim > q->tt.ttime) tim = q->tt.ttime;
  256.    if (tim < curtime) return NO_TIME; else return tim;
  257. }
  258.  
  259. /***************************************************************/
  260. /*                                                             */
  261. /*  FindNextReminder                                           */
  262. /*                                                             */
  263. /*  Find the next reminder to trigger                          */
  264. /*                                                             */
  265. /***************************************************************/
  266. #ifdef HAVE_PROTOS
  267. PRIVATE QueuedRem *FindNextReminder(void)
  268. #else
  269. static QueuedRem *FindNextReminder()
  270. #endif
  271. {
  272.    QueuedRem *q = QueueHead;
  273.    QueuedRem *ans = NULL;
  274.  
  275.    while (q) {
  276.       if (q->tt.nexttime != NO_TIME) {
  277.          if (!ans) ans = q;
  278.      else if (q->tt.nexttime < ans->tt.nexttime) ans = q;
  279.        }
  280.       
  281.       q = q->next;
  282.    }
  283.    return ans;
  284. }
  285.    
  286.  
  287. /***************************************************************/
  288. /*                                                             */
  289. /* GotSigInt                               */
  290. /*                                                             */
  291. /* Split out what's done on a SIGINT from the SIGINT Handler.  */
  292. /* This will be necessary for OS/2 multithreaded.           */
  293. /*                                                             */
  294. /***************************************************************/
  295. #ifdef HAVE_PROTOS
  296. void GotSigInt(void)
  297. #else
  298. void GotSigInt()
  299. #endif
  300. {
  301.    QueuedRem *q = QueueHead;
  302.  
  303.    printf("Contents of AT queue:%s", NL);
  304.  
  305.    while (q) {
  306.       if (q->tt.nexttime != NO_TIME) {
  307.          printf("Trigger: %02d%c%02d  Activate: %02d%c%02d  Rep: %d  Delta: %d  Sched: %s%s",
  308.                  q->tt.ttime / 60, TIMESEP, q->tt.ttime % 60,
  309.                  q->tt.nexttime / 60, TIMESEP, q->tt.nexttime % 60,
  310.                  q->tt.rep, q->tt.delta, q->sched, NL);
  311.                  printf("Text: %s %s%s%s", ((q->typ == MSG_TYPE) ? "MSG" :
  312.                                    ((q->typ == MSF_TYPE) ? "MSF" :"RUN")),
  313.                  q->text,
  314.                  NL, NL);
  315.       }
  316.       q = q->next;
  317.    }
  318.    printf(NL);
  319. }
  320.  
  321. /***************************************************************/
  322. /*                                                             */
  323. /*  CheckInitialFile                                           */
  324. /*                                                             */
  325. /*  If the initial file has been modified, then restart the    */
  326. /*  daemon.                                                    */
  327. /*                                                             */
  328. /***************************************************************/
  329. #ifdef HAVE_PROTOS
  330. PRIVATE void CheckInitialFile(void)
  331. #else
  332. static void CheckInitialFile()
  333. #endif
  334. {
  335.    /* If date has rolled around, or file has changed, spawn a new version. */
  336.    time_t tim = FileModTime;
  337.    int y, m, d;
  338.  
  339.    if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime;
  340.    if (tim != FileModTime ||
  341.        RealToday != SystemDate(&y, &m, &d))
  342.           execvp(ArgV[0], ArgV);
  343. }
  344.  
  345. /***************************************************************/
  346. /*                                                             */
  347. /*  CalculateNextTimeUsingSched                                */
  348. /*                                                             */
  349. /*  Call the scheduling function.                              */
  350. /*                                                             */
  351. /***************************************************************/
  352. #ifdef HAVE_PROTOS
  353. PRIVATE int CalculateNextTimeUsingSched(QueuedRem *q)
  354. #else
  355. static int CalculateNextTimeUsingSched(q)
  356. QueuedRem *q;
  357. #endif
  358. {
  359.    /* Use LineBuffer for temp. string storage. */
  360.    int r;
  361.    Value v;
  362.    char *s;
  363.    int LastTime = -1;
  364.    int ThisTime;
  365.  
  366.    if (UserFuncExists(q->sched) != 1) {
  367.       q->sched[0] = 0;
  368.       return NO_TIME;
  369.    }
  370.  
  371.    RunDisabled = q->RunDisabled;  /* Don't want weird scheduling functions
  372.                      to be a security hole!                */
  373.    while(1) {
  374.       sprintf(LineBuffer, "%s(%d)", q->sched, q->ntrig);
  375.       s = LineBuffer;
  376.       r = EvalExpr(&s, &v);
  377.       if (r) {
  378.          q->sched[0] = 0;
  379.          return NO_TIME;
  380.       }
  381.       if (v.type == TIM_TYPE) {
  382.          ThisTime = v.v.val;
  383.       } else if (v.type == INT_TYPE) {
  384.          if (v.v.val > 0) 
  385.         ThisTime = q->tt.nexttime + v.v.val;
  386.          else
  387.         ThisTime = q->tt.ttime + v.v.val;
  388.  
  389.       } else {
  390.          DestroyValue(&v);
  391.      q->sched[0] = 0;
  392.      return NO_TIME;
  393.       }
  394.       if (ThisTime < 0) ThisTime = 0;        /* Can't be less than 00:00 */
  395.       if (ThisTime > 1439) ThisTime = 1439;  /* or greater than 11:59 */
  396.       if (ThisTime > q->tt.nexttime) return ThisTime;
  397.       if (ThisTime <= LastTime) {
  398.          q->sched[0] = 0;
  399.      return NO_TIME;
  400.       }
  401.       LastTime = ThisTime;
  402.       q->ntrig++;
  403.    }
  404. }
  405.