/***************************************************************************
 *                                                                         *
 *   TLCFSD.CPP                                                            *
 *                                                                         *
 *   Copyright (c) 1993-1995 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   These are the handler routines for all FSD calls in Teleconference    *
 *                                                                         *
 *                                           - J. Moriarty 11/93           *
 *   Mods for unified Teleconference         - P. Henning 8/9/97           *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "tlcapi.hpp"
#include "tlctm.h"
#include "tlcfsd.h"

#define FILREV "$Revision: 25 $"

CEDCTRL cedctrl;                   // Channel editor control block
CHANINFO cedtemp;                  // Temp channel for channel editor

AEDCTRL aedctrl;                   // List/action editor control block
ACTLST ledtemp;                    // Temp list for list editor
ACTION aedtemp;                    // Temp action for action editor

CHAR *cedarea;                     // FSD scratch pad for channel editor
INT cedsiz;                        // Size of FSD scratch pad

CHAR *ledarea;                     // FSD scratch pad for list/action edt
INT ledsiz;                        // Size of FSD scratch pad

CHAR cedfsp[] =                    // Format specs for channel FSD
     "NAME "
     "TOPIC "
     "VISKEY(NOSPACES) "
     "JOIKEY(NOSPACES) "
     "SPKKEY(NOSPACES) "
     "SUPKEY(NOSPACES) "
     "MODKEY(NOSPACES) "
     "ACTLST1(NOSPACES) "
     "ACTLST2(NOSPACES) "
     "CPROFAN(ALT=NO ALT=YES MULTICHOICE) "
     "CENTERX(ALT=NO ALT=YES MULTICHOICE) "
     "COPENCL(ALT=NO ALT=YES MULTICHOICE) "
     "DONE(ALT=SAVE ALT=QUIT MULTICHOICE)";

CHAR cedfmt[] =                    // Return format for channel FSD
     "NAME=%s%c"
     "TOPIC=%s%c"
     "VISKEY=%s%c"
     "JOIKEY=%s%c"
     "SPKKEY=%s%c"
     "SUPKEY=%s%c"
     "MODKEY=%s%c"
     "ACTLST1=%s%c"
     "ACTLST2=%s%c"
     "CPROFAN=%s%c"
     "CENTERX=%s%c"
     "COPENCL=%s%c";

#define CEDFMTSIZ (sizeof(cedfmt)            \
                  +(CHAN_MAX_SIZE-4)         \
                  +(CHAN_MAX_TOPIC_SIZE-4)   \
                  +(KEYSIZ-4)                \
                  +(KEYSIZ-4)                \
                  +(KEYSIZ-4)                \
                  +(KEYSIZ-4)                \
                  +(KEYSIZ-4)                \
                  +(LISTSIZ-4)               \
                  +(LISTSIZ-4)               \
                  +(sizeof("YES")-4)         \
                  +(sizeof("YES")-4)         \
                  +(sizeof("YES")-4))

CHAR ledfsp[] =                    // Format specs for list FSD
     "NAME(NOSPACES) "
     "SEEKEY(NOSPACES) "
     "USEKEY(NOSPACES) "
     "DONE(ALT=SAVE ALT=QUIT MULTICHOICE)";

CHAR ledfmt[] =                    // Return format for list FSD
     "NAME=%s%c"
     "SEEKEY=%s%c"
     "USEKEY=%s%c";

#define LEDFMTSIZ (sizeof(ledfmt)  \
                  +(ACTSIZ-4)      \
                  +(KEYSIZ-4)      \
                  +(KEYSIZ-4))

CHAR aedfsp[] =                    // Format specs for action FSD
     "NAME(NOSPACES) "
     "SIMPLE1 "
     "SIMPLE2 "
     "SIMPLE3 "
     "SIMPLE4 "
     "COMPLEX1 "
     "COMPLEX2 "
     "COMPLEX3 "
     "COMPLEX4 "
     "RESPONSE1 "
     "RESPONSE2 "
     "RESPONSE3 "
     "RESPONSE4 "
     "AKEY(NOSPACES) "
     "DONE(ALT=SAVE ALT=QUIT MULTICHOICE)";

CHAR aedfmt[] =                    // Return format for action FSD
     "NAME=%s%c"
     "SIMPLE1=%s%c"
     "SIMPLE2=%s%c"
     "SIMPLE3=%s%c"
     "SIMPLE4=%s%c"
     "COMPLEX1=%s%c"
     "COMPLEX2=%s%c"
     "COMPLEX3=%s%c"
     "COMPLEX4=%s%c"
     "RESPONSE1=%s%c"
     "RESPONSE2=%s%c"
     "RESPONSE3=%s%c"
     "RESPONSE4=%s%c"
     "AKEY=%s%c";

#define AEDFMTSIZ (sizeof(aedfmt)  \
                  +(ACTSIZ-4)      \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +((RESSIZ/4)-4)  \
                  +(KEYSIZ-4))

/* local function declarations */

