/***************************************************************************
 *                                                                         *
 *   GCSGAGT.C                                                             *
 *                                                                         *
 *   Copyright (c) 1994-1997 Galacticomm, Inc.        All rights reserved. *
 *                                                                         *
 *   This file contains all routines used to create and maintain           *
 *   information on generic agents, and to permit generic agents to read   *
 *   and write to the generic dynapak database.                            *
 *                                                                         *
 *                                                  - C. Robert  6/21/94   *
 *                                                  - Bill Hyatt           *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "gcspsrv.h"
#include "majorbbs.h"
#include "gcsasys.h"
#include "wgserver.h"

#define   FILREV    "$Revision: 8 $"

#define   MAXGAS    500            /* maximum number of generic agents     */
#define   APPLIM    2147483647L    /* maximum number of bytes, each agent  */
#define   TOTLIM    2147483647L    /* maximum number of bytes, all agents  */
#define   GABLKS    20             /* generic agent alcrsz() block size    */
#define   GAGTDIR   "gcsgagt"SLS   /* path for generic agent files         */
#define   MAXGDR    (GCMAXPTH-GCMAXFNM-1-AIDSIZ-1-1)
                                   /* maximum size of generic dpk file dir */

static VOID garead(INT direction,struct saunam *dpknam);
static VOID gawrite(struct saunam *dpknam,USHORT length,VOID *value);
static VOID gaxdone(VOID);
static VOID gaabort(VOID);
static GBOOL fndgagt(CHAR *appid);
static VOID clsgenagt(VOID);

struct agent genagt={              /* agent information structure          */
     "",                           /*   appid                              */
     garead,                       /*   read-dynapak function pointer      */
     gawrite,                      /*   write-dynapak function pointer     */
     gaxdone,                      /*   file xfer-done function pointer    */
     gaabort                       /*   abort-request function pointer     */
};

CHAR *gagtkey;                     /* key required to use generic agent    */

ULONG tspace=0L;                   /* total disk space being taken up      */

INT ngagts=0,                      /* total number of generic agents       */
    ngalcd=0;                      /* total generic agents allocated for   */

struct gainfo {                    /* generic agent information structure  */
     CHAR appid[AIDSIZ];           /*   appid                              */
     ULONG space;                  /*   disk space being taken up          */
} *genagts,                        /* in-memory list of generic agents     */
  *gagtptr;                        /* current generic agent pointer        */

struct gapreq {                    /* per-request memory for generic agent */
     ULONG size;                   /*   size of current write request      */
     CHAR fspec[GCMAXPTH];         /*   filespec associated with request   */
     USHORT time;                  /*   time stamp on filespec             */
     USHORT date;                  /*   date stamp on filespec             */
     struct saunam dpknam;         /*   dynapak name                       */
};

#define garptr ((struct gapreq *)mrqptr)

VOID
inigenagt(VOID)                    /* initialize generic agent support     */
{
     struct saunam totsau;
     CHAR crenam[MAXGDR];

     setmbk(gcsmb);
     gagtkey=stgopt(GAGTKEY);
     rstmbk();
     cnvd2s("s:spcgdpk",&totsau);
     readgdpEQ(&totsau,sizeof(ULONG),&tspace,NULL);
     stlcpy(crenam,GAGTDIR,min(strlen(GAGTDIR),MAXGDR));
     MKDIR(crenam);
     dclmrq(sizeof(struct gapreq));
     hook_shutdown(clsgenagt);
}

static VOID
garead(                            /* generic agent: field read-request    */
INT direction,
struct saunam *dpknam)
{
     if (stdchk(gagtkey)) {
          r2rgdp(direction,dpknam);
          return;
     }
     rejectreq();
}

