148652Sbostic /*-
2*62386Sbostic * Copyright (c) 1985, 1993
3*62386Sbostic * The Regents of the University of California. All rights reserved.
448652Sbostic *
548652Sbostic * %sccs.include.proprietary.c%
648652Sbostic */
748652Sbostic
813634Ssam #ifndef lint
9*62386Sbostic static char sccsid[] = "@(#)anlwrk.c 8.1 (Berkeley) 06/06/93";
1048652Sbostic #endif /* not lint */
1113634Ssam
1213634Ssam #include "uucp.h"
1313634Ssam #include <sys/stat.h>
1417766Sralph #include "uust.h"
1513634Ssam #ifdef NDIR
1613634Ssam #include "ndir.h"
1713634Ssam #else
1813701Ssam #include <sys/dir.h>
1913634Ssam #endif
2018615Sralph #include <ctype.h>
2113634Ssam
2233558Srick #define TLIMIT (15*60L)
2313634Ssam #define NITEMS(X) (sizeof (X) / sizeof ((X)[0]))
2413634Ssam
2517766Sralph int Nfiles = 0;
2617766Sralph char Filent[LLEN][NAMESIZE];
2718615Sralph extern int TransferSucceeded;
2813634Ssam
2923584Sbloom /*LINTLIBRARY*/
3023584Sbloom
3118615Sralph /*
3218615Sralph * create a vector of command arguments
3313634Ssam *
3413634Ssam * return codes:
3513634Ssam * 0 - no more work in this file
3613634Ssam * positive number - number of arguments
3713634Ssam */
3813634Ssam
3913634Ssam /* LOCAL only */
4013634Ssam int
anlwrk(file,wvec)4113634Ssam anlwrk(file, wvec)
4213634Ssam register char *file, **wvec;
4313634Ssam {
4423584Sbloom static char str[MAXRQST], nstr[MAXRQST], lastfile[MAXFULLNAME] = "";
4513634Ssam static FILE *fp = NULL;
4618615Sralph static long nextread, nextwrite;
4713634Ssam
4817766Sralph /*
4917766Sralph * If called with a null string, force a shutdown
5013634Ssam * of the current work file.
5113634Ssam */
5213634Ssam if (file[0] == '\0') {
5313634Ssam if (fp != NULL)
5413634Ssam fclose (fp);
5513634Ssam fp = NULL;
5617766Sralph return 0;
5713634Ssam }
5813634Ssam if (fp == NULL) {
5923584Sbloom if (strncmp(file, lastfile, MAXFULLNAME) == 0) {
6023584Sbloom DEBUG(5,"Workfilename repeated: %s\n", file);
6123584Sbloom return 0;
6223584Sbloom }
6323584Sbloom strncpy(lastfile, file, MAXFULLNAME);
6418615Sralph fp = fopen(subfile(file), "r+w");
6513634Ssam if (fp == NULL) {
6618615Sralph char *bnp, rqstr[MAXFULLNAME];
6718615Sralph bnp = rindex(file, '/');
6818615Sralph sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : file);
6918615Sralph xmv(file, rqstr);
7033943Srick syslog(LOG_WARNING, "fopen(%s) failed: %m",
7133943Srick subfile(file));
7217766Sralph unlink(subfile(file));
7317766Sralph return 0;
7413634Ssam }
7517766Sralph Usrf = 0;
7618615Sralph nstr[0] = '\0';
7718615Sralph nextread = nextwrite = 0L;
7813634Ssam }
7913634Ssam
8018615Sralph if (nstr[0] != '\0' && TransferSucceeded) {
8118615Sralph fseek(fp, nextwrite, 0);
8218615Sralph fputs(nstr, fp);
8318615Sralph fseek(fp, nextread, 0);
8413634Ssam }
8518615Sralph
8618615Sralph do {
8718615Sralph nextwrite = ftell(fp);
8818615Sralph if (fgets(str, MAXRQST, fp) == NULL) {
8918615Sralph fclose(fp);
9018615Sralph if (TransferSucceeded)
9118615Sralph unlink(subfile(file));
9218615Sralph USRF(USR_COMP);
9318615Sralph US_RRS(file, Usrf);
9418615Sralph Usrf = 0;
9518615Sralph file[0] = '\0';
9623584Sbloom nstr[0] = '\0';
9718615Sralph fp = NULL;
9818615Sralph return 0;
9918615Sralph }
10018615Sralph } while (!isupper(str[0]));
10118615Sralph
10218615Sralph nextread = ftell(fp);
10318615Sralph strncpy(nstr, str, MAXRQST);
10418615Sralph nstr[0] = tolower(nstr[0]);
10517766Sralph return getargs(str, wvec, 20);
10613634Ssam }
10713634Ssam
10813634Ssam
10918615Sralph /*
11018615Sralph * build list of work files for given system
11113634Ssam *
11213634Ssam * return value - 1 if work was found, else 0
11313634Ssam *
11413634Ssam */
11513634Ssam
11613634Ssam /* LOCAL only */
11713634Ssam int
bldflst(reqst,dir,pre)11813634Ssam bldflst (reqst, dir, pre)
11913634Ssam char *reqst;
12013634Ssam register char *dir, *pre;
12113634Ssam {
12213634Ssam static DIR *dirp = NULL;
12333558Srick register struct direct *dentp;
12433558Srick register int i;
12533558Srick int plen = strlen(pre);
12617766Sralph extern char MaxGrade;
12713634Ssam
12813634Ssam if (dirp == NULL) {
12917766Sralph if ((dirp = opendir(subdir(dir,pre[0]))) == NULL) {
13017766Sralph DEBUG(1,"opendir(%s) FAILS\n",subdir(dir,pre[0]));
13117766Sralph return 0;
13217766Sralph }
13333558Srick } else
13413634Ssam rewinddir(dirp);
13533558Srick
13633558Srick Nfiles = 0;
13733558Srick while ((dentp = readdir(dirp)) != NULL && Nfiles < LLEN) {
13813634Ssam /* Check for two systems with the same prefix.
13913634Ssam * Magic number "5" is 1 for "grade" character plus
14013634Ssam * 4 for sequence number. The point here is to not
14113634Ssam * send work for a system which has as a prefix the
14213634Ssam * name of the system called for.
14313634Ssam * Special case: prefix "X." does not do this check
14413634Ssam * so uuxqt can use bldflst.
14513634Ssam */
14633558Srick if (!prefix(pre, dentp->d_name) ||
14733558Srick (plen != 2 && (dentp->d_namlen-plen) != 5)) {
14833558Srick DEBUG(99,"bldflst rejects %s\n",dentp->d_name);
14913634Ssam continue;
15017766Sralph }
15133558Srick if (dentp->d_name[dentp->d_namlen-5] > MaxGrade) {
15233558Srick DEBUG(8, "bldflst rejects %s, grade too low\n",
15333558Srick dentp->d_name);
15417766Sralph continue;
15517766Sralph }
15613634Ssam if (*reqst == 'c')
15717766Sralph return 1;
15813634Ssam
15933558Srick /* locate position for the new file and make room for it */
16033558Srick for (i = Nfiles; i > 0; i--) {
16133558Srick if (pcompar(dentp->d_name, Filent[i-1]) <= 0)
16233558Srick break;
16333558Srick if (i <LLEN)
16433558Srick strcpy(Filent[i], Filent[i-1]);
16533558Srick }
16613634Ssam
16733558Srick /* add new file (if there is room), and increase Nfiles if need be */
16833558Srick if (i < LLEN) {
16933558Srick DEBUG(99,"bldflst accepts %s",dentp->d_name);
17033558Srick DEBUG(99," as Filent[%d]\n", i);
17133558Srick strcpy(Filent[i], dentp->d_name);
17233558Srick if (Nfiles < LLEN)
17333558Srick Nfiles++;
17433558Srick } else
17533558Srick DEBUG(99,"Filent full, %s rejected by bldflst\n", dentp->d_name);
17633558Srick
17713634Ssam
17813634Ssam }
17933558Srick if (Debug >99)
18033558Srick for(i=0;i<Nfiles;i++)
18133558Srick fprintf(stderr,"Filent[%d]=%s\n",i,Filent[i]);
18213634Ssam
18333558Srick return Nfiles > 0;
18413634Ssam }
18513634Ssam
18613634Ssam /*
18713634Ssam Compare priority of filenames p1 and p2. Return:
18813634Ssam * < 0 if p1 "has lower priority than" p2.
18913634Ssam * = 0 if p1 "has priority equal to" p2.
19013634Ssam * > 0 if p1 "has greater priority than" p2.
19113634Ssam * Priority:
19213634Ssam * lower grade wins.
19313634Ssam * lower sequence number wins (unless wrap-around is suspected).
19413634Ssam *
19513634Ssam */
19613634Ssam /* LOCAL only */
pcompar(p1,p2)19713634Ssam pcompar(p1, p2)
19813634Ssam register char *p1, *p2;
19913634Ssam {
20013634Ssam register int rc;
20113634Ssam
20233943Srick /* strlen(p1) and strlen(p2) are >= 5 */
20313634Ssam p1 += strlen(p1)-5;
20413634Ssam p2 += strlen(p2)-5;
20513634Ssam /* check 'grade' */
20613634Ssam if (rc = *p2++ - *p1++)
20717766Sralph return rc;
20813634Ssam /* check for sequence wrap-around */
20913634Ssam if (rc = *p2++ - *p1++)
21013634Ssam if (rc < -10 || rc > 10)
21117766Sralph return -rc;
21213634Ssam else
21317766Sralph return rc;
21413634Ssam /* check remaining digits */
21517766Sralph return strcmp(p2, p1);
21613634Ssam }
21713634Ssam
21818615Sralph /*
21918615Sralph * get work vector
22013634Ssam *
22113634Ssam * return codes:
22213634Ssam * positive number - number of arguments
22313634Ssam * 0 - no arguments - fail
22413634Ssam */
22513634Ssam
22613634Ssam /* EXTERNALLY CALLED */
22713634Ssam int
gtwvec(file,dir,wkpre,wrkvec)22813634Ssam gtwvec(file, dir, wkpre, wrkvec)
22913634Ssam char *dir, *wkpre, **wrkvec;
23013634Ssam register char *file;
23113634Ssam {
23213634Ssam register int nargs, n;
23313634Ssam
23417766Sralph n = 0;
23513634Ssam while ((nargs = anlwrk(file, wrkvec)) == 0) {
23613634Ssam if (++n > 3 || !iswrk(file, "get", dir, wkpre))
23717766Sralph return 0;
23813634Ssam }
23917766Sralph return nargs;
24013634Ssam }
24113634Ssam
24218615Sralph /*
24313634Ssam * iswrk - this routine will check the work list (list).
24413634Ssam * If it is empty or the present work is exhausted, it
24513634Ssam * will call bldflst to generate a new list.
24613634Ssam * The "reqst" field will be the string "chk" or "get" to
24713634Ssam * check for work, or get the next work file respectively.
24813634Ssam *
24913634Ssam * return codes:
25013634Ssam * 0 - no more work (or some error)
25113634Ssam * 1 - there is work
25213634Ssam *
25313634Ssam */
25413634Ssam
25513634Ssam /* EXTERNALLY CALLED */
25613634Ssam int
iswrk(file,reqst,dir,pre)25713634Ssam iswrk(file, reqst, dir, pre)
25813634Ssam register char *file, *reqst, *dir, *pre;
25913634Ssam {
26013634Ssam static char *lastpre = 0;
26133558Srick register ret = 0;
26233558Srick int i;
26313634Ssam
26413634Ssam /* Starting new system; re-init */
26533558Srick if (lastpre == 0 || strcmp(lastpre, pre) != SAME) {
26633558Srick /* Force close of work file */
26733558Srick anlwrk("", (char **)0);
26813634Ssam
26913634Ssam /* Save last worked-on prefix */
27013634Ssam if (lastpre != 0)
27133558Srick free(lastpre);
27213634Ssam lastpre = malloc((unsigned)(strlen(pre)+1));
27333558Srick strcpy(lastpre, pre);
27413634Ssam
27533558Srick /* Set the external indexes properly */
27613634Ssam Nfiles = 0;
27713634Ssam }
27813634Ssam
27933558Srick /*
28033558Srick * If the list is empty or new files have entered
28113634Ssam * the spool area, call "bldflst" to read
28233558Srick * some file names into it.
28313634Ssam */
28433558Srick if (Nfiles <= 0 || newspool((time_t)TLIMIT)) {
28533558Srick ret = bldflst(reqst, dir, pre);
28633558Srick DEBUG(99, "bldflst returns %d\n", ret);
28733558Srick }
28813634Ssam
28933558Srick /* If they only wanted to check, return
29033558Srick * boolean list not empty. NB: the list
29133558Srick * will be forcibly emptied as soon as
29233558Srick * a new system name is mentioned.
29333558Srick */
29433558Srick if (*reqst == 'c')
29533558Srick return ret;
29613634Ssam
29733558Srick if (Nfiles-- <= 0) {
29833558Srick /* Didn't find any files in the spool area */
29933558Srick Nfiles = 0;
30033558Srick return 0;
30113634Ssam }
30233558Srick /* Found some files, return the first one */
30333558Srick sprintf(file, "%s/%s", dir, Filent[0]);
30433558Srick for (i = 0; i < Nfiles; i++)
30533558Srick strcpy(Filent[i], Filent[i+1]);
30633558Srick return 1;
30713634Ssam }
30813634Ssam
30913634Ssam /* Return non-zero if there is new work in the spool
31013634Ssam * area since last check. Assumes that if the sequence
31113634Ssam * file has been modified, there is new work. This is
31213634Ssam * not absolutely correct, but should be close enough.
31313634Ssam * Only checks every <limit> seconds at most. Called
31413634Ssam * from "iswrk()" when a new work file is requested.
31513634Ssam */
31613634Ssam /* LOCAL only */
31713634Ssam int
newspool(limit)31813634Ssam newspool(limit)
31913634Ssam time_t limit;
32013634Ssam {
32113634Ssam static time_t lastcheck = 0, lastmod = 0;
32213634Ssam time_t check;
32313634Ssam struct stat mod;
32413634Ssam register int ret = 0;
32513634Ssam
32613634Ssam /* (void) */ time (&check);
32713634Ssam if (check - lastcheck > limit || lastcheck - check > limit) {
32813634Ssam mod.st_mtime = 0;
32913634Ssam /* (void) */ stat (SEQFILE, &mod);
33013634Ssam if (mod.st_mtime != lastmod)
33113634Ssam ret = 1;
33213634Ssam lastmod = mod.st_mtime;
33313634Ssam }
33413634Ssam lastcheck = check;
33517766Sralph return ret;
33613634Ssam }
337