/***************************************************************************
 *                                                                         *
 *   WLMCSMC.C                                                             *
 *                                                                         *
 *   Copyright (c) 1997 Galacticomm, Inc.         All Rights Reserved.     *
 *                                                                         *
 *   Worldlink Messaging Client management module (C/S).                   *
 *                                                                         *
 *                                            - J. Alvrus   3/12/97        *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "gcspsrv.h"
#include "worldlnk.h"
#include "gme.h"
#include "chandir.h"
#include "wormsg.h"
#include "wlmutl.h"
#include "wlmstoru.h"
#include "wlmcfgu.h"
#include "wlmcfgc.h"
#include "wlmimpc.h"
#include "wlmexpc.h"
#include "wlmmodc.h"
#include "wlmcsmc.h"

#define FILREV "$Revision: 4 $"

                                   /* dynapak names                        */
#define FORLSTDPK   "saf:forumlist"/*   forum list dynapak (read)          */
#define DFTCFGDPK   "sa:dftcfg"    /*   default forum config info (read)   */
#define GETCFGDPK   "sa:getcfg"    /*   get forum config info (write)      */
#define SETCFGDPK   "sa:setcfg"    /*   set forum config info (write)      */
#define NOTIFYDPK   "sa:notify"    /*   set/clear event notification (wrt) */
#define STATSFX     "systat"       /*   get system status dpk suffix       */
#define STATDPK     "sa:"STATSFX   /*   get system status dpk name (read)  */
#define MODSTADPK   "sa:startmod"  /*   start module dynapak name (write)  */
#define MODSTODPK   "sa:stopmod"   /*   stop module dynapak name (write)   */
#define RESETDPK    "sa:reset"     /*   reset connection to hub (write)    */
#define GETINFDPK   "sa:getinfo"   /*   get global info from hub (read)    */
#define GETRDETDPK  "sa:getrdet"   /*   get forum details from hub (write) */
#define GETRCFGDPK  "sa:getrcfg"   /*   get forum config from hub (write)  */
#define CRTRFORDPK  "sa:crtrfor"   /*   create forum on hub (write)        */
#define MODRFORDPK  "sa:modrfor"   /*   modify forum on hub (write)        */
#define DELRFORDPK  "sa:delrfor"   /*   delete forum on hub (write)        */
#define GETRACCDPK  "sa:getracc"   /*   get forum access from hub (write)  */
#define GETRNDADPK  "sa:getrnda"   /*   get non-default forum acc (write)  */
#define SETRACCDPK  "sa:setracc"   /*   set forum access on hub (write)    */
#define INFCHGSFX   "infochg"      /*   forum list/global info changed sfx */

                                   /* WL mail system module names          */
#define ST_WOR  "Worldlink"        /*   Worldlink connected status         */
#define ST_SEND "Sender"           /*   message sender                     */
#define ST_RECV "Receiver"         /*   message receiver                   */
#define ST_IMP  "Importer"         /*   background importer                */
#define ST_MGR  "Manager"          /*   management system activity         */
#define ST_GEN  "System"           /*   general system activity            */

struct forListInfo {               /* forum list file per-request info     */
     INT fidx;                     /*   index of forum being examined      */
     FILE *ifp;                    /*   file pointer being read from       */
     FILE *ofp;                    /*   file pointer being written to      */
     CHAR fnam[GCMAXPTH];          /*   name of file being written to      */
};

struct hubInfo {                   /* used for getting info from the hub   */
     INT op;                       /*   operation in progress              */
     CHAR name[MAXFNAM];           /*   WL forum name                      */
};
                                   /* hub operation type codes             */
#define HOP_NORM    0              /*   doesn't require special handling   */
#define HOP_SETACC  1              /*   setting remote forum access        */

struct wlmReqInfo {                /* WL messaging per-request info        */
     INT reqType;                  /*   request type                       */
     union {
          struct forListInfo flst;
          struct hubInfo hinf;
     } u;
};

#define PRQ ((struct wlmReqInfo *)mrqptr)
#define FLSTRQ (PRQ->u.flst)
#define HINFRQ (PRQ->u.hinf)

                                   /* request type identifiers             */
#define RQT_FORLST 1               /*   forum list file download           */
#define RQT_HUBINF 2               /*   getting info from hub              */

