/***************************************************************************
 *                                                                         *
 *   AHLITE.CPP                                                            *
 *                                                                         *
 *   Copyright (c) 1998  Galacticomm, Inc.        All Rights Reserved      *
 *                                                                         *
 *   "Lite" Teleconference transport layer.                                *
 *                                                                         *
 *                                               - N.C. Osterc  6/14/97    *
 *                                                                         *
 ***************************************************************************/

#pragma option -w-par    // fixes warning in memory.h
#include "gcomm.h"
#include "majorbbs.h"
#include "stdcomp.h"
#include "tlcapi.hpp"
#pragma option -w-aus
#include <deque>
#pragma option -w-aus.
#include "iterand.h"
using namespace std;
#include "tlcahusr.hpp"
#include "ahlite.hpp"
#include "iostream.h"
#include "fstream.h"
#include "ahutil.h"
#include "webd.h"
#include "strings.h"
#define FILREV "$Revision: 21 $"

static CHAR* ansiarr[]= { "[0",NULL,
                          "[4",NULL,
                          "30m",NULL,
                          "31m",NULL,
                          "32m",NULL,
                          "33m",NULL,
                          "34m",NULL,
                          "35m",NULL,
                          "36m",NULL,
                          "37m",NULL,
                          "0m",NULL,
                          "1m",NULL,
                          "4m",NULL };

static CHAR* color2ansarr[]= {NULL,"\33[30m",
                              NULL,"\33[31m",
                              NULL,"\33[32m",
                              NULL,"\33[33m",
                              NULL,"\33[34m",
                              NULL,"\33[35m",
                              NULL,"\33[36m",
                              NULL,"\33[37m" };

static CHAR * fontTermTagBold;

#define FILTAGMAXSIZ 256                    // maximum size of a tag
#define MAXFILTAGS 100                      // maximum number of filter tags
#define MAXALLTAGS (FILTAGMAXSIZ*MAXFILTAGS)// total size of tags and size
#define MAXTELEINPSIZ 256                   // maximum size of teleconference input
#define LASTCOLOR2CHECK 19                  // last color 2 check in ansiarr
#define ANSARRSIZ 26                        // size of ansi array
#define NORMALATTON1 0                      // normal attribute
#define NORMALATTON2 20                     // normal attribute
#define UNDERLINEATTON1 2                   // underline attribute
#define UNDERLINEATTON2 24                  // underline attribute

static GBOOL gTagsAllowed=FALSE;            // are HTML tags allowed?
static GBOOL gEmulateTerm=FALSE;            // emulate terminal mode ( ANSI )?
static GBOOL gTransNeedsInit=TRUE;          // does transport need initializing?

MARKSOURCE(ahlite)

VOID
initAnsiArrays()                            // init ansi translation tables
{
     ansiarr[1]=strdup("");
     ansiarr[3]=strdup("");
     ansiarr[5]=stpans(stgopt(FONTGRAY));
     ansiarr[7]=stpans(stgopt(FONTRED));
     ansiarr[9]=stpans(stgopt(FONTGRN));
     ansiarr[11]=stpans(stgopt(FONTYEL));
     ansiarr[13]=stpans(stgopt(FONTBLUE));
     ansiarr[15]=stpans(stgopt(FONTMAG));
     ansiarr[17]=stpans(stgopt(FONTCYAN));
     ansiarr[19]=stpans(stgopt(FONTWHT));
     ansiarr[21]=stpans(stgopt(FONTWHT));
     ansiarr[23]=stpans(stgopt(FONTWHT));
     ansiarr[25]=stpans(stgopt(FONTWHT));

     color2ansarr[0]=stpans(stgopt(BLACK));
     color2ansarr[2]=stpans(stgopt(RED));
     color2ansarr[4]=stpans(stgopt(GREEN));
     color2ansarr[6]=stpans(stgopt(YELLOW));
     color2ansarr[8]=stpans(stgopt(BLUE));
     color2ansarr[10]=stpans(stgopt(MAGENTA));
     color2ansarr[12]=stpans(stgopt(CYAN));
     color2ansarr[14]=stpans(stgopt(WHITE));
     fontTermTagBold=stpans(stgopt(FTERMTAG));
}

