1: #ifndef lint 2: static char sccsid[] = "@(#)anlwrk.c 5.5 (Berkeley) 6/19/85"; 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: 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: logent(subfile(file), "CMD FILE UNREADABLE"); 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 nfound; 117: char filename[NAMESIZE]; 118: int plen = strlen (pre); 119: int flen; 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: } 128: else 129: rewinddir(dirp); 130: for (nfound = 0, Nfiles = 0; gnamef(dirp, filename);) { 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: flen = strlen(filename); 140: if (!prefix(pre, filename) || (plen != 2 && flen-plen != 5)) { 141: DEBUG(99,"bldflst rejects %s\n",filename); 142: continue; 143: } 144: if (filename[flen-5] > MaxGrade ) { 145: DEBUG(8,"bldflst rejects %s, grade too low\n",filename); 146: continue; 147: } 148: nfound++; 149: if (*reqst == 'c') 150: return 1; 151: entflst(filename); 152: } 153: return nfound? 1: 0; 154: } 155: 156: /* 157: * put new name if list is not full or new name is less than the MAX 158: * now in the list. 159: * 160: */ 161: 162: /* LOCAL only */ 163: int 164: entflst(file) 165: register char *file; 166: { 167: register int i; 168: 169: /* locate position for the new file and make room for it */ 170: for (i = Nfiles; i > 0; i--) { 171: if (pcompar(file, Filent[i-1]) <= 0) 172: break; 173: if (i <LLEN) 174: strcpy(Filent[i], Filent[i-1]); 175: } 176: 177: /* add new file (if there is room), and increase Nfiles if need be */ 178: if (i < LLEN) { 179: strcpy(Filent[i], file); 180: if (Nfiles < LLEN) 181: Nfiles++; 182: } 183: } 184: 185: /* 186: Compare priority of filenames p1 and p2. Return: 187: * < 0 if p1 "has lower priority than" p2. 188: * = 0 if p1 "has priority equal to" p2. 189: * > 0 if p1 "has greater priority than" p2. 190: * Priority: 191: * lower grade wins. 192: * lower sequence number wins (unless wrap-around is suspected). 193: * 194: */ 195: /* LOCAL only */ 196: int 197: pcompar(p1, p2) 198: register char *p1, *p2; 199: { 200: register int rc; 201: 202: /* assert: 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 next work file 220: * 221: * return value: 222: * 223: * 0 - No file gotten 224: * 1 - File successfully gotten. 225: * 226: */ 227: 228: /* LOCAL only */ 229: gtwrkf(dir, file) 230: char *file, *dir; 231: { 232: register int i; 233: 234: if (Nfiles-- <= 0) { 235: Nfiles = 0; 236: return 0; 237: } 238: sprintf(file, "%s/%s", dir, Filent[0]); 239: for (i=0; i<Nfiles;i++) 240: strcpy(Filent[i], Filent[i+1]); 241: return 1; 242: } 243: 244: /* 245: * get work vector 246: * 247: * return codes: 248: * positive number - number of arguments 249: * 0 - no arguments - fail 250: */ 251: 252: /* EXTERNALLY CALLED */ 253: int 254: gtwvec(file, dir, wkpre, wrkvec) 255: char *dir, *wkpre, **wrkvec; 256: register char *file; 257: { 258: register int nargs, n; 259: 260: n = 0; 261: while ((nargs = anlwrk(file, wrkvec)) == 0) { 262: if (++n > 3 || !iswrk(file, "get", dir, wkpre)) 263: return 0; 264: } 265: return nargs; 266: } 267: 268: /* 269: * iswrk - this routine will check the work list (list). 270: * If it is empty or the present work is exhausted, it 271: * will call bldflst to generate a new list. 272: * The "reqst" field will be the string "chk" or "get" to 273: * check for work, or get the next work file respectively. 274: * 275: * return codes: 276: * 0 - no more work (or some error) 277: * 1 - there is work 278: * 279: */ 280: 281: /* EXTERNALLY CALLED */ 282: int 283: iswrk(file, reqst, dir, pre) 284: register char *file, *reqst, *dir, *pre; 285: { 286: static char *lastpre = 0; 287: register ret; 288: 289: /* Starting new system; re-init */ 290: if (lastpre == 0 || strcmp(lastpre,pre) != 0) { 291: anlwrk ("", (char **)0); /* Force close of work file */ 292: 293: /* Save last worked-on prefix */ 294: if (lastpre != 0) 295: free (lastpre); 296: lastpre = malloc((unsigned)(strlen(pre)+1)); 297: strcpy (lastpre, pre); 298: 299: /* Set the external indexes properly 300: */ 301: Nfiles = 0; 302: } 303: 304: /* If the list is empty or new files have entered 305: * the spool area, call "bldflst" to read 306: * some file names into it. Because names can 307: * be put in the list that later turn out to 308: * be unusable (from "gtwrkf"), this operation 309: * continues until either "bldflst" can't find 310: * any new files, or "gtwrkf" signals success. 311: */ 312: for (;;) { 313: ret = 0; 314: if (Nfiles <= 0 || newspool((time_t)TLIMIT)) { 315: ret = bldflst (reqst, dir, pre); 316: DEBUG(99,"bldflst returns %d\n",ret); 317: } 318: 319: /* If they only wanted to check, return 320: * boolean list not empty. NB: the list 321: * will be forcibly emptied as soon as 322: * a new system name is mentioned. 323: */ 324: if (*reqst == 'c') 325: return ret; 326: 327: if (Nfiles <= 0) 328: return 0; 329: 330: if (gtwrkf(dir, file)) 331: return 1; 332: } 333: } 334: 335: /* Return non-zero if there is new work in the spool 336: * area since last check. Assumes that if the sequence 337: * file has been modified, there is new work. This is 338: * not absolutely correct, but should be close enough. 339: * Only checks every <limit> seconds at most. Called 340: * from "iswrk()" when a new work file is requested. 341: */ 342: /* LOCAL only */ 343: int 344: newspool(limit) 345: time_t limit; 346: { 347: static time_t lastcheck = 0, lastmod = 0; 348: time_t check; 349: struct stat mod; 350: register int ret = 0; 351: 352: /* (void) */ time (&check); 353: if (check - lastcheck > limit || lastcheck - check > limit) { 354: mod.st_mtime = 0; 355: /* (void) */ stat (SEQFILE, &mod); 356: if (mod.st_mtime != lastmod) 357: ret = 1; 358: lastmod = mod.st_mtime; 359: } 360: lastcheck = check; 361: return ret; 362: }