/***************************************************************************
 *                                                                         *
 *   GALFILCS.C                                                            *
 *                                                                         *
 *   Copyright (c) 1994-1997 Galacticomm, Inc.  All rights reserved.       *
 *                                                                         *
 *   This is the Galacticomm Client/Server File Library agent.             *
 *                                                                         *
 *                                              - D. Pitchford 9/7/94      *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "gcspsrv.h"
#include "filexfer.h"
#include "reserve.h"
#include "galfilh.h"
#include "galfil.h"

#define FILREV "$Revision: 31 $"

static VOID filwrite(struct saunam *dpknam,USHORT length,VOID *value);
static VOID filxdone(VOID);
static VOID filabort(VOID);
static VOID filread(INT direction,struct saunam *dpknam);
static struct fllib *dirlib(INT direction,CHAR *libname,GBOOL visonly);
static INT findaxs(INT direction,CHAR *libname);
static VOID filfs(INT direction);
static VOID fileinfo(VOID);
static VOID download(VOID);
static GBOOL respcdfile(VOID);
static VOID upload(struct filinf *fd);
static VOID moddesc(CHAR *desc);
static GBOOL genchek(CHAR *action,GBOOL nodos,GBOOL nocd);
static VOID approve(CHAR *datstr);
static VOID rendel(CHAR *newname);
static VOID csmvcpy(GBOOL move,CHAR *destlib);
static VOID csmcfile(VOID);
static VOID viewcomp(VOID);
static VOID viewtext(VOID);
static INT gotsrch(VOID);
static VOID cntview(VOID);
static VOID cycsrch(VOID);
static VOID updsuff(CHAR *suffix);
static struct fsdpk *flfrsp(GBOOL isdos,GBOOL verbose);
static VOID fildfts(VOID);
static VOID filibaxs(INT direction);
static VOID fillist(INT direction);
static VOID filunaps(INT direction);
static VOID filinfo(INT direction);
static VOID filjoin(INT direction);
static VOID filibedt(INT direction);
static VOID filjoins(INT direction);
static VOID wfiljoin(GBOOL join);
static VOID delalib(struct fllib *libptr);
static VOID dlibrou(VOID);
static VOID libedup(CHAR *libname,struct fllib *libptr);
VOID sendjoin(VOID);
static VOID reqcono(CHAR *value);
static VOID reqconn(CHAR *value);
static VOID reqcond(CHAR *value);
static VOID reqconf(CHAR *value);
static VOID reqconk(CHAR *value);
static VOID searcho(CHAR *nam,INT direction);
static VOID searchn(CHAR *nam,INT direction);
static VOID searchd(CHAR *nam,INT direction);
static VOID searchf(CHAR *nam,INT direction);
static VOID searchk(CHAR *nam,INT direction);
static GBOOL context(GBOOL get);
static GBOOL hascontext(VOID);
static INT cslibrsv(CHAR *lib,CHAR *fil);
static VOID copywait(VOID);
static VOID sendfile(CHAR *path);
static VOID uplerror(VOID);
static VOID finupl(VOID);
static VOID cskwdins(VOID);
static VOID filldesc(VOID);
static GBOOL isok2ul(GBOOL reserve);
static VOID delfile(VOID);
static VOID delkwds(VOID);
static VOID renkwds(VOID);
static VOID inimaint(GBOOL datype,GBOOL write,GBOOL approve,CHAR *libname);
static VOID maintit(VOID);
static VOID dlerr(VOID);
static VOID csunapan(VOID);
static VOID reg_dpk(VOID);
static VOID srcsmake(VOID);

static
struct agent filagt={              /* agent information structure          */
     "GALFIL",                     /*   appid                              */
     filread,                      /*   read-dynapak function pointer      */
     filwrite,                     /*   write-dynapak function pointer     */
     filxdone,                     /*   file xfer-done function pointer    */
     filabort                      /*   abort-request function pointer     */
};

#define XLDATLEN 600               /* max. length of space in xlibinfo     */

static
struct xlibinfo {                  /* extended Library information struct  */
     LONG totfiles;                /*   total files in Library             */
     SHORT addtoday;               /*   files added today                  */
     SHORT addweek;                /*   files added this week              */
     LONG maxfil;                  /*   max files in Library               */
     LONG maxbyt;                  /*   max bytes in Library               */
     LONG maxbup;                  /*   max upload size                    */
     CHAR data[XLDATLEN];          /*   space for strings                  */
} *xli;                            /* instance for reading information     */

struct flddef xlibinfoFDA[] = {
     { CVTFLD_LONG  ,1        ,fldoff(xlibinfo,totfiles)    ,NULL },
     { CVTFLD_SHORT ,2        ,fldoff(xlibinfo,addtoday)    ,NULL },
     { CVTFLD_LONG  ,3        ,fldoff(xlibinfo,maxfil)      ,NULL },
     { CVTFLD_RTEXT ,0        ,fldoff(xlibinfo,data)        ,NULL },
     { CVTFLD_END   ,0        ,0                            ,NULL }
};

static
struct llistinf {                  /* Library information struct           */
     LONG numfiles;                /*   number of files in Library         */
     SHORT flags;                  /*   bitflags (see below)               */
     CHAR desc[FLDESCSZ];          /*   short Library description          */
} *lli;                            /* instance for reading information     */

struct flddef llistinfFDA[] = {
     { CVTFLD_LONG  ,1        ,fldoff(llistinf,numfiles)    ,NULL },
     { CVTFLD_SHORT ,1        ,fldoff(llistinf,flags)       ,NULL },
     { CVTFLD_RTEXT ,0        ,fldoff(llistinf,desc)        ,NULL },
     { CVTFLD_END   ,0        ,0                            ,NULL }
};

#define LLISDOS 0x0001             /* flag for lli, DOS-Only Library       */
#define LLISUPL 0x0002             /* flag for lli, Lib uploadable to      */
#define LLISLOP 0x0004             /* flag for lli, LibOp access           */
#define LLISACD 0x0008             /* flag for lli, Library on CD          */
#define LLISHID 0x0010             /* flag for lli, Library hidden         */

struct libcsfil *lcsu,*lcsarr,*viewarr; /* files used by c/s users         */

static
struct libcsed {
     SHORT flags;                  /*   bitflags for Library, translated   */
     DOUBLE created;               /*   VB date & time Library created     */
     LONG dlchge;                  /*   credit charge per file to download */
     LONG kdlchge;                 /*   credit charge per K to download    */
     SHORT royal;                  /*   royalty percentage                 */
     LONG maxfil;                  /*   maximum # of files in Library      */
     LONG maxbyt;                  /*   maximum # of bytes in Library      */
     LONG maxbup;                  /*   maximum # of bytes per upload      */
     CHAR data[XLDATLEN];          /*   space for strings                  */
} *eli;                            /* instance for reading information     */

struct flddef libcsedFDA[] = {
     { CVTFLD_SHORT ,1        ,fldoff(libcsed,flags)   ,NULL },
     { CVTFLD_DOUBLE,1        ,fldoff(libcsed,created) ,NULL },
     { CVTFLD_LONG  ,2        ,fldoff(libcsed,dlchge)  ,NULL },
     { CVTFLD_SHORT ,1        ,fldoff(libcsed,royal)   ,NULL },
     { CVTFLD_LONG  ,3        ,fldoff(libcsed,maxfil)  ,NULL },
     { CVTFLD_RTEXT ,0        ,fldoff(libcsed,data)    ,NULL },
     { CVTFLD_END   ,0        ,0                       ,NULL }
};

#define ELIDOS 0x0001              /* flag for eli, DOS-Only Library       */
#define ELIRON 0x0002              /* flag for eli, Read-Only Library      */
#define ELIHID 0x0004              /* flag for eli, Hidden Library         */
#define ELISCD 0x0008              /* flag for eli, Library on CD          */
#define ELIADD 0x0010              /* flag for eli, Audit Downloads        */
#define ELIADU 0x0020              /* flag for eli, Audit Uploads          */
#define ELINCD 0x0040              /* flag for eli, No-charge Downloads    */
#define ELINCU 0x0080              /* flag for eli, No-charge Uploads      */
#define ELIAUD 0x0100              /* flag for eli, Always Audit UL/DL     */
#define ELIFUD 0x0200              /* flag for eli, Always Free Uploads    */

struct dlibrqi {                   /* delete-library request information   */
     INT reqtype;                  /*   type of request, if needed         */
     INT phase;                    /*   0=filedat 1=keywds 2=lib, then done*/
     CHAR libname[FLNAMESZ];       /*   library being deleted              */
     CHAR filname[FLFILENM];       /*   current file being deleted         */
};

#define dlqptr ((struct dlibrqi *)mrqptr)

struct srchrqi {                   /* cycled-search request information    */
     INT reqtype;                  /*   type of request, if needed         */
     CHAR libname[FLNAMESZ];       /*   library of last record             */
     CHAR filname[FLFILENM];       /*   file of last record                */
     CHAR other[FLKEYSIZ];         /*   date or # d/ls of last record      */
};                                 /*    (use max(DATESZ,NUMSZ,FLKEYSIZ)   */

#define srchptr ((struct srchrqi *)mrqptr)

struct ulrqi {                     /* write/file request information       */
     INT reqtype;                  /*   type of request, if needed         */
     CHAR libname[FLNAMESZ];       /*   library involved                   */
     CHAR filname[FLFILENM];       /*   file involved                      */
     CHAR newlib[FLNAMESZ];        /*   new library     (keywords)         */
     CHAR newname[FLFILENM];       /*   new file name   (keywords)         */
     GBOOL move;                   /*   file/kw move?    FALSE = copy      */
     GBOOL app;                    /*   approve file on login (maint)      */
     USHORT date;                  /*   date of file  (uploading)          */
     USHORT time;                  /*   time of file  (uploading)          */
     LONG size;                    /*   size of file  (uploading)          */
     INT status;                   /*   operation status                   */
     FILE *src;                    /*   source file pointer                */
     FILE *dst;                    /*   destination file pointer           */
     FILE *uzfp;                   /*   maint. file pointer                */
     struct ffblk fb;             /*   per-request dir data               */
};

#define ulptr ((struct ulrqi *)mrqptr)

#define ulkey(p) compkey(p->libname,p->filname)

#define ULRNON 0                   /* request type: none                   */
#define ULRUPL 1                   /* request type: upload                 */
#define ULRDNL 2                   /* request type: download               */
#define ULRTXT 3                   /* request type: viewtext               */
#define ULRMCP 4                   /* request type: move/copy              */
#define ULRMN0 5                   /* request type: maintenance type 0     */
#define ULRMN1 6                   /* request type: maintenance type 1     */
#define ULRZIP 7                   /* request type: unzipping in maint     */
#define ULRZPW 8                   /* request type: waiting to do desc     */

#define ULRVCM 20                  /* request type: viewing compressed     */

#define ULPONG 0                   /* upload status: file being sent       */
#define ULPCPY 1                   /* upload status: file being copied     */
#define ULPDAT 2                   /* upload status: data file insertion   */
#define ULPFIN 3                   /* upload status: finishing upload      */

#define MVCONG 0                   /* move/copy status: begin move/copy    */
#define MVCFIL 1                   /* move/copy status: copying bytes      */
#define MVCDAT 2                   /* move/copy status: file/lib data      */
#define MVCFIN 3                   /* move/copy status: finish up          */
#define MVCKWD 4                   /* move/copy status: keywords if needed */

struct fsdpk {                     /* file information return structure    */
     LONG cost;                    /*   approx. cost in credits to d/l     */
     LONG size;                    /*   file size                          */
     SHORT dltime;                 /*   apx download time in minutes       */
     SHORT flags;                  /*   flags on specific file             */
     DOUBLE filedt;                /*   file's date and time               */
     DOUBLE addedt;                /*   added date and time (0 = unapp'ed) */
     LONG numdls;                  /*   number of times downloaded         */
     CHAR data[UIDSIZ+DESCSIZ];    /*   short desc. or uploader & full desc*/
} *fsdpkr;

struct flddef fsdpkFDA[] = {
     { CVTFLD_LONG  ,2             ,fldoff(fsdpk,cost)      ,NULL },
     { CVTFLD_SHORT ,2             ,fldoff(fsdpk,dltime)    ,NULL },
     { CVTFLD_DOUBLE,2             ,fldoff(fsdpk,filedt)    ,NULL },
     { CVTFLD_LONG  ,1             ,fldoff(fsdpk,numdls)    ,NULL },
     { CVTFLD_RTEXT ,0             ,fldoff(fsdpk,data)      ,NULL },
     { CVTFLD_END   ,0             ,0                       ,NULL }
};

#define FSDTVIEW 0x0001            /* flag, file is viewable text          */
#define FSDCVIEW 0x0002            /* flag, file is viewable compressed    */
#define FSDLIBOP 0x0004            /* flag, user has libop authority       */
#define FSDISDOS 0x0008            /* flag, file in DOS-Only Lib           */

INT (*oldrsv)(CHAR *,CHAR *);      /* hook vector for old reserve call     */

GBOOL newjoins=FALSE;              /* are there new libraries joined?      */

static CHAR *uzbuf,                /* buffer for unzipping descriptions    */
             *lopcstg;             /* libop approve files command string   */

CHAR *cslkey=NULL;                 /* key required for C/S access          */

static GBOOL mainting=FALSE;       /* sysop currently using maint option?  */

VOID
init_cslib(VOID)                   /* initialize File Library for C/S mode */
{
     register_agent(&filagt);
     hook_connect(genlon);
     hook_disconnect(genhup);
     cslkey=stgopt(CSLKEY);
     lopcstg=stgopt(LOPCSTG);
     hook_announce(csunapan);
     dclmrq(sizeof(struct dlibrqi));
     dclmrq(sizeof(struct srchrqi));
     dclmrq(sizeof(struct ulrqi));
     xli=(struct xlibinfo *)alcmem(sizeof(struct xlibinfo));
     lli=(struct llistinf *)alcmem(sizeof(struct llistinf));
     eli=(struct libcsed *)alcmem(sizeof(struct libcsed));
     lcsarr=(struct libcsfil *)alczer(nterms*sizeof(struct libcsfil));
     viewarr=(struct libcsfil *)alczer(nterms*sizeof(struct libcsfil));
     uzbuf=alcmem(2049);
     oldrsv=librsv->amreading;
     librsv->amreading=cslibrsv;
     reg_dpk();
}

static VOID
filread(                           /* read-dynapak handler                 */
INT direction,                     /*   read direction: 0=eq, 1=gt, -1=lt  */
struct saunam *dpknam)             /*   dynapak name to read               */
{
     CHAR *dpkstg;

