xref: /csrg-svn/usr.bin/uucp/libuu/anlwrk.c (revision 17766)
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