VOID wlmRead(INT direction,struct saunam *dpknam);
VOID wlmWrite(struct saunam *dpknam,USHORT length,VOID *value);
VOID wlmXdone(VOID);
VOID wlmAbort(VOID);

struct agent wlmagt={              /* agent information structure          */
     WLMAPID,                      /*   appid                              */
     wlmRead,                      /*   read-dynapak function pointer      */
     wlmWrite,                     /*   write-dynapak function pointer     */
     wlmXdone,                     /*   file xfer-done function pointer    */
     wlmAbort                      /*   abort-request function pointer     */
};

GBOOL wlMgrActive=FALSE;           /* has management module been init?     */

CHAR wlForumList[GCMAXPTH];        /* path & file name of all forums list  */
CHAR *csMgrKey;                    /* key to use C/S management module     */
CHAR dftcfg[WLMAXFCFG];            /* default forum configuration          */

INT fcpypc;                        /* forums to copy to list file/cycle    */
INT faddpc;                        /* forums to add to list file/cycle     */
INT fchkpc;                        /* max forums to check per cycle        */

INT maxntfy;                       /* max users to receive notifications   */
struct ntfy {                      /* notification info structure          */
     INT usr;                      /*   channel number to notify on        */
     CHAR app[AIDSIZ];             /*   app-ID to receive notification     */
} *ntfyapp=NULL;                   /* array of notifiers                   */

struct wmsgen {                    /* generic user database record struct  */
     CHAR userid[UIDSIZ];          /*   User-ID                            */
     CHAR modnam[MNMSIZ];          /*   Module Name                        */
     CHAR info[1];                 /*   saved info                         */
};

#define GENREC ((struct wmsgen *)genbb->data)
#define GENBUF (GENREC->info)
#define GENMAX (GENSIZ-fldoff(wmsgen,info))
#define GENLEN(s) (fldoff(wmsgen,info)+strlen(s)+1)

VOID wlmDisc(VOID);
VOID cpyflst(VOID);
VOID cmkflst(VOID);
const CHAR *flstfil(VOID);
VOID hdlSetCfg(CHAR *cfg);
GBOOL setntfy(const CHAR *appid);
VOID delntfy(VOID);
CHAR *formSysStat(CHAR *dst,size_t dstSiz);
const CHAR *statWor(VOID);
VOID startMod(const CHAR *modid);
VOID stopMod(const CHAR *modid);
VOID hdlReset(VOID);
VOID hdlHubDetails(const CHAR *forName);
VOID hdlHubConfig(const CHAR *forName);
VOID hdlHubCreate(const CHAR *cfg);
VOID hdlHubModify(const CHAR *cfg);
VOID hdlHubDelete(const CHAR *forName);
VOID hdlHubGetAcc(const CHAR *forsys);
VOID hdlHubGetNDA(const CHAR *forName);
VOID hdlHubSetAcc(const CHAR *forsys);
GBOOL chkConn(VOID);
struct saunam *formDpkName(struct saunam *dpknam,const CHAR *suffix);
VOID notifyClients(struct saunam *dpknam,size_t length,VOID *value);

GBOOL
initCSMgr(VOID)                    /* initialize management module         */
{
     INT i;

     makePath(wlForumList,mailRoot,FLSTNAM,GCMAXPTH);
     csMgrKey=stgopt(CSMGRKY);
     fcpypc=numopt(FCPYPC,1,32767);
     faddpc=numopt(FADDPC,1,32767);
     fchkpc=numopt(FCHKPC,1,32767);
     *dftcfg='\0';
     setConfigStr(NULL,FC_APVATT,l2as((LONG)dftAutoApv),dftcfg,WLMAXFCFG);
     setConfigStr(NULL,FC_MAXATT,l2as(dftMaxForAtt),dftcfg,WLMAXFCFG);
     setConfigStr(NULL,FC_NETCANI,l2as((LONG)dftNetCanIn),dftcfg,WLMAXFCFG);
     setConfigStr(NULL,FC_NETCANO,l2as((LONG)dftNetCanOut),dftcfg,WLMAXFCFG);
     setConfigStr(NULL,FC_NETMODI,l2as((LONG)dftNetModIn),dftcfg,WLMAXFCFG);
     setConfigStr(NULL,FC_NETMODO,l2as((LONG)dftNetModOut),dftcfg,WLMAXFCFG);
     if ((maxntfy=numopt(MAXNTFY,0,32767)) != 0) {
          ntfyapp=alcmem(maxntfy*sizeof(struct ntfy));
          for (i=0 ; i < maxntfy ; ++i) {
               ntfyapp[i].usr=-1;
               *ntfyapp[i].app='\0';
          }
     }
     register_agent(&wlmagt);
     hook_disconnect(wlmDisc);
     wlMgrActive=TRUE;
     return(TRUE);
}