     setmbk(flmsg);
     fluoff(usrnum);
     *namtmp=*dpknam;
     dpkstg=cnvs2d(namtmp);
     if (!stdchk(cslkey)) {
          rejectreq();
          return;
     }
     if (!sameas(namtmp->usrid,usaptr->userid)) {
          if (samepato("sau:",dpkstg) || samepato("sauf:",dpkstg)) {
               rejectreq();
               return;
          }
     }
     ulptr->reqtype=ULRNON;
     if (samepato("sau:fs",dpkstg) && direction != 0) {
          filfs(direction);
          return;
     }
     if (samepato("sau:fileinfo ",dpkstg) && direction == 0) {
          fileinfo();
          return;
     }
     if (samepato("sauf:download ",dpkstg) && direction == 0) {
          download();
          return;
     }
     if (samepato("sau:viewcomp ",dpkstg) && direction == 0) {
          viewcomp();
          return;
     }
     if (samepato("sauf:viewtext ",dpkstg) && direction == 0) {
          viewtext();
          return;
     }
     if (samepato("sau:libaxs",dpkstg)
      && strlen(firstwd(namtmp->suffix)) == strlen("libaxs")) {
          filibaxs(direction);
          return;
     }
     if (samepato("sau:llist ",dpkstg)) {
          fillist(direction);
          return;
     }
     if (samepato("sau:lunaps ",dpkstg)) {
          filunaps(direction);
          return;
     }
     if (samepato("sau:linfo ",dpkstg)) {
          filinfo(direction);
          return;
     }
     if (samepato("sa:libdft",dpkstg) && haskey(flsysop)) {
          fildfts();
          return;
     }
     if (samepato("sa:ljoin ",dpkstg)) {
          filjoin(direction);
          return;
     }
     if (samepato("sa:libedit ",dpkstg) && haskey(flsysop)) {
          filibedt(direction);
          return;
     }
     if (samepato("sau:ljoinings ",dpkstg)) {
          filjoins(direction);
          return;
     }
     rejectreq();
}

static VOID
filwrite(                          /* write-dynapak handler                */
struct saunam *dpknam,             /*   dynapak name to write              */
USHORT length,                     /*   length of dynapak value            */
VOID *value)                       /*   dynapak value to write             */
{
     struct fllib *libptr;
     CHAR *dpkstg,libname[FLNAMESZ],*s;
     GBOOL join,datype,write,app;
     INT i;

     setmbk(flmsg);
     fluoff(usrnum);
     *namtmp=*dpknam;
     dpkstg=cnvs2d(namtmp);
     if (!stdchk(cslkey)) {
          rejectreq();
          return;
     }
     if (!sameas(namtmp->usrid,usaptr->userid)) {
          if (samepato("sau:",dpkstg) || samepato("sauf:",dpkstg)) {
               rejectreq();
               return;
          }
     }
     ulptr->reqtype=ULRNON;
     if (haskey(flsysop)) {
          if (samepato("sau:maint ",dpkstg)) {
               firstwd(namtmp->suffix);
               datype=sameas(nextwd(),"1");
               write=!sameas(s=nextwd(),"0");
               app=sameas(s,"2");
               inimaint(datype,write,app,length == 0 ? "" : value);
               return;
          }
          if (samepato("sa:ljoin ",dpkstg) && length > 0) {
               if ((join=sameto("1",value)) != FALSE || sameto("0",value)) {
                    wfiljoin(join);
               }
               else {
                    rejectreq();
               }
               return;
          }
          if (samepato("sa:libedit ",dpkstg)) {
               stzcpy(libname,lastwd(namtmp->suffix),FLNAMESZ);
               libptr=libfind(strupr(libname));
               if (length == 0) { /* delete Library */
                    if (libptr != NULL) {
                         delalib(libptr);
                         return;
                    }
               }
               else {
                    dfaSetBlk(flldat);
                    setmem(libupd,sizeof(struct libdisk),0);
                    curlib=&libupd->lib;
                    if (dfaAcqEQ(libupd,libname,0)) {
                         if (libptr == NULL) {
                              prfmsg(NOCRTLIB);
                              r2wprf(FALSE);
                              return;
                         }
                    }
                    else {
                         if (libptr != NULL) {
                              prfmsg(NOEDTLIB);
                              r2wprf(FALSE);
                              return;
                         }
                         if (!valname(libname)) {
                              prfmsg(NAMEOLIB);
                              r2wprf(FALSE);
                              return;
                         }
                    }
                    curlib=&libupd->lib;
                    movmem(value,eli,sizeof(struct libcsed));
                    eli->data[XLDATLEN-1]='\0';
                    while (eli->data[i=strlen(eli->data)-1] == ' ') {
                         eli->data[i]='\0';
                    }
                    libedup(libname,libptr);
                    return;
               }
               rejectreq();
               return;
          }
     }
     if (samepato("sauf:upload ",dpkstg)) {
          upload(value);
          return;
     }
     if (samepato("sau:moddesc ",dpkstg)) {
          moddesc(length > 0 ? value : "");
          return;
     }
     if (samepato("sau:approve ",dpkstg)) {
          approve(length > 0 ? value : "");
          return;
     }
     if (samepato("sau:file ",dpkstg)) {
          rendel(length > 0 ? value : "");
          return;
     }
     if (samepato("sau:move ",dpkstg) && length > 0) {
          csmvcpy(TRUE,value);
          return;
     }
     if (samepato("sau:copy ",dpkstg) && length > 0) {
          csmvcpy(FALSE,value);
          return;
     }
     if (samepato("sau:fs",dpkstg)) {
          if (length == 0) {
               if (samepat("sau:fs",dpkstg)) { /* end of context */
                    context(FALSE);
                    rsp2write(TRUE,0,NULL,NULL);
               }
               else {
                    rejectreq();
               }
               return;
          }
          if (sameas(namtmp->suffix,"fso")) { /* request DOS-Only context */
               context(FALSE);
               if (context(TRUE)) {
                    reqcono(value);
                    return;
               }
          }
          else if (sameas(namtmp->suffix,"fsn")) { /* request #D/Ls context */
               context(FALSE);
               if (context(TRUE)) {
                    reqconn(value);
                    return;
               }
          }
          else if (sameas(namtmp->suffix,"fsd")) { /* request datesrch context */
               context(FALSE);
               if (context(TRUE)) {
                    reqcond(value);
                    return;
               }
          }
          else if (sameas(namtmp->suffix,"fsf")) { /* request filename context */
               context(FALSE);
               if (context(TRUE)) {
                    reqconf(value);
                    return;
               }
          }
          else if (sameas(namtmp->suffix,"fsk")) { /* request keyword context */
               context(FALSE);
               if (context(TRUE)) {
                    reqconk(value);
                    return;
               }
          }
          else {
               rejectreq();
               return;
          }
          prfmsg(CSNOSRCH);
          r2wprf(FALSE);
          return;
     }
     rejectreq();
}

static VOID
filxdone(VOID)                     /* file transfer-done handler           */
{
     struct fllib *libptr;
     LONG charge;

     setmbk(flmsg);
     switch (ulptr->reqtype) {
     case ULRUPL:
          if (isok2ul(FALSE)) {
               cycleme(finupl);
          }
          else {
               donewrit(0);
               unlink(spr("%s"SLS"%s",userdir(1),ulptr->filname));
               r2wprf(FALSE);
          }
          break;
     case ULRTXT:
          setmem(&viewarr[usrnum],sizeof(struct libcsfil),0);
          break;
     case ULRDNL:
          libptr=libfind(lcsarr[usrnum].libname);
          if ((charge=lcsarr[usrnum].charge) != 0L && libptr->royal > 0) {
               dfaSetBlk(flfdat);
               if (dfaAcqEQ(NULL,compkey(lcsarr[usrnum].libname,
                           lcsarr[usrnum].filname),COMPLF)
             && !sameas(flf->ulby,"Sysop")) {
                    crdusr(flf->ulby,l2as(charge*(LONG)libptr->royal/100L),0,0);
               }
               dfaRstBlk();
          }
          sv.dwnlds++;
          if (libptr != NULL && (auditall || (libptr->flags&FLGADL))) {
               shocst("LIBRARY FILE DOWNLOAD","User %s download %s"SLS"%s",
                  usaptr->userid,lcsarr[usrnum].libname,lcsarr[usrnum].filname);
          }
          dnlcount(lcsarr[usrnum].libname,lcsarr[usrnum].filname,-1L);
          lcsarr[usrnum].status=-abs(lcsarr[usrnum].status);
          csclean(usrnum);
     }
}

static VOID
fildfts(VOID)
{
     setmbk(flmsg);
     strcat(strcpy(rsptmp,getmsg(FLVKEY)),"\t");
     strcat(strcat(rsptmp,getmsg(FLDKEY)),"\t");
     strcat(strcat(rsptmp,getmsg(DEFUL)),"\t");
     strcat(strcat(rsptmp,getmsg(DEFOVR)),"\t");
     strcat(strcat(rsptmp,getmsg(DEFAPP)),"\t");
     strcat(strcat(rsptmp,getmsg(DEFLOP)),"\t");
     strcat(rsptmp,getmsg(DEFPLOP));
     rsp2read(namtmp,STGLEN,rsptmp,NULL);
     rstmbk();
}

static VOID
filabort(VOID)                     /* abort-request handler                */
{
     struct fllib *libptr;

     setmbk(flmsg);
     switch (ulptr->reqtype) {
     case ULRVCM:
          switch (flo->cszview.state) {
          case 0:
          case 1: /* VEWOPN */
               break;  /* file closed */
          default:
               fclose(flo->cszview.fp);
          }
          setmem(&viewarr[usrnum],sizeof(struct libcsfil),0);
          flo->cszview.state=0;
          break;
     case ULRUPL:
          if (ulptr->src != NULL) {
               fclose(ulptr->src);
               ulptr->src=NULL;
          }
          if (ulptr->dst != NULL) {
               fclose(ulptr->dst);
               ulptr->dst=NULL;
          }
          donewrit(0);
          unlink(spr("%s"SLS"%s",userdir(1),ulptr->filname));
          libptr=libfind(ulptr->libname);
          if (libptr != NULL && (auditall || (libptr->flags&FLGAUL))) {
               shocst("LIBRARY FILE UPLOAD ABORTED",
                      "User %s aborted upld of %s"SLS"%s",
                      usaptr->userid,ulptr->libname,ulptr->filname);
          }
          break;
     case ULRMCP:
          if (ulptr->src != NULL) {
               fclose(ulptr->src);
               ulptr->src=NULL;
          }
          if (ulptr->dst != NULL) {
               fclose(ulptr->dst);
               ulptr->dst=NULL;
          }
          donewrit(1);
          donewrit(2);
          break;
     case ULRDNL:
          if (lcsarr[usrnum].charge != 0L) {
               hdedcrd(usaptr,-lcsarr[usrnum].charge,0,1);
          }
          libptr=libfind(lcsarr[usrnum].libname);
          if (libptr != NULL && (auditall || (libptr->flags&FLGADL))) {
               shocst("LIBRARY FILE DOWNLOAD ABORTED",
                "User %s aborted dnld of %s"SLS"%s",usaptr->userid,
                lcsarr[usrnum].libname,
                lcsarr[usrnum].filname);
          }
          lcsarr[usrnum].status=-abs(lcsarr[usrnum].status);
          csclean(usrnum);
          break;
     case ULRMN0:
     case ULRMN1:
     case ULRZIP:
     case ULRZPW:
          mainting=FALSE;
          if (ulptr->uzfp != NULL) {
               fclose(ulptr->uzfp);
          }
          break;
     default:
          break;
     }
}

static struct fllib *
dirlib(                            /* get nxt/prv/matching visible Library */
INT direction,                     /*   read direction: 0=eq, 1=gt, -1=lt  */
CHAR *libname,                     /*   Library name                       */
GBOOL visonly)                     /*   visible Libraries only             */
{
     INT i;
     struct fllib *libptr;

     if (direction == 0) {
          if ((libptr=libfind(libname)) != NULL) {
               if (visonly) {
                    if (!visilib(libptr)) {
                         libptr=NULL;
                    }
               }
               else {
                    if (!haslibkey(libptr,libptr->keyreq)) {
                         libptr=NULL;
                    }
               }
          }
     }
     else if (direction < 0) {
          for (i=numoflib-1 ; i >= 0 ; i--) {
               libptr=alphlibs[i];
               if (stricmp(libptr->libname,libname) < 0) {
                    if (visonly) {
                         if (visilib(libptr)) {
                              return(libptr);
                         }
                    }
                    else {
                         if (haslibkey(libptr,libptr->keyreq)) {
                              return(libptr);
                         }
                    }
               }
          }
          libptr=NULL;
     }
     else {
          for (i=0 ; i < numoflib ; i++) {
               libptr=alphlibs[i];
               if (stricmp(libptr->libname,libname) > 0) {
                    if (visonly) {
                         if (visilib(libptr)) {
                              return(libptr);
                         }
                    }
                    else {
                         if (haslibkey(libptr,libptr->keyreq)) {
                              return(libptr);
                         }
                    }
               }
          }
          libptr=NULL;
     }
     return(libptr);
}

static INT
findaxs(                           /* return appropriate Library access    */
INT direction,                     /*   dynapak read direction             */
CHAR *libname)                     /*   library name to key with           */
{
     INT retval=0,loop;

     if (libname[0] == '\0' && direction == 0) {
          for (loop=0 ; loop < numoflib ; loop++) {
               if (isflop(curlib=liboff(loop))) {
                    retval=haskey(flsysop) ? 2 : 1;
                    break;
               }
          }
     }
     else {
          if ((curlib=dirlib(direction,libname,TRUE)) == NULL) {
               retval=-1;
          }
          else if (haskey(flsysop)) {
               retval=2;
          }
          else if (isflop(curlib)) {
               retval=1;
          }
     }
     return(retval);
}

static VOID
filfs(
INT direction)
{
     CHAR *nam;

     if (!hascontext()) {
          rejectreq();
          return;
     }
     nam=skpwht(skpwrd(namtmp->suffix));
     if (sameto("fso ",namtmp->suffix)) {
          searcho(nam,direction);
          return;
     }
     if (sameto("fsn ",namtmp->suffix)) {
          searchn(nam,direction);
          return;
     }
     if (sameto("fsd ",namtmp->suffix)) {
          searchd(nam,direction);
          return;
     }
     if (sameto("fsf ",namtmp->suffix)) {
          searchf(nam,direction);
          return;
     }
     if (sameto("fsk ",namtmp->suffix)) {
          searchk(nam,direction);
          return;
     }
     rejectreq();
}

static VOID
fileinfo(VOID)                     /* send all information on a file       */
{
     struct key1 key;
     struct ffblk fb;
     CHAR curlib[FLNAMESZ];
     struct fllib *libptr;
     GBOOL ok=FALSE;

     stzcpy(key.libname,firstwd(skpwht(skpwrd(namtmp->suffix))),FLNAMESZ);
     stzcpy(key.filname,nextwd(),FLFILENM);
     stzcpy(curlib,nextwd(),FLNAMESZ);
     dfaSetBlk(flfdat);
     if ((libptr=libfind(key.libname)) != NULL) {
          if (strlen(visxlib(libptr,curlib)) != 0) {
               if (libptr->flags&FLGDOS) {
                    fb=flo->fb;
                    if (fndfile(&flo->fb,spr("%s"SLS"%s",
                                             libpath(libptr),key.filname),0)) {
                         fsdpkr=flfrsp(TRUE,TRUE);
                         ok=TRUE;
                    }
                    flo->fb=fb;
               }
               else if (dfaAcqEQ(flf,&key,COMPLF)) {
                    fsdpkr=flfrsp(FALSE,TRUE);
                    ok=TRUE;
               }
          }
     }
     dfaRstBlk();
     if (ok) {
          rsp2read(namtmp,
                   sizeof(struct fsdpk)-(UIDSIZ+DESCSIZ)+strlen(fsdpkr->data),
                   fsdpkr,fsdpkFDA);
     }
     else {
          rejectreq();
     }
}

