1 /*
2  *      Copyright (C) 2008-2015 Team Kodi
3  *      http://kodi.tv
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with Kodi; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #pragma once
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #ifdef _WIN32
28 #include <winsock.h>
29 #else
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netdb.h>
33 #include <arpa/inet.h>
34 #endif
35 #include <vector>
36 #include <iostream>
37 #include <fstream>
38 #include <time.h>
39 
40 #define STD_PORT       9777
41 
42 #define MS_ABSOLUTE    0x01
43 //#define MS_RELATIVE    0x02
44 
45 #define BTN_USE_NAME   0x01
46 #define BTN_DOWN       0x02
47 #define BTN_UP         0x04
48 #define BTN_USE_AMOUNT 0x08
49 #define BTN_QUEUE      0x10
50 #define BTN_NO_REPEAT  0x20
51 #define BTN_VKEY       0x40
52 #define BTN_AXIS       0x80
53 
54 #define PT_HELO         0x01
55 #define PT_BYE          0x02
56 #define PT_BUTTON       0x03
57 #define PT_MOUSE        0x04
58 #define PT_PING         0x05
59 #define PT_BROADCAST    0x06
60 #define PT_NOTIFICATION 0x07
61 #define PT_BLOB         0x08
62 #define PT_LOG          0x09
63 #define PT_ACTION       0x0A
64 #define PT_DEBUG        0xFF
65 
66 #define ICON_NONE       0x00
67 #define ICON_JPEG       0x01
68 #define ICON_PNG        0x02
69 #define ICON_GIF        0x03
70 
71 #define MAX_PACKET_SIZE  1024
72 #define HEADER_SIZE      32
73 #define MAX_PAYLOAD_SIZE (MAX_PACKET_SIZE - HEADER_SIZE)
74 
75 #define MAJOR_VERSION 2
76 #define MINOR_VERSION 0
77 
78 #define LOGDEBUG   0
79 #define LOGINFO    1
80 #define LOGNOTICE  2
81 #define LOGWARNING 3
82 #define LOGERROR   4
83 #define LOGSEVERE  5
84 #define LOGFATAL   6
85 #define LOGNONE    7
86 
87 #define ACTION_EXECBUILTIN 0x01
88 #define ACTION_BUTTON      0x02
89 
90 class CAddress
91 {
92 private:
93   struct sockaddr_in m_Addr;
94 public:
95   CAddress(int Port = STD_PORT)
96   {
97     m_Addr.sin_family = AF_INET;
98     m_Addr.sin_port = htons(Port);
99     m_Addr.sin_addr.s_addr = INADDR_ANY;
100     memset(m_Addr.sin_zero, '\0', sizeof m_Addr.sin_zero);
101   }
102 
103   CAddress(const char *Address, int Port = STD_PORT)
104   {
105     m_Addr.sin_port = htons(Port);
106 
107     struct hostent *h;
108     if (Address == NULL || (h=gethostbyname(Address)) == NULL)
109     {
110         if (Address != NULL)
111 			printf("Error: Get host by name\n");
112 
113         m_Addr.sin_addr.s_addr  = INADDR_ANY;
114         m_Addr.sin_family       = AF_INET;
115     }
116     else
117     {
118       m_Addr.sin_family = h->h_addrtype;
119       m_Addr.sin_addr = *((struct in_addr *)h->h_addr);
120     }
121     memset(m_Addr.sin_zero, '\0', sizeof m_Addr.sin_zero);
122   }
123 
SetPort(int port)124   void SetPort(int port)
125   {
126     m_Addr.sin_port = htons(port);
127   }
128 
GetAddress()129   const sockaddr *GetAddress()
130   {
131     return ((struct sockaddr *)&m_Addr);
132   }
133 
Bind(int Sockfd)134   bool Bind(int Sockfd)
135   {
136     return (bind(Sockfd, (struct sockaddr *)&m_Addr, sizeof m_Addr) == 0);
137   }
138 };
139 
140 class XBMCClientUtils
141 {
142 public:
143   XBMCClientUtils() = default;
144   ~XBMCClientUtils() = default;
GetUniqueIdentifier()145   static unsigned int GetUniqueIdentifier()
146   {
147     static time_t id = time(NULL);
148     return id;
149   }
150 
Clean()151   static void Clean()
152   {
153   #ifdef _WIN32
154     WSACleanup();
155   #endif
156   }
157 
Initialize()158   static bool Initialize()
159   {
160   #ifdef _WIN32
161     WSADATA wsaData;
162     if (WSAStartup(MAKEWORD(1, 1), &wsaData))
163       return false;
164   #endif
165     return true;
166   }
167 };
168 
169 class CPacket
170 {
171 /*   Base class that implements a single event packet.
172 
173      - Generic packet structure (maximum 1024 bytes per packet)
174      - Header is 32 bytes long, so 992 bytes available for payload
175      - large payloads can be split into multiple packets using H4 and H5
176        H5 should contain total no. of packets in such a case
177      - H6 contains length of P1, which is limited to 992 bytes
178      - if H5 is 0 or 1, then H4 will be ignored (single packet msg)
179      - H7 must be set to zeros for now
180 
181          -----------------------------
182          | -H1 Signature ("XBMC")    | - 4  x CHAR                4B
183          | -H2 Version (eg. 2.0)     | - 2  x UNSIGNED CHAR       2B
184          | -H3 PacketType            | - 1  x UNSIGNED SHORT      2B
185          | -H4 Sequence number       | - 1  x UNSIGNED LONG       4B
186          | -H5 No. of packets in msg | - 1  x UNSIGNED LONG       4B
187          | -H6 Payload size          | - 1  x UNSIGNED SHORT      2B
188          | -H7 Client's unique token | - 1  x UNSIGNED LONG       4B
189          | -H8 Reserved              | - 10 x UNSIGNED CHAR      10B
190          |---------------------------|
191          | -P1 payload               | -
192          -----------------------------
193 */
194 public:
CPacket()195   CPacket()
196   {
197     m_PacketType = 0;
198   }
199   virtual ~CPacket() = default;
200 
201   bool Send(int Socket, CAddress &Addr, unsigned int UID = XBMCClientUtils::GetUniqueIdentifier())
202   {
203     if (m_Payload.empty())
204       ConstructPayload();
205     bool SendSuccessful = true;
206     int NbrOfPackages = (m_Payload.size() / MAX_PAYLOAD_SIZE) + 1;
207     int Send = 0;
208     int Sent = 0;
209     int Left = m_Payload.size();
210     for (int Package = 1; Package <= NbrOfPackages; Package++)
211     {
212       if (Left > MAX_PAYLOAD_SIZE)
213       {
214         Send = MAX_PAYLOAD_SIZE;
215         Left -= Send;
216       }
217       else
218       {
219         Send = Left;
220         Left = 0;
221       }
222 
223       ConstructHeader(m_PacketType, NbrOfPackages, Package, Send, UID, m_Header);
224       char t[MAX_PACKET_SIZE];
225       int i, j;
226       for (i = 0; i < 32; i++)
227         t[i] = m_Header[i];
228 
229       for (j = 0; j < Send; j++)
230         t[(32 + j)] = m_Payload[j + Sent];
231 
232       int rtn = sendto(Socket, t, (32 + Send), 0, Addr.GetAddress(), sizeof(struct sockaddr));
233 
234       if (rtn != (32 + Send))
235         SendSuccessful = false;
236 
237       Sent += Send;
238     }
239     return SendSuccessful;
240   }
241 protected:
242   char            m_Header[HEADER_SIZE];
243   unsigned short  m_PacketType;
244 
245   std::vector<char> m_Payload;
246 
ConstructHeader(int PacketType,int NumberOfPackets,int CurrentPacket,unsigned short PayloadSize,unsigned int UniqueToken,char * Header)247   static void ConstructHeader(int PacketType, int NumberOfPackets, int CurrentPacket, unsigned short PayloadSize, unsigned int UniqueToken, char *Header)
248   {
249     sprintf(Header, "XBMC");
250     for (int i = 4; i < HEADER_SIZE; i++)
251       Header[i] = 0;
252     Header[4]  = MAJOR_VERSION;
253     Header[5]  = MINOR_VERSION;
254     if (CurrentPacket == 1)
255     {
256       Header[6]  = ((PacketType & 0xff00) >> 8);
257       Header[7]  =  (PacketType & 0x00ff);
258     }
259     else
260     {
261       Header[6]  = ((PT_BLOB & 0xff00) >> 8);
262       Header[7]  =  (PT_BLOB & 0x00ff);
263     }
264     Header[8]  = ((CurrentPacket & 0xff000000) >> 24);
265     Header[9]  = ((CurrentPacket & 0x00ff0000) >> 16);
266     Header[10] = ((CurrentPacket & 0x0000ff00) >> 8);
267     Header[11] =  (CurrentPacket & 0x000000ff);
268 
269     Header[12] = ((NumberOfPackets & 0xff000000) >> 24);
270     Header[13] = ((NumberOfPackets & 0x00ff0000) >> 16);
271     Header[14] = ((NumberOfPackets & 0x0000ff00) >> 8);
272     Header[15] =  (NumberOfPackets & 0x000000ff);
273 
274     Header[16] = ((PayloadSize & 0xff00) >> 8);
275     Header[17] =  (PayloadSize & 0x00ff);
276 
277     Header[18] = ((UniqueToken & 0xff000000) >> 24);
278     Header[19] = ((UniqueToken & 0x00ff0000) >> 16);
279     Header[20] = ((UniqueToken & 0x0000ff00) >> 8);
280     Header[21] =  (UniqueToken & 0x000000ff);
281   }
282 
ConstructPayload()283   virtual void ConstructPayload()
284   { }
285 };
286 
287 class CPacketHELO : public CPacket
288 {
289     /************************************************************************/
290     /* Payload format                                                       */
291     /* %s -  device name (max 128 chars)                                    */
292     /* %c -  icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF )              */
293     /* %s -  my port ( 0=>not listening )                                   */
294     /* %d -  reserved1 ( 0 )                                                */
295     /* %d -  reserved2 ( 0 )                                                */
296     /* XX -  imagedata ( can span multiple packets )                        */
297     /************************************************************************/
298 private:
299   std::vector<char> m_DeviceName;
300   unsigned short m_IconType;
301   char *m_IconData;
302   unsigned short m_IconSize;
303 public:
ConstructPayload()304   void ConstructPayload() override
305   {
306     m_Payload.clear();
307 
308     for (unsigned int i = 0; i < m_DeviceName.size(); i++)
309       m_Payload.push_back(m_DeviceName[i]);
310 
311     m_Payload.push_back('\0');
312 
313     m_Payload.push_back(m_IconType);
314 
315     m_Payload.push_back(0);
316     m_Payload.push_back('\0');
317 
318     for (int j = 0; j < 8; j++)
319       m_Payload.push_back(0);
320 
321     for (int ico = 0; ico < m_IconSize; ico++)
322       m_Payload.push_back(m_IconData[ico]);
323   }
324 
CPacket()325   CPacketHELO(const char *DevName, unsigned short IconType, const char *IconFile = NULL) : CPacket()
326   {
327     m_PacketType = PT_HELO;
328 
329     unsigned int len = strlen(DevName);
330     for (unsigned int i = 0; i < len; i++)
331       m_DeviceName.push_back(DevName[i]);
332 
333     m_IconType = IconType;
334 
335     if (IconType == ICON_NONE || IconFile == NULL)
336     {
337       m_IconData = NULL;
338       m_IconSize = 0;
339       return;
340     }
341 
342     std::ifstream::pos_type size;
343 
344     std::ifstream file (IconFile, std::ios::in|std::ios::binary|std::ios::ate);
345     if (file.is_open())
346     {
347       size = file.tellg();
348       m_IconData = new char [size];
349       file.seekg (0, std::ios::beg);
350       file.read (m_IconData, size);
351       file.close();
352       m_IconSize = size;
353     }
354     else
355     {
356       m_IconType = ICON_NONE;
357       m_IconSize = 0;
358     }
359   }
360 
~CPacketHELO()361   ~CPacketHELO() override
362   {
363     m_DeviceName.clear();
364     delete[] m_IconData;
365   }
366 };
367 
368 class CPacketNOTIFICATION : public CPacket
369 {
370     /************************************************************************/
371     /* Payload format:                                                      */
372     /* %s - caption                                                         */
373     /* %s - message                                                         */
374     /* %c - icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF )               */
375     /* %d - reserved ( 0 )                                                  */
376     /* XX - imagedata ( can span multiple packets )                         */
377     /************************************************************************/
378 private:
379   std::vector<char> m_Title;
380   std::vector<char> m_Message;
381   unsigned short m_IconType;
382   char *m_IconData;
383   unsigned short m_IconSize;
384 public:
ConstructPayload()385   void ConstructPayload() override
386   {
387     m_Payload.clear();
388 
389     for (unsigned int i = 0; i < m_Title.size(); i++)
390       m_Payload.push_back(m_Title[i]);
391 
392     m_Payload.push_back('\0');
393 
394     for (unsigned int i = 0; i < m_Message.size(); i++)
395       m_Payload.push_back(m_Message[i]);
396 
397     m_Payload.push_back('\0');
398 
399     m_Payload.push_back(m_IconType);
400 
401     for (int i = 0; i < 4; i++)
402       m_Payload.push_back(0);
403 
404     for (int ico = 0; ico < m_IconSize; ico++)
405       m_Payload.push_back(m_IconData[ico]);
406   }
407 
CPacket()408   CPacketNOTIFICATION(const char *Title, const char *Message, unsigned short IconType, const char *IconFile = NULL) : CPacket()
409   {
410     m_PacketType = PT_NOTIFICATION;
411     m_IconData = NULL;
412     m_IconSize = 0;
413     unsigned int len = 0;
414     if (Title != NULL)
415     {
416       len = strlen(Title);
417       for (unsigned int i = 0; i < len; i++)
418         m_Title.push_back(Title[i]);
419     }
420 
421     if (Message != NULL)
422     {
423       len = strlen(Message);
424       for (unsigned int i = 0; i < len; i++)
425         m_Message.push_back(Message[i]);
426     }
427     m_IconType = IconType;
428 
429     if (IconType == ICON_NONE || IconFile == NULL)
430       return;
431 
432     std::ifstream::pos_type size;
433 
434     std::ifstream file (IconFile, std::ios::in|std::ios::binary|std::ios::ate);
435     if (file.is_open())
436     {
437       size = file.tellg();
438       m_IconData = new char [size];
439       file.seekg (0, std::ios::beg);
440       file.read (m_IconData, size);
441       file.close();
442       m_IconSize = size;
443     }
444     else
445       m_IconType = ICON_NONE;
446   }
447 
~CPacketNOTIFICATION()448   ~CPacketNOTIFICATION() override
449   {
450     m_Title.clear();
451     m_Message.clear();
452     delete[] m_IconData;
453   }
454 };
455 
456 class CPacketBUTTON : public CPacket
457 {
458     /************************************************************************/
459     /* Payload format                                                       */
460     /* %i - button code                                                     */
461     /* %i - flags 0x01 => use button map/name instead of code               */
462     /*            0x02 => btn down                                          */
463     /*            0x04 => btn up                                            */
464     /*            0x08 => use amount                                        */
465     /*            0x10 => queue event                                       */
466     /*            0x20 => do not repeat                                     */
467     /*            0x40 => virtual key                                       */
468     /*            0x40 => axis key                                          */
469     /* %i - amount ( 0 => 65k maps to -1 => 1 )                             */
470     /* %s - device map (case sensitive and required if flags & 0x01)        */
471     /*      "KB" - Standard keyboard map                                    */
472     /*      "XG" - Xbox Gamepad                                             */
473     /*      "R1" - Xbox Remote                                              */
474     /*      "R2" - Xbox Universal Remote                                    */
475     /*      "LI:devicename" -  valid LIRC device map where 'devicename'     */
476     /*                         is the actual name of the LIRC device        */
477     /*      "JS<num>:joyname" -  valid Joystick device map where            */
478     /*                           'joyname'  is the name specified in        */
479     /*                           the keymap. JS only supports button code   */
480     /*                           and not button name currently (!0x01).     */
481     /* %s - button name (required if flags & 0x01)                          */
482     /************************************************************************/
483 private:
484   std::vector<char> m_DeviceMap;
485   std::vector<char> m_Button;
486   unsigned short m_ButtonCode;
487   unsigned short m_Amount;
488   unsigned short m_Flags;
489 public:
ConstructPayload()490   void ConstructPayload() override
491   {
492     m_Payload.clear();
493 
494     if (m_Button.size() != 0)
495     {
496       if (!(m_Flags & BTN_USE_NAME)) // If the BTN_USE_NAME isn't flagged for some reason
497         m_Flags |= BTN_USE_NAME;
498       m_ButtonCode = 0;
499     }
500     else
501       m_Button.clear();
502 
503     if (m_Amount > 0)
504     {
505       if (!(m_Flags & BTN_USE_AMOUNT))
506         m_Flags |= BTN_USE_AMOUNT;
507     }
508     if (!((m_Flags & BTN_DOWN) || (m_Flags & BTN_UP))) //If none of them are tagged.
509       m_Flags |= BTN_DOWN;
510 
511     m_Payload.push_back(((m_ButtonCode & 0xff00) >> 8));
512     m_Payload.push_back( (m_ButtonCode & 0x00ff));
513 
514     m_Payload.push_back(((m_Flags & 0xff00) >> 8) );
515     m_Payload.push_back( (m_Flags & 0x00ff));
516 
517     m_Payload.push_back(((m_Amount & 0xff00) >> 8) );
518     m_Payload.push_back( (m_Amount & 0x00ff));
519 
520 
521     for (unsigned int i = 0; i < m_DeviceMap.size(); i++)
522       m_Payload.push_back(m_DeviceMap[i]);
523 
524     m_Payload.push_back('\0');
525 
526     for (unsigned int i = 0; i < m_Button.size(); i++)
527       m_Payload.push_back(m_Button[i]);
528 
529     m_Payload.push_back('\0');
530   }
531 
CPacket()532   CPacketBUTTON(const char *Button, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0) : CPacket()
533   {
534     m_PacketType = PT_BUTTON;
535     m_Flags      = Flags;
536     m_ButtonCode = 0;
537     m_Amount     = Amount;
538 
539     unsigned int len = strlen(DeviceMap);
540     for (unsigned int i = 0; i < len; i++)
541       m_DeviceMap.push_back(DeviceMap[i]);
542 
543     len = strlen(Button);
544     for (unsigned int i = 0; i < len; i++)
545       m_Button.push_back(Button[i]);
546   }
547 
CPacket()548   CPacketBUTTON(unsigned short ButtonCode, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0) : CPacket()
549   {
550     m_PacketType = PT_BUTTON;
551     m_Flags      = Flags;
552     m_ButtonCode = ButtonCode;
553     m_Amount     = Amount;
554 
555     unsigned int len = strlen(DeviceMap);
556     for (unsigned int i = 0; i < len; i++)
557       m_DeviceMap.push_back(DeviceMap[i]);
558   }
559 
CPacket()560   CPacketBUTTON(unsigned short ButtonCode, unsigned short Flags, unsigned short Amount = 0) : CPacket()
561   {
562     m_PacketType = PT_BUTTON;
563     m_Flags      = Flags;
564     m_ButtonCode = ButtonCode;
565     m_Amount     = Amount;
566   }
567 
568   // Used to send a release event
CPacketBUTTON()569   CPacketBUTTON() : CPacket()
570   {
571     m_PacketType = PT_BUTTON;
572     m_Flags = BTN_UP;
573     m_Amount = 0;
574     m_ButtonCode = 0;
575   }
576 
~CPacketBUTTON()577   ~CPacketBUTTON() override
578   {
579     m_DeviceMap.clear();
580     m_Button.clear();
581   }
582 
GetFlags()583   inline unsigned short GetFlags() { return m_Flags; }
GetButtonCode()584   inline unsigned short GetButtonCode() { return m_ButtonCode; }
585 };
586 
587 class CPacketPING : public CPacket
588 {
589     /************************************************************************/
590     /* no payload                                                           */
591     /************************************************************************/
592 public:
CPacketPING()593   CPacketPING() : CPacket()
594   {
595     m_PacketType = PT_PING;
596   }
597   ~CPacketPING() override = default;
598 };
599 
600 class CPacketBYE : public CPacket
601 {
602     /************************************************************************/
603     /* no payload                                                           */
604     /************************************************************************/
605 public:
CPacketBYE()606   CPacketBYE() : CPacket()
607   {
608     m_PacketType = PT_BYE;
609   }
610   ~CPacketBYE() override = default;
611 };
612 
613 class CPacketMOUSE : public CPacket
614 {
615     /************************************************************************/
616     /* Payload format                                                       */
617     /* %c - flags                                                           */
618     /*    - 0x01 absolute position                                          */
619     /* %i - mousex (0-65535 => maps to screen width)                        */
620     /* %i - mousey (0-65535 => maps to screen height)                       */
621     /************************************************************************/
622 private:
623   unsigned short m_X;
624   unsigned short m_Y;
625   unsigned char  m_Flag;
626 public:
627   CPacketMOUSE(int X, int Y, unsigned char Flag = MS_ABSOLUTE)
628   {
629     m_PacketType = PT_MOUSE;
630     m_Flag = Flag;
631     m_X = X;
632     m_Y = Y;
633   }
634 
ConstructPayload()635   void ConstructPayload() override
636   {
637     m_Payload.clear();
638 
639     m_Payload.push_back(m_Flag);
640 
641     m_Payload.push_back(((m_X & 0xff00) >> 8));
642     m_Payload.push_back( (m_X & 0x00ff));
643 
644     m_Payload.push_back(((m_Y & 0xff00) >> 8));
645     m_Payload.push_back( (m_Y & 0x00ff));
646   }
647 
648   ~CPacketMOUSE() override = default;
649 };
650 
651 class CPacketLOG : public CPacket
652 {
653     /************************************************************************/
654     /* Payload format                                                       */
655     /* %c - log type                                                        */
656     /* %s - message                                                         */
657     /************************************************************************/
658 private:
659   std::vector<char> m_Message;
660   unsigned char  m_LogLevel;
661   bool m_AutoPrintf;
662 public:
663   CPacketLOG(int LogLevel, const char *Message, bool AutoPrintf = true)
664   {
665     m_PacketType = PT_LOG;
666 
667     unsigned int len = strlen(Message);
668     for (unsigned int i = 0; i < len; i++)
669       m_Message.push_back(Message[i]);
670 
671     m_LogLevel = LogLevel;
672     m_AutoPrintf = AutoPrintf;
673   }
674 
ConstructPayload()675   void ConstructPayload() override
676   {
677     m_Payload.clear();
678 
679     m_Payload.push_back( (m_LogLevel & 0x00ff) );
680 
681     if (m_AutoPrintf)
682     {
683       char* str=&m_Message[0];
684       printf("%s\n", str);
685     }
686     for (unsigned int i = 0; i < m_Message.size(); i++)
687       m_Payload.push_back(m_Message[i]);
688 
689     m_Payload.push_back('\0');
690   }
691 
692   ~CPacketLOG() override = default;
693 };
694 
695 class CPacketACTION : public CPacket
696 {
697     /************************************************************************/
698     /* Payload format                                                       */
699     /* %c - action type                                                     */
700     /* %s - action message                                                  */
701     /************************************************************************/
702 private:
703   unsigned char     m_ActionType;
704   std::vector<char> m_Action;
705 public:
706   CPacketACTION(const char *Action, unsigned char ActionType = ACTION_EXECBUILTIN)
707   {
708     m_PacketType = PT_ACTION;
709 
710     m_ActionType = ActionType;
711     unsigned int len = strlen(Action);
712     for (unsigned int i = 0; i < len; i++)
713       m_Action.push_back(Action[i]);
714   }
715 
ConstructPayload()716   void ConstructPayload() override
717   {
718     m_Payload.clear();
719 
720     m_Payload.push_back(m_ActionType);
721     for (unsigned int i = 0; i < m_Action.size(); i++)
722       m_Payload.push_back(m_Action[i]);
723 
724     m_Payload.push_back('\0');
725   }
726 
727   ~CPacketACTION() override = default;
728 };
729 
730 class CXBMCClient
731 {
732 private:
733   CAddress      m_Addr;
734   int           m_Socket;
735   unsigned int  m_UID;
736 public:
737   CXBMCClient(const char *IP = "127.0.0.1", int Port = 9777, int Socket = -1, unsigned int UID = 0)
738   {
739     m_Addr = CAddress(IP, Port);
740     if (Socket == -1)
741       m_Socket = socket(AF_INET, SOCK_DGRAM, 0);
742     else
743       m_Socket = Socket;
744 
745     if (UID)
746       m_UID = UID;
747     else
748       m_UID = XBMCClientUtils::GetUniqueIdentifier();
749   }
750 
751   void SendNOTIFICATION(const char *Title, const char *Message, unsigned short IconType, const char *IconFile = NULL)
752   {
753     if (m_Socket < 0)
754       return;
755 
756     CPacketNOTIFICATION notification(Title, Message, IconType, IconFile);
757     notification.Send(m_Socket, m_Addr, m_UID);
758   }
759 
760   void SendHELO(const char *DevName, unsigned short IconType, const char *IconFile = NULL)
761   {
762     if (m_Socket < 0)
763       return;
764 
765     CPacketHELO helo(DevName, IconType, IconFile);
766     helo.Send(m_Socket, m_Addr, m_UID);
767   }
768 
769   void SendButton(const char *Button, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0)
770   {
771     if (m_Socket < 0)
772       return;
773 
774     CPacketBUTTON button(Button, DeviceMap, Flags, Amount);
775     button.Send(m_Socket, m_Addr, m_UID);
776   }
777 
778   void SendButton(unsigned short ButtonCode, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0)
779   {
780     if (m_Socket < 0)
781       return;
782 
783     CPacketBUTTON button(ButtonCode, DeviceMap, Flags, Amount);
784     button.Send(m_Socket, m_Addr, m_UID);
785   }
786 
787   void SendButton(unsigned short ButtonCode, unsigned Flags, unsigned short Amount = 0)
788   {
789     if (m_Socket < 0)
790       return;
791 
792     CPacketBUTTON button(ButtonCode, Flags, Amount);
793     button.Send(m_Socket, m_Addr, m_UID);
794   }
795 
796   void SendMOUSE(int X, int Y, unsigned char Flag = MS_ABSOLUTE)
797   {
798     if (m_Socket < 0)
799       return;
800 
801     CPacketMOUSE mouse(X, Y, Flag);
802     mouse.Send(m_Socket, m_Addr, m_UID);
803   }
804 
805   void SendLOG(int LogLevel, const char *Message, bool AutoPrintf = true)
806   {
807     if (m_Socket < 0)
808       return;
809 
810     CPacketLOG log(LogLevel, Message, AutoPrintf);
811     log.Send(m_Socket, m_Addr, m_UID);
812   }
813 
814   void SendACTION(const char *ActionMessage, int ActionType = ACTION_EXECBUILTIN)
815   {
816     if (m_Socket < 0)
817       return;
818 
819     CPacketACTION action(ActionMessage, ActionType);
820     action.Send(m_Socket, m_Addr, m_UID);
821   }
822 };
823 
824