1: #if !defined(lint) && defined(DOSCCS) 2: static char sccsid[] = "@(#)anlwrk.c 5.5.1 (2.11BSD) 1997/10/2"; 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 (5*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: logent(subfile(file), "CMD FILE UNREADABLE"); 64: unlink(subfile(file)); 65: return 0; 66: } 67: Usrf = 0; 68: nstr[0] = '\0'; 69: nextread = nextwrite = 0L; 70: } 71: 72: if (nstr[0] != '\0' && TransferSucceeded) { 73: fseek(fp, nextwrite, 0); 74: fputs(nstr, fp); 75: fseek(fp, nextread, 0); 76: } 77: 78: do { 79: nextwrite = ftell(fp); 80: if (fgets(str, MAXRQST, fp) == NULL) { 81: fclose(fp); 82: if (TransferSucceeded) 83: unlink(subfile(file)); 84: USRF(USR_COMP); 85: US_RRS(file, Usrf); 86: Usrf = 0; 87: file[0] = '\0'; 88: nstr[0] = '\0'; 89: fp = NULL; 90: return 0; 91: } 92: } while (!isupper(str[0])); 93: 94: nextread = ftell(fp); 95: strncpy(nstr, str, MAXRQST); 96: nstr[0] = tolower(nstr[0]); 97: return getargs(str, wvec, 20); 98: } 99: 100: 101: /* 102: * build list of work files for given system 103: * 104: * return value - 1 if work was found, else 0 105: * 106: */ 107: 108: /* LOCAL only */ 109: int 110: bldflst (reqst, dir, pre) 111: char *reqst; 112: register char *dir, *pre; 113: { 114: static DIR *dirp = NULL; 115: register nfound; 116: char filename[NAMESIZE]; 117: int plen = strlen (pre); 118: int flen; 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: } 127: else 128: rewinddir(dirp); 129: for (nfound = 0, Nfiles = 0; gnamef(dirp, filename);) { 130: /* Check for two systems with the same prefix. 131: * Magic number "5" is 1 for "grade" character plus 132: * 4 for sequence number. The point here is to not 133: * send work for a system which has as a prefix the 134: * name of the system called for. 135: * Special case: prefix "X." does not do this check 136: * so uuxqt can use bldflst. 137: */ 138: flen = strlen(filename); 139: if (!prefix(pre, filename) || (plen != 2 && flen-plen != 5)) { 140: DEBUG(99,"bldflst rejects %s\n",filename); 141: continue; 142: } 143: if (filename[flen-5] > MaxGrade ) { 144: DEBUG(8,"bldflst rejects %s, grade too low\n",filename); 145: continue; 146: } 147: nfound++; 148: if (*reqst == 'c') 149: return 1; 150: entflst(filename); 151: } 152: return nfound? 1: 0; 153: } 154: 155: /* 156: * put new name if list is not full or new name is less than the MAX 157: * now in the list. 158: * 159: */ 160: 161: /* LOCAL only */ 162: int 163: entflst(file) 164: register char *file; 165: { 166: register int i; 167: 168: /* locate position for the new file and make room for it */ 169: for (i = Nfiles; i > 0; i--) { 170: if (pcompar(file, Filent[i-1]) <= 0) 171: break; 172: if (i <LLEN) 173: strcpy(Filent[i], Filent[i-1]); 174: } 175: 176: /* add new file (if there is room), and increase Nfiles if need be */ 177: if (i < LLEN) { 178: strcpy(Filent[i], file); 179: if (Nfiles < LLEN) 180: Nfiles++; 181: } 182: } 183: 184: /* 185: Compare priority of filenames p1 and p2. Return: 186: * < 0 if p1 "has lower priority than" p2. 187: * = 0 if p1 "has priority equal to" p2. 188: * > 0 if p1 "has greater priority than" p2. 189: * Priority: 190: * lower grade wins. 191: * lower sequence number wins (unless wrap-around is suspected). 192: * 193: */ 194: /* LOCAL only */ 195: int 196: pcompar(p1, p2) 197: register char *p1, *p2; 198: { 199: register int rc; 200: 201: /* assert: strlen(p1) and strlen(p2) are >= 5 */ 202: p1 += strlen(p1)-5; 203: p2 += strlen(p2)-5; 204: /* check 'grade' */ 205: if (rc = *p2++ - *p1++) 206: return rc; 207: /* check for sequence wrap-around */ 208: if (rc = *p2++ - *p1++) 209: if (rc < -10 || rc > 10) 210: return -rc; 211: else 212: return rc; 213: /* check remaining digits */ 214: return strcmp(p2, p1); 215: } 216: 217: /* 218: * get next work file 219: * 220: * return value: 221: * 222: * 0 - No file gotten 223: * 1 - File successfully gotten. 224: * 225: */ 226: 227: /* LOCAL only */ 228: gtwrkf(dir, file) 229: char *file, *dir; 230: { 231: register int i; 232: 233: if (Nfiles-- <= 0) { 234: Nfiles = 0; 235: return 0; 236: } 237: sprintf(file, "%s/%s", dir, Filent[0]); 238: for (i=0; i<Nfiles;i++) 239: strcpy(Filent[i], Filent[i+1]); 240: return 1; 241: } 242: 243: /* 244: * get work vector 245: * 246: * return codes: 247: * positive number - number of arguments 248: * 0 - no arguments - fail 249: */ 250: 251: /* EXTERNALLY CALLED */ 252: int 253: gtwvec(file, dir, wkpre, wrkvec) 254: char *dir, *wkpre, **wrkvec; 255: register char *file; 256: { 257: register int nargs, n; 258: 259: n = 0; 260: while ((nargs = anlwrk(file, wrkvec)) == 0) { 261: if (++n > 3 || !iswrk(file, "get", dir, wkpre)) 262: return 0; 263: } 264: return nargs; 265: } 266: 267: /* 268: * iswrk - this routine will check the work list (list). 269: * If it is empty or the present work is exhausted, it 270: * will call bldflst to generate a new list. 271: * The "reqst" field will be the string "chk" or "get" to 272: * check for work, or get the next work file respectively. 273: * 274: * return codes: 275: * 0 - no more work (or some error) 276: * 1 - there is work 277: * 278: */ 279: 280: /* EXTERNALLY CALLED */ 281: int 282: iswrk(file, reqst, dir, pre) 283: register char *file, *reqst, *dir, *pre; 284: { 285: static char *lastpre = 0; 286: register ret; 287: 288: /* Starting new system; re-init */ 289: if (lastpre == 0 || strcmp(lastpre,pre) != 0) { 290: anlwrk ("", (char **)0); /* Force close of work file */ 291: 292: /* Save last worked-on prefix */ 293: if (lastpre != 0) 294: free (lastpre); 295: lastpre = (char *)malloc((unsigned)(strlen(pre)+1)); 296: strcpy (lastpre, pre); 297: 298: /* Set the external indexes properly 299: */ 300: Nfiles = 0; 301: } 302: 303: /* If the list is empty or new files have entered 304: * the spool area, call "bldflst" to read 305: * some file names into it. Because names can 306: * be put in the list that later turn out to 307: * be unusable (from "gtwrkf"), this operation 308: * continues until either "bldflst" can't find 309: * any new files, or "gtwrkf" signals success. 310: */ 311: for (;;) { 312: ret = 0; 313: if (Nfiles <= 0 || newspool((time_t)TLIMIT)) { 314: ret = bldflst (reqst, dir, pre); 315: DEBUG(99,"bldflst returns %d\n",ret); 316: } 317: 318: /* If they only wanted to check, return 319: * boolean list not empty. NB: the list 320: * will be forcibly emptied as soon as 321: * a new system name is mentioned. 322: */ 323: if (*reqst == 'c') 324: return ret; 325: 326: if (Nfiles <= 0) 327: return 0; 328: 329: if (gtwrkf(dir, file)) 330: return 1; 331: } 332: } 333: 334: /* Return non-zero if there is new work in the spool 335: * area since last check. Assumes that if the sequence 336: * file has been modified, there is new work. This is 337: * not absolutely correct, but should be close enough. 338: * Only checks every <limit> seconds at most. Called 339: * from "iswrk()" when a new work file is requested. 340: */ 341: /* LOCAL only */ 342: int 343: newspool(limit) 344: time_t limit; 345: { 346: static time_t lastcheck = 0, lastmod = 0; 347: time_t check; 348: struct stat mod; 349: register int ret = 0; 350: 351: /* (void) */ time (&check); 352: if (check - lastcheck > limit || lastcheck - check > limit) { 353: mod.st_mtime = 0; 354: /* (void) */ stat (SEQFILE, &mod); 355: if (mod.st_mtime != lastmod) 356: ret = 1; 357: lastmod = mod.st_mtime; 358: } 359: lastcheck = check; 360: return ret; 361: }