~ubuntu-branches/ubuntu/karmic/remind/karmic

« back to all changes in this revision

Viewing changes to src/queue.c

  • Committer: Bazaar Package Importer
  • Author(s): Javier Fernandez-Sanguino Pen~a
  • Date: 1999-02-19 13:36:15 UTC
  • Revision ID: james.westby@ubuntu.com-19990219133615-ovob95sord67b0ks
Tags: 03.00.22-1
* NMU upload, maintainer seems to be missing.
* Changed to main (now GPL) (Closes: #42402)
* New upstream version (Closes: #59447)
* Moved to use debconf.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-1998 by David F. Skoll                  */
 
9
/*  Copyright (C) 1999-2000 by Roaring Penguin Software Inc.   */
 
10
/*                                                             */
 
11
/***************************************************************/
 
12
 
 
13
#include "config.h"
 
14
static char const RCSID[] = "$Id: queue.c,v 1.16 2000/06/26 14:44:07 dfs Exp $";
 
15
 
 
16
/* Solaris needs this to get select() prototype */
 
17
#ifdef __sun__
 
18
#define __EXTENSIONS__ 1
 
19
#endif
 
20
 
 
21
/* We only want object code generated if we have queued reminders */
 
22
#ifdef HAVE_QUEUED
 
23
#include <stdio.h>
 
24
#include <string.h>
 
25
#include <signal.h>
 
26
#include <sys/types.h>
 
27
#include <sys/stat.h>
 
28
 
 
29
#ifdef HAVE_SYS_TIME_H
 
30
#include <sys/time.h>
 
31
#endif
 
32
 
 
33
#ifdef HAVE_SYS_SELECT_H
 
34
#include <sys/select.h>
 
35
#endif
 
36
 
 
37
#ifdef HAVE_STDLIB_H
 
38
#include <stdlib.h>
 
39
#endif
 
40
 
 
41
#ifdef HAVE_MALLOC_H
 
42
#include <malloc.h>
 
43
#endif
 
44
 
 
45
#ifdef HAVE_UNISTD_H
 
46
#include <unistd.h>
 
47
#endif
 
48
 
 
49
#if defined(__OS2__) || defined(__MSDOS__)
 
50
#include <io.h>
 
51
#if defined(__BORLANDC__)
 
52
#include <dos.h>
 
53
#endif
 
54
#include <process.h>
 
55
#endif
 
56
 
 
57
#include "globals.h"
 
58
#include "err.h"
 
59
#include "types.h"
 
60
#include "protos.h"
 
61
#include "expr.h"
 
62
 
 
63
/* List structure for holding queued reminders */
 
64
typedef struct queuedrem {
 
65
    struct queuedrem *next;
 
66
    int typ;
 
67
    int RunDisabled;
 
68
    int ntrig;
 
69
    char *text;
 
70
    char sched[VAR_NAME_LEN+1];
 
71
    char tag[TAG_LEN+1];
 
72
    TimeTrig tt;
 
73
} QueuedRem;
 
74
 
 
75
/* Global variables */
 
76
 
 
77
static QueuedRem *QueueHead;
 
78
static time_t FileModTime;
 
79
static struct stat StatBuf;
 
80
 
 
81
PRIVATE void CheckInitialFile ARGS ((void));
 
82
PRIVATE int CalculateNextTime ARGS ((QueuedRem *q));
 
83
PRIVATE QueuedRem *FindNextReminder ARGS ((void));
 
84
PRIVATE int CalculateNextTimeUsingSched ARGS ((QueuedRem *q));
 
85
PRIVATE void DaemonWait ARGS ((unsigned int sleeptime));
 
86
PRIVATE void reread ARGS((void));
 
87
 
 
88
/***************************************************************/
 
89
/*                                                             */
 
90
/*  QueueReminder                                              */
 
91
/*                                                             */
 
92
/*  Put the reminder on a queue for later, if queueing is      */
 
93
/*  enabled.                                                   */
 
94
/*                                                             */
 
95
/***************************************************************/
 
96
#ifdef HAVE_PROTOS
 
97
PUBLIC int QueueReminder(ParsePtr p, Trigger *trig,
 
98
                         TimeTrig *tim, const char *sched)
 
99
#else
 
100
int QueueReminder(p, trig, tim, sched)
 
101
ParsePtr p;
 
102
Trigger *trig,
 
103
TimeTrig *tim;
 
104
char *sched;
 
105
#endif
 
106
{
 
107
    QueuedRem *qelem;
 
108
 
 
109
    if (DontQueue ||
 
110
        tim->ttime == NO_TIME ||
 
111
        trig->typ == CAL_TYPE ||
 
112
        tim->ttime < SystemTime(0) / 60 ||
 
113
        ((trig->typ == RUN_TYPE) && RunDisabled)) return OK;
 
114
 
 
115
    qelem = NEW(QueuedRem);
 
116
    if (!qelem) {
 
117
        return E_NO_MEM;
 
118
    }
 
119
    qelem->text = StrDup(p->pos);  /* Guaranteed that parser is not nested. */
 
120
    if (!qelem->text) {
 
121
        free(qelem);
 
122
        return E_NO_MEM;
 
123
    }
 
124
    NumQueued++;
 
125
    qelem->typ = trig->typ;
 
126
    qelem->tt = *tim;
 
127
    qelem->next = QueueHead;
 
128
    qelem->RunDisabled = RunDisabled;
 
129
    qelem->ntrig = 0;
 
130
    strcpy(qelem->sched, sched);
 
131
    strcpy(qelem->tag, trig->tag);
 
132
    QueueHead = qelem;
 
133
    return OK;
 
134
}
 
135
 
 
136
/***************************************************************/
 
137
/*                                                             */
 
138
/*  HandleQueuedReminders                                      */
 
139
/*                                                             */
 
140
/*  Handle the issuing of queued reminders in the background   */
 
141
/*                                                             */
 
142
/***************************************************************/
 
143
#ifdef HAVE_PROTOS
 
144
PUBLIC void HandleQueuedReminders(void)
 
145
#else
 
146
void HandleQueuedReminders()
 
147
#endif
 
148
{
 
149
    QueuedRem *q = QueueHead;
 
150
    long TimeToSleep;
 
151
    unsigned SleepTime;
 
152
    Parser p;
 
153
    Trigger trig;
 
154
 
 
155
    /* Suppress the BANNER from being issued */
 
156
    NumTriggered = 1;
 
157
 
 
158
    /* Turn off sorting -- otherwise, TriggerReminder has no effect! */
 
159
    SortByDate = 0;
 
160
 
 
161
    /* If we are not connected to a tty, then we must close the
 
162
     * standard file descriptors. This is to prevent someone
 
163
     * doing:
 
164
     *          remind file | <filter> | >log
 
165
     * and have <filter> hung because the child (us) is still
 
166
     * connected to it. This means the only commands that will be
 
167
     * processed correctly are RUN commands, provided they mail
 
168
     * the result back or use their own resource (as a window).
 
169
     */
 
170
    if (!DontFork && (!isatty(1) || !isatty(2))) {
 
171
        close(1);
 
172
        close(2);
 
173
    }
 
174
 
 
175
    /* If we're a daemon, get the mod time of initial file */
 
176
    if (Daemon > 0) {
 
177
        if (stat(InitialFile, &StatBuf)) {
 
178
            fprintf(ErrFp, "Cannot stat %s - not running as daemon!\n",
 
179
                    InitialFile);
 
180
            Daemon = 0;
 
181
        } else FileModTime = StatBuf.st_mtime;
 
182
    }
 
183
   
 
184
    /* Initialize the queue - initialize all the entries time of issue */
 
185
   
 
186
    while (q) {
 
187
        q->tt.nexttime = (int) (SystemTime(0)/60 - 1);
 
188
        q->tt.nexttime = CalculateNextTime(q);
 
189
        q = q->next;
 
190
    }
 
191
 
 
192
#ifdef __BORLANDC__
 
193
    signal(SIGINT, SigIntHandler);
 
194
#else
 
195
    if (!DontFork || Daemon) signal(SIGINT, SigIntHandler);
 
196
#endif
 
197
 
 
198
    /* Sit in a loop, issuing reminders when necessary */
 
199
    while(1) {
 
200
        q = FindNextReminder();
 
201
 
 
202
        /* If no more reminders to issue, we're done unless we're a daemon. */
 
203
        if (!q && !Daemon) break;
 
204
 
 
205
        if (Daemon && !q) {
 
206
            if (Daemon < 0) {
 
207
                /* Sleep until midnight */
 
208
                TimeToSleep = (long) 1440*60L - SystemTime(0);
 
209
            } else {
 
210
                TimeToSleep = (long) 60*Daemon;
 
211
            }
 
212
        } else {
 
213
            TimeToSleep = (long) q->tt.nexttime * 60L - SystemTime(0);
 
214
        }
 
215
 
 
216
        while (TimeToSleep > 0L) {
 
217
            SleepTime = (unsigned) ((TimeToSleep > 30000L) ? 30000 : TimeToSleep);
 
218
 
 
219
            if (Daemon > 0 && SleepTime > 60*Daemon) SleepTime = 60*Daemon;
 
220
 
 
221
            if (Daemon >= 0) {
 
222
                sleep(SleepTime);
 
223
            } else {
 
224
                DaemonWait(SleepTime);
 
225
            }
 
226
 
 
227
            if (Daemon> 0 && SleepTime) CheckInitialFile();
 
228
 
 
229
            if (Daemon && !q) {
 
230
                if (Daemon < 0) {
 
231
                    /* Sleep until midnight */
 
232
                    TimeToSleep = (long) 1440*60L - SystemTime(0);
 
233
                } else {
 
234
                    TimeToSleep = (long) 60*Daemon;
 
235
                }
 
236
            } else {
 
237
                TimeToSleep = (long) q->tt.nexttime * 60L - SystemTime(0);
 
238
            }
 
239
 
 
240
        }
 
241
 
 
242
        /* Trigger the reminder */
 
243
        CreateParser(q->text, &p);
 
244
        trig.typ = q->typ;
 
245
        RunDisabled = q->RunDisabled;
 
246
        if (Daemon < 0) {
 
247
            printf("NOTE reminder %s ",
 
248
                   SimpleTime(q->tt.ttime));
 
249
            printf("%s ", SimpleTime(SystemTime(0)/60));
 
250
            if (!*q->tag) {
 
251
                printf("*");
 
252
            } else {
 
253
                printf("%s", q->tag);
 
254
            }
 
255
            printf("\n");
 
256
        }
 
257
 
 
258
        /* Set up global variables so some functions like trigdate()
 
259
           and trigtime() work correctly                             */
 
260
        LastTriggerDate = JulianToday;
 
261
        LastTriggerTime = q->tt.ttime;
 
262
        LastTrigValid = 1;
 
263
#ifdef OS2_POPUP
 
264
        (void) TriggerReminder(&p, &trig, &q->tt, JulianToday, 1);
 
265
#else
 
266
        (void) TriggerReminder(&p, &trig, &q->tt, JulianToday);
 
267
#endif
 
268
        if (Daemon < 0) {
 
269
            printf("NOTE endreminder\n");
 
270
        }
 
271
        fflush(stdout);
 
272
      
 
273
        /* Calculate the next trigger time */
 
274
        q->tt.nexttime = CalculateNextTime(q);
 
275
    }
 
276
#ifdef __BORLANDC__
 
277
    signal(SIGINT, SIG_DFL);
 
278
#endif
 
279
    exit(0);
 
280
}
 
281
   
 
282
 
 
283
/***************************************************************/
 
284
/*                                                             */
 
285
/*  CalculateNextTime                                          */
 
286
/*                                                             */
 
287
/*  Calculate the next time when a reminder should be issued.  */
 
288
/*  Return NO_TIME if reminder expired.                        */
 
289
/*  Strategy is:  If a sched() function is defined, call it.   */
 
290
/*  Otherwise, use AT time with delta and rep.  If sched()     */
 
291
/*  fails, revert to AT with delta and rep.                    */
 
292
/*                                                             */
 
293
/***************************************************************/
 
294
#ifdef HAVE_PROTOS
 
295
PRIVATE int CalculateNextTime(QueuedRem *q)
 
296
#else
 
297
static int CalculateNextTime(q)
 
298
QueuedRem *q;
 
299
#endif
 
300
{
 
301
    int tim = q->tt.ttime;
 
302
    int rep = q->tt.rep;
 
303
    int delta = q->tt.delta;
 
304
    int curtime = q->tt.nexttime+1;
 
305
    int r;
 
306
 
 
307
/* Increment number of times this one has been triggered */
 
308
    q->ntrig++;
 
309
    if (q->sched[0]) {
 
310
        r = CalculateNextTimeUsingSched(q);
 
311
        if (r != NO_TIME) return r;
 
312
    }
 
313
    if (delta == NO_DELTA) {
 
314
        if (tim < curtime) {
 
315
            return NO_TIME; 
 
316
        } else {
 
317
            return tim;
 
318
        }
 
319
    }
 
320
 
 
321
    tim -= delta;
 
322
    if (rep == NO_REP) rep = delta;
 
323
    if (tim < curtime) tim += ((curtime - tim) / rep) * rep;
 
324
    if (tim < curtime) tim += rep;
 
325
    if (tim > q->tt.ttime) tim = q->tt.ttime;
 
326
    if (tim < curtime) return NO_TIME; else return tim;
 
327
}
 
328
 
 
329
/***************************************************************/
 
330
/*                                                             */
 
331
/*  FindNextReminder                                           */
 
332
/*                                                             */
 
333
/*  Find the next reminder to trigger                          */
 
334
/*                                                             */
 
335
/***************************************************************/
 
336
#ifdef HAVE_PROTOS
 
337
PRIVATE QueuedRem *FindNextReminder(void)
 
338
#else
 
339
static QueuedRem *FindNextReminder()
 
340
#endif
 
341
{
 
342
    QueuedRem *q = QueueHead;
 
343
    QueuedRem *ans = NULL;
 
344
 
 
345
    while (q) {
 
346
        if (q->tt.nexttime != NO_TIME) {
 
347
            if (!ans) ans = q;
 
348
            else if (q->tt.nexttime < ans->tt.nexttime) ans = q;
 
349
        }
 
350
      
 
351
        q = q->next;
 
352
    }
 
353
    return ans;
 
354
}
 
355
   
 
356
 
 
357
/***************************************************************/
 
358
/*                                                             */
 
359
/* GotSigInt                                                   */
 
360
/*                                                             */
 
361
/* Split out what's done on a SIGINT from the SIGINT Handler.  */
 
362
/* This will be necessary for OS/2 multithreaded.              */
 
363
/*                                                             */
 
364
/***************************************************************/
 
365
#ifdef HAVE_PROTOS
 
366
void GotSigInt(void)
 
367
#else
 
368
void GotSigInt()
 
369
#endif
 
370
{
 
371
    QueuedRem *q = QueueHead;
 
372
 
 
373
    printf("Contents of AT queue:%s", NL);
 
374
 
 
375
    while (q) {
 
376
        if (q->tt.nexttime != NO_TIME) {
 
377
            printf("Trigger: %02d%c%02d  Activate: %02d%c%02d  Rep: %d  Delta: %d  Sched: %s",
 
378
                   q->tt.ttime / 60, TIMESEP, q->tt.ttime % 60,
 
379
                   q->tt.nexttime / 60, TIMESEP, q->tt.nexttime % 60,
 
380
                   q->tt.rep, q->tt.delta, q->sched);
 
381
            if (*q->sched) printf("(%d)", q->ntrig+1);
 
382
            printf("%s", NL);
 
383
            printf("Text: %s %s%s%s", ((q->typ == MSG_TYPE) ? "MSG" :
 
384
                                       ((q->typ == MSF_TYPE) ? "MSF" :"RUN")),
 
385
                   q->text,
 
386
                   NL, NL);
 
387
        }
 
388
        q = q->next;
 
389
    }
 
390
    printf(NL);
 
391
}
 
392
 
 
393
/***************************************************************/
 
394
/*                                                             */
 
395
/*  CheckInitialFile                                           */
 
396
/*                                                             */
 
397
/*  If the initial file has been modified, then restart the    */
 
398
/*  daemon.                                                    */
 
399
/*                                                             */
 
400
/***************************************************************/
 
401
#ifdef HAVE_PROTOS
 
402
PRIVATE void CheckInitialFile(void)
 
403
#else
 
404
static void CheckInitialFile()
 
405
#endif
 
406
{
 
407
    /* If date has rolled around, or file has changed, spawn a new version. */
 
408
    time_t tim = FileModTime;
 
409
    int y, m, d;
 
410
 
 
411
    if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime;
 
412
    if (tim != FileModTime ||
 
413
        RealToday != SystemDate(&y, &m, &d)) {
 
414
        reread();
 
415
    }
 
416
}
 
417
 
 
418
/***************************************************************/
 
419
/*                                                             */
 
420
/*  CalculateNextTimeUsingSched                                */
 
421
/*                                                             */
 
422
/*  Call the scheduling function.                              */
 
423
/*                                                             */
 
424
/***************************************************************/
 
425
#ifdef HAVE_PROTOS
 
426
PRIVATE int CalculateNextTimeUsingSched(QueuedRem *q)
 
427
#else
 
428
static int CalculateNextTimeUsingSched(q)
 
429
QueuedRem *q;
 
430
#endif
 
431
{
 
432
    /* Use LineBuffer for temp. string storage. */
 
433
    int r;
 
434
    Value v;
 
435
    char *s;
 
436
    int LastTime = -1;
 
437
    int ThisTime;
 
438
 
 
439
    if (UserFuncExists(q->sched) != 1) {
 
440
        q->sched[0] = 0;
 
441
        return NO_TIME;
 
442
    }
 
443
 
 
444
    RunDisabled = q->RunDisabled;  /* Don't want weird scheduling functions
 
445
                                     to be a security hole!                */
 
446
    while(1) {
 
447
        char exprBuf[VAR_NAME_LEN+32];
 
448
        sprintf(exprBuf, "%s(%d)", q->sched, q->ntrig);
 
449
        s = exprBuf;
 
450
        r = EvalExpr(&s, &v);
 
451
        if (r) {
 
452
            q->sched[0] = 0;
 
453
            return NO_TIME;
 
454
        }
 
455
        if (v.type == TIM_TYPE) {
 
456
            ThisTime = v.v.val;
 
457
        } else if (v.type == INT_TYPE) {
 
458
            if (v.v.val > 0) 
 
459
                ThisTime = q->tt.nexttime + v.v.val;
 
460
            else
 
461
                ThisTime = q->tt.ttime + v.v.val;
 
462
 
 
463
        } else {
 
464
            DestroyValue(v);
 
465
            q->sched[0] = 0;
 
466
            return NO_TIME;
 
467
        }
 
468
        if (ThisTime < 0) ThisTime = 0;        /* Can't be less than 00:00 */
 
469
        if (ThisTime > 1439) ThisTime = 1439;  /* or greater than 11:59 */
 
470
        if (ThisTime > q->tt.nexttime) return ThisTime;
 
471
        if (ThisTime <= LastTime) {
 
472
            q->sched[0] = 0;
 
473
            return NO_TIME;
 
474
        }
 
475
        LastTime = ThisTime;
 
476
        q->ntrig++;
 
477
    }
 
478
}
 
479
 
 
480
/***************************************************************/
 
481
/*                                                             */
 
482
/*  DaemonWait                                                 */
 
483
/*                                                             */
 
484
/*  Sleep or read command from stdin in "daemon -1" mode       */
 
485
/*                                                             */
 
486
/***************************************************************/
 
487
#ifdef HAVE_PROTOS
 
488
PRIVATE void DaemonWait(unsigned int sleeptime)
 
489
#else
 
490
static DaemonWait(sleeptime)
 
491
unsigned int sleeptime;
 
492
#endif
 
493
{
 
494
    fd_set readSet;
 
495
    struct timeval timeout;
 
496
    int retval;
 
497
    int y, m, d;
 
498
    char cmdLine[256];
 
499
 
 
500
    FD_ZERO(&readSet);
 
501
    FD_SET(0, &readSet);
 
502
    timeout.tv_sec = sleeptime;
 
503
    timeout.tv_usec = 0;
 
504
    retval = select(1, &readSet, NULL, NULL, &timeout);
 
505
 
 
506
    /* If date has rolled around, restart */
 
507
    if (RealToday != SystemDate(&y, &m, &d)) {
 
508
        printf("NOTE newdate\nNOTE reread\n");
 
509
        fflush(stdout);
 
510
        reread();
 
511
    }
 
512
 
 
513
    /* If nothing readable or interrupted system call, return */
 
514
    if (retval <= 0) return;
 
515
 
 
516
    /* If stdin not readable, return */
 
517
    if (!FD_ISSET(0, &readSet)) return;
 
518
 
 
519
    /* If EOF on stdin, exit */
 
520
    if (feof(stdin)) {
 
521
        exit(0);
 
522
    }
 
523
 
 
524
    /* Read a line from stdin and interpret it */
 
525
    if (!fgets(cmdLine, sizeof(cmdLine), stdin)) {
 
526
        exit(0);
 
527
    }
 
528
 
 
529
    if (!strcmp(cmdLine, "EXIT\n")) {
 
530
        exit(0);
 
531
    } else if (!strcmp(cmdLine, "STATUS\n")) {
 
532
        int nqueued = 0;
 
533
        QueuedRem *q = QueueHead;
 
534
        while(q) {
 
535
            if (q->tt.nexttime != NO_TIME) {
 
536
                nqueued++;
 
537
            }
 
538
            q = q->next;
 
539
        }
 
540
        printf("NOTE queued %d\n", nqueued);
 
541
        fflush(stdout);
 
542
    } else if (!strcmp(cmdLine, "REREAD\n")) {
 
543
        printf("NOTE reread\n");
 
544
        fflush(stdout);
 
545
        reread();
 
546
    } else {
 
547
        printf("ERR Invalid daemon command: %s", cmdLine);
 
548
        fflush(stdout);
 
549
    }
 
550
}
 
551
 
 
552
/***************************************************************/
 
553
/*                                                             */
 
554
/*  reread                                                     */
 
555
/*                                                             */
 
556
/*  Restarts Remind if date rolls over or REREAD cmd received  */
 
557
/*                                                             */
 
558
/***************************************************************/
 
559
#ifdef HAVE_PROTOS
 
560
PRIVATE void reread(void)
 
561
#else
 
562
static reread()
 
563
#endif
 
564
{
 
565
    execvp(ArgV[0], ArgV);
 
566
}
 
567
 
 
568
#endif /* HAVE_QUEUED from way at the top */