/////////////////////////////////////////////////////////////////////////////
//
//   TLCAHLIT.CPP
//
//   Copyright (c) 1997 Galacticomm, Inc.         All Rights Reserved
//
//   Active HTML LITE Teleconference interface
//
//                                              - N.C. Osterc  3/17/98
//   Text Variable changes
//
//                                              - P Henning    9/23/98
//
////////////////////////////////////////////////////////////////////////////

#pragma option -w-par    // fixes warning in memory.h
#define _RWSTDLL
#include "gcomm.h"
#include "majorbbs.h"
#include <stdcomp.h>
#define RWSTD_NO_BOOL
#pragma option -w-aus
#include <deque>
#pragma option -w-aus.
#include <cstring.h>
#include "iterand.h"
using namespace std;
#include "galacth.h"
#include "tlcapi.hpp"
#include "ahlite.hpp"
#include "ahtrans.hpp"
#include "tlcahusr.hpp"
#include "dnf.h"
#include "dnfmgr.h"
#include "tvb.h"
#include "enctvb.h"
#include "tlcahtvb.h"
#include "ahutil.h"
#include "gcspsrv.h"
#include "remote.h"
#include <time.h>
#include "tlcahlit.h"

#define FILREV "$Revision: 22 $"


#define DFTSUCCESS "index.htm"
#define DFTERROR "error.htm"


acthSynthesis* teleNewSynthesis(acthSession*);    // from tlcah.cpp

extern CAHTransport transAH;       // instance of active html transport


#define PPFIX "galacth/galtele"

enum {TELEMSG,LISTITEM};

#define GETINPUT(X)      (ses->param(X,m_strInp,tinpsz))

VOID
initLiteAgent(                     // initialize the AH Lite agent
VOID);

GBOOL
isAHUser(                          // is passed user on via Active H?
const CHAR *uid);                  // user in question

CTlcUser*                          // user object (NULL if not found)
getUser(                           // get a user object
const CHAR* usr);                  // the user to get

CTlcChannel*                       // channel object (NULL if not found)
getChannel(                        // get a channel object
const CHAR* usr);                  // this user's current channel

static VOID
ScanListUser(                      // scan info for user
CTlcUser *pUser,                   // the user doing the scan
CTlcUser *pOthUsr);                // the user in the scan

static VOID
ScanListChan(                      // do a scan on a channel
CTlcChannel* pChannel,             // channel to scan
CTlcUser* pUser);                  // user to scan for

VOID
add2recentCallers(                 // add user to recent callers
CTlcUser* pUser);                  // the user to add

VOID
liteUsersOn(                       // generate list of AH lite users online
VOID);

VOID (*oldUsersOn)(VOID);          // userson vector

VOID
liteLogOff(                        // log off a lite user (kick out of tele)
VOID);

static VOID
(*oldinvhook)(                     // invisibility function pointer
INT unum);                         // the user concerned

static VOID
liteInvHook(                       // notify me when invisibility is toggled
INT unum);                         // the user concerned

CHAR*
Stripcrlf(                         // strip \r and \n from a string
CHAR* str);                         // string to strip

CLiteAHTrans transLiteAH;          // lite transport instance
INT iAHLiteTrans;                  // lite transport unique id
CTlcAHUser* g_pUser=NULL;          // global point to AH user class
static INT gGracePeriod=10;        // grace-period (for initial load).
static INT gDefaultTele;           // which is default tele? HTML or JAVA?
static INT gTimeOut=30;            // browser time-out
static CHAR gKeyReqed[KEYSIZ];     // the key required to enter ah lite tele
static CHAR gKey4Tags[KEYSIZ];     // the key requred for user to send tags
static GBOOL gCheckRegistry=FALSE; // check to see if registry is present?
DFAFILE** regbb=NULL;              // pointer to a pointer to registry data structure

dnfStep dnfFileSteps[]={
     dnfStep(DNFMAPEND)
};
dnfMap tlcFileMap(PPFIX "/file/index.htm","Generic File Response",dnfFileSteps);

dnfStep dnfInitialSteps[]={
     dnfStep(DNFMAPEND)
};
dnfMap tlcInitialMap(PPFIX "/index2.htm","Initial Response",dnfInitialSteps);

dnfStep dnfInitialErrorSteps[]={
     dnfStep(DNFMAPEND)
};
dnfMap tlcInitialErrorMap(PPFIX "/error.htm","Initial Error Response",dnfInitialErrorSteps);

dnfStep dnfProfileSteps[]={
     dnfStep(DNFMAPEND)
};
dnfMap dnfProfileMap(PPFIX "/profile/index.htm","Profile Response",dnfProfileSteps);

dnfStep dnfProfileErrorSteps[]={
     dnfStep(DNFMAPEND)
};
dnfMap dnfProfileErrorMap(PPFIX "/profile/error.htm","Profile Error Response",dnfProfileErrorSteps);

dnfStep dnfSendSteps[]={
     dnfStep(DNFMAPEND)
};
dnfMap dnfSendMap(PPFIX "/send/index.htm","Send Response",dnfSendSteps);


dnfStep userSteps[] =
{
     dnfStep(DNFTABLE),
          dnfStep(DNFCOLUMN,LISTITEM,"LISTITEM"),
     dnfStep(DNFTABLEEND),
     dnfStep(DNFMAPEND)
};
dnfMap dnfUserMap(PPFIX "/list/user/index.htm","Users",userSteps);

dnfStep chanSteps[] =
{
     dnfStep(DNFTABLE),
          dnfStep(DNFCOLUMN,LISTITEM,"LISTITEM"),
     dnfStep(DNFTABLEEND),
     dnfStep(DNFMAPEND)
};
dnfMap dnfChanMap(PPFIX "/list/channel/index.htm","Channels",chanSteps);

dnfStep actSteps[] =
{
     dnfStep(DNFTABLE),
          dnfStep(DNFCOLUMN,LISTITEM,"LISTITEM"),
     dnfStep(DNFTABLEEND),
     dnfStep(DNFMAPEND)
};
dnfMap dnfActMap(PPFIX "/list/action/index.htm","Actions",actSteps);

dnfStep messageSteps[] =
{
     dnfStep(DNFTABLE),
          dnfStep(DNFCOLUMN,TELEMSG,"TELEMSG"),
     dnfStep(DNFTABLEEND),
     dnfStep(DNFMAPEND)
};
dnfMap dnfMessageMap(PPFIX "/receive/index.htm","Messages",messageSteps);

dnfStep messageErrorSteps[] =
{
     dnfStep(DNFMAPEND)
};
dnfMap dnfMessageErrorMap(PPFIX "/receive/error.htm","Message Error",messageErrorSteps);


MARKSOURCE(tlcahlit);

//
// Base Synthesis Member Functions
//


ACTHCODE
tlcBaseSyn::proceed()              // proceed with synthesis
{
     ACTHCODE rc=ACTHMORE;
     setmbk(msgTlc);
     switch (m_SynState) {
     case SYNSTATE_REQUEST:
         rc=proceedRequest();
         break;
     case SYNSTATE_SYNTH:
         rc=proceedSynth();
         break;
     case SYNSTATE_RESPONSE:
         rc=proceedResponse();
         break;
     }
     tlcAPI->OutputFinished();
     rstmbk();
     return(rc);
}


ACTHCODE
tlcBaseAuthSyn::proceedRequest()        // get common params, check authentication
{
     ACTHCODE rc=ACTHMORE;
     if (!tlcAPI->isinit()) {
          m_err=ERR_TELENOTINIT;
     }
     else if (ses->urlargc() == m_lvlcnt && ses->forceDir()) {
          rc=ACTHDONE;
     }
     else if ((m_usr=ses->getUser()) == NULL) {
          rc=ACTHNOANON;
     }
     else {
          getTeleParams();
     }
     initTemplates();
     return(rc);
}

ACTHCODE
tlcBaseAuthSyn::proceedResponse()  // proceed with response
{
     ACTHCODE rc;
     clearAllTVars();
     if (m_usr != NULL) {
          setusaptr(m_usr->userid());
     }
     setErrorVars();
     setProfileVars();
     dnfSetTemplateTvb(m_dnf);
     rc=proceedDerivedResponse();
     usaptr=uacoff(usrnum);
     clearAllTVars();
     return(rc);
}

VOID
tlcBaseAuthSyn::getTeleParams() // get common HTML-chat parameters
{
     if (m_usr != NULL) {
          stlcpy(m_userIDBuf,m_usr->userid(),UIDSIZ);
     }
     ses->param("sessionid",m_sesIDBuf,SESIDSIZ);
}


VOID
tlcBaseAuthSyn::setErrorVars()
{
     switch (m_err) {
     case ERR_SESSIONFAILURE:
          teleErrorMessage=stpans(rawmsg(SESFAIL));
          break;
     case ERR_AFRDENT:
     case ERR_AFRDEXT:
          teleErrorMessage="You can't afford to change your ";
          teleErrorMessage+=(m_err == ERR_AFRDENT ? "Entrance" : "Exit");
          teleErrorMessage+=" Message.";
          break;
     case ERR_BADCHATINTERVAL:
          teleErrorMessage=stpans(rawmsg(INVCHAI));
          break;
     case ERR_ALREADIN:
          teleErrorMessage=stpans(rawmsg(ALREADIN));
          break;
     case ERR_NOERROR:
     case ERR_TELENOTINIT:
     case ERR_EMPTYINPUT:
     default:
          teleErrorCode=m_err;
          teleErrorMessage="";
     }
}