static VOID
cedGetAnswers(VOID);               // get channel answers from FSD

static VOID
cedExit(                           // exit from channel editor FSD session
bool toMenu);                      //   exit to menu (or back to tele)

static VOID
ledGetAnswers(VOID);               // get list answers from FSD

static VOID
ledExit();                         // exit from list editor FSD session

static VOID
aedGetAnswers(VOID);               // get action word answers from FSD

static VOID
aedGetResp(                        // extract action response from FSD
CHAR *buf,                         //   buffer to receive response
INT respID);                       //   first response identifier

static VOID
aedExit();                         // exit from word editor FSD session

/* function definitions start here */

MARKSOURCE(tlcfsd)

VOID
initfsd(VOID)                      // Initialize FSD buffers
{
     dclvda(CEDFMTSIZ);
     dclvda(LEDFMTSIZ);
     dclvda(AEDFMTSIZ);
     cedsiz=fsdroom(CEDFSAN3,cedfsp,0);
     cedsiz=max(cedsiz,fsdroom(CEDFSIN2,cedfsp,-1));
     cedsiz=max(cedsiz,fsdroom(CEDFSNA2,cedfsp,0));
     cedarea=static_cast<CHAR*>(alcmem(cedsiz));
     ledsiz=fsdroom(LEDFSANS,ledfsp,0);
     ledsiz=max(ledsiz,fsdroom(LEDFSINF,ledfsp,-1));
     ledsiz=max(ledsiz,fsdroom(LEDFSNAN,ledfsp,0));
     ledsiz=max(ledsiz,fsdroom(AEDFSAN2,aedfsp,0));
     ledsiz=max(ledsiz,fsdroom(AEDFSIN2,aedfsp,-1));
     ledsiz=max(ledsiz,fsdroom(AEDFSNA2,aedfsp,0));
     ledarea=static_cast<CHAR*>(alcmem(ledsiz));
     cedctrl.user=-1;
     aedctrl.user=-1;
}

CHAR *
tfsdpft(VOID)                      // Get message for FSD use
{
     switch(fsdusr->amode) {
     case 1:
          return(getasc(fsdusr->tmpmsg));
     case 0:
          return(rawmsg(fsdusr->tmpmsg));
     case -1:
          return(getmsg(fsdusr->tmpmsg));
     }
     return(NULL);
}

/********************** CHANNEL EDITOR ROUTINES ****************************/

VOID
cedEnter(                          // enter channel editor
bool isCreate)                     //   are we creating?
{
     curUser->m_fFlags|=USR_INCHNEDT;
     if (FULLSCREEN()) {
          cedprp(CEDFSAN3,1);
          fsdbkg(tfsdpft());
     }
     else {
          cedprp(CEDFSNA2,0);
     }
     cedptc(cedctrl.sysop);
     fsdego(cedvfy,isCreate ? cedcdun : ceddun);
}