VOID
closeCSMgr(VOID)                   /* shut down management module          */
{
     if (wlMgrActive) {
          free(csMgrKey);
     }
     wlMgrActive=FALSE;
}

VOID
wlmDisc(VOID)                      /* disconnect handler                   */
{
     delntfy();
}

VOID
wlmRead(                           /* dynapak read handler                 */
INT direction,                     /*   read direction                     */
struct saunam *dpknam)             /*   dynapak name being read            */
{
     CHAR *dpkstr;

     if (!wlMgrActive || !stdchk(csMgrKey)) {
          rejectreq();
          return;
     }
     setmbk(wlmb);
     dpkstr=cnvs2d(dpknam);
     if (sameas(STATDPK,dpkstr) && direction == 0) {
          rsp2read(NULL,STGLEN,formSysStat(rsptmp,MAXDPKV),NULL);
          return;
     }
     if (sameas(GETINFDPK,dpkstr)) {
          rsp2read(NULL,STGLEN,getGlobalInfo(),NULL);
          return;
     }
     if (sameas(DFTCFGDPK,dpkstr) && direction == 0) {
          rsp2read(NULL,STGLEN,dftcfg,NULL);
          return;
     }
     if (sameas(FORLSTDPK,dpkstr) && direction == 0) {
          PRQ->reqType=RQT_FORLST;
          stlcpy(FLSTRQ.fnam,flstfil(),GCMAXPTH);
          if ((FLSTRQ.ofp=fopen(FLSTRQ.fnam,FOPWA)) == NULL) {
               rejectreq();
               return;
          }
          if ((FLSTRQ.ifp=fopen(wlForumList,FOPRA)) == NULL) {
               cycleme(cmkflst);
               cmkflst();
          }
          else {
               cycleme(cpyflst);
               cpyflst();
          }
          return;
     }
     rejectreq();
}

VOID
wlmWrite(                          /* dynapak write handler                */
struct saunam *dpknam,             /*   dynapak name being written         */
USHORT length,                     /*   length of contents                 */
VOID *value)                       /*   contents of dynapak                */
{
     CHAR *dpkstr;

     if (!wlMgrActive || !stdchk(csMgrKey)) {
          rejectreq();
          return;
     }
     setmbk(wlmb);
     dpkstr=cnvs2d(dpknam);
     if (sameas(GETCFGDPK,dpkstr)) {
          getCfg(rsptmp,MAXDPKV,value);
          rsp2write(TRUE,STGLEN,rsptmp,NULL);
          return;
     }
     if (sameas(SETCFGDPK,dpkstr)) {
          hdlSetCfg(value);
          return;
     }
     if (sameas(NOTIFYDPK,dpkstr)) {
          if (length == 0) {
               delntfy();
               rsp2write(TRUE,0,NULL,NULL);
          }
          else {
               rsp2write(setntfy(value),0,NULL,NULL);
          }
          return;
     }
     if (sameas(MODSTADPK,dpkstr)) {
          startMod(value);
          return;
     }
     if (sameas(MODSTODPK,dpkstr)) {
          stopMod(value);
          return;
     }
     if (sameas(RESETDPK,dpkstr)) {
          hdlReset();
          return;
     }
     if (sameas(GETRDETDPK,dpkstr)) {
          hdlHubDetails(value);
          return;
     }
     if (sameas(GETRCFGDPK,dpkstr)) {
          hdlHubConfig(value);
          return;
     }
     if (sameas(CRTRFORDPK,dpkstr)) {
          hdlHubCreate(value);
          return;
     }
     if (sameas(MODRFORDPK,dpkstr)) {
          hdlHubModify(value);
          return;
     }
     if (sameas(DELRFORDPK,dpkstr)) {
          hdlHubDelete(value);
          return;
     }
     if (sameas(GETRACCDPK,dpkstr)) {
          hdlHubGetAcc(value);
          return;
     }
     if (sameas(GETRNDADPK,dpkstr)) {
          hdlHubGetNDA(value);
          return;
     }
     if (sameas(SETRACCDPK,dpkstr)) {
          hdlHubSetAcc(value);
          return;
     }
     rejectreq();
}

