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