VOID
cedprp(                            // Prepare channel editor
INT msgno,                         //   FSD template text block number
INT mode)                          //   FSD mode
{
     fsdroom(msgno,cedfsp,mode);
     bool isClosed=((cedtemp.m_flags&CHAN_FLAG_CLOSED)
                 && !sameas(cedtemp.m_strName,mainchan));
     sprintf(vdatmp,cedfmt
            ,cedtemp.m_strName,'\0'
            ,cedtemp.m_strTopic,'\0'
            ,cedtemp.m_keyVis,'\0'
            ,cedtemp.m_keyJoin,'\0'
            ,cedtemp.m_keySpeak,'\0'
            ,cedtemp.m_keyByPass,'\0'
            ,cedtemp.m_keyMod,'\0'
            ,cedtemp.m_actList1,'\0'
            ,cedtemp.m_actList2,'\0'
            ,(cedtemp.m_flags&CHAN_FLAG_PROFOK) ? "YES" : "NO", '\0'
            ,(cedtemp.m_flags&CHAN_FLAG_NOENTMESSAGE) ? "NO" : "YES", '\0'
            ,isClosed ? "YES" : "NO", '\0');
     fsdapr(cedarea,cedsiz,vdatmp);
}

VOID
cedptc(                            // Protect channel fields
bool isSysop)                      //   is user a tele Sysop (or moderator)
{
     // can't change channel name
     fsdscb->flddat[CEDNAME].flags|=FFFAVD;
     // can't close default channel
     if (sameas(cedtemp.m_strName,mainchan)) {
          fsdscb->flddat[CEDCOPE].flags|=FFFAVD;
     }
     // don't let moderator change this info
     if (!isSysop) {
          fsdscb->flddat[CEDVISK].flags|=FFFAVD;
          fsdscb->flddat[CEDJOIK].flags|=FFFAVD;
          fsdscb->flddat[CEDSPKK].flags|=FFFAVD;
          fsdscb->flddat[CEDSUPK].flags|=FFFAVD;
          fsdscb->flddat[CEDMODK].flags|=FFFAVD;
          fsdscb->flddat[CEDACT1].flags|=FFFAVD;
          fsdscb->flddat[CEDACT2].flags|=FFFAVD;
          fsdscb->flddat[CEDCPRO].flags|=FFFAVD;
          fsdscb->flddat[CEDCENT].flags|=FFFAVD;
     }
}

VOID
ceddun(                            // Done editing channel
GBOOL save)                        //   did user save info? (or abort)
{
     setmbk(msgTlc);
     if (save) {
          cedGetAnswers();
          CTlcChannel* pChannel=tlcAPI->chanGetByName(cedtemp.m_strName);
          if (pChannel != NULL && pChannel->Update(&cedtemp)) {
               pChannel->Save();
               prfmsg(CEDSAV2);
          }
          else {
               prfmsg(CEDSVER2);
          }
     }
     else {
          prfmsg(CEDQIT2);
     }
     cedExit(cedctrl.sysop);
}

VOID
cedcdun(                           // Done creating channel
GBOOL save)                        //   did user save info? (or abort)
{
     setmbk(msgTlc);
     if (save) {
          cedGetAnswers();
          tlcChannelCreateLocal(&cedtemp,TRUE);
          prfmsg(CEDSAV2);
     }
     else {
          prfmsg(CEDQIT2);
     }
     cedExit(true);
}