static VOID
download(VOID)                     /* download a file                      */
{
     struct key1 key;
     CHAR curlib[FLNAMESZ];
     struct fllib *libptr;
     GBOOL ok=FALSE;

     stzcpy(key.libname,firstwd(skpwht(skpwrd(namtmp->suffix))),FLNAMESZ);
     stzcpy(key.filname,nextwd(),FLFILENM);
     stzcpy(curlib,nextwd(),FLNAMESZ);
     dfaSetBlk(flfdat);
     if ((libptr=libfind(key.libname)) != NULL) {
          if (strlen(visxlib(libptr,curlib)) != 0) {
               if (!haslibkey(libptr,libptr->dlkey)) {
                    ok=FALSE;
               }
               else if (libptr->flags&FLGDOS) {
                    ok=isfile(spr("%s"SLS"%s",libpath(libptr),key.filname));
               }
               else if (dfaAcqEQ(flf,&key,COMPLF)) {
                    if (!notapped(flf->udate) || isflop(libptr)) {
                         ok=TRUE;
                    }
               }
          }
     }
     dfaRstBlk();
     if (ok) {
          if ((othusn=w2read(key.libname,key.filname)) != NOCONFLICT) {
               prfmsg(CSNODL,key.libname,key.filname
                     ,haskey(flsysop) ? uacoff(othusn)->userid : "someone");
               rejectreq();
               dlerr();
               return;
          }
          if (lcsarr[usrnum].status < 0) {
               csclean(usrnum);
          }
          else if (lcsarr[usrnum].status > 0) {
               prfmsg(CSCTDL,key.filname,lcsarr[usrnum].filname);
               rejectreq();
               dlerr();
               return;
          }
          stzcpy(lcsarr[usrnum].libname,key.libname,FLNAMESZ);
          stzcpy(lcsarr[usrnum].filname,key.filname,FLFILENM);
          lcsarr[usrnum].status=FREADY;
          lcsarr[usrnum].time=now();
          ulptr->reqtype=ULRDNL;
          if (forreal()) {
               if (!(libptr->flags&FLGDOS) && (libptr->flags&FLGCBD)) {
                    lcsarr[usrnum].status=(libptr->path[0] == '\0' ? EXTCDF
                                                                   : CDFILE);
                    cycleme(copywait);
               }
               else {
                    sendfile(spr("%s"SLS"%s",libpath(libptr),key.filname));
               }
          }
          else {
               if (!(libptr->flags&FLGDOS) && (libptr->flags&FLGCBD)) {
                    if (!respcdfile()) {
                         rejectreq();
                         dlerr();
                    }
               }
               else {
                    sendfile(spr("%s"SLS"%s",libpath(libptr),key.filname));
               }
          }
     }
     else {
          prfmsg(CSDLGONE,key.libname,key.filname);
          rejectreq();
          dlerr();
     }
}

static GBOOL
respcdfile(VOID)                   /* respond with bogus temporary file    */
{
     FILE *fp;
     CHAR *fname;
     CHAR dirbuf[GCMAXPTH];
     GBOOL rv;

     rv=FALSE;
     if (flf->siz > 0L) {
          fname=spr("%s"SLS"%s"SLS"%s",copydir,
                                       lcsarr[usrnum].libname,
                                       lcsarr[usrnum].filname);
          lcsarr[usrnum].status=CDDONE;
          fileparts(GCPART_PATH,fname,dirbuf,GCMAXPTH);
          gmkdir(dirbuf);
          if (isfile(fname)) {
               rv=TRUE;
          }
          else {
               fp=fopen(fname,FOPWB);
               if (fp != NULL) {
                    fseek(fp,flf->siz-1L,SEEK_SET);
                    fwrite("\0",1,1,fp);
                    fclose(fp);
                    setFileTm(fname,flf->tim,dcdate(srt2datl(flf->fdate)));
                    rv=TRUE;
               }
          }
          if (rv) {
               sendfile(fname);
          }
          if (lcsarr[usrnum].status == CDDONE) {
               lcsarr[usrnum].status=CDDLOD;
          }
     }
     return(rv);
}

static VOID
upload(                            /* receive a file dpk upload            */
struct filinf *fd)                 /*   file data                          */
{
     CHAR *s;

     firstwd(namtmp->suffix);
     stzcpy(ulptr->libname,strupr(nextwd()),FLNAMESZ);
     stzcpy(ulptr->filname,fnmcse(nextwd()),FLFILENM);
     /* we don't care what fd->name, the "actual" file name is */
     ulptr->date=fd->date;
     ulptr->time=fd->time;
     ulptr->size=fd->size;
     if (isok2ul(TRUE)) {
          MKDIR(s=userdir(1));
          ulptr->status=ULPONG;
          ulptr->src=NULL;
          ulptr->dst=NULL;
          ulptr->reqtype=ULRUPL;
          ok2write(spr("%s"SLS"%s",s,ulptr->filname));
     }
     else {
          r2wprf(FALSE);
     }
}

static VOID
moddesc(                           /* receive a description, uploader, date */
CHAR *desc)
{
     struct fllib *libptr;
     CHAR *s,*othinfo;
     GBOOL ok=TRUE;
     LONG datpos;

     firstwd(namtmp->suffix);
     stzcpy(ulptr->libname,strupr(nextwd()),FLNAMESZ);
     stzcpy(ulptr->filname,fnmcse(nextwd()),FLFILENM);
     if ((libptr=libfind(ulptr->libname)) == NULL
      || strlen(visxlib(libptr,"")) == 0) {
          prfmsg(CSNOMODD);
          r2wprf(FALSE);
          return;
     }
     if (libptr->flags&FLGDOS) {
          prfmsg(CSNOMDOS);
          r2wprf(FALSE);
          return;
     }
     dfaSetBlk(flfdat);
     if (!dfaAcqEQ(NULL,ulkey(ulptr),COMPLF)) {
          prfmsg(CSNOMFNF);
          r2wprf(FALSE);
          return;
     }
     if ((othinfo=strchr(desc,'\t')) != NULL) {
          *othinfo++='\0';
     }
     if (!isflop(libptr)) {
          if (othinfo != NULL) {
               ok=FALSE;
          }
          else if (!sameas(usaptr->userid,flf->ulby)) {
               ok=FALSE;
          }
          else if (!notapped(flf->udate)
             && !haslibkey(libptr,libptr->autoap)) {
               ok=FALSE;
          }
     }
     if (!ok) {
          prfmsg(CSNOMDNY);
          r2wprf(FALSE);
          return;
     }
     if ((othusn=w2writ(libptr->libname,ulptr->filname,0)) != NOCONFLICT) {
          prfmsg(CSNOMRSV,ulptr->libname,ulptr->filname,
           haskey(flsysop) ? uacoff(othusn)->userid  : "someone");
          r2wprf(FALSE);
          return;
     }
     stzcpy(s=descedit,desc,DESCSIZ);
     do {
          while (*s == '\n') {
               strcpy(s,s+1);
          }
     } while (*s++ != '\0');
     darsdesc(NDESCLN,'\r');
     filldesc();
     if (othinfo != NULL) {
          s=itemidx(othinfo,0);
          s=(*s == '\0' ? NOTAPPED : dat2srt(s));
          if (notapped(flf->udate)) {
               libptr->appwait--;
          }
          chuldate(libptr,flf->udate,0);
          stzcpy(flf->udate,s,DATESZ);
          if (notapped(flf->udate)) {
               libptr->appwait++;
          }
          chuldate(libptr,flf->udate,1);
          s=itemidx(othinfo,1);
          if (*s != '\0') {
               datpos=dfaAbs();
               dfaSetBlk(accbb);
               if (dfaQueryEQ(s,0)) {
                    stzcpy(flf->ulby,s,UIDSIZ);
               }
               dfaRstBlk();
               if (!dfaAcqAbsLock(vdatmp,datpos,COMPLF,0)) {
                    catastro("BAD LIBRARY FILE DATA FILE POINTER (C/S)");
               }
          }
     }
     dfaUpdateV(NULL,FLFILREC+strlen(flf->desc)+1);
     if (longsrch) {
          rsp2write(TRUE,0,"",NULL);
          donewrit(0);
     }
     else {
          cycleme(cskwdins);
     }
}

static GBOOL                       /*   returns FALSE for failed check     */
genchek(                           /* generic check of file rights for     */
CHAR *action,                      /*   write operation.  action=operation */
GBOOL nodos,                       /*   operation not for DOS-ONLY Libs    */
GBOOL nocd)                        /*   operation not for CD libs          */
{
     struct ffblk fb;

     firstwd(namtmp->suffix);
     stzcpy(ulptr->libname,strupr(nextwd()),FLNAMESZ);
     stzcpy(ulptr->filname,fnmcse(nextwd()),FLFILENM);
     if ((curlib=libfind(ulptr->libname)) == NULL
      || strlen(visxlib(curlib,"")) == 0) {
          prfmsg(ACTNOLIB,action);
          return(FALSE);
     }
     if (!isflop(curlib)) {
          prfmsg(ACTNOAXS,action);
          return(FALSE);
     }
     if (curlib->flags&FLGDOS) {
          if (nodos) {
               prfmsg(ACTNODOS,action);
               return(FALSE);
          }
          if (!fndfile(&fb,spr("%s"SLS"%s",libpath(curlib),ulptr->filname),0)) {
               prfmsg(ACTFNF,action);
               return(FALSE);
          }
          ulptr->size=fb.ff_fsize;
          ulptr->date=fb.ff_fdate;
          ulptr->time=fb.ff_ftime;
     }
     else {
          dfaSetBlk(flfdat);
          if (!dfaAcqEQ(NULL,ulkey(ulptr),COMPLF)) {
               prfmsg(ACTFNF,action);
               return(FALSE);
          }
          ulptr->size=flf->siz;
          ulptr->date=dcdate(srt2datl(flf->fdate));
          ulptr->time=flf->tim;
     }
     if (nocd && curlib->flags&FLGCBD) {
          prfmsg(ACTNONCD,action);
          return(FALSE);
     }
     if ((othusn=w2writ(ulptr->libname,ulptr->filname,1)) != NOCONFLICT) {
          prfmsg(ACTNORSV,action,
           haskey(flsysop) ? uacoff(othusn)->userid : "someone");
          return(FALSE);
     }
     return(TRUE);
}

static VOID
approve(                           /* approve a file                       */
CHAR *datstr)                      /*   MM/DD/YY date, or "" to unapprove  */
{
     CHAR newdat[DATESZ],*action;
     USHORT dosDate;

     action=(datstr[0] == '\0' ? "unapprove" : "approve");
     if (!genchek(action,TRUE,FALSE)) {
          r2wprf(FALSE);
          return;
     }
     if (datstr[0] == '\0') {
          stzcpy(newdat,NOTAPPED,DATESZ);
     }
     else {
          dosDate=dcdate(datstr);
          if (!validDateDOS(dosDate)) {
               prfmsg(ACTNODAT,action);
               donewrit(1);
               r2wprf(FALSE);
               return;
          }
          stzcpy(newdat,dat2srt(datstr),DATESZ);
     }
     if (notapped(flf->udate)) {
          curlib->appwait--;
     }
     chuldate(curlib,flf->udate,0);
     stzcpy(flf->udate,newdat,DATESZ);
     if (notapped(flf->udate)) {
          curlib->appwait++;
     }
     else {
          flf->utime=now();
     }
     chuldate(curlib,flf->udate,1);
     dfaUpdateV(NULL,FLFILREC+strlen(flf->desc)+1);
     donewrit(1);
     rsp2write(TRUE,0,"",NULL);
}

static VOID
rendel(                            /* rename or delete file                */
CHAR *newname)                     /*   new name, or "" to delete          */
{
     CHAR fname[FLFILENM],*f,*n,*s,*action;
     INT lnn,lpp;

     action=(newname[0] == '\0' ? "delete" : "rename");
     fnmcse(newname);
     if (!genchek(action,FALSE,newname[0] == '\0' ? FALSE : TRUE)) {
          r2wprf(FALSE);
          return;
     }
     if (newname[0] == '\0') { /* delete */
          if ((curlib->flags&FLGDOS) || longsrch) {
               delfile();
          }
          else {
               cycleme(delkwds);
          }
          return;
     }
     s=strchr(newname,'.');
     if (s != NULL) {
          lpp=(INT)(s-newname);
     }
     lnn=strlen(newname);
     if ((s == NULL && lnn > 8) || lpp > 9 || lnn-lpp > 4) {
          prfmsg(RENNOFNM,"rename",newname);
          donewrit(1);
          r2wprf(FALSE);
          return;
     }
     setmem(fname,FLFILENM,0);
     for (n=newname,f=fname ; *n != '\0' ; n++,f++) {
          if (!isfiln(*n,fname) || strlen(fname) == FLFILENM-1) {
               prfmsg(RENNOFNM,"rename",newname);
               donewrit(1);
               r2wprf(FALSE);
               return;
          }
          *f=*n;
     }
     if ((othusn=w2writ(strupr(ulptr->libname),fnmcse(fname),2))
      != NOCONFLICT) {
          prfmsg(RENNORSV,haskey(flsysop) ? uacoff(othusn)->userid : "someone");
          donewrit(1);
          r2wprf(FALSE);
          return;
     }
     if (curlib->flags&FLGDOS) {
          if (rename(spr("%s"SLS"%s",libpath(curlib),ulptr->filname)
                    ,spr("%s"SLS"%s",libpath(curlib),fname)) == 0) {
               donewrit(1);
               donewrit(2);
               rsp2write(TRUE,0,"",NULL);
               return;
          }
     }
     else {
          dfaSetBlk(flfdat);
          if (!dfaAcqEQ(NULL,compkey(ulptr->libname,fname),COMPLF)) {
               unlink(s=spr("%s"SLS"%s",libpath(curlib),fname));
               if (rename(spr("%s"SLS"%s",libpath(curlib),
                     ulptr->filname),s) == 0) {
                    if (dfaAcqEQ(NULL,ulkey(ulptr),COMPLF)) {
                         stzcpy(flf->filname,fname,FLFILENM);
                         dfaUpdateV(NULL,FLFILREC+strlen(flf->desc)+1);
                    }
                    else {
                         prf("Lost record of old file during rename.");
                         donewrit(1);
                         donewrit(2);
                         r2wprf(FALSE);
                         return;
                    }
                    if (!longsrch) {
                         stzcpy(ulptr->newname,fname,FLFILENM);
                         stzcpy(ulptr->newlib,ulptr->libname,FLNAMESZ);
                         ulptr->move=TRUE;
                         cycleme(renkwds);
                    }
                    else {
                         donewrit(1);
                         donewrit(2);
                         rsp2write(TRUE,0,"",NULL);
                    }
                    dfaRstBlk();
                    return;
               }
          }
          dfaRstBlk();
     }
     prfmsg(RENNOWAY,ulptr->filname,fname);
     donewrit(1);
     donewrit(2);
     r2wprf(FALSE);
}

static VOID
csmvcpy(                           /* move or copy file                    */
GBOOL move,                        /*   whether to move                    */
CHAR *destlib)                     /*   destination libname                */
{
     CHAR *action;

     action=move ? "move" : "copy";
     if (!genchek(action,FALSE,TRUE)) {
          r2wprf(FALSE);
          return;
     }
     if ((curlib=libfind(destlib)) == NULL
      || strlen(visxlib(curlib,"")) == 0) {
          prfmsg(MVCNOLIB,action);
          donewrit(1);
          r2wprf(FALSE);
          return;
     }
     if (!isflop(curlib)) {
          prfmsg(MVCNOAXS,action);
          donewrit(1);
          r2wprf(FALSE);
          return;
     }
     if (curlib->flags&FLGCBD) {
          prfmsg(MVCNONCD,action);
          donewrit(1);
          r2wprf(FALSE);
          return;
     }
     ulptr->move=move;
     stzcpy(ulptr->newlib,strupr(destlib),FLNAMESZ);
     stzcpy(ulptr->newname,fnmcse(ulptr->filname),FLFILENM);
     ulptr->status=MVCONG;
     if ((othusn=w2writ(ulptr->newlib,ulptr->newname,2)) != NOCONFLICT) {
          prfmsg(MVCNORSV,
           haskey(flsysop) ? uacoff(othusn)->userid : "someone");
          donewrit(1);
          r2wprf(FALSE);
          return;
     }
     ulptr->reqtype=ULRMCP;
     cycleme(csmcfile);
}

