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