CecTray: try/catch xml exceptions when reading the xml config. bugzid: 2082
[deb_libcec.git] / src / LibCecTray / controller / applications / internal / XBMCController.cs
index 9e4fb3a1973d717351d04993bb8cc145a4d4b212..6b961008986ed01cd26ae12f724eda227c62be1a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the libCEC(R) library.
  *
- * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited.  All rights reserved.
  * libCEC(R) is an original work, containing original code.
  *
  * libCEC(R) is a trademark of Pulse-Eight Limited.
@@ -44,8 +44,8 @@ namespace LibCECTray.controller.applications.@internal
 {
        internal class XBMCController : ApplicationController
        {
-    public XBMCController(CECSettings settings) :
-      base(settings,
+    public XBMCController(CECController controller) :
+      base(controller,
            Resources.application_xbmc,
            "XBMC",
            "XBMC.exe",
@@ -56,6 +56,17 @@ namespace LibCECTray.controller.applications.@internal
       ControlApplication.Value = false;
 
       LoadXMLConfiguration();
+
+      ApplicationRunningChanged += RunningChanged;
+    }
+
+         static void RunningChanged(bool running)
+    {
+      if (running)
+      {
+        // XBMC is running, close the application, or we'll block communication
+        Application.Exit();
+      }
     }
 
     public override ApplicationAction DefaultValue(CecKeypress key)
@@ -70,18 +81,25 @@ namespace LibCECTray.controller.applications.@internal
 
     public bool LoadXMLConfiguration()
     {
-      bool gotConfig = false;
-      string xbmcDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\XBMC\userdata\peripheral_data";
-      string defaultDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
-      string file = defaultDir + @"\usb_2548_1001.xml";
-      if (File.Exists(xbmcDir + @"\usb_2548_1001.xml"))
-        file = xbmcDir + @"\usb_2548_1001.xml";
+      var xbmcDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\XBMC\userdata\peripheral_data";
+      return LoadXMLConfiguration(xbmcDir + string.Format(@"\usb_{0:X}_{1:X}.xml", Program.Instance.Controller.AdapterVendorId, Program.Instance.Controller.AdapterProductId)) ||
+             LoadXMLConfiguration(xbmcDir + @"\usb_2548_1001.xml") ||
+             LoadXMLConfiguration(xbmcDir + @"\usb_2548_1002.xml");
+    }
 
-      if (File.Exists(file))
+    public bool LoadXMLConfiguration(string filename)
+    {
+      bool gotConfig = false;
+      if (File.Exists(filename))
       {
-        XmlTextReader reader = new XmlTextReader(file);
-        while (reader.Read())
+        XmlTextReader reader = new XmlTextReader(filename);
+        while (true)
         {
+          try
+          {
+            if (!reader.Read())
+              break;
+          } catch (XmlException) {}
           gotConfig = true;
           switch (reader.NodeType)
           {
@@ -110,9 +128,9 @@ namespace LibCECTray.controller.applications.@internal
                     break;
                   case "connected_device":
                     {
-                      ushort iDevice;
-                      if (ushort.TryParse(value, out iDevice))
-                        Settings.ConnectedDevice.Value = (CecLogicalAddress)iDevice;
+                      int iDevice;
+                      if (int.TryParse(value, out iDevice))
+                        Settings.ConnectedDevice.Value = iDevice == 36038 ? CecLogicalAddress.AudioSystem : CecLogicalAddress.Tv;
                     }
                     break;
                   case "cec_power_on_startup":
@@ -157,7 +175,29 @@ namespace LibCECTray.controller.applications.@internal
                         Settings.TVVendor.Value = (CecVendorId)iVendor;
                     }
                     break;
-                  case "wake_devices":
+                  case "wake_device":
+                    {
+                      int iWakeDevices;
+                      if (int.TryParse(value, out iWakeDevices))
+                      {
+                        Settings.WakeDevices.Value.Clear();
+                        switch (iWakeDevices)
+                        {
+                          case 36037:
+                            Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv);
+                            break;
+                          case 36038:
+                            Settings.WakeDevices.Value.Set(CecLogicalAddress.AudioSystem);
+                            break;
+                          case 36039:
+                            Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv);
+                            Settings.WakeDevices.Value.Set(CecLogicalAddress.AudioSystem);
+                            break;
+                        }
+                      }
+                    }
+                    break;
+                  case "wake_devices_advanced":
                     {
                       Settings.WakeDevices.Value.Clear();
                       string[] split = value.Split(new[] { ' ' });
@@ -170,6 +210,28 @@ namespace LibCECTray.controller.applications.@internal
                     }
                     break;
                   case "standby_devices":
+                    {
+                      int iStandbyDevices;
+                      if (int.TryParse(value, out iStandbyDevices))
+                      {
+                        Settings.PowerOffDevices.Value.Clear();
+                        switch (iStandbyDevices)
+                        {
+                          case 36037:
+                            Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Tv);
+                            break;
+                          case 36038:
+                            Settings.PowerOffDevices.Value.Set(CecLogicalAddress.AudioSystem);
+                            break;
+                          case 36039:
+                            Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Tv);
+                            Settings.PowerOffDevices.Value.Set(CecLogicalAddress.AudioSystem);
+                            break;
+                        }
+                      }
+                    }
+                    break;
+                  case "standby_devices_advanced":
                     {
                       Settings.PowerOffDevices.Value.Clear();
                       string[] split = value.Split(new[] { ' ' });
@@ -190,6 +252,10 @@ namespace LibCECTray.controller.applications.@internal
                   case "send_inactive_source":
                     SendInactiveSource.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
                     break;
+                  // 1.9.0+ settings
+                  case "pause_playback_on_deactivate":
+                    PausePlaybackOnDeactivate.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
+                    break;
                 }
               }
               break;
@@ -199,18 +265,35 @@ namespace LibCECTray.controller.applications.@internal
       return gotConfig;
     }
 