static VOID
cedGetAnswers(VOID)                // get channel answers from FSD
{
     fsdfxt(CEDNAME,cedtemp.m_strName,CHAN_MAX_SIZE);
     fsdfxt(CEDTOPI,cedtemp.m_strTopic,CHAN_MAX_TOPIC_SIZE);
     fsdfxt(CEDVISK,cedtemp.m_keyVis,KEYSIZ);
     fsdfxt(CEDMODK,cedtemp.m_keyMod,KEYSIZ);
     fsdfxt(CEDJOIK,cedtemp.m_keyJoin,KEYSIZ);
     fsdfxt(CEDSPKK,cedtemp.m_keySpeak,KEYSIZ);
     fsdfxt(CEDSUPK,cedtemp.m_keyByPass,KEYSIZ);
     fsdfxt(CEDACT1,cedtemp.m_actList1,LISTSIZ);
     fsdfxt(CEDACT2,cedtemp.m_actList2,LISTSIZ);
     if (fsdord(CEDCPRO)) {
          cedtemp.m_flags|=CHAN_FLAG_PROFOK;
     }
     else {
          cedtemp.m_flags&=~CHAN_FLAG_PROFOK;
     }
     if (fsdord(CEDCENT)) {
          cedtemp.m_flags&=~CHAN_FLAG_NOENTMESSAGE;
     }
     else {
          cedtemp.m_flags|=CHAN_FLAG_NOENTMESSAGE;
     }
     if (fsdord(CEDCOPE)) {
          cedtemp.m_flags|=CHAN_FLAG_CLOSED;
     }
     else {
          cedtemp.m_flags&=~CHAN_FLAG_CLOSED;
     }
}

static VOID
cedExit(                           // exit from channel editor FSD session
bool toMenu)                       //   exit to menu (or back to tele)
{
     CTlcUser* pUser=tlcAPI->usrGetByName(usaptr->userid);
     if (pUser == NULL) {
          return;
     }
     pUser->m_fFlags&=~USR_INCHNEDT;
     usrptr->state=GetTeleState();
     if (toMenu) {
          RetChanEditor();
     }
     else {                        // Return moderator directly to TLC
          ASSERT(usrnum == cedctrl.user);
          cedctrl.user=-1;
          cedctrl.channel[0]='\0';
          tmReturnChannel(pUser,tlcAPI->chanGetByName(pUser->GetChannelName()));
          prfmsg(ED2TLC2);
     }
}

INT
cedvfy(                            // Verify channel info
INT fldno,                         //   field ID to verify
CHAR *answer)                      //   proposed answer
{
     switch (fldno) {
     case CEDVISK:
     case CEDMODK:
     case CEDSUPK:
     case CEDJOIK:
     case CEDSPKK:
          if (*answer == '\0' || keynam(answer)) {
               strupr(answer);
               return(VFYOK);
          }
          prf("\7");
          outprf(usrnum);
          return(VFYREJ);
     case CEDACT1:
     case CEDACT2:
          if (*answer == '\0' || chkalph(answer)) {
               strupr(answer);
               return(VFYOK);
          }
          prf("\7");
          outprf(usrnum);
          return(VFYREJ);
     case CEDNAME:
          if (*answer == '\0' || chkalph(answer)) {
               return(VFYOK);
          }
          prf("\7");
          outprf(usrnum);
          return(VFYREJ);
     }
     return(vfyadn(fldno,answer));
}

/************************ ACTION LIST EDITOR *******************************/

VOID
ledEnter(                          // enter action list editor
bool isCreate)                     //   are we creating?
{
     curUser->m_fFlags|=USR_INACTEDT;
     if (FULLSCREEN()) {
          ledprp(LEDFSANS,1);
          fsdbkg(tfsdpft());
     }
     else {
          ledprp(LEDFSNAN,0);
     }
     ledptc();
     fsdego(ledvfy,isCreate ? ledcdun : leddun);
}

VOID
ledprp(                            // Prepare action list editor
INT msgno,                         //   FSD template text block number
INT mode)                          //   FSD mode
{
     fsdroom(msgno,ledfsp,mode);
     sprintf(vdatmp,ledfmt
            ,ledtemp.name,'\0'
            ,ledtemp.seekey,'\0'
            ,ledtemp.usekey,'\0');
     fsdapr(ledarea,ledsiz,vdatmp);
}