VOID
wlmXdone(VOID)                     /* file transfer done handler           */
{
     if (!wlMgrActive) {
          return;
     }
     switch (PRQ->reqType) {
     case RQT_FORLST:
          unlink(FLSTRQ.fnam);
          break;
     }
}

VOID
wlmAbort(VOID)                     /* dynapak aborted handler              */
{
     if (!wlMgrActive) {
          return;
     }
     switch (PRQ->reqType) {
     case RQT_FORLST:
          if (FLSTRQ.ifp != NULL) {
               fclose(FLSTRQ.ifp);
               FLSTRQ.ifp=NULL;
          }
          if (FLSTRQ.ofp != NULL) {
               fclose(FLSTRQ.ofp);
               FLSTRQ.ofp=NULL;
          }
          unlink(FLSTRQ.fnam);
          break;
     case RQT_HUBINF:
          mgrCancel(greqid);
          break;
     }
}

VOID
cpyflst(VOID)                      /* cycled copy list of forums           */
{
     INT i,flg;
     CHAR *cp;

     for (i=0 ; i < fcpypc ; ++i) {
          if (fgets(vdatmp,vdasiz,FLSTRQ.ifp) == NULL) {
               fclose(FLSTRQ.ifp);
               FLSTRQ.ifp=NULL;
               cycleme(cmkflst);
               return;
          }
          if ((cp=strchr(vdatmp,' ')) != NULL) {
               *cp++='\0';
          }
          flg=atoi(cp)&FAF_VALID;
          unpad(vdatmp);
          ASSERT(!isspace(vdatmp[0]));
          if (isCfg(vdatmp)) {
               flg|=FAF_ISCFG;
          }
          fprintf(FLSTRQ.ofp,"%s\t%d\n",vdatmp,flg);
     }
}

VOID
cmkflst(VOID)                      /* cycled make forum list function      */
{
     INT nchk,nadd,i,nfor;
     CHAR *cp;
     const adr_t *echo;
     const struct fordef *fdef;

     nfor=numforums();
     for (nchk=nadd=0 ; nchk < fchkpc && nadd < faddpc ; ++nchk) {
          if (FLSTRQ.fidx >= nfor) {
               fclose(FLSTRQ.ofp);
               FLSTRQ.ofp=NULL;
               cycleme(NULL);
               rsp2read(NULL,STGLEN,FLSTRQ.fnam,NULL);
               return;
          }
          fdef=fiddefp(FLSTRQ.fidx++);
          echo=(const adr_t *)fdef->echoes;
          for (i=0 ; i < fdef->necho ; ++i) {
               if (sameto(wfpfx,echo[i])) {
                    cp=skppfx(echo[i]);
                    fprintf(FLSTRQ.ofp,"%s\t%d\t%s\n",
                            cp,isCfg(cp) ? FAF_ISCFG : 0,fdef->name);
                    ++nadd;
               }
          }
     }
}

const CHAR *
flstfil(VOID)                      /* form temp file name for forum list   */
{
     static CHAR retbuf[GCMAXPTH];

     chdmak();
     stlcpy(retbuf,uchdpath(usrnum,WLMAPID),GCMAXPTH);
     MKDIR(retbuf);
     return(makePath(retbuf,NULL,tmpanam(NULL),GCMAXPTH));
}

VOID
hdlSetCfg(                         /* handle set-config dynapak            */
CHAR *cfg)                         /*   updated configuration              */
{
     CHAR fnam[MAXFNAM];

     if (*getConfigStr(NULL,WFK_NAME,"",fnam,MAXFNAM,cfg) == '\0') {
          prfmsg(CFGNONAM);
          r2wprf(FALSE);
          return;
     }
     setConfigStr(NULL,WFK_NAME,NULL,cfg,MAXDPKV);
     if (*cfg == '\0') {
          clearCfg(fnam);
     }
     else {
          if (!editCfg(cfg,fnam)) {
               prfmsg(CFGROOM);
               r2wprf(FALSE);
               return;
          }
     }
     rsp2write(TRUE,0,NULL,NULL);
}