static VOID
csmcfile(VOID)                     /* grunt work of moving/copying file    */
{
     CHAR *src,*dst;
     struct fllib *srcl,*dstl;
     INT loop,byte;

     setmbk(flmsg);
     fluoff(usrnum);
     if ((srcl=libfind(ulptr->libname)) == NULL
      || (dstl=libfind(ulptr->newlib)) == NULL) {
          prfmsg(MVCERLIB);
          r2wprf(FALSE);
          donewrit(1);
          donewrit(2);
          return;
     }
     switch (ulptr->status) {
     case MVCONG:
          src=spr("%s"SLS"%s",libpath(srcl),ulptr->filname);
          dst=spr("%s"SLS"%s",libpath(dstl),ulptr->newname);
          if (!ulptr->move || rename(src,dst) != 0) {
               if (ulptr->move && (ulptr->dst=fopen(dst,FOPRB)) != NULL) {
                    fclose(ulptr->dst);
                    prfmsg(WARNMVCS);
                    r2wprf(FALSE);
                    donewrit(1);
                    donewrit(2);
                    return;
               }
               if ((ulptr->src=fopen(src,FOPRB)) == NULL) {
                    uplerror();
                    donewrit(1);
                    donewrit(2);
                    return;
               }
               if ((ulptr->dst=fopen(dst,FOPWB)) == NULL) {
                    uplerror();
                    donewrit(1);
                    donewrit(2);
                    return;
               }
               ulptr->status=MVCFIL;
          }
          else {
               ulptr->status=MVCDAT;
          }
          break;
     case MVCFIL:
          if (ulptr->src == NULL || ulptr->dst == NULL) {
               uplerror();
               donewrit(1);
               donewrit(2);
               return;
          }
          for (loop=0 ; loop < 1024 ; loop++) {
               byte=fgetc(ulptr->src);
               if (!feof(ulptr->src) && !ferror(ulptr->src)
             && !ferror(ulptr->dst)) {
                    fputc(byte,ulptr->dst);
               }
               else {
                    loop=2000;
               }
          }
          if (loop >= 2000) {
               if (ulptr->src != NULL) {
                    fclose(ulptr->src);
                    ulptr->src=NULL;
               }
               if (ulptr->dst != NULL) {
                    fclose(ulptr->dst);
                    ulptr->dst=NULL;
               }
               src=spr("%s"SLS"%s",libpath(srcl),ulptr->filname);
               dst=spr("%s"SLS"%s",libpath(dstl),ulptr->newname);
               touch(src,dst);
               if (ulptr->move) {
                    unlink(src);
               }
               ulptr->status=MVCDAT;
          }
          break;
     case MVCDAT: /* data files */
          dfaSetBlk(flfdat);
          if (!(dstl->flags&FLGDOS)) {
               if (dfaAcqEQ(NULL,compkey(ulptr->newlib,ulptr->newname),COMPLF)) {
                    dfaDelete();
               }
          }
          if (!(srcl->flags&FLGDOS)) {
               if (!dfaAcqEQ(NULL,ulkey(ulptr),COMPLF)) {
                    prf("Error - source file data missing!");
                    /* highly unusual */
                    r2wprf(FALSE);
                    donewrit(1);
                    donewrit(2);
                    return;
               }
               if (ulptr->move) {
                    srcl->numfiles--;
                    srcl->totbytes-=flclfit(ulptr->size,srcl->cluster);
                    if (notapped(flf->udate)) {
                         srcl->appwait--;
                    }
                    chuldate(srcl,flf->udate,0);
                    dfaDelete();
                    srcl->flags|=LIBCHN;
               }
          }
          if (!(dstl->flags&FLGDOS)) {
               stzcpy(flf->libname,strupr(ulptr->newlib),FLNAMESZ);
               stzcpy(flf->filname,fnmcse(ulptr->newname),FLFILENM);
               if (srcl->flags&FLGDOS) {
                    sprintf(flf->numdls,NUMSZP,0L);
                    stzcpy(flf->udate,ddat2srt(today()),DATESZ);
                    stzcpy(flf->ulby,usaptr->userid,UIDSIZ);
                    flf->utime=now();
                    stzcpy(flf->fdate,ddat2srt(ulptr->date),DATESZ);
                    flf->tim=ulptr->time;
                    flf->siz=ulptr->size;
                    flf->desc[0]='\0';
               }
               dfaInsertV(NULL,FLFILREC+strlen(flf->desc)+1);
               dstl->numfiles++;
               dstl->totbytes+=flclfit(ulptr->size,dstl->cluster);
               if (notapped(flf->udate)) {
                    dstl->appwait++;
               }
               chuldate(dstl,flf->udate,1);
               dstl->flags|=LIBCHN;
          }
          ulptr->status=MVCFIN;
          break;
     case MVCFIN: /* keywords if necessary, else finish */
          if (longsrch || (srcl->flags&FLGDOS)) {
               donewrit(1);
               donewrit(2);
               rsp2write(TRUE,0,"",NULL);
               return;
          }
          ulptr->status=MVCKWD;
     case MVCKWD:
          renkwds();
     }
}

static VOID
viewcomp(VOID)                     /* send all information on a file       */
{
     struct key1 key;
     struct fllib *libptr;
     GBOOL ok=FALSE;

     stzcpy(key.libname,firstwd(skpwht(skpwrd(namtmp->suffix))),FLNAMESZ);
     stzcpy(key.filname,nextwd(),FLFILENM);
     fnmcse(key.filname);
     dfaSetBlk(flfdat);
     if ((libptr=libfind(key.libname)) != NULL
      && haslibkey(libptr,libptr->dlkey)) {
          if (flo->cszview.state != 0) {
               if (sameas(flo->cszview.libname,key.libname)
                  && sameas(flo->cszview.filname,key.filname)) {
                    ok=TRUE;
               }
          }
          else if (strlen(visxlib(libptr,"")) != 0) {
               if ((libptr->flags&FLGDOS) || dfaAcqEQ(flf,&key,COMPLF)) {
                    if (!(libptr->flags&FLGCBD)) {
                         ok=isfile(spr("%s"SLS"%s",libpath(libptr),key.filname));
                    }
               }
          }
     }
     dfaRstBlk();
     if (ok) {
          stzcpy(viewarr[usrnum].libname,key.libname,FLNAMESZ);
          stzcpy(viewarr[usrnum].filname,key.filname,FLFILENM);
          if (flo->cszview.state == 0) {
               stzcpy(flo->cszview.libname,key.libname,FLNAMESZ);
               stzcpy(flo->cszview.filname,key.filname,FLFILENM);
               flo->cszview.state=1;
          }
          ulptr->reqtype=ULRVCM;
          cycleme(cntview);
          return;
     }
     rejectreq();
}

static VOID
viewtext(VOID)                     /* transfer a text file for display     */
{
     struct key1 key;
     struct fllib *libptr;
     CHAR *fpath;
     GBOOL ok=FALSE;

     stzcpy(key.libname,firstwd(skpwht(skpwrd(namtmp->suffix))),FLNAMESZ);
     stzcpy(key.filname,nextwd(),FLFILENM);
     fnmcse(key.filname);
     dfaSetBlk(flfdat);
     if ((libptr=libfind(key.libname)) != NULL
      && haslibkey(libptr,libptr->dlkey)) {
          if (strlen(visxlib(libptr,"")) != 0) {
               if (w2read(key.libname,key.filname) == NOCONFLICT) {
                    if ((libptr->flags&FLGDOS) || dfaAcqEQ(flf,&key,COMPLF)) {
                         if (!(libptr->flags&FLGCBD)) {
                              fpath=spr("%s"SLS"%s",libpath(libptr),key.filname);
                              ok=isfile(fpath);
                         }
                    }
               }
          }
     }
     dfaRstBlk();
     if (ok) {
          if (forreal()) {
               stzcpy(viewarr[usrnum].libname,key.libname,FLNAMESZ);
               stzcpy(viewarr[usrnum].filname,key.filname,FLFILENM);
               ulptr->reqtype=ULRTXT;
          }
          rsp2read(namtmp,STGLEN,fpath,NULL);
     }
     else {
          rejectreq();
     }
}

static VOID
cntview(VOID)
{
     struct saunam unsol;

     fluoff(usrnum);
     rsptmp[0]='\0';
     if (vewctn()) {
          if (rsptmp[0] == '\0') {
               return;
          }
          if (qroom(usrnum,NORMAL) && cnvd2s("sa:viewcomp",&unsol)) {
               senddpk(usrnum,"GALFIL",NORMAL,&unsol,STGLEN,rsptmp,NULL);
          }
     }
     else {
          setmem(&viewarr[usrnum],sizeof(struct libcsfil),0);
          flo->cszview.state=0;
          *namtmp=rqdptr->saunam;
          rsp2read(namtmp,STGLEN,"done",NULL);
     }
}

static INT
gotsrch(VOID)                      /* gets next search element             */
{
     INT rv=0,i;
     GBOOL vdamoved=FALSE;
     CHAR klist[FLKEYLST],*s;

     if (flo->keymeth == 2 || (flo->keymeth == 4 && flo->styp == 6)) {
          movmem(vdaptr,vdatmp,vdasiz);
          vdamoved=TRUE;
          stzcpy(klist,flo->cskwds,FLKEYLST);
          for (i=0,s=firstwd(klist) ; i < flo->kcount ; i++,s=nextwd()) {
               stzcpy(&vdaptr[i*FLKEYSIZ],s,FLKEYSIZ);
          }
     }
     if (srcnext()) {
          rv=srcgood();
          if (rv != 0) {
               srcukey();
            if (vdamoved) {
                    movmem(vdatmp,vdaptr,vdasiz);
                    vdamoved=FALSE;
               }
               switch (flo->keymeth) {
               case 0:
                    stzcpy(srchptr->filname,flo->u.key0.filname,FLFILENM);
                    stzcpy(srchptr->other,flo->u.key0.udate,DATESZ);
                    if (flo->miscflag != 0 && !notapped(flo->u.key0.udate)) {
                         i=cofdat(dcdate(srt2datl(flo->u.key0.udate)));
                         if (flo->miscflag < 0
                          || cofdat(today())-i > flo->miscflag) {
                              rv=0;
                         }
                    }
                    break;
               case 3:
                    stzcpy(srchptr->libname,flo->u.key3.libkey,FLNAMESZ);
                    stzcpy(srchptr->filname,flo->u.key3.filname,FLFILENM);
                    stzcpy(srchptr->other,flo->u.key3.udate,DATESZ);
                    if (flo->miscflag != 0 && !notapped(flo->u.key3.udate)) {
                         i=cofdat(dcdate(srt2datl(flo->u.key3.udate)));
                         if (flo->miscflag < 0
                          || cofdat(today())-i > flo->miscflag) {
                              rv=0;
                         }
                    }
                    break;
               case 5:
                    stzcpy(srchptr->libname,flo->u.key5.libkey,FLNAMESZ);
                    stzcpy(srchptr->filname,flo->u.key5.filname,FLFILENM);
                    stzcpy(srchptr->other,flo->u.key5.numdls,NUMSZ);
                    break;
               case 1:
               case 6:
                    stzcpy(srchptr->filname,flo->u.key1.filname,FLFILENM);
                    break;
               case 2:
                    stzcpy(srchptr->libname,flo->u.key2.libkey,FLNAMESZ);
                    stzcpy(srchptr->filname,flo->u.key2.filname,FLFILENM);
                    stzcpy(srchptr->other,flo->u.key2.keyword,FLKEYSIZ);
                    break;
               case 4:
               case 7:
                    stzcpy(srchptr->libname,flo->u.key4.libkey,FLNAMESZ);
                    stzcpy(srchptr->filname,flo->u.key4.filname,FLFILENM);
                    break;
               }
          }
     }
     if (vdamoved) {
          movmem(vdatmp,vdaptr,vdasiz);
     }
     return(rv);
}

static VOID
cycsrch(VOID)                      /* cycle search read request            */
{
     INT result;

     fluoff(usrnum);
     if (!(flo->flags&FILCONT)) {
          rejectreq();
          return;
     }
     flo->flags&=~(REVSRCH|NXTEQUL);
     flo->flags|=(rqdptr->direction < 0) ? REVSRCH : 0L;
     switch (flo->keymeth) {
     case 0:
          stzcpy(flo->u.key0.libname,flo->lrange,FLNAMESZ);
          stzcpy(flo->u.key0.filname,srchptr->filname,FLFILENM);
          stzcpy(flo->u.key0.udate,srchptr->other,DATESZ);
          break;
     case 3:
          stzcpy(flo->u.key3.libkey,srchptr->libname,FLNAMESZ);
          stzcpy(flo->u.key3.filname,srchptr->filname,FLFILENM);
          stzcpy(flo->u.key3.udate,srchptr->other,DATESZ);
          stzcpy(flo->u.key3.libname,flo->lrange,FLNAMESZ);
          break;
     case 5:
          flo->flags&=~REVSRCH;
          flo->flags|=(rqdptr->direction > 0) ? REVSRCH : 0L;
          stzcpy(flo->u.key5.libkey,srchptr->libname,FLNAMESZ);
          stzcpy(flo->u.key5.filname,srchptr->filname,FLFILENM);
          stzcpy(flo->u.key5.numdls,srchptr->other,NUMSZ);
          stzcpy(flo->u.key5.libname,flo->lrange,FLNAMESZ);
          break;
     case 1:
     case 6:
          stzcpy(flo->u.key1.filname,srchptr->filname,FLFILENM);
          stzcpy(flo->u.key1.libname,flo->lrange,FLNAMESZ);
          break;
     case 2:
          stzcpy(flo->u.key2.libkey,srchptr->libname,FLNAMESZ);
          stzcpy(flo->u.key2.filname,srchptr->filname,FLFILENM);
          stzcpy(flo->u.key2.keyword,srchptr->other,FLKEYSIZ);
          break;
     case 7:
     case 4:
          stzcpy(flo->u.key4.libkey,srchptr->libname,FLNAMESZ);
          stzcpy(flo->u.key4.filname,srchptr->filname,FLFILENM);
          stzcpy(flo->u.key4.libname,flo->lrange,FLNAMESZ);
          break;
     }
     if ((result=gotsrch()) != -1) {
          if (result == 1) {
               *namtmp=rqdptr->saunam;
               updsuff(namtmp->suffix);
               fsdpkr=flfrsp(FALSE,FALSE);
               rsp2read(namtmp,
                        sizeof(struct fsdpk)-(UIDSIZ+DESCSIZ)+strlen(fsdpkr->data),
                        fsdpkr,fsdpkFDA);
          }
          else {
               rejectreq();
          }
     }
}

static VOID
updsuff(                           /* update passed suffix from flf pointer*/
CHAR *suffix)
{
     CHAR *s;

     s=skpwht(skpwrd(suffix));
     switch (flo->keymeth) {
     case 0:
     case 3:
          sprintf(s,"%s %s %s",flf->udate[0] != '\0' ? flf->udate : NOTAPPED,
            flf->filname,flf->libname);
          break;
     case 5:
          sprintf(s,"%07ld %s %s",atol(flf->numdls),flf->libname,
            flf->filname);
          break;
     case 4:
          if (flo->styp != 6) {
               sprintf(s,"%s %s",flf->filname,flf->libname);
               break;
          }
     case 2:
          sprintf(s,"%s %s %s",flo->keymeth == 2 ? flo->u.key2.keyword :
                                             "-",
            flf->filname,flf->libname);
          break;
     case 1:
     case 6:
     case 7:
          sprintf(s,"%s %s",flf->filname,flf->libname);
          break;
     }
}

