1 #ifndef __XBMC_CLIENT_H__
2 #define __XBMC_CLIENT_H__
3 
4 /*
5  *  Copyright (C) 2008-2013 Team XBMC
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License along
18  *  with this program; if not, write to the Free Software Foundation, Inc.,
19  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #ifdef _WIN32
27 #include <winsock.h>
28 #else
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <netdb.h>
32 #include <arpa/inet.h>
33 #endif
34 #include <vector>
35 #include <iosfwd>
36 #include <fstream>
37 #include <time.h>
38 
39 #define STD_PORT       9777
40 
41 #define MS_ABSOLUTE    0x01
42 //#define MS_RELATIVE    0x02
43 
44 #define BTN_USE_NAME   0x01
45 #define BTN_DOWN       0x02
46 #define BTN_UP         0x04
47 #define BTN_USE_AMOUNT 0x08
48 #define BTN_QUEUE      0x10
49 #define BTN_NO_REPEAT  0x20
50 #define BTN_VKEY       0x40
51 #define BTN_AXIS       0x80
52 
53 #define PT_HELO         0x01
54 #define PT_BYE          0x02
55 #define PT_BUTTON       0x03
56 #define PT_MOUSE        0x04
57 #define PT_PING         0x05
58 #define PT_BROADCAST    0x06
59 #define PT_NOTIFICATION 0x07
60 #define PT_BLOB         0x08
61 #define PT_LOG          0x09
62 #define PT_ACTION       0x0A
63 #define PT_DEBUG        0xFF
64 
65 #define ICON_NONE       0x00
66 #define ICON_JPEG       0x01
67 #define ICON_PNG        0x02
68 #define ICON_GIF        0x03
69 
70 #define MAX_PACKET_SIZE  1024
71 #define HEADER_SIZE      32
72 #define MAX_PAYLOAD_SIZE (MAX_PACKET_SIZE - HEADER_SIZE)
73 
74 #define MAJOR_VERSION 2
75 #define MINOR_VERSION 0
76 
77 #define LOGDEBUG   0
78 #define LOGINFO    1
79 #define LOGNOTICE  2
80 #define LOGWARNING 3
81 #define LOGERROR   4
82 #define LOGSEVERE  5
83 #define LOGFATAL   6
84 #define LOGNONE    7
85 
86 #define ACTION_EXECBUILTIN 0x01
87 #define ACTION_BUTTON      0x02
88 
89 class CAddress
90 {
91 private:
92   struct sockaddr_in m_Addr;
93 public:
94   CAddress(int Port = STD_PORT)
95   {
96     m_Addr.sin_family = AF_INET;
97     m_Addr.sin_port = htons(Port);
98     m_Addr.sin_addr.s_addr = INADDR_ANY;
99     memset(m_Addr.sin_zero, '\0', sizeof m_Addr.sin_zero);
100   }
101 
102   CAddress(const char *Address, int Port = STD_PORT)
103   {
104     m_Addr.sin_port = htons(Port);
105 
106     struct hostent *h;
107     if (Address == NULL || (h=gethostbyname(Address)) == NULL)
108     {
109         if (Address != NULL)
110 			printf("Error: Get host by name\n");
111 
112         m_Addr.sin_addr.s_addr  = INADDR_ANY;
113         m_Addr.sin_family       = AF_INET;
114     }
115     else
116     {
117       m_Addr.sin_family = h->h_addrtype;
118       m_Addr.sin_addr = *((struct in_addr *)h->h_addr);
119     }
120     memset(m_Addr.sin_zero, '\0', sizeof m_Addr.sin_zero);
121   }
122 
SetPort(int port)123   void SetPort(int port)
124   {
125     m_Addr.sin_port = htons(port);
126   }
127 
GetAddress()128   const sockaddr *GetAddress()
129   {
130     return ((struct sockaddr *)&m_Addr);
131   }
132 
Bind(int Sockfd)133   bool Bind(int Sockfd)
134   {
135     return (bind(Sockfd, (struct sockaddr *)&m_Addr, sizeof m_Addr) == 0);
136   }
137 };
138 
139 class XBMCClientUtils
140 {
141 public:
XBMCClientUtils()142   XBMCClientUtils() {}
~XBMCClientUtils()143   ~XBMCClientUtils() {}
GetUniqueIdentifier()144   static unsigned int GetUniqueIdentifier()
145   {
146     static time_t id = time(NULL);
147 	return (unsigned int)id;
148   }
149 
Clean()150   static void Clean()
151   {
152   #ifdef _WIN32
153     WSACleanup();
154   #endif
155   }
156 
Initialize()157   static bool Initialize()
158   {
159   #ifdef _WIN32
160     WSADATA wsaData;
161     if (WSAStartup(MAKEWORD(1, 1), &wsaData))
162       return false;
163   #endif
164     return true;
165   }
166 };
167 
168 class CPacket
169 {
170 /*   Base class that implements a single event packet.
171 
172      - Generic packet structure (maximum 1024 bytes per packet)
173      - Header is 32 bytes long, so 992 bytes available for payload
174      - large payloads can be split into multiple packets using H4 and H5
175        H5 should contain total no. of packets in such a case
176      - H6 contains length of P1, which is limited to 992 bytes
177      - if H5 is 0 or 1, then H4 will be ignored (single packet msg)
178      - H7 must be set to zeros for now
179 
180          -----------------------------
181          | -H1 Signature ("XBMC")    | - 4  x CHAR                4B
182          | -H2 Version (eg. 2.0)     | - 2  x UNSIGNED CHAR       2B
183          | -H3 PacketType            | - 1  x UNSIGNED SHORT      2B
184          | -H4 Sequence number       | - 1  x UNSIGNED LONG       4B
185          | -H5 No. of packets in msg | - 1  x UNSIGNED LONG       4B
186          | -H6 Payload size          | - 1  x UNSIGNED SHORT      2B
187          | -H7 Client's unique token | - 1  x UNSIGNED LONG       4B
188          | -H8 Reserved              | - 10 x UNSIGNED CHAR      10B
189          |---------------------------|
190          | -P1 payload               | -
191          -----------------------------
192 */
193 public:
CPacket()194   CPacket()
195   {
196     m_PacketType = 0;
197   }
~CPacket()198   virtual ~CPacket()
199   { }
200 
201   bool Send(int Socket, CAddress &Addr, unsigned int UID = XBMCClientUtils::GetUniqueIdentifier())
202   {
203     if (m_Payload.size() == 0)
204       ConstructPayload();
205     bool SendSuccessfull = 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         SendSuccessfull = false;
236 
237       Sent += Send;
238     }
239     return SendSuccessfull;
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   virtual void ConstructPayload()
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((const char)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[(unsigned int)size];
349       file.seekg (0, std::ios::beg);
350       file.read (m_IconData, size);
351       file.close();
352       m_IconSize = (unsigned int)size;
353     }
354     else
355     {
356       m_IconType = ICON_NONE;
357       m_IconSize = 0;
358     }
359   }
360 
~CPacketHELO()361   virtual ~CPacketHELO()
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   virtual void ConstructPayload()
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((unsigned char)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[(unsigned int)size];
439       file.seekg (0, std::ios::beg);
440       file.read (m_IconData, size);
441       file.close();
442       m_IconSize = (unsigned int)size;
443     }
444     else
445       m_IconType = ICON_NONE;
446   }
447 
~CPacketNOTIFICATION()448   virtual ~CPacketNOTIFICATION()
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   virtual void ConstructPayload()
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   virtual ~CPacketBUTTON()
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   }
~CPacketPING()597   virtual ~CPacketPING()
598   { }
599 };
600 
601 class CPacketBYE : public CPacket
602 {
603     /************************************************************************/
604     /* no payload                                                           */
605     /************************************************************************/
606 public:
CPacketBYE()607   CPacketBYE() : CPacket()
608   {
609     m_PacketType = PT_BYE;
610   }
~CPacketBYE()611   virtual ~CPacketBYE()
612   { }
613 };
614 
615 class CPacketMOUSE : public CPacket
616 {
617     /************************************************************************/
618     /* Payload format                                                       */
619     /* %c - flags                                                           */
620     /*    - 0x01 absolute position                                          */
621     /* %i - mousex (0-65535 => maps to screen width)                        */
622     /* %i - mousey (0-65535 => maps to screen height)                       */
623     /************************************************************************/
624 private:
625   unsigned short m_X;
626   unsigned short m_Y;
627   unsigned char  m_Flag;
628 public:
629   CPacketMOUSE(int X, int Y, unsigned char Flag = MS_ABSOLUTE)
630   {
631     m_PacketType = PT_MOUSE;
632     m_Flag = Flag;
633     m_X = X;
634     m_Y = Y;
635   }
636 
ConstructPayload()637   virtual void ConstructPayload()
638   {
639     m_Payload.clear();
640 
641     m_Payload.push_back(m_Flag);
642 
643     m_Payload.push_back(((m_X & 0xff00) >> 8));
644     m_Payload.push_back( (m_X & 0x00ff));
645 
646     m_Payload.push_back(((m_Y & 0xff00) >> 8));
647     m_Payload.push_back( (m_Y & 0x00ff));
648   }
649 
~CPacketMOUSE()650   virtual ~CPacketMOUSE()
651   { }
652 };
653 
654 class CPacketLOG : public CPacket
655 {
656     /************************************************************************/
657     /* Payload format                                                       */
658     /* %c - log type                                                        */
659     /* %s - message                                                         */
660     /************************************************************************/
661 private:
662   std::vector<char> m_Message;
663   unsigned char  m_LogLevel;
664   bool m_AutoPrintf;
665 public:
666   CPacketLOG(int LogLevel, const char *Message, bool AutoPrintf = true)
667   {
668     m_PacketType = PT_LOG;
669 
670     unsigned int len = strlen(Message);
671     for (unsigned int i = 0; i < len; i++)
672       m_Message.push_back(Message[i]);
673 
674     m_LogLevel = LogLevel;
675     m_AutoPrintf = AutoPrintf;
676   }
677 
ConstructPayload()678   virtual void ConstructPayload()
679   {
680     m_Payload.clear();
681 
682     m_Payload.push_back( (m_LogLevel & 0x00ff) );
683 
684     if (m_AutoPrintf)
685     {
686       char* str=&m_Message[0];
687       printf("%s\n", str);
688     }
689     for (unsigned int i = 0; i < m_Message.size(); i++)
690       m_Payload.push_back(m_Message[i]);
691 
692     m_Payload.push_back('\0');
693   }
694 
~CPacketLOG()695   virtual ~CPacketLOG()
696   { }
697 };
698 
699 class CPacketACTION : public CPacket
700 {
701     /************************************************************************/
702     /* Payload format                                                       */
703     /* %c - action type                                                     */
704     /* %s - action message                                                  */
705     /************************************************************************/
706 private:
707   unsigned char     m_ActionType;
708   std::vector<char> m_Action;
709 public:
710   CPacketACTION(const char *Action, unsigned char ActionType = ACTION_EXECBUILTIN)
711   {
712     m_PacketType = PT_ACTION;
713 
714     m_ActionType = ActionType;
715     unsigned int len = strlen(Action);
716     for (unsigned int i = 0; i < len; i++)
717       m_Action.push_back(Action[i]);
718   }
719 
ConstructPayload()720   virtual void ConstructPayload()
721   {
722     m_Payload.clear();
723 
724     m_Payload.push_back(m_ActionType);
725     for (unsigned int i = 0; i < m_Action.size(); i++)
726       m_Payload.push_back(m_Action[i]);
727 
728     m_Payload.push_back('\0');
729   }
730 
~CPacketACTION()731   virtual ~CPacketACTION()
732   { }
733 };
734 
735 class CXBMCClient
736 {
737 private:
738   CAddress      m_Addr;
739   int           m_Socket;
740   unsigned int  m_UID;
741 public:
742   CXBMCClient(const char *IP = "127.0.0.1", int Port = 9777, int Socket = -1, unsigned int UID = 0)
743   {
744     m_Addr = CAddress(IP, Port);
745     if (Socket == -1)
746       m_Socket = socket(AF_INET, SOCK_DGRAM, 0);
747     else
748       m_Socket = Socket;
749 
750     if (UID)
751       m_UID = UID;
752     else
753       m_UID = XBMCClientUtils::GetUniqueIdentifier();
754   }
755 
756   void SendNOTIFICATION(const char *Title, const char *Message, unsigned short IconType, const char *IconFile = NULL)
757   {
758     if (m_Socket < 0)
759       return;
760 
761     CPacketNOTIFICATION notification(Title, Message, IconType, IconFile);
762     notification.Send(m_Socket, m_Addr, m_UID);
763   }
764 
765   void SendHELO(const char *DevName, unsigned short IconType, const char *IconFile = NULL)
766   {
767     if (m_Socket < 0)
768       return;
769 
770     CPacketHELO helo(DevName, IconType, IconFile);
771     helo.Send(m_Socket, m_Addr, m_UID);
772   }
773 
774   void SendButton(const char *Button, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0)
775   {
776     if (m_Socket < 0)
777       return;
778 
779     CPacketBUTTON button(Button, DeviceMap, Flags, Amount);
780     button.Send(m_Socket, m_Addr, m_UID);
781   }
782 
783   void SendButton(unsigned short ButtonCode, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0)
784   {
785     if (m_Socket < 0)
786       return;
787 
788     CPacketBUTTON button(ButtonCode, DeviceMap, Flags, Amount);
789     button.Send(m_Socket, m_Addr, m_UID);
790   }
791 
792   void SendButton(unsigned short ButtonCode, unsigned Flags, unsigned short Amount = 0)
793   {
794     if (m_Socket < 0)
795       return;
796 
797     CPacketBUTTON button(ButtonCode, Flags, Amount);
798     button.Send(m_Socket, m_Addr, m_UID);
799   }
800 
801   void SendMOUSE(int X, int Y, unsigned char Flag = MS_ABSOLUTE)
802   {
803     if (m_Socket < 0)
804       return;
805 
806     CPacketMOUSE mouse(X, Y, Flag);
807     mouse.Send(m_Socket, m_Addr, m_UID);
808   }
809 
810   void SendLOG(int LogLevel, const char *Message, bool AutoPrintf = true)
811   {
812     if (m_Socket < 0)
813       return;
814 
815     CPacketLOG log(LogLevel, Message, AutoPrintf);
816     log.Send(m_Socket, m_Addr, m_UID);
817   }
818 
819   void SendACTION(const char *ActionMessage, int ActionType = ACTION_EXECBUILTIN)
820   {
821     if (m_Socket < 0)
822       return;
823 
824     CPacketACTION action(ActionMessage, ActionType);
825     action.Send(m_Socket, m_Addr, m_UID);
826   }
827 };
828 
829 #endif
830 
831