VOID
statUpdate(VOID)                   /* system status has changed            */
{
     struct saunam dpknam;

     formSysStat(vdatmp,vdasiz);
     notifyClients(formDpkName(&dpknam,STATSFX),STGLEN,vdatmp);
}

GBOOL                              /*   returns TRUE if successful         */
setntfy(                           /* set notification app for this channel*/
const CHAR *appid)                 /*   App-ID to receive notification     */
{
     INT i;

     delntfy();
     for (i=0 ; i < maxntfy ; ++i) {
          if (ntfyapp[i].usr < 0) {
               ntfyapp[i].usr=usrnum;
               stlcpy(ntfyapp[i].app,appid,AIDSIZ);
               return(TRUE);
          }
     }
     return(FALSE);
}

VOID
delntfy(VOID)                      /* remove notification for this channel */
{
     INT i;

     for (i=0 ; i < maxntfy ; ++i) {
          if (ntfyapp[i].usr == usrnum) {
               ntfyapp[i].usr=-1;
               *ntfyapp[i].app='\0';
          }
     }
}

CHAR *                             /*   returns pointer to destination     */
formSysStat(                       /* form system statistics string        */
CHAR *dst,                         /*   buffer to fill in                  */
size_t dstSiz)                     /*   size of buffer                     */
{
     *dst='\0';
     setConfigStr(NULL,ST_WOR,statWor(),dst,dstSiz);
     setConfigStr(NULL,ST_SEND,statSend(),dst,dstSiz);
     setConfigStr(NULL,ST_RECV,statRecv(),dst,dstSiz);
     setConfigStr(NULL,ST_IMP,statImp(),dst,dstSiz);
     setConfigStr(NULL,ST_MGR,statMgr(),dst,dstSiz);
     setConfigStr(NULL,ST_GEN,statSys(),dst,dstSiz);
     clrprf();
     return(dst);
}

const CHAR *                       /*   pointer to internal buffer         */
statWor(VOID)                      /* get Worldlink connected status       */
{
     setmbk(wlmb);
     clrprf();
     prfmsg(worConnected() ? STWCONN : STWDISC);
     stpans(prfbuf);
     rstmbk();
     return(prfbuf);
}

VOID
startMod(                          /* handle start-module dynapak          */
const CHAR *modnam)                /*   WL mail system module name         */
{
     if (sameas(ST_SEND,modnam)) {
          sndStart();
     }
     else if (sameas(ST_RECV,modnam)) {
          rcvStart();
     }
     else if (sameas(ST_IMP,modnam)) {
          impStart();
     }
     rsp2write(TRUE,0,NULL,NULL);
}

VOID
stopMod(                           /* handle stop-module dynapak           */
const CHAR *modnam)                /*   WL mail system module name         */
{
     if (sameas(ST_SEND,modnam)) {
          sndStop();
     }
     else if (sameas(ST_RECV,modnam)) {
          rcvStop();
     }
     else if (sameas(ST_IMP,modnam)) {
          impStop();
     }
     else if (sameas(ST_MGR,modnam)) {
          mgrStop();
     }
     else if (sameas(ST_GEN,modnam)) {
          genStop();
     }
     rsp2write(TRUE,0,NULL,NULL);
}

VOID
hdlReset(VOID)                     /* handle reset-connection dynapak      */
{
     resetSys();
     rsp2write(TRUE,0,NULL,NULL);
}

VOID
infoChangeCS(VOID)                 /* forum list or global info changed    */
{
     struct saunam dpknam;

     notifyClients(formDpkName(&dpknam,INFCHGSFX),0,NULL);
}

VOID
setGlobalInfo(                     /* save global hub info                 */
const CHAR *info)                  /*   info string from hub               */
{
     *GENREC->userid='\0';
     stlcpy(GENREC->modnam,WLMAPID,MNMSIZ);
     dfaSetBlk(genbb);
     if (dfaAcqEQ(NULL,GENREC,0)) {
          stlcpy(GENBUF,info,GENMAX);
          dfaUpdateV(NULL,GENLEN(info));
     }
     else {
          stlcpy(GENBUF,info,GENMAX);
          dfaInsertV(NULL,GENLEN(info));
     }
     dfaRstBlk();
}

