/***************************************************************************
 *                                                                         *
 *   TLCFCHN.CPP                                                           *
 *                                                                         *
 *   Copyright (c) 1997-1998  Galacticomm, Inc.   All Rights Reserved      *
 *                                                                         *
 *   Teleconference Forum Channels                                         *
 *   Implementation                                                        *
 *                                               - Phil Henning 2/25/98    *
 *                                                                         *
 ***************************************************************************/

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

#define FILREV "$Revision: 6 $"

#define FCCACHE  10               // only good under dos, cached records

CSmb* forumChanSmb;

typedef struct tagFORUMCHAN {
     USHORT id;
     CHAR   channel[CHAN_MAX_SIZE];
} FORUMCHAN, *pFORUMCHAN;

SMBKEYTABLE smbForumChanKey[]={
     {offsetof(tagFORUMCHAN,id),smbCompareSHORT},
     {offsetof(tagFORUMCHAN,channel),smbCompareString},
     {0,NULL}
};

extern "C" {

VOID
forumPreWelcome(                   // send welcome message
LPUSRSTRUCT pUser);                //   user to send to

static GBOOL                       //   TRUE/FALSE
forumCanAccess(                    // can user speak in this channel
const CHAR* channel,               //   channel name
LPUSRSTRUCT pUser,                 //   user structure
INT access);                       //   access being requested

CHFUNCPTRS ForumChannel={
     NULL,                         // constructor
     NULL,                         // destructor
     NULL,                         // number visible func
     NULL,                         // add user
     NULL,                         // remove user
     forumPreWelcome,              // pre send welcome
     NULL,                         // post send welcome
     forumCanAccess,               // can access channel
};

static VOID
notifyForumNew(                    // forum has been created hook
const struct fordsk *newdsk,       //   new forum definition structure
const CHAR *desc,                  //   descriptive text
const CHAR *echoes);               //   pointer to array of echo addresses

static VOID
notifyForumUpdate(                 // forum has been updated hook
const struct fordef *newdef,       //   forum definition structure
const CHAR *desc,                  //   descriptive text
const CHAR *echoes);               //   pointer to array of echo addresses

static VOID
notifyForumDelete(                 // forum has been deleted hook
const struct fordsk *newdef,       //   forum definition structure
const CHAR *desc,                  //   descriptive text
const CHAR *echoes);               //   pointer to array of echo addresses

static VOID
joinFromForums(                    // join teleconference forum channel
USHORT id);                        //   forum id

};

static VOID
addForumChannel(                   // add new forum channel
USHORT id,                         //   forum id
const CHAR* name,                  //   forum name
const CHAR* topic,                 //   forum topic
SHORT rate);                       //   forum credit consumption rate

static VOID
deleteForumChannel(                // delete a forum channel
USHORT id);                        //   forum id

static LPCHANINFO                  //   pointer to tele channel info
GetChannelByForumID(               // get channel pointer by forum id
USHORT id);                        //   forum-id to get


static VOID
SetupForumChannel(                 // set the channel settings
LPCHANINFO pInfo,                  //   pointer to the channel information
const CHAR* topic,                 //   forum topic
SHORT rate);                       //   forum credit consumption rate

MARKSOURCE(tlcfchn);

VOID
initForumChannels()
{
     init__galme();

     forumChanSmb=new CSmb(sizeof(FORUMCHAN),smbForumChanKey,FCCACHE);
     hook_gme(GMEHOOK_NOT_NEWFOR,(voidfunc)notifyForumNew);
     hook_gme(GMEHOOK_NOT_UPDFOR,(voidfunc)notifyForumUpdate);
     hook_gme(GMEHOOK_NOT_DELFOR,(voidfunc)notifyForumDelete);
     for (INT idx=0; idx < numforums(); idx++) {
          const struct fordef* def=fiddefp(idx);
          addForumChannel(def->forum,def->name,def->topic,def->ccr);
     }
     tjoinrou=joinFromForums;
}

VOID
dwnForumChannels()
{
     delete forumChanSmb;
}

static VOID
notifyForumNew(                    // forum has been created hook
const struct fordsk *newdsk,       //   new forum definition structure
const CHAR *desc,                  //   descriptive text
const CHAR *echoes)                //   pointer to array of echo addresses
{
     addForumChannel(newdsk->forum,newdsk->name,newdsk->topic,newdsk->ccr);
     UNREFERENCED(desc);
     UNREFERENCED(echoes);
}

static VOID
notifyForumUpdate(                 // forum has been updated hook
const struct fordef *newdef,       //   forum definition structure
const CHAR *desc,                  //   descriptive text
const CHAR *echoes)                //   pointer to array of echo addresses
{
     LPCHANINFO pInfo=GetChannelByForumID(newdef->forum);

     if (pInfo == NULL) {
          return;
     }
     if (!sameas(pInfo->m_strName,newdef->name)) {
          // forum name was changed
          if (tlcChannelGetInfo(newdef->name) == NULL) {
               forumChanSmb->Delete();
               addForumChannel(newdef->forum,newdef->name,newdef->topic
                              ,newdef->ccr);
               tlcChannelMoveAllUsers(pInfo->m_strName,newdef->name
                                     ,CHAN_SWITCH_DELETED,SCMSG_CHAN_FORUPD);
               tlcChannelRemove(pInfo->m_strName);
          }
     }
     else {
          // only access level or topic was changed
          SetupForumChannel(pInfo,newdef->topic,newdef->ccr);
     }
     UNREFERENCED(desc);
     UNREFERENCED(echoes);
}

