diff --git a/Action/Command.cs b/Action/Command.cs new file mode 100644 index 00000000..ae3cfc07 --- /dev/null +++ b/Action/Command.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace XiboClient.Logic +{ + [Serializable] + public class Command + { + public string Code; + public string CommandString; + public string Validation; + + public bool notifyStatus() + { + return !string.IsNullOrEmpty(Validation); + } + + /// + /// Run the Command + /// + /// true on success + public bool Run() + { + if (string.IsNullOrEmpty(CommandString)) + throw new ArgumentNullException("Command string is empty, please check your Display Profile " + Code + " command for a valid command string."); + + // Parse the command string to work out how we should run this command. + if (CommandString.StartsWith("rs232")) + { + Rs232Command rs232 = new Rs232Command(this); + string line = rs232.Run(); + + if (notifyStatus()) + { + return line == Validation; + } + else + { + return true; + } + } + else + { + // Process with CMD + using (Process process = new Process()) + { + ProcessStartInfo startInfo = new ProcessStartInfo(); + + startInfo.CreateNoWindow = true; + startInfo.WindowStyle = ProcessWindowStyle.Hidden; + startInfo.FileName = "cmd.exe"; + startInfo.Arguments = "/C " + CommandString; + startInfo.UseShellExecute = false; + + if (notifyStatus()) + startInfo.RedirectStandardOutput = true; + + process.StartInfo = startInfo; + process.Start(); + + if (notifyStatus()) + { + string line = ""; + while (!process.StandardOutput.EndOfStream) + { + line += process.StandardOutput.ReadLine(); + } + + return line == Validation; + } + else + return true; + } + } + } + + /// + /// Get a command from Application Settings based on its Command Code + /// + /// + /// + public static Command GetByCode(string code) + { + foreach (Command command in ApplicationSettings.Default.Commands) + { + if (command.Code == code) + return command; + } + + throw new KeyNotFoundException("Command Not Found"); + } + } +} diff --git a/Action/PlayerAction.cs b/Action/PlayerAction.cs new file mode 100644 index 00000000..7b0ae634 --- /dev/null +++ b/Action/PlayerAction.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace XiboClient.Action +{ + class PlayerAction + { + public string action; + + public DateTime createdDt; + public int ttl; + } +} diff --git a/Action/Rs232Command.cs b/Action/Rs232Command.cs new file mode 100644 index 00000000..7b17912f --- /dev/null +++ b/Action/Rs232Command.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO.Ports; +using System.Linq; +using System.Text; + +namespace XiboClient.Logic +{ + public class Rs232Command + { + private Command _command; + + private SerialPort _port; + private string _toSend; + + public Rs232Command(Command command) + { + _command = command; + } + + /// + /// Run the command + /// + public string Run() + { + string response = ""; + + // Parse and configure the port + parse(); + + // try to open the COM port + if (!_port.IsOpen) + _port.Open(); + + try + { + // Write our data stream + _port.Write(_toSend); + + // Read + if (_command.notifyStatus()) + { + _port.ReadTimeout = 5000; + response = _port.ReadLine(); + } + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("CommandRs232 - run", e.Message), LogType.Error.ToString()); + } + finally + { + // Close the port + _port.Close(); + } + + return response; + } + + /// + /// Parses the command string + /// + private void parse() + { + if (!_command.CommandString.StartsWith("rs232")) + throw new ArgumentException("Not a RS232 command"); + + // Split the command string by "space" + string[] command = _command.CommandString.Split('|'); + + // The second part of the string is our comma separated connection string + // Port,Baud,Data,Parity,Stop,Flow + string[] connection = command[1].Split(','); + + _port = new SerialPort(); + _port.PortName = connection[0]; + _port.BaudRate = Convert.ToInt32(connection[1]); + _port.DataBits = Convert.ToInt16(connection[2]); + _port.Parity = (Parity)Enum.Parse(typeof(Parity), connection[3]); + _port.StopBits = (StopBits)Enum.Parse(typeof(StopBits), connection[4]); + _port.Handshake = (Handshake)Enum.Parse(typeof(Handshake), connection[5]); + + // Get the actual command to send + _toSend = command[2]; + } + } +} diff --git a/Action/ScheduleCommand.cs b/Action/ScheduleCommand.cs new file mode 100644 index 00000000..8e93e7e3 --- /dev/null +++ b/Action/ScheduleCommand.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace XiboClient.Logic +{ + public class ScheduleCommand + { + public DateTime Date { get; set; } + public String Code { get; set; } + public Command Command { get; set; } + public int ScheduleId { get; set; } + + private bool _run = false; + public bool HasRun + { + get + { + return _run; + } + set + { + _run = value; + } + } + + public void Run() + { + bool success; + + try + { + // Get a fresh command from settings + Command = Command.GetByCode(Code); + + // Run the command. + success = Command.Run(); + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("CommandSchedule - Run", "Cannot start Run Command: " + e.Message), LogType.Error.ToString()); + success = false; + } + + // Notify the state of the command (success or failure) + using (xmds.xmds statusXmds = new xmds.xmds()) + { + statusXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds; + statusXmds.NotifyStatusAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, "{\"lastCommandSuccess\":" + success + "}"); + } + } + } +} diff --git a/Action/XmrSubscriber.cs b/Action/XmrSubscriber.cs new file mode 100644 index 00000000..33c9f8e6 --- /dev/null +++ b/Action/XmrSubscriber.cs @@ -0,0 +1,161 @@ +using NetMQ; +using NetMQ.Sockets; +using Newtonsoft.Json; +using Org.BouncyCastle.Crypto; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using XiboClient.Action; +using XiboClient.Log; + +namespace XiboClient.Logic +{ + class XmrSubscriber + { + public static object _locker = new object(); + + // Members to stop the thread + private bool _forceStop = false; + + /// + /// Last Heartbeat packet received + /// + public DateTime LastHeartBeat = DateTime.MinValue; + + // Events + public delegate void OnCollectNowActionDelegate(); + public event OnCollectNowActionDelegate OnCollectNowAction; + + /// + /// Client Hardware key + /// + public HardwareKey HardwareKey + { + set + { + _hardwareKey = value; + } + } + private HardwareKey _hardwareKey; + + /// + /// Client Info Form + /// + public ClientInfo ClientInfoForm + { + set + { + _clientInfoForm = value; + } + } + private ClientInfo _clientInfoForm; + + /// + /// Runs the agent + /// + public void Run() + { + try + { + // Check we have an address to connect to. + if (string.IsNullOrEmpty(ApplicationSettings.Default.XmrNetworkAddress)) + throw new Exception("Empty XMR Network Address"); + + // Get the Private Key + AsymmetricCipherKeyPair rsaKey = _hardwareKey.getXmrKey(); + + // Connect to XMR + using (NetMQContext context = NetMQContext.Create()) + { + using (SubscriberSocket socket = context.CreateSubscriberSocket()) + { + // Bind + socket.Connect(ApplicationSettings.Default.XmrNetworkAddress); + socket.Subscribe("H"); + socket.Subscribe(_hardwareKey.Channel); + + // Notify + _clientInfoForm.XmrSubscriberStatus = "Connected to " + ApplicationSettings.Default.XmrNetworkAddress; + + while (!_forceStop) + { + lock (_locker) + { + try + { + NetMQMessage message = socket.ReceiveMultipartMessage(); + + // Update status + _clientInfoForm.XmrSubscriberStatus = "Connected (" + ApplicationSettings.Default.XmrNetworkAddress + "), last activity: " + DateTime.Now.ToString(); + + // Deal with heart beat + if (message[0].ConvertToString() == "H") + { + LastHeartBeat = DateTime.Now; + continue; + } + + // Decrypt the message + string opened = OpenSslInterop.decrypt(message[2].ConvertToString(), message[1].ConvertToString(), rsaKey.Private); + + // Decode into a JSON string + PlayerAction action = JsonConvert.DeserializeObject(opened); + + // Make sure the TTL hasn't expired + if (DateTime.Now > action.createdDt.AddSeconds(action.ttl)) + { + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Expired Message: " + action.action), LogType.Info.ToString()); + continue; + } + + // Decide what to do with the message, probably raise events according to the type of message we have + switch (action.action) + { + case "commandAction": + + // Create a schedule command out of the message + Dictionary obj = JsonConvert.DeserializeObject>(opened); + ScheduleCommand command = new ScheduleCommand(); + string code; + obj.TryGetValue("commandCode", out code); + command.Code = code; + + new Thread(new ThreadStart(command.Run)).Start(); + break; + + case "collectNow": + OnCollectNowAction(); + break; + + default: + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Unknown Message: " + action.action), LogType.Info.ToString()); + break; + } + } + catch (Exception ex) + { + // Log this message, but dont abort the thread + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString()); + _clientInfoForm.XmrSubscriberStatus = "Error. " + ex.Message; + } + } + } + } + } + + // Update status + _clientInfoForm.XmrSubscriberStatus = "Not Running, last activity: " + LastHeartBeat.ToString(); + + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Subscriber Stopped"), LogType.Info.ToString()); + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Unable to Subscribe to XMR: " + e.Message), LogType.Error.ToString()); + _clientInfoForm.XmrSubscriberStatus = e.Message; + } + } + } +} diff --git a/Forms/OptionForm.cs b/Forms/OptionForm.cs index 9010a4b1..d186072d 100644 --- a/Forms/OptionForm.cs +++ b/Forms/OptionForm.cs @@ -133,7 +133,17 @@ private void buttonSaveSettings_Click(object sender, EventArgs e) ApplicationSettings.Default.Save(); // Call register - xmds1.RegisterDisplayAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, ApplicationSettings.Default.DisplayName, "windows", ApplicationSettings.Default.ClientVersion, ApplicationSettings.Default.ClientCodeVersion, Environment.OSVersion.ToString(), _hardwareKey.MacAddress, ApplicationSettings.Default.Version); + xmds1.RegisterDisplayAsync( + ApplicationSettings.Default.ServerKey, + ApplicationSettings.Default.HardwareKey, + ApplicationSettings.Default.DisplayName, + "windows", + ApplicationSettings.Default.ClientVersion, + ApplicationSettings.Default.ClientCodeVersion, + Environment.OSVersion.ToString(), + _hardwareKey.MacAddress, + _hardwareKey.Channel, + _hardwareKey.getXmrPublicKey()); } catch (Exception ex) { diff --git a/Log/ClientInfo.Designer.cs b/Log/ClientInfo.Designer.cs index fed61e07..db995695 100644 --- a/Log/ClientInfo.Designer.cs +++ b/Log/ClientInfo.Designer.cs @@ -46,6 +46,8 @@ private void InitializeComponent() this.scheduleManagerStatus = new System.Windows.Forms.TextBox(); this.saveLogToDisk = new System.Windows.Forms.Button(); this.saveFileDialog = new System.Windows.Forms.SaveFileDialog(); + this.label3 = new System.Windows.Forms.Label(); + this.xmrStatus = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.logDataGridView)).BeginInit(); this.SuspendLayout(); // @@ -137,7 +139,7 @@ private void InitializeComponent() // scheduleStatusLabel // this.scheduleStatusLabel.AutoSize = true; - this.scheduleStatusLabel.Location = new System.Drawing.Point(148, 11); + this.scheduleStatusLabel.Location = new System.Drawing.Point(103, 11); this.scheduleStatusLabel.Name = "scheduleStatusLabel"; this.scheduleStatusLabel.Size = new System.Drawing.Size(61, 13); this.scheduleStatusLabel.TabIndex = 2; @@ -195,11 +197,31 @@ private void InitializeComponent() // this.saveFileDialog.FileOk += new System.ComponentModel.CancelEventHandler(this.saveFileDialog_FileOk); // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(103, 734); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(67, 13); + this.label3.TabIndex = 10; + this.label3.Text = "XMR Status:"; + // + // xmrStatus + // + this.xmrStatus.AutoSize = true; + this.xmrStatus.Location = new System.Drawing.Point(176, 734); + this.xmrStatus.Name = "xmrStatus"; + this.xmrStatus.Size = new System.Drawing.Size(61, 13); + this.xmrStatus.TabIndex = 11; + this.xmrStatus.Text = "Not Started"; + // // ClientInfo // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(810, 758); + this.Controls.Add(this.xmrStatus); + this.Controls.Add(this.label3); this.Controls.Add(this.saveLogToDisk); this.Controls.Add(this.scheduleManagerStatus); this.Controls.Add(this.requiredFilesTextBox); @@ -233,5 +255,7 @@ private void InitializeComponent() private System.Windows.Forms.TextBox scheduleManagerStatus; private System.Windows.Forms.Button saveLogToDisk; private System.Windows.Forms.SaveFileDialog saveFileDialog; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label xmrStatus; } } \ No newline at end of file diff --git a/Log/ClientInfo.cs b/Log/ClientInfo.cs index 13f4b14b..35a52dd4 100644 --- a/Log/ClientInfo.cs +++ b/Log/ClientInfo.cs @@ -89,6 +89,24 @@ public string CurrentLayoutId } } + /// + /// XMR Status + /// + public string XmrSubscriberStatus + { + set + { + if (InvokeRequired) + { + BeginInvoke(new StatusDelegate(SetXmrStatus), value); + } + else + { + SetXmrStatus(value); + } + } + } + /// /// Client Info Object /// @@ -150,6 +168,15 @@ public void SetCurrentlyPlaying(string layoutName) Text = "Client Information and Status - " + ApplicationSettings.Default.ServerUri + " - Currently Showing: " + layoutName; } + /// + /// Sets the XMR Status + /// + /// + public void SetXmrStatus(string status) + { + xmrStatus.Text = status; + } + /// /// Adds a log message /// diff --git a/Logic/ApplicationSettings.cs b/Logic/ApplicationSettings.cs index 52a06a0a..93087ae2 100644 --- a/Logic/ApplicationSettings.cs +++ b/Logic/ApplicationSettings.cs @@ -26,6 +26,7 @@ using System.Text; using System.Windows.Forms; using System.Xml.Serialization; +using XiboClient.Logic; namespace XiboClient { @@ -38,7 +39,7 @@ public class ApplicationSettings // Application Specific Settings we want to protect private string _clientVersion = "1.7.5"; - private string _version = "4"; + private string _version = "5"; private int _clientCodeVersion = 109; public string ClientVersion { get { return _clientVersion; } } @@ -161,6 +162,7 @@ public object this[string propertyName] public string LogToDiskLocation { get; set; } public string CursorStartPosition { get; set; } public string ClientInformationKeyCode { get; set; } + public string XmrNetworkAddress { get; set; } // Download window @@ -286,6 +288,8 @@ public void IncrementXmdsErrorCount() }; } + public List Commands { get; set; } + // Settings HASH public string Hash { get; set; } } diff --git a/Logic/HardwareKey.cs b/Logic/HardwareKey.cs index ea5dfbc7..20a74e6a 100644 --- a/Logic/HardwareKey.cs +++ b/Logic/HardwareKey.cs @@ -23,6 +23,12 @@ using System.Management; using System.Text; using System.Diagnostics; +using System.Security.Cryptography; +using System.Windows.Forms; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.OpenSsl; +using System.IO; namespace XiboClient { @@ -32,6 +38,26 @@ class HardwareKey private string _hardwareKey; private string _macAddress; + private string _channel; + + public string Channel + { + get + { + if (String.IsNullOrEmpty(_channel)) + { + // Channel is based on the CMS URL, CMS Key and Hardware Key + _channel = Hashes.MD5(ApplicationSettings.Default.ServerUri + ApplicationSettings.Default.ServerKey + _hardwareKey); + } + + return _channel; + } + } + + public void clearChannel() + { + _channel = null; + } public string MacAddress { @@ -171,5 +197,40 @@ public string GetCPUId() return cpuInfo; } } + + /// + /// Get the XMR public key + /// + /// + public AsymmetricCipherKeyPair getXmrKey() + { + const int PROVIDER_RSA_FULL = 1; + CspParameters cspParams; + cspParams = new CspParameters(PROVIDER_RSA_FULL); + cspParams.KeyContainerName = Application.ProductName + "RsaKey"; + cspParams.Flags = CspProviderFlags.UseMachineKeyStore; + cspParams.ProviderName = "Microsoft Strong Cryptographic Provider"; + + using (RSACryptoServiceProvider provider = new RSACryptoServiceProvider(cspParams)) + { + RSAParameters keyInfo = provider.ExportParameters(true); + + return DotNetUtilities.GetRsaKeyPair(keyInfo); + } + } + + public string getXmrPublicKey() + { + AsymmetricCipherKeyPair key = getXmrKey(); + + using (TextWriter textWriter = new StringWriter()) + { + PemWriter writer = new PemWriter(textWriter); + writer.WriteObject(key.Public); + writer.Writer.Flush(); + + return textWriter.ToString(); + } + } } } diff --git a/Logic/OpenSslInterop.cs b/Logic/OpenSslInterop.cs new file mode 100644 index 00000000..3f073b54 --- /dev/null +++ b/Logic/OpenSslInterop.cs @@ -0,0 +1,32 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace XiboClient.Logic +{ + public class OpenSslInterop + { + public static string decrypt(string cypherText, string cypherKey, AsymmetricKeyParameter privateKey) + { + // Create a RSA cypher + IBufferedCipher rsaCipher = CipherUtilities.GetCipher("RSA//PKCS1PADDING"); + rsaCipher.Init(false, privateKey); + + // Get the decrypted key + byte[] key = rsaCipher.DoFinal(Convert.FromBase64String(cypherKey)); + + // Use this Key to decrypt the main message + IBufferedCipher rsaKeyCipher = CipherUtilities.GetCipher("RC4"); + KeyParameter parameter = new KeyParameter(key); + rsaKeyCipher.Init(false, parameter); + + byte[] opened = rsaKeyCipher.DoFinal(Convert.FromBase64String(cypherText)); + + return Encoding.ASCII.GetString(opened); + } + } +} diff --git a/Logic/Schedule.cs b/Logic/Schedule.cs index b767c8d5..6f9e3ddb 100644 --- a/Logic/Schedule.cs +++ b/Logic/Schedule.cs @@ -31,6 +31,7 @@ using System.Threading; using XiboClient.Properties; using XiboClient.Log; +using XiboClient.Logic; /// 17/02/12 Dan Removed Schedule call, introduced ScheduleAgent /// 21/02/12 Dan Named the threads @@ -81,6 +82,10 @@ class Schedule private LogAgent _logAgent; Thread _logAgentThread; + // XMR Subscriber + private XmrSubscriber _xmrSubscriber; + Thread _xmrSubscriberThread; + /// /// Client Info Form /// @@ -111,6 +116,7 @@ public Schedule(string scheduleLocation, ref CacheManager cacheManager, ref Clie // Create a Register Agent _registerAgent = new RegisterAgent(); + _registerAgent.OnXmrReconfigure += _registerAgent_OnXmrReconfigure; _registerAgentThread = new Thread(new ThreadStart(_registerAgent.Run)); _registerAgentThread.Name = "RegisterAgentThread"; @@ -118,6 +124,7 @@ public Schedule(string scheduleLocation, ref CacheManager cacheManager, ref Clie _scheduleManager = new ScheduleManager(_cacheManager, scheduleLocation); _scheduleManager.OnNewScheduleAvailable += new ScheduleManager.OnNewScheduleAvailableDelegate(_scheduleManager_OnNewScheduleAvailable); _scheduleManager.OnRefreshSchedule += new ScheduleManager.OnRefreshScheduleDelegate(_scheduleManager_OnRefreshSchedule); + _scheduleManager.OnScheduleManagerCheckComplete += _scheduleManager_OnScheduleManagerCheckComplete; _scheduleManager.ClientInfoForm = _clientInfoForm; // Create a schedule manager thread @@ -158,6 +165,16 @@ public Schedule(string scheduleLocation, ref CacheManager cacheManager, ref Clie _logAgent = new LogAgent(); _logAgentThread = new Thread(new ThreadStart(_logAgent.Run)); _logAgentThread.Name = "LogAgent"; + + // XMR Subscriber + _xmrSubscriber = new XmrSubscriber(); + _xmrSubscriber.HardwareKey = _hardwareKey; + _xmrSubscriber.ClientInfoForm = _clientInfoForm; + _xmrSubscriber.OnCollectNowAction += _xmrSubscriber_OnCollectNowAction; + + // Thread start + _xmrSubscriberThread = new Thread(new ThreadStart(_xmrSubscriber.Run)); + _xmrSubscriberThread.Name = "XmrSubscriber"; } /// @@ -182,6 +199,9 @@ public void InitializeComponents() // Start the LogAgent thread _logAgentThread.Start(); + + // Start the subscriber thread + _xmrSubscriberThread.Start(); } /// @@ -206,6 +226,77 @@ void _scheduleManager_OnRefreshSchedule() _layoutSchedule = _scheduleManager.CurrentSchedule; } + /// + /// Schedule Manager has completed a cycle + /// + void _scheduleManager_OnScheduleManagerCheckComplete() + { + try + { + // See if XMR should be running + if (!string.IsNullOrEmpty(ApplicationSettings.Default.XmrNetworkAddress) && _xmrSubscriber.LastHeartBeat != DateTime.MinValue) + { + // Check to see if the last update date was over 5 minutes ago + if (_xmrSubscriber.LastHeartBeat < DateTime.Now.AddSeconds(-90)) + { + // Reconfigure it + _registerAgent_OnXmrReconfigure(); + } + } + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("Schedule - OnScheduleManagerCheckComplete", "Error = " + e.Message), LogType.Error.ToString()); + } + } + + /// + /// XMR Reconfigure + /// + void _registerAgent_OnXmrReconfigure() + { + try + { + // Stop and start the XMR thread + if (_xmrSubscriberThread != null && _xmrSubscriberThread.IsAlive) + { + _xmrSubscriberThread.Abort(); + } + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("Schedule - OnXmrReconfigure", "Unable to abort Subscriber. " + e.Message), LogType.Error.ToString()); + } + + try + { + // Reassert the hardware key, incase its changed at all + _xmrSubscriber.HardwareKey = _hardwareKey; + + // Start the thread again + _xmrSubscriberThread = new Thread(new ThreadStart(_xmrSubscriber.Run)); + _xmrSubscriberThread.Name = "XmrSubscriber"; + + _xmrSubscriberThread.Start(); + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("Schedule - OnXmrReconfigure", "Unable to start Subscriber. " + e.Message), LogType.Error.ToString()); + } + } + + /// + /// Collect Now Action + /// + void _xmrSubscriber_OnCollectNowAction() + { + // Run all of the various agents + _registerAgent.WakeUp(); + _scheduleAgent.WakeUp(); + _requiredFilesAgent.WakeUp(); + _logAgent.WakeUp(); + } + /// /// Moves the layout on /// @@ -315,6 +406,9 @@ public void Stop() // Stop the LogAgent Thread _logAgent.Stop(); + + // Stop the subsriber thread + _xmrSubscriberThread.Abort(); } } } diff --git a/Logic/ScheduleManager.cs b/Logic/ScheduleManager.cs index fbaf791b..8970c5bb 100644 --- a/Logic/ScheduleManager.cs +++ b/Logic/ScheduleManager.cs @@ -57,10 +57,16 @@ class ScheduleManager public delegate void OnRefreshScheduleDelegate(); public event OnRefreshScheduleDelegate OnRefreshSchedule; + // Event for Subscriber inactive + public delegate void OnScheduleManagerCheckCompleteDelegate(); + public event OnScheduleManagerCheckCompleteDelegate OnScheduleManagerCheckComplete; + // Member Varialbes private string _location; private Collection _layoutSchedule; private Collection _currentSchedule; + private Collection _commands; + private bool _refreshSchedule; private CacheManager _cacheManager; private DateTime _lastScreenShotDate; @@ -89,6 +95,7 @@ public ScheduleManager(CacheManager cacheManager, string scheduleLocation) // Create an empty layout schedule _layoutSchedule = new Collection(); _currentSchedule = new Collection(); + _commands = new Collection(); _lastScreenShotDate = DateTime.MinValue; } @@ -182,6 +189,29 @@ public void Run() _lastScreenShotDate = DateTime.Now; } + // Run any commands that occur in the next 10 seconds. + DateTime now = DateTime.Now; + DateTime tenSecondsTime = now.AddSeconds(10); + + foreach (ScheduleCommand command in _commands) + { + if (command.Date >= now && command.Date < tenSecondsTime && !command.HasRun) + { + try + { + // We need to run this command + new Thread(new ThreadStart(command.Run)).Start(); + + // Mark run + command.HasRun = true; + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("ScheduleManager - Run", "Cannot start Thread to Run Command: " + e.Message), LogType.Error.ToString()); + } + } + } + // Write a flag to the status.xml file File.WriteAllText(Path.Combine(ApplicationSettings.Default.LibraryPath, "status.json"), "{\"lastActivity\":\"" + DateTime.Now.ToString() + "\"}"); } @@ -193,6 +223,9 @@ public void Run() } } + // Completed this check + OnScheduleManagerCheckComplete(); + // Sleep this thread for 10 seconds _manualReset.WaitOne(10 * 1000); } @@ -341,6 +374,9 @@ private void LoadScheduleFromFile() // Empty the current schedule collection _layoutSchedule.Clear(); + // Clear the list of commands + _commands.Clear(); + // Get the schedule XML XmlDocument scheduleXml = GetScheduleXml(); @@ -366,6 +402,27 @@ private void LoadScheduleFromFile() { // Do nothing for now } + else if (temp.NodeName == "command") + { + // Try to get the command using the code + try + { + // Pull attributes from layout nodes + XmlAttributeCollection attributes = node.Attributes; + + ScheduleCommand command = new ScheduleCommand(); + command.Date = DateTime.Parse(attributes["date"].Value, CultureInfo.InvariantCulture); + command.Code = attributes["code"].Value; + command.ScheduleId = int.Parse(attributes["scheduleid"].Value); + + // Add to the collection + _commands.Add(command); + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("ScheduleManager - LoadScheduleFromFile", e.Message), LogType.Error.ToString()); + } + } else { // Pull attributes from layout nodes diff --git a/Media/ShellCommand.cs b/Media/ShellCommand.cs index 7189a403..423b67bb 100644 --- a/Media/ShellCommand.cs +++ b/Media/ShellCommand.cs @@ -22,61 +22,95 @@ using System.Text; using System.Diagnostics; using XiboClient.Properties; +using XiboClient.Logic; namespace XiboClient { class ShellCommand : Media { string _command = ""; + string _code = ""; public ShellCommand(RegionOptions options) : base(options.width, options.height, options.top, options.left) { _command = Uri.UnescapeDataString(options.Dictionary.Get("windowsCommand")).Replace('+', ' '); + _code = options.Dictionary.Get("commandCode"); } public override void RenderMedia() { - // Is this module enabled? - if (ApplicationSettings.Default.EnableShellCommands) + if (!string.IsNullOrEmpty(_code)) { - // Check to see if we have an allow list - if (!string.IsNullOrEmpty(ApplicationSettings.Default.ShellCommandAllowList)) + // Stored command + bool success; + + try + { + Command command = Command.GetByCode(_code); + success = command.Run(); + } + catch (Exception e) { - // Array of allowed commands - string[] allowedCommands = ApplicationSettings.Default.ShellCommandAllowList.Split(','); + Trace.WriteLine(new LogMessage("ScheduleManager - Run", "Cannot run Command: " + e.Message), LogType.Error.ToString()); + success = false; + } - // Check we are allowed to execute the command - bool found = false; + // Notify the state of the command (success or failure) + using (xmds.xmds statusXmds = new xmds.xmds()) + { + statusXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds; + statusXmds.NotifyStatusAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, "{\"lastCommandSuccess\":" + success + "}"); + } + } + else + { + // shell command - foreach (string allowedCommand in allowedCommands) + // Is this module enabled? + if (ApplicationSettings.Default.EnableShellCommands) + { + // Check to see if we have an allow list + if (!string.IsNullOrEmpty(ApplicationSettings.Default.ShellCommandAllowList)) { - if (_command.StartsWith(allowedCommand)) + // Array of allowed commands + string[] allowedCommands = ApplicationSettings.Default.ShellCommandAllowList.Split(','); + + // Check we are allowed to execute the command + bool found = false; + + foreach (string allowedCommand in allowedCommands) { - found = true; - ExecuteShellCommand(); - break; + if (_command.StartsWith(allowedCommand)) + { + found = true; + ExecuteShellCommand(); + break; + } } - } - if (!found) - Trace.WriteLine(new LogMessage("ShellCommand - RenderMedia", "Shell Commands not in allow list: " + ApplicationSettings.Default.ShellCommandAllowList), LogType.Error.ToString()); + if (!found) + Trace.WriteLine(new LogMessage("ShellCommand - RenderMedia", "Shell Commands not in allow list: " + ApplicationSettings.Default.ShellCommandAllowList), LogType.Error.ToString()); + } + else + { + // All commands are allowed + ExecuteShellCommand(); + } } else { - // All commands are allowed - ExecuteShellCommand(); + Trace.WriteLine(new LogMessage("ShellCommand - RenderMedia", "Shell Commands are disabled"), LogType.Error.ToString()); } } - else - { - Trace.WriteLine(new LogMessage("ShellCommand - RenderMedia", "Shell Commands are disabled"), LogType.Error.ToString()); - } // All shell commands have a duration of 1 base.RenderMedia(); } + /// + /// Execute the shell command + /// private void ExecuteShellCommand() { Trace.WriteLine(new LogMessage("ShellCommand - ExecuteShellCommand", _command), LogType.Info.ToString()); diff --git a/Web References/xmds/Reference.cs b/Web References/xmds/Reference.cs index 6e46e00e..e6c5e8c5 100644 --- a/Web References/xmds/Reference.cs +++ b/Web References/xmds/Reference.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// Runtime Version:4.0.30319.34209 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -9,7 +9,7 @@ //------------------------------------------------------------------------------ // -// This source code was auto-generated by Microsoft.VSDesigner, Version 4.0.30319.18444. +// This source code was auto-generated by Microsoft.VSDesigner, Version 4.0.30319.34209. // #pragma warning disable 1591 @@ -23,7 +23,7 @@ namespace XiboClient.xmds { /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Web.Services.WebServiceBindingAttribute(Name="xmdsBinding", Namespace="urn:xmds")] @@ -55,7 +55,7 @@ public partial class xmds : System.Web.Services.Protocols.SoapHttpClientProtocol /// public xmds() { - this.Url = "http://172.28.128.3/xmds.php?v=4"; + this.Url = "http://192.168.0.28/xmds.php?v=5"; if ((this.IsLocalFileSystemWebService(this.Url) == true)) { this.UseDefaultCredentials = true; this.useDefaultCredentialsSetExplicitly = false; @@ -125,7 +125,7 @@ public xmds() { /// [System.Web.Services.Protocols.SoapRpcMethodAttribute("urn:xmds#RegisterDisplay", RequestNamespace="urn:xmds", ResponseNamespace="urn:xmds")] [return: System.Xml.Serialization.SoapElementAttribute("ActivationMessage")] - public string RegisterDisplay(string serverKey, string hardwareKey, string displayName, string clientType, string clientVersion, int clientCode, string operatingSystem, string macAddress) { + public string RegisterDisplay(string serverKey, string hardwareKey, string displayName, string clientType, string clientVersion, int clientCode, string operatingSystem, string macAddress, string xmrChannel, string xmrPubKey) { object[] results = this.Invoke("RegisterDisplay", new object[] { serverKey, hardwareKey, @@ -134,17 +134,19 @@ public string RegisterDisplay(string serverKey, string hardwareKey, string displ clientVersion, clientCode, operatingSystem, - macAddress}); + macAddress, + xmrChannel, + xmrPubKey}); return ((string)(results[0])); } /// - public void RegisterDisplayAsync(string serverKey, string hardwareKey, string displayName, string clientType, string clientVersion, int clientCode, string operatingSystem, string macAddress) { - this.RegisterDisplayAsync(serverKey, hardwareKey, displayName, clientType, clientVersion, clientCode, operatingSystem, macAddress, null); + public void RegisterDisplayAsync(string serverKey, string hardwareKey, string displayName, string clientType, string clientVersion, int clientCode, string operatingSystem, string macAddress, string xmrChannel, string xmrPubKey) { + this.RegisterDisplayAsync(serverKey, hardwareKey, displayName, clientType, clientVersion, clientCode, operatingSystem, macAddress, xmrChannel, xmrPubKey, null); } /// - public void RegisterDisplayAsync(string serverKey, string hardwareKey, string displayName, string clientType, string clientVersion, int clientCode, string operatingSystem, string macAddress, object userState) { + public void RegisterDisplayAsync(string serverKey, string hardwareKey, string displayName, string clientType, string clientVersion, int clientCode, string operatingSystem, string macAddress, string xmrChannel, string xmrPubKey, object userState) { if ((this.RegisterDisplayOperationCompleted == null)) { this.RegisterDisplayOperationCompleted = new System.Threading.SendOrPostCallback(this.OnRegisterDisplayOperationCompleted); } @@ -156,7 +158,9 @@ public void RegisterDisplayAsync(string serverKey, string hardwareKey, string di clientVersion, clientCode, operatingSystem, - macAddress}, this.RegisterDisplayOperationCompleted, userState); + macAddress, + xmrChannel, + xmrPubKey}, this.RegisterDisplayOperationCompleted, userState); } private void OnRegisterDisplayOperationCompleted(object arg) { @@ -536,11 +540,11 @@ private bool IsLocalFileSystemWebService(string url) { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void RegisterDisplayCompletedEventHandler(object sender, RegisterDisplayCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class RegisterDisplayCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -562,11 +566,11 @@ public string Result { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void RequiredFilesCompletedEventHandler(object sender, RequiredFilesCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class RequiredFilesCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -588,11 +592,11 @@ public string Result { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void GetFileCompletedEventHandler(object sender, GetFileCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class GetFileCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -614,11 +618,11 @@ public byte[] Result { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void ScheduleCompletedEventHandler(object sender, ScheduleCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class ScheduleCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -640,11 +644,11 @@ public string Result { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void BlackListCompletedEventHandler(object sender, BlackListCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class BlackListCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -666,11 +670,11 @@ public bool Result { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void SubmitLogCompletedEventHandler(object sender, SubmitLogCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class SubmitLogCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -692,11 +696,11 @@ public bool Result { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void SubmitStatsCompletedEventHandler(object sender, SubmitStatsCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class SubmitStatsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -718,11 +722,11 @@ public bool Result { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void MediaInventoryCompletedEventHandler(object sender, MediaInventoryCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class MediaInventoryCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -744,11 +748,11 @@ public bool Result { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void GetResourceCompletedEventHandler(object sender, GetResourceCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class GetResourceCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -770,11 +774,11 @@ public string Result { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void NotifyStatusCompletedEventHandler(object sender, NotifyStatusCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class NotifyStatusCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -796,11 +800,11 @@ public bool Result { } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] public delegate void SubmitScreenShotCompletedEventHandler(object sender, SubmitScreenShotCompletedEventArgs e); /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class SubmitScreenShotCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { diff --git a/Web References/xmds/Reference.map b/Web References/xmds/Reference.map index f0d7f68d..9933f18d 100644 --- a/Web References/xmds/Reference.map +++ b/Web References/xmds/Reference.map @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/Web References/xmds/xmds.wsdl b/Web References/xmds/xmds.wsdl index 477728ce..ef22c111 100644 --- a/Web References/xmds/xmds.wsdl +++ b/Web References/xmds/xmds.wsdl @@ -1,271 +1,273 @@ - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Register the Display with the CMS - - - - + + + + The files required by the requesting display - - - - + + + + Gets the file requested - - - - + + + + Gets the schedule - - - - + + + + Set media to be blacklisted - - - - + + + + Submit Logging from the Client - - - - + + + + Submit Display statistics from the Client - - - - + + + + Report back the clients MediaInventory - - - - + + + + Gets the file requested - - - - + + + + Report back the current status - - - - + + + + Submit a screen shot for a display - - - - - + + + + + - + - + - - + + - - - + + + - + - - + + - - - + + + - + - - + + - - - + + + - + - - + + - - - + + + - + - - + + - - - + + + - + - - + + - - - + + + - + - - + + - - - + + + - + - - + + - - - + + + - + - - + + - - - + + + - + - - + + - - - + + + - + - - + + - - - - - - - - - \ No newline at end of file + + + + + + + + + \ No newline at end of file diff --git a/XiboClient.csproj b/XiboClient.csproj index ca96c04b..3051178d 100644 --- a/XiboClient.csproj +++ b/XiboClient.csproj @@ -76,16 +76,28 @@ false + + packages\AsyncIO.0.1.18.0\lib\net40\AsyncIO.dll + False wmpdll\AxInterop.WMPLib.dll False + + packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll + False False wmpdll\Interop.WMPLib.dll + + packages\NetMQ.3.3.2.2\lib\net40\NetMQ.dll + + + packages\Newtonsoft.Json.7.0.1\lib\net40\Newtonsoft.Json.dll + @@ -103,6 +115,7 @@ + Component @@ -114,12 +127,17 @@ + + + + + Form @@ -183,6 +201,7 @@ + SettingsSingleFileGenerator Settings.Designer.cs @@ -265,10 +284,10 @@ - + Static Web References\xmds\ - http://172.28.128.3/xmds.php%3fv=4&WSDL + http://192.168.0.28/xmds.php%3fv=5&WSDL diff --git a/XiboClient.v11.suo b/XiboClient.v11.suo index a098a0bc..62c2f29f 100644 Binary files a/XiboClient.v11.suo and b/XiboClient.v11.suo differ diff --git a/XmdsAgents/LogAgent.cs b/XmdsAgents/LogAgent.cs index 46daf08f..cace906a 100644 --- a/XmdsAgents/LogAgent.cs +++ b/XmdsAgents/LogAgent.cs @@ -36,6 +36,14 @@ class LogAgent private bool _forceStop = false; private ManualResetEvent _manualReset = new ManualResetEvent(false); + /// + /// Wake Up + /// + public void WakeUp() + { + _manualReset.Set(); + } + /// /// Stops the thread /// diff --git a/XmdsAgents/RegisterAgent.cs b/XmdsAgents/RegisterAgent.cs index 622a0b21..274aaa00 100644 --- a/XmdsAgents/RegisterAgent.cs +++ b/XmdsAgents/RegisterAgent.cs @@ -37,6 +37,18 @@ class RegisterAgent private bool _forceStop = false; private ManualResetEvent _manualReset = new ManualResetEvent(false); + // Events + public delegate void OnXmrReconfigureDelegate(); + public event OnXmrReconfigureDelegate OnXmrReconfigure; + + /// + /// Wake Up + /// + public void WakeUp() + { + _manualReset.Set(); + } + /// /// Stops the thread /// @@ -72,7 +84,20 @@ public void Run() xmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds; xmds.UseDefaultCredentials = false; - RegisterAgent.ProcessRegisterXml(xmds.RegisterDisplay(ApplicationSettings.Default.ServerKey, key.Key, ApplicationSettings.Default.DisplayName, "windows", ApplicationSettings.Default.ClientVersion, ApplicationSettings.Default.ClientCodeVersion, Environment.OSVersion.ToString(), key.MacAddress)); + // Store the XMR address + string xmrAddress = ApplicationSettings.Default.XmrNetworkAddress; + + RegisterAgent.ProcessRegisterXml(xmds.RegisterDisplay( + ApplicationSettings.Default.ServerKey, + key.Key, + ApplicationSettings.Default.DisplayName, + "windows", + ApplicationSettings.Default.ClientVersion, + ApplicationSettings.Default.ClientCodeVersion, + Environment.OSVersion.ToString(), + key.MacAddress, + key.Channel, + key.getXmrPublicKey())); // Set the flag to indicate we have a connection to XMDS ApplicationSettings.Default.XmdsLastConnection = DateTime.Now; @@ -83,6 +108,12 @@ public void Run() ApplicationSettings.Default.ScreenShotRequested = false; ScreenShot.TakeAndSend(); } + + // Has the XMR address changed? + if (xmrAddress != ApplicationSettings.Default.XmrNetworkAddress) + { + OnXmrReconfigure(); + } } } catch (WebException webEx) @@ -145,41 +176,67 @@ public static string ProcessRegisterXml(string xml) foreach (XmlNode node in result.DocumentElement.ChildNodes) { - Object value = node.InnerText; - - switch (node.Attributes["type"].Value) + // Are we a commands node? + if (node.Name == "commands") { - case "int": - value = Convert.ToInt32(value); - break; - - case "double": - value = Convert.ToDecimal(value); - break; - - case "string": - case "word": - value = node.InnerText; - break; - - case "checkbox": - value = (node.InnerText == "0") ? false : true; - break; - - default: - message += String.Format("Unable to set {0} with value {1}", node.Name, value) + Environment.NewLine; - continue; - } + List commands = new List(); - // Match these to settings - try - { - ApplicationSettings.Default[node.Name] = Convert.ChangeType(value, ApplicationSettings.Default[node.Name].GetType()); + foreach (XmlNode commandNode in node.ChildNodes) + { + Command command = new Command(); + command.Code = commandNode.Name; + command.CommandString = commandNode.SelectSingleNode("commandString").InnerText; + command.Validation = commandNode.SelectSingleNode("validationString").InnerText; + + commands.Add(command); + } + + // Store commands + ApplicationSettings.Default.Commands = commands; } - catch + else { - error = true; - message += "Invalid Configuration Option from CMS [" + node.Name + "]" + Environment.NewLine; + Object value = node.InnerText; + + switch (node.Attributes["type"].Value) + { + case "int": + value = Convert.ToInt32(value); + break; + + case "double": + value = Convert.ToDecimal(value); + break; + + case "string": + case "word": + value = node.InnerText; + break; + + case "checkbox": + value = (node.InnerText == "0") ? false : true; + break; + + default: + message += String.Format("Unable to set {0} with value {1}", node.Name, value) + Environment.NewLine; + continue; + } + + // Match these to settings + try + { + if (ApplicationSettings.Default[node.Name] != null) + { + value = Convert.ChangeType(value, ApplicationSettings.Default[node.Name].GetType()); + } + + ApplicationSettings.Default[node.Name] = value; + } + catch + { + error = true; + message += "Invalid Configuration Option from CMS [" + node.Name + "]" + Environment.NewLine; + } } } diff --git a/XmdsAgents/RequiredFilesAgent.cs b/XmdsAgents/RequiredFilesAgent.cs index 63a8d9af..86874d6b 100644 --- a/XmdsAgents/RequiredFilesAgent.cs +++ b/XmdsAgents/RequiredFilesAgent.cs @@ -96,6 +96,14 @@ public RequiredFilesAgent() _requiredFiles = new RequiredFiles(); } + /// + /// Wake Up + /// + public void WakeUp() + { + _manualReset.Set(); + } + /// /// Stops the thread /// diff --git a/XmdsAgents/ScheduleAgent.cs b/XmdsAgents/ScheduleAgent.cs index 20998677..fdd7ee61 100644 --- a/XmdsAgents/ScheduleAgent.cs +++ b/XmdsAgents/ScheduleAgent.cs @@ -87,6 +87,14 @@ public ClientInfo ClientInfoForm } private ClientInfo _clientInfoForm; + /// + /// Wake Up + /// + public void WakeUp() + { + _manualReset.Set(); + } + /// /// Stops the thread /// diff --git a/app.config b/app.config index b21fe50b..c0003477 100644 --- a/app.config +++ b/app.config @@ -1,10 +1,17 @@ - + - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bin/x86/Release/Xibo.scr b/bin/x86/Release/Xibo.scr index f6ec0aab..d02af6db 100644 Binary files a/bin/x86/Release/Xibo.scr and b/bin/x86/Release/Xibo.scr differ diff --git a/default.config.xml b/default.config.xml index cd468504..73df049f 100644 --- a/default.config.xml +++ b/default.config.xml @@ -51,4 +51,5 @@ 0 0 0 + \ No newline at end of file diff --git a/packages.config b/packages.config new file mode 100644 index 00000000..a13b0fb0 --- /dev/null +++ b/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file