/***************************************************************************
 *                                                                         *
 *   TLCTMTRA.CPP                                                          *
 *                                                                         *
 *   Copyright (c) 1998 Galacticomm, Inc.         All Rights Reserved.     *
 *                                                                         *
 *   Teleconference terminal-mode transport.                               *
 *                                                                         *
 *                                            - J. Alvrus   02/24/1998     *
 *                                                                         *
 ***************************************************************************/

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

#define FILREV "$Revision: 16 $"

/* function definitions start here */

MARKSOURCE(tlctmtra)

CTerminalTransport::CTerminalTransport() : // default constructor
     CTlcTransport()
{
     m_fFlags|=(TRANS_IMPLCHAT|TRANS_IMPLPRIV);
}

VOID
CTerminalTransport::RecvText(      // Send text to one user by ID
CTlcUser* pUserFrom,               //   user object sending text (NULL = system)
CTlcUser* pUserTo,                 //   user object receiving text
const CHAR* pMsg,                  //   Text to send
SHORT fType,                       //   Type of text
SHORT iMsgNum,                     //   Type of event
const CHAR* ptr1,                  //   extra information
const CHAR* ptr2,                  //   extra information
const CHAR* ptr3)                  //   extra information
{
     ASSERT(pUserTo != NULL);
     // recipient is in an editor
     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) {
          // a user-from context is required
          if (NeedFromUser(fType,iMsgNum)) {
               return;
          }
     }
     else {
          // recipient has forgotten sender
          if (pUserTo->CheckForget(pUserFrom)) {
               return;
          }
          // recipient has actions off, has ignored sender,
          // or doesn't have access to see this action
          if (fType == RECV_TYPE_ACTION
           && ((pUserTo->m_fFlags&USR_NOACTIONS)
            || pUserTo->CheckIgnore(pUserFrom)
            || (tmpAList != NULL
             && !pUserTo->CheckAccess(tmpAList->GetConfigPtr()->seekey)))) {
               return;
          }
     }
     RecvTextLowLevel(pUserFrom,pUserTo,pMsg,fType,iMsgNum
                     ,ptr1,ptr2,ptr3);
}

