/*--------------------------------------------------------------------------*/ /* */ /* */ /* ------------ Bit-Bucket Software, Co. */ /* \ 10001101 / Writers and Distributors of */ /* \ 011110 / Freely Available Software. */ /* \ 1011 / */ /* ------ */ /* */ /* (C) Copyright 1987-96, Bit Bucket Software Co. */ /* */ /* */ /* */ /* BinkleyTerm File Request Processor */ /* */ /* */ /* For complete details of the licensing restrictions, please refer */ /* to the License agreement, which is published in its entirety in */ /* the MAKEFILE and BT.C, and also contained in the file LICENSE.260. */ /* */ /* USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE */ /* BINKLEYTERM LICENSING AGREEMENT. IF YOU DO NOT FIND THE TEXT OF */ /* THIS AGREEMENT IN ANY OF THE AFOREMENTIONED FILES, OR IF YOU DO */ /* NOT HAVE THESE FILES, YOU SHOULD IMMEDIATELY CONTACT BIT BUCKET */ /* SOFTWARE CO. AT ONE OF THE ADDRESSES LISTED BELOW. IN NO EVENT */ /* SHOULD YOU PROCEED TO USE THIS FILE WITHOUT HAVING ACCEPTED THE */ /* TERMS OF THE BINKLEYTERM LICENSING AGREEMENT, OR SUCH OTHER */ /* AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO. */ /* */ /* */ /* You can contact Bit Bucket Software Co. at any one of the following */ /* addresses: */ /* */ /* Bit Bucket Software Co. FidoNet 1:104/501, 1:343/491 */ /* P.O. Box 460398 AlterNet 7:42/1491 */ /* Aurora, CO 80046 BBS-Net 86:2030/1 */ /* Internet f491.n343.z1.fidonet.org */ /* */ /* Please feel free to contact us at any time to share your comments about */ /* our software and/or licensing policies. */ /* */ /* */ /* This module is based largely on a similar module in OPUS-CBCS V1.03b. */ /* The original work is (C) Copyright 1987, Wynn Wagner III. The original */ /* author has graciously allowed us to use his code in this work. */ /* */ /*--------------------------------------------------------------------------*/ /* Include this file before any other includes or defines! */ #include "includes.h" #define AREA_ID 0x54414441L /* "ADAT" */ #define MAX_ALEN 10 /* Max length of usr.msg[] and usr.files[] */ #define MAX_OVR 16 /* Maximum # of override privs per area */ #define NUM_MENU 256 /* Max. # of options in a menu file */ #define MAXCLASS 12 /* number of possible priv levels */ /* New Max 2.xx format for MAXFILES.IDX. The file is simply an array of * * these structures. */ struct _maxfile { byte name[12]; word areaofs; word fileofs; }; struct _override { signed short priv; /* Override priv level */ unsigned long lock; /* Override lock setting */ byte ch; /* First letter of menu option to override */ byte fill; /* Reserved by Maximus */ }; struct _area { long id; /* Unique identifier for AREA.DAT structure.* * Should be AREA_ID, above. */ word struct_len; /* Length of _area structure -- this needs * * only to be read from the first record in * * an area data file, since it can be * * assumed to remain the same throughout the* * entire file. This is GUARANTEED to be at* * offset four for this and all future * * versions of this structure. */ word areano; /* OBSOLETE. Two-byte integer representation* * of the area name. Use area.name instead. */ byte name[40]; /* String format of area's name. USE THIS! */ /************************************************************************/ /** Message Area Information **/ /************************************************************************/ word type; /* Message base type. MSGTYPE_SDM = *.MSG. * * MSGTYPE_SQUISH = SquishMail. (Constants * * are in MSGAPI.H) */ byte msgpath[80]; /* Path to messages */ byte msgname[40]; /* The 'tag' of area, used in ECHOTOSS.LOG */ byte msginfo[80]; /* The DIR.BBS-like desc for msg section */ byte msgbar[80]; /* Barricade file for message area */ byte origin[62]; /* The ORIGIN line for this area */ short msgpriv; /* This is the priv required to access the * * msg section of this area. */ byte fill0; /* The lock for the message area (obsolete) */ byte fill1; short origin_aka; /* The AKA number to use on the origin line.* * See the normal SysOp documentation on * * the "Origin" statement, for info on how * * this number is used. */ /************************************************************************/ /** File Area Information **/ /************************************************************************/ byte filepath[80]; /* Path for downloads */ byte uppath[80]; /* Path for uploads */ byte filebar[80]; /* Barricade file for file areas */ byte filesbbs[80]; /* Path to FILES.BBS-like catalog for area */ byte fileinfo[80]; /* The DIR.BBS-like desc for file section */ short filepriv; /* The priv required to access the file * * section of this area. */ byte fill15; /* The locks for the file area (obsolete) */ byte fill2; /************************************************************************/ /** Miscellaneous Information **/ /************************************************************************/ byte msgmenuname[13]; /* Alternate *.MNU name to use for msg.area */ byte filemenuname[13]; /* Alternate *.MNU name to use for file area */ word attrib[MAXCLASS]; /* This is an array of attributes for the * * msg/file areas. These are dependant on PRIV * * level. Once you have the CLASS number for a * * particular user (via Find_Class_Number()),you* * can find the attributes for that particular * * priv level like this: "area.attrib[class]" * * ...which will get you the attribute for that * * priv level. */ /************************************************************************/ /** Stuff hacked on later **/ /************************************************************************/ struct _override movr[MAX_OVR]; /* Override privs for msg/file areas */ struct _override fovr[MAX_OVR]; unsigned long msglock; /* 32-bit locks for message areas */ unsigned long filelock; /* 32-bit locks for file areas */ word killbyage; /* MAXREN: max # of days to keep msgs in area */ /* (use 0 for no deletion by age) */ word killbynum; /* MAXREN: max # of msgs to keep in area (use 0 */ /* for no deletion by #msgs.) */ }; static char *their_pwd; /* Password in REQ file */ static char required_pwd[10]; /* Password in OK file */ static int xfer_seconds; int prep_match (char *, char *); int match (char *, char *); void run_prog (char *); int check_password (void); int freq_abort (long, int (*)(long)); int what_event (int); int what_event_sub (int, int, int, int, int, int); int prep_match (char *template, char *buffer) { register int i, delim; register char *sptr; int start; (void) memset (buffer, 0, 11); i = (int) strlen (template); sptr = template; for (start = i = 0; sptr[i]; i++) if ((sptr[i] == '\\') || (sptr[i] == ':')) start = i + 1; if (start) sptr += start; delim = 8; /* last column for ? */ (void) strupr (sptr); for (i = 0; *sptr && i < 12; sptr++) switch (*sptr) { case '.': if (i > 8) return (-1); while (i < 8) { buffer[i++] = ' '; } buffer[i++] = *sptr; delim = 12; break; case '*': while (i < delim) { buffer[i++] = '?'; } break; default: buffer[i++] = *sptr; break; } /* switch */ while (i < 12) { if (i == 8) buffer[i++] = '.'; else buffer[i++] = ' '; } buffer[i] = '\0'; return 0; } int match (char *s1, char *s2) { register char *i, *j; i = s1; j = s2; while (*i) { if ((*j != '?') && (*i != *j)) { return ((int) (*i - *j)); } i++; j++; } return 0; } /*--------------------------------------------------------------------------*/ /* Process file requests from the remote system. The filespec requested is */ /* turned into a local filespec if possible, then transferred via the */ /* caller-supplied routine. */ /*--------------------------------------------------------------------------*/ int n_frproc (char *request, int nfiles, int (*callback) (char *), int (*calltime) (long)) { register int i; register int j = 0; static char s[80]; static char s1[80]; static char s2[80]; char *p; FILE *approved; struct FILEINFO dta = {0}; struct stat st; char *sptr; char *after_pwd; long updreq = 0L; char updtype = 0; int saved_nfiles; char our_wildcard[15]; char their_wildcard[15]; int mfunc; int magic_state = 0; int tried_about = 0; int failure_reason = 1; /* 1 = not available */ /* 2 = no update */ /* 3 = bad password */ struct _area area; struct _maxfile filmax; int fmax = 0, fdat = 0, slen = 0; long fmaxpos = 0L; unsigned int fmaxstep = 30; long fmaxmax = 0L; long fmaxsiz = (long) sizeof (struct _maxfile); if (freq_accum.time == 0L) freq_accum.time = (long) time (NULL); approved = NULL; their_pwd = NULL; after_pwd = NULL; (void) strcpy (s1, request); /*----------------------------------------------------------------------*/ /* Fix up the file name */ /*----------------------------------------------------------------------*/ for (i = 0; request[i]; i++) { if (request[i] <= ' ') { request[i++] = '\0'; j = i; break; } if ((request[i] == ':') || (request[i] == '\\')) { request[0] = '\0'; j = 0; break; } } if (j) { /* If we have a '!', find the end of the password, point j past it, then truncate and fold if necessary. This leaves j properly aligned for other fields. */ if (request[j] == '!') { their_pwd = request + (++j); for (; request[j]; j++) { if (request[j] <= ' ') { request[j++] = '\0'; break; } } if (strlen (their_pwd) > 6) their_pwd[6] = '\0'; (void) fancy_str (their_pwd); } /* Test for update/backdate request */ if (request[j] == '+' || request[j] == '-') { updtype = request[j++]; #ifdef ANSI_TIME_T updreq = atol (&request[j]) + ANSI_TIME_T_DELTA; #else updreq = atol (&request[j]); #endif } } if (!request[0]) /* Still any filename? */ return (nfiles); /* If not, return df=0. */ if (freq_abort (0L, calltime)) /* Any reason to abort? */ return (-2); /* If so, return error. */ /*----------------------------------------------------------------------*/ /* Initialization(s) */ /*----------------------------------------------------------------------*/ i = 0; sptr = NULL; (void) strupr (request); status_line ("*%s %s (%s)", (updreq != 0L) ? MSG_TXT (M_UPDATE) : MSG_TXT (M_FILE), MSG_TXT (M_REQUEST), request); saved_nfiles = nfiles; /*----------------------------------------------------------------------*/ /* Reserved words */ /*----------------------------------------------------------------------*/ if (!strcmp (request, "FILES")) { if (CURRENT.rq_FILES) (void) strcpy (s, CURRENT.rq_FILES); else { s[0] = '\0'; sptr = MSG_TXT (M_NO_AVAIL); } goto avail; } else if (!strcmp (request, "ABOUT")) { s[0] = '\0'; goto avail; } (void) prep_match (request, their_wildcard); /*----------------------------------------------------------------------*/ /* See if the file is approved for transmission */ /*----------------------------------------------------------------------*/ if ((approved = share_fopen (CURRENT.rq_OKFile, read_ascii, DENY_WRITE)) == NULL) { (void) got_error (MSG_TXT (M_OPEN_MSG), CURRENT.rq_OKFile); goto err; } while (!feof (approved)) { /* If we were magic, set flag to cause exit if we don't do it again */ if (magic_state) magic_state = 1; /* 1 means done if no @ */ s[0] = required_pwd[0] = '\0'; (void) fgets (s, 78, approved); for (i = 0; s[i]; i++) if (s[i] == 0x09) s[i] = ' '; else if (s[i] < ' ') s[i] = '\0'; if (!s[0] || s[0] == ';') continue; /*--------------------------------------------------------------*/ /* Check for transaction-level password */ /*--------------------------------------------------------------*/ for (i = 0; s[i]; i++) { if (s[i] == ' ') { s[i] = '\0'; if (s[i + 1] == '!') { (void) strncpy (required_pwd, s + i + 2, 8); if (strlen (required_pwd) > 6) required_pwd[6] = '\0'; after_pwd = skip_blanks (s + i + 1); while (*after_pwd && (!isspace (*after_pwd))) ++after_pwd; if (*after_pwd) ++after_pwd; for (i = 0; required_pwd[i]; i++) if (required_pwd[i] <= ' ') required_pwd[i] = '\0'; break; } else { after_pwd = skip_blanks (s + i + 1); break; } } else if (s[i] < ' ') s[i] = '\0'; } if (!s[0]) continue; if (strchr ("@+$", s[0]) != NULL) { /* Magic name or function */ if ((s[0] != '>') && stricmp (&s[1], request)) continue; /* Name matches, check password */ if (!(check_password ())) { failure_reason = 3; /* Password doesn't match */ continue; /* Go on */ } mfunc = 0; if (s[0] == '$') { (void) sprintf (s2, after_pwd, remote_addr.Net, remote_addr.Node, remote_addr.Point); mfunc = 1; } if (s[0] == '+') { (void) sprintf (s, " %d %d %d %d", remote_addr.Zone, remote_addr.Net, remote_addr.Node, remote_addr.Point); (void) strcpy (s2, s1); (void) strcat (s2, s); mfunc = 2; } if (mfunc) { run_prog (s2); goto check_HLO; } if (s[0] == '@') { (void) strcpy (s, after_pwd); magic_state = 2; /* Will be reset up above */ } } /* * We're past the magic stuff here. So check for whether this is * a new iteration of a magic loop that somehow didn't catch. * If not, then check out the filespec we have on this line. */ if (magic_state == 1) goto check_HLO; j = 1; if (Netmail_Session == 2) SENDBYTE (NUL); /*--------------------------------------------------------------*/ /* Check MAXFILES.IDX */ /*--------------------------------------------------------------*/ if ((s[0] == '*') && (max_areadat != NULL)) { p = s; p++; if ((fmax = share_open (p, O_RDONLY | O_BINARY, DENY_NONE)) == -1) { (void) got_error (MSG_TXT (M_OPEN_MSG), p); fmax = 0; goto err; } if ((fdat = share_open (max_areadat, O_RDONLY | O_BINARY, DENY_NONE)) == -1) { (void) got_error (MSG_TXT (M_OPEN_MSG), max_areadat); (void) close (fmax); fmax = fdat = 0; goto err; } /* Read the first record of the file, to grab the structure-length * * byte. */ (void) read (fdat, &area, sizeof (struct _area)); slen = area.struct_len; (void) stat (p, &st); fmaxmax = st.st_size / fmaxsiz; if (fmaxmax > 5000L) fmaxstep = 60; if (abs (loglevel) == 5) status_line (MSG_TXT (M_MAXFILE_SCANNING), fmaxmax, fmaxstep, p); /* original while (!eof (fmax)) */ for (;;) { if (fmaxstep) { fmaxpos += fmaxstep; if (fmaxpos >= fmaxmax) { fmaxpos -= (long) fmaxstep; fmaxstep = 0; } lseek (fmax, fmaxpos * fmaxsiz, SEEK_SET); } /* original (void) read (fmax, &filmax, (unsigned)fmaxsiz); */ /* This should work same as the eof test and be more portable */ if (read (fmax, &filmax, (unsigned) fmaxsiz) != (int) fmaxsiz) break; if (!(--j)) /* If we've looped a bit */ { i = freq_abort (0L, calltime); if (i) /* See if we want to quit */ { (void) close (fmax); (void) close (fdat); fmax = fdat = 0; if (i == 1) /* Yes, why? Carrier? */ goto finished; /* uh-huh -- get out fast */ else { failure_reason = i; /* Not carrier, get reason*/ goto make_RSP; /* Make a .RSP file */ } } j = 10; /* No, reset bounds */ } filmax.fileofs = filmax.areaofs;/* save the offset... :-) */ filmax.name[12] = '\0'; if (prep_match ((char *) filmax.name, our_wildcard) < 0) continue; i = match (our_wildcard, their_wildcard); if (i < 0) continue; else { if (fmaxstep) { fmaxpos -= (long) fmaxstep; fmaxstep = 0; lseek (fmax, fmaxpos * fmaxsiz, SEEK_SET); continue; } else if (i > 0) break; } fmaxstep = 0; /* File names match, check security now */ lseek (fdat, (long) filmax.fileofs * (long) slen, SEEK_SET); read (fdat, &area, sizeof (struct _area)); if (CURRENT.security < area.filepriv) { failure_reason = 3; /* Security doesn't match */ if (abs (loglevel) == 5) status_line (MSG_TXT (M_MAX_SECURITY_MISMATCH), (int) CURRENT.security, (int) area.filepriv); continue; /* Go on */ } /* Add in the exact name found */ (void) strcpy (s2, (char *) area.filepath); (void) strcat (s2, (char *) filmax.name); /* Now find the "real" file */ if ((i = stat (s2, &st)) != -1) { /* Got full filename, now do file update validation */ if (updtype && !i) { if ((updtype == '+' && (st.st_atime <= (time_t) updreq)) || (updtype == '-' && (st.st_atime >= (time_t) updreq))) { failure_reason = 2; /* No update available */ continue; /* Go on */ } } i = freq_abort (st.st_size, calltime); /* Check file size */ if (i) /* See if we want to quit */ { (void) close (fmax); (void) close (fdat); fmax = fdat = 0; if (i == 1) /* Yes, why? Carrier? */ goto finished; /* uh-huh -- get out fast */ else { failure_reason = i; /* Not carrier, get reason*/ goto make_RSP; /* Make a .RSP file */ } } /* Everything is OK, send the file if we can */ CLEAR_INBOUND (); if ((*callback) (s2)) { ++nfiles; freq_accum.bytes += st.st_size; freq_accum.CumTime += xfer_seconds; ++freq_accum.files; } j = 1; /* Force abort test */ } } /* end of while */ /* close open max files */ if (fmax) (void) close (fmax); if (fdat) (void) close (fdat); } /* end of MAXFILES.IDX check */ else { /*--------------------------------------------------------------*/ /* Check for any other line */ /*--------------------------------------------------------------*/ if (!dfind (&dta, s, 0)) { do { if (!(--j)) /* If we've looped a bit */ { i = freq_abort (0L, calltime); if (i) /* See if we want to quit */ { if (i == 1) /* Yes, why? Carrier? */ goto finished; /* uh-huh -- get out fast */ else { failure_reason = i; /* No, get reason */ goto make_RSP; /* Make a .RSP file */ } } j = 10; /* No, reset bounds */ } if (!magic_state) /* If not "magic", */ { if (prep_match (dta.name, our_wildcard) < 0) continue; if (match (our_wildcard, their_wildcard) != 0) continue; /* File names match, check password now */ if (!check_password ()) { failure_reason = 3; /* Password doesn't match */ continue; /* Go on */ } } /* Good password, get path with wildcard from OKFILE */ (void) strcpy (s2, s); /* Subtract the wild card file name, keep path */ if ((p = strrchr (s2, '\\')) != NULL) *++p = '\0'; else s2[0] = '\0'; /* Then add in the exact name found */ (void) strcat (s2, dta.name); /* Got full filename, now do file update validation */ if (updtype && !stat (s2, &st)) { if ((updtype == '+' && (st.st_atime <= (time_t) updreq)) || (updtype == '-' && (st.st_atime >= (time_t) updreq))) { failure_reason = 2; /* No update available */ continue; /* Go on */ } } i = freq_abort (dta.size, calltime);/* Check file size*/ if (i) /* See if we want to quit */ { if (i == 1) /* Yes, why? Carrier? */ goto finished; /* uh-huh -- get out fast */ else { failure_reason = i; /* Not carrier, get reason*/ goto make_RSP; /* Make a .RSP file */ } } /* Everything is OK, send the file if we can */ CLEAR_INBOUND (); if ((*callback) (s2)) { ++nfiles; freq_accum.bytes += dta.size; freq_accum.CumTime += xfer_seconds; ++freq_accum.files; } j = 1; /* Force abort test */ } while (!dfind (&dta, s, 1)); (void) dfind (&dta, s, 2); } /* if dfind */ else status_line (MSG_TXT (M_OKFILE_ERR), s); /* if not dfind */ } s[0] = '\0'; } /* while not eof(approved) */ if (saved_nfiles != nfiles) failure_reason = 9; make_RSP: s[0] = '\0'; /* Initialize string */ if ((CURRENT.rq_Template != NULL) && (dexists (CURRENT.rq_Template))) { Make_Response (s1, failure_reason); /* Build a response */ (void) strcpy (s, s1); /* Copy it for xmission */ } if ((!s[0]) && (failure_reason > 3)) /* if no .RSP file, */ goto finished; /* give it up */ /*--------------------------------------------------------------------*/ /* File requested not found, send the system ABOUT file. */ /*--------------------------------------------------------------------*/ avail: if (!s[0]) { if (CURRENT.rq_About) (void) strcpy (s, CURRENT.rq_About); else { if (tried_about) { sptr = MSG_TXT (M_NO_ABOUT); goto err; } else { ++tried_about; (void) strcpy (s1, request); failure_reason = 1; /* Didn't find what we wanted */ goto make_RSP; /* Make a .RSP file */ } } } CLEAR_INBOUND (); if ((*callback) (s)) ++nfiles; goto finished; /*--------------------------------------------------------------------*/ /* See if we generated a .QLO file somehow, if so send listed files */ /*--------------------------------------------------------------------*/ check_HLO: CLEAR_INBOUND (); (void) do_FLOfile ("Q", callback); /*--------------------------------------------------------------------*/ /* Maybe the magic request made a conventional .FLO file, try that too*/ /*--------------------------------------------------------------------*/ *ext_flags = 'F'; (void) do_FLOfile (ext_flags, callback); goto finished; /*--------------------------------------------------------------------*/ /* Error return */ /*--------------------------------------------------------------------*/ err: if (sptr) status_line ("!%s %s %s: %s", (updreq != 0L) ? MSG_TXT (M_UPDATE) : MSG_TXT (M_FILE), MSG_TXT (M_REQUEST), &(MSG_TXT (M_ERROR)[1]), sptr); finished: if (approved) (void) fclose (approved); return (nfiles); } void run_prog (char *s) { struct baud_str saved_baud; status_line ("%s '%s'", MSG_TXT (M_EXECUTING), s); if (fullscreen && un_attended) { screen_clear (); } scr_printf (&(MSG_TXT (M_EXECUTING)[1])); scr_printf (s); scr_printf ("\r\n"); vfossil_cursor (1); saved_baud = cur_baud; b_spawn (s); vfossil_cursor (0); if (fullscreen && un_attended) { screen_clear (); sb_dirty (); opening_banner (); mailer_banner (); } (void) set_baud (saved_baud.rate_value, 0); /* Restore baud rate */ } int check_password () { if (required_pwd != NULL && required_pwd[0]) { if (their_pwd == NULL && remote_password == NULL) { status_line (MSG_TXT (M_FREQ_PW_ERR), required_pwd, "(NULL)", "(NULL)" ); return (0); } (void) fancy_str (required_pwd); if ((stricmp (required_pwd, their_pwd)) && (remote_password == NULL || (remote_password != NULL && stricmp (required_pwd, remote_password)))) { status_line (MSG_TXT (M_FREQ_PW_ERR), required_pwd, their_pwd, remote_password ); return (0); } } return (1); } int freq_abort (long file_size, int (*calltime) (long)) { int w_event; int xfer_time; if (!CARRIER) { status_line (MSG_TXT (M_CARRIER_REQUEST_ERR)); return (1); } if ((CURRENT.rq_Limit != 0) && ((freq_accum.files + 1) >= CURRENT.rq_Limit)) { status_line (MSG_TXT (M_FREQ_LIMIT)); return (4); } if ((CURRENT.byte_Limit != 0L) && ((freq_accum.bytes + file_size) > CURRENT.byte_Limit)) { status_line (MSG_TXT (M_BYTE_LIMIT)); return (6); } /* Get file time in seconds for comparison with quota */ if (file_size != 0L) xfer_time = calltime (file_size); else xfer_time = 0; xfer_seconds = xfer_time; if ((CURRENT.time_Limit != 0) && (((long) time (NULL) + xfer_time - freq_accum.time) > CURRENT.time_Limit)) { status_line (MSG_TXT (M_TIME_LIMIT)); return (7); } xfer_time /= 60; /* We want minutes for event calculations */ w_event = what_event (xfer_time); if ((w_event >= 0) && (w_event != cur_event)) { if (e_ptrs[w_event].behavior & MAT_NOREQ) { status_line (MSG_TXT (M_EVENT_OVERRUN)); return (5); } } else if (w_event == -2) { status_line (MSG_TXT (M_EVENT_OVERRUN)); return (5); } return (0); } int what_event (int delta_time) { time_t long_time; struct tm *tm; int now; int tomorrow = 0; int our_time; int w_event; int save_time; /* Get the current time into a structure */ (void) time (&long_time); tm = localtime (&long_time); /* Calculate minutes since midnight */ now = tm->tm_hour * 60 + tm->tm_min; /* Then number of minutes past midnight at end of delta_time */ save_time = our_time = delta_time + now; /* Is the end in Tomorrow? (Sounds like a soap opera, eh?) */ if (1440 < our_time) { tomorrow = 1; /* Remember that we've wrapped */ our_time = 1439; /* Set event end = 23:59 for now */ } /* Test "today," and if we find an event, get the hell out */ w_event = what_event_sub (tm->tm_mon, tm->tm_wday, tm->tm_mday, now, our_time, 0); if (w_event != -1) return w_event; /* * If we need to test tomorrow, figure out all the salient info * on what tomorrow is, and test that. */ if (tomorrow) { long_time += 86400L; /* Any time tomorrow will do. */ tm = localtime (&long_time); w_event = what_event_sub (tm->tm_mon, tm->tm_wday, tm->tm_mday, 0, (save_time - 1440), 1); } return w_event; } int what_event_sub (int cur_mon, int cur_day, int cur_mday, int now, int our_time, int tomorrow) { int i; cur_day = 1 << cur_day; /* Make cur_day a bit mask */ for (i = 0; i < num_events; i++) { /* If this is an event we need to think about (i.e., it started * before the end of the transfer, and ends after "now") ... */ if ((our_time >= e_ptrs[i].minute) && (now <= (e_ptrs[i].minute + e_ptrs[i].length))) { /* And if it's on a day we care about ... */ if ((cur_day & e_ptrs[i].days) && ((!e_ptrs[i].day) || (e_ptrs[i].day == (char) cur_mday)) && ((!e_ptrs[i].month) || (e_ptrs[i].month == (char) cur_mon))) { /* Don't do events that have been exited already unless * the tomorrow flag is set (in which case, no events have * occurred, have they?) */ if (!tomorrow && (e_ptrs[i].last_ran == (char) cur_mday) && (e_ptrs[i].behavior & MAT_SKIP)) continue; /* If the event we are considering does not allow requests, * then this is a bugger we are looking for. Return its index. */ if ((e_ptrs[i].behavior & MAT_NOREQ)) return i; } /* end of if ((cur_day & ... )) */ } /* end of if ( our_time >= ... ) */ } /* end of for ( ... ) */ return -1; }