CLiteAHTrans::CLiteAHTrans() : CTlcTransport()
{
     m_fFlags|=(TRANS_IMPLPRIV|TRANS_IMPLCHAT);
     filterqueue=NULL;
     m_storeBuf=NULL;
}

CLiteAHTrans::~CLiteAHTrans()
{
     if (filterqueue != NULL) {
          while (!filterqueue->empty()) {
               delete [] filterqueue->back();
               filterqueue->pop_back();

          }
          delete filterqueue;
     }
}

VOID
CLiteAHTrans::initTransport()      // Initialize transport
{
     ASSERT(msgTlc != NULL);

     setmbk(msgTlc);
     gTagsAllowed=ynopt(ALLOWTAG);
     gEmulateTerm=ynopt(EMUTERM);
     CHAR *tagfltr=getmsg(TAGFLTR);
     if (strlen(tagfltr) == 0) {
          rstmbk();
          return;
     }
     fstream* fstrptr=new fstream(tagfltr,ios::in);
     if (fstrptr == NULL) {
          shocst("Tag Filter File not found","File %s not found",tagfltr);
          rstmbk();
          return;
     }
     filterqueue=new FILTERQUE;

     CHAR *fptr=new CHAR[FILTAGMAXSIZ];
     fstrptr->getline(fptr,FILTAGMAXSIZ,'\n');
     INT count=0;
     while (fstrptr->gcount() > 0 && fptr != NULL && strlen(skptwht(fptr)) > 0
       && count < MAXFILTAGS) {
          filterqueue->push_front((const CHAR *)fptr);
          fptr = new CHAR[FILTAGMAXSIZ];
          fstrptr->getline(fptr,FILTAGMAXSIZ,'\n');
          count++;
     }
     delete fptr;
     delete fstrptr;
     ::initAnsiArrays();
     rstmbk();
}

VOID
CLiteAHTrans::SendTabbedDbData(    // must be overriden; unused in my transport
const CHAR *data,
CTlcChannel* pChannel)
{
     (VOID)data;
     (VOID)pChannel;
}

GBOOL                              // TRUE OR FALSE
CLiteAHTrans::IsJustTags(          // does this message just consist of tags?
CHAR *msg)                         // the message being checked
{
     CHAR msgBuf[MAXTELEINPSIZ];

     setmem(msgBuf,MAXTELEINPSIZ,0);
     ASSERT(msg != NULL);
     if(msg == NULL) {
          return(TRUE);
     }
     stlcpy(msgBuf,msg,MAXTELEINPSIZ);
     strrpl(msgBuf,'\n',' ');
     strrpl(msgBuf,'\r',' ');
     CHAR* removed=removeFilterTags(msgBuf);
     if (removed == NULL || strlen(skpwht(removed)) == 0) {
          return(TRUE);
     }
     return(FALSE);
}

VOID
CLiteAHTrans::SupportedTags(       // Generate a list of supported tags
CTlcAHUser *pAHUser)               // the user to show list to
{
     static CHAR tagBuf[MAXALLTAGS];

     setmem(tagBuf,MAXALLTAGS,0);
     if (gTransNeedsInit) {
          initTransport();
     }

     CHAR *theTag=NULL;
     INT queueSize=filterqueue->size();

     for (INT i=queueSize-1 ; i >= 0 ; i--) {
          theTag=(CHAR *)filterqueue->at(i);
          if (tagBuf[0] == '\0') {
               stlcpy(tagBuf,"Supported Tags: ",MAXALLTAGS);
               stlcat(tagBuf,theTag,MAXALLTAGS);
          }
          else {
               stlcat(tagBuf," ",MAXALLTAGS);
               stlcat(tagBuf,theTag,MAXALLTAGS);
          }
     }
     ASSERT(pAHUser != NULL);
     pAHUser->AddLiteMsg(Stp4Html(tagBuf));
}

