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
anlwrk(file,wvec)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
bldflst(reqst,dir,pre)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 */
pcompar(p1,p2)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
gtwvec(file,dir,wkpre,wrkvec)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
iswrk(file,reqst,dir,pre)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
newspool(limit)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