+    static bool HasAdvancedDeviceIdSet(CecLogicalAddresses addresses)
+    {
+      foreach (var val in addresses.Addresses)
+        if (val != CecLogicalAddress.Tv && val != CecLogicalAddress.AudioSystem)
+          return true;
+      return false;
+    }
+
     public void SaveXMLConfiguration()
     {
       Settings.Persist();
 
-      string xbmcDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\XBMC\userdata\peripheral_data";
-      string defaultDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
+      var xbmcDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\XBMC\userdata\peripheral_data";
+      if (!Directory.Exists(xbmcDir))
+        Directory.CreateDirectory(xbmcDir);
+
+      if (!Directory.Exists(xbmcDir))
+      {
+        // couldn't create directory
+        MessageBox.Show(string.Format(Resources.could_not_create_directory, xbmcDir), Resources.error,
+                        MessageBoxButtons.OK, MessageBoxIcon.Error);
+        return;
+      }
 
       SaveFileDialog dialog = new SaveFileDialog
-                                {
+      {
         Title = Resources.store_settings_where,
-        InitialDirectory = Directory.Exists(xbmcDir) ? xbmcDir : defaultDir,
-        FileName = "usb_2548_1001.xml",
+        InitialDirectory = xbmcDir,
+        FileName = string.Format("usb_{0:X}_{1:X}.xml", Program.Instance.Controller.AdapterVendorId, Program.Instance.Controller.AdapterProductId),
         Filter = Resources.xml_file_filter,
         FilterIndex = 1
       };
@@ -236,7 +319,7 @@ namespace LibCECTray.controller.applications.@internal
         StringBuilder output = new StringBuilder();
         output.AppendLine("<settings>");
         output.AppendLine("<setting id=\"cec_hdmi_port\" value=\"" + Settings.HDMIPort.Value + "\" />");
-        output.AppendLine("<setting id=\"connected_device\" value=\"" + (Settings.ConnectedDevice.Value == CecLogicalAddress.AudioSystem ? 5 : 0) + "\" />");
+        output.AppendLine("<setting id=\"connected_device\" value=\"" + (Settings.ConnectedDevice.Value == CecLogicalAddress.AudioSystem ? 36038 : 36037) + "\" />");
         output.AppendLine("<setting id=\"cec_power_on_startup\" value=\"" + (Settings.ActivateSource.Value ? 1 : 0) + "\" />");
         output.AppendLine("<setting id=\"cec_power_off_shutdown\" value=\"" + (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Broadcast) ? 1 : 0) + "\" />");
         output.AppendLine("<setting id=\"cec_standby_screensaver\" value=\"" + (StandbyScreensaver.Value ? 1 : 0) + "\" />");
@@ -252,26 +335,54 @@ namespace LibCECTray.controller.applications.@internal
         output.AppendLine("<setting id=\"device_type\" value=\"" + (int)Settings.DeviceType.Value + "\" />");
         output.AppendLine("<setting id=\"tv_vendor\" value=\"" + string.Format("{0,6:X}", Settings.OverrideTVVendor.Value ? (int)Settings.TVVendor.Value : 0).Trim() + "\" />");
 
-        output.Append("<setting id=\"wake_devices\" value=\"");
-        StringBuilder strWakeDevices = new StringBuilder();
-        foreach (CecLogicalAddress addr in Settings.WakeDevices.Value.Addresses)
-          if (addr != CecLogicalAddress.Unknown)
-            strWakeDevices.Append(" " + (int)addr);
-        output.Append(strWakeDevices.ToString().Trim());
-        output.AppendLine("\" />");
+        if (HasAdvancedDeviceIdSet(Settings.WakeDevices.Value))
+        {
+          output.Append("<setting id=\"wake_devices_advanced\" value=\"");
+          StringBuilder strWakeDevices = new StringBuilder();
+          foreach (CecLogicalAddress addr in Settings.WakeDevices.Value.Addresses)
+            if (addr != CecLogicalAddress.Unknown)
+              strWakeDevices.Append(" " + (int)addr);
+          output.Append(strWakeDevices.ToString().Trim());
+          output.AppendLine("\" />");
+        }
+
+        if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.Tv) &&
+            Settings.WakeDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
+          output.Append("<setting id=\"wake_devices\" value=\"36039\">");
+        else if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.Tv))
+          output.Append("<setting id=\"wake_devices\" value=\"36037\">");
+        else if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
+          output.Append("<setting id=\"wake_devices\" value=\"36038\">");
+        else
+          output.Append("<setting id=\"wake_devices\" value=\"231\">");
 