VOID
CLiteAHTrans::RecvText(            // Overridden transport text handler
CTlcUser* pUserFrom,
CTlcUser* pUserTo,
const CHAR* pMsg,
SHORT fType,
SHORT iMsgNum,
const CHAR* ptr1,
const CHAR* ptr2,
const CHAR* ptr3)
{
     CTlcAHUser* pAHUser;
     CTlcUser* pOthUser;
     GBOOL clrpr=FALSE;
     INT msg;

     if (gTransNeedsInit) {
          initTransport();
          gTransNeedsInit=FALSE;
     }

     ASSERT(pUserTo != NULL);
     if (!(pUserTo->m_fFlags&USR_INCHAN)
      && !((pUserTo->m_fFlags&USR_CHATTING)
      && (fType == RECV_TYPE_CHATMSG))) {
          return;
     }
     if (fType == RECV_TYPE_CHATMSG
      && (!(pUserTo->m_fFlags&USR_CHATTING)
        || !sameas(pUserTo->GetChatUser(),pUserFrom->GetName()))) {
          return;
     }
     if (pUserFrom != NULL) {
          if (pUserTo->CheckForget(pUserFrom)) {
               return;
          }
          if (fType == RECV_TYPE_ACTION
           && (pUserTo->m_fFlags&USR_NOACTIONS
              || pUserTo->CheckIgnore(pUserFrom)
              || (tmpAList != NULL
                && !pUserTo->CheckAccess(tmpAList->GetConfigPtr()->seekey)))) {
              return;
          }
     }
     if (pUserFrom == NULL && NeedFromUser(fType,iMsgNum)) {
          return;
     }

     switch (fType) {
     case RECV_TYPE_WHISPER:
          ASSERT(pUserFrom != NULL);
          prfmsg(WHSTO3
                ,colors[SEXIDX(pUserFrom->GetSex())],pUserFrom->GetName()
                ,pMsg);
          clrpr=TRUE;
          break;
     case RECV_TYPE_WHISPERFR:
          ASSERT(ptr1 != NULL);
          ASSERT(pUserFrom != NULL);
          pOthUser=sameas(ptr1,pUserTo->GetName()) ? pUserTo
                                                   : tlcAPI->usrGetByName(ptr1);
          ASSERT(pOthUser != NULL);
          prfmsg(WHSFRM3
                ,colors[SEXIDX(pUserFrom->GetSex())],pUserFrom->GetName()
                ,colors[SEXIDX(pOthUser->GetSex())],ptr1
                ,pMsg);
          clrpr=TRUE;
          break;
     case RECV_TYPE_INTRO:
          prfmsg(iMsgNum);
          clrpr=TRUE;
          break;
     case RECV_TYPE_EXIT:
          if (pMsg != NULL && *pMsg != '\0') {
               prfmsg(EXISKL2,pMsg);
          }
          else {
               ASSERT(pUserFrom != NULL);
               switch (iMsgNum) {
               case EXMSG_EXT_LEFTC:
                    msg=LEFTCH3;
                    prfmsg(msg
                     ,colors[SEXIDX(pUserFrom->GetSex())]
                     ,pUserFrom->GetName());
                    break;
               case EXMSG_EXT_HUP:
                    msg=TLCHUP2;
                    prfmsg(msg,pUserFrom->GetName());
                    break;
               case EXMSG_EXT_KICK:
                    msg=KICKDO2;
                    prfmsg(msg,pUserFrom->GetName());
                    break;
               case EXMSG_EXT_LEAVE:
               default:
                    msg=LVITLC3;
                    prfmsg(msg
                     ,colors[SEXIDX(pUserFrom->GetSex())]
                     ,pUserFrom->GetName());
                    break;
               }
          }
          clrpr=TRUE;
          pUserTo->m_fFlags|=USR_CHANCHANGE;
          break;
     case RECV_TYPE_ENTRANCE:
          if (pMsg != NULL && *pMsg != '\0') {
               prfmsg(EXISKL2,pMsg);
          }
          else {
               ASSERT(pUserFrom != NULL);
               msg=(iMsgNum == ENMSG_ENT_TELE ? ENTTLC3 : CAMEIN3);
               prfmsg(msg
                     ,colors[SEXIDX(pUserFrom->GetSex())]
                     ,pUserFrom->GetName());
          }
          clrpr=TRUE;
          pUserTo->m_fFlags|=USR_CHANCHANGE;
          break;
     case RECV_TYPE_USERLIST:
          break;
     case RECV_TYPE_WELCOME:
          prfmsg(iMsgNum,pMsg);
          clrpr=TRUE;
          break;
     case RECV_TYPE_DIRECTED:
          ASSERT(ptr1 != NULL);
          ASSERT(pUserFrom != NULL);
          pOthUser=sameas(ptr1,pUserTo->GetName()) ? pUserTo
                                                   : tlcAPI->usrGetByName(ptr1);
          ASSERT(pOthUser != NULL);
          prfmsg(DIRTO3
                ,colors[SEXIDX(pUserFrom->GetSex())],pUserFrom->GetName()
                ,colors[SEXIDX(pOthUser->GetSex())]
                ,sameas(ptr1,pUserFrom->GetName()) ? "you" : ptr1
                ,pMsg);
          clrpr=TRUE;
          break;
     case RECV_TYPE_NEWTOPIC:
          ASSERT(pUserFrom != NULL);
          prfmsg(NOWTHE2,pUserFrom->GetName(),pMsg);
          clrpr=TRUE;
          break;
     case RECV_TYPE_ENTEREDEDIT:
          ASSERT(pUserFrom != NULL);
          prfmsg(ENTEDT2,pUserFrom->GetName());
          clrpr=TRUE;
          break;
      case RECV_TYPE_RETEDIT:
          ASSERT(pUserFrom != NULL);
          prfmsg(RETEDT,pUserFrom->GetName());
          clrpr=TRUE;
          break;
     case RECV_TYPE_SWITCHCHAN:
          switch (iMsgNum) {
          case SCMSG_CHAN_DELETE:
               msg=CHNDELD2;
               break;
          case SCMSG_USER_LOGOFF:
               msg=HKICKO3;
               break;
          case SCMSG_CHAN_FORUPD:
               msg=FORCUPD;
               break;
          default:
               msg=iMsgNum;
               break;
          }
          prfmsg(msg,ptr1);
          clrpr=TRUE;
          pUserTo->m_fFlags|=USR_CHANCHANGE;
          break;
     case RECV_TYPE_ACTION:
          actPrfFrame(iMsgNum,pMsg,ptr1);
          clrpr=TRUE;
          break;
     case RECV_TYPE_CHATMSG:
          prfmsg(OTHCHAT3,pMsg);
          clrpr=TRUE;
          break;
     case RECV_TYPE_DBTOGGLE:
          break;
     case RECV_TYPE_USERENTER:
     case RECV_TYPE_USEREXIT:
          pUserTo->m_fFlags|=USR_CHANCHANGE;
          return;
     case RECV_TYPE_PAGE:
          clrpr=TRUE;
          break;
     case RECV_TYPE_PRFBUF:
          clrpr=FALSE;
          break;
     case RECV_TYPE_ENTCHAT:
          if (pUserTo->m_fFlags&USR_CHATTING) {
               return;
          }
          prfmsg(GONCHA,pUserFrom->GetName());
          clrpr=TRUE;
          break;
     case RECV_TYPE_RETCHAT:
          if (pUserTo->m_fFlags&USR_CHATTING) {
               return;
          }
          prfmsg(RETCHAT,pUserFrom->GetName());
          clrpr=TRUE;
          break;
     case RECV_TYPE_RETCHATUSER:
          prfmsg(iMsgNum);
          pUserFrom=NULL;
          clrpr=TRUE;
          break;
     case RECV_TYPE_PUBLIC:
          ASSERT(pUserFrom != NULL);
          if (iMsgNum == 0) {
               iMsgNum=TLCFRM3;
               prfmsg(iMsgNum
                ,colors[SEXIDX(pUserFrom->GetSex())]
                ,pUserFrom->GetName(), pMsg);
          }
          else {
               prfmsg(iMsgNum,pUserFrom->GetName(),pMsg,ptr1,ptr2,ptr3);
          }
          clrpr=TRUE;
          break;
     case RECV_TYPE_LISTCHG:
          return;
#if defined(DEBUG)
     default:
          shocst("TLC DEBUGAH","Unhandled receive type: %d",fType);
          return;
#endif // DEBUG
     }
     //pAHUser=dynamic_cast<CTlcAHUser*>(pUserTo);
     pAHUser=(CTlcAHUser *)(pUserTo);
     ASSERT(pAHUser->GetTransport() == this);
     CHAR *theMsg;
     if (pAHUser->m_fFlags&USR_ENCODETAGS
       || (pUserFrom == NULL || pUserFrom->GetTransport() != this)) {
           theMsg=encodeTags(skpwht(prfbuf),TRUE);
     }
     else {
           theMsg=encodeTags(skpwht(prfbuf),FALSE);
     }
     const CHAR *msg2add=(const CHAR *)handleURLs(belStrip(theMsg));
     msg2add=encodeSpaces((CHAR *)msg2add);
     if (gEmulateTerm) {
           msg2add=ANSI2HTML((CHAR *)msg2add);
     }
     pAHUser->AddLiteMsg(msg2add);
     clearStoreBuf();
     if (clrpr) {
           clrprf();
     }
}

