Files
Client/Server/ManageTool/MonitoringTool/ChatServerEventHandler.cpp
LGram16 dd97ddec92 Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code:
- Client: Game client source (moved to Client/Client/)
- Server: Game server source
- GameTools: Development tools
- CryptoSource: Encryption utilities
- database: Database scripts
- Script: Game scripts
- rylCoder_16.02.2008_src: Legacy coder tools
- GMFont, Game: Additional resources

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 20:17:20 +09:00

486 lines
14 KiB
C++

#include "stdafx.h"
#include "MonitoringTool.h"
#include "MonitoringToolDlg.h"
#include "ChatServerEventHandler.h"
#include "MonitoringToolSetup.h"
#include "MonitoringToolLog.h"
#include "WhisperDlg.h"
#include "ChattingPage.h"
#include "LoginDlg.h"
#include "GlobalFunc.h"
#include <Log/ServerLog.h>
#include <Stream/Buffer/Buffer.h>
#include <Utility/Setup/ServerSetup.h>
#include <Network/Packet/WrapPacket.h>
#include <Network/Packet/ChatToolPacketCmd.h>
#include <Network/Packet/PacketStruct/CharCommunityPacket.h>
#include <mmsystem.h>
const char* szChatSection = _T("CHAT_SERVER_CONNECTION");
const unsigned int MAX_CHAT = CMonitoringToolSetup::GetInstance().GetInt(szChatSection, _T("CHAT_SERVER_NUM"));
ClientNet::CChatServerEventHandler::CChatServerEventHandler(unsigned int nServerGroup)
: m_nServerGroup(nServerGroup), m_dwLastPingRecvTime(0)
{
}
bool ClientNet::CChatServerEventHandler::Connect()
{
char szKey[MAX_PATH];
unsigned int nServerGroup;
const char* szIP;
CMonitoringToolSetup Setup = CMonitoringToolSetup::GetInstance();
for(unsigned int nIndex = 0; nIndex < MAX_CHAT; ++nIndex)
{
_snprintf(szKey, MAX_PATH, "CHAT_SERVER_IP_%02d", nIndex);
szIP = Setup.GetString(szChatSection, szKey);
_snprintf(szKey, MAX_PATH, "CHAT_SERVER_INDEX_%02d", nIndex);
nServerGroup = Setup.GetInt(szChatSection, szKey);
ClientNet::CClientEventHandlerMgr& eventHandlerMgr = theApp.GetEventHandlerMgr();
ClientNet::CChatServerEventHandler* lpEventHandler = new ClientNet::CChatServerEventHandler(nServerGroup);
if (!eventHandlerMgr.Connect(
INET_Addr(szIP, CServerSetup::ChatServerMonitoringToolListen), lpEventHandler))
{
delete lpEventHandler;
return false;
}
}
return true;
}
int ClientNet::CChatServerEventHandler::OnOpen(int iErrorCode)
{
if(0 == iErrorCode)
{
theApp.RegisterChatHandler(m_nServerGroup, this);
INET_Addr& addr = GetPeerAddress();
INFLOG3(g_Log, _T("Connect Session (ChatServer) : DP:0x%p, %s:%d"),
this, addr.get_addr_string(), addr.get_port_in());
theApp.ReportResult(GetMyINIString("LOCAL_STRING", "STRING_031"));
}
else
{
ERRLOG1(g_Log, _T("Connect Session Failed (ChatServer): Err- %d"), iErrorCode);
theApp.ReportResult(GetMyINIString("LOCAL_STRING", "STRING_032"));
}
m_dwLastPingRecvTime = timeGetTime();
return 0;
}
int ClientNet::CChatServerEventHandler::OnClose()
{
theApp.RemoveChatHandler(m_nServerGroup, this);
INFLOG1(g_Log, _T("Disconnect Session (ChatServer): DP:0x%p"), this);
theApp.ReportResult(GetMyINIString("LOCAL_STRING", "STRING_033"));
return 0;
}
int ClientNet::CChatServerEventHandler::OnDispatch(PktBase* lpPktBase, INET_Addr& peerAddr)
{
bool bResult = false;
switch(lpPktBase->GetCmd())
{
case ChatToolCMD::Authorize: RecvAuthAck(lpPktBase, peerAddr); break;
case ChatToolCMD::ChatSend: RecvChatData(lpPktBase, peerAddr); break;
case ChatToolCMD::ChatPing: RecvChatPing(lpPktBase, peerAddr); break;
case ChatToolCMD::ChatRequest: RecvChatRequest(lpPktBase, peerAddr); break;
default: break;
}
return 0;
}
/// \brief 채팅서버로 인증 패킷 전송
/// \param szUserID 로그인 계정명
/// \param szPass 로그인 패스워드
/// \return 패킷 전송 처리 성공 여부
bool ClientNet::CChatServerEventHandler::SendAuthPkt(char* szUserID, char* szPass)
{
CMonitoringToolSetup Setup = CMonitoringToolSetup::GetInstance();
char szKey[MAX_PATH];
for(unsigned int nIndex = 0; nIndex < MAX_CHAT; ++nIndex)
{
_snprintf(szKey, MAX_PATH, "CHAT_SERVER_INDEX_%02d", nIndex);
CChatServerEventHandler* lpHandler =
theApp.GetChatServerHandler(Setup.GetInt(szChatSection, szKey, 100));
if(0 != lpHandler)
{
CNetworkMsgBlock* lpMsg =
CNetworkMsgPool::GetInstance().GetNetworkMsgBlock(
sizeof(ChatToolPkt::Authorize), INET_Addr());
if(0 != lpMsg)
{
ChatToolPkt::Authorize* lpAuthorize =
reinterpret_cast<ChatToolPkt::Authorize*>(lpMsg->wr_ptr());
_snprintf(lpAuthorize->m_szUserID, ChatToolPkt::MAX_USER_ID, szUserID);
lpAuthorize->m_szUserID[ChatToolPkt::MAX_USER_ID - 1] = 0;
_snprintf(lpAuthorize->m_szPassword, ChatToolPkt::MAX_PASSWORD, szPass);
lpAuthorize->m_szPassword[ChatToolPkt::MAX_PASSWORD - 1] = 0;
if(lpMsg->WrapCrypt(sizeof(ChatToolPkt::Authorize), ChatToolCMD::Authorize, 0))
{
theApp.GetEventHandlerMgr().SendPacket(lpHandler, lpMsg);
}
else
{
CNetworkMsgPool::GetInstance().FreeNetworkMsgBlock(lpMsg);
}
}
Sleep(1000);
}
else
{
ERRLOG1(g_Log, "Failed get session(ChatServer): Group- %d", Setup.GetInt(szChatSection, szKey, 100));
theApp.ReportResult(GetMyINIString("LOCAL_STRING", "STRING_030"));
}
}
return true;
}
/// \brief 인증 패킷 Ack 처리
/// \return 패킷 전송 성공 여부
bool ClientNet::CChatServerEventHandler::RecvAuthAck(PktBase* lpPktBase, INET_Addr& peerAddr)
{
CLoginDlg* lpLoginDlg = static_cast<CLoginDlg*>(theApp.GetRegisteredWindow(IDD_LOGINDLG));
if(NULL != lpLoginDlg)
{
ChatToolPkt::Authorize* lpAuthorize = static_cast<ChatToolPkt::Authorize*>(lpPktBase);
if(1 == lpAuthorize->m_cResult)
{
theApp.ReportResult(GetMyINIString("LOCAL_STRING", "STRING_034"));
theApp.SetAuthorized(true);
CString strLoginedName;
strLoginedName.Format("%s", lpAuthorize->m_szUserID);
theApp.SetLoginedName(strLoginedName);
lpLoginDlg->OnOK();
CChattingPage* lpChatPage =
static_cast<CChattingPage*>(theApp.GetRegisteredWindow(IDD_CHATTINGPAGE));
if (NULL != lpChatPage)
{
lpChatPage->SetLoginedNameEdit(strLoginedName);
lpChatPage->CheckDlgButton(IDC_GMLOGINED_CHK, BST_CHECKED);
}
unsigned char szOption[ChatToolPkt::ChatOption::MAX_OPTION];
std::fill_n(szOption, int(ChatToolPkt::ChatOption::MAX_OPTION), 1);
SendChatOptPkt(m_nServerGroup, szOption, ChatToolPkt::ChatOption::MAX_OPTION);
}
else
{
theApp.ReportResult(GetMyINIString("LOCAL_STRING", "STRING_035"));
}
}
return true;
}
/// \brief 채팅 메세지 보내기(외치기, 귓속말등)
/// \param nServerGroup 전송할 서버군
/// \param cChatType 전송할 메세지의 타입
/// \param cTargetType 메세지를 받을 대상 타입
/// \param dwTargetUID 메세지를 받을 대상의 UID
/// \param dwMessageID 메세지의 고유 ID (Ack를 받을때 활용)
/// \param strGMName 메세지를 보내는 GM의 로그인 계정명
/// \param strTargetName 메세지를 받을 대상의 계정명 또는 캐릭터명
/// \param strMsg 메세지 내용
/// \return 패킷 전송 처리 성공 여부
bool ClientNet::CChatServerEventHandler::SendChatReqPkt(unsigned int nServerGroup,
unsigned char cChatType,
unsigned char cTargetType,
unsigned long dwTargetUID,
unsigned long dwMessageID,
const CString& strGMName,
const CString& strTargetName,
const CString& strMsg)
{
if (!theApp.IsAuthorized())
{
return false;
}
CClientEventHandler* lpHandler = theApp.GetChatServerHandler(nServerGroup);
if (0 == lpHandler)
{
return false;
}
unsigned char cMsgLen = static_cast<unsigned char>(strMsg.GetLength());
CNetworkMsgBlock* lpMsg =
CNetworkMsgPool::GetInstance().GetNetworkMsgBlock(
sizeof(ChatToolPkt::ChatRequest) + cMsgLen + 1, INET_Addr());
if(0 != lpMsg)
{
ChatToolPkt::ChatRequest* lpChatReq =
reinterpret_cast<ChatToolPkt::ChatRequest*>(lpMsg->wr_ptr());
memset(lpChatReq, 0, sizeof(ChatToolPkt::ChatRequest));
lpChatReq->m_dwUID = dwTargetUID; // 대상 캐릭터 UID (TargetName이 없을 경우 사용)
lpChatReq->m_cTargetType = cTargetType; // UID / CharName / AccountName 중 하나
lpChatReq->m_dwMessageID = dwMessageID;
lpChatReq->m_cChatType = cChatType;
lpChatReq->m_cChatMsgLen = cMsgLen + 1; // +1 : 널 문자 사이즈
_snprintf(lpChatReq->m_szAdminName, ChatToolPkt::MAX_CHAR_NAME - 1, "%s", strGMName);
lpChatReq->m_szAdminName[ChatToolPkt::MAX_CHAR_NAME - 1] = 0;
_snprintf(lpChatReq->m_szTargetName, ChatToolPkt::MAX_CHAR_NAME - 1, "%s", strTargetName);
lpChatReq->m_szTargetName[ChatToolPkt::MAX_CHAR_NAME - 1] = 0;
memcpy(reinterpret_cast<char*>(lpChatReq + 1), strMsg, cMsgLen);
*(reinterpret_cast<char*>(lpChatReq + 1) + cMsgLen) = 0;
if (lpMsg->WrapCrypt(sizeof(ChatToolPkt::ChatRequest) + lpChatReq->m_cChatMsgLen,
ChatToolCMD::ChatRequest, 0))
{
theApp.GetEventHandlerMgr().SendPacket(lpHandler, lpMsg);
return true;
}
CNetworkMsgPool::GetInstance().FreeNetworkMsgBlock(lpMsg);
}
return true;
}
/// \brief 채팅 관련 데이터 처리
/// \return 패킷 처리 성공 여부
bool ClientNet::CChatServerEventHandler::RecvChatData(PktBase* lpPktBase, INET_Addr& peerAddr)
{
ChatToolPkt::ChatDataSend* lpChatDataSend =
reinterpret_cast<ChatToolPkt::ChatDataSend*>(lpPktBase);
CChattingPage* lpPage =
static_cast<CChattingPage*>(theApp.GetRegisteredWindow(IDD_CHATTINGPAGE));
CFilterUserDialog* lpFilter =
static_cast<CFilterUserDialog*>(theApp.GetRegisteredWindow(IDD_FILTERDIALOG));
CGMReportDialog* lpGMReport =
static_cast<CGMReportDialog*>(theApp.GetRegisteredWindow(IDD_GMREPORTDIALOG));
if (NULL != lpPage)
{
if(PktChat::GMREPORT == lpChatDataSend->m_cChatType)
{
if(lpGMReport)
{
lpGMReport->AddMessage(lpChatDataSend);
}
}
else
{
// 여기서 필터링
if(lpFilter)
{
lpFilter->CheckMessage(lpChatDataSend);
}
if (PktChat::WHISPER == lpChatDataSend->m_cChatType)
{
if ((0 == theApp.GetLoginedName().Compare(lpChatDataSend->m_szTargetName))
|| (0 == theApp.GetLoginedName().Compare(lpChatDataSend->m_szSenderName)))
{
CWhisperDlg* lpWhisperDlg = lpPage->GetWhisperDlg(lpChatDataSend->m_dwUID);
if (NULL != lpWhisperDlg)
{
lpWhisperDlg->ParseChatData(lpChatDataSend);
}
else
{
bool bGMSender = false;
// sender 유저가 GM이면
if(0 == theApp.GetLoginedName().Compare(lpChatDataSend->m_szSenderName))
bGMSender = true;
// 두번째 매개변수는 유저가 운영자에게 말을 거는 경우 true
lpPage->ParseChatData(lpChatDataSend, true, bGMSender);
}
}
else
{
lpPage->ParseChatData(lpChatDataSend);
}
}
else
{
lpPage->ParseChatData(lpChatDataSend);
}
}
}
CMonitoringToolLog::GetInstance().WriteChatLog(lpChatDataSend);
return true;
}
/// \brief 모니터링 할 채팅 타입 보내기
/// \param nServerGroup 패킷을 전송할 서버군
/// \param szOption 모니터링할 옵션
/// \param cOptionNum 모니터링 하고자 선택한 타입의 개수
/// \return 패킷 전송 처리 성공 여부
bool ClientNet::CChatServerEventHandler::SendChatOptPkt(unsigned int nServerGroup,
unsigned char* szOption, unsigned char cOptionNum)
{
if (true != theApp.IsAuthorized())
{
return false;
}
cOptionNum = std::min(cOptionNum, unsigned char(ChatToolPkt::ChatOption::MAX_OPTION));
CChatServerEventHandler* lpHandler = theApp.GetChatServerHandler(nServerGroup);
if(0 == lpHandler)
{
ERRLOG1(g_Log, "Failed get session(ChatServer): Group- %u", nServerGroup);
theApp.ReportResult(GetMyINIString("LOCAL_STRING", "STRING_030"));
return false;
}
CNetworkMsgBlock* lpMsg =
CNetworkMsgPool::GetInstance().GetNetworkMsgBlock(
sizeof(ChatToolPkt::ChatOption), INET_Addr());
if(0 != lpMsg)
{
ChatToolPkt::ChatOption* lpOption =
reinterpret_cast<ChatToolPkt::ChatOption*>(lpMsg->wr_ptr());
memcpy(lpOption->m_cChatOption, szOption, sizeof(unsigned char) * cOptionNum);
if(lpMsg->WrapCrypt(sizeof(ChatToolPkt::ChatOption), ChatToolCMD::ChangeOption, 0))
{
theApp.GetEventHandlerMgr().SendPacket(lpHandler, lpMsg);
return true;
}
CNetworkMsgPool::GetInstance().FreeNetworkMsgBlock(lpMsg);
}
return true;
}
/// \brief 운영자의 접속 상태 설정
/// \param nServerGroup 상태를 다시 설정할 서버군
/// \param strAdminName 상태를 설정할 운영자의 계정명
/// \param cStatus 로그인 또는 로그아웃 상태
/// \return 패킷 전송 처리 성공 여부
bool ClientNet::CChatServerEventHandler::SendAdminStatus(unsigned int nServerGroup,
const CString& strAdminName, unsigned char cStatus)
{
if(!theApp.IsAuthorized())
{
return false;
}
CChatServerEventHandler* lpHandler = theApp.GetChatServerHandler(nServerGroup);
if(0 == lpHandler)
{
ERRLOG1(g_Log, "Failed get session(ChatServer): Group- %u", nServerGroup);
theApp.ReportResult(GetMyINIString("LOCAL_STRING", "STRING_030"));
return false;
}
CNetworkMsgBlock* lpMsg =
CNetworkMsgPool::GetInstance().GetNetworkMsgBlock(sizeof(ChatToolPkt::ChatAdminStatus), INET_Addr());
if(0 != lpMsg)
{
ChatToolPkt::ChatAdminStatus* lpAdminStatus =
reinterpret_cast<ChatToolPkt::ChatAdminStatus*>(lpMsg->wr_ptr());
strncpy(lpAdminStatus->m_szChatAdminName, strAdminName, ChatToolPkt::MAX_USER_ID);
lpAdminStatus->m_cChangeStatus = cStatus;
if(lpMsg->WrapCrypt(sizeof(ChatToolPkt::ChatAdminStatus), ChatToolCMD::ChatAdminStatus, 0))
{
theApp.GetEventHandlerMgr().SendPacket(lpHandler, lpMsg);
return true;
}
CNetworkMsgPool::GetInstance().FreeNetworkMsgBlock(lpMsg);
}
return true;
}
/// \brief 핑 패킷을 마지막으로 받은 시간 갱신
/// \return 패킷 처리 성공 여부
bool ClientNet::CChatServerEventHandler::RecvChatPing(PktBase* lpPktBase, INET_Addr& peerAddr)
{
m_dwLastPingRecvTime = timeGetTime();
return true;
}
/// \brief 채팅 요청에 대한 Ack처리
/// \return 패킷 처리 성공 여부
bool ClientNet::CChatServerEventHandler::RecvChatRequest(PktBase* lpPktBase, INET_Addr& peerAddr)
{
ChatToolPkt::ChatRequest* lpChatRequest =
reinterpret_cast<ChatToolPkt::ChatRequest*>(lpPktBase);
switch (lpChatRequest->GetError())
{
case 0:
{
// 메세지 ID에 매칭되는 창이 띄워져있다면 Ack로 받은 UID를 셋팅해준다.
CChattingPage* lpPage =
static_cast<CChattingPage*>(theApp.GetRegisteredWindow(IDD_CHATTINGPAGE));
CWhisperDlg* lpDlg = lpPage->GetAccountDlg(lpChatRequest->m_dwMessageID);
if ((NULL != lpDlg) && (0 == lpDlg->GetKeyUID()))
{
lpDlg->SetKeyUID(lpChatRequest->m_dwUID, lpChatRequest->m_dwCID);
}
}
break;
case ChatToolPkt::ChatRequest::PACKET_ERROR:
// 패킷에 에러가 있는 경우. 어쨌건 Ack는 왔음이요...
break;
case ChatToolPkt::ChatRequest::NONE_CHARACTER:
theApp.ReportResult(GetMyINIString("LOCAL_STRING", "STRING_043"));
break;
}
return true;
}