113634Ssam #ifndef lint 2*13701Ssam static char sccsid[] = "@(#)anlwrk.c 5.2 (Berkeley) 07/02/83"; 313634Ssam #endif 413634Ssam 513634Ssam #include "uucp.h" 613634Ssam #include <sys/types.h> 713634Ssam #include <sys/stat.h> 813634Ssam #ifdef NDIR 913634Ssam #include "ndir.h" 1013634Ssam #else 11*13701Ssam #include <sys/dir.h> 1213634Ssam #endif 1313634Ssam 1413634Ssam /* Re-written to be reasonable 1513634Ssam * Mon Nov 15 17:19:52 EST 1982 1613634Ssam * Alan S. Watt (ittvax!swatt) 1713634Ssam * 1813634Ssam * Tom Truscott (rti!trt): 1913634Ssam * Priority ordering cleaned up. New 'pcompar' subroutine. 2013634Ssam * 'stat' removed (speeds things up). 2113634Ssam * Possible infinite loop in gtwvec defended against. 2213634Ssam * Feb 23, 1983 2313634Ssam * 2413634Ssam * Changes: 2513634Ssam * 2613634Ssam * 1) The check for work is much faster; the first filename 2713634Ssam * that matches the prefix causes a "yes" return. 2813634Ssam * 2913634Ssam * 2) The filename is not "stat" ed , so 3013634Ssam * there is no massive delay while the list of potential 3113634Ssam * names is built. 3213634Ssam * 3313634Ssam * 3) Requesting work for a new system is now detected so 3413634Ssam * internal variables are re-initialized properly. In 3513634Ssam * particular, the stream pointer for the current work 3613634Ssam * file is properly closed so work for a system which 3713634Ssam * hangs up will not be sent to the next system called. 3813634Ssam * 3913634Ssam * Fri Dec 3 09:31:45 EST 1982 4013634Ssam * 4113634Ssam * 5) As new work files are requested, a check is made 4213634Ssam * every TLIMIT seconds (5 minutes at present) to see 4313634Ssam * if new files have entered the spool area. Since 4413634Ssam * work file names are now cached up to LLEN, this can 4513634Ssam * represent a very long transmission time before new 4613634Ssam * work enters the list to be processed. If people want 4713634Ssam * to use the "grade" character to specify a higher 4813634Ssam * priority, the list must be re-built and re-sorted for 4913634Ssam * higher priority stuff to have an immediate effect. 5013634Ssam */ 5113634Ssam 5213634Ssam 5313634Ssam #define LLEN 20 5413634Ssam #define MAXRQST 250 5513634Ssam #define TLIMIT (5*60L) 5613634Ssam #define NITEMS(X) (sizeof (X) / sizeof ((X)[0])) 5713634Ssam 5813634Ssam /* These are all used only locally 5913634Ssam */ 6013634Ssam static int Nfiles = 0; 6113634Ssam static char Filent[LLEN][NAMESIZE]; 6213634Ssam 6313634Ssam /******* 6413634Ssam * anlwrk(file, wvec) create a vector of command arguments 6513634Ssam * char *file, **wvec; 6613634Ssam * 6713634Ssam * return codes: 6813634Ssam * 0 - no more work in this file 6913634Ssam * positive number - number of arguments 7013634Ssam */ 7113634Ssam 7213634Ssam /* LOCAL only */ 7313634Ssam int 7413634Ssam anlwrk(file, wvec) 7513634Ssam register char *file, **wvec; 7613634Ssam { 7713634Ssam static char str[MAXRQST]; 7813634Ssam static FILE *fp = NULL; 7913634Ssam 8013634Ssam /* If called with a null string, force a shutdown 8113634Ssam * of the current work file. 8213634Ssam * John Levine, ima.247, related change in cntl.c 8313634Ssam */ 8413634Ssam if (file[0] == '\0') { 8513634Ssam if (fp != NULL) 8613634Ssam fclose (fp); 8713634Ssam fp = NULL; 8813634Ssam return(0); 8913634Ssam } 9013634Ssam if (fp == NULL) { 9113634Ssam fp = fopen(subfile(file), "r"); 9213634Ssam if (fp == NULL) { 9313634Ssam unlink(subfile(file)); /* Try to zap the thing. rti!trt */ 9413634Ssam return(0); 9513634Ssam } 9613634Ssam } 9713634Ssam 9813634Ssam /* This is what deletes the current work file when EOF 9913634Ssam * is reached. As this is called from gtwvec, which is 10013634Ssam * in turn called externally, it is not possible to save 10113634Ssam * "C." files in case of error, except for line errors, 10213634Ssam * which shuts down the whole system. 10313634Ssam */ 10413634Ssam if (fgets(str, MAXRQST, fp) == NULL) { 10513634Ssam fclose(fp); 10613634Ssam unlink(subfile(file)); 10713634Ssam file[0] = '\0'; 10813634Ssam fp = NULL; 10913634Ssam return(0); 11013634Ssam } 11113634Ssam return(getargs(str, wvec)); 11213634Ssam } 11313634Ssam 11413634Ssam 11513634Ssam /*** 11613634Ssam * bldflst - build list of work files for given system 11713634Ssam * Nfiles, Filent are global 11813634Ssam * 11913634Ssam * return value - 1 if work was found, else 0 12013634Ssam * 12113634Ssam * Jul 26 19:17 1982 (ittvax!swatt). fixed this obnoxious 12213634Ssam * routine to NOT read all the way through the damned directory 12313634Ssam * "stat"'ing every file in sight just to get 10 names!!! 12413634Ssam * 12513634Ssam * It still reads through the directory from the beginning until 12613634Ssam * the list is filled, but this is only once every LLEN names. 12713634Ssam */ 12813634Ssam 12913634Ssam /* LOCAL only */ 13013634Ssam int 13113634Ssam bldflst (reqst, dir, pre) 13213634Ssam char *reqst; 13313634Ssam register char *dir, *pre; 13413634Ssam { 13513634Ssam static DIR *dirp = NULL; 13613634Ssam register nfound; 13713634Ssam char filename[NAMESIZE]; /* @@@ NB: this needs new dir stuff */ 13813634Ssam int plen = strlen (pre); 13913634Ssam 14013634Ssam if (dirp == NULL) { 14113634Ssam if ((dirp = opendir(subdir(dir,pre[0]), "r")) == NULL) 14213634Ssam return(0); 14313634Ssam } 14413634Ssam else 14513634Ssam rewinddir(dirp); 14613634Ssam for (nfound = 0, Nfiles = 0; gnamef(dirp, filename);) { 14713634Ssam /* Check for two systems with the same prefix. 14813634Ssam * Magic number "5" is 1 for "grade" character plus 14913634Ssam * 4 for sequence number. The point here is to not 15013634Ssam * send work for a system which has as a prefix the 15113634Ssam * name of the system called for. 15213634Ssam * Special case: prefix "X." does not do this check 15313634Ssam * so uuxqt can use bldflst. 15413634Ssam */ 15513634Ssam if (!prefix(pre, filename) 15613634Ssam || (plen != 2 && strlen(filename)-plen != 5)) 15713634Ssam continue; 15813634Ssam nfound++; 15913634Ssam if (*reqst == 'c') 16013634Ssam return (1); 16113634Ssam entflst(filename); 16213634Ssam } 16313634Ssam return (nfound? 1: 0); 16413634Ssam } 16513634Ssam 16613634Ssam /*** 16713634Ssam * entflst - put new name if list is not full 16813634Ssam * or new name is less than the MAX 16913634Ssam * now in the list. 17013634Ssam * Nfiles, Filent[] are modified. 17113634Ssam * return value - none 17213634Ssam * 17313634Ssam */ 17413634Ssam 17513634Ssam /* LOCAL only */ 17613634Ssam int 17713634Ssam entflst(file) 17813634Ssam char *file; 17913634Ssam { 18013634Ssam register int i; 18113634Ssam register char *p; 18213634Ssam 18313634Ssam /* If there is room in the table, just add it. */ 18413634Ssam if (Nfiles < LLEN) { 18513634Ssam strcpy(Filent[Nfiles++], file); 18613634Ssam return; 18713634Ssam } 18813634Ssam 18913634Ssam /* Find lowest priority file in table */ 19013634Ssam p = Filent[0]; 19113634Ssam for (i = 1; i < Nfiles; i++) 19213634Ssam if (pcompar(Filent[i], p) < 0) 19313634Ssam p = Filent[i]; 19413634Ssam 19513634Ssam /* 19613634Ssam * If new candidate is of higher priority 19713634Ssam * that the lowest priority file in the table, 19813634Ssam * replace the table entry. 19913634Ssam */ 20013634Ssam if (pcompar(p, file) < 0) 20113634Ssam strcpy(p, file); 20213634Ssam } 20313634Ssam 20413634Ssam /* 20513634Ssam Compare priority of filenames p1 and p2. Return: 20613634Ssam * < 0 if p1 "has lower priority than" p2. 20713634Ssam * = 0 if p1 "has priority equal to" p2. 20813634Ssam * > 0 if p1 "has greater priority than" p2. 20913634Ssam * Priority: 21013634Ssam * lower grade wins. 21113634Ssam * lower sequence number wins (unless wrap-around is suspected). 21213634Ssam * 21313634Ssam */ 21413634Ssam /* LOCAL only */ 21513634Ssam int 21613634Ssam pcompar(p1, p2) 21713634Ssam register char *p1, *p2; 21813634Ssam { 21913634Ssam register int rc; 22013634Ssam 22113634Ssam /* assert: strlen(p1) and strlen(p2) are >= 5 */ 22213634Ssam p1 += strlen(p1)-5; 22313634Ssam p2 += strlen(p2)-5; 22413634Ssam /* check 'grade' */ 22513634Ssam if (rc = *p2++ - *p1++) 22613634Ssam return(rc); 22713634Ssam /* check for sequence wrap-around */ 22813634Ssam if (rc = *p2++ - *p1++) 22913634Ssam if (rc < -10 || rc > 10) 23013634Ssam return(-rc); 23113634Ssam else 23213634Ssam return(rc); 23313634Ssam /* check remaining digits */ 23413634Ssam return(strcmp(p2, p1)); 23513634Ssam } 23613634Ssam 23713634Ssam /*** 23813634Ssam * gtwrkf - get next work file 23913634Ssam * Nfiles, Filent[] are modified. 24013634Ssam * 24113634Ssam * return value: 24213634Ssam * 24313634Ssam * 0 - No file gotten 24413634Ssam * 1 - File successfully gotten. 24513634Ssam * 24613634Ssam */ 24713634Ssam 24813634Ssam /* LOCAL only */ 24913634Ssam gtwrkf(dir, file) 25013634Ssam char *file, *dir; 25113634Ssam { 25213634Ssam register char *p; 25313634Ssam register int i; 25413634Ssam 25513634Ssam if (Nfiles == 0) 25613634Ssam return(0); 25713634Ssam /* Find highest priority file in table */ 25813634Ssam p = Filent[0]; 25913634Ssam for (i = 1; i < Nfiles; i++) 26013634Ssam if (pcompar(Filent[i], p) > 0) 26113634Ssam p = Filent[i]; 26213634Ssam sprintf(file, "%s/%s", dir, p); 26313634Ssam strcpy(p, Filent[--Nfiles]); 26413634Ssam return(1); 26513634Ssam } 26613634Ssam 26713634Ssam /*** 26813634Ssam * gtwvec(file, dir, wkpre, wrkvec) get work vector 26913634Ssam * char *file, *dir, *wkpre, **wrkvec; 27013634Ssam * 27113634Ssam * return codes: 27213634Ssam * positive number - number of arguments 27313634Ssam * 0 - no arguments - fail 27413634Ssam */ 27513634Ssam 27613634Ssam /* EXTERNALLY CALLED */ 27713634Ssam int 27813634Ssam gtwvec(file, dir, wkpre, wrkvec) 27913634Ssam char *dir, *wkpre, **wrkvec; 28013634Ssam register char *file; 28113634Ssam { 28213634Ssam register int nargs, n; 28313634Ssam 28413634Ssam n = 0; /* Break possible infinite loop. rti!trt */ 28513634Ssam while ((nargs = anlwrk(file, wrkvec)) == 0) { 28613634Ssam if (++n > 3 || !iswrk(file, "get", dir, wkpre)) 28713634Ssam return(0); 28813634Ssam } 28913634Ssam return(nargs); 29013634Ssam } 29113634Ssam 29213634Ssam /*** 29313634Ssam * iswrk(file, reqst, dir, pre) 29413634Ssam * char *file, *reqst, *dir, *pre; 29513634Ssam * 29613634Ssam * iswrk - this routine will check the work list (list). 29713634Ssam * If it is empty or the present work is exhausted, it 29813634Ssam * will call bldflst to generate a new list. 29913634Ssam * The "reqst" field will be the string "chk" or "get" to 30013634Ssam * check for work, or get the next work file respectively. 30113634Ssam * 30213634Ssam * return codes: 30313634Ssam * 0 - no more work (or some error) 30413634Ssam * 1 - there is work 30513634Ssam * 30613634Ssam */ 30713634Ssam 30813634Ssam /* EXTERNALLY CALLED */ 30913634Ssam int 31013634Ssam iswrk(file, reqst, dir, pre) 31113634Ssam register char *file, *reqst, *dir, *pre; 31213634Ssam { 31313634Ssam static char *lastpre = 0; 31413634Ssam register ret; 31513634Ssam 31613634Ssam /* Starting new system; re-init */ 31713634Ssam if (lastpre == 0 || strcmp(lastpre,pre) != 0) { 31813634Ssam anlwrk ("", (char **)0); /* Force close of work file */ 31913634Ssam 32013634Ssam /* Save last worked-on prefix */ 32113634Ssam if (lastpre != 0) 32213634Ssam free (lastpre); 32313634Ssam lastpre = malloc((unsigned)(strlen(pre)+1)); 32413634Ssam strcpy (lastpre, pre); 32513634Ssam 32613634Ssam /* Set the external indexes properly 32713634Ssam */ 32813634Ssam Nfiles = 0; 32913634Ssam } 33013634Ssam 33113634Ssam /* If the list is empty or new files have entered 33213634Ssam * the spool area, call "bldflst" to read 33313634Ssam * some file names into it. Because names can 33413634Ssam * be put in the list that later turn out to 33513634Ssam * be unusable (from "gtwrkf"), this operation 33613634Ssam * continues until either "bldflst" can't find 33713634Ssam * any new files, or "gtwrkf" signals success. 33813634Ssam */ 33913634Ssam for (;;) { 34013634Ssam ret = 0; 34113634Ssam if (Nfiles == 0 || newspool((time_t)TLIMIT)) 34213634Ssam ret = bldflst (reqst, dir, pre); 34313634Ssam 34413634Ssam /* If they only wanted to check, return 34513634Ssam * boolean list not empty. NB: the list 34613634Ssam * will be forcibly emptied as soon as 34713634Ssam * a new system name is mentioned. 34813634Ssam */ 34913634Ssam if (*reqst == 'c') 35013634Ssam return (ret); 35113634Ssam 35213634Ssam if (Nfiles == 0) 35313634Ssam return(0); 35413634Ssam 35513634Ssam if (gtwrkf(dir, file)) 35613634Ssam return (1); 35713634Ssam } 35813634Ssam } 35913634Ssam 36013634Ssam /* Return non-zero if there is new work in the spool 36113634Ssam * area since last check. Assumes that if the sequence 36213634Ssam * file has been modified, there is new work. This is 36313634Ssam * not absolutely correct, but should be close enough. 36413634Ssam * Only checks every <limit> seconds at most. Called 36513634Ssam * from "iswrk()" when a new work file is requested. 36613634Ssam */ 36713634Ssam /* LOCAL only */ 36813634Ssam int 36913634Ssam newspool(limit) 37013634Ssam time_t limit; 37113634Ssam { 37213634Ssam static time_t lastcheck = 0, lastmod = 0; 37313634Ssam time_t check; 37413634Ssam struct stat mod; 37513634Ssam register int ret = 0; 37613634Ssam 37713634Ssam /* (void) */ time (&check); 37813634Ssam if (check - lastcheck > limit || lastcheck - check > limit) { 37913634Ssam mod.st_mtime = 0; 38013634Ssam /* (void) */ stat (SEQFILE, &mod); 38113634Ssam if (mod.st_mtime != lastmod) 38213634Ssam ret = 1; 38313634Ssam lastmod = mod.st_mtime; 38413634Ssam } 38513634Ssam lastcheck = check; 38613634Ssam return (ret); 38713634Ssam } 388