static struct fsdpk *
flfrsp(                            /* builds response from file data       */
GBOOL isdos,                       /*   is Library involved, DOS-Only?     */
GBOOL verbose)                     /*   w/ or w/o uploader & full desc.    */
{
     struct fsdpk *rs;
     struct fllib *libptr;
     INT loop;
//     CHAR *ext;
     CHAR tempPath[GCMAXPTH],dosName[FLFILENM],ext[GCMAXEXT+1];

     rs=(struct fsdpk *)rsptmp;
     setmem(rs,sizeof(struct fsdpk),0);
     if (isdos) {
          if ((libptr=libfind(flo->lrange)) == NULL) {
               return(rs);
          }
          if (isflop(libptr)) {
               rs->flags|=FSDLIBOP;
          }
          if (libptr->flags&FLGDOS) {
               rs->flags|=FSDISDOS;
          }
          makePath(tempPath,libpath(libptr),flo->fb.ff_name,GCMAXPTH);
          getShortName(dosName,tempPath,FLFILENM);
          fileparts(GCPART_EXTN,dosName,ext,sizeof(ext));
          if (!(libptr->flags&FLGCBD) && *ext != '\0') {
               switch (viewmode(ext)) {
               case CMPVIEW:
                    rs->flags|=FSDCVIEW;
                    break;
               case LSTVIEW:
               case ANSVIEW:
                    rs->flags|=FSDTVIEW;
                    break;
               }
          }
          rs->cost=libptr != NULL ? dnlprc(flo->fb.ff_fsize,libptr) : 0L;
          rs->size=flo->fb.ff_fsize;
          rs->dltime=atoi(dnlmin(rs->size));
          rs->filedt=d2vdat(flo->fb.ff_fdate,flo->fb.ff_ftime);
          rs->addedt=0.0;
          rs->numdls=0L;
          rs->data[0]='\0';
     }
     else {
          if ((libptr=libfind(flf->libname)) == NULL) {
               return(rs);
          }
          stzcpy(descedit,flf->desc,DESCSIZ);
          stpans(descedit);
          darsdesc(NDESCLN,'\r');
          if (isflop(libptr)) {
               rs->flags|=FSDLIBOP;
          }
          fileparts(GCPART_EXTN,flf->filname,ext,sizeof(ext));
          if (!(libptr->flags&FLGCBD) && *ext != '\0') {
               switch (viewmode(ext)) {
               case CMPVIEW:
                    rs->flags|=FSDCVIEW;
                    break;
               case LSTVIEW:
               case ANSVIEW:
                    rs->flags|=FSDTVIEW;
                    break;
               }
          }
          rs->cost=libptr != NULL ? dnlprc(flf->siz,libptr) : 0L;
          rs->size=flf->siz;
          rs->dltime=atoi(dnlmin(rs->size));
          rs->filedt=d2vdat(dcdate(srt2datl(flf->fdate)),flf->tim);
          rs->addedt=notapped(flf->udate) ? 0.0
                    : d2vdat(dcdate(srt2datl(flf->udate)),flf->utime);
          rs->numdls=atol(flf->numdls);
          if (verbose) {
               stzcpy(rs->data,flf->ulby,UIDSIZ);
               strcat(rs->data,"\t");
               for (loop=0 ; loop < NDESCLN ; loop++) {
                    if (dargv[loop][0] != '\0') {
                         strcat(rs->data,dargv[loop]);
                         strcat(rs->data,"\r");
                    }
               }
          }
          else {
               strcpy(rs->data,dargv[0]);
          }
     }
     return(rs);
}

static VOID
filibaxs(
INT direction)
{
     CHAR *s;
     INT i;

     if ((i=findaxs(direction,skpwht(s=skpwrd(namtmp->suffix)))) == -1) {
          rejectreq();
          return;
     }
     sprintf(rsptmp,"%d",i);
     if (direction != 0) {
          sprintf(s," %s",curlib->libname);
     }
     rsp2read(namtmp,STGLEN,rsptmp,rtextFDA);
}

static VOID
fillist(
INT direction)
{
     CHAR *s;

     if ((curlib=dirlib(direction,
               skpwht(s=skpwrd(namtmp->suffix)),TRUE)) == NULL) {
          rejectreq();
          return;
     }
     lli->numfiles=atol(tvfnum());
     lli->flags=(curlib->flags&FLGDOS) ? LLISDOS : 0;
     if (haslibkey(curlib,curlib->ulkey) && writable(curlib)) {
          lli->flags|=LLISUPL;
     }
     if (isflop(curlib)) {
          lli->flags|=LLISLOP;
     }
     if (curlib->flags&FLGCBD) {
          lli->flags|=LLISACD;
     }
     if (curlib->flags&FLGHID) {
          lli->flags|=LLISHID;
     }
     stzcpy(lli->desc,curlib->libdesc,FLDESCSZ);
     if (direction != 0) {
          sprintf(s," %s",curlib->libname);
     }
     rsp2read(namtmp,sizeof(struct llistinf)-FLDESCSZ+strlen(lli->desc),lli,
              llistinfFDA);
}

static VOID
filunaps(
INT direction)
{
     CHAR *s;

     if ((curlib=dirlib(direction,
               skpwht(s=skpwrd(namtmp->suffix)),TRUE)) == NULL) {
          rejectreq();
          return;
     }
     while ((curlib->flags&FLGDOS) != 0L
         || curlib->appwait == 0
         || !isflop(curlib)) {
          if (direction == 0
           || (curlib=dirlib(direction,curlib->libname,TRUE)) == NULL) {
               rejectreq();
               return;
          }
     }
     sprintf(rsptmp,"%d",curlib->appwait);
     if (direction != 0) {
          sprintf(s," %s",curlib->libname);
     }
     rsp2read(namtmp,STGLEN,rsptmp,rtextFDA);
}

static VOID
filinfo(
INT direction)
{
     CHAR *s;
     INT i;

     if ((curlib=dirlib(direction,
               skpwht(s=skpwrd(namtmp->suffix)),TRUE)) == NULL) {
          rejectreq();
          return;
     }
     setmem(xli,sizeof(struct xlibinfo),0);
     xli->totfiles=atol(tvfnum());
     xli->addtoday=curlib->newfiles[0];
     xli->addweek=0;
     for (i=0 ; i < ULDAYS ; i++) {
          xli->addweek+=curlib->newfiles[i];
     }
     xli->maxfil=atol(tvfilt());
     xli->maxbyt=atol(tvbytt());
     xli->maxbup=atol(tvbytu());
     strcpy(xli->data,curlib->libdesc);
     strcat(xli->data,"\t");
     loadldsc(NULL);
     for (i=0 ; i < NLDLIN ; i++) {
          strcat(xli->data,libupd->ldesc[i]);
          strcat(xli->data,"\r");
     }
     strcat(xli->data,"\t");
     strcat(xli->data,curlib->primary[0] == '\0' ? "Sysop" :
                                                curlib->primary);
     if (direction != 0) {
          sprintf(s," %s",curlib->libname);
     }
     rsp2read(namtmp,sizeof(struct xlibinfo)-XLDATLEN+strlen(xli->data),xli,
              xlibinfoFDA);
}

static VOID
filjoin(                           /* joined Library read handler          */
INT direction)                     /*   with directional support           */
{
     CHAR *s,*sptr,lib1[FLNAMESZ],lib2[FLNAMESZ];
     struct fllib *libptr;

     sptr=skpwht(s=skpwrd(namtmp->suffix));
     stzcpy(lib1,firstwd(sptr),FLNAMESZ);
     stzcpy(lib2,firstwd(skpwht(skpwrd(sptr))),FLNAMESZ);
     do {
          if ((libptr=dirlib(0,lib1,TRUE)) != NULL) {
               if ((libptr->flags&FLGDOS)
             || (curlib=dirlib(direction,lib2,TRUE)) == NULL) {
                    libptr=NULL;
               }
               else {
                    stzcpy(lib2,curlib->libname,FLNAMESZ);
                    if (libptr != curlib && !(curlib->flags&FLGDOS)) {
                         sprintf(rsptmp,"%d\t%s",
                     chjoined(curlib,libptr->libname) ? 1 : 0,
                     curlib->libdesc);
                         if (direction != 0) {
                              sprintf(s," %s %s",libptr->libname,
                          curlib->libname);
                         }
                         rsp2read(namtmp,STGLEN,rsptmp,rtextFDA);
                         return;
                    }
               }
          }
          if (libptr == NULL) {
               if ((libptr=dirlib(direction,lib1,TRUE)) != NULL) {
                    stzcpy(lib1,libptr->libname,FLNAMESZ);
                    setmem(lib2,FLNAMESZ,0);
                    if (direction < 0) {
                         setmem(lib2,FLNAMESZ-1,0xFF);
                    }
               }
               else {
                    break;
               }
          }
     } while (direction != 0);
     rejectreq();
}

static VOID
filibedt(
INT direction)
{
     CHAR *s;

     dfaSetBlk(flldat);
     if ((curlib=dirlib(direction,
               skpwht(s=skpwrd(namtmp->suffix)),TRUE)) == NULL
      || !dfaAcqEQ(libupd,curlib->libname,0)) {
          rejectreq();
          return;
     }
     setmem(eli,sizeof(struct libcsed),0);
     if (curlib->flags&FLGDOS) {
          eli->flags|=ELIDOS;
     }
     if (curlib->flags&FLGRDO) {
          eli->flags|=ELIRON;
     }
     if (curlib->flags&FLGHID) {
          eli->flags|=ELIHID;
     }
     if (curlib->flags&FLGCBD) {
          eli->flags|=ELISCD;
     }
     if ((curlib->flags&FLGADL) || auditall) {
          eli->flags|=ELIADD;
     }
     if ((curlib->flags&FLGAUL) || auditall) {
          eli->flags|=ELIADU;
     }
     if (auditall) {
          eli->flags|=ELIAUD;
     }
     if ((curlib->flags&FLGFUL) || freeuls) {
          eli->flags|=ELINCU;
     }
     if (freeuls) {
          eli->flags|=ELIFUD;
     }
     if (curlib->flags&FLGFDL) {
          eli->flags|=ELINCD;
     }
     eli->created=d2vdat(curlib->day,curlib->time);
     eli->dlchge=curlib->dlchge;
     eli->kdlchge=curlib->kdlchge;
     eli->royal=curlib->royal;
     eli->maxfil=curlib->maxfil;
     eli->maxbyt=curlib->maxbyt;
     eli->maxbup=curlib->maxbup;
     sprintf(eli->data,
          "%s\t%s\t%s\r%s\r%s\r%s\r%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
          curlib->path,
          curlib->libdesc,
          libupd->ldesc[0],
          libupd->ldesc[1],
          libupd->ldesc[2],
          libupd->ldesc[3],
          libupd->ldesc[4],
          curlib->keyreq,
          curlib->libop,
          curlib->autoap,
          curlib->dlkey,
          curlib->ulkey,
          curlib->overw,
          curlib->primary);
     if (direction != 0) {
          sprintf(s," %s",curlib->libname);
     }
     rsp2read(namtmp,sizeof(struct libcsed)-XLDATLEN+strlen(eli->data),eli,
              libcsedFDA);
}

static VOID
filjoins(                          /* Library joinings read handler        */
INT direction)                     /*   with directional support           */
{
     INT i;
     CHAR *s,*libname;
     struct fllib *libptr;

     libname=skpwht(s=skpwrd(namtmp->suffix));
     do {
          if ((curlib=dirlib(direction,libname,FALSE)) == NULL
           || (direction == 0 && curlib->cat[0][0] == '\0')) {
               rejectreq();
               return;
          }
          libname=curlib->libname;
     } while (curlib->cat[0][0] == '\0');
     rsptmp[0]='\0';
     for (i=0 ; i < FLNMCATS ; i++) {
          if (curlib->cat[i][0] != '\0') {
               libptr=libfind(curlib->cat[i]);
               if (libptr != NULL && haslibkey(libptr,libptr->keyreq)) {
                    strcat(rsptmp,curlib->cat[i]);
                    strcat(rsptmp,"\t");
               }
          }
          else {
               break;
          }
     }
     if (direction != 0) {
          sprintf(s," %s",curlib->libname);
     }
     if ((i=strlen(rsptmp)-1) >= 0 && rsptmp[i] == '\t') {
          rsptmp[i]='\0';
     }
     rsp2read(namtmp,STGLEN,rsptmp,rtextFDA);
}

static VOID
wfiljoin(                          /* join a Library to another            */
GBOOL join)                        /*   whether to join the Libraries      */
{                                  /*    as opposed to unjoin              */
     CHAR *sptr;
     GBOOL done;
     struct fllib *lib1,*lib2;

     lib1=libfind(firstwd(sptr=skpwht(skpwrd(namtmp->suffix))));
     lib2=libfind(firstwd(skpwht(skpwrd(sptr))));
     if (lib1 != lib2 && lib1 != NULL && lib2 != NULL
      && !(lib1->flags&FLGDOS) && !(lib2->flags&FLGDOS)) {
          done=chjoin(lib1,lib2,!join) ? TRUE : FALSE;
          if (done) {
               newjoins=TRUE;
          }
          rsp2write(done,0,NULL,NULL);
     }
     else {
          rejectreq();
     }
}

static VOID
delalib(                           /* delete Library                       */
struct fllib *libptr)              /*   library pointer to delete          */
{
     if (othrsin(libptr->libname)) {
          prfmsg(LIBNODEL,othuap->userid);
     }
     else if ((othusn=w2writ(libptr->libname,"*",2)) != NOCONFLICT) {
          prfmsg(LIBNODEL,uacoff(othusn)->userid);
     }
     else if (sameas(libptr->libname,deflname)) {
          prfmsg(CANTDEFL);
     }
     else {
          dlqptr->phase=0;
          stzcpy(dlqptr->libname,libptr->libname,FLNAMESZ);
          untagall(libptr->libname,"");
          setmem(libptr,sizeof(struct fllib),0);
          sortlibs();
          scanlibs();
          donewrit(2);
          cycleme(dlibrou);
          sendres(spr("Deleting file records in %s Library:",
                dlqptr->libname));
          return;
     }
     r2wprf(FALSE);
}

static VOID
dlibrou(VOID)                      /* cycleme() routine for lib deletion   */
{                                  /*   calls generic cycdelib()           */
     fluoff(usrnum);
     if (!cycdelib(&dlqptr->phase,dlqptr->libname,dlqptr->filname)) {
          rsp2write(TRUE,0,"",NULL);
     }
     else if (dlqptr->phase == 0) {
          sendres(spr("%s"SLS"%s",dlqptr->libname,dlqptr->filname));
     }
}

static VOID
libedup(                           /* create/update a Library              */
CHAR *libname,
struct fllib *libptr)              /*   pointer to existing lib            */
{
     GBOOL create;
     CHAR *s,*e;
     INT i;