VOID
tlcBaseAuthSyn::clearAllTVars()
{
     teleActionHelp="";
     teleActionName="";
     teleActionNameURL="";
     teleChannelTopic="";
     teleChannelName="";
     teleChannelNameURL="";
     teleNumInChannel="";
     teleErrorCode="";
     teleErrorMessage="";
     teleRegistryLink="";
     teleUserid=m_usr->userid();
     teleUseridURL=m_usr->userid();
     teleSesid=m_sesIDBuf;
}

VOID
tlcBaseAuthSyn::setProfileVars()
{
     if (m_pUser != NULL) {
          teleEncodeNo=(m_pUser->m_fFlags&USR_ENCODETAGS ? "" : "Selected");
          teleEncodeYes=(m_pUser->m_fFlags&USR_ENCODETAGS ? "Selected" : "");
          teleEntranceMessage=m_pUser->GetEntrance(MSG_CURRENT);
          teleExitMessage=m_pUser->GetExit(MSG_CURRENT);
          teleReqEntranceMessage=m_pUser->GetEntrance(MSG_REQUESTED);
          teleReqExitMessage=m_pUser->GetExit(MSG_REQUESTED);
          telePrivateTopic=m_pUser->GetPrivateTopic();
          teleHTMLSel=(m_pUser->m_fFlags&USR_WEBTELHTML ? "Selected" : "");
          teleJavaSel=(m_pUser->m_fFlags&USR_WEBTELJAVA ? "Selected" : "");
          setChatIntTvb(m_pUser->GetChatInterval());
          SHORT dftChan=m_pUser->GetDefaultChan();
          teleMainSel=(dftChan == CHANDFT_MAIN ? "Selected" : "");
          telePrivateSel=(dftChan == CHANDFT_PRIVATE ? "Selected" : "");
     }
}


VOID
tlcBaseAuthSyn::setusaptr(
CHAR const * userid)                // set usaptr for use with global Tvars
{
     if (::onsysn(userid,TRUE)) {
          usaptr=othuap;
     }
     else {
          ::dfaSetBlk(::accbb);
          if (dfaAcqEQ(&m_usaptr,userid,0)) {
               usaptr=&m_usaptr;
          }
          ::dfaRstBlk();
     }
}

VOID
tlcBaseAuthSyn::initTemplates()         // get onxxx parameter values
{
     m_succRedir=getOnParam("onsuccess",DFTSUCCESS,&m_onsuccessFile);
     m_errRedir=getOnParam("onerror",DFTERROR,&m_onerrorFile);
}


ACTHCODE                                //   continue synthesis?
tlcBaseAuthSyn::errorResponse(          // process an error
dnfMap& map,                            //   map to use
CHAR const * path)                      //   path to template directory
{
     if (m_errRedir) {
          ses->redirect(m_onerrorFile);
          return(ACTHDONE);
     }
     ASSERT(path != NULL);
     string dest=path;

     dest+=(m_onerrorFile == NULL ? DFTERROR : m_onerrorFile);
     m_dnf=dnfCreateHandler(&bout,&map,dest.c_str());
     return(ACTHMORE);
}

ACTHCODE                                //   continue synthesis?
tlcBaseAuthSyn::successResponse(        // process an onsuccess
dnfMap& map,                            //   map to use
CHAR const * path)                      //   path to template directory
{
     if (m_succRedir) {
          ses->redirect(m_onsuccessFile);
          return(ACTHDONE);
     }
     ASSERT(path != NULL);
     string dest=path;

     dest+=(m_onsuccessFile == NULL ? DFTSUCCESS : m_onsuccessFile);
     m_dnf=dnfCreateHandler(&bout,&map,dest.c_str());
     return(ACTHMORE);
}



bool                                    //   is a redirct?
tlcBaseAuthSyn::getOnParam(             // get onxxx parameter
CHAR const * paramName,                 //   parameter to get
CHAR const * dftFileName,               //   dft file name to use
CHAR** pStorePtr)                       //   store redir path here
{
     if (ses->param(paramName)) {
          if (*pStorePtr != NULL) {
               delete [] *pStorePtr;
          }
          INT sz=ses->paramRoom(paramName);
          *pStorePtr=new CHAR[sz];
          ses->param(paramName,*pStorePtr,sz);
          if (sameto("http://",*pStorePtr) || **pStorePtr == '/') {
               return(true);
          }
          if (!isvalfn(*pStorePtr)) {
               if (sz < strlen(dftFileName)+1) {
                    delete [] *pStorePtr;
                    *pStorePtr=NULL;
               }
          }
          return(false);
     }
     else if (*pStorePtr != NULL) {
          delete [] *pStorePtr;
          *pStorePtr=NULL;
     }
     return(false);
}


ACTHCODE
fileSyn::proceedRequest()            // setup request context
{
     ACTHCODE rc=tlcBaseAuthSyn::proceedRequest();
     if (m_err == ERR_NOERROR) {
          m_SynState=SYNSTATE_SYNTH;
     }
     return(rc);
}

ACTHCODE
fileSyn::proceedSynth()              // proceed with synthesis
{
     m_SynState=SYNSTATE_RESPONSE;
     return(ACTHMORE);
}

ACTHCODE
fileSyn::proceedDerivedResponse()    // proceed with response
{
     ACTHCODE rc=ACTHMORE;

     if (m_dnf == NULL) {
          m_dnf=dnfCreateHandlerURL(ses,&tlcFileMap,PPFIX);
          if (m_dnf != NULL) {
               CHAR fileExtension[GCMAXEXT+1];
               const CHAR* fileName=m_dnf->getMap().getFile();
               fileparts(GCPART_EXTN,fileName,fileExtension,GCMAXEXT+1);
               ses->contypeFext(fileExtension);
          }
     }
     else if (m_dnf->process() == DNFEND) {
          rc=ACTHDONE;
     }
     return(rc);
}

ACTHCODE
actionSyn::proceedRequest()            // setup request context
{
     ACTHCODE rc=tlcBaseAuthSyn::proceedRequest();
     if (m_err == ERR_NOERROR) {
          m_SynState=SYNSTATE_SYNTH;
     }
     return(rc);
}

ACTHCODE
actionSyn::proceedSynth()              // proceed with synthesis
{
     m_SynState=SYNSTATE_RESPONSE;
     return(ACTHMORE);
}

ACTHCODE
actionSyn::proceedDerivedResponse()    // proceed with response
{
     ACTHCODE rc=ACTHMORE;

     if (!isValidSession()) {
          return(ACTHFORBID);
     }
     if (m_dnf == NULL) {
          m_dnf=dnfCreateHandlerURL(ses,&dnfActMap,PPFIX);
     }
     else {
          m_pChannel=getChannel(m_userIDBuf);
          if (m_pChannel == NULL) {
               return(ACTHDONE);
          }
          m_psavUser=curUser=m_pUser;
          if (m_pszAction != NULL) {
               teleActionName=m_pszAction;
               teleActionNameURL=m_pszAction;
          }
          if (m_pList != NULL) {
               tmpact=m_pList->actionGetCurrentPtr();
               acthlp();
               stpans(strrpl(prfbuf,'\"','\''));
               depad(prfbuf);
               stlcpy(m_helpbuf,skptwht(prfbuf),MAXHLPSIZ);
               clrprf();
               teleActionHelp=m_helpbuf;
          }
          switch (m_dnf->process()) {
          case DNFBEGIN:
               if (m_pChannel->m_actList1 == NULL) {
                    ++m_table;
                    if (m_pChannel->m_actList2 != NULL) {
                         m_pList=tlcAPI->actGetByName(m_pChannel->m_actList2);
                         if (m_pList == NULL) {
                              bout << stpans(rawmsg(NOACFND));
                              rc=ACTHDONE;
                              break;
                         }
                    }
                    else {
                         bout << stpans(rawmsg(NOACFND));
                         rc=ACTHDONE;
                         break;
                    }
               }
               else {
                    m_pList=tlcAPI->actGetByName(m_pChannel->m_actList1);
                    if (m_pList == NULL) {
                         bout << stpans(rawmsg(NOACFND));
                         rc=ACTHDONE;
                         break;
                    }
               }
               if (m_pList != NULL) {
                    m_pszAction=m_pList->wordGetFirst();
               }
               break;
          case DNFROWBEGIN:
               if (m_pList == NULL) {
                    m_dnf->tableDone();
                    break;
               }
               if (m_pszAction != NULL) {
                    tmpact=m_pList->actionGetCurrentPtr();
                    if (!(m_pUser->CheckAccess(tmpact->actkey))) {
                         m_pszAction=m_pList->wordGetGT(m_pszAction);
                         m_dnf->sayAgain();
                    }
               }
               break;
          case LISTITEM:
               break;
          case DNFROWEND:
               if (m_pszAction != NULL) {
                    m_pszAction=m_pList->wordGetGT(m_pszAction);
               }
               if (m_pszAction == NULL && m_table >= 1) {
                    m_dnf->tableDone();
               }
               else if (m_pszAction == NULL && m_table == 0) {
                    if (m_pChannel->m_actList2 != NULL) {
                         ++m_table;
                         m_pList=tlcAPI->actGetByName(m_pChannel->m_actList2);
                         if (m_pList == NULL) {
                              m_dnf->tableDone();
                         }
                         else {
                              m_pszAction=m_pList->wordGetFirst();
                         }
                    }
                    else {
                         m_dnf->tableDone();
                    }
               }
               break;
          case DNFEND:
               rc=ACTHDONE;
               break;
          }
     }
     return(rc);
}

