1 /*- 2 * Copyright (c) 1985 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)anlwrk.c 5.9 (Berkeley) 04/24/91"; 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 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 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 */ 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 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 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 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