     create=(libptr == NULL);
     if (!create) {
          libptr->flags&=~(LIBCHN|LIBONG);
          movmem(libptr,curlib,sizeof(struct fllib));
     }
     curlib->flags&=~(FLGRDO|FLGHID|FLGFDL|FLGCBD);
     if (create) {
          if (eli->flags&ELIDOS) {
               curlib->flags|=FLGDOS;
          }
          curlib->day=v2ddat(eli->created);
          curlib->time=v2dtim(eli->created);
          stzcpy(curlib->libname,libname,FLNAMESZ);
     }
     if (!auditall) {
          curlib->flags&=~(FLGAUL|FLGADL);
          if (eli->flags&ELIADD) {
               curlib->flags|=FLGADL;
          }
          if (eli->flags&ELIADU) {
               curlib->flags|=FLGAUL;
          }
     }
     if (!freeuls) {
          if (eli->flags&ELINCU) {
               curlib->flags|=FLGFUL;
          }
          else {
               curlib->flags&=~FLGFUL;
          }
     }
     if (eli->flags&ELIRON) {
          curlib->flags|=FLGRDO;
     }
     if (eli->flags&ELIHID) {
          curlib->flags|=FLGHID;
     }
     if (eli->flags&ELINCD) {
          curlib->flags|=FLGFDL;
     }
     if (eli->flags&ELISCD) {
          curlib->flags|=FLGCBD;
     }
     if (*(s=itemidx(eli->data,0)) == '\0' || valpath(s)) {
          stzcpy(curlib->path,fnmcse(checkdir(s)),PATHSIZE);
     }
     stzcpy(curlib->libdesc,itemidx(eli->data,1),FLDESCSZ);
     s=itemidx(eli->data,2);
     for (i=0 ; i < NLDLIN ; i++) {
          if ((e=strchr(s,13)) == NULL) {
               e=&s[strlen(s)];
          }
          else {
               do {
                    *e++='\0';
               } while (*e == 0x0A);
          }
          stzcpy(libupd->ldesc[i],s,FLLDESCS);
          if (libupd->ldesc[i][0] == '\0' && *e != '\0') {
               i--;
          }
          s=e;
     }
     stzcpy(curlib->keyreq,itemidx(eli->data,3),KEYSIZ);
     stzcpy(curlib->libop,itemidx(eli->data,4),KEYSIZ);
     stzcpy(curlib->autoap,itemidx(eli->data,5),KEYSIZ);
     stzcpy(curlib->dlkey,itemidx(eli->data,6),KEYSIZ);
     stzcpy(curlib->ulkey,itemidx(eli->data,7),KEYSIZ);
     stzcpy(curlib->overw,itemidx(eli->data,8),KEYSIZ);
     dfaSetBlk(accbb);
     if (dfaAcqEQ(&acctmp,itemidx(eli->data,9),0)) {
          stzcpy(curlib->primary,acctmp.userid,UIDSIZ);
     }
     dfaRstBlk();
     i=eli->royal;
     if (i >= 0 && i <= 100) {
          curlib->royal=i;
     }
     if (eli->dlchge >= -999999999L && eli->dlchge <= 999999999L) {
          curlib->dlchge=eli->dlchge;
     }
     if (eli->kdlchge >= -999999999L && eli->kdlchge <= 999999999L) {
          curlib->kdlchge=eli->kdlchge;
     }
     if (eli->maxfil >= 0L && eli->maxfil <= 999999999L) {
          curlib->maxfil=eli->maxfil;
     }
     if (eli->maxbyt >= 0L && eli->maxbyt <= 999999999L) {
          curlib->maxbyt=eli->maxbyt;
     }
     if (eli->maxbup >= 0L && eli->maxbup <= 999999999L) {
          curlib->maxbup=eli->maxbup;
     }
     savelib(libupd);
     rsp2write(TRUE,0,"",NULL);
}

VOID
sendres(                           /* send operation note via unsol. dpk   */
CHAR *restg)                       /*   string to send                     */
{
     struct saunam unsol;

     if (qroom(usrnum,NORMAL) && cnvd2s("sa:results",&unsol)) {
          senddpk(usrnum,"GALFIL",NORMAL,&unsol,STGLEN,restg,NULL);
     }
}

static VOID
reqcono(                           /* request context: DOS-Only Library    */
CHAR *value)
{
     struct fllib *libptr;

     value=firstwd(value);
     clrprf();
     if ((libptr=libfind(value)) == NULL
         || !haslibkey(libptr,libptr->keyreq)) {
          prfmsg(LIBNOEXT);
          flo->flags&=~FILCONT;
          r2wprf(FALSE);
     }
     else if (!(libptr->flags&FLGDOS)) {
          prfmsg(CONNODOS,value);
          flo->flags&=~FILCONT;
          r2wprf(FALSE);
     }
     else {
          stzcpy(flo->lrange,libptr->libname,FLNAMESZ);
          setmem(&flo->u,sizeof(union combo),0);
          flo->csidx=0L;
          rsp2write(TRUE,0,"",NULL);
     }
}

static VOID
reqconn(                           /* request context: # of D/Ls           */
CHAR *value)
{
     struct fllib *libptr;

     value=firstwd(value);
     clrprf();
     if (value[0] != '*') {
          if ((libptr=libfind(value)) == NULL
              || !haslibkey(libptr,libptr->keyreq)) {
               prfmsg(LIBNOEXT);
               flo->flags&=~FILCONT;
               r2wprf(FALSE);
               return;
          }
          stzcpy(flo->lrange,libptr->libname,FLNAMESZ);
     }
     else {
          stzcpy(flo->lrange,"",FLNAMESZ);
     }
     setmem(&flo->u,sizeof(union combo),0);
     stzcpy(flo->u.key5.libname,flo->lrange,FLNAMESZ);
     flo->keymeth=5;
     srcoff();
     srcu->nlibs=0;
     rsp2write(TRUE,0,"",NULL);
}

static VOID
reqcond(                           /* request context: date search         */
CHAR *value)
{
     CHAR *s;
     struct fllib *libptr;

     s=itemidx(value,1);
     clrprf();
     setmem(&flo->u,sizeof(union combo),0);
     if (s[0] != '*') {
          if ((libptr=libfind(s)) == NULL
              || !haslibkey(libptr,libptr->keyreq)) {
               prfmsg(LIBNOEXT);
               flo->flags&=~FILCONT;
               r2wprf(FALSE);
               return;
          }
          else if (libptr->flags&FLGDOS) {
               prfmsg(CONISDOS,s);
               flo->flags&=~FILCONT;
               r2wprf(FALSE);
               return;
          }
          stzcpy(flo->lrange,libptr->libname,FLNAMESZ);
          stzcpy(flo->u.key3.libname,libptr->libname,FLNAMESZ);
     }
     else {
          stzcpy(flo->lrange,"",FLNAMESZ);
     }
     flo->keymeth=3;
     flo->flags&=~DATESRC;
     if (sameas(s=itemidx(value,0),"Q")) {
          flo->flags|=DATESRC;
          stzcpy(flu->newdate,ddat2srt(today()),DATESZ);
     }
     else if (sameas(s,"U")) {
          flo->miscflag=-1; /* unapproved files only */
     }
     else {
          flo->miscflag=atoi(s);
     }
     if (initsrc()) {
          cycleme(srcsmake);
     }
     else {
          if (flo->lrange[0] != '\0'
            && (libptr=libfind(flo->lrange)) != NULL) {
               if (scanlib(1,libptr)) {
                    flo->keymeth=3;
               }
               else {
                    flo->keymeth=0;
               }
               scanlib(0,libptr);
          }
          rsp2write(TRUE,0,"",NULL);
     }
}

static VOID
reqconf(                           /* request context: filename search     */
CHAR *value)
{
     CHAR *s;
     struct fllib *libptr;
     GBOOL change=FALSE;

     flo->styp=0;
     s=itemidx(value,1);
     clrprf();
     flo->miscfil[0]='\0';
     setmem(&flo->u,sizeof(union combo),0);
     if (s[0] != '*') {
          if ((libptr=libfind(s)) == NULL
              || !haslibkey(libptr,libptr->keyreq)) {
               prfmsg(LIBNOEXT);
               flo->flags&=~FILCONT;
               r2wprf(FALSE);
               return;
          }
          else if (libptr->flags&FLGDOS) {
               prfmsg(CONISDOS,value);
               flo->flags&=~FILCONT;
               r2wprf(FALSE);
               return;
          }
          stzcpy(flo->lrange,libptr->libname,FLNAMESZ);
          stzcpy(flo->u.key4.libname,libptr->libname,FLNAMESZ);
     }
     else {
          stzcpy(flo->lrange,"",FLNAMESZ);
     }
     flo->keymeth=7;
     if (sameas(s=itemidx(value,0),"*.*") || s[0] == '\0') {
          change=TRUE;
     }
     else {
          stzcpy(flo->miscfil,s,FLFILENM);
     }
     if (flo->miscfil[0] == '\0' && initsrc()) {
          if (change) {
               flo->keymeth=4;
          }
          cycleme(srcsmake);
     }
     else {
          if (change) {
               stzcpy(flo->miscfil,s,FLFILENM);
          }
          if (flo->lrange[0] != '\0'
            && (libptr=libfind(flo->lrange)) != NULL) {
               if (scanlib(1,libptr)) {
                    flo->keymeth=7;
               }
               else {
                    flo->keymeth=(change ? 1 : 6);
               }
               scanlib(0,libptr);
          }
          rsp2write(TRUE,0,"",NULL);
     }
}

static VOID
reqconk(                           /* request context: keyword search      */
CHAR *value)
{
     struct fllib *libptr;
     CHAR *s;
     INT i;

     stzcpy(flo->cskwds,itemidx(value,0),FLKEYLST);
     movmem(vdaptr,vdatmp,vdasiz);
     flo->styp=4;
     clrprf();
     if (!fparsrch(flo->cskwds)) {
          if (prfptr == prfbuf) {
               prfmsg(CONNOKWD);
          }
          flo->flags&=~FILCONT;
          movmem(vdatmp,vdaptr,vdasiz);
          r2wprf(FALSE);
          return;
     }
     flo->cskwds[0]='\0';
     for (i=0 ; i < flo->kcount ; i++) {
          stzcat(flo->cskwds,spr("%s ",&vdaptr[i*FLKEYSIZ]),FLKEYLST);
     }
     if ((i=strlen(flo->cskwds)) > 0 && *(s=&flo->cskwds[i-1]) == ' ') {
          *s='\0';
     }
     movmem(vdatmp,vdaptr,vdasiz);
     setmem(&flo->u,sizeof(union combo),0);
     clrprf();
     s=itemidx(value,1);
     if (s[0] != '*') {
          if ((libptr=libfind(s)) == NULL
              || !haslibkey(libptr,libptr->keyreq)) {
               prfmsg(LIBNOEXT);
               flo->flags&=~FILCONT;
               r2wprf(FALSE);
               return;
          }
          else if (libptr->flags&FLGDOS) {
               prfmsg(CONISDOS,value);
               flo->flags&=~FILCONT;
               r2wprf(FALSE);
               return;
          }
          stzcpy(flo->lrange,libptr->libname,FLNAMESZ);
          switch (flo->styp) {
          case 4:
               flo->keymeth=2;
               stzcpy(flo->u.key2.keyword,firstwd(flo->cskwds),FLKEYSIZ);
               stzcpy(flo->u.key2.origkey,firstwd(flo->cskwds),FLKEYSIZ);
               break;
          case 6:
               flo->keymeth=4;
               stzcpy(flo->u.key4.libname,libptr->libname,FLNAMESZ);
               break;
          }
     }
     else {
          stzcpy(flo->lrange,"",FLNAMESZ);
          switch (flo->styp) {
          case 4:
               flo->keymeth=2;
               stzcpy(flo->u.key2.keyword,firstwd(flo->cskwds),FLKEYSIZ);
               stzcpy(flo->u.key2.origkey,firstwd(flo->cskwds),FLKEYSIZ);
               break;
          case 6:
               flo->keymeth=4;
               break;
          }
     }
     if (initsrc()) {
          cycleme(srcsmake);
     }
     else {
          rsp2write(TRUE,0,"",NULL);
     }
}

static VOID
searcho(                           /* search/list DOS-Only Lib             */
CHAR *nam,
INT direction)
{
     struct fllib *libptr;
     INT cont;
     CHAR tempPath[GCMAXPTH],dosName[FLFILENM];

     if (flo->csidx == -1L) {
          rejectreq();
          return;
     }
     if (direction <= 0 || (libptr=libfind(flo->lrange)) == NULL) {
          rejectreq();
          return;
     }
     if (flo->csidx == 0L) {
          cont=fnd1st(&flo->fb,spr("%s"SLS STAR,libpath(libptr)),0);
     }
     else {
          cont=fndnxt(&flo->fb);
     }
     if (cont) {
          makePath(tempPath,libpath(libptr),flo->fb.ff_name,GCMAXPTH);
          getShortName(dosName,tempPath,FLFILENM);
          sprintf(rsptmp,"%s\t%s\t%ld\t%ld\t%f",
                  dosName,
                  flo->lrange,
                  dnlprc(flo->fb.ff_fsize,libptr),
                  flo->fb.ff_fsize,
                  d2vdat(flo->fb.ff_fdate,flo->fb.ff_ftime));
          sprintf(nam,"%05lX %s %s",
                  flo->csidx++,libptr->libname,dosName);
          fsdpkr=flfrsp(TRUE,FALSE);
          rsp2read(namtmp,
                   sizeof(struct fsdpk)-(UIDSIZ+DESCSIZ)+strlen(fsdpkr->data),
                   fsdpkr,fsdpkFDA);
     }
     else {
          flo->csidx=-1L;
          rejectreq();
     }
}

static VOID
searchn(                           /* search/list on # of D/Ls             */
CHAR *nam,
INT direction)
{
     INT result;
     LONG l;
     CHAR *s;

     if (flo->keymeth != 5) {
          rejectreq();
          return;
     }
     flo->flags&=~NXTEQUL;
     if (direction > 0) {
          flo->flags|=REVSRCH;
     }
     else {
          flo->flags&=~REVSRCH;
     }
     l=atol(s=firstwd(nam));
     if (l == 0L && stricmp(s,"9999999") > 0) {
          stzcpy(flo->u.key5.numdls,s,NUMSZ);
     }
     else {
          stzcpy(flo->u.key5.numdls,spr("%07ld",l),NUMSZ);
     }
     s=nextwd();
     stzcpy(flo->u.key5.libkey,s,FLNAMESZ);
     s=nextwd();
     stzcpy(flo->u.key5.filname,s,FLFILENM);
     stzcpy(flo->u.key5.libname,flo->lrange,FLNAMESZ);
     if ((result=gotsrch()) != -1) {
          if (result != 0) {
               updsuff(namtmp->suffix);
               fsdpkr=flfrsp(FALSE,FALSE);
               rsp2read(namtmp,
                        sizeof(struct fsdpk)-(UIDSIZ+DESCSIZ)+strlen(fsdpkr->data),
                        fsdpkr,fsdpkFDA);
          }
          else {
               rejectreq();
          }
     }
     else {
          stzcpy(srchptr->libname,flo->u.key5.libkey,FLNAMESZ);
          stzcpy(srchptr->filname,flo->u.key5.filname,FLFILENM);
          stzcpy(srchptr->other,flo->u.key5.numdls,NUMSZ);
          cycleme(cycsrch);
     }
}