ACTHCODE
channelSyn::proceedRequest()            // setup request context
{
     ACTHCODE rc=tlcBaseAuthSyn::proceedRequest();
     if (m_err == ERR_NOERROR) {
          m_SynState=SYNSTATE_SYNTH;
     }
     return(rc);
}

ACTHCODE
channelSyn::proceedSynth()              // proceed with synthesis
{
     m_SynState=SYNSTATE_RESPONSE;
     return(ACTHMORE);
}

ACTHCODE
channelSyn::proceedDerivedResponse()    // proceed with response
{
     ACTHCODE rc=ACTHMORE;

     if (!isValidSession()) {
          return(ACTHFORBID);
     }
     if (m_dnf == NULL) {
          m_dnf=dnfCreateHandlerURL(ses,&dnfChanMap,PPFIX);
     }
     else {
          if (m_pChannel != NULL) {
               teleChannelName=m_pChannel->GetName();
               teleChannelNameURL=m_pChannel->GetName();
               teleChannelTopic=m_pChannel->GetTopic();
               teleNumInChannel=m_pChannel->GetNumVisible();
          }
          switch (m_dnf->process()) {
          case DNFBEGIN:
               m_pChannel=tlcAPI->chanGetFirst();
               if (m_pChannel == NULL) {
                    rc=ACTHDONE;
                    break;
               }
               saveChanName();
               break;
          case DNFROWBEGIN:
               if (m_pChannel == NULL) {
                    m_dnf->tableDone();
                    break;
               }
               if (m_pChannel->GetType()&CHAN_TYPE_PRIVATE) {
                    m_pPrivate=dynamic_cast<CTlcPrivateChannel*>(m_pChannel);
                    if (!m_pPrivate->CheckInvite(m_pUser)
                         && !sameas(m_pUser->GetName(),m_pPrivate->GetOwner())) {
                         m_pChannel=tlcAPI->chanGetGT(m_saveChanBuf);
                         saveChanName();
                         m_dnf->sayAgain();
                         break;
                    }
               }
               if (m_pChannel->m_flags&CHAN_FLAG_NOLIST) {
                    m_pChannel=tlcAPI->chanGetGT(m_saveChanBuf);
                    saveChanName();
                    m_dnf->sayAgain();
                    break;
               }
               if (!m_pChannel->CanAccess(m_pUser,CHAN_AXS_SEE)) {
                    m_pChannel=tlcAPI->chanGetGT(m_saveChanBuf);
                    saveChanName();
                    m_dnf->sayAgain();
                    break;
               }
               saveChanName();
               break;
          case LISTITEM:
               break;
          case DNFROWEND:
               m_pChannel=tlcAPI->chanGetGT(m_saveChanBuf);
               if (m_pChannel == NULL) {
                    m_dnf->tableDone();
                    break;
               }
               saveChanName();
               break;
          case DNFEND:
               rc=ACTHDONE;
               break;
          }
     }
     return(rc);
}

ACTHCODE
userSyn::proceedRequest()            // setup request context
{
     ACTHCODE rc=tlcBaseAuthSyn::proceedRequest();
     if (m_err == ERR_NOERROR) {
          m_SynState=SYNSTATE_SYNTH;
     }
     return(rc);
}

ACTHCODE
userSyn::proceedSynth()              // proceed with synthesis
{
     m_SynState=SYNSTATE_RESPONSE;
     return(ACTHMORE);
}

ACTHCODE
userSyn::proceedDerivedResponse()    // proceed with response
{
      ACTHCODE rc=ACTHMORE;

     if (!isValidSession()) {
          return(ACTHFORBID);
     }
     if (m_dnf == NULL) {
          m_dnf=dnfCreateHandlerURL(ses,&dnfUserMap,PPFIX);
     }
     else {
          m_pChannel=getChannel(m_userIDBuf);
          if (m_pChannel == NULL) {
               return(ACTHDONE);
          }
          if (m_psavUser != NULL) {
               struct usracc *ptr;
               // I'm setting usaptr up so that normal user-context
               // text variables will work.  For worldlink users,
               // the text vbls will obviously fail.
               ptr=GetAccPtr((CHAR *)m_psavUser->GetName());
               if (ptr != NULL) {
                    usaptr=ptr;
               }
          }
          teleChannelName=m_pChannel->GetName();
          teleChannelTopic=m_pChannel->GetTopic();
          if (m_psavUser != NULL) {
               teleUserid=m_psavUser->GetName();
               teleUseridURL=m_psavUser->GetName();
               teleUserAge=m_psavUser->GetAge();
               CHAR sex=m_psavUser->GetSex();
               setusaptr(m_psavUser->GetName());
               teleUserSex=sex;
               if (gCheckRegistry) {
                    dfaSetBlk(*regbb);
                    if (dfaAcqEQ(NULL,m_psavUser->GetName(),0)) {
                         setUpRegLink();
                    }
                    dfaRstBlk();
               }
               else {
                    setUpRegLink();
               }
               dfaRstBlk();
          }
          switch (m_dnf->process()) {
          case DNFBEGIN:
               m_psavUser=tlcAPI->chanUserLow(m_pChannel->GetName());
               if (m_psavUser == NULL) {
                    rc=ACTHDONE;
                    break;
               }
               saveUserName();
               break;
          case DNFROWBEGIN:
               if (!(m_psavUser->m_fFlags&USR_INCHAN) ||
                    m_psavUser->m_fFlags&USR_INVISB) {
                    m_psavUser=tlcAPI->chanUserGT(m_pChannel->GetName(),m_saveUserBuf);
                    if (m_psavUser == NULL) {
                         m_dnf->tableDone();
                         break;
                    }
                    saveUserName();
                    m_dnf->sayAgain();
               }
               break;
          case LISTITEM:
               break;
          case DNFROWEND:
               m_psavUser=tlcAPI->chanUserGT(m_pChannel->GetName(),m_saveUserBuf);
               if (m_psavUser == NULL) {
                    m_dnf->tableDone();
                    break;
               }
               saveUserName();
               break;
          case DNFEND:
               rc=ACTHDONE;
               break;
          }
     }
     return(rc);
}

ACTHCODE
sendSyn::proceedRequest()            // setup request context
{
     ACTHCODE rc=tlcBaseAuthSyn::proceedRequest();
     if (m_err == ERR_NOERROR) {
          m_SynState=SYNSTATE_SYNTH;
          if (GETINPUT("NAM_MSG")) {
               if (strlen(skpwht((const CHAR *)m_strInp)) == 0) {
                    m_err=ERR_EMPTYINPUT;
               }
          }
     }
     return(rc);
}

ACTHCODE
sendSyn::proceedSynth()              // proceed with synthesis
{
     m_SynState=SYNSTATE_RESPONSE;
     return(ACTHMORE);
}

ACTHCODE
sendSyn::proceedDerivedResponse()    // proceed with response
{
     ACTHCODE rc=ACTHFORBID;

     if (isValidSession() && m_dnf == NULL) {
          if (m_err == ERR_EMPTYINPUT) {
               m_pChannel=getChannel(m_pUser->GetName());
               m_pChannel->SendWelcome(m_pUser);
          }
          else {
               curUser=m_pUser;
               ASSERT(m_pUser != NULL);
               if (m_pUser != NULL && m_pUser->m_fFlags&USR_CHATTING) {
                    if (sameas(m_strInp,"x")) {
                         ExitChat(FALSE,m_pUser->GetName(),TRUE);
                         m_pChannel=getChannel(m_pUser->GetName());
                         m_pChannel->SendWelcome(m_pUser);
                    }
                    CTlcUser* pOthUser=tlcAPI->usrGetByName(m_pUser->GetChatUser());
                    if (pOthUser != NULL) {
                         CLiteAHTrans *liteTrans=dynamic_cast<CLiteAHTrans *>(m_pUser->GetTransport());
                         if (sameas(pOthUser->GetTransport()->GetName(),"Active HTML Lite")) {
                              pOthUser->OnRecvText(m_pUser->GetName(),NULL,(CHAR *)liteTrans->Color2ANSI(m_strInp),RECV_TYPE_CHATMSG);
                         }
                         else {
                              pOthUser->OnRecvText(m_pUser->GetName(),NULL,liteTrans->removeFilterTags((CHAR *)liteTrans->Color2ANSI(m_strInp)),RECV_TYPE_CHATMSG);
                         }
                         prfmsg(OTHCHAT3,(CHAR *)liteTrans->Color2ANSI(m_strInp));
                         stlcat(prfbuf,"\n",PFBSIZ);
                         m_pUser->AddLiteMsg(liteTrans->ANSI2HTML(prfbuf));
                         liteTrans->clearStoreBuf();
                         clrprf();
                    }
               }
               else if (m_pUser != NULL) {
                    curChannel=m_pChannel=getChannel(m_userIDBuf);
                    ASSERT(m_pChannel != NULL);
                    if (m_pChannel != NULL && !myCommandHandler()) {
                         ParseInput();
                    }
               }
          }
          return(successResponse(dnfSendMap,PPFIX "/send/"));
     }
     else if (m_dnf != NULL && m_dnf->process() == DNFEND) {
          rc=ACTHDONE;
     }
     return(rc);
}

