Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
6.1 KiB

// irc.h
#ifndef _IRC_H_
#define _IRC_H_
/*
IRC (RFC #1459) Client Implementation
*/
#pragma warning (disable: 4786)
#include "socket.h"
#include "CrossThreadsMessagingDevice.h"
////////////////////////////////////////////////////////////////////
namespace irc {
////////////////////////////////////////////////////////////////////
static const char* endl = "\r\n";
// RFC's Identity Server (RFC #1413)
class CIrcIdentServer
{
public :
CIrcIdentServer();
virtual ~CIrcIdentServer();
bool Start(
const char* lpszUserID,
unsigned int uiPort = 113,
const char* lpszResponseType = "UNIX"
);
void Stop();
HANDLE m_hReady;
protected :
AgString m_sResponseType;
unsigned int m_uiPort;
AgString m_sUserID;
void DoThread();
private :
Socket m_socket;
HANDLE m_hThread;
static DWORD WINAPI ListenProc(LPVOID pparam);
};
////////////////////////////////////////////////////////////////////
class CIrcMessage
{
public :
struct Prefix
{
AgString sNick, sUser, sHost;
} prefix;
AgString sCommand;
vector<AgString> parameters;
bool m_bIncoming;
CIrcMessage() : m_bIncoming(false) {} // default constructor
CIrcMessage(const char* lpszCmdLine, bool bIncoming=false); // parser constructor
CIrcMessage(const CIrcMessage& m); // copy constructor
void Reset();
CIrcMessage& operator = (const CIrcMessage& m);
CIrcMessage& operator = (const char* lpszCmdLine);
AgString AsString() const;
private :
void ParseIrcCommand(const char* lpszCmdLine);
};
////////////////////////////////////////////////////////////////////
struct IIrcSessionMonitor
{
virtual void OnIrcMessage(const CIrcMessage* pmsg) = 0;
};
////////////////////////////////////////////////////////////////////
struct CIrcSessionInfo
{
AgString sServer;
AgString sServerName;
unsigned int iPort;
AgString sNick;
AgString sUserID;
AgString sFullName;
AgString sPassword;
bool bIdentServer;
AgString sIdentServerType;
unsigned int iIdentServerPort;
CIrcSessionInfo();
CIrcSessionInfo(const CIrcSessionInfo& si);
void Reset();
};
////////////////////////////////////////////////////////////////////
class CIrcDefaultMonitor; // foreward
class CIrcSession
{
public :
friend class CIrcDefaultMonitor;
CIrcSession(IIrcSessionMonitor* pMonitor = NULL);
virtual ~CIrcSession();
void AddMonitor(IIrcSessionMonitor* pMonitor);
void RemoveMonitor(IIrcSessionMonitor* pMonitor);
bool Connect(const CIrcSessionInfo& info);
void Disconnect(const char* lpszMessage = "Bye!");
const CIrcSessionInfo& GetInfo() const
{ return (const CIrcSessionInfo&)m_info; }
operator bool() const { return (bool)m_socket; }
// send-to-stream operators
friend CIrcSession& operator << (CIrcSession& os, const CIrcMessage& m);
protected :
Socket m_socket;
CIrcSessionInfo m_info;
void DoReceive();
private :
typedef set<IIrcSessionMonitor*, less<IIrcSessionMonitor*> > CIrcSessionMonitors;
CIrcSessionMonitors m_monitors;
HANDLE m_hThread;
CRITICAL_SECTION m_cs; // protect m_monitors
void Notify(const CIrcMessage* pmsg);
static DWORD WINAPI ThreadProc(LPVOID pparam);
CIrcIdentServer m_identServer;
};
__inline CIrcSession& operator << (CIrcSession& os, const CIrcMessage& m)
{
if( os )
{
os.m_socket.Send(m.AsString().c_str());
os.Notify(&m);
}
return os;
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
class CIrcMonitor :
public IIrcSessionMonitor,
private CCrossThreadsMessagingDevice::ICrossThreadsMessagingDeviceMonitor
{
public :
typedef bool (CIrcMonitor::*PfnIrcMessageHandler)(const CIrcMessage* pmsg);
struct LessString
{
bool operator()(const char* s1, const char* s2) const
{ return stricmp(s1, s2) < 0; }
};
typedef map<const char*, PfnIrcMessageHandler, LessString > HandlersMap;
struct IrcCommandsMapsListEntry
{
HandlersMap* pHandlersMap;
IrcCommandsMapsListEntry* pBaseHandlersMap;
};
CIrcMonitor(CIrcSession& session);
virtual ~CIrcMonitor();
virtual void OnIrcMessage(const CIrcMessage* pmsg);
protected :
CIrcSession& m_session;
virtual IrcCommandsMapsListEntry* GetIrcCommandsMap()
{ return &m_handlersMapsListEntry; }
virtual void OnIrcAll(const CIrcMessage* pmsg) {}
virtual void OnIrcDefault(const CIrcMessage* pmsg) {}
virtual void OnIrcDisconnected() {}
protected :
CCrossThreadsMessagingDevice m_xPost;
static IrcCommandsMapsListEntry m_handlersMapsListEntry;
static HandlersMap m_handlers;
PfnIrcMessageHandler FindMethod(const char* lpszName);
PfnIrcMessageHandler FindMethod(IrcCommandsMapsListEntry* pMapsList, const char* lpszName);
virtual void OnCrossThreadsMessage(WPARAM wParam, LPARAM lParam);
};
// define an IRC command-to-member map.
// put that macro inside the class definition (.H file)
#define DEFINE_IRC_MAP() \
protected : \
virtual IrcCommandsMapsListEntry* GetIrcCommandsMap() \
{ return &m_handlersMapsListEntry; } \
protected : \
static CIrcMonitor::IrcCommandsMapsListEntry m_handlersMapsListEntry; \
static CIrcMonitor::HandlersMap m_handlers; \
protected :
// IRC command-to-member map's declaration.
// add this macro to the class's .CPP file
#define DECLARE_IRC_MAP(this_class, base_class) \
CIrcMonitor::HandlersMap this_class##::m_handlers; \
CIrcMonitor::IrcCommandsMapsListEntry this_class##::m_handlersMapsListEntry \
= { &this_class##::m_handlers, &base_class##::m_handlersMapsListEntry };
// map actual member functions to their associated IRC command.
// put any number of this macro in the class's constructor.
#define IRC_MAP_ENTRY(class_name, name, member) \
m_handlers[(name)] = (PfnIrcMessageHandler)&class_name##::member;
////////////////////////////////////////////////////////////////////
class CIrcDefaultMonitor : public CIrcMonitor
{
public :
CIrcDefaultMonitor(CIrcSession& session);
DEFINE_IRC_MAP()
protected :
bool OnIrc_NICK(const CIrcMessage* pmsg);
bool OnIrc_PING(const CIrcMessage* pmsg);
bool OnIrc_YOURHOST(const CIrcMessage* pmsg);
bool OnIrc_BOUNCE(const CIrcMessage* pmsg);
};
////////////////////////////////////////////////////////////////////
}; // end of namespace irc
////////////////////////////////////////////////////////////////////
#endif // _IRC_H_