VOID
CLiteAHTrans::Output(              // overriden transport output method
CTlcUser* pUser)
{
     if (!(pUser->m_fFlags&USR_INCHAN)) {
          return;
     }
     if (gEmulateTerm) {
          //(dynamic_cast<CTlcAHUser*>(pUser))->AddLiteMsg(ANSI2HTML(belStrip(prfbuf)));
          ((CTlcAHUser*)(pUser))->AddLiteMsg(ANSI2HTML(belStrip(prfbuf)));
     }
     else {
          //(dynamic_cast<CTlcAHUser*>(pUser))->AddLiteMsg(belStrip(prfbuf));
          ((CTlcAHUser*)(pUser))->AddLiteMsg(belStrip(prfbuf));
     }
     clearStoreBuf();
     clrprf();
}

VOID
CLiteAHTrans::clearStoreBuf()      // delete m_storeBuf ( member variable )
{
     if(m_storeBuf != NULL) {
          delete [] m_storeBuf;
     }
     m_storeBuf=NULL;
}

CHAR *
CLiteAHTrans::handleURLs(          // return string with formatted URLs
CHAR *stg)                         // the string to analyze
{
     static CHAR myUrlBuf[URISIZ];
     setmem(myUrlBuf,URISIZ,0);
     stlcpy(myUrlBuf,Str2Url(stg,"\" TARGET = \"TeleURL\">"),URISIZ);
     return(myUrlBuf);
}