ACTHCODE
profileSyn::proceedRequest()            // setup request context
{
     ACTHCODE rc=tlcBaseAuthSyn::proceedRequest();
     if (m_err == ERR_NOERROR) {
          m_SynState=SYNSTATE_SYNTH;
          if (isValidSession()) {
               if (GETINPUT("NAM_SELINTVAL")) {
                    SHORT retval=m_pUser->SetChatInterval(atoi(m_strInp));
                    if (retval != atoi(m_strInp)) {
                         m_err=ERR_BADCHATINTERVAL;
                         return(ACTHMORE);
                    }
               }
               if (GETINPUT("NAM_CHKCLEARENT")) {
                    ClearEntExit(REQENT3);
               }
               if (GETINPUT("NAM_REQENTMESSAGE") && strlen(m_strInp) > 0) {
                    if (!RequestEntExit(REQENT3,FALSE)) {
                         return(ACTHDONE);
                    }
                    RequestEntExit(REQENT3,TRUE);
               }
               if (GETINPUT("NAM_CHKCLEAREX")) {
                    ClearEntExit(REQEXT3);
               }
               if (GETINPUT("NAM_REQEXTMESSAGE") && strlen(m_strInp) > 0) {
                    if (!RequestEntExit(REQEXT3,FALSE)) {
                         return(ACTHDONE);
                    }
                    RequestEntExit(REQEXT3,TRUE);
               }
               if (GETINPUT("NAM_SELDEFCHAN")) {
                    if (sameas(m_strInp,"Private")) {
                         m_pUser->SetDefaultChan(CHANDFT_PRIVATE);
                    }
                    else {
                         m_pUser->SetDefaultChan(CHANDFT_MAIN);
                    }
               }
               if (GETINPUT("NAM_WEBTEL")) {
                    if (sameas(m_strInp,"JAVA")) {
                         m_pUser->m_fFlags|=USR_WEBTELJAVA;
                         m_pUser->m_fFlags&=~USR_WEBTELHTML;
                    }
                    else {
                         m_pUser->m_fFlags|=USR_WEBTELHTML;
                         m_pUser->m_fFlags&=~USR_WEBTELJAVA;
                    }
               }
               if (GETINPUT("NAM_STRIP")) {
                    if (sameas(m_strInp,"YES")) {
                         m_pUser->m_fFlags&=~USR_ENCODETAGS;
                    }
                    else {
                         m_pUser->m_fFlags|=USR_ENCODETAGS;
                    }
               }
               if (GETINPUT("NAM_TOPIC")) {
                    m_pUser->SetPrivateTopic(m_strInp);
               }
               else {
                    m_pUser->SetPrivateTopic("");
               }
               bout << "Update Successful.";
               rc=ACTHDONE;
          }
          else {
               rc=ACTHFORBID;
          }
     }
     return(rc);
}

ACTHCODE
profileSyn::proceedSynth()              // proceed with synthesis
{
     m_SynState=SYNSTATE_RESPONSE;
     return(ACTHMORE);
}


ACTHCODE
profileSyn::proceedDerivedResponse()    // proceed with response
{
     ACTHCODE rc=ACTHMORE;

     if (m_dnf == NULL) {
          if (m_err == ERR_NOERROR) {
               return(successResponse(dnfProfileMap,PPFIX "/profile/"));
          }
          else {
               return(errorResponse(dnfProfileErrorMap,PPFIX "/profile"));
          }
     }
     else {
          if (m_dnf->process() == DNFEND) {
               rc=ACTHDONE;
          }
     }
     return(rc);
}

ACTHCODE
receiveSyn::proceedRequest()            // setup request context
{
     ACTHCODE rc=tlcBaseAuthSyn::proceedRequest();
     if (m_err == ERR_NOERROR) {
          m_SynState=SYNSTATE_SYNTH;
     }
     return(rc);
}

ACTHCODE
receiveSyn::proceedSynth()              // proceed with synthesis
{
     m_SynState=SYNSTATE_RESPONSE;
     return(ACTHMORE);
}

ACTHCODE
receiveSyn::proceedDerivedResponse()    // proceed with response
{
     ACTHCODE rc=ACTHMORE;
     m_blogoff=TRUE;
     if (!isValidSession()) {
          m_err=ERR_SESSIONFAILURE;
     }
     if (m_dnf == NULL) {
          if (m_err == ERR_NOERROR) {
               m_dnf=dnfCreateHandlerURL(ses,&dnfMessageMap,PPFIX);
          }
          else {
               return(errorResponse(dnfMessageErrorMap,PPFIX "/receive/"));
          }
     }
     else {
          if (m_err != ERR_NOERROR) {
               if (m_dnf->process() == DNFEND) {
                    rc=ACTHDONE;
               }
          }
          else {
               ASSERT(m_pUser != NULL);
               GBOOL bSentMsg=FALSE;
               if (kilipg != 0) {  // channels are busied out
                    string sysdown=stpans(rawmsg(SYSDOWN));
                    bout << sysdown.c_str();
                    g_pUser = m_pUser;
                    liteLogOff();
                    rc=ACTHDONE;
               }
               else {
                    switch (m_dnf->process()) {
                    case DNFROWBEGIN:
                         if (m_pUser->m_fFlags&USR_CHANCHANGE) {
                              openTableTags();
                              updateScript();
                              termTableTags();
                              m_pUser->m_fFlags&=~USR_CHANCHANGE;
                              bout << flush;
                         }
                         if (m_pUser->GetMsg() == NULL) {
                              // do keepalive text so browser doesn't time out
                              if (m_tickSave == 0) {
                                   m_tickSave=::GetTickCount();
                              }
                              m_tickCurrent=::GetTickCount() - m_tickSave;
                              if (m_tickCurrent > (gTimeOut*1000)) {
                                   break;
                              }
                              m_dnf->sayAgain();
                         }
                         break;
                    case TELEMSG:
                         m_tickSave=0;  // went out, so reset save
                         if (m_pUser->GetMsg() != NULL ) {
                              openTableTags();
                              bout << m_pUser->GetMsg();
                              termTableTags();
                              m_pUser->PopMsg();
                         }
                         else {
                              string tmouttag=getasc(TMOUTTAG);
                              bout << tmouttag.c_str();
                         }
                         bout << flush;
                         break;
                    case DNFEND:
                         rc=ACTHDONE;
                         break;
                    }
                    if (m_pUser->m_fFlags&USR_LOGOFF) {
                         g_pUser=m_pUser;
                         liteLogOff();
                         rc=ACTHDONE;
                    }
               }
          }
     }
     return(rc);
}

ACTHCODE
initialSyn::proceedRequest()            // setup request context
{
     ACTHCODE rc=tlcBaseAuthSyn::proceedRequest();
     if (m_err == ERR_NOERROR) {
          m_SynState=SYNSTATE_SYNTH;
     }
     return(rc);
}

ACTHCODE
initialSyn::proceedSynth()              // proceed with synthesis
{
     m_SynState=SYNSTATE_RESPONSE;
     m_pszUserid=m_usr->userid();
     CTlcUser* pUser;
     if ((pUser=tlcAPI->usrGetByName(m_pszUserid)) != NULL) {
          m_err=ERR_ALREADIN;
     }
     return(ACTHMORE);
}

ACTHCODE
initialSyn::proceedDerivedResponse()    // proceed with response
{
     ACTHCODE rc=ACTHMORE;

     if (m_dnf == NULL) {
          if (m_err == ERR_NOERROR) {
               CHAR chanbuf[CHAN_MAX_SIZE];
               ses->param("channel",chanbuf,CHAN_MAX_SIZE);
               m_dnf=dnfCreateHandlerURL(ses,&tlcInitialMap,PPFIX);
               m_sesID=::GetTickCount();
               m_blogoff=TRUE;
               CTlcAHUser User;
               ULONG unum;

               User.m_iType=USR_TYPE_AHLITE;
               User.SetName(m_pszUserid);
               User.SetTransport(&transLiteAH);
               if ((unum=tlcAPI->FindIDByUser(m_pszUserid)) == 0L) {
                    unum=tlcAPI->CreateUniqueID(m_pszUserid);
               }
               User.SetTlcUnum(unum);
               User.SetTlcBoardNum(0);
               usaptr=GetAccPtr(m_pszUserid);
               User.SetSex(usaptr->sex == 'F' ? 'F' : 'M');
               User.SetAge(usaptr->age);
               User.LoadRecord();
               User.SetQueues(new MSGQUE, NULL);
               m_pUser=dynamic_cast<CTlcAHUser *>(tlcAPI->usrAdd(&User));
               User.Cleanup();
               transLiteAH.AddUser(m_pUser);
               if (!onsysn(m_pszUserid,1)) {
                    tlcChannelCreatePrivate(m_pszUserid);
               }
               JoinDefault(chanbuf);
               m_pUser->SetTime(m_sesID);
               stlcpy(m_sesIDBuf,ltoa(m_sesID),SESIDSIZ);
          }
          else {
               return(errorResponse(tlcInitialErrorMap,PPFIX "/"));
          }
     }
     else {
          if (m_dnf->process() == DNFEND) {
               rc=ACTHDONE;
          }
     }
     return(rc);
}