VOID
CTerminalTransport::RecvTextLowLevel( // Send text to one user by usrnum
CTlcUser* pUserFrom,               //   user object sending text (NULL = system)
CTlcUser* pUserTo,                 //   user object receiving text
const CHAR* pMsg,                  //   Text to send
SHORT fType,                       //   Type of text
SHORT iMsgNum,                     //   MSG file template to use
const CHAR* ptr1,                  //   extra information for MSG template
const CHAR* ptr2,                  //   extra information for MSG template
const CHAR* ptr3)                  //   extra information for MSG template
{
     INT msg;
     CTlcUser* pUserTemp;

     INT savnum=usrnum;
     INT unum=pUserTo->GetUsrnum();
     ASSERT(0 <= unum && unum < nterms);
     curusr(unum);

     const CHAR* pszUseridFrom=(pUserFrom == NULL ? SYSUID
                                                  : pUserFrom->GetName());
     bool SameUser=sameas(pszUseridFrom,pUserTo->GetName());

     switch (fType) {
     case RECV_TYPE_INTRO:
          prfmsg(iMsgNum);
          break;
     case RECV_TYPE_EXIT:
          if (!NULSTR(pMsg)) {
               prfmsg(EXISKL2,pMsg);
          }
          else {
               switch (iMsgNum) {
               case EXMSG_EXT_LEFTC:
                    prfmsg(LEFTCH3,colors[SEXIDX(pUserFrom->GetSex())]
                          ,pszUseridFrom);
                    break;
               case EXMSG_EXT_HUP:
                    prfmsg(TLCHUP2,pszUseridFrom);
                    break;
               case EXMSG_EXT_KICK:
                    prfmsg(KICKDO2,pszUseridFrom);
                    break;
               case EXMSG_EXT_LEAVE:
               default:
                    prfmsg(LVITLC3,colors[SEXIDX(pUserFrom->GetSex())]
                          ,pszUseridFrom);
                    break;
               }
          }
          break;
     case RECV_TYPE_ENTRANCE:
          if (!NULSTR(pMsg)) {
               prfmsg(EXISKL2,pMsg);
          }
          else {
               msg=(iMsgNum == ENMSG_ENT_TELE ? ENTTLC3 : CAMEIN3);
               prfmsg(msg,colors[SEXIDX(pUserFrom->GetSex())],pszUseridFrom);
          }
          break;
     case RECV_TYPE_WELCOME:
          prfmsg(iMsgNum,pMsg);
          break;
     case RECV_TYPE_NEWTOPIC:
          prfmsg(NOWTHE2,pszUseridFrom,pMsg);
          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;
          }
          prfmsg(msg,ptr1);
          break;
     case RECV_TYPE_ENTEREDEDIT:
          prfmsg(ENTEDT2,pszUseridFrom);
          break;
     case RECV_TYPE_RETEDIT:
          prfmsg(RETEDT,pszUseridFrom);
          break;
     case RECV_TYPE_ACTION:
          actPrfFrame(iMsgNum,pMsg,ptr1);
          break;
     case RECV_TYPE_PRFBUF:
     case RECV_TYPE_USERLIST:
     case RECV_TYPE_PAGE:
          break;
     case RECV_TYPE_USERENTER:     // not implemented in terminal mode
     case RECV_TYPE_USEREXIT:
          curusr(savnum);
          return;
     case RECV_TYPE_WHISPER:
          prfmsg(WHSTO3,colors[SEXIDX(pUserFrom->GetSex())]
                ,pszUseridFrom,pMsg);
          break;
     case RECV_TYPE_WHISPERFR:
          if (SameUser && !tmEcho) {
               prfmsg(WHSSNT2);
          }
          else {
               // in this case, the to user and from user are the same,
               // because this is an echo-back; the user to whom the
               // whisper was actually sent is ptr1
               ASSERT(ptr1 != NULL);
               pUserTemp=sameas(ptr1,usaptr->userid) ? pUserTo
                                                     : tlcAPI->usrGetByName(ptr1);
               prfmsg(WHSFRM3
                     ,colors[SEXIDX(pUserFrom->GetSex())],pszUseridFrom
                     ,colors[SEXIDX(pUserTemp->GetSex())],ptr1,pMsg);
          }
          break;
     case RECV_TYPE_DIRECTED:
          if (SameUser && !tmEcho) {
               prfmsg(MSGSNT);
          }
          else {
               // in this case, the same message is sent to everyone; the
               // user to whom the text is directed is ptr1
               ASSERT(ptr1 != NULL);
               pUserTemp=sameas(ptr1, usaptr->userid) ? pUserTo
                                                      : tlcAPI->usrGetByName(ptr1);
               prfmsg(DIRTO3,colors[SEXIDX(pUserFrom->GetSex())],pszUseridFrom
                     ,colors[SEXIDX(pUserTemp->GetSex())]
                     ,sameas(ptr1,usaptr->userid) ? "you" : ptr1,pMsg);
          }
          break;
     case RECV_TYPE_ENTCHAT:
          prfmsg(GONCHA,pszUseridFrom);
          break;
     case RECV_TYPE_RETCHATUSER:
          prfmsg(iMsgNum);
          break;
     case RECV_TYPE_RETCHAT:
          prfmsg(RETCHAT,pszUseridFrom);
          break;
     case RECV_TYPE_CHATMSG:
          prfmsg(OTHCHAT3,pMsg);
          break;
     case RECV_TYPE_PUBLIC:
          if (SameUser && !tmEcho) {
               prfmsg(MSGSNT);
          }
          else if (iMsgNum == 0) {
               prfmsg(TLCFRM3,colors[SEXIDX(pUserFrom->GetSex())]
                     ,pszUseridFrom,pMsg);
          }
          else {
               prfmsg(iMsgNum,pszUseridFrom,pMsg,ptr1,ptr2,ptr3);
          }
          break;
     case RECV_TYPE_LISTCHG:
          curusr(savnum);
          return;
#if defined(DEBUG)
     default:
          shocst("TLC DEBUG","Unhandled receive type: %d",fType);
          return;
#endif // DEBUG
     }
     Output(pUserTo);
     curusr(savnum);
}

VOID
CTerminalTransport::SendTabbedDbData( // send drawing board data
const CHAR*,                       //   drawing board data
CTlcChannel*)                      //   channel
{
     // not implemented in terminal mode
}

