1*13634Ssam #ifndef lint 2*13634Ssam static char sccsid[] = "@(#)anlwrk.c 5.1 (Berkeley) 07/02/83"; 3*13634Ssam #endif 4*13634Ssam 5*13634Ssam #include "uucp.h" 6*13634Ssam #include <sys/types.h> 7*13634Ssam #include <sys/stat.h> 8*13634Ssam #ifdef NDIR 9*13634Ssam #include "ndir.h" 10*13634Ssam #else 11*13634Ssam #include <dir.h> 12*13634Ssam #endif 13*13634Ssam 14*13634Ssam /* Re-written to be reasonable 15*13634Ssam * Mon Nov 15 17:19:52 EST 1982 16*13634Ssam * Alan S. Watt (ittvax!swatt) 17*13634Ssam * 18*13634Ssam * Tom Truscott (rti!trt): 19*13634Ssam * Priority ordering cleaned up. New 'pcompar' subroutine. 20*13634Ssam * 'stat' removed (speeds things up). 21*13634Ssam * Possible infinite loop in gtwvec defended against. 22*13634Ssam * Feb 23, 1983 23*13634Ssam * 24*13634Ssam * Changes: 25*13634Ssam * 26*13634Ssam * 1) The check for work is much faster; the first filename 27*13634Ssam * that matches the prefix causes a "yes" return. 28*13634Ssam * 29*13634Ssam * 2) The filename is not "stat" ed , so 30*13634Ssam * there is no massive delay while the list of potential 31*13634Ssam * names is built. 32*13634Ssam * 33*13634Ssam * 3) Requesting work for a new system is now detected so 34*13634Ssam * internal variables are re-initialized properly. In 35*13634Ssam * particular, the stream pointer for the current work 36*13634Ssam * file is properly closed so work for a system which 37*13634Ssam * hangs up will not be sent to the next system called. 38*13634Ssam * 39*13634Ssam * Fri Dec 3 09:31:45 EST 1982 40*13634Ssam * 41*13634Ssam * 5) As new work files are requested, a check is made 42*13634Ssam * every TLIMIT seconds (5 minutes at present) to see 43*13634Ssam * if new files have entered the spool area. Since 44*13634Ssam * work file names are now cached up to LLEN, this can 45*13634Ssam * represent a very long transmission time before new 46*13634Ssam * work enters the list to be processed. If people want 47*13634Ssam * to use the "grade" character to specify a higher 48*13634Ssam * priority, the list must be re-built and re-sorted for 49*13634Ssam * higher priority stuff to have an immediate effect. 50*13634Ssam */ 51*13634Ssam 52*13634Ssam 53*13634Ssam #define LLEN 20 54*13634Ssam #define MAXRQST 250 55*13634Ssam #define TLIMIT (5*60L) 56*13634Ssam #define NITEMS(X) (sizeof (X) / sizeof ((X)[0])) 57*13634Ssam 58*13634Ssam /* These are all used only locally 59*13634Ssam */ 60*13634Ssam static int Nfiles = 0; 61*13634Ssam static char Filent[LLEN][NAMESIZE]; 62*13634Ssam 63*13634Ssam /******* 64*13634Ssam * anlwrk(file, wvec) create a vector of command arguments 65*13634Ssam * char *file, **wvec; 66*13634Ssam * 67*13634Ssam * return codes: 68*13634Ssam * 0 - no more work in this file 69*13634Ssam * positive number - number of arguments 70*13634Ssam */ 71*13634Ssam 72*13634Ssam /* LOCAL only */ 73*13634Ssam int 74*13634Ssam anlwrk(file, wvec) 75*13634Ssam register char *file, **wvec; 76*13634Ssam { 77*13634Ssam static char str[MAXRQST]; 78*13634Ssam static FILE *fp = NULL; 79*13634Ssam 80*13634Ssam /* If called with a null string, force a shutdown 81*13634Ssam * of the current work file. 82*13634Ssam * John Levine, ima.247, related change in cntl.c 83*13634Ssam */ 84*13634Ssam if (file[0] == '\0') { 85*13634Ssam if (fp != NULL) 86*13634Ssam fclose (fp); 87*13634Ssam fp = NULL; 88*13634Ssam return(0); 89*13634Ssam } 90*13634Ssam if (fp == NULL) { 91*13634Ssam fp = fopen(subfile(file), "r"); 92*13634Ssam if (fp == NULL) { 93*13634Ssam unlink(subfile(file)); /* Try to zap the thing. rti!trt */ 94*13634Ssam return(0); 95*13634Ssam } 96*13634Ssam } 97*13634Ssam 98*13634Ssam /* This is what deletes the current work file when EOF 99*13634Ssam * is reached. As this is called from gtwvec, which is 100*13634Ssam * in turn called externally, it is not possible to save 101*13634Ssam * "C." files in case of error, except for line errors, 102*13634Ssam * which shuts down the whole system. 103*13634Ssam */ 104*13634Ssam if (fgets(str, MAXRQST, fp) == NULL) { 105*13634Ssam fclose(fp); 106*13634Ssam unlink(subfile(file)); 107*13634Ssam file[0] = '\0'; 108*13634Ssam fp = NULL; 109*13634Ssam return(0); 110*13634Ssam } 111*13634Ssam return(getargs(str, wvec)); 112*13634Ssam } 113*13634Ssam 114*13634Ssam 115*13634Ssam /*** 116*13634Ssam * bldflst - build list of work files for given system 117*13634Ssam * Nfiles, Filent are global 118*13634Ssam * 119*13634Ssam * return value - 1 if work was found, else 0 120*13634Ssam * 121*13634Ssam * Jul 26 19:17 1982 (ittvax!swatt). fixed this obnoxious 122*13634Ssam * routine to NOT read all the way through the damned directory 123*13634Ssam * "stat"'ing every file in sight just to get 10 names!!! 124*13634Ssam * 125*13634Ssam * It still reads through the directory from the beginning until 126*13634Ssam * the list is filled, but this is only once every LLEN names. 127*13634Ssam */ 128*13634Ssam 129*13634Ssam /* LOCAL only */ 130*13634Ssam int 131*13634Ssam bldflst (reqst, dir, pre) 132*13634Ssam char *reqst; 133*13634Ssam register char *dir, *pre; 134*13634Ssam { 135*13634Ssam static DIR *dirp = NULL; 136*13634Ssam register nfound; 137*13634Ssam char filename[NAMESIZE]; /* @@@ NB: this needs new dir stuff */ 138*13634Ssam int plen = strlen (pre); 139*13634Ssam 140*13634Ssam if (dirp == NULL) { 141*13634Ssam if ((dirp = opendir(subdir(dir,pre[0]), "r")) == NULL) 142*13634Ssam return(0); 143*13634Ssam } 144*13634Ssam else 145*13634Ssam rewinddir(dirp); 146*13634Ssam for (nfound = 0, Nfiles = 0; gnamef(dirp, filename);) { 147*13634Ssam /* Check for two systems with the same prefix. 148*13634Ssam * Magic number "5" is 1 for "grade" character plus 149*13634Ssam * 4 for sequence number. The point here is to not 150*13634Ssam * send work for a system which has as a prefix the 151*13634Ssam * name of the system called for. 152*13634Ssam * Special case: prefix "X." does not do this check 153*13634Ssam * so uuxqt can use bldflst. 154*13634Ssam */ 155*13634Ssam if (!prefix(pre, filename) 156*13634Ssam || (plen != 2 && strlen(filename)-plen != 5)) 157*13634Ssam continue; 158*13634Ssam nfound++; 159*13634Ssam if (*reqst == 'c') 160*13634Ssam return (1); 161*13634Ssam entflst(filename); 162*13634Ssam } 163*13634Ssam return (nfound? 1: 0); 164*13634Ssam } 165*13634Ssam 166*13634Ssam /*** 167*13634Ssam * entflst - put new name if list is not full 168*13634Ssam * or new name is less than the MAX 169*13634Ssam * now in the list. 170*13634Ssam * Nfiles, Filent[] are modified. 171*13634Ssam * return value - none 172*13634Ssam * 173*13634Ssam */ 174*13634Ssam 175*13634Ssam /* LOCAL only */ 176*13634Ssam int 177*13634Ssam entflst(file) 178*13634Ssam char *file; 179*13634Ssam { 180*13634Ssam register int i; 181*13634Ssam register char *p; 182*13634Ssam 183*13634Ssam /* If there is room in the table, just add it. */ 184*13634Ssam if (Nfiles < LLEN) { 185*13634Ssam strcpy(Filent[Nfiles++], file); 186*13634Ssam return; 187*13634Ssam } 188*13634Ssam 189*13634Ssam /* Find lowest priority file in table */ 190*13634Ssam p = Filent[0]; 191*13634Ssam for (i = 1; i < Nfiles; i++) 192*13634Ssam if (pcompar(Filent[i], p) < 0) 193*13634Ssam p = Filent[i]; 194*13634Ssam 195*13634Ssam /* 196*13634Ssam * If new candidate is of higher priority 197*13634Ssam * that the lowest priority file in the table, 198*13634Ssam * replace the table entry. 199*13634Ssam */ 200*13634Ssam if (pcompar(p, file) < 0) 201*13634Ssam strcpy(p, file); 202*13634Ssam } 203*13634Ssam 204*13634Ssam /* 205*13634Ssam Compare priority of filenames p1 and p2. Return: 206*13634Ssam * < 0 if p1 "has lower priority than" p2. 207*13634Ssam * = 0 if p1 "has priority equal to" p2. 208*13634Ssam * > 0 if p1 "has greater priority than" p2. 209*13634Ssam * Priority: 210*13634Ssam * lower grade wins. 211*13634Ssam * lower sequence number wins (unless wrap-around is suspected). 212*13634Ssam * 213*13634Ssam */ 214*13634Ssam /* LOCAL only */ 215*13634Ssam int 216*13634Ssam pcompar(p1, p2) 217*13634Ssam register char *p1, *p2; 218*13634Ssam { 219*13634Ssam register int rc; 220*13634Ssam 221*13634Ssam /* assert: strlen(p1) and strlen(p2) are >= 5 */ 222*13634Ssam p1 += strlen(p1)-5; 223*13634Ssam p2 += strlen(p2)-5; 224*13634Ssam /* check 'grade' */ 225*13634Ssam if (rc = *p2++ - *p1++) 226*13634Ssam return(rc); 227*13634Ssam /* check for sequence wrap-around */ 228*13634Ssam if (rc = *p2++ - *p1++) 229*13634Ssam if (rc < -10 || rc > 10) 230*13634Ssam return(-rc); 231*13634Ssam else 232*13634Ssam return(rc); 233*13634Ssam /* check remaining digits */ 234*13634Ssam return(strcmp(p2, p1)); 235*13634Ssam } 236*13634Ssam 237*13634Ssam /*** 238*13634Ssam * gtwrkf - get next work file 239*13634Ssam * Nfiles, Filent[] are modified. 240*13634Ssam * 241*13634Ssam * return value: 242*13634Ssam * 243*13634Ssam * 0 - No file gotten 244*13634Ssam * 1 - File successfully gotten. 245*13634Ssam * 246*13634Ssam */ 247*13634Ssam 248*13634Ssam /* LOCAL only */ 249*13634Ssam gtwrkf(dir, file) 250*13634Ssam char *file, *dir; 251*13634Ssam { 252*13634Ssam register char *p; 253*13634Ssam register int i; 254*13634Ssam 255*13634Ssam if (Nfiles == 0) 256*13634Ssam return(0); 257*13634Ssam /* Find highest priority file in table */ 258*13634Ssam p = Filent[0]; 259*13634Ssam for (i = 1; i < Nfiles; i++) 260*13634Ssam if (pcompar(Filent[i], p) > 0) 261*13634Ssam p = Filent[i]; 262*13634Ssam sprintf(file, "%s/%s", dir, p); 263*13634Ssam strcpy(p, Filent[--Nfiles]); 264*13634Ssam return(1); 265*13634Ssam } 266*13634Ssam 267*13634Ssam /*** 268*13634Ssam * gtwvec(file, dir, wkpre, wrkvec) get work vector 269*13634Ssam * char *file, *dir, *wkpre, **wrkvec; 270*13634Ssam * 271*13634Ssam * return codes: 272*13634Ssam * positive number - number of arguments 273*13634Ssam * 0 - no arguments - fail 274*13634Ssam */ 275*13634Ssam 276*13634Ssam /* EXTERNALLY CALLED */ 277*13634Ssam int 278*13634Ssam gtwvec(file, dir, wkpre, wrkvec) 279*13634Ssam char *dir, *wkpre, **wrkvec; 280*13634Ssam register char *file; 281*13634Ssam { 282*13634Ssam register int nargs, n; 283*13634Ssam 284*13634Ssam n = 0; /* Break possible infinite loop. rti!trt */ 285*13634Ssam while ((nargs = anlwrk(file, wrkvec)) == 0) { 286*13634Ssam if (++n > 3 || !iswrk(file, "get", dir, wkpre)) 287*13634Ssam return(0); 288*13634Ssam } 289*13634Ssam return(nargs); 290*13634Ssam } 291*13634Ssam 292*13634Ssam /*** 293*13634Ssam * iswrk(file, reqst, dir, pre) 294*13634Ssam * char *file, *reqst, *dir, *pre; 295*13634Ssam * 296*13634Ssam * iswrk - this routine will check the work list (list). 297*13634Ssam * If it is empty or the present work is exhausted, it 298*13634Ssam * will call bldflst to generate a new list. 299*13634Ssam * The "reqst" field will be the string "chk" or "get" to 300*13634Ssam * check for work, or get the next work file respectively. 301*13634Ssam * 302*13634Ssam * return codes: 303*13634Ssam * 0 - no more work (or some error) 304*13634Ssam * 1 - there is work 305*13634Ssam * 306*13634Ssam */ 307*13634Ssam 308*13634Ssam /* EXTERNALLY CALLED */ 309*13634Ssam int 310*13634Ssam iswrk(file, reqst, dir, pre) 311*13634Ssam register char *file, *reqst, *dir, *pre; 312*13634Ssam { 313*13634Ssam static char *lastpre = 0; 314*13634Ssam register ret; 315*13634Ssam 316*13634Ssam /* Starting new system; re-init */ 317*13634Ssam if (lastpre == 0 || strcmp(lastpre,pre) != 0) { 318*13634Ssam anlwrk ("", (char **)0); /* Force close of work file */ 319*13634Ssam 320*13634Ssam /* Save last worked-on prefix */ 321*13634Ssam if (lastpre != 0) 322*13634Ssam free (lastpre); 323*13634Ssam lastpre = malloc((unsigned)(strlen(pre)+1)); 324*13634Ssam strcpy (lastpre, pre); 325*13634Ssam 326*13634Ssam /* Set the external indexes properly 327*13634Ssam */ 328*13634Ssam Nfiles = 0; 329*13634Ssam } 330*13634Ssam 331*13634Ssam /* If the list is empty or new files have entered 332*13634Ssam * the spool area, call "bldflst" to read 333*13634Ssam * some file names into it. Because names can 334*13634Ssam * be put in the list that later turn out to 335*13634Ssam * be unusable (from "gtwrkf"), this operation 336*13634Ssam * continues until either "bldflst" can't find 337*13634Ssam * any new files, or "gtwrkf" signals success. 338*13634Ssam */ 339*13634Ssam for (;;) { 340*13634Ssam ret = 0; 341*13634Ssam if (Nfiles == 0 || newspool((time_t)TLIMIT)) 342*13634Ssam ret = bldflst (reqst, dir, pre); 343*13634Ssam 344*13634Ssam /* If they only wanted to check, return 345*13634Ssam * boolean list not empty. NB: the list 346*13634Ssam * will be forcibly emptied as soon as 347*13634Ssam * a new system name is mentioned. 348*13634Ssam */ 349*13634Ssam if (*reqst == 'c') 350*13634Ssam return (ret); 351*13634Ssam 352*13634Ssam if (Nfiles == 0) 353*13634Ssam return(0); 354*13634Ssam 355*13634Ssam if (gtwrkf(dir, file)) 356*13634Ssam return (1); 357*13634Ssam } 358*13634Ssam } 359*13634Ssam 360*13634Ssam /* Return non-zero if there is new work in the spool 361*13634Ssam * area since last check. Assumes that if the sequence 362*13634Ssam * file has been modified, there is new work. This is 363*13634Ssam * not absolutely correct, but should be close enough. 364*13634Ssam * Only checks every <limit> seconds at most. Called 365*13634Ssam * from "iswrk()" when a new work file is requested. 366*13634Ssam */ 367*13634Ssam /* LOCAL only */ 368*13634Ssam int 369*13634Ssam newspool(limit) 370*13634Ssam time_t limit; 371*13634Ssam { 372*13634Ssam static time_t lastcheck = 0, lastmod = 0; 373*13634Ssam time_t check; 374*13634Ssam struct stat mod; 375*13634Ssam register int ret = 0; 376*13634Ssam 377*13634Ssam /* (void) */ time (&check); 378*13634Ssam if (check - lastcheck > limit || lastcheck - check > limit) { 379*13634Ssam mod.st_mtime = 0; 380*13634Ssam /* (void) */ stat (SEQFILE, &mod); 381*13634Ssam if (mod.st_mtime != lastmod) 382*13634Ssam ret = 1; 383*13634Ssam lastmod = mod.st_mtime; 384*13634Ssam } 385*13634Ssam lastcheck = check; 386*13634Ssam return (ret); 387*13634Ssam } 388