GBOOL
CLiteAHTrans::allowedTag(          // check to see if the string starts with a valid tag
char *checkStr)                    // the string in question
{
     CHAR *theTag=NULL;
     INT queueSize=filterqueue->size();

     for (INT i=0 ; i < queueSize ; i++) {
          theTag=(CHAR *)filterqueue->at(i);

          if (sameto(theTag,checkStr)) {
               return(TRUE);
          }
     }
     return(FALSE);
}

CHAR *
CLiteAHTrans::removeFilterTags(    // remove valid tags ( for other transports )
CHAR *tagStr)                      // the string to operate on
{
     static String theString;
     GBOOL inTag=FALSE;

     theString="";
     ASSERT(tagStr != NULL);
     while (*tagStr != '\0') {
          if (*tagStr == '<') {
               if (allowedTag(tagStr)) {
                    inTag=TRUE;
               }
          }
          if (!inTag) {
               theString+=*tagStr;
          }
          if (*tagStr == '>') {
               inTag=FALSE;
          }
          tagStr++;
     }
     return((CHAR *)theString.c_str());
}

CHAR *                             // String w/ encoded spaces
CLiteAHTrans::encodeSpaces(        // HTML-encode spaces
CHAR *tagStr)                      // the string to operate on
{
     static String theString;
     GBOOL modded=FALSE;
     GBOOL inTag=FALSE;

     theString="";
     while (*tagStr !='\0') {
          if(*tagStr == '<') {
               inTag=TRUE;
          }
          else if(*tagStr == '>') {
               inTag=FALSE;
          }
          else if(*tagStr == ' ' && *(tagStr+1) == ' ' && !inTag) {
               theString+="&nbsp;";
               modded=TRUE;
          }
          if (!modded) {
               theString+=*tagStr;
          }
          tagStr++;
          modded=FALSE;
     }
     return((CHAR *)theString.c_str());
}

