#include <\fido\fido.h> /* Fido v12's structures */ /* Generate a LASTUSR.BBS file by pulling out the correct record number from CALLER.SYS. Tom Jennings 15 Feb 90 (k) All rights reversed */ /* Version 11 callers record (modified). */ #define OLDMAXLREAD 10 struct _usr { char name[36]; /* users ASCII name, */ char city[36]; /* city and state, */ /* This structure takes exactly 40 bytes, and replaces the old first date. (Which was luckily int[20] by mistake!) */ struct { int area; /* message area */ int msg; /* last msg read */ } lastmsg[OLDMAXLREAD]; char pwd[16]; /* what else, */ int times; /* # times called, */ int help; /* last help setting, */ int tabs; /* 1 == expand tabs, */ int nulls; /* number of nulls after CR, */ int msg; /* last selected message area, */ int more; /* last MORE setting, */ int priv; /* user privelege level, */ char ldate[20]; /* last time called, */ int time; /* total time on system in 1 day, */ unsigned bits; /* various bit flags, */ unsigned upld; /* total K byte uploaded, */ unsigned dnld; /* total K bytes downloaded, */ unsigned dnldl; /* download, for limiting, */ int files; /* last selected file area, */ char width; /* screen width, */ char len; /* screen length, */ int credit; /* credit, in cents, */ int debit; /* debit, in cents, */ /* These are NOT part of the Fido 11 caller record; they were added simply to provide the extra info needed for various utilities. */ int next_event; /* time til next event (0 - 1440 mins) or -1 */ unsigned baud; /* callers last baud rate */ unsigned extra[16]; /* oh, something for later */ }; struct _fido fido; /* v12 FIDO.SYS structure */ struct _usr user; /* v11 USER.BBS record structure */ struct _clr caller; /* v12 CALLER.SYS record structure */ char taskid; /* program taskID */ int _stack = 4000; main(argc,argv) int argc; char **argv; { int f,i,n; char *cp,buff[80],swbuff[80]; long p; printf("Generating Fido/FidoNet version 11 \"LASTUSER.BBS\"\r\n"); printf("Tom Jennings 18 Feb 90, (k) all rites reversed\r\n"); allmem(); /* remove these lines */ fastfile(2); /* remove these lines */ while (--argc) { cpyarg(buff,*++argv); /* filename? */ strip_switch(swbuff,*argv); /* the switches, */ cp= swbuff; while (*cp) { switch (*cp) { case 'I': taskid= atoi(buff); cprintf(" * TaskID: %d\r\n",taskid); break; default: printf("\07\"/%c\" doesn't mean anything\r\n",*cp); break; } ++cp; } } f= open("fido.sys",0); /* read FIDO.SYS */ if (f == -1) { printf("Can't find \"FIDO.SYS\"!\r\n"); exit(1); } read(f,&fido,sizeof(struct _fido)); /* too lazy to error check */ close(f); if (fido.fido_version != FIDOVER) { printf("\"FIDO.SYS\" version doesn't match\r\n"); exit(1); } f= open("caller.sys",0); /* then read CALLER.SYS */ if (f == -1) { printf("Can't find \"CALLER.SYS\"!\r\n"); exit(1); } /* now yank the right record */ p= fido.caller; /* explicit arithmetic */ p *= sizeof(struct _clr); /* avoid lattice 2.15 bug */ lseek(f,p,0); read(f,&caller,sizeof(struct _clr)); /* too lazy to error check */ close(f); for (cp= (char *)&user, f= sizeof(struct _usr); f--;) *cp++= 0; strcpy(user.name,caller.name); /* copy some fields as is */ strcpy(user.city,caller.city); strcpy(user.pwd,caller.pwd); strcpy(user.ldate,caller.date); for (f= 0; f < OLDMAXLREAD; f++) { /* last read msg stuff */ if (caller.lastmsg[f].area != 0) { user.lastmsg[f].area= caller.lastmsg[f].area + 1; user.lastmsg[f].msg= caller.lastmsg[f].msg; } } switch (uval(22,7)) { /* translate priv */ case 0: user.priv= -1; break; /* TWIT */ case 2: user.priv= 2; break; /* NORMAL */ case 3: user.priv= 4; break; /* PRIVEL */ case 4: user.priv= 6; break; /* EXTRA */ case 7: user.priv= 10; break; /* SYSOP */ case 1: default: user.priv= 0; break; /* DISGRACE */ } switch (uval(2,3)) { /* translate help */ case 0: user.help= 2; break; case 1: user.help= 4; break; case 2: default: user.help= 6; break; } user.width= uval(8,127); user.len= uval(15,127); user.nulls= uval(4,15); user.more= uval(1L,1); user.tabs= uval(1,1); user.msg= caller.msg; user.files= caller.files; user.time= caller.time; user.times= caller.time; user.dnld= caller.dnld; user.dnldl= caller.dnldl; user.upld= caller.upld; user.credit= caller.credit; user.debit= caller.debit; /* Now fill in the extra, non-fido-11 stuff. */ user.next_event= til_sched(); /* time til next event */ user.baud= caller.baud; /* last-used baud rate */ f= creat("lastuser.bbs",1); /* create LASTUSR.BBS */ if (f == -1) { cprintf("Can't create \"LASTUSER.BBS\"!\r\n"); exit(1); } write(f,&user,sizeof(struct _usr)); close(f); exit(0); } /* til_sched(); Returns the number of minutes until the soonest runnable event, or -1 if none. OPTional 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. */ til_sched() { int n,i; unsigned next_time; int next_event; struct _sched *sc; next_time= MINS_WK; /* oldest possible */ next_event= -1; /* none of them */ for (i= 0; i < SCHEDS; i++) { sc= &fido.sched[i]; /* keep it simple! */ if (! sc-> tag) break; /* NUL == end of table */ if (sc-> tag == 'Y') continue; /* ignore P)age */ if (sc-> tag == 'Z') continue; /* ignore F)ilerequest */ /* If this is not for our task ID, then ignore it. */ if (sc-> taskid && (sc-> taskid != taskid)) continue; /* only our task ID */ /* If there is a switch specified for this event, make sure it is on, otherwise ignore this event. */ if (sc-> swtch) /* if a switch is specified, */ if (! istoggle(sc-> swtch - 1)) continue; /* it must be on */ /* OK, it's runnable. Get the time til this event runs. */ n= til_event(i); /* time til this event runs, */ /* If we are in the middle of this events window, (time til event == 0) see if it has already run (SCHED_COMPLETE); if so, ignore it. */ if (n == 0) { /* if its runnable NOW, */ if (sc-> bits & SCHED_COMPLETE) continue; next_event= i; next_time= n; /* not run yet */ } /* Remember the next-soonest event, so we can return it when we terminate the loop. OPTIONAL events are not checked, since are only interested in them when their time comes up. */ if ((n < next_time) && !(sc-> bits & SCHED_OPTIONAL)) { next_event= i; /* this is soonest */ next_time= n; /* so far, */ } /* If the soonest is in "zero minutes" (ie now!) then there's no sense in looking any further. */ if (! next_time) break; } /* If we found one within the desired time, return it, else return -1. */ if (next_event != -1) return(next_time); /* found one */ else return(-1); /* else we didnt */ } /* Return the number of minutes until this event can be run, or 0 if it should be running now. */ 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. */ 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. */ 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; } cprintf("Clock keeps changing? (get_time)\r\n"); } /* Return toggle #N. */ istoggle(n) int n; { n= 1 << n; /* it's easier to type */ if (fido.oneshots & n) return(-1); /* oneshot set, (ONCE) */ return((fido.switches & n) ? 1 : 0); /* switch (ON) or (OFF) */ } /* Strip any switches from the input string, put into the output array. */ strip_switch(out,in) char *out; char *in; { while (*in && (*in != '/')) /* skip to end of string */ ++in; /* or first switch, */ while (*in && (*in == '/')) { /* copy switch args while */ ++in; *out++ = toupper(*in); /* stripping switch chars, */ ++in; } *out= '\0'; /* terminate it, */ } /* Copy the string to the destination array, stopping if we find one of our delimiters or switches. */ cpyarg(to,from) char *to; char *from; { while ((*from != ' ') && (*from != '/') && *from) *to++= *from++; *to= '\0'; } /* Return the value from the caller bit record. Since there is no equate or other sensible system for the resolution of 4 used in CLR_WID, we hard code the value here, since its pretty much hardcoded anyways. */ uval(shift,mask) int shift,mask; { int n; n= (caller.stuff >> shift) & mask; return(n); } /* Set a field in the caller bit record. */ setuval(val,mask,shift) int val,mask,shift; { long n; n= mask; n <<= shift; /* we NEED long arith */ caller.stuff &= ~n; /* remove old value */ n= val & mask; n <<= shift; /* set it THEN shift it */ caller.stuff |= n; /* add in new value */ }