extern "C" {

VOID check_consumption(VOID)       // do credit consumption/profanity checking
{
     static INT cnt;
     static INT acb;
     CHAR user[TLCUIDSIZ];
     CTlcAHUser* pUser=NULL;

     pUser=dynamic_cast<CTlcAHUser*>(transLiteAH.GetFirstUser(NULL));

     setmbk(msgTlc);
     while (pUser != NULL) {
          CTlcChannel* pChannel=tlcAPI->chanGetByName(pUser->GetChannelName());
          stlcpy(user,pUser->GetName(),TLCUIDSIZ);
          if (cnt == 15) {
               LONG credconsumed=tlcAPI->m_iTlcSur;
               if (pChannel != NULL) {
                    credconsumed=pChannel->m_iCrConsumptionRate;
               }
               if (onsysn(pUser->GetName(),1)) {
                    credconsumed-=mmucrr;
               }
               // we charge 4 times a minute
               if (credconsumed > 0 && !gdedcrd(user,credconsumed/4,0,0)) {
                    string discnc=stpans(rawmsg(DISCNC));
                    pUser->AddLiteMsg(discnc.c_str());
                    pUser->m_fFlags|=USR_LOGOFF;
               }
          }
          if (cnt == 15 && (acb&1) && pUser->m_pfnacc != 0) {
               pUser->m_pfnacc--;
          }
          pUser=(CTlcAHUser*)transLiteAH.GetUserGT(user,NULL);
     }
     if (cnt == 15) {
          cnt=0;
     }
     cnt+=3;
     acb+=3;
     rstmbk();
     rtkick(3,check_consumption);
}

VOID check_offline(VOID)           // if user is in tele, but not online knock-off
{
     CTlcAHUser* pUser=NULL;
     GBOOL sessionIsLive=FALSE;
     INT savusrnum;
     CHAR user[TLCUIDSIZ];
     CHAR uidBuf[UIDSIZ+2];

     pUser=dynamic_cast<CTlcAHUser*>(transLiteAH.GetFirstUser(NULL));

     savusrnum=usrnum;
     while(pUser != NULL) {
          stlcpy(user,pUser->GetName(),TLCUIDSIZ);
          for (INT i=0; i < nterms; i++) {
               curusr(i);
               if (incusr(i,TRUE,TRUE) == BBSPRV) {
                    if (isAHUser((const CHAR *)usaptr->userid)) {
                         stlcpy(uidBuf,usaptr->userid,UIDSIZ+2);
                         CHAR *uptr=&uidBuf[1];
                         uidBuf[strlen(uidBuf)-1]='\0';
                         ASSERT(uidBuf != NULL);
                         if (sameas(pUser->GetName(),uptr)) {
                              sessionIsLive=TRUE;
                              break;
                         }
                    }
               }
          }
          if (!sessionIsLive
           && (::GetTickCount()-pUser->GetTime()) > (gGracePeriod*1000)) {
               g_pUser=pUser;
               liteLogOff();
          }
          pUser=(CTlcAHUser*)transLiteAH.GetUserGT(user,NULL);
     }
     usrnum=savusrnum;
     curusr(usrnum);
     rtkick(1,check_offline);
}

static VOID
pageticker(VOID)                   // keep track of page timing
{
     CTlcAHUser *pUser=(CTlcAHUser*)(transLiteAH.GetFirstUser(NULL));
     while (pUser != NULL) {
          struct pageInfo* pInfo=pUser->GetPageInfo();
          if (pInfo->pagedCtr > 0) {
               pInfo->pagedCtr--;
          }
          if (pInfo->pagedConsCtr > 0) {
               pInfo->pagedConsCtr--;
          }
          pUser=(CTlcAHUser*)(transLiteAH.GetNextUser(NULL));
     }
     rtkick(PAGETCKINT,pageticker);
}

VOID
initActiveHLite(VOID)              // initialization for active H lite
{
     tlcAPI->DeclareObjSize(sizeof(CTlcAHUser),0);
     iAHLiteTrans=tlcAPI->transRegister("Active HTML Lite",&transLiteAH);
     oldUsersOn=hdlusrson;
     hdlusrson=liteUsersOn;
     rtkick(1,check_consumption);
     rtkick(1,check_offline);
     hook_startup(initLiteAgent);
     rtkick(PAGETCKINT,pageticker);
     oldinvhook=tlcInvisRou;
     tlcInvisRou=liteInvHook;
}

} // end of extern "C"

class teleLiteAgent : public acthAgent {
public:
     VOID
     initOptions();                // init active H Lite message options

     teleLiteAgent() : acthAgent("Active HTML Lite Teleconference","telelite")
     {
          registerAgent(acthVersion);
          initOptions();
     }
     acthSynthesis* newSynthesis(acthSession *ses);

     ~teleLiteAgent()
     {
     }
};


teleLiteAgent* theteleLiteAgent;        // pointer to teleliteagent object

VOID
initLiteAgent(VOID)                // initialize lite agent
{
     HINSTANCE hinst;
     FARPROC regFunc;
     typedef DFAFILE** (*REGFUNC)(VOID);

     theteleLiteAgent=new teleLiteAgent;
     setmbk(msgTlc);
     GBOOL usingDefault=ynopt(REGDFLT);
     if (usingDefault && GetModuleHandle("GALREGAH.DLL") != NULL
      && (hinst=LoadLibrary("GALREG.DLL")) != NULL) {
          if ((regFunc=GetProcAddress(hinst,"_getregbb")) != NULL) {
               regbb=((REGFUNC)regFunc)();
               if (regbb != NULL) {
                    gCheckRegistry=TRUE;
               }
          }
     }
     initTeleTvbs();
     rstmbk();
}

acthSynthesis*                     // returned synthesis object
teleLiteAgent::newSynthesis(       // give base agent class synth object
acthSession* ses)                  // session object
{
     return(::teleNewSynthesis(ses));
}

VOID
teleLiteSynthesis::openTableTags() // opening table tags
{
     string opnttag=stpans(rawmsg(OPNTTAG));
     bout << opnttag.c_str();
}

VOID
teleLiteSynthesis::updateScript()  // javascript updates user list
{
     string updufunc=stpans(rawmsg(UPDUFUNC));
     bout << updufunc.c_str();
}

VOID
teleLiteSynthesis::termTableTags() // closing table tags
{
     string clstag=stpans(rawmsg(CLSTAG));
     bout << clstag.c_str();
}

VOID
teleLiteSynthesis::saveChanName()  // save channel name in buffer
{
     setmem(m_saveChanBuf,CHAN_MAX_SIZE,0);
     if (m_pChannel != NULL) {
          stlcpy(m_saveChanBuf,m_pChannel->GetName(),CHAN_MAX_SIZE);
     }
}

VOID
teleLiteSynthesis::saveUserName()  // save user name in buffer
{
     setmem(m_saveUserBuf,TLCUIDSIZ,0);
     if (m_psavUser != NULL) {
          stlcpy(m_saveUserBuf,m_psavUser->GetName(),TLCUIDSIZ);
     }
}