const CHAR *
getGlobalInfo(VOID)                /* get saved global hub info            */
{
     *GENREC->userid='\0';
     stlcpy(GENREC->modnam,WLMAPID,MNMSIZ);
     *GENBUF='\0';
     dfaSetBlk(genbb);
     dfaAcqEQ(NULL,GENREC,0);
     dfaRstBlk();
     return(GENBUF);
}

VOID
hdlHubDetails(                     /* get details on a forum on hub        */
const CHAR *forName)               /*   WL forum name                      */
{
     PRQ->reqType=RQT_HUBINF;
     HINFRQ.op=HOP_NORM;
     if (chkConn() && !mgrGetDetails(forName,greqid,mopResp,mopAbort)) {
          prfmsg(MEBUSY);
          r2wprf(FALSE);
     }
}

VOID
hdlHubConfig(                      /* get forum configuration from hub     */
const CHAR *forName)               /*   WL forum name                      */
{
     PRQ->reqType=RQT_HUBINF;
     HINFRQ.op=HOP_NORM;
     if (chkConn() && !mgrGetConfig(forName,greqid,mopResp,mopAbort)) {
          prfmsg(MEBUSY);
          r2wprf(FALSE);
     }
}

VOID
hdlHubCreate(
const CHAR *cfg)
{
     PRQ->reqType=RQT_HUBINF;
     HINFRQ.op=HOP_NORM;
     if (chkConn() && !mgrCreateFor(cfg,greqid,mopResp,mopAbort)) {
          prfmsg(MEBUSY);
          r2wprf(FALSE);
     }
}

VOID
hdlHubModify(
const CHAR *cfg)
{
     PRQ->reqType=RQT_HUBINF;
     HINFRQ.op=HOP_NORM;
     if (chkConn() && !mgrModifyFor(cfg,greqid,mopResp,mopAbort)) {
          prfmsg(MEBUSY);
          r2wprf(FALSE);
     }
}

VOID
hdlHubDelete(
const CHAR *forName)
{
     PRQ->reqType=RQT_HUBINF;
     HINFRQ.op=HOP_NORM;
     if (chkConn() && !mgrDeleteFor(forName,greqid,mopResp,mopAbort)) {
          prfmsg(MEBUSY);
          r2wprf(FALSE);
     }
}

VOID
hdlHubGetAcc(                      /* get forum access from hub            */
const CHAR *forsys)                /*   forum and list of systems          */
{
     PRQ->reqType=RQT_HUBINF;
     HINFRQ.op=HOP_NORM;
     if (chkConn() && !mgrGetAccess(forsys,greqid,mopResp,mopAbort)) {
          prfmsg(MEBUSY);
          r2wprf(FALSE);
     }
}

VOID
hdlHubGetNDA(                      /* get non-default forum access from hub*/
const CHAR *forName)               /*   WL forum name                      */
{
     PRQ->reqType=RQT_HUBINF;
     HINFRQ.op=HOP_NORM;
     if (chkConn() && !mgrGetNonDft(forName,greqid,mopResp,mopAbort)) {
          prfmsg(MEBUSY);
          r2wprf(FALSE);
     }
}

VOID
hdlHubSetAcc(                      /* get non-default forum access from hub*/
const CHAR *forsys)                /*   forum and list of systems          */
{
     CHAR *cp;

     PRQ->reqType=RQT_HUBINF;
     HINFRQ.op=HOP_SETACC;
     if ((cp=strchr(stlcpy(HINFRQ.name,forsys,MAXFNAM),'\n')) != NULL) {
          *cp='\0';
     }
     if (chkConn() && !mgrSetAccess(forsys,greqid,mopResp,mopAbort)) {
          prfmsg(MEBUSY);
          r2wprf(FALSE);
     }
}

GBOOL
chkConn(VOID)                      /* handle not-connected state           */
{
     if (!worConnected()) {
          prfmsg(MENOC);
          r2wprf(FALSE);
          return(FALSE);
     }
     return(TRUE);
}

