xref: /original-bsd/usr.bin/uucp/libuu/anlwrk.c (revision c3e32dec)
1 /*-
2  * Copyright (c) 1985, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)anlwrk.c	8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11 
12 #include "uucp.h"
13 #include <sys/stat.h>
14 #include "uust.h"
15 #ifdef	NDIR
16 #include "ndir.h"
17 #else
18 #include <sys/dir.h>
19 #endif
20 #include <ctype.h>
21 
22 #define TLIMIT	(15*60L)
23 #define NITEMS(X)	(sizeof (X) / sizeof ((X)[0]))
24 
25 int Nfiles = 0;
26 char Filent[LLEN][NAMESIZE];
27 extern int TransferSucceeded;
28 
29 /*LINTLIBRARY*/
30 
31 /*
32  *	create a vector of command arguments
33  *
34  *	return codes:
35  *		0  -  no more work in this file
36  *		positive number  -  number of arguments
37  */
38 
39 /* LOCAL only */
40 int
41 anlwrk(file, wvec)
42 register char *file, **wvec;
43 {
44 	static char str[MAXRQST], nstr[MAXRQST], lastfile[MAXFULLNAME] = "";
45 	static FILE *fp = NULL;
46 	static long nextread, nextwrite;
47 
48 	/*
49 	 * If called with a null string, force a shutdown
50 	 * of the current work file.
51 	 */
52 	if (file[0] == '\0') {
53 		if (fp != NULL)
54 			fclose (fp);
55 		fp = NULL;
56 		return 0;
57 	}
58 	if (fp == NULL) {
59 		if (strncmp(file, lastfile, MAXFULLNAME) == 0) {
60 			DEBUG(5,"Workfilename repeated: %s\n", file);
61 			return 0;
62 		}
63 		strncpy(lastfile, file, MAXFULLNAME);
64 		fp = fopen(subfile(file), "r+w");
65 		if (fp == NULL) {
66 			char *bnp, rqstr[MAXFULLNAME];
67 			bnp = rindex(file, '/');
68 			sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : file);
69 			xmv(file, rqstr);
70 			syslog(LOG_WARNING, "fopen(%s) failed: %m",
71 				subfile(file));
72 			unlink(subfile(file));
73 			return 0;
74 		}
75 		Usrf = 0;
76 		nstr[0] = '\0';
77 		nextread = nextwrite = 0L;
78 	}
79 
80 	if (nstr[0] != '\0' && TransferSucceeded) {
81 		fseek(fp, nextwrite, 0);
82 		fputs(nstr, fp);
83 		fseek(fp, nextread, 0);
84 	}
85 
86 	do {
87 		nextwrite = ftell(fp);
88 		if (fgets(str, MAXRQST, fp) == NULL) {
89 			fclose(fp);
90 			if (TransferSucceeded)
91 				unlink(subfile(file));
92 			USRF(USR_COMP);
93 			US_RRS(file, Usrf);
94 			Usrf = 0;
95 			file[0] = '\0';
96 			nstr[0] = '\0';
97 			fp = NULL;
98 			return 0;
99 		}
100 	} while (!isupper(str[0]));
101 
102 	nextread = ftell(fp);
103 	strncpy(nstr, str, MAXRQST);
104 	nstr[0] = tolower(nstr[0]);
105 	return getargs(str, wvec, 20);
106 }
107 
108 
109 /*
110  *	build list of work files for given system
111  *
112  *	return value - 1 if work was found, else 0
113  *
114  */
115 
116 /* LOCAL only */
117 int
118 bldflst (reqst, dir, pre)
119 char *reqst;
120 register char *dir, *pre;
121 {
122 	static DIR  *dirp = NULL;
123 	register struct direct *dentp;
124 	register int i;
125 	int plen = strlen(pre);
126 	extern char MaxGrade;
127 
128 	if (dirp == NULL) {
129 		if ((dirp = opendir(subdir(dir,pre[0]))) == NULL) {
130 			DEBUG(1,"opendir(%s) FAILS\n",subdir(dir,pre[0]));
131 			return 0;
132 		}
133 	} else
134 		rewinddir(dirp);
135 
136 	Nfiles = 0;
137 	while ((dentp = readdir(dirp)) != NULL && Nfiles < LLEN) {
138 		/* Check for two systems with the same prefix.
139 		 * Magic number "5" is 1 for "grade" character plus
140 		 * 4 for sequence number.  The point here is to not
141 		 * send work for a system which has as a prefix the
142 		 * name of the system called for.
143 		 * Special case: prefix "X." does not do this check
144 		 * so uuxqt can use bldflst.
145 		 */
146 		if (!prefix(pre, dentp->d_name) ||
147 			(plen != 2 && (dentp->d_namlen-plen) != 5)) {
148 			DEBUG(99,"bldflst rejects %s\n",dentp->d_name);
149 			continue;
150 		}
151 		if (dentp->d_name[dentp->d_namlen-5] > MaxGrade) {
152 			DEBUG(8, "bldflst rejects %s, grade too low\n",
153 				dentp->d_name);
154 			continue;
155 		}
156 		if (*reqst == 'c')
157 			return 1;
158 
159 		/* locate position for the new file and make room for it */
160 		for (i = Nfiles; i > 0; i--) {
161 			if (pcompar(dentp->d_name, Filent[i-1]) <= 0)
162 				break;
163 			if (i <LLEN)
164 				strcpy(Filent[i], Filent[i-1]);
165 		}
166 
167 		/* add new file (if there is room), and increase Nfiles if need be */
168 		if (i < LLEN) {
169 			DEBUG(99,"bldflst accepts %s",dentp->d_name);
170 			DEBUG(99," as Filent[%d]\n", i);
171 			strcpy(Filent[i], dentp->d_name);
172 			if (Nfiles < LLEN)
173 				Nfiles++;
174 		} else
175 			DEBUG(99,"Filent full, %s rejected by bldflst\n", dentp->d_name);
176 
177 
178 	}
179 	if (Debug >99)
180 		for(i=0;i<Nfiles;i++)
181 			fprintf(stderr,"Filent[%d]=%s\n",i,Filent[i]);
182 
183 	return Nfiles > 0;
184 }
185 
186 /*
187   Compare priority of filenames p1 and p2.  Return:
188  *	< 0	if p1 "has lower priority than" p2.
189  *	= 0	if p1 "has priority equal to" p2.
190  *	> 0	if p1 "has greater priority than" p2.
191  * Priority:
192  *	lower grade wins.
193  *	lower sequence number wins (unless wrap-around is suspected).
194  *
195  */
196 /* LOCAL only */
197 pcompar(p1, p2)
198 register char *p1, *p2;
199 {
200 	register int rc;
201 
202 	/* strlen(p1) and strlen(p2) are >= 5 */
203 	p1 += strlen(p1)-5;
204 	p2 += strlen(p2)-5;
205 	/* check 'grade' */
206 	if (rc = *p2++ - *p1++)
207 		return rc;
208 	/* check for  sequence wrap-around */
209 	if (rc = *p2++ - *p1++)
210 		if (rc < -10 || rc > 10)
211 			return -rc;
212 		else
213 			return rc;
214 	/* check remaining digits */
215 	return strcmp(p2, p1);
216 }
217 
218 /*
219  *	get work vector
220  *
221  *	return codes:
222  *		positive number  -  number of arguments
223  *		0 -  no arguments - fail
224  */
225 
226 /* EXTERNALLY CALLED */
227 int
228 gtwvec(file, dir, wkpre, wrkvec)
229 char *dir, *wkpre, **wrkvec;
230 register char *file;
231 {
232 	register int nargs, n;
233 
234 	n = 0;
235 	while ((nargs = anlwrk(file, wrkvec)) == 0) {
236 		if (++n > 3 || !iswrk(file, "get", dir, wkpre))
237 			return 0;
238 	}
239 	return nargs;
240 }
241 
242 /*
243  *	iswrk  -  this routine will check the work list (list).
244  *	If it is empty or the present work is exhausted, it
245  *	will call bldflst to generate a new list.
246  *	The "reqst" field will be the string "chk" or "get" to
247  *	check for work, or get the next work file respectively.
248  *
249  *	return codes:
250  *		0  -  no more work (or some error)
251  *		1  -  there is work
252  *
253  */
254 
255 /* EXTERNALLY CALLED */
256 int
257 iswrk(file, reqst, dir, pre)
258 register char *file, *reqst, *dir, *pre;
259 {
260 	static char *lastpre = 0;
261 	register ret = 0;
262 	int i;
263 
264 	/* Starting new system; re-init */
265 	if (lastpre == 0 || strcmp(lastpre, pre) != SAME) {
266 		/* Force close of work file */
267 		anlwrk("", (char **)0);
268 
269 		/* Save last worked-on prefix */
270 		if (lastpre != 0)
271 			free(lastpre);
272 		lastpre = malloc((unsigned)(strlen(pre)+1));
273 		strcpy(lastpre, pre);
274 
275 		/* Set the external indexes properly */
276 		Nfiles = 0;
277 	}
278 
279 	/*
280 	 * If the list is empty or new files have entered
281 	 * the spool area, call "bldflst" to read
282 	 * some file names into it.
283 	 */
284 	if (Nfiles <= 0 || newspool((time_t)TLIMIT)) {
285 		ret = bldflst(reqst, dir, pre);
286 		DEBUG(99, "bldflst returns %d\n", ret);
287 	}
288 
289 	/* If they only wanted to check, return
290 	 * boolean list not empty.  NB: the list
291 	 * will be forcibly emptied as soon as
292 	 * a new system name is mentioned.
293 	 */
294 	if (*reqst == 'c')
295 		return ret;
296 
297 	if (Nfiles-- <= 0) {
298 		/* Didn't find any files in the spool area */
299 		Nfiles = 0;
300 		return 0;
301 	}
302 	/* Found some files, return the first one */
303 	sprintf(file, "%s/%s", dir, Filent[0]);
304 	for (i = 0; i < Nfiles; i++)
305 		strcpy(Filent[i], Filent[i+1]);
306 	return 1;
307 }
308 
309 /* Return non-zero if there is new work in the spool
310  * area since last check.  Assumes that if the sequence
311  * file has been modified, there is new work. This is
312  * not absolutely correct, but should be close enough.
313  * Only checks every <limit> seconds at most.  Called
314  * from "iswrk()" when a new work file is requested.
315  */
316 /* LOCAL only */
317 int
318 newspool(limit)
319 time_t	limit;
320 {
321 	static time_t lastcheck = 0, lastmod = 0;
322 	time_t check;
323 	struct stat mod;
324 	register int ret = 0;
325 
326 	/* (void) */ time (&check);
327 	if (check - lastcheck > limit || lastcheck - check > limit) {
328 		mod.st_mtime = 0;
329 		/* (void) */ stat (SEQFILE, &mod);
330 		if (mod.st_mtime != lastmod)
331 			ret = 1;
332 		lastmod = mod.st_mtime;
333 	}
334 	lastcheck = check;
335 	return ret;
336 }
337