VOID
teleLiteSynthesis::ParseInput()    // handle inputted message
{
     CLiteAHTrans *liteTrans=dynamic_cast<CLiteAHTrans *>(m_pUser->GetTransport());
     CTlcTransport* pTransport;
     ASSERT(liteTrans != NULL);
     CHAR *pAnsStr=(CHAR *)liteTrans->Color2ANSI(m_strInp);
     if (!m_pChannel->CommandParse(pAnsStr,m_pUser->GetName())) {
          if (!tlcAPI->Parse(pAnsStr,m_pUser->GetName(),m_pChannel)) {
               if (!m_pChannel->ActionParse(pAnsStr,m_pUser->GetName())) {
                    if (m_pUser->m_fFlags&USR_SQUELCH) {
                         m_pUser->CmdResult(CMD_SPEAK,FALSE,CMD_SPEAK_SQUEL);
                    }
                    else if (!m_pUser->IsTypeOf(USR_NORMAL)
                      && m_pUser->m_iTimesSpoken >= tlcAPI->m_npaymx) {
                         m_pUser->CmdResult(CMD_SPEAK,FALSE,CMD_SPEAK_LIMITED);
                    }
                    else {
                         strcpy(input,pAnsStr);
                         CHAR* pfch=strdup(input);
                         (*setpfn)(stpans(pfch));
                         free(pfch);
                         parsin();
                         SHORT spd=m_pUser->IsTalkingTooFast();
                         if (spd != USR_SPEED_OK) {
                              clingo=0;
                              clrprf();
                              prfmsg(TOOFAST);
                              CLiteAHTrans *liteTrans=dynamic_cast<CLiteAHTrans *>(m_pUser->GetTransport());
                              ASSERT(liteTrans != NULL);
                              m_pUser->AddLiteMsg(prfbuf);
                              liteTrans->clearStoreBuf();
                              clrprf();
                         }
                         else if (!chk4pfn()) {
                              CHAR *msg2send;
                              CHAR *messageBuf=new CHAR[tinpsz];
                              CHAR *saveBuf=new CHAR[tinpsz];
                              CHAR *checkBuf=new CHAR[tinpsz];
                              stlcpy(messageBuf,m_strInp,tinpsz);
                              stlcpy(saveBuf,m_strInp,tinpsz);
                              pTransport=tlcAPI->transGetFirst();
                              while (pTransport != NULL) {
                                   if (sameas(pTransport->GetName(),"Active HTML Lite")) {
                                        GBOOL tagOnly=liteTrans->IsJustTags(messageBuf);
                                        if(!tagOnly) {
                                             msg2send=(CHAR *)liteTrans->Color2ANSI(messageBuf);
                                             stlcpy(messageBuf,msg2send,tinpsz);
                                        }
                                        if (!m_usr->hasKey(gKey4Tags) || tagOnly) {
                                             msg2send=liteTrans->encodeTags(messageBuf,TRUE);
                                        }
                                        stlcpy(checkBuf,msg2send,tinpsz);
                                        m_pChannel->PublicSendToTrans(pTransport,m_pUser->GetName(),NULL,checkBuf,RECV_TYPE_PUBLIC,0);
                                   }
                                   else {
                                        msg2send=(CHAR *)liteTrans->Color2ANSI(messageBuf);
                                        stlcpy(messageBuf,msg2send,tinpsz);
                                        stlcpy(checkBuf,msg2send,tinpsz);
                                        if(strlen(stpans(checkBuf)) == 0) {
                                             break;
                                        }
                                        if (!liteTrans->IsJustTags(messageBuf)) {
                                             msg2send=liteTrans->removeFilterTags(messageBuf);
                                        }
                                        m_pChannel->PublicSendToTrans(pTransport,m_pUser->GetName(),NULL,msg2send,RECV_TYPE_PUBLIC,0);

                                   }
                                   stlcpy(messageBuf,saveBuf,tinpsz);
                                   msg2send=saveBuf;
                                   pTransport=tlcAPI->transGetNext();
                              }
                              delete messageBuf;
                              delete saveBuf;
                              delete checkBuf;
                              m_pUser->CmdResult(CMD_SPEAK,TRUE,0);
                         }
                         else {
                              clingo=0;
                              clrprf();
                              prfmsg(PFNWRD2);
                              CLiteAHTrans *liteTrans=dynamic_cast<CLiteAHTrans *>(m_pUser->GetTransport());
                              ASSERT(liteTrans != NULL);
                              m_pUser->AddLiteMsg(prfbuf);
                              liteTrans->clearStoreBuf();
                              clrprf();
                         }
                    }
               }
          }
     }
}

VOID
teleLiteSynthesis::JoinDefault(    // join default channel
const CHAR *requestedChannel)      // requested channel to join
{
     if (requestedChannel != NULL
      && (m_pChannel=tlcAPI->chanGetByName(requestedChannel)) != NULL) {
          ;
     }
     else if (m_pUser->GetDefaultChan() == CHANDFT_MAIN) {
          if ((m_pChannel=tlcAPI->chanGetByName(dftchan)) == NULL) {
              m_pChannel=tlcAPI->chanGetByName(mainchan);
          }
          if (!m_pChannel->CanAccess(m_pUser,CHAN_AXS_JOIN)) {
               m_pChannel=tlcAPI->chanGetByName(tlcPrivateFromUser(m_pUser->GetName()));
          }
     }
     else {
          m_pChannel=tlcAPI->chanGetByName(tlcPrivateFromUser(m_pUser->GetName()));
     }
     ASSERT(m_pChannel != NULL);
     tlcenter(m_pUser->GetName());
     m_pUser->m_fFlags|=USR_INCHAN;
     if (m_pChannel->AddUser(m_pUser,TRUE)) {
          tlcAPI->usrDelete(m_pUser);  // delete the user with no channel info
          m_pUser=dynamic_cast<CTlcAHUser*>(tlcAPI->chanFindUser(m_pChannel->GetName(),m_pszUserid));
     }
}

CTlcUser *                         // user object
getUser(                           // get a user's user object
const CHAR *usr)                   // user in question
{
     ASSERT(usr != NULL);
     return(tlcAPI->usrGetByName(usr));
}

CTlcChannel *                      // channel object
getChannel(                        // get a user's channel object
const CHAR *usr)                   // user in question
{
     ASSERT(usr != NULL);
     CTlcAHUser *pUser=dynamic_cast<CTlcAHUser *>(getUser(usr));
     if (pUser == NULL) {
          return(NULL);
     }
     return(tlcAPI->chanGetByName(pUser->GetChannelName()));
}



GBOOL
teleLiteSynthesis::isValidSession()// top-level session validation method
{
     getTeleParams();
     if (validSession(m_userIDBuf,m_sesIDBuf)) {
          return(TRUE);
     }
     return(FALSE);
}

GBOOL
teleLiteSynthesis::validSession(   // low-level session validation
const CHAR *user,                  // the user in question
const CHAR *sesid)                 // the session-id to validate
{
     if (m_userIDBuf[0] == '\0' || m_sesIDBuf[0] == '\0') {
          return(FALSE);
     }
     m_pUser=dynamic_cast<CTlcAHUser *>(getUser(m_userIDBuf));

     if (m_pUser == NULL) {
          return(FALSE);
     }
     if (m_pUser->GetTime() != atol(sesid)) {
          return(FALSE);
     }
     return(TRUE);
}

VOID
teleLiteSynthesis::abort()         // catch session abort and log user off
{
     if (m_blogoff == TRUE
      && (g_pUser=dynamic_cast<CTlcAHUser *>(getUser(ses->getUser()->userid()))) != NULL) {
          liteLogOff();
     }
}

GBOOL
teleLiteSynthesis::RequestEntExit( // handle requested entrance/exit message
SHORT iType,                       // entrance or exit?
GBOOL change)                      // actually change?
{
     SHORT fMsg;

     acthUserID *usr=ses->getUser();
     CLiteAHTrans *liteTrans=dynamic_cast<CLiteAHTrans *>(m_pUser->GetTransport());
     if (m_pUser->CheckAccess(rawmsg(AUTKEY))) {
          if (iType == REQENT3 && sameas(m_strInp,m_pUser->GetEntrance(MSG_CURRENT))) {
               return(TRUE);
          }
          if (iType == REQEXT3 && sameas(m_strInp,m_pUser->GetExit(MSG_CURRENT))) {
               return(TRUE);
          }
          if (tlcAPI->m_bEMsgChg) {
               if (!usr->afford(static_cast<LONG>(tlcAPI->m_iEMsgChg))) {
                    m_err=(iType == REQENT3 ? ERR_AFRDENT : ERR_AFRDEXT);
                    isbout=TRUE;
                    return(FALSE);
               }
               else {
                    if (tlcAPI->m_bLogEMsg && change) {
                         logcrd(m_pUser->GetName(),tlcAPI->m_iEMsgChg);
                    }
                    fMsg=MSG_CURRENT;
               }
          }
          else {
               fMsg=MSG_CURRENT;
          }
     }
     if (!change) {
          return(TRUE);
     }
     if (iType == REQENT3) {
          if (sameas(m_strInp,m_pUser->GetEntrance(MSG_CURRENT))) {
               return(TRUE);
          }
          m_pUser->SetEntrance(m_strInp,fMsg);
     }
     else {
          if (sameas(m_strInp,m_pUser->GetExit(MSG_CURRENT))) {
               return(TRUE);
          }
          m_pUser->SetExit(m_strInp,fMsg);
     }
     if (fMsg == MSG_CURRENT) {
          if (iType == REQENT3) {
               m_pUser->SetEntrance("",MSG_REQUESTED);
          }
          else {
               m_pUser->SetExit("",MSG_REQUESTED);
          }
          if (tlcAPI->m_bEMsgChg) {
               if (m_flag == FALSE) {
                    usr->charge(static_cast<LONG>(tlcAPI->m_iEMsgChg));
                    prfmsg(YOUUPD3,tlcAPI->m_iEMsgChg);
                    CHAR *ptr;
                    ptr=skptwht(stpans(liteTrans->belStrip(prfbuf)));
                    depad(ptr);
                    bout << ptr << endl;
                    isbout=TRUE;
                    m_flag=TRUE;
                    clrprf();
               }
          }
     }
     else {
          if (iType == REQENT3
           && sameas(m_strInp,m_pUser->GetEntrance(MSG_REQUESTED))) {
                    return(TRUE);
          }
          if (iType == REQEXT3
           && sameas(m_strInp,m_pUser->GetExit(MSG_REQUESTED))) {
                    return(TRUE);
          }
          prfmsg(OKSET2);
          if (!m_pUser->ChangedMsg()) {
               chgnot(m_pUser->GetName(),EEMNOT);
               m_pUser->SetChangedMsg(TRUE);
          }
          CHAR *ptr;
          ptr=skptwht(stpans(liteTrans->belStrip(prfbuf)));
          depad(ptr);
          bout << ptr << endl;
          isbout=TRUE;
          clrprf();
     }
     return(TRUE);
}

