/***************************************************************************
 *                                                                         *
 *   WLMCFGU.C                                                             *
 *                                                                         *
 *   Copyright (c) 1997 Galacticomm, Inc.         All Rights Reserved.     *
 *                                                                         *
 *   Worldlink Messaging forum configuration management utilities.         *
 *                                                                         *
 *                                            - J. Alvrus   3/31/97        *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "wlmutl.h"
#include "wlmcfgu.h"

#define FILREV "$Revision: 1.1 $"

struct cfgrec *curcfg;             /* cache for last-used forum            */
DFAFILE *cfgbb;                    /* forum configuration data file        */
size_t cfgmax;                     /* max configuration record size        */

#define CFGREC ((struct cfgrec *)cfgbb->data)
#define CFGKEY ((struct cfgrec *)cfgbb->key)
#define CFGRLEN(pcfg) (fldoff(cfgrec,config)+strlen((pcfg)->config)+1)

GBOOL getCfgRec(const CHAR *name);
GBOOL loadCfgRec(const CHAR *name,struct cfgrec *pcfg);
VOID addupCfgRec(GBOOL existed,struct cfgrec *pcfg);
VOID updCfgRec(struct cfgrec *pcfg);
VOID addCfgRec(struct cfgrec *pcfg);
USHORT nameHash(const CHAR *name);

VOID
openCfg(                           /* open configuration file              */
const CHAR *fileName,              /*   data file name                     */
size_t maxrec)                     /*   maximum record size                */
{
     cfgmax=maxrec;
     cfgbb=dfaOpen(fileName,fldoff(cfgrec,config)+cfgmax,NULL);
     curcfg=alczer(fldoff(cfgrec,config)+cfgmax);
}

VOID
closeCfg(VOID)                     /* close configuration file             */
{
     free(curcfg);
     dfaClose(cfgbb);
}

GBOOL
isCfg(                             /* has named forum been configured?     */
const CHAR *name)                  /*   name of forum to check             */
{
     return(getCfgRec(name));
}

CHAR *                             /*   returns pointer to destination     */
getCfg(                            /* get configuration info               */
CHAR *dst,                         /*   buffer to receive result           */
size_t dstSiz,                     /*   size of destination buffer         */
const CHAR *name)                  /*   name of WL forum                   */
{
     if (getCfgRec(name)) {
          stlcpy(dst,curcfg->config,dstSiz);
     }
     else {
          *dst='\0';
     }
     return(dst);
}

CHAR *                             /*   ptr to internal buf (NULL if err)  */
getCfgPtr(                         /* get pointer to configuration info    */
const CHAR *name)                  /*   name of WL forum                   */
{
     if (getCfgRec(name)) {
          return(curcfg->config);
     }
     return(NULL);
}

CHAR *                             /*   returns pointer to destination     */
getCfgItem(                        /* get configuration item for a forum   */
CHAR *dst,                         /*   buffer to receive result           */
size_t dstSiz,                     /*   size of destination buffer         */
const CHAR *name,                  /*   name of WL forum                   */
const CHAR *sect,                  /*   configuration section name         */
const CHAR *kwd,                   /*   configuration item keyword         */
const CHAR *dft)                   /*   default value for item             */
{
     if (getCfgRec(name)) {
          return(getConfigStr(sect,kwd,dft,dst,dstSiz,curcfg->config));
     }
     return(stlcpy(dst,dft,dstSiz));
}

GBOOL                              /*   returns TRUE if able to set        */
setCfgItem(                        /* set a configuration item for a forum */
const CHAR *name,                  /*   name of WL forum                   */
const CHAR *sect,                  /*   configuration section name         */
const CHAR *kwd,                   /*   config item keyword (NULL for all) */
const CHAR *val)                   /*   new value for item (NULL to clear) */
{
     GBOOL existed;

     if (!(existed=loadCfgRec(name,curcfg))) {
          unpad(stlcpy(curcfg->name,skptwht(name),MAXFNAM));
          *curcfg->config='\0';
     }
     if (setConfigStr(sect,kwd,val,curcfg->config,cfgmax)) {
          addupCfgRec(existed,curcfg);
          return(TRUE);
     }
     *curcfg->name='\0';
     return(FALSE);
}

