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