context: /*
   *  Copyright (C) 2008-2013 Team XBMC
   *
   *  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 of the License, 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 this program; if not, write to the Free Software Foundation, Inc.,
   *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   */
  
  using System;
  using System.IO;
  using System.Net;
  using System.Net.Sockets;
  
  namespace XBMC
  {
  
      public enum IconType
      {
          ICON_NONE = 0x00,
          ICON_JPEG = 0x01,
          ICON_PNG = 0x02,
          ICON_GIF = 0x03
      }
  
      public enum ButtonFlagsType
      {
          BTN_USE_NAME = 0x01,
          BTN_DOWN = 0x02,
          BTN_UP = 0x04,
          BTN_USE_AMOUNT = 0x08,
          BTN_QUEUE = 0x10,
          BTN_NO_REPEAT = 0x20,
          BTN_VKEY = 0x40,
          BTN_AXIS = 0x80
      }
  
      public enum MouseFlagsType
      {
          MS_ABSOLUTE = 0x01
      }
  
      public enum LogTypeEnum
      {
          LOGDEBUG = 0,
          LOGINFO = 1,
          LOGNOTICE = 2,
          LOGWARNING = 3,
          LOGERROR = 4,
          LOGSEVERE = 5,
          LOGFATAL = 6,
          LOGNONE = 7
      }
  
      public enum ActionType
      {
          ACTION_EXECBUILTIN = 0x01,
          ACTION_BUTTON = 0x02
      }
  
      public class EventClient
      {
  
          /************************************************************************/
          /* Written by Peter Tribe aka EqUiNox (TeamBlackbolt)                   */
          /* Based upon XBMC's xbmcclient.cpp class                               */
          /************************************************************************/
  
          private enum PacketType
          {
              PT_HELO = 0x01,
              PT_BYE = 0x02,
              PT_BUTTON = 0x03,
              PT_MOUSE = 0x04,
              PT_PING = 0x05,
              PT_BROADCAST = 0x06,  //Currently not implemented
              PT_NOTIFICATION = 0x07,
              PT_BLOB = 0x08,
              PT_LOG = 0x09,
              PT_ACTION = 0x0A,
              PT_DEBUG = 0xFF //Currently not implemented
          }
  
          private const int STD_PORT = 9777;
          private const int MAX_PACKET_SIZE = 1024;
          private const int HEADER_SIZE = 32;
          private const int MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE;
          private const byte MAJOR_VERSION = 2;
          private const byte MINOR_VERSION = 0;
  
          private uint uniqueToken;
          private Socket socket;
  
          public bool Connect(string Address)
          {
              return Connect(Address, STD_PORT, (uint)System.DateTime.Now.TimeOfDay.Milliseconds);
          }
  
          public bool Connect(string Address, int Port)
          {
              return Connect(Address, Port, (uint)System.DateTime.Now.TimeOfDay.Milliseconds);
          }
  
  
          public bool Connect(string Address, int Port, uint UID)
          {
              try
              {
                  if (socket != null) Disconnect();
                  uniqueToken = UID;
                  socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  
  // For compilation with .net framework 1.0 or 1.1
  // define the FRAMEWORK_1_x conditional compilation constant in the project
  // or add /define:FRAMEWORK_1_x to the csc.exe command line
  #if FRAMEWORK_1_x
                  socket.Connect(Dns.GetHostByName(Address).AddressList[0].ToString(), Port);
  #else
                  socket.Connect(Address, Port);
  #endif
                  return true;
              }
              catch
              {
                  return false;
              }
          }
  
          public bool Connected
          {
              get
              {
                  if (socket == null) return false;
                  return socket.Connected;
              }
          }
  
          public void Disconnect()
          {
              try
              {
                  if (socket != null)
                  {
                      socket.Shutdown(SocketShutdown.Both);
                      socket.Close();
                      socket = null;
                  }
              }
              catch
              {
              }
          }
  
          private byte[] Header(PacketType PacketType, int NumberOfPackets, int CurrentPacket, int PayloadSize)
          {
  
              byte[] header = new byte[HEADER_SIZE];
  
              header[0] = (byte)'X';
              header[1] = (byte)'B';
              header[2] = (byte)'M';
              header[3] = (byte)'C';
  
              header[4] = MAJOR_VERSION;
              header[5] = MINOR_VERSION;
  
              if (CurrentPacket == 1)
              {
                  header[6] = (byte)(((ushort)PacketType & 0xff00) >> 8);
                  header[7] = (byte)((ushort)PacketType & 0x00ff);
              }
              else
              {
                  header[6] = (byte)(((ushort)PacketType.PT_BLOB & 0xff00) >> 8);
                  header[7] = (byte)((ushort)PacketType.PT_BLOB & 0x00ff);
              }
  
              header[8] = (byte)((CurrentPacket & 0xff000000) >> 24);
              header[9] = (byte)((CurrentPacket & 0x00ff0000) >> 16);
              header[10] = (byte)((CurrentPacket & 0x0000ff00) >> 8);
              header[11] = (byte)(CurrentPacket & 0x000000ff);
  
              header[12] = (byte)((NumberOfPackets & 0xff000000) >> 24);
              header[13] = (byte)((NumberOfPackets & 0x00ff0000) >> 16);
              header[14] = (byte)((NumberOfPackets & 0x0000ff00) >> 8);
              header[15] = (byte)(NumberOfPackets & 0x000000ff);
  
              header[16] = (byte)((PayloadSize & 0xff00) >> 8);
              header[17] = (byte)(PayloadSize & 0x00ff);
  
              header[18] = (byte)((uniqueToken & 0xff000000) >> 24);
              header[19] = (byte)((uniqueToken & 0x00ff0000) >> 16);
              header[20] = (byte)((uniqueToken & 0x0000ff00) >> 8);
              header[21] = (byte)(uniqueToken & 0x000000ff);
  
              return header;
  
          }
  
          private bool Send(PacketType PacketType, byte[] Payload)
          {
              try
              {
  
                  bool successful = true;
                  int packetCount = (Payload.Length / MAX_PAYLOAD_SIZE) + 1;
                  int bytesToSend = 0;
                  int bytesSent = 0;
                  int bytesLeft = Payload.Length;
  
                  for (int Package = 1; Package <= packetCount; Package++)
                  {
  
                      if (bytesLeft > MAX_PAYLOAD_SIZE)
                      {
                          bytesToSend = MAX_PAYLOAD_SIZE;
                          bytesLeft -= bytesToSend;
                      }
                      else
                      {
                          bytesToSend = bytesLeft;
                          bytesLeft = 0;
                      }
  
                      byte[] header = Header(PacketType, packetCount, Package, bytesToSend);
                      byte[] packet = new byte[MAX_PACKET_SIZE];
  
                      Array.Copy(header, 0, packet, 0, header.Length);
                      Array.Copy(Payload, bytesSent, packet, header.Length, bytesToSend);
  
                      int sendSize = socket.Send(packet, header.Length + bytesToSend, SocketFlags.None);
  
                      if (sendSize != (header.Length + bytesToSend))
                      {
                          successful = false;
                          break;
                      }
  
                      bytesSent += bytesToSend;
  
                  }
  
                  return successful;
  
              }
              catch
              {
  
                  return false;
  
              }
  
          }
  
          /************************************************************************/
          /* SendHelo - 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 )                        */
          /************************************************************************/
          public bool SendHelo(string DevName, IconType IconType, string IconFile)
          {
  
              byte[] icon = new byte[0];
              if (IconType != IconType.ICON_NONE)
                  icon = File.ReadAllBytes(IconFile);
  
              byte[] payload = new byte[DevName.Length + 12 + icon.Length];
  
              int offset = 0;
  
              for (int i = 0; i < DevName.Length; i++)
                  payload[offset++] = (byte)DevName[i];
              payload[offset++] = (byte)'\0';
  
              payload[offset++] = (byte)IconType;
  
              payload[offset++] = (byte)0;
              payload[offset++] = (byte)'\0';
  
              for (int i = 0; i < 8; i++)
                  payload[offset++] = (byte)0;
  
              Array.Copy(icon, 0, payload, DevName.Length + 12, icon.Length);
  
              return Send(PacketType.PT_HELO, payload);
  
          }
  
          public bool SendHelo(string DevName)
          {
              return SendHelo(DevName, IconType.ICON_NONE, "");
          }
  
          /************************************************************************/
          /* SendNotification - 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 )                         */
          /************************************************************************/
          public bool SendNotification(string Caption, string Message, IconType IconType, string IconFile)
          {
  
              byte[] icon = new byte[0];
              if (IconType != IconType.ICON_NONE)
                  icon = File.ReadAllBytes(IconFile);
  
              byte[] payload = new byte[Caption.Length + Message.Length + 7 + icon.Length];
  
              int offset = 0;
  
              for (int i = 0; i < Caption.Length; i++)
                  payload[offset++] = (byte)Caption[i];
              payload[offset++] = (byte)'\0';
  
              for (int i = 0; i < Message.Length; i++)
                  payload[offset++] = (byte)Message[i];
              payload[offset++] = (byte)'\0';
  
              payload[offset++] = (byte)IconType;
  
              for (int i = 0; i < 4; i++)
                  payload[offset++] = (byte)0;
  
              Array.Copy(icon, 0, payload, Caption.Length + Message.Length + 7, icon.Length);
  
              return Send(PacketType.PT_NOTIFICATION, payload);
  
          }
  
          public bool SendNotification(string Caption, string Message)
          {
              return SendNotification(Caption, Message, IconType.ICON_NONE, "");
          }
  
          /************************************************************************/
          /* SendButton - 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                                       */
          /*            0x80 => 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 bool SendButton(string Button, ushort ButtonCode, string DeviceMap, ButtonFlagsType Flags, short Amount)
          {
  
              if (Button.Length != 0)
              {
                  if ((Flags & ButtonFlagsType.BTN_USE_NAME) == 0)
                      Flags |= ButtonFlagsType.BTN_USE_NAME;
                  ButtonCode = 0;
              }
              else
                  Button = "";
  
              if (Amount > 0)
              {
                  if ((Flags & ButtonFlagsType.BTN_USE_AMOUNT) == 0)
                      Flags |= ButtonFlagsType.BTN_USE_AMOUNT;
              }
  
              if ((Flags & ButtonFlagsType.BTN_DOWN) == 0 && (Flags & ButtonFlagsType.BTN_UP) == 0)
                  Flags |= ButtonFlagsType.BTN_DOWN;
  
              byte[] payload = new byte[Button.Length + DeviceMap.Length + 8];
  
              int offset = 0;
  
              payload[offset++] = (byte)((ButtonCode & 0xff00) >> 8);
              payload[offset++] = (byte)(ButtonCode & 0x00ff);
  
              payload[offset++] = (byte)(((ushort)Flags & 0xff00) >> 8);
              payload[offset++] = (byte)((ushort)Flags & 0x00ff);
  
              payload[offset++] = (byte)((Amount & 0xff00) >> 8);
              payload[offset++] = (byte)(Amount & 0x00ff);
  
              for (int i = 0; i < DeviceMap.Length; i++)
                  payload[offset++] = (byte)DeviceMap[i];
              payload[offset++] = (byte)'\0';
  
              for (int i = 0; i < Button.Length; i++)
                  payload[offset++] = (byte)Button[i];
              payload[offset++] = (byte)'\0';
  
              return Send(PacketType.PT_BUTTON, payload);
  
          }
  
          public bool SendButton(string Button, string DeviceMap, ButtonFlagsType Flags, short Amount)
          {
              return SendButton(Button, 0, DeviceMap, Flags, Amount);
          }
  
          public bool SendButton(string Button, string DeviceMap, ButtonFlagsType Flags)
          {
              return SendButton(Button, 0, DeviceMap, Flags, 0);
          }
  
          public bool SendButton(ushort ButtonCode, string DeviceMap, ButtonFlagsType Flags, short Amount)
          {
              return SendButton("", ButtonCode, DeviceMap, Flags, Amount);
          }
  
          public bool SendButton(ushort ButtonCode, string DeviceMap, ButtonFlagsType Flags)
          {
              return SendButton("", ButtonCode, DeviceMap, Flags, 0);
          }
  
          public bool SendButton(ushort ButtonCode, ButtonFlagsType Flags, short Amount)
          {
              return SendButton("", ButtonCode, "", Flags, Amount);
          }
  
          public bool SendButton(ushort ButtonCode, ButtonFlagsType Flags)
          {
              return SendButton("", ButtonCode, "", Flags, 0);
          }
  
          public bool SendButton()
          {
              return SendButton("", 0, "", ButtonFlagsType.BTN_UP, 0);
          }
  
          /************************************************************************/
          /* SendPing - No payload                                                */
          /************************************************************************/
          public bool SendPing()
          {
              byte[] payload = new byte[0];
              return Send(PacketType.PT_PING, payload);
          }
  
          /************************************************************************/
          /* SendBye - No payload                                                 */
          /************************************************************************/
          public bool SendBye()
          {
              byte[] payload = new byte[0];
              return Send(PacketType.PT_BYE, payload);
          }
  
          /************************************************************************/
          /* SendMouse - Payload format                                           */
          /* %c - flags                                                           */
          /*    - 0x01 absolute position                                          */
          /* %i - mousex (0-65535 => maps to screen width)                        */
          /* %i - mousey (0-65535 => maps to screen height)                       */
          /************************************************************************/
          public bool SendMouse(ushort X, ushort Y, MouseFlagsType Flags)
          {
  
              byte[] payload = new byte[9];
  
              int offset = 0;
  
              payload[offset++] = (byte)Flags;
  
              payload[offset++] = (byte)((X & 0xff00) >> 8);
              payload[offset++] = (byte)(X & 0x00ff);
  
              payload[offset++] = (byte)((Y & 0xff00) >> 8);
              payload[offset++] = (byte)(Y & 0x00ff);
  
  
gt:             return Send(PacketType.PT_MOUSE, payload);