diff --git a/scripts/tkremind b/scripts/tkremind index f43250a1..116ceefb 100755 --- a/scripts/tkremind +++ b/scripts/tkremind @@ -11,7 +11,7 @@ # #-------------------------------------------------------------- -# $Id: tkremind,v 1.4 1998-03-01 20:43:23 dfs Exp $ +# $Id: tkremind,v 1.5 1998-03-02 19:38:33 dfs Exp $ # the next line restarts using wish \ exec wish "$0" "$@" @@ -25,6 +25,7 @@ set ConfirmQuit 0 # Remind program to execute -- supply full path if you want set Remind "remind" +#set Remind "/home/dfs/Remind/src/remind" # Rem2PS program to execute -- supply full path if you want set Rem2PS "rem2ps" @@ -52,6 +53,9 @@ set EnglishDayNames {Sunday Monday Tuesday Wednesday Thursday Friday Saturday} set CurMonth -1 set CurYear -1 +# Background reminder counter +set BgCounter 0 + # Absolutely today -- unlike the CurMonth and CurYear, these won't change set TodayMonth -1 set TodayYear -1 @@ -192,7 +196,7 @@ proc ColumnNumber { firstDay mondayFirst day } { # dayNames -- names of weekdays in current language {Sun .. Sat} #--------------------------------------------------------------------------- proc CreateCalWindow { firstDay mondayFirst daysInMonth month year dayNames } { - global CurMonth CurYear TodayMonth TodayYear TodayDay + global CurMonth CurYear TodayMonth TodayYear TodayDay DaemonFile catch { destroy .h } catch { destroy .b } @@ -239,13 +243,19 @@ proc CreateCalWindow { firstDay mondayFirst daysInMonth month year dayNames } { button .b.goto -text {Go To Date...} -command {GotoDialog} button .b.print -text {Print...} -command {DoPrint} button .b.quit -text {Quit} -command {Quit} - label .b.status -text "" -width 10 -relief sunken + label .b.status -text "" -width 25 -relief sunken + label .b.nqueued -text "" -width 20 -relief sunken pack .b.prev .b.this .b.next .b.goto .b.print .b.quit -side left -fill x pack .b.status -side left -fill x -expand 1 + pack .b.nqueued -side left -fill x pack .h -side top -expand 1 -fill both pack .b -side top -fill x -expand 0 wm title . "TkRemind - $month $year" wm iconname . "$month $year" + catch { + puts $DaemonFile "STATUS" + flush $DaemonFile + } } #--------------------------------------------------------------------------- @@ -860,6 +870,7 @@ proc ModifyDay {d firstDay} { puts $f "" close $f FillCalWindow + RestartBackgroundRemindDaemon return 0 } } @@ -1373,6 +1384,140 @@ proc BrowseForFileRead {w {dir ""}} { $w.entry delete 0 end } +#--------------------------------------------------------------------------- +# StartBackgroundRemindDaemon +# Arguments: +# none +# Returns: +# nothing +# Description: +# Starts a background Remind daemon to handle timed reminders +#--------------------------------------------------------------------------- +proc StartBackgroundRemindDaemon {} { + global Remind DaemonFile ReminderFile + set problem [catch { set DaemonFile [open "|$Remind -z0 $ReminderFile" "r+"] } err] + if {$problem} { + tk_dialog .error Error "Can't start Remind daemon in background: $err" error 0 OK + } else { + fileevent $DaemonFile readable "DaemonReadable $DaemonFile" + puts $DaemonFile "STATUS" + flush $DaemonFile + } +} + +#--------------------------------------------------------------------------- +# StopBackgroundRemindDaemon +# Arguments: +# none +# Returns: +# nothing +# Description: +# Stops the background Remind daemon +#--------------------------------------------------------------------------- +proc StopBackgroundRemindDaemon {} { + global DaemonFile + catch { + puts $DaemonFile "EXIT" + flush $DaemonFile + close $DaemonFile + } +} + +#--------------------------------------------------------------------------- +# RestartBackgroundRemindDaemon +# Arguments: +# none +# Returns: +# nothing +# Description: +# Restarts the background Remind daemon +#--------------------------------------------------------------------------- +proc RestartBackgroundRemindDaemon {} { + global DaemonFile + catch { + puts $DaemonFile "REREAD" + flush $DaemonFile + } +} + +#--------------------------------------------------------------------------- +# DaemonReadable +# Arguments: +# file -- file channel that is readable +# Returns: +# nothing +# Description: +# Reads data from the Remind daemon and handles it appropriately +#--------------------------------------------------------------------------- +proc DaemonReadable { file } { + set line "" + catch { set line [gets $file] } + switch -glob $line { + "NOTE reminder*" { + scan $line "NOTE reminder %s %s" time now + IssueBackgroundReminder $file $time $now + } + "NOTE reread" { + puts $file "STATUS" + flush $file + } + "NOTE queued*" { + scan $line "NOTE queued %d" n + if {$n == 1} { + .b.nqueued configure -text "1 reminder queued" + } else { + .b.nqueued configure -text "$n reminders queued" + } + } + default { + puts "Unknown message from daemon: $line\n" + } + } +} + +#--------------------------------------------------------------------------- +# IssueBackgroundReminder +# Arguments: +# file -- file channel that is readable +# time -- time of reminder +# now -- current time according to Remind daemon +# Returns: +# nothing +# Description: +# Reads a background reminder from daemon and pops up window. +#--------------------------------------------------------------------------- +proc IssueBackgroundReminder { file time now } { + global BgCounter + set msg "" + set line "" + while (1) { + gets $file line + if {$line == "NOTE endreminder"} { + break + } + if {$msg != ""} { + append msg "\n"; + } + append msg $line + } + incr BgCounter + set w .bg$BgCounter + toplevel $w + wm iconname $w "Reminder" + wm title $w "Timed reminder ($time)" + label $w.l -text "Reminder for $time issued at $now" + message $w.msg -width 6i -text $msg + button $w.ok -text "OK" -command "destroy $w" + pack $w.l -side top + pack $w.msg -side top -expand 1 -fill both + pack $w.ok -side top + CenterWindow $w + + # reread status + puts $file "STATUS" + flush $file +} + proc main {} { wm withdraw . puts "\nTkRemind Copyright (c) 1996-1998 by David F. Skoll\n" @@ -1389,12 +1534,7 @@ proc main {} { wm geometry . ${x}x600 update -} - -proc t {} { - catch { destroy .foo } - toplevel .foo - CreateModifyDialog .foo 20 1 + StartBackgroundRemindDaemon } main diff --git a/src/init.c b/src/init.c index 5e229b4c..ccdf5078 100644 --- a/src/init.c +++ b/src/init.c @@ -12,7 +12,7 @@ /***************************************************************/ #include "config.h" -static char const RCSID[] = "$Id: init.c,v 1.7 1998-03-01 20:43:56 dfs Exp $"; +static char const RCSID[] = "$Id: init.c,v 1.8 1998-03-02 19:38:40 dfs Exp $"; #define L_IN_INIT 1 #include @@ -258,9 +258,16 @@ char *argv[]; case 'z': case 'Z': DontFork = 1; - PARSENUM(Daemon, arg); - if (Daemon<5) Daemon=5; - else if (Daemon>60) Daemon=60; + if (*arg == '0') { + PARSENUM(Daemon, arg); + if (Daemon == 0) Daemon = -1; + else if (Daemon < 5) Daemon = 5; + else if (Daemon > 60) Daemon = 60; + } else { + PARSENUM(Daemon, arg); + if (Daemon<5) Daemon=5; + else if (Daemon>60) Daemon=60; + } break; case 'a': diff --git a/src/queue.c b/src/queue.c index da5d0095..c9255116 100644 --- a/src/queue.c +++ b/src/queue.c @@ -10,7 +10,7 @@ /***************************************************************/ #include "config.h" -static char const RCSID[] = "$Id: queue.c,v 1.4 1998-02-10 03:15:54 dfs Exp $"; +static char const RCSID[] = "$Id: queue.c,v 1.5 1998-03-02 19:38:40 dfs Exp $"; /* We only want object code generated if we have queued reminders */ #ifdef HAVE_QUEUED @@ -20,6 +20,10 @@ static char const RCSID[] = "$Id: queue.c,v 1.4 1998-02-10 03:15:54 dfs Exp $"; #include #include +#ifdef HAVE_SYS_TIME_H +#include +#endif + #ifdef HAVE_STDLIB_H #include #endif @@ -67,6 +71,8 @@ PRIVATE void CheckInitialFile ARGS ((void)); PRIVATE int CalculateNextTime ARGS ((QueuedRem *q)); PRIVATE QueuedRem *FindNextReminder ARGS ((void)); PRIVATE int CalculateNextTimeUsingSched ARGS ((QueuedRem *q)); +PRIVATE void DaemonWait ARGS ((unsigned int sleeptime)); +PRIVATE void reread ARGS((void)); /***************************************************************/ /* */ @@ -154,7 +160,7 @@ void HandleQueuedReminders() } /* If we're a daemon, get the mod time of initial file */ - if (Daemon) { + if (Daemon > 0) { if (stat(InitialFile, &StatBuf)) { fprintf(ErrFp, "Cannot stat %s - not running as daemon!\n", InitialFile); @@ -183,35 +189,60 @@ void HandleQueuedReminders() /* 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 + if (Daemon && !q) { + if (Daemon < 0) { + /* Sleep until midnight */ + TimeToSleep = (long) 1440*60L - SystemTime(0); + } else { + 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; + if (Daemon > 0 && SleepTime > 60*Daemon) SleepTime = 60*Daemon; - sleep(SleepTime); + if (Daemon >= 0) { + sleep(SleepTime); + } else { + DaemonWait(SleepTime); + } - if (Daemon && SleepTime) CheckInitialFile(); + if (Daemon> 0 && SleepTime) CheckInitialFile(); - if (Daemon && !q) - TimeToSleep = (long) 60*Daemon; - else + if (Daemon && !q) { + if (Daemon < 0) { + /* Sleep until midnight */ + TimeToSleep = (long) 1440*60L - SystemTime(0); + } else { + 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; + if (Daemon < 0) { + printf("NOTE reminder %s ", + SimpleTime(q->tt.ttime)); + printf("%s\n", SimpleTime(SystemTime(0)/60)); + } #ifdef OS2_POPUP (void) TriggerReminder(&p, &trig, &q->tt, JulianToday, 1); #else (void) TriggerReminder(&p, &trig, &q->tt, JulianToday); #endif + if (Daemon < 0) { + printf("NOTE endreminder\n"); + } fflush(stdout); /* Calculate the next trigger time */ @@ -349,8 +380,9 @@ static void CheckInitialFile() if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime; if (tim != FileModTime || - RealToday != SystemDate(&y, &m, &d)) - execvp(ArgV[0], ArgV); + RealToday != SystemDate(&y, &m, &d)) { + reread(); + } } /***************************************************************/ @@ -415,4 +447,92 @@ QueuedRem *q; } } +/***************************************************************/ +/* */ +/* DaemonWait */ +/* */ +/* Sleep or read command from stdin in "daemon -1" mode */ +/* */ +/***************************************************************/ +#ifdef HAVE_PROTOS +PRIVATE void DaemonWait(unsigned int sleeptime) +#else +static DaemonWait(sleeptime) +unsigned int sleeptime +#endif +{ + fd_set readSet; + struct timeval timeout; + int retval; + int y, m, d; + char cmdLine[256]; + + FD_ZERO(&readSet); + FD_SET(0, &readSet); + timeout.tv_sec = sleeptime; + timeout.tv_usec = 0; + retval = select(1, &readSet, NULL, NULL, &timeout); + + /* If date has rolled around, restart */ + if (RealToday != SystemDate(&y, &m, &d)) { + printf("NOTE reread\n"); + fflush(stdout); + reread(); + } + + /* If nothing readable or interrupted system call, return */ + if (retval <= 0) return; + + /* If stdin not readable, return */ + if (!FD_ISSET(0, &readSet)) return; + + /* If EOF on stdin, exit */ + if (feof(stdin)) { + exit(0); + } + + /* Read a line from stdin and interpret it */ + if (!fgets(cmdLine, sizeof(cmdLine), stdin)) { + exit(0); + } + + if (!strcmp(cmdLine, "EXIT\n")) { + exit(0); + } else if (!strcmp(cmdLine, "STATUS\n")) { + int nqueued = 0; + QueuedRem *q = QueueHead; + while(q) { + if (q->tt.nexttime != NO_TIME) { + nqueued++; + } + q = q->next; + } + printf("NOTE queued %d\n", nqueued); + fflush(stdout); + } else if (!strcmp(cmdLine, "REREAD\n")) { + printf("NOTE reread\n"); + fflush(stdout); + reread(); + } else { + printf("ERR Invalid daemon command: %s", cmdLine); + fflush(stdout); + } +} + +/***************************************************************/ +/* */ +/* reread */ +/* */ +/* Restarts Remind if date rolls over or REREAD cmd received */ +/* */ +/***************************************************************/ +#ifdef HAVE_PROTOS +PRIVATE void reread(void) +#else +static reread() +#endif +{ + execvp(ArgV[0], ArgV); +} + #endif /* HAVE_QUEUED from way at the top */