CHAR *
CLiteAHTrans::encodeTags(          // HTML-encode tags as appropriate
CHAR *tagStr,                      // the string to operate on
GBOOL encodeAll)                   // TRUE=encode all tags
{
     static String theString;
     GBOOL isAllowed=FALSE;
     GBOOL modded=FALSE;

     theString="";
     if(!gTagsAllowed) {
          encodeAll=TRUE;
     }

     while (*tagStr !='\0') {
          if (*tagStr == '<') {
               isAllowed=FALSE;
               if (encodeAll || !allowedTag(tagStr)) {
                   theString+="&lt;";
                   modded=TRUE;
               }
               else {
                    isAllowed=TRUE;
               }
          }
          if (*tagStr == '>' && (encodeAll || !isAllowed)) {
               theString+="&gt;";
               modded=TRUE;
          }
          if (!modded) {
               theString+=*tagStr;
          }
          tagStr++;
          modded=FALSE;
     }
     return((CHAR *)theString.c_str());
}

const CHAR *                       // doctored string
CLiteAHTrans::Color2ANSI(          // convert <color> tags to ANSI
CHAR *str)                         // the string to operate on
{
     static CHAR storeBuf[MAXTELEINPSIZ]; // max size of input
     ansiqueue=new ANSIQUE;
     CHAR *moveptr=str;

     CHAR *endcptr;

     do {
          if (*moveptr == '<') {
               SHORT sMatch=-1;
               for (INT idx=0; idx <= 14; idx+=2 ) {
                    if (sameto(color2ansarr[idx],moveptr)) {
                         sMatch=idx+1;
                         endcptr=(moveptr+strlen(color2ansarr[sMatch-1]))-1;
                         ansiqueue->push_back(new CStringPositions(moveptr-str,
                                                                   endcptr-str,
                                                                   sMatch));
                         break;
                    }
               }
          }
          moveptr++;
     } while (*moveptr != '\0');

     INT numSequences=ansiqueue->size();
     INT storeSize=strlen(str)+1;

     setmem(storeBuf,MAXTELEINPSIZ,0);
     CStringPositions *curcspos=NULL, *pvcspos=NULL;
     INT lastpos=0;

     for ( INT i=0 ; i < numSequences ; i++ ) {
          curcspos=(CStringPositions *)ansiqueue->at(i);
          if (i > 0) {
               pvcspos=(CStringPositions *)ansiqueue->at(i-1);
               lastpos=pvcspos->getEnd()+1;
               ASSERT(lastpos <= strlen(str));
          }

          INT begpos=curcspos->getBegin();
          CHAR savChar=*(str+begpos);
          *(str+begpos)='\0';
          stlcat(storeBuf,str+lastpos,MAXTELEINPSIZ);
          stlcat(storeBuf,color2ansarr[curcspos->getIdx()],MAXTELEINPSIZ);
          *(str+begpos)=savChar;
     }
     if (strlen(storeBuf) == 0) {  // found no sequences
          stlcpy(storeBuf,str,MAXTELEINPSIZ);
     }
     else if (curcspos != NULL && curcspos->getEnd()+1 <= strlen(str)) {
                                   // tack on last piece
          stlcat(storeBuf,str+curcspos->getEnd()+1,MAXTELEINPSIZ);
     }
     delAnsQueue();
     return(storeBuf);
}