VOID
teleLiteSynthesis::ClearEntExit(   // clear entrace/exit msg
SHORT iType)                       // entrance or exit?
{
     if (iType == REQENT3) {
          m_pUser->SetEntrance("",MSG_REQUESTED);
          m_pUser->SetEntrance("",MSG_CURRENT);
     }
     else {
          m_pUser->SetExit("",MSG_REQUESTED);
          m_pUser->SetExit("",MSG_CURRENT);
     }
}

VOID
add2recentCallers(                 // add user to recent caller list
CTlcUser* pUser)                   // the user to add
{
     if (sysrec || !(pUser->m_fFlags&USR_OPERATOR)) {
          movmem(recents,&recents[1],sizeof(struct recalls)*(nreccl-1));
          recents[0].logon=(static_cast<CTlcAHUser*>(pUser)->GetPackedTime() == 0
                  ? now() : static_cast<CTlcAHUser*>(pUser)->GetPackedTime());
          recents[0].logoff=now();
          strcpy(recents[0].userid,pUser->GetName());
     }
}

VOID
liteUsersOn(VOID)                  // list of AH lite users
{
     CTlcUser* pUser;

     oldUsersOn();
     setmbk(msgTlc);
     if ((pUser=transLiteAH.GetFirstUser(NULL)) != NULL) {
          do {
               if (!onsysn(pUser->GetName(),1)) {
                    prfmsg(ULSLINA2,"AH",pUser->GetName(),tlcmod.descrp);
               }
          }
          while ((pUser=transLiteAH.GetNextUser(NULL)) != NULL);
          outprf(usrnum);
          prf("");
     }
     rstmbk();
}

VOID
teleLiteAgent::initOptions()       // initialize message options
{
     ASSERT(msgTlc != NULL);
     setmbk(msgTlc);
     CHAR *keyr=getmsg(HTLCKEY);
     stlcpy(gKeyReqed,keyr,KEYSIZ);
     CHAR *kptr=getmsg(HTAGKEY);
     stlcpy(gKey4Tags,kptr,KEYSIZ);
     gGracePeriod=numopt(GRACEPD,1,30);
     gTimeOut=numopt(BRWSTOUT,5,240);
     gDefaultTele=tokopt(DFTWBTEL,"HTML","JAVA",NULL);
     rstmbk();
}

VOID
liteLogOff()                        // Handle AH-Lite user logoff
{                                   // assumes g_pUser is valid
     setmbk(msgTlc);
     CHAR chanName[CHAN_MAX_SIZE];
     CHAR tlcUsrBuf[TLCUIDSIZ];
     CHAR *pUserName;
     CTlcChannel* m_pChannel;

     ASSERT(g_pUser != NULL);

     stlcpy(tlcUsrBuf,g_pUser->GetName(),TLCUIDSIZ);
     pUserName=tlcUsrBuf;

     m_pChannel=getChannel(pUserName);
     if (m_pChannel == NULL) {
          return;
     }
     stzcpy(chanName,pUserName,CHAN_MAX_SIZE);
     strcat(chanName,"'s");
     if (g_pUser->m_fFlags&USR_CHATTING) {
           ExitChat(TRUE,pUserName,TRUE);
     }
     g_pUser->SaveRecord();
     transLiteAH.RemoveUser(g_pUser);
     RemoveInvite(g_pUser);
     RemoveForget(g_pUser);
     add2recentCallers(g_pUser);

     m_pChannel->RemoveUser(g_pUser,LEAVE_LOGOFF);
     if (!onsysn(pUserName,1)) {
           tlcAPI->chanMoveAllUsers(chanName,dftchan,CHAN_SWITCH_USER_LOGOFF,SCMSG_USER_LOGOFF);
           tlcAPI->chanRemoveByName(chanName);
     }
     tlcexit(pUserName);
     rstmbk();
}


GBOOL
isAHUser(                          // is this user Active H?
const CHAR *uid)                   // the user in question
{
     if (uid[0] == '(' && uid[strlen(uid)-1] == ')') {
          return(TRUE);
     }
     return(FALSE);
}

VOID
teleLiteSynthesis::setUpRegLink()  // setup our registry link
{
     ostrstream ost;
     ost << " HREF=\"http://" << ses->host();
     string uid=m_psavUser->GetName();
     prfmsg(REGHREF,urlEncode(uid).c_str());
     ost << prfbuf << "\"";
     clrprf();
     teleRegistryLink=ost.str();
     ost.rdbuf()->freeze(0);
}

GBOOL
teleLiteSynthesis::myCommandHandler()// handles SCAN/LIST/USERS
{                                    // because default handler won't work properly for me
     CTlcUser* pOthUsr;
     CTlcChannel* pChannel;

     stlcpy(input,m_strInp,tinpsz);
     parsin();
     if (margc == 2 && sameas(margv[0],"help")
      && sameas(margv[1],"tags")) {
          CLiteAHTrans *liteTrans=dynamic_cast<CLiteAHTrans *>(m_pUser->GetTransport());
          liteTrans->SupportedTags(m_pUser);
          return(TRUE);
     }
     if (margc >= 1 && sameas(margv[0],"SCAN")) {
          clrprf();
          string scntabo=stpans(rawmsg(SCNTABO));
          string scntabc=stpans(rawmsg(SCNTABC));

          stlcat(prfbuf,scntabo.c_str(),PFBSIZ);
          if (margc == 1) { // regular scan
               pOthUsr=tlcAPI->usrGetFirst();
               while (pOthUsr != NULL) {
                    VOID* SavePos=tlcAPI->usrGetPos();
                    if (teleIsLocal(pOthUsr)) {
                         ScanListUser(m_pUser,pOthUsr);
                    }
                    tlcAPI->usrSetPos(SavePos);
                    pOthUsr=tlcAPI->usrGetNext();
               }
          }
          else if (sameas(margv[1],"ALL")) {
               pChannel=tlcAPI->chanGetFirst();
               while (pChannel != NULL) {
                    VOID* SavePos=tlcAPI->chanGetPos();
                    ScanListChan(pChannel,m_pUser);
                    tlcAPI->chanSetPos(SavePos);
                    pChannel=tlcAPI->chanGetNext();
               }
          }
          else if (sameas(margv[1],"c") || sameas(margv[1],"chan")
            || sameas(margv[1],"channel")) {
               pChannel=tlcAPI->chanGetByName(margc == 2 ? m_pUser->GetChannelName()
                                                         : margv[2]);
               if (pChannel != NULL) {
                    ScanListChan(pChannel,m_pUser);
               }
               else {
                    /* if bad channel name, rebuff the guy! */
                    return(TRUE);
               }
          }
          else {
               pOthUsr=tlcAPI->usrGetFirst();
               while (pOthUsr != NULL) {
                    if (findstg(margv[0],const_cast<CHAR*>(pOthUsr->GetName())) > 0) {
                         VOID* SavePos=tlcAPI->usrGetPos();
                         ScanListUser(m_pUser,pOthUsr);
                         tlcAPI->usrSetPos(SavePos);
                    }
                    pOthUsr=tlcAPI->usrGetNext();
               }
          }
          stlcat(prfbuf,scntabc.c_str(),PFBSIZ);
          Stripcrlf(prfbuf);
          m_pUser->AddLiteMsg(prfbuf);
          clrprf();
          return(TRUE);
     }
     else if (margc == 1 && sameas(margv[0],"USERS")) {
          INT res;
          CTlcUser* pUser=NULL;
          curUser=m_pUser;

          clrprf();
          string usrtabo=stpans(rawmsg(USRTABO));
          string usrtabc=stpans(rawmsg(USRTABC));
          string usrtro=stpans(rawmsg(USRTRO));
          string usrtdo=stpans(rawmsg(USRTDO));
          string usrtrc=stpans(rawmsg(USRTRC));

          stlcat(prfbuf,usrtabo.c_str(),PFBSIZ);
          for (othusn=0; othusn < nterms; othusn++) {
               othusp=usroff(othusn);
               if ((res=incusr(othusn,TRUE,FALSE)) > VACANT) {
                    othuap=uacoff(othusn);
                    stlcat(prfbuf,usrtro.c_str(),PFBSIZ);
                    CHAR buf[3];
                    sprintf(buf,"%X",channel[othusn]);
                    stlcat(prfbuf,buf,PFBSIZ);
                    stlcat(prfbuf,usrtdo.c_str(),PFBSIZ);
                    switch (res) {
                    case ONLINE:
                    case SUPIPG:
                         stlcat(prfbuf,res == ONLINE ? "(log-on)" : "(sign-up)" ,PFBSIZ);
                         stlcat(prfbuf,usrtdo.c_str(),PFBSIZ);
                         break;
                    default:
                         stlcat(prfbuf,othuap->userid,PFBSIZ);
                         stlcat(prfbuf,usrtdo.c_str(),PFBSIZ);
                         stlcat(prfbuf,module[othusp->state]->descrp,PFBSIZ);
                    }
                    stlcat(prfbuf,usrtrc.c_str(),PFBSIZ);
               }
          }
          if ((pUser=transAH.GetFirstUser(NULL)) != NULL) {
               do {
                    if (!onsysn(pUser->GetName(),1)) {
                         stlcat(prfbuf,usrtro.c_str(),PFBSIZ);
                         stlcat(prfbuf,"AH",PFBSIZ);
                         stlcat(prfbuf,usrtdo.c_str(),PFBSIZ);
                         stlcat(prfbuf,pUser->GetName(),PFBSIZ);
                         stlcat(prfbuf,usrtdo.c_str(),PFBSIZ);
                         stlcat(prfbuf,tlcmod.descrp,PFBSIZ);
                         stlcat(prfbuf,usrtdo.c_str(),PFBSIZ);
                         stlcat(prfbuf,usrtrc.c_str(),PFBSIZ);
                    }
               } while ((pUser=transAH.GetNextUser(NULL)) != NULL);
          }
          if ((pUser=transLiteAH.GetFirstUser(NULL)) != NULL) {
               do {
                    if (!onsysn(pUser->GetName(),1)) {
                         stlcat(prfbuf,usrtro.c_str(),PFBSIZ);
                         stlcat(prfbuf,"AH",PFBSIZ);
                         stlcat(prfbuf,usrtdo.c_str(),PFBSIZ);
                         stlcat(prfbuf,pUser->GetName(),PFBSIZ);
                         stlcat(prfbuf,usrtdo.c_str(),PFBSIZ);
                         stlcat(prfbuf,tlcmod.descrp,PFBSIZ);
                         stlcat(prfbuf,usrtdo.c_str(),PFBSIZ);
                         stlcat(prfbuf,usrtrc.c_str(),PFBSIZ);
                    }
               } while ((pUser=transLiteAH.GetNextUser(NULL)) != NULL);
          }
          stlcat(prfbuf,usrtabc.c_str(),PFBSIZ);
          Stripcrlf(prfbuf);
          m_pUser->AddLiteMsg(prfbuf);
          clrprf();
          return(TRUE);
     }
     else if (margc == 1 && sameas(margv[0],"LIST")) {
          if (!(m_pUser->m_fFlags&USR_INCHAN)) {
               return(TRUE);
          }
          pChannel=tlcAPI->chanGetFirst();

          /* HACK strings */
          string lsttdo=stpans(rawmsg(LSTTDO));
          string lsttro=stpans(rawmsg(LSTTRO));
          string lsttrc=stpans(rawmsg(LSTTRC));
          string lsttabc=stpans(rawmsg(LSTTABC));
          string lsttabo=stpans(rawmsg(LSTTABO));

          stlcat(prfbuf,lsttabo.c_str(),PFBSIZ);
          while (pChannel != NULL) {
               VOID* SavePos=tlcAPI->chanGetPos();
               if (pChannel->GetType()&CHAN_TYPE_PRIVATE) {
                    CTlcPrivateChannel* pPrivate;
                    pPrivate=dynamic_cast<CTlcPrivateChannel*>(pChannel);
                    if (!pPrivate->CheckInvite(m_pUser)
                     && !sameas(curUser->GetName(),pPrivate->GetOwner())) {
                         tlcAPI->chanSetPos(SavePos);
                         pChannel=tlcAPI->chanGetNext();
                         continue;
                    }
               }
               if (pChannel->m_flags&CHAN_FLAG_NOLIST) {
                    tlcAPI->chanSetPos(SavePos);
                    pChannel=tlcAPI->chanGetNext();
                    continue;
               }
               if (pChannel->CanAccess(m_pUser,CHAN_AXS_SEE)
                || m_pUser->CheckAccess(tlcAPI->keyGetSys())) {
                    stlcat(prfbuf,lsttro.c_str(),PFBSIZ);
                    stlcat(prfbuf,pChannel->GetName(),PFBSIZ);
                    stlcat(prfbuf,lsttdo.c_str(),PFBSIZ);
                    stlcat(prfbuf,pChannel->GetTopic(),PFBSIZ);
                    stlcat(prfbuf,lsttdo.c_str(),PFBSIZ);
                    stlcat(prfbuf,ltoa(pChannel->GetNumVisible()),PFBSIZ);
                    stlcat(prfbuf,lsttrc.c_str(),PFBSIZ);
               }
               tlcAPI->chanSetPos(SavePos);
               pChannel=tlcAPI->chanGetNext();
          }
          stlcat(prfbuf,lsttabc.c_str(),PFBSIZ);
          Stripcrlf(prfbuf);
          m_pUser->AddLiteMsg(prfbuf);
          clrprf();
          return(TRUE);
     }
     return(FALSE);
}