VOID
CTerminalTransport::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
{
     CTlcUser* pOthUser;
     CTlcChannel* pChannel;
     INT savusn=usrnum;

     switch (iOperation) {
     case CMD_EDIT:
          ASSERT(pUser->GetUsrnum() == usrnum);
          switch (iReason) {
          case CMD_EDIT_ENTER:
               tmExitChannel(pUser);
               pUser->m_fFlags|=USR_INEDIT;
               prfmsg(EDTHDR);
               DisplayEditMenu(pUser);
               prfmsg(usrptr->substt=EDTMNUP);
               outprf(usrnum);
               break;
          }
          break;
     case CMD_MENU:
          ASSERT(pUser->GetUsrnum() == usrnum);
          if (bSuccess) {
               tmExitChannel(pUser);
               pUser->m_fFlags|=USR_INMENU;
               ASSERT(tlcsysedt.m_usrnum < 0);
               tlcsysedt.m_usrnum=usrnum;
               tmInSysopMenu=false;
               prfmsg(SYSHDR);
               prfmsg(usrptr->substt=SYSEDT3);
               outprf(usrnum);
          }
          else {
               prfmsg(EDBUSY);
               Output(pUser);
          }
          break;
     case CMD_CHANNEL:
          ASSERT(pUser->GetUsrnum() == usrnum);
          if (bSuccess) {
               ASSERT(cedctrl.user < 0);
               switch (iReason) {
               case CMD_CHANNEL_ENTER_SYS:
                    tmExitChannel(pUser);
                    cedctrl.user=usrnum;
                    cedctrl.sysop=true;
                    prfmsg(CEDENT);
                    prfmsg(CEDHDR2);
                    prfmsg(usrptr->substt=CEDHDRP3);
                    outprf(usrnum);
                    break;
               case CMD_CHANNEL_ENTER_MOD:
                    tmExitChannel(pUser);
                    cedctrl.user=usrnum;
                    cedctrl.sysop=false;
                    usrptr->substt=CEDEDP2;
                    stlcpy(cedctrl.channel,pUser->GetChannelName(),CHAN_MAX_SIZE);
                    ASSERT(tlcAPI->chanGetByName(cedctrl.channel) != NULL);
                    memcpy(&cedtemp
                          ,tlcAPI->chanGetByName(cedctrl.channel)->GetConfig()
                          ,sizeof(CHANINFO));
                    cedEnter(false);
                    outprf(usrnum);
                    break;
               }
          }
          else {
               prfmsg(CEDBUSY2);
               Output(pUser);
          }
          break;
     case CMD_ACTION:
          switch (iReason) {
          case CMD_ACTION_EDITOR:
               ASSERT(pUser->GetUsrnum() == usrnum);
               if (bSuccess) {
                    ASSERT(aedctrl.user < 0);
                    tmExitChannel(pUser);
                    aedctrl.user=usrnum;
                    prfmsg(LEDENT);
                    prfmsg(LEDHDR2);
                    prfmsg(usrptr->substt=LEDHDRP2);
                    outprf(usrnum);
               }
               else {
                    prfmsg(LEDBUSY2);
                    Output(pUser);
               }
               break;
          default:
               CTlcTransport::CmdResult(pUser,iOperation,bSuccess,iReason);
               break;
          }
          break;
     case CMD_CHAT:
          curusr(pUser->GetUsrnum());
          switch (iReason) {
          case CMD_CHAT_BEGIN:
          case CMD_CHAT_ACCEPTED:

               pOthUser=tlcAPI->usrGetByName(pUser->GetChatUser());
               btucli(usrnum);
               aachat[usrnum].chatflags=(usrptr->flags&(NOGLOB|NOINJO));
               usrptr->flags|=(NOGLOB|NOINJO);
               if (pOthUser->GetTransport() == this) {
                    btumil(pUser->GetUsrnum(),0);
                    btuchi(pUser->GetUsrnum(),tlchat);
               }
               pChannel=tlcAPI->chanGetByName(pUser->GetChannelName());
               ASSERT(pChannel != NULL);
               CTlcTransport::CmdResult(pUser,iOperation,bSuccess,iReason);
               pUser->m_fFlags&=~USR_INCHAN;
               pChannel->PublicSendBut(pUser->GetName(),NULL,NULL
                                      ,RECV_TYPE_ENTCHAT,NULL,NULL,NULL
                                      ,/*pUser->GetChatUser()*/ NULL);

               break;
          case CMD_CHAT_HANGUP:
          case CMD_CHAT_STOPCHATTING:
               btuchi(usrnum,NULL);
               btucli(usrnum);
               usrptr->flags&=~(NOGLOB|NOINJO);
               usrptr->flags|=aachat[usrnum].chatflags;
               curChannel->PublicSendBut(pUser->GetName(),NULL,NULL
                                        ,RECV_TYPE_RETCHAT,NULL,NULL,NULL
                                        ,pUser->GetName());

               tmEnterChannel(pUser);
               break;
          default:
               CTlcTransport::CmdResult(pUser,iOperation,bSuccess,iReason);
               break;
          }
          curusr(savusn);
          break;
     default:
          CTlcTransport::CmdResult(pUser,iOperation,bSuccess,iReason);
          break;
     }
}

VOID
CTerminalTransport::Output(        // output whatever is in buffer
CTlcUser* pUser)                   //   user to output to
{
     ASSERT(pUser->GetUsrnum() == usrnum);
     outtele(usrnum);
     UNREFERENCED(pUser);
}

VOID
CTerminalTransport::OutputFinished() // a user is done generating output
{
     INT SaveLingo=clingo;
     clingo=0;
     setmbk(msgTlc);
     clrprf();
     prfmsg(TLCPMT);
     rstmbk();
     clingo=SaveLingo;
     for (INT iElem=0 ; iElem < FLAG_NUM(nterms) ; ++iElem) {
          INT elem=OutFlagArr[iElem];
          if (elem != 0) {
               for (INT iBit=0,mask=1 ; iBit < INT_BIT ; ++iBit,mask<<=1) {
                    if (elem&mask) {
                         OutFlagArr[iElem]&=~mask;
                         INT unum=(INT_BIT*iElem)+iBit;
                         CTlcUser* pUser=tlcAPI->usrGetByName(uacoff(unum)->userid);
                         if (pUser != NULL && pUser->GetTransport() == this
                          && (pUser->m_fFlags&USR_INCHAN)) {
                              PmtFlagArr[iElem]|=mask;
                              outprf(unum);
                         }
                    }
               }
          }
     }
     clrprf();
}