static VOID
searchd(                           /* search/list on date added            */
CHAR *nam,
INT direction)
{
     INT result;
     CHAR *s;

     s=firstwd(nam);
     switch (flo->keymeth) {
     case 0:
          stzcpy(flo->u.key0.udate,s,DATESZ);
          s=nextwd();
          stzcpy(flo->u.key0.filname,s,FLFILENM);
          nextwd();
          stzcpy(flo->u.key0.libname,flo->lrange,FLNAMESZ);
          break;
     case 3:
          stzcpy(flo->u.key3.udate,s,DATESZ);
          s=nextwd();
          stzcpy(flo->u.key3.filname,s,FLFILENM);
          s=nextwd();
          stzcpy(flo->u.key3.libkey,s,FLNAMESZ);
          stzcpy(flo->u.key3.libname,flo->lrange,FLNAMESZ);
          break;
     default:
          rejectreq();
          return;
     }
     flo->flags&=~NXTEQUL;
     if (direction > 0) {
          flo->flags&=~REVSRCH;
     }
     else {
          flo->flags|=REVSRCH;
     }
     if ((result=gotsrch()) != -1) {
          if (result != 0) {
               updsuff(namtmp->suffix);
               fsdpkr=flfrsp(FALSE,FALSE);
               rsp2read(namtmp,
                        sizeof(struct fsdpk)-(UIDSIZ+DESCSIZ)+strlen(fsdpkr->data),
                        fsdpkr,fsdpkFDA);
          }
          else {
               rejectreq();
          }
     }
     else {
          switch (flo->keymeth) {
          case 0:
               stzcpy(srchptr->filname,flo->u.key0.filname,FLFILENM);
               stzcpy(srchptr->other,flo->u.key0.udate,DATESZ);
               break;
          case 3:
               stzcpy(srchptr->libname,flo->u.key3.libkey,FLNAMESZ);
               stzcpy(srchptr->filname,flo->u.key3.filname,FLFILENM);
               stzcpy(srchptr->other,flo->u.key3.udate,DATESZ);
               break;
          }
          cycleme(cycsrch);
     }
}

static VOID
searchf(                           /* search/list on filename              */
CHAR *nam,
INT direction)
{
     INT result;
     CHAR *s;

     s=firstwd(nam);
     switch (flo->keymeth) {
     case 6:
          if (*s == '\0') {
               wldstuff(flo->u.key1.filname);
               s=NULL;
          }
     case 1:
          if (s != NULL) {
               stzcpy(flo->u.key1.filname,s,FLFILENM);
          }
          stzcpy(flo->u.key1.libname,flo->lrange,FLNAMESZ);
          break;
     case 7:
          if (*s == '\0') {
               wldstuff(flo->u.key4.filname);
               s=NULL;
          }
     case 4:
          if (s != NULL) {
               stzcpy(flo->u.key4.filname,s,FLFILENM);
          }
          s=nextwd();
          stzcpy(flo->u.key4.libkey,s,FLNAMESZ);
          stzcpy(flo->u.key4.libname,flo->lrange,FLNAMESZ);
          break;
     default:
          rejectreq();
          return;
     }
     flo->flags&=~NXTEQUL;
     if (direction > 0) {
          flo->flags&=~REVSRCH;
     }
     else {
          flo->flags|=REVSRCH;
     }
     if ((result=gotsrch()) != -1) {
          if (result != 0) {
               updsuff(namtmp->suffix);
               fsdpkr=flfrsp(FALSE,FALSE);
               rsp2read(namtmp,
                        sizeof(struct fsdpk)-(UIDSIZ+DESCSIZ)+strlen(fsdpkr->data),
                        fsdpkr,fsdpkFDA);
          }
          else {
               rejectreq();
          }
     }
     else {
          switch (flo->keymeth) {
          case 1:
          case 6:
               stzcpy(srchptr->filname,flo->u.key1.filname,FLFILENM);
               break;
          case 4:
          case 7:
               stzcpy(srchptr->libname,flo->u.key4.libkey,FLNAMESZ);
               stzcpy(srchptr->filname,flo->u.key4.filname,FLFILENM);
               break;
          }
          cycleme(cycsrch);
     }
}

static VOID
searchk(                           /* search/list on keyword               */
CHAR *nam,
INT direction)
{
     INT result;
     CHAR *s;

     s=firstwd(nam);
     switch (flo->keymeth) {
     case 2:
          if (*s == '\0' || sameas(s,"-")) {
               stzcpy(flo->u.key2.keyword,flo->u.key2.origkey,FLKEYSIZ);
          }
          else {
               stzcpy(flo->u.key2.keyword,s,FLKEYSIZ);
          }
          s=nextwd();
          stzcpy(flo->u.key2.filname,s,FLFILENM);
          s=nextwd();
          stzcpy(flo->u.key2.libkey,s,FLNAMESZ);
          stzcpy(flo->u.key2.libname,flo->lrange,FLNAMESZ);
          break;
     case 4:
          s=nextwd();
          stzcpy(flo->u.key4.filname,s,FLFILENM);
          s=nextwd();
          stzcpy(flo->u.key4.libkey,s,FLNAMESZ);
          stzcpy(flo->u.key4.libname,flo->lrange,FLNAMESZ);
          break;
     default:
          rejectreq();
          return;
     }
     flo->csidx=atol(nextwd());
     flo->flags&=~NXTEQUL;
     if (direction > 0) {
          flo->flags&=~REVSRCH;
     }
     else {
          flo->flags|=REVSRCH;
     }
     if ((result=gotsrch()) != -1) {
          if (result != 0) {
               updsuff(namtmp->suffix);
               fsdpkr=flfrsp(FALSE,FALSE);
               rsp2read(namtmp,
                        sizeof(struct fsdpk)-(UIDSIZ+DESCSIZ)+strlen(fsdpkr->data),
                        fsdpkr,fsdpkFDA);
          }
          else {
               rejectreq();
          }
     }
     else {
          switch (flo->keymeth) {
          case 2:
               stzcpy(srchptr->filname,flo->u.key2.filname,FLFILENM);
               stzcpy(srchptr->libname,flo->u.key2.libkey,FLNAMESZ);
               stzcpy(srchptr->other,flo->u.key2.keyword,FLKEYSIZ);
               break;
          case 4:
               stzcpy(srchptr->libname,flo->u.key4.libkey,FLNAMESZ);
               stzcpy(srchptr->filname,flo->u.key4.filname,FLFILENM);
               break;
          }
          cycleme(cycsrch);
     }
}

static GBOOL                       /*   returns FALSE if operation failed  */
context(                           /* secure/erase a context               */
GBOOL get)                         /*   get: TRUE means secure, FALSE erase*/
{
     if (get) {
          if (flo->flags&FILCONT) {
               return(FALSE);
          }
          flo->flags|=FILCONT;
     }
     else {
          if (!(flo->flags&FILCONT)) {
               return(FALSE);
          }
          flo->flags&=~FILCONT;
     }
     return(TRUE);
}

static GBOOL
hascontext(VOID)                   /* whether there is a current context   */
{
     return((flo->flags&FILCONT) ? TRUE : FALSE);
}

static INT
cslibrsv(                          /* c/s file reservation amreading() hook*/
CHAR *lib,                         /*   Library name                       */
CHAR *fil)                         /*   file name                          */
{
     INT i;

     for (i=0 ; i < nterms ; i++) {
          if (sameas(lcsarr[i].libname,lib)
           || sameas(viewarr[i].libname,lib)) {
               if (sameas(fil,"*") || sameas(fil,lcsarr[i].filname)) {
                    return(i);
               }
          }
     }
     return((*oldrsv)(lib,fil));
}

static VOID
copywait(VOID)                     /* waiting for file to copy from CD     */
{
     INT stt;

     fluoff(usrnum);
     if ((stt=lcsarr[usrnum].status) < 0) {
          rejectreq();
          csclean(usrnum);
          return;
     }
     switch (stt) {
     case CDDONE:
          *namtmp=rqdptr->saunam;
          sendfile(spr("%s"SLS"%s"SLS"%s",copydir,
                       lcsarr[usrnum].libname,lcsarr[usrnum].filname));
          if (lcsarr[usrnum].status == CDDONE) {
               lcsarr[usrnum].status=CDDLOD;
          }
          break;
     case EXTCDF:
          if (now()-lcsarr[usrnum].time > 60L) {
               rejectreq();
               lcsarr[usrnum].status=-lcsarr[usrnum].status;
               csclean(usrnum);
          }
     }
}

static VOID
sendfile(                          /* send c/s user the requested file.    */
CHAR *path)                        /*   path of file, checks it first      */
{                                  /*   assumes namtmp is correct, and     */
     struct ffblk fb;              /*   that lcsarr[] is filled            */
     FILE *fp;
     LONG charge;

     if (fndfile(&fb,path,0) && (fp=fopen(path,FOPRB)) != NULL) {
          fclose(fp);
          if (forreal()) {
               if (!tstcrd(dnlchg(fb.ff_fsize,lcsarr[usrnum].libname))) {
                    rejectreq();
                    setmbk(flmsg);
                    prfmsg(DNLNOCRD,lcsarr[usrnum].filname);
                    dlerr();
                    lcsarr[usrnum].status=-abs(lcsarr[usrnum].status);
                    csclean(usrnum);
                    return;
               }
               charge=dnlprc(fb.ff_fsize,libfind(lcsarr[usrnum].libname));
               lcsarr[usrnum].charge=(charge == 0L ? 0L
                                                   : hdedcrd(usaptr,charge,0,1));
               rsp2read(namtmp,STGLEN,path,NULL);
          }
          else {
               lcsarr[usrnum].charge=0L;
               rsp2read(namtmp,STGLEN,path,NULL);
               lcsarr[usrnum].status=-abs(lcsarr[usrnum].status);
               csclean(usrnum);
          }
     }
     else {
          shocst("FILE LIBRARIES: MISSING FILE","%s"SLS"%s is missing!",
                 lcsarr[usrnum].libname,lcsarr[usrnum].filname);
          rejectreq();
          setmbk(flmsg);
          prfmsg(DNLNOFIL,lcsarr[usrnum].filname);
          dlerr();
          lcsarr[usrnum].status=-abs(lcsarr[usrnum].status);
          csclean(usrnum);
     }
}

INT                                /*   returns: -1 or usrnum of c/s tag   */
csfbest(                           /* is there a better c/s tag waiting?   */
INT mode,                          /*   mode: TGCOPY or TGINWAIT           */
LONG time)                         /*   time of best A/A tag if TGINWAIT   */
{                                  /*   or -1L if no best A/A time         */
     INT i,better=-1;
     LONG best=0L,testime;

     for (i=0 ; i < nterms ; i++) {
          switch (mode) {
          case TGCOPY:
               if (lcsarr[i].status == CDCOPY) {
                    return(i);
               }
               break;
          case TGINWAIT:
               if (lcsarr[i].status == CDFILE) {
                    if (time == -1L || (testime=lcsarr[i].time) < time) {
                         if (better == -1 || testime < best) {
                              better=i;
                              best=testime;
                         }
                    }
               }
               break;
          default:
               return(-1);
          }
     }
     if (mode == TGINWAIT && better != -1) {
          return(better);
     }
     return(-1);
}

VOID
csclean(                           /* clean up c/s file tags               */
INT unum)                          /*   usrnum of tag to clean up          */
{
     CHAR *l,*f;
     struct taglib *tag;
     GBOOL found=FALSE;
     INT loop,stt;

     stt=lcsarr[unum].status;
     switch (-stt) {
     case CDCOPY:
          if (cdst != NULL) {
               fclose(cdst);
               cdst=NULL;
          }
          if (csrc != NULL) {
               fclose(csrc);
               csrc=NULL;
          }
          l=lcsarr[unum].libname;
          f=lcsarr[unum].filname;
          unlink(spr("%s"SLS"%s"SLS"%s",copydir,l,f));
          break;
     case CDDONE:
     case CDDLOD:
          l=lcsarr[unum].libname;
          f=lcsarr[unum].filname;
          for (loop=0 ; loop < systags ; loop++) {
               tag=tagoff(loop);
               if (tag->status > TGEMPTY) {
                    if (sameas(f,tag->filname) && sameas(l,tag->libname)) {
                         found=TRUE;
                         break;
                    }
               }
          }
          if (!found) {
               for (loop=0 ; loop < nterms ; loop++) {
                    if (loop != unum && lcsarr[loop].status > 0
                       && sameas(f,lcsarr[loop].filname)
                       && sameas(l,lcsarr[loop].libname)) {
                         found=TRUE;
                         break;
                    }
               }
               if (!found) {
                    unlink(spr("%s"SLS"%s"SLS"%s",copydir,l,f));
               }
          }
     }
     setmem(&lcsarr[unum],sizeof(struct libcsfil),0);
}

static VOID
uplerror(VOID)                     /* caught a file copy error             */
{
     prf("1"); /* bad library */
     prfmsg(MVCERLB2,ulptr->libname);
     r2wprf(FALSE);
     donewrit(0);
     if (ulptr->src != NULL) {
          fclose(ulptr->src);
          ulptr->src=NULL;
     }
     if (ulptr->dst != NULL) {
          fclose(ulptr->dst);
          ulptr->dst=NULL;
     }
}

static VOID
finupl(VOID)                       /* finish upload cycle                  */
{
     struct ffblk fb;
     struct fllib *libptr;
     CHAR *s;
     ULONG begtime;
     INT loop,byte;
     GBOOL upv;

     setmbk(flmsg);
     fluoff(usrnum);
     if ((libptr=libfind(ulptr->libname)) == NULL) {
          uplerror();
          return;
     }
     fluoff(usrnum);
     switch (ulptr->status) {
     case ULPONG: /* just finished upload, move file */
          makePath(flo->srcpath,userdir(1),ulptr->filname,GCMAXPTH);
          makePath(flo->destpath,libpath(libptr),ulptr->filname,GCMAXPTH);
          setFileTm(flo->srcpath,ulptr->time,ulptr->date);
          switch (tryMove()) {
          case INS_ERROR:
               uplerror();
               return;
          case INS_MOVE:
               ulptr->src=flo->fsrc;
               ulptr->dst=flo->fdst;
               ulptr->status=ULPCPY;
               break;
          case INS_DONE:
               ulptr->status=(libptr->flags&FLGDOS) ? ULPFIN : ULPDAT;
               break;
          }
          break;
     case ULPCPY:
          if (ulptr->src == NULL || ulptr->dst == NULL) {
               uplerror();
               return;
          }
          /* copy for 10 ms at a time */
          begtime=hrtval();
          do {
               byte=fgetc(ulptr->src);
               if (byte == EOF) {
                    if (ferror(ulptr->src) || ferror(ulptr->dst)) {
                         uplerror();
                         return;
                    }
                    if (ulptr->src != NULL) {
                         fclose(ulptr->src);
                         ulptr->src=NULL;
                    }
                    if (ulptr->dst != NULL) {
                         fclose(ulptr->dst);
                         ulptr->dst=NULL;
                    }
                    makePath(flo->srcpath,userdir(1),ulptr->filname,GCMAXPTH);
                    makePath(flo->destpath
                            ,libpath(libptr),ulptr->filname,GCMAXPTH);
                    touch(flo->srcpath,flo->destpath);
                    unlink(flo->srcpath);
                    ulptr->status=(libptr->flags&FLGDOS) ? ULPFIN : ULPDAT;
                    break;
               }
               fputc(byte,ulptr->dst);
          } while ((hrtval()-begtime) < ((10*65536UL)/1000));
          break;
     case ULPDAT:
          makePath(flo->destpath,libpath(libptr),ulptr->filname,GCMAXPTH);
          if (!fndfile(&fb,flo->destpath,0)) {
               uplerror();
               return;
          }
          dfaSetBlk(flfdat);
          upv=dfaAcqEQ(NULL,ulkey(ulptr),COMPLF);
          if (!upv) {
               setmem(flf,FLFILREC+DESCSIZ,0);
               stzcpy(flf->libname,libptr->libname,FLNAMESZ);
               stzcpy(flf->filname,ulptr->filname,FLFILENM);
          }
          s=haslibkey(libptr,libptr->autoap) ? ddat2srt(today()) : NOTAPPED;
          flf->siz=fb.ff_fsize;
          if (upv) {
               libptr->numfiles--;
               libptr->totbytes-=flclfit(flf->siz,libptr->cluster);
               if (notapped(flf->udate)) {
                    libptr->appwait--;
               }
               chuldate(libptr,flf->udate,0);
          }
          stzcpy(flf->udate,s,DATESZ);
          flf->utime=now();
          stzcpy(flf->fdate,ddat2srt(fb.ff_fdate),DATESZ);
          flf->tim=fb.ff_ftime;
          stzcpy(flf->numdls,spr(NUMSZP,0L),NUMSZ);
          stzcpy(flf->ulby,usaptr->userid,UIDSIZ);
          if (!upv) {
               flf->desc[0]='\0';
          }
          if (upv) {
               dfaUpdateV(NULL,FLFILREC+strlen(flf->desc)+1);
          }
          else {
               dfaInsertV(NULL,FLFILREC+strlen(flf->desc)+1);
          }
          dfaRstBlk();
          if (!upv && !longsrch) {
               if (makwdlst("",ulptr->filname)) { /* filename kwds only */
                    for (loop=0 ; loop < dargc ; loop++) {
                         addkw(dargv[loop],ulptr->filname,ulptr->libname);
                    }
               }
          }
          libptr->numfiles++;
          libptr->totbytes+=flclfit(flf->siz,libptr->cluster);
          if (notapped(flf->udate)) {
               libptr->appwait++;
          }
          chuldate(libptr,flf->udate,1);
          libptr->flags|=LIBCHN;
          /* intentional fall-through */
     case ULPFIN:
          rsp2write(TRUE,0,"",NULL);
          donewrit(0);
          sv.uplds++;
          if (libptr != NULL && (auditall || (libptr->flags&FLGAUL))) {
               shocst("LIBRARY FILE UPLOAD","User %s uploaded %s"SLS"%s",
                      usaptr->userid,ulptr->libname,ulptr->filname);
          }
     }
}

