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