GBOOL                              /*   returns TRUE if room in config buf */
editCfg(                           /* edit configuration info for a forum  */
CHAR *src,                         /*   config str w/ items to change      */
const CHAR *name)                  /*   name of WL forum                   */
{
     GBOOL existed;

     if (!(existed=loadCfgRec(name,curcfg))) {
          unpad(stlcpy(curcfg->name,skptwht(name),MAXFNAM));
          *curcfg->config='\0';
     }
     if (!mergeConfig(curcfg->config,src,cfgmax)) {
          *curcfg->name='\0';
          return(FALSE);
     }
     addupCfgRec(existed,curcfg);
     return(TRUE);
}

VOID
clearCfg(                          /* delete all config info for a forum   */
const CHAR *name)                  /*   name of WL forum                   */
{
     if (sameas(curcfg->name,name)) {
          *curcfg->name='\0';
     }
     if (loadCfgRec(name,NULL)) {
          dfaSetBlk(cfgbb);
          dfaDelete();
          dfaRstBlk();
     }
}

GBOOL
getCfgRec(                         /* get configuration record into curcfg */
const CHAR *name)                  /*   name of forum to read              */
{
     CHAR tmpName[MAXFNAM];

     return(sameas(curcfg->name,unpad(stlcpy(tmpName,skptwht(name),MAXFNAM)))
         || loadCfgRec(tmpName,curcfg));
}

GBOOL
loadCfgRec(                        /* load a configuration record          */
const CHAR *name,                  /*   name of forum to read              */
struct cfgrec *pcfg)               /*   buffer to load                     */
{
     GBOOL fnd;
     struct cfgkey key;
     CHAR tmpName[MAXFNAM];

     key.hash=nameHash(unpad(stlcpy(tmpName,skptwht(name),MAXFNAM)));
     key.tiebrk=0;
     dfaSetBlk(cfgbb);
     for (fnd=dfaAcqGE(NULL,&key,0)
        ; fnd && CFGKEY->hash == key.hash
        ; fnd=dfaAcqGT(NULL,NULL,0)) {
          if (sameas(CFGREC->name,tmpName)) {
               if (pcfg != NULL) {
                    memcpy(pcfg,cfgbb->data,dfaLastLen());
               }
               dfaRstBlk();
               return(TRUE);
          }
     }
     dfaRstBlk();
     return(FALSE);
}

VOID
addupCfgRec(                       /* add or update configuration record   */
GBOOL existed,                     /*   record already present             */
struct cfgrec *pcfg)               /*   buffer to save                     */
{
     if (existed) {
          updCfgRec(pcfg);
     }
     else {
          addCfgRec(pcfg);
     }
}

VOID
updCfgRec(                         /* save an existing configuration record*/
struct cfgrec *pcfg)               /*   buffer to save                     */
{
     dfaSetBlk(cfgbb);
     dfaUpdateV(pcfg,CFGRLEN(pcfg));
     dfaRstBlk();
}

VOID
addCfgRec(                         /* save a new configuration record      */
struct cfgrec *pcfg)               /*   buffer to save                     */
{
     ASSERT(pcfg != NULL);
     ASSERT(skptwht(pcfg->name) == pcfg->name);
     ASSERT(strpln(pcfg->name) == strlen(pcfg->name));
     pcfg->hash=nameHash(pcfg->name);
     pcfg->tiebrk=0;
     dfaSetBlk(cfgbb);
     while (dfaAcqEQ(NULL,pcfg,0)) {
          ASSERT(CFGKEY->hash == pcfg->hash);
          if (sameas(CFGREC->name,pcfg->name)) {
               dfaDelete();
               break;
          }
          ++pcfg->tiebrk;
     }
     dfaInsertV(pcfg,CFGRLEN(pcfg));
     dfaRstBlk();
}

USHORT
nameHash(                          /* generate hash value for WL forum name*/
const CHAR *name)                  /*   name to hash                       */
{
     CHAR tmpName[MAXFNAM];

     ASSERT(skptwht(name) == name);
     ASSERT(strpln(name) == strlen(name));
     strlwr(stlcpy(tmpName,name,MAXFNAM));
     return(crc16(tmpName,strlen(tmpName)));
}