-        output.Append("<setting id=\"standby_devices\" value=\"");
-        StringBuilder strSleepDevices = new StringBuilder();
-        foreach (CecLogicalAddress addr in Settings.PowerOffDevices.Value.Addresses)
-          if (addr != CecLogicalAddress.Unknown)
-            strSleepDevices.Append(" " + (int)addr);
-        output.Append(strSleepDevices.ToString().Trim());
-        output.AppendLine("\" />");
+        if (HasAdvancedDeviceIdSet(Settings.PowerOffDevices.Value))
+        {
+          output.Append("<setting id=\"standby_devices_advanced\" value=\"");
+          StringBuilder strSleepDevices = new StringBuilder();
+          foreach (CecLogicalAddress addr in Settings.PowerOffDevices.Value.Addresses)
+            if (addr != CecLogicalAddress.Unknown)
+              strSleepDevices.Append(" " + (int) addr);
+          output.Append(strSleepDevices.ToString().Trim());
+          output.AppendLine("\" />");
+        }
+
+        if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Tv) &&
+            Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
+          output.Append("<setting id=\"standby_devices\" value=\"36039\">");
+        else if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Tv))
+          output.Append("<setting id=\"standby_devices\" value=\"36037\">");
+        else if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
+          output.Append("<setting id=\"standby_devices\" value=\"36038\">");
+        else
+          output.Append("<setting id=\"standby_devices\" value=\"231\">");
 
         // only supported by 1.5.1+ clients
         output.AppendLine("<!-- the following lines are only supported by v1.5.1+ clients -->");
-        //TODO
-        //output.AppendLine("<setting id=\"send_inactive_source\" value=\"" + (config.SendInactiveSource ? 1 : 0) + "\" />");
+        output.AppendLine("<setting id=\"send_inactive_source\" value=\"" + (SendInactiveSource.Value ? 1 : 0) + "\" />");
+
+        // only supported by 1.9.0+ clients
+        output.AppendLine("<setting id=\"pause_playback_on_deactivate\" value=\"" + (PausePlaybackOnDeactivate.Value ? 1 : 0) + "\" />");
 
         output.AppendLine("</settings>");
         writer.Write(output.ToString());
@@ -351,5 +462,19 @@ namespace LibCECTray.controller.applications.@internal
         return Settings[ProcessName + "_send_inactive_source"].AsSettingBool;
       }
     }
+
+    public CECSettingBool PausePlaybackOnDeactivate
+    {
+      get
+      {
+        if (!Settings.ContainsKey(ProcessName + "_pause_playback_on_deactivate"))
+        {
+          CECSettingBool setting = new CECSettingBool(ProcessName + "_pause_playback_on_deactivate", Resources.app_pause_playback_on_deactivate, true, null);
+          Settings.Load(setting);
+          Settings[ProcessName + "_pause_playback_on_deactivate"] = setting;
+        }
+        return Settings[ProcessName + "_pause_playback_on_deactivate"].AsSettingBool;
+      }
+    }
        }
 }