#include #include "fido.h" #include "fidomem.h" #include "proto.h" /* Scheduler for Fido, etc. Various scheduling and support routines. These use the MSDOS time and date, and assumes a continuous seven day schedule. Resolution is one minute. til_sched(tag,m,dsp) Returns the index of the soonest event within M minutes; -1 of none within the window, or -2 if no such event exists. * Tags A - W are FidoNet events. * Tag X is ERRORLEVEL. * Tag Y is P)age. * Tag Z is FileRequest. * Tag ! is Idle. * OPTional and CONTinuous events return as -1, until til_sched is called during the event itself, ie. 0 minutes til runtime. This prevents OPT events from preempting other events; they are, after all, optional. * Completed events return -1. * TaskIDs must match; events with not-our task ID are considered to not exist, ie. return as -2. * If dsp is true, each valid event encountered is displayed. * If ? is passed as the search tag, then any runnable event A - W is allowed, else the tag must match exactly. * If / is passed as the search tag, then only runnable non-OPT or CONT events as in ? are checked. * If -1 is passed as a time til event, then no action is actually taken; usually used when merely listing events. til_event(e) Return the number of minutes until the specified event should be running, or 0 if it is currently running (or should be). Returns -1 if error. put_sched() Writes the time table out to disk. dsp_event(b,e) Generate a report string on event E in buffer B. markevt(n) Mark event #N as complete. clrevts() Reenable all events. clrrevts() Reenable RUSH events. clrcevts() Reenable CONT events. cont(e) Returns true if the event is CONT. rush(e) Returns true if the event is RUSH. set_cont(e) Mark event e as a CONT event. set_rush(e) Mark event e as a RUSH event. */ /* Find the soonest runnable event within M minutes, and return it's index, or < 0 if none. */ til_sched(tag,m,dsp) char tag; int m; int dsp; { int n,i; FLAG no_events; unsigned next_time; int next_event; char buff[SS]; struct _sched *sc; next_time= MINS_WK; /* oldest possible */ next_event= -1; /* none of them */ no_events= 1; /* none found yet */ for (i= 0; i < SCHEDS; i++) { sc= &fido.sched[i]; /* keep it simple! */ if (! sc-> tag) break; /* NUL == end of table */ n= til_event(i); /* time til this event runs, */ /* Clear the COMPLETE bit if not within this event's window. */ if (n > 0) sc-> bits &= ~SCHED_COMPLETE; if (dsp) { /* if display wanted, */ if (sc-> bits & SCHED_COMPLETE) cprintf(SM+144); /* "complete: */ else if (! n) cprintf(SM+145); /* "now" */ else cprintf(SM+146,n); dsp_event(buff,i); /* display it */ cputs(buff); } if ((tag == '?') || (tag == '/')) { /* if ? or / specified */ if (sc-> tag == 'Y') continue; /* any runnable */ if (sc-> tag == 'Z') continue; /* any runnable */ } else if (sc-> tag != tag) continue; /* else must be exact match */ /* If this is not for our task ID, then ignore it. */ if (sc-> taskid && (sc-> taskid != taskid)) continue; /* only our task ID */ /* Flag that we at least found an event. */ no_events= 0; /* 0 == event found */ /* If there is a switch specified for this event, make sure it is on, otherwise ignore this event. */ if (sc-> swtch) { /* if a switch specified, */ if (! istoggle(sc-> swtch - 1)) continue; /* it must be on */ } /* If we are passed -1, we're only listing events; don't check any further for a runnable one. */ if (m < 0) continue; /* do nothing else */ /* If we are looking for hard events only, ignore all CONT and OPT events. */ if ((tag == '/') && (sc-> bits & (SCHED_OPTIONAL | SCHED_CNT))) continue; /* If the event is runnable NOW (ie. time til event is 0) check if it has already been run. If so, ignore it. (ie. 60 min. ERRORLEVELs). If not, stop looking; run it immediately. */ if (n == 0) { /* runnable NOW */ if (sc-> bits & SCHED_COMPLETE) continue; next_event= i; /* this is soonest */ next_time= n; /* so far, */ break; /* stop looking */ /* If this is the soonest event we found so far, remember it. We don't remember CONT or OPT events until they are runnable NOW; they are, after all, "optional", we don't want to shorten callers time limits etc. */ } else if (n < next_time) { /* soonest so far */ if (sc-> bits & (SCHED_OPTIONAL | SCHED_CNT)) continue; next_event= i; /* this is soonest */ next_time= n; /* so far, */ } /* Since this event is no longer current, clear it's completion bit. */ /* sc-> bits &= ~SCHED_COMPLETE; */ /* clear it */ } if (dsp && no_events) cprintf(SM+147); /* If we found one within the desired time, return it; returns -1 if not within the specified window, or -2 if there is no such event. */ if (next_time <= m) return(next_event); /* one we found, */ else if (no_events) return(-2); /* or no such event, */ else return(-1); /* or not within window */ } /* Generate a report on event E. */ void dsp_event(b,e) char *b; int e; { char c; char buff[SS]; /* complete: 1234 Min: Cont Rush Opt *Errorlevel 255, Sun 23:59 1440 min, ID=1, Trig=7(Once) */ *b= NUL; if (fido.sched[e].bits & SCHED_OPTIONAL) strcat(b,"Opt "); else strcat(b," "); if (fido.sched[e].bits & SCHED_CNT) strcat(b,"Cont "); else if (fido.sched[e].bits & SCHED_RUSH) strcat(b,"Rush "); else strcat(b," "); b += strlen(b); /* point to the end */ if (e == fido.event) strcat(b,"-"); /* is currently running */ else strcat(b," "); /* else strcat(b,(e == fido.event ? "*" : " ")); */ /* or last run */ b += strlen(b); switch (fido.sched[e].tag) { case 'Z': sprintf(buff,0,"FileRequest, "); break; case 'Y': sprintf(buff,0,"Page, "); break; case 'X': sprintf(buff,0,"ErrorLevel %d,",fido.sched[e].result); break; case '!': sprintf(buff,0,"Idle,"); break; default: sprintf(buff, 0,"FidoNet \"%c\",",fido.sched[e].tag); break; } while (strlen(buff) < sizeof("Errorlevel 255,")) strcat(buff," "); strcat(b,buff); /* pad it out */ b += strlen(b); sprintf(b,0," %s %02d:%02d %4d min", dayname[fido.sched[e].daywk], /* daywk */ fido.sched[e].hr, /* hour, */ fido.sched[e].min, /* min */ fido.sched[e].len); /* how long */ b += strlen(b); /* show task ID */ sprintf(b,0,(fido.sched[e].taskid ? ", ID=%d," : " "),fido.sched[e].taskid); c= fido.sched[e].swtch; if (c) { /* if a switch set, */ b += strlen(b); sprintf(b,SM+148,c); /* "T=%d" switch status */ switch (istoggle(c - 1)) { case 1: strcat(b,string(SM+1)); break; /* ON */ case 0: strcat(b,string(SM+2)); break; /* OFF */ case -1: strcat(b,string(SM+3)); break; /* ONCE */ } strcat(b,")"); } strcat(b,"\r\n"); } /* Mark this event as completed */ void markevt(n) unsigned n; { if (n < SCHEDS) { fido.sched[n].bits |= SCHED_COMPLETE; n= fido.sched[n].swtch; /* (save typing) */ if (n--) { /* if a switch set, */ if (istoggle(n) < 0) /* and its a oneshot */ stoggle(n,0); /* turn it off */ } } } /* Clear all events to reenable them. */ void clrevts() { int i; for (i= 0; i < SCHEDS; i++) { if (! fido.sched[i].tag) break; /* end of table */ clrevt(i); } } /* Clear RUSH events to reenable them. */ void clrrevts() { int i; for (i= 0; i < SCHEDS; i++) { if (! fido.sched[i].tag) break; /* end of table */ if (fido.sched[i].bits & SCHED_RUSH) clrevt(i); } } /* Clear CONT events to reenable them. */ void clrcevts() { int i; for (i= 0; i < SCHEDS; i++) { if (! fido.sched[i].tag) break; /* end of table */ if (fido.sched[i].bits & SCHED_CNT) clrevt(i); } } /* Reenable this event. */ void clrevt(e) unsigned e; { if (e < SCHEDS) fido.sched[e].bits &= ~SCHED_COMPLETE; } /* Return true if this is a CONTinuous event. */ int cont(e) unsigned e; { return(e > SCHEDS ? 0 : fido.sched[e].bits & SCHED_CNT); } /* Return true if this is a RUSH event. */ int rush(n) unsigned n; { if (n < SCHEDS) return(fido.sched[n].bits & SCHED_RUSH); return(0); } /* Set the CONT bit on this event. */ void set_cont(e) int e; { if (e < SCHEDS) fido.sched[e].bits |= SCHED_CNT; } /* Set the RUSH bit on this event. */ void set_rush(e) int e; { if (e < SCHEDS) fido.sched[e].bits |= SCHED_RUSH; } /* Return the number of minutes until this event can be run, or 0 if it should be running now. */ int til_event(n) int n; { char daywk,d,h,m; int now,start,end; if (n >= SCHEDS) return(-1); /* out of range */ get_time(&d,&h,&m); /* get current time, */ now= lt(d,h,m); /* make mins since Sun 00:00 */ daywk= fido.sched[n].daywk; /* convert event day "ALL" */ if (daywk > 6) daywk= d; /* into "today" */ start= lt(daywk,fido.sched[n].hr,fido.sched[n].min); /* when it starts */ end= start + fido.sched[n].len; /* when it ends */ if ((now >= start) && (now < end)) /* should be running now */ return(0); /* zero mins until start ... */ start -= now; /* just time until it starts */ if (start < 0) start += MINS_WK; /* modulo one week */ if (fido.sched[n].daywk > 6) /* if day == ALL */ start %= MINS_DAY; /* 24 * 60 or less, no? */ return(start); } /* Convert the time elements dayinweek, hour, minute to an integer minutes since Sun. 00:00. */ static lt(d,h,m) char d,h,m; { return((d * MINS_DAY) + (h * MINS_HR) + m); } /* Get the time of day, hours & minutes. Make sure we dont catch in changing. */ static get_time(d,h,m) char *d,*h,*m; { char dt,ht,mt; int n; for (n= 0; n < 10; n++) { *d= gtod3(3); *h= gtod3(4); *m= gtod3(5); dt= gtod3(3); ht= gtod3(4); mt= gtod3(5); if ((*d == dt) && (*h == ht) && (*m == mt)) return; } clprintf(SM+114); /* clock keeps changing? */ }