static VOID
notifyForumDelete(                 // forum has been deleted hook
const struct fordsk *newdsk,       //   forum definition structure
const CHAR *desc,                  //   descriptive text
const CHAR *echoes)                //   pointer to array of echo addresses
{
     deleteForumChannel(newdsk->forum);
     UNREFERENCED(desc);
     UNREFERENCED(echoes);
}

static VOID
addForumChannel(                   // add new forum channel
USHORT id,                         //   forum id
const CHAR* name,                  //   forum name
const CHAR* topic,                 //   forum topic
SHORT rate)                        //   forum credit consumption rate
{
     CHANINFO channel;
     LPCHANINFO pInfo;
     FORUMCHAN fc;

     memset(&channel,0,sizeof(CHANINFO));
     stlcpy(channel.m_strName,name,CHAN_MAX_SIZE);

     channel.m_flags|=CHAN_FLAG_NOLIST;
     channel.m_type|=(CHAN_TYPE_FORUM|CHAN_TYPE_NOEDIT);
     stlcpy(channel.m_actList1,tlcAPI->m_actListP,LISTSIZ);
     stlcpy(channel.m_actList2,tlcAPI->m_actListS,LISTSIZ);
     fc.id=id;
     stlcpy(fc.channel,channel.m_strName,CHAN_MAX_TOPIC_SIZE);
     forumChanSmb->Insert(&fc);
     if (tlcChannelCreateCustom(&channel,&ForumChannel) == CHAN_CREATE_OK) {
          pInfo=tlcChannelGetInfo(channel.m_strName);
          SetupForumChannel(pInfo,topic,rate);
     }
     else {
          forumChanSmb->Delete();
     }
}

static VOID
deleteForumChannel(                // delete a forum channel
USHORT id)                         //   forum id
{
     LPCHANINFO pInfo=GetChannelByForumID(id);
     if (pInfo != NULL) {
          tlcChannelMoveAllUsers(pInfo->m_strName,dftchan,CHAN_SWITCH_DELETED,SCMSG_CHAN_DELETE);
          tlcChannelRemove(pInfo->m_strName);
          forumChanSmb->Delete();
     }
}

static LPCHANINFO                  //   pointer to tele channel info
GetChannelByForumID(               // get channel pointer by forum id
USHORT id)                         //   forum id
{
     VOID* ptr=forumChanSmb->GetEqual(&id,0);
     if (ptr == NULL) {
          return(NULL);
     }
     return(tlcChannelGetInfo((static_cast<pFORUMCHAN>(ptr))->channel));
}

static VOID
SetupForumChannel(                 // set the channel settings
LPCHANINFO pInfo,                  //   pointer to the channel information
const CHAR* topic,                 //   forum topic
SHORT rate)                        //   forum credit consumption rate
{
     pInfo->m_iCrConsumptionRate=rate;
     stlcpy(pInfo->m_strTopic,topic,CHAN_MAX_TOPIC_SIZE);
}

static GBOOL                       //   TRUE/FALSE
forumCanAccess(                    // can user access channel
const CHAR* channel,               //   channel name
LPUSRSTRUCT pUser,                 //   user structure
INT access)                        //   access being requested
{
     VOID* ptr=forumChanSmb->GetEqual(channel,1);

     if (ptr == NULL) {
          return(FALSE);
     }

     USHORT forumID=(static_cast<pFORUMCHAN>(ptr))->id;

     switch (access) {
     case CHAN_AXS_SEE:
     case CHAN_AXS_JOIN:
          return(gforac(pUser->m_pszName,forumID) > NOAXES);
     case CHAN_AXS_SPEAK:
          return(gforac(pUser->m_pszName,forumID) >= WRAXES);
     default:
          return(FALSE);
     }
}

VOID
forumPreWelcome(                   // send welcome message
LPUSRSTRUCT pUser)                 //   user to send to
{
     tlcUserSendText(pUser->m_pszName,SYSUID,NULL,pUser->m_pszChannel,RECV_TYPE_WELCOME,SIGCHN2,0,0,0);
}


static VOID
joinFromForums(                    // join teleconference from forums
USHORT id)                         //   forum id
{
     VOID* ptr=forumChanSmb->GetEqual(&id,0);
     if (ptr != NULL) {
          LPCHANINFO pInfo=GetChannelByForumID(id);
          if (pInfo != NULL) {
               if (!(usrptr->flags&X2MAIN)) {
                   aachat[usrnum].flags|=RSTX2M;
                   usrptr->flags|=X2MAIN;
               }
               aachat[usrnum].retstt=usrptr->state;
               aachat[usrnum].retsub=usrptr->substt;
               aachat[usrnum].retrat=usrptr->crdrat;
               aachat[usrnum].flags|=XTOOTH;
               stlcpy(aachat[usrnum].lastchannel,pInfo->m_strName
                     ,CHAN_MAX_SIZE);
               usrptr->state=GetTeleState();
               usrptr->substt=0;
               tlcinp();
               return;
          }
     }
     setmbk(msgTlc);
     prfmsg(TOOHIF2);
     rstmbk();
     outprf(usrnum);
     clrprf();
     injacr();
}