VOID
ledptc(VOID)                       // Protect action list fields
{
     fsdscb->flddat[LEDNAME].flags|=FFFAVD;
}

VOID
leddun(                            // Done editing action list
GBOOL save)
{
     setmbk(msgTlc);
     if (save) {
          strcpy(ledtemp.list,LSTNAM);
          ledGetAnswers();
          if (chglst(&ledtemp) == 0) {
               prfmsg(LEDSAV2);
          }
          else {
               prfmsg(LEDSVER2);
          }
     }
     else {
          prfmsg(LEDQIT2);
     }
     ledExit();
}

VOID
ledcdun(                           // Done creating action list
GBOOL save)
{
     setmbk(msgTlc);
     if (save) {
          memset(&ledtemp,0,sizeof(ACTLST));
          strcpy(ledtemp.list,LSTNAM);
          ledGetAnswers();
          if (addlst(&ledtemp) == 0) {
               prfmsg(LEDSAV2);
          }
          else {
               prfmsg(LEDSVER2);
          }
     }
     else {
          prfmsg(LEDQIT2);
     }
     ledExit();
}

static VOID
ledGetAnswers(VOID)                // get list answers from FSD
{
     fsdfxt(LEDNAME,ledtemp.name,ACTSIZ);
     fsdfxt(LEDSEEK,ledtemp.seekey,KEYSIZ);
     fsdfxt(LEDUSEK,ledtemp.usekey,KEYSIZ);
}

static VOID
ledExit()                          // exit from list editor FSD session
{
     CTlcUser* pUser=tlcAPI->usrGetByName(usaptr->userid);
     if (pUser == NULL) {
          return;
     }
     pUser->m_fFlags&=~USR_INACTEDT;
     usrptr->state=GetTeleState();
     RetListEditor();
}

INT
ledvfy(                            // Verify action list info
INT fldno,                         //   field ID to verify
CHAR *answer)                      //   proposed answer
{
     switch (fldno) {
     case LEDSEEK:
     case LEDUSEK:
          if (*answer == '\0' || keynam(answer)) {
               strupr(answer);
               return(VFYOK);
          }
          prf("\7");
          outprf(usrnum);
          return(VFYREJ);
     }
     return(vfyadn(fldno,answer));
}

/************************** ACTION WORD EDITOR *****************************/

VOID
aedEnter(                          // enter action word editor
bool isCreate)                     //   are we creating?
{
     curUser->m_fFlags|=USR_INACTEDT;
     if (FULLSCREEN()) {
          aedprp(AEDFSAN2,1);
          fsdbkg(tfsdpft());
     }
     else {
          aedprp(AEDFSNA2,0);
     }
     aedptc();
     fsdego(aedvfy,isCreate ? aedcdun : aeddun);
}