const CHAR *                       // doctored string
CLiteAHTrans::ANSI2HTML(           // convert ANSI sequences to HTML <font></font>
CHAR *ansiStr)                     // the string to operate on
{
     CHAR *moveptr=ansiStr;

     ansiqueue=new ANSIQUE;

     do {
          if (*moveptr == '\x1B' && *(moveptr+1) == '[') { // ESC character

               CHAR *savbptr=moveptr;

               while (*moveptr != '\0') {
                    if (*moveptr == 'm') {
                         ansiqueue->push_back(
                           new CStringPositions(savbptr-ansiStr,
                                                moveptr-ansiStr));
                         break;
                    }
                    moveptr++;
               }
          }
          else if (*moveptr == '\x0A' || *moveptr == '\x0D') {  // new line need to continue same color
               ansiqueue->push_back(new CStringPositions(moveptr-ansiStr,
                                                         moveptr-ansiStr));
          }
          moveptr++;
     } while (*moveptr != '\0');

     INT numSequences=ansiqueue->size();
     INT prfsize=strlen(ansiStr);
     INT storeBufSiz=-1;
     GBOOL underlineOn=FALSE;

     m_storeBuf=new CHAR[(storeBufSiz=prfsize+((numSequences+1)*72))];

     setmem(m_storeBuf,storeBufSiz,0);

     CStringPositions *current=NULL, *next=NULL;
     INT ncnt=0;
     INT lastColorIdx=LASTCOLOR2CHECK;

     for (INT i=0; i < numSequences; i++) {

          current=(CStringPositions *)ansiqueue->at(i);
          if (i < numSequences-1 ) {
               next=(CStringPositions *)ansiqueue->at(i+1);
          }
          else {
               next=NULL;
          }

          INT curBeg;
          if ((curBeg=current->getBegin()) == current->getEnd()  // we have a new line
            && i != (numSequences-1)) {
               stlcat(m_storeBuf,"\n",storeBufSiz);
               stlcat(m_storeBuf,ansiarr[lastColorIdx],storeBufSiz);

               CHAR rplChar;
               if (next != NULL) {
                    INT nextBeg=next->getBegin();
                    CHAR *cptr=ansiStr+curBeg+1;
                    CHAR *nptr=ansiStr+nextBeg;
                    if (cptr < nptr) {
                         rplChar=*nptr;
                         *nptr='\0';
                         stlcat(m_storeBuf,cptr,storeBufSiz);
                         *nptr=rplChar;
                    }
               }
               stlcat(m_storeBuf,fontTermTagBold,storeBufSiz);
               continue;
          }

          CHAR *curPosPtr=ansiStr+current->getBegin();
          INT foundPos;

          for (INT j=0; j < ANSARRSIZ; j+=2) {
               if ((foundPos=findstg(ansiarr[j],curPosPtr)) != 0) {
                 if (foundPos <= (current->getEnd()-current->getBegin())+1) {
                   if (j == NORMALATTON1) {
                        underlineOn=FALSE;
                   }
                   else if (j == UNDERLINEATTON1) {
                        underlineOn=TRUE;
                   }
                   else {
                        if (j == NORMALATTON2) {
                             underlineOn=FALSE;
                        }
                        else if (j == UNDERLINEATTON2) {
                             underlineOn=TRUE;
                        }
                        if (underlineOn) {
                             stlcat(m_storeBuf," <u>",storeBufSiz);
                        }
                        CHAR *tempStgPtr=NULL;
                        CHAR rplchar;
                        INT tempStgBegPos=current->getEnd()+1;

                        ASSERT(tempStgBegPos <= strlen(ansiStr));

                        INT tempStgEndPos=0;
                        if (next != NULL) {
                             tempStgEndPos=next->getBegin();
                        }
                        else {
                             tempStgEndPos=strlen(ansiStr);
                        }
                        tempStgPtr=ansiStr+tempStgBegPos;
                        rplchar=*(ansiStr+tempStgEndPos);
                        *(ansiStr+tempStgEndPos)='\0'; // need to replace this char
                        stlcat(m_storeBuf,ansiarr[j+1],storeBufSiz);
                        stlcat(m_storeBuf,tempStgPtr,storeBufSiz);
                        stlcat(m_storeBuf,fontTermTagBold,storeBufSiz);
                        *(ansiStr+tempStgEndPos)=rplchar;
                        if (underlineOn) {
                             stlcat(m_storeBuf," </u>",storeBufSiz);
                        }
                        lastColorIdx=j+1;
                        break;
                   }
                 }
               }
          }
     }

     delAnsQueue();
     if (m_storeBuf[0] == '\0' || m_storeBuf[0] != '<') {
          setmem(m_storeBuf,sizeof(m_storeBuf),0);
          stlcpy(m_storeBuf,"<b><font color=white>",storeBufSiz);
          stlcat(m_storeBuf,ansiStr,storeBufSiz);
          stlcat(m_storeBuf,fontTermTagBold,storeBufSiz);
     }
     return(m_storeBuf);
}