static VOID
ScanListChan(                      // get scan info for channel
CTlcChannel* pChannel,             // channel to get info for
CTlcUser* pUser)                   // user requesting info
{
     CTlcUser* pOthUsr=pChannel->GetFirstUser();

     while (pOthUsr != NULL) {
          VOID* SavePos=tlcAPI->usrGetPos();
          ScanListUser(pUser,pOthUsr);
          tlcAPI->usrSetPos(SavePos);
          pOthUsr=pChannel->GetNextUser();
     }
}

static VOID
ScanListUser(                      // scan info for part. user
CTlcUser *pUser,                   // user doing scan
CTlcUser *pOthUsr)                 // user to getting info on
{
     CTlcScanInf* pScanInf=static_cast<CTlcScanInf*>(tlcwrk);
     CTlcChannel* pChannel;
     SHORT        visInfo;

     visInfo=FULL;

     if (pOthUsr->m_fFlags&USR_INVISB) {
          return;
     }
     pChannel=tlcAPI->chanGetByName(pOthUsr->GetChannelName());
     if (pChannel == NULL) {
          return;
     }
     if (!pChannel->CanAccess(pUser,CHAN_AXS_SEE)) {
          visInfo|=CHANUN;
     }
     else if (!pOthUsr->IsListed()) {
          visInfo|=UNLIST;
     }
     if (visInfo != FULL) {
          if (pOthUsr == pUser || pUser->CheckAccess(tlcAPI->keyGetSys())) {
               visInfo|=PARA;
          }
          if (visInfo&CHANUN && pChannel->CanAccess(pUser,CHAN_AXS_MODERATOR)) {
               visInfo|=PARA;
          }
          if (!teleIsLocal(pOthUsr)) {
               visInfo&=~PARA;
          }
     }
     if (pOthUsr->m_fFlags&USR_CHATTING) {
          stzcpy(pScanInf->m_strChan,"(Chatting...)",CHAN_MAX_SIZE);

     }
     else if (!(pOthUsr->m_fFlags&USR_INCHAN)) {
          stzcpy(pScanInf->m_strChan,"(Editing...)",CHAN_MAX_SIZE);
     }
     else if (visInfo == FULL) {
          stzcpy(pScanInf->m_strChan,pChannel->GetName(),CHAN_MAX_SIZE);
     }
     else if (visInfo&PARA) {
          stzcpy(pScanInf->m_strChan,spr("Unlisted... [%s]",pChannel->GetName()),CHAN_MAX_SIZE);
     }
     else {
          stzcpy(pScanInf->m_strChan,"Unlisted...",CHAN_MAX_SIZE);
     }
     string scntro=stpans(rawmsg(SCNTRO));
     string scntdo=stpans(rawmsg(SCNTDO));
     string scntrc=stpans(rawmsg(SCNTRC));

     stlcat(prfbuf,scntro.c_str(),PFBSIZ);
     stlcat(prfbuf,pOthUsr->GetName(),PFBSIZ);
     stlcat(prfbuf,scntdo.c_str(),PFBSIZ);
     if (pUser->CheckForget(pOthUsr)) {
          stlcat(prfbuf,languages[clingo]->yes,PFBSIZ);
     }
     else {
          stlcat(prfbuf,languages[clingo]->no,PFBSIZ);
     }
     stlcat(prfbuf,scntdo.c_str(),PFBSIZ);
     if (pUser->CheckInvite(pOthUsr)) {
          stlcat(prfbuf,languages[clingo]->yes,PFBSIZ);
     }
     else {
          stlcat(prfbuf,languages[clingo]->no,PFBSIZ);
     }
     stlcat(prfbuf,scntdo.c_str(),PFBSIZ);
     stlcat(prfbuf,pScanInf->m_strChan,PFBSIZ);
     stlcat(prfbuf,scntrc.c_str(),PFBSIZ);
}

static VOID
liteInvHook(
INT unum)
{
     GBOOL invis=FALSE;

     if (usroff(unum)->flags&INVISB) {
          invis=TRUE;
     }
     CTlcUser* pUser;
     if ((pUser=tlcAPI->usrGetByName(uacoff(unum)->userid)) != NULL
      && pUser->GetUsrnum() >= 0) {
          CTlcChannel* savchn;
          savchn=curChannel;
          curChannel=tlcAPI->chanGetByName(pUser->GetChannelName());
          transLiteAH.SendAll(pUser->GetName(),NULL,NULL,
             (invis ? RECV_TYPE_USEREXIT : RECV_TYPE_USERENTER),NULL,0);
          curChannel=savchn;
     }
     oldinvhook(unum);
}

CHAR*
Stripcrlf(                         // strip \r and \n from a string
CHAR* str)                         // string to strip
{
     strrpl(str,'\r',' ');
     strrpl(str,'\n',' ');
     return(str);
}