VOID
aedprp(                            // Prepare action word editor
INT msgno,                         //   FSD template text block number
INT mode)                          //   FSD mode
{
     CHAR *sp1,*sp2,*sp3,*sp4;
     CHAR *cp1,*cp2,*cp3,*cp4;
     CHAR *rp1,*rp2,*rp3,*rp4;

//HACK: this test is kind of stupid
     if (strchr(aedtemp.simple,'\1') != NULL) {
          sp1=aedtemp.simple;
          sp2=strchr(sp1,'\1')+1;
          sp3=strchr(sp2,'\1')+1;
          sp4=strchr(sp3,'\1')+1;
          strrpl(aedtemp.simple,'\1','\0');
          cp1=aedtemp.complx;
          cp2=strchr(cp1,'\1')+1;
          cp3=strchr(cp2,'\1')+1;
          cp4=strchr(cp3,'\1')+1;
          strrpl(aedtemp.complx,'\1','\0');
          rp1=aedtemp.resp;
          rp2=strchr(rp1,'\1')+1;
          rp3=strchr(rp2,'\1')+1;
          rp4=strchr(rp3,'\1')+1;
          strrpl(aedtemp.resp,'\1','\0');
          fsdroom(msgno,aedfsp,mode);
          sprintf(vdatmp,aedfmt
                 ,aedtemp.name,'\0'
                 ,sp1,'\0',sp2,'\0',sp3,'\0',sp4,'\0'
                 ,cp1,'\0',cp2,'\0',cp3,'\0',cp4,'\0'
                 ,rp1,'\0',rp2,'\0',rp3,'\0',rp4,'\0'
                 ,aedtemp.actkey,'\0');
     }
     else {
          fsdroom(msgno,aedfsp,mode);
          sprintf(vdatmp,aedfmt
                 ,aedtemp.name,'\0'
                 ,"",'\0',"",'\0',"",'\0',"",'\0'
                 ,"",'\0',"",'\0',"",'\0',"",'\0'
                 ,"",'\0',"",'\0',"",'\0',"",'\0'
                 ,"",'\0');
     }
     fsdapr(ledarea,ledsiz,vdatmp);
}

VOID
aedptc(VOID)                       // Protect action word fields
{
     fsdscb->flddat[AEDNAME].flags|=FFFAVD;
}

VOID
aeddun(                            // Done editing action word
GBOOL save)
{
     setmbk(msgTlc);
     if (save) {
          aedGetAnswers();
          if (chgact(&aedtemp) == 0) {
               prfmsg(AEDSAV2);
          }
          else {
               prfmsg(AEDSVER2);
          }
     }
     else {
          prfmsg(AEDQIT2);
     }
     aedExit();
}

VOID
aedcdun(                           // Done creating action word
GBOOL save)
{
     setmbk(msgTlc);
     if (save) {
          aedGetAnswers();
          if (addact(&aedtemp) == 0) {
               prfmsg(AEDSAV2);
          }
          else {
               prfmsg(AEDSVER2);
          }
     }
     else {
          prfmsg(AEDQIT2);
     }
     aedExit();
}

static VOID
aedGetAnswers(VOID)                // get action word answers from FSD
{
     memset(&aedtemp,0,sizeof(ACTION));
     fsdfxt(AEDKEY,aedtemp.actkey,KEYSIZ);
     strcpy(aedtemp.list,ledtemp.name);
     fsdfxt(AEDNAME,aedtemp.name,ACTSIZ);
     aedGetResp(aedtemp.simple,AEDSIMP1);
     aedGetResp(aedtemp.complx,AEDCOMP1);
     aedGetResp(aedtemp.resp,AEDRESP1);
}

static VOID
aedGetResp(                        // extract action response from FSD
CHAR *buf,                         //   buffer to receive response
INT respID)                        //   first response identifier
{
     INT i;
     CHAR tmpres[RESSIZ];

     for (i=0,*buf='\0' ; i < 4 ; ++i) {
          fsdfxt(respID+i,tmpres,RESSIZ);
          if (i != 0) {
               stlcat(buf,"\1",RESSIZ);
          }
          stlcat(buf,tmpres,RESSIZ);
     }
}

static VOID
aedExit()                          // exit from word editor FSD session
{
     CTlcUser* pUser=tlcAPI->usrGetByName(usaptr->userid);
     if (pUser == NULL) {
          return;
     }
     pUser->m_fFlags&=~USR_INACTEDT;
     usrptr->state=GetTeleState();
     RetActionEditor();
}

INT
aedvfy(                            // Verify action word info
INT fldno,                         //   field ID to verify
CHAR *answer)                      //   proposed answer
{
     switch (fldno) {
     case AEDKEY:
          if (*answer == '\0' || keynam(answer)) {
               strupr(answer);
               return(VFYOK);
          }
          prf("\7");
          outprf(usrnum);
          return(VFYREJ);
     }
     return(vfyadn(fldno,answer));
}