static VOID
gawrite(                           /* generic agent: field write-request   */
struct saunam *dpknam,
USHORT length,
VOID *value)
{
     ULONG oldlen;
     static struct ffblk fb;

     fndgagt(dpknam->appid);
     ASSERT(gagtptr != NULL);
     if (stdchk(gagtkey)) {
          movmem(dpknam,&garptr->dpknam,sizeof(struct saunam));
          oldlen=readgdpEQ(dpknam,0,NULL,NULL);
          if ((dpknam->flags&FLGFIL) && fndfile(&fb,GDPBTR->value,0)) {
               oldlen+=fb.ff_fsize;
          }
          if ((dpknam->flags&FLGFIL) && length != 0) {
               if (tspace+FINFPTR->size+length <= TOTLIM+oldlen
                   && gagtptr->space+FINFPTR->size+length <= APPLIM+oldlen) {
                    unlink(GDPBTR->value);
                    stzcpy(garptr->fspec,
                    spr("%s%s"SLS"%s",GAGTDIR,dpknam->appid,
                      FINFPTR->name),GCMAXPTH);
                    writegdp(dpknam,STGLEN,garptr->fspec,NULL);
                    ok2write(garptr->fspec);
                    garptr->time=FINFPTR->time;
                    garptr->date=FINFPTR->date;
                    garptr->size=strlen(garptr->fspec)+FINFPTR->size;
                    tspace-=min(oldlen,tspace);
                    tspace+=garptr->size;
                    gagtptr->space-=min(oldlen,gagtptr->space);
                    gagtptr->space+=garptr->size;
                    return;
               }
          }
          else if (tspace+length <= TOTLIM+oldlen
                   && gagtptr->space+length <= APPLIM+oldlen) {
               if (dpknam->flags&FLGFIL) {   /* deleting file dynapak */
                    unlink(GDPBTR->value);
               }
               writegdp(dpknam,length,value,NULL);
               rsp2write(TRUE,0,NULL,NULL);
               tspace-=min(oldlen,tspace);
               tspace+=length;
               gagtptr->space-=min(oldlen,gagtptr->space);
               gagtptr->space+=length;
               return;
          }
     }
     rejectreq();
}

static VOID
gaxdone(VOID)                      /* generic agent: handle end of transfer*/
{
     if (iswrite()) {
          setFileTm(garptr->fspec,garptr->time,garptr->date);
          rsp2write(TRUE,0,NULL,NULL);
     }
}

static VOID
gaabort(VOID)                      /* generic agent: abort read/write req  */
{
     if (iswrite()) {
          unlink(garptr->fspec);
          writegdp(&garptr->dpknam,0,NULL,NULL);
          tspace-=min(garptr->size,tspace);
          gagtptr->space-=min(garptr->size,gagtptr->space);
     }
}

GBOOL
newgenagt(                         /* add a new generic agent              */
CHAR *appid)                       /*   appid to add generic agent for     */
{
     struct saunam appsau;
     ULONG curspc=0L;

     if (!haskey(gagtkey) || ngagts >= MAXGAS) {
          return(FALSE);
     }
     if (fndgagt(appid)) {
          return(TRUE);
     }
     MKDIR(spr("%s%s",GAGTDIR,appid));
     stzcpy(genagt.appid,appid,AIDSIZ);
     register_agent(&genagt);
     if (ngalcd <= ngagts) {
          if (ngalcd == 0) {
               genagts=(struct gainfo *)alcmem(sizeof(struct gainfo)*GABLKS);
          }
          else {
               genagts=(struct gainfo *)alcrsz(genagts,
                                sizeof(struct gainfo)*ngalcd,
                                sizeof(struct gainfo)*
                                (ngalcd+GABLKS));
          }
          ngalcd+=GABLKS;
     }
     stzcpy(genagts[ngagts].appid,appid,AIDSIZ);
     cnvd2s(spr("s:spcgdpk %s",appid),&appsau);
     readgdpEQ(&appsau,sizeof(ULONG),&curspc,NULL);
     genagts[ngagts].space=curspc;
     ngagts++;
     return(TRUE);
}

static GBOOL
fndgagt(                           /* find a generic agent in table        */
CHAR *appid)                       /*   appid of agent to find             */
{
     INT i;

     for (i=0 ; i < ngagts ; i++) {
          if (sameas(appid,genagts[i].appid)) {
              gagtptr=&genagts[i];
              return(TRUE);
          }
     }
     gagtptr=NULL;
     return(FALSE);
}

static VOID
clsgenagt(VOID)                    /* close down generic agent support     */
{
     INT i;
     struct saunam totsau;

     for (i=0 ; i < ngagts ; i++) {
          cnvd2s(spr("s:spcgdpk %s",genagts[i].appid),&totsau);
          writegdp(&totsau,sizeof(ULONG),&genagts[i].space,NULL);
     }
     cnvd2s("s:spcgdpk",&totsau);
     writegdp(&totsau,sizeof(ULONG),&tspace,NULL);
}