VOID
CLiteAHTrans::delAnsQueue()        // free up alloced memory in ansiqueue
{
     ASSERT(ansiqueue != NULL);
     while (!ansiqueue->empty()) {
          delete ansiqueue->back();
          ansiqueue->pop_back();
     }
     delete ansiqueue;
}

CHAR *
CLiteAHTrans::belStrip(            // convert bel characters to spaces
CHAR *str)
{
     strrpl(str,'\x07',' ');
     return(str);
}

VOID
CLiteAHTrans::CmdResult(     // Send output based on a command
CTlcUser* pUser,                   //   user to send to
SHORT iOperation,                  //   operation performed
GBOOL bSuccess,                    //   successful?
SHORT iReason)                     //   reason for success/failure
{
     CTlcChannel* pChannel;
     INT savusn=usrnum;

     switch (iOperation) {
     case CMD_CHAT:
          curusr(pUser->GetUsrnum());
          switch (iReason) {
          case CMD_CHAT_BEGIN:
          case CMD_CHAT_ACCEPTED:
               pChannel=tlcAPI->chanGetByName(pUser->GetChannelName());
               ASSERT(pChannel != NULL);
               CTlcTransport::CmdResult(pUser,iOperation,bSuccess,iReason);
               pUser->m_fFlags&=~USR_INCHAN;
               pUser->m_fFlags|=USR_CHATTING;
               pChannel->PublicSendBut(pUser->GetName(),NULL,NULL
                                      ,RECV_TYPE_ENTCHAT,NULL,NULL,NULL
                                      ,/*pUser->GetChatUser()*/ NULL);

               break;
          case CMD_CHAT_HANGUP:
          case CMD_CHAT_STOPCHATTING:
               curChannel->PublicSendBut(pUser->GetName(),NULL,NULL
                                        ,RECV_TYPE_RETCHAT,NULL,NULL,NULL
                                        ,pUser->GetName());
               pUser->m_fFlags|=USR_INCHAN;
               pUser->m_fFlags&=~USR_CHATTING;
               break;
          default:
               CTlcTransport::CmdResult(pUser,iOperation,bSuccess,iReason);
               break;
          }
          curusr(savusn);
          break;
     default:
          CTlcTransport::CmdResult(pUser,iOperation,bSuccess,iReason);
          break;
     }
}


////////////////////////////////////////////////////////////////////////////
//
//  CStringPosition definition
//
//  Used with ANSI <--> HTML tag conversion.
//
////////////////////////////////////////////////////////////////////////////


CStringPositions::CStringPositions(
INT beg,
INT end)
{
     m_begPos=beg;
     m_endPos=end;
}

CStringPositions::CStringPositions(
INT beg,
INT end,
INT idx)
{
     m_begPos=beg;
     m_endPos=end;
     m_idx=idx;
}

CStringPositions::~CStringPositions()
{
}

CStringPositions::getIdx()         // return value marker
{
     return(m_idx);
}

CStringPositions::getBegin()       // return beginning position of a sub-string
{
     return(m_begPos);
}

CStringPositions::getEnd()         // return end position of a sub-string
{
     return(m_endPos);
}
