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