static VOID
cskwdins(VOID)                     /* insert keywords in good time         */
{
     INT loop;

     fluoff(usrnum);
     if (!delkw("",ulptr->filname,ulptr->libname)
      && kwbuf[0].keyword[0] == '\0') {
          dfaSetBlk(flfdat);
          if (dfaAcqEQ(NULL,ulkey(ulptr),COMPLF)) {
               if (makwdlst(flf->desc,flf->filname)) {
                    for (loop=0 ; loop < dargc ; loop++) {
                         addkw(dargv[loop],flf->filname,flf->libname);
                    }
               }
          }
          rsp2write(TRUE,0,"",NULL);
          donewrit(0);
     }
}

static VOID
filldesc(VOID)                     /* fill flf->desc with dargv[] lines    */
{
     INT loop,back;
     CHAR *s;

     flf->desc[0]='\0';
     for (loop=0 ; loop < dargc && countc(flf->desc,'\r') < NDESCLN ; loop++) {
          if (strlen(dargv[loop]) < SDESCLN) {
               stzcat(flf->desc,spr("%s\r",dargv[loop]),DESCSIZ);
          }
          else {
               for (back=SDESCLN-1 ; back > SDESCLN-20 ; back--) {
                    s=&dargv[loop][back];
                    if (*s == ' ') {
                         break;
                    }
                    else {
                         s="";
                    }
               }
               if (*s == '\0') {
                    stzcat(flf->desc,spr("%.*s\r",SDESCLN-1,dargv[loop]),
                  DESCSIZ);
                    dargv[loop]=&dargv[loop][SDESCLN-1];
               }
               else {
                    stzcat(flf->desc,spr("%.*s\r",back,dargv[loop]),DESCSIZ);
                    dargv[loop]=++s;
               }
               loop--;
          }
     }
}

static GBOOL                       /*   returns: false if unacceptable     */
isok2ul(                           /* is it acceptable to upload this file */
GBOOL reserve)                     /*   whether to reserve the file now    */
{                                  /* if FALSE, prfbuf is filled.          */
     struct fllib *libptr;

     /* prf codes: 0 = no recourse 1=bad lib 2=filename change might help */

     if ((libptr=libfind(ulptr->libname)) == NULL
      || strlen(visxlib(libptr,"")) == 0) {
          prf("1"); /* bad library */
          prfmsg(LIBNOEXT);
          return(FALSE);
     }
     if (!haslibkey(libptr,libptr->ulkey) || !writable(libptr)) {
          prf("1"); /* bad library */
          prfmsg(UPLNOAXS,libptr->libname);
          return(FALSE);
     }
     if (!okfname(ulptr->filname)) {
          prf("2");
          prfmsg(RENNOFNM,"upload",ulptr->filname);
          return(FALSE);
     }
     if (!(libptr->flags&FLGDOS)) {
          dfaSetBlk(flfdat);
          if (dfaAcqEQ(flf,ulkey(ulptr),COMPLF)) {
               if (!ucanovw(libptr,flf)) {
                    prf("2");
                    prfmsg(CANTOVER);
                    return(FALSE);
               }
          }
          dfaRstBlk();
     }
     if (libroom(libptr) <= 0L && !haskey(flsysop)) {
          prf("0");
          prfmsg(UPLNOFRM,libptr->libname);
          return(FALSE);
     }
     if (ulptr->size > byteroom && !haskey(flsysop)) {
          prf("0");
          prfmsg(UPLF2BIG,ulptr->filname,libptr->libname);
          return(FALSE);
     }
     /* note: next one must be last because of w2writ() */
     if (reserve &&
        (othusn=w2writ(ulptr->libname,ulptr->filname,0)) != NOCONFLICT) {
          prf("2");
          prfmsg(ACTNORSV,"upload",
           haskey(flsysop) ? uacoff(othusn)->userid : "someone");
          return(FALSE);
     }
     return(TRUE);
}

static VOID
delfile(VOID)                      /* delete dfa record and DOS file       */
{
     struct fllib *libptr;

     if ((libptr=libfind(ulptr->libname)) != NULL) {
          if (!(libptr->flags&FLGCBD)) {
               unlink(spr("%s"SLS"%s",libpath(libptr),ulptr->filname));
          }
          if (!(libptr->flags&FLGDOS)) {
               dfaSetBlk(flfdat);
               if (dfaAcqEQ(NULL,ulkey(ulptr),COMPLF)) {
                    libptr->numfiles--;
                    libptr->totbytes-=flclfit(flf->siz,libptr->cluster);
                    if (notapped(flf->udate)) {
                         libptr->appwait--;
                    }
                    chuldate(libptr,flf->udate,0);
                    libptr->flags|=LIBCHN;
                    dfaDelete();
               }
               dfaRstBlk();
          }
     }
     donewrit(1);
     rsp2write(TRUE,0,"",NULL);
}

static VOID
delkwds(VOID)                      /* delete keyword records               */
{
     fluoff(usrnum);
     dfaSetBlk(flkdat);
     if (dfaAcqEQ(NULL,rcompkey(ulptr->libname,ulptr->filname),COMPFL_K)) {
          dfaDelete();
     }
     else {
          delfile();
     }
     dfaRstBlk();
}

static VOID
renkwds(VOID)
{
     struct key2 dat;
     LONG pos;
     struct fllib *srcl,*dstl;

     fluoff(usrnum);
     if ((srcl=libfind(ulptr->libname)) == NULL
        || (dstl=libfind(ulptr->newlib)) == NULL) {
          /* highly unusual */
          prf("Error while updating keywords - Library missing");
          donewrit(1);
          donewrit(2);
          r2wprf(FALSE);
          return;
     }
     if (srcl->flags&FLGDOS || (!ulptr->move && (dstl->flags&FLGDOS))) {
          donewrit(1);
          donewrit(2);
          rsp2write(TRUE,0,"",NULL);
          return;
     }
     dfaSetBlk(flkdat);
     if (dfaAcqEQ(&dat,rcompkey(ulptr->libname,ulptr->filname),COMPFL_K)) {
          if (ulptr->move) {
               dfaDelete();
               if (!(dstl->flags&FLGDOS)) {
                    stzcpy(dat.filname,ulptr->newname,FLFILENM);
                    stzcpy(dat.libkey,ulptr->newlib,FLNAMESZ);
                    dfaInsert(&dat);
               }
               return;
          }
          else {
               do {
                    pos=dfaAbs();
                    stzcpy(dat.libkey,ulptr->newlib,FLNAMESZ);
                    stzcpy(dat.filname,ulptr->newname,FLFILENM);
                    addkw(dat.keyword,dat.filname,dat.libkey);
                    dfaAcqAbs(&dat,pos,COMPFL_K);
               } while (dfaAcqNX(&dat) && sameas(dat.libkey,ulptr->libname));
          }
     }
     donewrit(1);
     donewrit(2);
     rsp2write(TRUE,0,"",NULL);
}

static VOID
inimaint(                          /* initialize Library maintenance       */
GBOOL datype,                      /*   read data, not files               */
GBOOL write,                       /*   actually change vs. just list      */
GBOOL approve,                     /*   approve file if we're logging in   */
CHAR *libname)                     /*   lib to do, or "" for all           */
{
     struct fllib *libptr;

     if (libname[0] != '\0') {
          if ((libptr=libfind(libname)) == NULL) {
               prfmsg(ACTNOLIB,"maintain");
               r2wprf(FALSE);
               return;
          }
          if (libptr->flags&FLGCBD) {
               prfmsg(ACTNONCD,"maintain");
               r2wprf(FALSE);
               return;
          }
          if (libptr->flags&FLGDOS) {
               prfmsg(ACTNODOS,"maintain");
               r2wprf(FALSE);
               return;
          }
     }
     if (mainting) {
          prfmsg(MAINTING);
          r2wprf(FALSE);
          return;
     }
     mainting=TRUE;
     ulptr->reqtype=datype ? ULRMN1 : ULRMN0;
     setmem(ulptr->filname,FLFILENM,0);
     stzcpy(ulptr->newlib,libname,FLNAMESZ);
     ulptr->move=write;
     ulptr->app=approve;
     ulptr->uzfp=NULL;
     if (datype) {
          stzcpy(ulptr->libname,libname,FLNAMESZ);
     }
     else {
          setmem(ulptr->libname,FLNAMESZ,0);
     }
     cycleme(maintit);
}

static VOID
maintit(VOID)                      /* ongoing Library maintenance          */
{
     struct ffblk fb;
     CHAR misclib[FLNAMESZ],destpath[GCMAXPTH];
     struct key1 key1;
     INT miscflag,cont;
     FILE *fp;
     LONG oldflags;

     fluoff(usrnum);
     fb=flo->fb;
     movmem(flo->misclib,misclib,FLNAMESZ);
     stlcpy(destpath,flo->destpath,GCMAXPTH);
     key1=flo->key1;
     miscflag=flo->miscflag;
     fp=flo->fsrc;
     oldflags=flo->flags&APPTHEM;
     flo->fb=ulptr->fb;
     stzcpy(flo->misclib,ulptr->newlib,FLNAMESZ);
     stzcpy(flo->key1.libname,ulptr->libname,FLNAMESZ);
     stzcpy(flo->key1.filname,ulptr->filname,FLFILENM);
     flo->miscflag=ulptr->reqtype == ULRMN1 ? 1 : 2;
     flo->fsrc=ulptr->uzfp;
     flo->flags&=~APPTHEM;
     if (ulptr->newlib[0] == '\0') {
          flo->miscflag+=2;
     }
     if (ulptr->move) {
          flo->miscflag=-flo->miscflag;
     }
     setmbk(flmsg);
     switch (ulptr->reqtype) {
     case ULRMN0:
          if (ulptr->app) {
               flo->flags|=APPTHEM;
          }
          else {
               flo->flags&=~APPTHEM;
          }
          cont=srch2();
          if (cont == 2) {
               ulptr->reqtype=ULRZIP;
          }
          break;
     case ULRMN1:
          cont=srch1();
          break;
     case ULRZIP:
          if (!dizread(uzbuf)) {
               ulptr->reqtype=ULRZPW;
          }
          cont=1;
          break;
     case ULRZPW:
          if (kwbuf[0].keyword[0] == '\0') {
               gather();
               if (ulptr->app) {
                    flo->flags|=APPTHEM;
               }
               else {
                    flo->flags&=~APPTHEM;
               }
               dofiler(descedit);
               ulptr->reqtype=ULRMN0;
          }
          cont=1;
          break;
     default:
          rsp2write(TRUE,0,"",NULL);
          cont=1;
     }
     ulptr->fb=flo->fb;
     stzcpy(ulptr->libname,flo->key1.libname,FLNAMESZ);
     stzcpy(ulptr->filname,flo->key1.filname,FLFILENM);
     ulptr->uzfp=flo->fsrc;
     if (cont == 0) {
          prf("done");
          mainting=FALSE;
          r2wprf(TRUE);
     }
     flo->fb=fb;
     movmem(misclib,flo->misclib,FLNAMESZ);
     stlcpy(flo->destpath,destpath,GCMAXPTH);
     flo->key1=key1;
     flo->miscflag=miscflag;
     flo->fsrc=fp;
     flo->flags|=oldflags;
}

VOID
sendjoin(VOID)                     /* send joinings note via unsol. dpk    */
{
     struct saunam unsol;
     INT i;
     struct user *up;

     if (cnvd2s("sa=GALFIL;:rejoin",&unsol)) {
          for (i=0 ; i < nterms ; i++) {
               up=usroff(i);
               if (up->usrcls > SUPIPG && (up->flags&ISGCSU)) {
                    if (qroom(i,NORMAL)) {
                         senddpk(i,"GALFIL",NORMAL,&unsol,STGLEN,"1",NULL);
                    }
               }
          }
     }
}

static VOID
dlerr(VOID)                        /* send prfbuf d/l error to current usr */
{
     struct saunam unsol;

     depad(stp4cs(prfbuf));
     if (qroom(usrnum,NORMAL) && cnvd2s("sa=GALFIL;:dlerr",&unsol)) {
          senddpk(usrnum,"GALFIL",NORMAL,&unsol,STGLEN,prfbuf,NULL);
     }
}

static VOID
csunapan(VOID)                     /* announce to Libops of unapp'd files  */
{
     INT i,num;

     fluoff(usrnum);
     for (i=0,num=0 ; i < numoflib ; i++) {
          if (isflop(curlib=liboff(i)) && curlib->appwait > 0) {
               num+=curlib->appwait;
          }
     }
     if (num > 0) {
          setmbk(flmsg);
          if (num == 1) {
               prfmsg(CSLOPAN1);
          }
          else {
               prfmsg(CSLOPANN,num);
          }
          addannom(prfbuf,"GALFIL",lopcstg);
          rstmbk();
     }
     else {
          addanno("");
     }
}

VOID
setlcsu(                           /* set lcsu for generic reference       */
INT unum)                          /*   usrnum to set it to                */
{
     ASSERT(unum >= 0 && unum < nterms);
     lcsu=&lcsarr[unum];
}

static VOID
srcsmake(VOID)                     /* cycleme to set up join search        */
{
     fluoff(usrnum);
     if (!ccycidx()) {
          rsp2write(TRUE,0,"",NULL);
     }
}

static VOID
reg_dpk(VOID)
{
     register_dpkfda("GALFIL","sa:libedit",libcsedFDA);
     register_dpkfda("GALFIL","sauf:upload" ,filinfFDA);
}
