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