113634Ssam #ifndef lint 2*17766Sralph static char sccsid[] = "@(#)anlwrk.c 5.3 (Berkeley) 01/22/85"; 313634Ssam #endif 413634Ssam 513634Ssam #include "uucp.h" 613634Ssam #include <sys/types.h> 713634Ssam #include <sys/stat.h> 8*17766Sralph #include "uust.h" 913634Ssam #ifdef NDIR 1013634Ssam #include "ndir.h" 1113634Ssam #else 1213701Ssam #include <sys/dir.h> 1313634Ssam #endif 1413634Ssam 1513634Ssam /* Re-written to be reasonable 1613634Ssam * Mon Nov 15 17:19:52 EST 1982 1713634Ssam * Alan S. Watt (ittvax!swatt) 1813634Ssam * 1913634Ssam * Tom Truscott (rti!trt): 2013634Ssam * Priority ordering cleaned up. New 'pcompar' subroutine. 2113634Ssam * 'stat' removed (speeds things up). 2213634Ssam * Possible infinite loop in gtwvec defended against. 2313634Ssam * Feb 23, 1983 2413634Ssam * 2513634Ssam * Changes: 2613634Ssam * 2713634Ssam * 1) The check for work is much faster; the first filename 2813634Ssam * that matches the prefix causes a "yes" return. 2913634Ssam * 3013634Ssam * 2) The filename is not "stat" ed , so 3113634Ssam * there is no massive delay while the list of potential 3213634Ssam * names is built. 3313634Ssam * 3413634Ssam * 3) Requesting work for a new system is now detected so 3513634Ssam * internal variables are re-initialized properly. In 3613634Ssam * particular, the stream pointer for the current work 3713634Ssam * file is properly closed so work for a system which 3813634Ssam * hangs up will not be sent to the next system called. 3913634Ssam * 4013634Ssam * Fri Dec 3 09:31:45 EST 1982 4113634Ssam * 4213634Ssam * 5) As new work files are requested, a check is made 4313634Ssam * every TLIMIT seconds (5 minutes at present) to see 4413634Ssam * if new files have entered the spool area. Since 4513634Ssam * work file names are now cached up to LLEN, this can 4613634Ssam * represent a very long transmission time before new 4713634Ssam * work enters the list to be processed. If people want 4813634Ssam * to use the "grade" character to specify a higher 4913634Ssam * priority, the list must be re-built and re-sorted for 5013634Ssam * higher priority stuff to have an immediate effect. 5113634Ssam */ 5213634Ssam 5313634Ssam 5413634Ssam #define TLIMIT (5*60L) 5513634Ssam #define NITEMS(X) (sizeof (X) / sizeof ((X)[0])) 5613634Ssam 57*17766Sralph int Nfiles = 0; 58*17766Sralph char Filent[LLEN][NAMESIZE]; 5913634Ssam 6013634Ssam /******* 6113634Ssam * anlwrk(file, wvec) create a vector of command arguments 6213634Ssam * char *file, **wvec; 6313634Ssam * 6413634Ssam * return codes: 6513634Ssam * 0 - no more work in this file 6613634Ssam * positive number - number of arguments 6713634Ssam */ 6813634Ssam 6913634Ssam /* LOCAL only */ 7013634Ssam int 7113634Ssam anlwrk(file, wvec) 7213634Ssam register char *file, **wvec; 7313634Ssam { 7413634Ssam static char str[MAXRQST]; 7513634Ssam static FILE *fp = NULL; 7613634Ssam 77*17766Sralph /* 78*17766Sralph * If called with a null string, force a shutdown 7913634Ssam * of the current work file. 8013634Ssam */ 8113634Ssam if (file[0] == '\0') { 8213634Ssam if (fp != NULL) 8313634Ssam fclose (fp); 8413634Ssam fp = NULL; 85*17766Sralph return 0; 8613634Ssam } 8713634Ssam if (fp == NULL) { 8813634Ssam fp = fopen(subfile(file), "r"); 8913634Ssam if (fp == NULL) { 90*17766Sralph unlink(subfile(file)); 91*17766Sralph return 0; 9213634Ssam } 93*17766Sralph Usrf = 0; 9413634Ssam } 9513634Ssam 9613634Ssam /* This is what deletes the current work file when EOF 9713634Ssam * is reached. As this is called from gtwvec, which is 9813634Ssam * in turn called externally, it is not possible to save 9913634Ssam * "C." files in case of error, except for line errors, 10013634Ssam * which shuts down the whole system. 10113634Ssam */ 10213634Ssam if (fgets(str, MAXRQST, fp) == NULL) { 10313634Ssam fclose(fp); 10413634Ssam unlink(subfile(file)); 105*17766Sralph USRF(USR_COMP); 106*17766Sralph US_RRS(file, Usrf); 107*17766Sralph Usrf = 0; 10813634Ssam file[0] = '\0'; 10913634Ssam fp = NULL; 110*17766Sralph return 0; 11113634Ssam } 112*17766Sralph return getargs(str, wvec, 20); 11313634Ssam } 11413634Ssam 11513634Ssam 11613634Ssam /*** 11713634Ssam * bldflst - build list of work files for given system 11813634Ssam * Nfiles, Filent are global 11913634Ssam * 12013634Ssam * return value - 1 if work was found, else 0 12113634Ssam * 12213634Ssam * Jul 26 19:17 1982 (ittvax!swatt). fixed this obnoxious 12313634Ssam * routine to NOT read all the way through the damned directory 12413634Ssam * "stat"'ing every file in sight just to get 10 names!!! 12513634Ssam * 12613634Ssam * It still reads through the directory from the beginning until 12713634Ssam * the list is filled, but this is only once every LLEN names. 12813634Ssam */ 12913634Ssam 13013634Ssam /* LOCAL only */ 13113634Ssam int 13213634Ssam bldflst (reqst, dir, pre) 13313634Ssam char *reqst; 13413634Ssam register char *dir, *pre; 13513634Ssam { 13613634Ssam static DIR *dirp = NULL; 13713634Ssam register nfound; 138*17766Sralph char filename[NAMESIZE]; 13913634Ssam int plen = strlen (pre); 140*17766Sralph int flen; 141*17766Sralph extern char MaxGrade; 14213634Ssam 14313634Ssam if (dirp == NULL) { 144*17766Sralph if ((dirp = opendir(subdir(dir,pre[0]))) == NULL) { 145*17766Sralph DEBUG(1,"opendir(%s) FAILS\n",subdir(dir,pre[0])); 146*17766Sralph return 0; 147*17766Sralph } 14813634Ssam } 14913634Ssam else 15013634Ssam rewinddir(dirp); 15113634Ssam for (nfound = 0, Nfiles = 0; gnamef(dirp, filename);) { 15213634Ssam /* Check for two systems with the same prefix. 15313634Ssam * Magic number "5" is 1 for "grade" character plus 15413634Ssam * 4 for sequence number. The point here is to not 15513634Ssam * send work for a system which has as a prefix the 15613634Ssam * name of the system called for. 15713634Ssam * Special case: prefix "X." does not do this check 15813634Ssam * so uuxqt can use bldflst. 15913634Ssam */ 160*17766Sralph flen = strlen(filename); 161*17766Sralph if (!prefix(pre, filename) || (plen != 2 && flen-plen != 5)) { 162*17766Sralph DEBUG(99,"bldflst rejects %s\n",filename); 16313634Ssam continue; 164*17766Sralph } 165*17766Sralph if (filename[flen-5] > MaxGrade ) { 166*17766Sralph DEBUG(8,"bldflst rejects %s, grade too low\n",filename); 167*17766Sralph continue; 168*17766Sralph } 16913634Ssam nfound++; 17013634Ssam if (*reqst == 'c') 171*17766Sralph return 1; 17213634Ssam entflst(filename); 17313634Ssam } 174*17766Sralph return nfound? 1: 0; 17513634Ssam } 17613634Ssam 17713634Ssam /*** 17813634Ssam * entflst - put new name if list is not full 17913634Ssam * or new name is less than the MAX 18013634Ssam * now in the list. 18113634Ssam * Nfiles, Filent[] are modified. 18213634Ssam * return value - none 18313634Ssam * 18413634Ssam */ 18513634Ssam 18613634Ssam /* LOCAL only */ 18713634Ssam int 18813634Ssam entflst(file) 189*17766Sralph register char *file; 19013634Ssam { 19113634Ssam register int i; 19213634Ssam 193*17766Sralph /* locate position for the new file and make room for it */ 194*17766Sralph for (i = Nfiles; i > 0; i--) { 195*17766Sralph if (pcompar(file, Filent[i-1]) >= 0) 196*17766Sralph break; 197*17766Sralph if (i <LLEN) 198*17766Sralph strcpy(Filent[i], Filent[i-1]); 19913634Ssam } 20013634Ssam 201*17766Sralph /* add new file (if there is room), and increase Nfiles if need be */ 202*17766Sralph if (i < LLEN) { 203*17766Sralph strcpy(Filent[i], file); 204*17766Sralph if (Nfiles < LLEN) 205*17766Sralph Nfiles++; 206*17766Sralph } 20713634Ssam } 20813634Ssam 20913634Ssam /* 21013634Ssam Compare priority of filenames p1 and p2. Return: 21113634Ssam * < 0 if p1 "has lower priority than" p2. 21213634Ssam * = 0 if p1 "has priority equal to" p2. 21313634Ssam * > 0 if p1 "has greater priority than" p2. 21413634Ssam * Priority: 21513634Ssam * lower grade wins. 21613634Ssam * lower sequence number wins (unless wrap-around is suspected). 21713634Ssam * 21813634Ssam */ 21913634Ssam /* LOCAL only */ 22013634Ssam int 22113634Ssam pcompar(p1, p2) 22213634Ssam register char *p1, *p2; 22313634Ssam { 22413634Ssam register int rc; 22513634Ssam 22613634Ssam /* assert: strlen(p1) and strlen(p2) are >= 5 */ 22713634Ssam p1 += strlen(p1)-5; 22813634Ssam p2 += strlen(p2)-5; 22913634Ssam /* check 'grade' */ 23013634Ssam if (rc = *p2++ - *p1++) 231*17766Sralph return rc; 23213634Ssam /* check for sequence wrap-around */ 23313634Ssam if (rc = *p2++ - *p1++) 23413634Ssam if (rc < -10 || rc > 10) 235*17766Sralph return -rc; 23613634Ssam else 237*17766Sralph return rc; 23813634Ssam /* check remaining digits */ 239*17766Sralph return strcmp(p2, p1); 24013634Ssam } 24113634Ssam 24213634Ssam /*** 24313634Ssam * gtwrkf - get next work file 24413634Ssam * Nfiles, Filent[] are modified. 24513634Ssam * 24613634Ssam * return value: 24713634Ssam * 24813634Ssam * 0 - No file gotten 24913634Ssam * 1 - File successfully gotten. 25013634Ssam * 25113634Ssam */ 25213634Ssam 25313634Ssam /* LOCAL only */ 25413634Ssam gtwrkf(dir, file) 25513634Ssam char *file, *dir; 25613634Ssam { 257*17766Sralph if (Nfiles <= 0) 258*17766Sralph return 0; 259*17766Sralph sprintf(file, "%s/%s", dir, Filent[--Nfiles]); 260*17766Sralph return 1; 26113634Ssam } 26213634Ssam 26313634Ssam /*** 264*17766Sralph * gtwvec(file, dir, wkpre, wrkvec) get work vector 26513634Ssam * char *file, *dir, *wkpre, **wrkvec; 26613634Ssam * 26713634Ssam * return codes: 26813634Ssam * positive number - number of arguments 26913634Ssam * 0 - no arguments - fail 27013634Ssam */ 27113634Ssam 27213634Ssam /* EXTERNALLY CALLED */ 27313634Ssam int 27413634Ssam gtwvec(file, dir, wkpre, wrkvec) 27513634Ssam char *dir, *wkpre, **wrkvec; 27613634Ssam register char *file; 27713634Ssam { 27813634Ssam register int nargs, n; 27913634Ssam 280*17766Sralph n = 0; 28113634Ssam while ((nargs = anlwrk(file, wrkvec)) == 0) { 28213634Ssam if (++n > 3 || !iswrk(file, "get", dir, wkpre)) 283*17766Sralph return 0; 28413634Ssam } 285*17766Sralph return nargs; 28613634Ssam } 28713634Ssam 28813634Ssam /*** 28913634Ssam * iswrk(file, reqst, dir, pre) 29013634Ssam * char *file, *reqst, *dir, *pre; 29113634Ssam * 29213634Ssam * iswrk - this routine will check the work list (list). 29313634Ssam * If it is empty or the present work is exhausted, it 29413634Ssam * will call bldflst to generate a new list. 29513634Ssam * The "reqst" field will be the string "chk" or "get" to 29613634Ssam * check for work, or get the next work file respectively. 29713634Ssam * 29813634Ssam * return codes: 29913634Ssam * 0 - no more work (or some error) 30013634Ssam * 1 - there is work 30113634Ssam * 30213634Ssam */ 30313634Ssam 30413634Ssam /* EXTERNALLY CALLED */ 30513634Ssam int 30613634Ssam iswrk(file, reqst, dir, pre) 30713634Ssam register char *file, *reqst, *dir, *pre; 30813634Ssam { 30913634Ssam static char *lastpre = 0; 31013634Ssam register ret; 31113634Ssam 31213634Ssam /* Starting new system; re-init */ 31313634Ssam if (lastpre == 0 || strcmp(lastpre,pre) != 0) { 31413634Ssam anlwrk ("", (char **)0); /* Force close of work file */ 31513634Ssam 31613634Ssam /* Save last worked-on prefix */ 31713634Ssam if (lastpre != 0) 31813634Ssam free (lastpre); 31913634Ssam lastpre = malloc((unsigned)(strlen(pre)+1)); 32013634Ssam strcpy (lastpre, pre); 32113634Ssam 32213634Ssam /* Set the external indexes properly 32313634Ssam */ 32413634Ssam Nfiles = 0; 32513634Ssam } 32613634Ssam 32713634Ssam /* If the list is empty or new files have entered 32813634Ssam * the spool area, call "bldflst" to read 32913634Ssam * some file names into it. Because names can 33013634Ssam * be put in the list that later turn out to 33113634Ssam * be unusable (from "gtwrkf"), this operation 33213634Ssam * continues until either "bldflst" can't find 33313634Ssam * any new files, or "gtwrkf" signals success. 33413634Ssam */ 33513634Ssam for (;;) { 33613634Ssam ret = 0; 337*17766Sralph if (Nfiles == 0 || newspool((time_t)TLIMIT)) { 33813634Ssam ret = bldflst (reqst, dir, pre); 339*17766Sralph DEBUG(99,"bldflst returns %d\n",ret); 340*17766Sralph } 34113634Ssam 34213634Ssam /* If they only wanted to check, return 34313634Ssam * boolean list not empty. NB: the list 34413634Ssam * will be forcibly emptied as soon as 34513634Ssam * a new system name is mentioned. 34613634Ssam */ 34713634Ssam if (*reqst == 'c') 348*17766Sralph return ret; 34913634Ssam 35013634Ssam if (Nfiles == 0) 351*17766Sralph return 0; 35213634Ssam 35313634Ssam if (gtwrkf(dir, file)) 354*17766Sralph return 1; 35513634Ssam } 35613634Ssam } 35713634Ssam 35813634Ssam /* Return non-zero if there is new work in the spool 35913634Ssam * area since last check. Assumes that if the sequence 36013634Ssam * file has been modified, there is new work. This is 36113634Ssam * not absolutely correct, but should be close enough. 36213634Ssam * Only checks every <limit> seconds at most. Called 36313634Ssam * from "iswrk()" when a new work file is requested. 36413634Ssam */ 36513634Ssam /* LOCAL only */ 36613634Ssam int 36713634Ssam newspool(limit) 36813634Ssam time_t limit; 36913634Ssam { 37013634Ssam static time_t lastcheck = 0, lastmod = 0; 37113634Ssam time_t check; 37213634Ssam struct stat mod; 37313634Ssam register int ret = 0; 37413634Ssam 37513634Ssam /* (void) */ time (&check); 37613634Ssam if (check - lastcheck > limit || lastcheck - check > limit) { 37713634Ssam mod.st_mtime = 0; 37813634Ssam /* (void) */ stat (SEQFILE, &mod); 37913634Ssam if (mod.st_mtime != lastmod) 38013634Ssam ret = 1; 38113634Ssam lastmod = mod.st_mtime; 38213634Ssam } 38313634Ssam lastcheck = check; 384*17766Sralph return ret; 38513634Ssam } 386