VOID
mopResp(                           /* got response to management operation */
INT reqid,                         /*   request ID getting response        */
const CHAR *value)                 /*   info returned by hub               */
{
     INT savreq,acc;
     CHAR *cp,sysnam[WBOASIZ];

     if (ismyreq(reqid,WLMAPID)) {
          savreq=greqid;
          curreq(reqid);
          if (PRQ->reqType == RQT_HUBINF) {
               switch (HINFRQ.op) {
               case HOP_NORM:
                    rsp2write(TRUE,STGLEN,value,NULL);
                    break;
               case HOP_SETACC:
                    ASSERT(value != rsptmp);
                    if ((cp=strchr(value,'\n')) != NULL) {
                         *cp++='\0';
                    }
                    if (sameas(value,HINFRQ.name)) {
                         setmbk(wlmb);
                         *rsptmp='\0';
                         while ((cp=parseAccLine(cp,sysnam,&acc)) != NULL) {
                              if (acc != ERR_NONE) {
                                   clrprf();
                                   switch (acc) {
                                   case ERR_NOSYS:
                                        prfmsg(AENSYS);
                                        break;
                                   case ERR_SPACE:
                                        prfmsg(AESPC);
                                        break;
                                   default:
                                        prfmsg(AEUNK);
                                        break;
                                   }
                                   unpad(stp4cs(prfbuf));
                                   if (strlen(rsptmp)+strlen(sysnam)+1
                                      +strlen(prfbuf)+1 >= MAXDPKV) {
                                        break;
                                   }
                                   strcat(strcat(rsptmp,sysnam),"\t");
                                   strcat(strcat(rsptmp,prfbuf),"\n");
                              }
                         }
                         rstmbk();
                         rsp2write(TRUE,STGLEN,rsptmp,NULL);
                    }
                    else {
                         rejectreq();
                    }
                    break;
               }
          }
          else {
               rejectreq();
          }
          curreq(savreq);
     }
}

VOID
mopAbort(                          /* management operation aborted         */
INT reqid,                         /*   request ID getting response        */
INT reason)                        /*   reason for abort                   */
{
     INT savreq,msgnum;

     if (ismyreq(reqid,WLMAPID)) {
          savreq=greqid;
          curreq(reqid);
          setmbk(wlmb);
          switch (reason) {
          case ERR_DISC:
               msgnum=MEDISC;
               break;
          case ERR_RESET:
               msgnum=MERST;
               break;
          case ERR_CANCEL:
               msgnum=MECAN;
               break;
          case ERR_SEQ:
               msgnum=MESEQ;
               break;
          case ERR_SPACE:
               msgnum=MESPC;
               break;
          case ERR_NOTFND:
               msgnum=MENFND;
               break;
          case ERR_ACCESS:
               msgnum=MEACC;
               break;
          case ERR_MAXCRT:
               msgnum=MEMAX;
               break;
          case ERR_EXISTS:
               msgnum=MEXST;
               break;
          case ERR_BADNAME:
               msgnum=MEFNAM;
               break;
          case GMEERR:
          case GMEDUP:
          case GME2MFR:
          case GMENFID:
          case GMEMEM:
          case GME2MFL:
               msgnum=MENOMO;
               break;
          default:
               msgnum=MEUNK;
               break;
          }
          if (msgnum == MEUNK) {
               prfmsg(MEUNK,reason);
          }
          else {
               prfmsg(msgnum);
          }
          r2wprf(FALSE);
          rstmbk();
          curreq(savreq);
     }
}

struct saunam *                    /*   returns pointer to dynapak name    */
formDpkName(                       /* form a dynapak name for a senddpk()  */
struct saunam *dpknam,             /*   dynapak name structure to fill in  */
const CHAR *suffix)                /*   suffix to use                      */
{
     setmem(dpknam,sizeof(struct saunam),0);
     stlcpy(dpknam->sysid,msysid,SIDSIZ);
     stlcpy(dpknam->appid,WLMAPID,AIDSIZ);
     stlcpy(dpknam->suffix,suffix,SFXSIZ);
     return(dpknam);
}

VOID
notifyClients(                     /* notify clients of some change        */
struct saunam *dpknam,             /*   dynapak name structure to use      */
size_t length,                     /*   length of contents                 */
VOID *value)                       /*   dynapak contents to send           */
{
     INT i;

     for (i=0 ; i < maxntfy ; ++i) {
          if (*ntfyapp[i].app != '\0' && qroom(ntfyapp[i].usr,NORMAL)) {
               senddpk(ntfyapp[i].usr,ntfyapp[i].app,
                       NORMAL,dpknam,length,value,NULL);
          }
     }
}
