diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /tools/EventClients/lib/c++/xbmcclient.h | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools/EventClients/lib/c++/xbmcclient.h')
-rw-r--r-- | tools/EventClients/lib/c++/xbmcclient.h | 823 |
1 files changed, 823 insertions, 0 deletions
diff --git a/tools/EventClients/lib/c++/xbmcclient.h b/tools/EventClients/lib/c++/xbmcclient.h new file mode 100644 index 0000000..ef9afc5 --- /dev/null +++ b/tools/EventClients/lib/c++/xbmcclient.h @@ -0,0 +1,823 @@ +/* + * Copyright (C) 2008-2015 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kodi; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#ifdef _WIN32 +#include <winsock.h> +#else +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> +#endif +#include <vector> +#include <iostream> +#include <fstream> +#include <time.h> + +#define STD_PORT 9777 + +#define MS_ABSOLUTE 0x01 +//#define MS_RELATIVE 0x02 + +#define BTN_USE_NAME 0x01 +#define BTN_DOWN 0x02 +#define BTN_UP 0x04 +#define BTN_USE_AMOUNT 0x08 +#define BTN_QUEUE 0x10 +#define BTN_NO_REPEAT 0x20 +#define BTN_VKEY 0x40 +#define BTN_AXIS 0x80 + +#define PT_HELO 0x01 +#define PT_BYE 0x02 +#define PT_BUTTON 0x03 +#define PT_MOUSE 0x04 +#define PT_PING 0x05 +#define PT_BROADCAST 0x06 +#define PT_NOTIFICATION 0x07 +#define PT_BLOB 0x08 +#define PT_LOG 0x09 +#define PT_ACTION 0x0A +#define PT_DEBUG 0xFF + +#define ICON_NONE 0x00 +#define ICON_JPEG 0x01 +#define ICON_PNG 0x02 +#define ICON_GIF 0x03 + +#define MAX_PACKET_SIZE 1024 +#define HEADER_SIZE 32 +#define MAX_PAYLOAD_SIZE (MAX_PACKET_SIZE - HEADER_SIZE) + +#define MAJOR_VERSION 2 +#define MINOR_VERSION 0 + +#define LOGDEBUG 0 +#define LOGINFO 1 +#define LOGNOTICE 2 +#define LOGWARNING 3 +#define LOGERROR 4 +#define LOGSEVERE 5 +#define LOGFATAL 6 +#define LOGNONE 7 + +#define ACTION_EXECBUILTIN 0x01 +#define ACTION_BUTTON 0x02 + +class CAddress +{ +private: + struct sockaddr_in m_Addr; +public: + CAddress(int Port = STD_PORT) + { + m_Addr.sin_family = AF_INET; + m_Addr.sin_port = htons(Port); + m_Addr.sin_addr.s_addr = INADDR_ANY; + memset(m_Addr.sin_zero, '\0', sizeof m_Addr.sin_zero); + } + + CAddress(const char *Address, int Port = STD_PORT) + { + m_Addr.sin_port = htons(Port); + + struct hostent *h; + if (Address == NULL || (h=gethostbyname(Address)) == NULL) + { + if (Address != NULL) + printf("Error: Get host by name\n"); + + m_Addr.sin_addr.s_addr = INADDR_ANY; + m_Addr.sin_family = AF_INET; + } + else + { + m_Addr.sin_family = h->h_addrtype; + m_Addr.sin_addr = *((struct in_addr *)h->h_addr); + } + memset(m_Addr.sin_zero, '\0', sizeof m_Addr.sin_zero); + } + + void SetPort(int port) + { + m_Addr.sin_port = htons(port); + } + + const sockaddr *GetAddress() + { + return ((struct sockaddr *)&m_Addr); + } + + bool Bind(int Sockfd) + { + return (bind(Sockfd, (struct sockaddr *)&m_Addr, sizeof m_Addr) == 0); + } +}; + +class XBMCClientUtils +{ +public: + XBMCClientUtils() = default; + ~XBMCClientUtils() = default; + static unsigned int GetUniqueIdentifier() + { + static time_t id = time(NULL); + return id; + } + + static void Clean() + { + #ifdef _WIN32 + WSACleanup(); + #endif + } + + static bool Initialize() + { + #ifdef _WIN32 + WSADATA wsaData; + if (WSAStartup(MAKEWORD(1, 1), &wsaData)) + return false; + #endif + return true; + } +}; + +class CPacket +{ +/* Base class that implements a single event packet. + + - Generic packet structure (maximum 1024 bytes per packet) + - Header is 32 bytes long, so 992 bytes available for payload + - large payloads can be split into multiple packets using H4 and H5 + H5 should contain total no. of packets in such a case + - H6 contains length of P1, which is limited to 992 bytes + - if H5 is 0 or 1, then H4 will be ignored (single packet msg) + - H7 must be set to zeros for now + + ----------------------------- + | -H1 Signature ("XBMC") | - 4 x CHAR 4B + | -H2 Version (eg. 2.0) | - 2 x UNSIGNED CHAR 2B + | -H3 PacketType | - 1 x UNSIGNED SHORT 2B + | -H4 Sequence number | - 1 x UNSIGNED LONG 4B + | -H5 No. of packets in msg | - 1 x UNSIGNED LONG 4B + | -H6 Payload size | - 1 x UNSIGNED SHORT 2B + | -H7 Client's unique token | - 1 x UNSIGNED LONG 4B + | -H8 Reserved | - 10 x UNSIGNED CHAR 10B + |---------------------------| + | -P1 payload | - + ----------------------------- +*/ +public: + CPacket() + { + m_PacketType = 0; + } + virtual ~CPacket() = default; + + bool Send(int Socket, CAddress &Addr, unsigned int UID = XBMCClientUtils::GetUniqueIdentifier()) + { + if (m_Payload.empty()) + ConstructPayload(); + bool SendSuccessful = true; + int NbrOfPackages = (m_Payload.size() / MAX_PAYLOAD_SIZE) + 1; + int Send = 0; + int Sent = 0; + int Left = m_Payload.size(); + for (int Package = 1; Package <= NbrOfPackages; Package++) + { + if (Left > MAX_PAYLOAD_SIZE) + { + Send = MAX_PAYLOAD_SIZE; + Left -= Send; + } + else + { + Send = Left; + Left = 0; + } + + ConstructHeader(m_PacketType, NbrOfPackages, Package, Send, UID, m_Header); + char t[MAX_PACKET_SIZE]; + int i, j; + for (i = 0; i < 32; i++) + t[i] = m_Header[i]; + + for (j = 0; j < Send; j++) + t[(32 + j)] = m_Payload[j + Sent]; + + int rtn = sendto(Socket, t, (32 + Send), 0, Addr.GetAddress(), sizeof(struct sockaddr)); + + if (rtn != (32 + Send)) + SendSuccessful = false; + + Sent += Send; + } + return SendSuccessful; + } +protected: + char m_Header[HEADER_SIZE]; + unsigned short m_PacketType; + + std::vector<char> m_Payload; + + static void ConstructHeader(int PacketType, int NumberOfPackets, int CurrentPacket, unsigned short PayloadSize, unsigned int UniqueToken, char *Header) + { + sprintf(Header, "XBMC"); + for (int i = 4; i < HEADER_SIZE; i++) + Header[i] = 0; + Header[4] = MAJOR_VERSION; + Header[5] = MINOR_VERSION; + if (CurrentPacket == 1) + { + Header[6] = ((PacketType & 0xff00) >> 8); + Header[7] = (PacketType & 0x00ff); + } + else + { + Header[6] = ((PT_BLOB & 0xff00) >> 8); + Header[7] = (PT_BLOB & 0x00ff); + } + Header[8] = ((CurrentPacket & 0xff000000) >> 24); + Header[9] = ((CurrentPacket & 0x00ff0000) >> 16); + Header[10] = ((CurrentPacket & 0x0000ff00) >> 8); + Header[11] = (CurrentPacket & 0x000000ff); + + Header[12] = ((NumberOfPackets & 0xff000000) >> 24); + Header[13] = ((NumberOfPackets & 0x00ff0000) >> 16); + Header[14] = ((NumberOfPackets & 0x0000ff00) >> 8); + Header[15] = (NumberOfPackets & 0x000000ff); + + Header[16] = ((PayloadSize & 0xff00) >> 8); + Header[17] = (PayloadSize & 0x00ff); + + Header[18] = ((UniqueToken & 0xff000000) >> 24); + Header[19] = ((UniqueToken & 0x00ff0000) >> 16); + Header[20] = ((UniqueToken & 0x0000ff00) >> 8); + Header[21] = (UniqueToken & 0x000000ff); + } + + virtual void ConstructPayload() + { } +}; + +class CPacketHELO : public CPacket +{ + /************************************************************************/ + /* Payload format */ + /* %s - device name (max 128 chars) */ + /* %c - icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF ) */ + /* %s - my port ( 0=>not listening ) */ + /* %d - reserved1 ( 0 ) */ + /* %d - reserved2 ( 0 ) */ + /* XX - imagedata ( can span multiple packets ) */ + /************************************************************************/ +private: + std::vector<char> m_DeviceName; + unsigned short m_IconType; + char *m_IconData; + unsigned short m_IconSize; +public: + void ConstructPayload() override + { + m_Payload.clear(); + + for (unsigned int i = 0; i < m_DeviceName.size(); i++) + m_Payload.push_back(m_DeviceName[i]); + + m_Payload.push_back('\0'); + + m_Payload.push_back(m_IconType); + + m_Payload.push_back(0); + m_Payload.push_back('\0'); + + for (int j = 0; j < 8; j++) + m_Payload.push_back(0); + + for (int ico = 0; ico < m_IconSize; ico++) + m_Payload.push_back(m_IconData[ico]); + } + + CPacketHELO(const char *DevName, unsigned short IconType, const char *IconFile = NULL) : CPacket() + { + m_PacketType = PT_HELO; + + unsigned int len = strlen(DevName); + for (unsigned int i = 0; i < len; i++) + m_DeviceName.push_back(DevName[i]); + + m_IconType = IconType; + + if (IconType == ICON_NONE || IconFile == NULL) + { + m_IconData = NULL; + m_IconSize = 0; + return; + } + + std::ifstream::pos_type size; + + std::ifstream file (IconFile, std::ios::in|std::ios::binary|std::ios::ate); + if (file.is_open()) + { + size = file.tellg(); + m_IconData = new char [size]; + file.seekg (0, std::ios::beg); + file.read (m_IconData, size); + file.close(); + m_IconSize = size; + } + else + { + m_IconType = ICON_NONE; + m_IconSize = 0; + } + } + + ~CPacketHELO() override + { + m_DeviceName.clear(); + delete[] m_IconData; + } +}; + +class CPacketNOTIFICATION : public CPacket +{ + /************************************************************************/ + /* Payload format: */ + /* %s - caption */ + /* %s - message */ + /* %c - icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF ) */ + /* %d - reserved ( 0 ) */ + /* XX - imagedata ( can span multiple packets ) */ + /************************************************************************/ +private: + std::vector<char> m_Title; + std::vector<char> m_Message; + unsigned short m_IconType; + char *m_IconData; + unsigned short m_IconSize; +public: + void ConstructPayload() override + { + m_Payload.clear(); + + for (unsigned int i = 0; i < m_Title.size(); i++) + m_Payload.push_back(m_Title[i]); + + m_Payload.push_back('\0'); + + for (unsigned int i = 0; i < m_Message.size(); i++) + m_Payload.push_back(m_Message[i]); + + m_Payload.push_back('\0'); + + m_Payload.push_back(m_IconType); + + for (int i = 0; i < 4; i++) + m_Payload.push_back(0); + + for (int ico = 0; ico < m_IconSize; ico++) + m_Payload.push_back(m_IconData[ico]); + } + + CPacketNOTIFICATION(const char *Title, const char *Message, unsigned short IconType, const char *IconFile = NULL) : CPacket() + { + m_PacketType = PT_NOTIFICATION; + m_IconData = NULL; + m_IconSize = 0; + unsigned int len = 0; + if (Title != NULL) + { + len = strlen(Title); + for (unsigned int i = 0; i < len; i++) + m_Title.push_back(Title[i]); + } + + if (Message != NULL) + { + len = strlen(Message); + for (unsigned int i = 0; i < len; i++) + m_Message.push_back(Message[i]); + } + m_IconType = IconType; + + if (IconType == ICON_NONE || IconFile == NULL) + return; + + std::ifstream::pos_type size; + + std::ifstream file (IconFile, std::ios::in|std::ios::binary|std::ios::ate); + if (file.is_open()) + { + size = file.tellg(); + m_IconData = new char [size]; + file.seekg (0, std::ios::beg); + file.read (m_IconData, size); + file.close(); + m_IconSize = size; + } + else + m_IconType = ICON_NONE; + } + + ~CPacketNOTIFICATION() override + { + m_Title.clear(); + m_Message.clear(); + delete[] m_IconData; + } +}; + +class CPacketBUTTON : public CPacket +{ + /************************************************************************/ + /* Payload format */ + /* %i - button code */ + /* %i - flags 0x01 => use button map/name instead of code */ + /* 0x02 => btn down */ + /* 0x04 => btn up */ + /* 0x08 => use amount */ + /* 0x10 => queue event */ + /* 0x20 => do not repeat */ + /* 0x40 => virtual key */ + /* 0x40 => axis key */ + /* %i - amount ( 0 => 65k maps to -1 => 1 ) */ + /* %s - device map (case sensitive and required if flags & 0x01) */ + /* "KB" - Standard keyboard map */ + /* "XG" - Xbox Gamepad */ + /* "R1" - Xbox Remote */ + /* "R2" - Xbox Universal Remote */ + /* "LI:devicename" - valid LIRC device map where 'devicename' */ + /* is the actual name of the LIRC device */ + /* "JS<num>:joyname" - valid Joystick device map where */ + /* 'joyname' is the name specified in */ + /* the keymap. JS only supports button code */ + /* and not button name currently (!0x01). */ + /* %s - button name (required if flags & 0x01) */ + /************************************************************************/ +private: + std::vector<char> m_DeviceMap; + std::vector<char> m_Button; + unsigned short m_ButtonCode; + unsigned short m_Amount; + unsigned short m_Flags; +public: + void ConstructPayload() override + { + m_Payload.clear(); + + if (m_Button.size() != 0) + { + if (!(m_Flags & BTN_USE_NAME)) // If the BTN_USE_NAME isn't flagged for some reason + m_Flags |= BTN_USE_NAME; + m_ButtonCode = 0; + } + else + m_Button.clear(); + + if (m_Amount > 0) + { + if (!(m_Flags & BTN_USE_AMOUNT)) + m_Flags |= BTN_USE_AMOUNT; + } + if (!((m_Flags & BTN_DOWN) || (m_Flags & BTN_UP))) //If none of them are tagged. + m_Flags |= BTN_DOWN; + + m_Payload.push_back(((m_ButtonCode & 0xff00) >> 8)); + m_Payload.push_back( (m_ButtonCode & 0x00ff)); + + m_Payload.push_back(((m_Flags & 0xff00) >> 8) ); + m_Payload.push_back( (m_Flags & 0x00ff)); + + m_Payload.push_back(((m_Amount & 0xff00) >> 8) ); + m_Payload.push_back( (m_Amount & 0x00ff)); + + + for (unsigned int i = 0; i < m_DeviceMap.size(); i++) + m_Payload.push_back(m_DeviceMap[i]); + + m_Payload.push_back('\0'); + + for (unsigned int i = 0; i < m_Button.size(); i++) + m_Payload.push_back(m_Button[i]); + + m_Payload.push_back('\0'); + } + + CPacketBUTTON(const char *Button, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0) : CPacket() + { + m_PacketType = PT_BUTTON; + m_Flags = Flags; + m_ButtonCode = 0; + m_Amount = Amount; + + unsigned int len = strlen(DeviceMap); + for (unsigned int i = 0; i < len; i++) + m_DeviceMap.push_back(DeviceMap[i]); + + len = strlen(Button); + for (unsigned int i = 0; i < len; i++) + m_Button.push_back(Button[i]); + } + + CPacketBUTTON(unsigned short ButtonCode, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0) : CPacket() + { + m_PacketType = PT_BUTTON; + m_Flags = Flags; + m_ButtonCode = ButtonCode; + m_Amount = Amount; + + unsigned int len = strlen(DeviceMap); + for (unsigned int i = 0; i < len; i++) + m_DeviceMap.push_back(DeviceMap[i]); + } + + CPacketBUTTON(unsigned short ButtonCode, unsigned short Flags, unsigned short Amount = 0) : CPacket() + { + m_PacketType = PT_BUTTON; + m_Flags = Flags; + m_ButtonCode = ButtonCode; + m_Amount = Amount; + } + + // Used to send a release event + CPacketBUTTON() : CPacket() + { + m_PacketType = PT_BUTTON; + m_Flags = BTN_UP; + m_Amount = 0; + m_ButtonCode = 0; + } + + ~CPacketBUTTON() override + { + m_DeviceMap.clear(); + m_Button.clear(); + } + + inline unsigned short GetFlags() { return m_Flags; } + inline unsigned short GetButtonCode() { return m_ButtonCode; } +}; + +class CPacketPING : public CPacket +{ + /************************************************************************/ + /* no payload */ + /************************************************************************/ +public: + CPacketPING() : CPacket() + { + m_PacketType = PT_PING; + } + ~CPacketPING() override = default; +}; + +class CPacketBYE : public CPacket +{ + /************************************************************************/ + /* no payload */ + /************************************************************************/ +public: + CPacketBYE() : CPacket() + { + m_PacketType = PT_BYE; + } + ~CPacketBYE() override = default; +}; + +class CPacketMOUSE : public CPacket +{ + /************************************************************************/ + /* Payload format */ + /* %c - flags */ + /* - 0x01 absolute position */ + /* %i - mousex (0-65535 => maps to screen width) */ + /* %i - mousey (0-65535 => maps to screen height) */ + /************************************************************************/ +private: + unsigned short m_X; + unsigned short m_Y; + unsigned char m_Flag; +public: + CPacketMOUSE(int X, int Y, unsigned char Flag = MS_ABSOLUTE) + { + m_PacketType = PT_MOUSE; + m_Flag = Flag; + m_X = X; + m_Y = Y; + } + + void ConstructPayload() override + { + m_Payload.clear(); + + m_Payload.push_back(m_Flag); + + m_Payload.push_back(((m_X & 0xff00) >> 8)); + m_Payload.push_back( (m_X & 0x00ff)); + + m_Payload.push_back(((m_Y & 0xff00) >> 8)); + m_Payload.push_back( (m_Y & 0x00ff)); + } + + ~CPacketMOUSE() override = default; +}; + +class CPacketLOG : public CPacket +{ + /************************************************************************/ + /* Payload format */ + /* %c - log type */ + /* %s - message */ + /************************************************************************/ +private: + std::vector<char> m_Message; + unsigned char m_LogLevel; + bool m_AutoPrintf; +public: + CPacketLOG(int LogLevel, const char *Message, bool AutoPrintf = true) + { + m_PacketType = PT_LOG; + + unsigned int len = strlen(Message); + for (unsigned int i = 0; i < len; i++) + m_Message.push_back(Message[i]); + + m_LogLevel = LogLevel; + m_AutoPrintf = AutoPrintf; + } + + void ConstructPayload() override + { + m_Payload.clear(); + + m_Payload.push_back( (m_LogLevel & 0x00ff) ); + + if (m_AutoPrintf) + { + char* str=&m_Message[0]; + printf("%s\n", str); + } + for (unsigned int i = 0; i < m_Message.size(); i++) + m_Payload.push_back(m_Message[i]); + + m_Payload.push_back('\0'); + } + + ~CPacketLOG() override = default; +}; + +class CPacketACTION : public CPacket +{ + /************************************************************************/ + /* Payload format */ + /* %c - action type */ + /* %s - action message */ + /************************************************************************/ +private: + unsigned char m_ActionType; + std::vector<char> m_Action; +public: + CPacketACTION(const char *Action, unsigned char ActionType = ACTION_EXECBUILTIN) + { + m_PacketType = PT_ACTION; + + m_ActionType = ActionType; + unsigned int len = strlen(Action); + for (unsigned int i = 0; i < len; i++) + m_Action.push_back(Action[i]); + } + + void ConstructPayload() override + { + m_Payload.clear(); + + m_Payload.push_back(m_ActionType); + for (unsigned int i = 0; i < m_Action.size(); i++) + m_Payload.push_back(m_Action[i]); + + m_Payload.push_back('\0'); + } + + ~CPacketACTION() override = default; +}; + +class CXBMCClient +{ +private: + CAddress m_Addr; + int m_Socket; + unsigned int m_UID; +public: + CXBMCClient(const char *IP = "127.0.0.1", int Port = 9777, int Socket = -1, unsigned int UID = 0) + { + m_Addr = CAddress(IP, Port); + if (Socket == -1) + m_Socket = socket(AF_INET, SOCK_DGRAM, 0); + else + m_Socket = Socket; + + if (UID) + m_UID = UID; + else + m_UID = XBMCClientUtils::GetUniqueIdentifier(); + } + + void SendNOTIFICATION(const char *Title, const char *Message, unsigned short IconType, const char *IconFile = NULL) + { + if (m_Socket < 0) + return; + + CPacketNOTIFICATION notification(Title, Message, IconType, IconFile); + notification.Send(m_Socket, m_Addr, m_UID); + } + + void SendHELO(const char *DevName, unsigned short IconType, const char *IconFile = NULL) + { + if (m_Socket < 0) + return; + + CPacketHELO helo(DevName, IconType, IconFile); + helo.Send(m_Socket, m_Addr, m_UID); + } + + void SendButton(const char *Button, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0) + { + if (m_Socket < 0) + return; + + CPacketBUTTON button(Button, DeviceMap, Flags, Amount); + button.Send(m_Socket, m_Addr, m_UID); + } + + void SendButton(unsigned short ButtonCode, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0) + { + if (m_Socket < 0) + return; + + CPacketBUTTON button(ButtonCode, DeviceMap, Flags, Amount); + button.Send(m_Socket, m_Addr, m_UID); + } + + void SendButton(unsigned short ButtonCode, unsigned Flags, unsigned short Amount = 0) + { + if (m_Socket < 0) + return; + + CPacketBUTTON button(ButtonCode, Flags, Amount); + button.Send(m_Socket, m_Addr, m_UID); + } + + void SendMOUSE(int X, int Y, unsigned char Flag = MS_ABSOLUTE) + { + if (m_Socket < 0) + return; + + CPacketMOUSE mouse(X, Y, Flag); + mouse.Send(m_Socket, m_Addr, m_UID); + } + + void SendLOG(int LogLevel, const char *Message, bool AutoPrintf = true) + { + if (m_Socket < 0) + return; + + CPacketLOG log(LogLevel, Message, AutoPrintf); + log.Send(m_Socket, m_Addr, m_UID); + } + + void SendACTION(const char *ActionMessage, int ActionType = ACTION_EXECBUILTIN) + { + if (m_Socket < 0) + return; + + CPacketACTION action(ActionMessage, ActionType); + action.Send(m_Socket, m_Addr, m_UID); + } +}; + |