private void ShowSettings(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Displays a list of service settings from the config file.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Settings -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                StringBuilder responseMessage = new StringBuilder();
                responseMessage.AppendFormat("Settings for {0}:", Name);
                responseMessage.AppendLine();
                responseMessage.AppendLine();
                responseMessage.Append("Category".PadRight(20));
                responseMessage.Append(' ');
                responseMessage.Append("Name".PadRight(25));
                responseMessage.Append(' ');
                responseMessage.Append("Value".PadRight(30));
                responseMessage.AppendLine();
                responseMessage.Append(new string('-', 20));
                responseMessage.Append(' ');
                responseMessage.Append(new string('-', 25));
                responseMessage.Append(' ');
                responseMessage.Append(new string('-', 30));

                IPersistSettings typedComponent;
                lock (m_serviceComponents)
                {
                    foreach (object component in m_serviceComponents)
                    {
                        typedComponent = component as IPersistSettings;

                        if ((object)typedComponent == null)
                            continue;

                        foreach (CategorizedSettingsElement setting in ConfigurationFile.Current.Settings[typedComponent.SettingsCategory].Cast<CategorizedSettingsElement>().Where(setting => !setting.Encrypted))
                        {
                            responseMessage.AppendLine();
                            responseMessage.Append(typedComponent.SettingsCategory.PadRight(20));
                            responseMessage.Append(' ');
                            responseMessage.Append(setting.Name.PadRight(25));
                            responseMessage.Append(' ');

                            if (!string.IsNullOrEmpty(setting.Value))
                                responseMessage.Append(setting.Value.PadRight(30));
                            else
                                responseMessage.Append("[Not Set]".PadRight(30));
                        }
                    }
                }
                responseMessage.AppendLine();
                responseMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, responseMessage.ToString());
            }
        }
 /// <summary>
 /// Sends an actionable response to client.
 /// </summary>
 /// <param name="requestInfo"><see cref="ClientRequestInfo"/> instance containing the client request.</param>
 /// <param name="success">Flag that determines if this response to client request was a success.</param>
 protected virtual void SendResponse(ClientRequestInfo requestInfo, bool success)
 {
     SendResponseWithAttachment(requestInfo, success, null, null);
 }
        // Send a message to the service monitors on request
        private void MsgServiceMonitorsRequestHandler(ClientRequestInfo requestInfo)
        {
            Arguments arguments = requestInfo.Request.Arguments;

            if (arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Sends a message to all service monitors.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       MsgServiceMonitors [Options] [Args...]");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");

                DisplayResponseMessage(requestInfo, helpMessage.ToString());
            }
            else
            {
                string[] args = Enumerable.Range(1, arguments.OrderedArgCount)
                    .Select(arg => arguments[arguments.OrderedArgID + arg])
                    .ToArray();

                // Go through all service monitors and handle the message
                foreach (IServiceMonitor serviceMonitor in m_serviceMonitors.Adapters)
                {
                    try
                    {
                        // If the service monitor is enabled, notify it of the message
                        if (serviceMonitor.Enabled)
                            serviceMonitor.HandleClientMessage(args);
                    }
                    catch (Exception ex)
                    {
                        // Handle each service monitor's exceptions individually
                        HandleException(ex);
                    }
                }

                SendResponse(requestInfo, true);
            }
        }
        private void ShowTime(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Shows the current system time.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Time -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -actionable".PadRight(20));
                helpMessage.Append("Returns results via an actionable event");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string message;
                //          1         2         3         4         5         6         7         8
                // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
                //  Current system time: yyyy-MM-dd HH:mm:ss.fff, yyyy-MM-dd HH:mm:ss.fff UTC
                // Total system runtime: xx days yy hours zz minutes ii seconds
                if ((object)m_remotingServer != null)
                    message = $" Current system time: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}, {DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")} UTC\r\nTotal system runtime: {m_remotingServer.RunTime.ToString(3)}";
                else
                    message = $"Current system time: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}, {DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")} UTC";

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, message + "\r\n\r\n");

                // Also allow consumers to directly consume message via event in response to a time request
                if (requestInfo.Request.Arguments.Exists("actionable"))
                    SendActionableResponse(requestInfo, true, null, message);
            }
        }
        private void RemoteTelnetSession(ClientRequestInfo requestinfo)
        {
            if ((object)m_remoteCommandProcess == null && requestinfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Allows for a telnet session to the service server.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Telnet -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -connect".PadRight(20));
                helpMessage.Append("Establishes a telnet session (requires password)");
                helpMessage.AppendLine();
                helpMessage.Append("       -disconnect".PadRight(20));
                helpMessage.Append("Terminates established telnet session");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestinfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                bool connectSession = requestinfo.Request.Arguments.Exists("connect");
                bool disconnectSession = requestinfo.Request.Arguments.Exists("disconnect");

                if ((object)m_remoteCommandProcess == null && connectSession && !string.IsNullOrEmpty(requestinfo.Request.Arguments["connect"]))
                {
                    // User wants to establish a remote command session.
                    string password = requestinfo.Request.Arguments["connect"];

                    if (password == m_telnetSessionPassword)
                    {
                        // Establish remote command session
                        m_remoteCommandProcess = new Process();
                        m_remoteCommandProcess.ErrorDataReceived += RemoteCommandProcess_ErrorDataReceived;
                        m_remoteCommandProcess.OutputDataReceived += RemoteCommandProcess_OutputDataReceived;
                        m_remoteCommandProcess.StartInfo.FileName = "cmd.exe";
                        m_remoteCommandProcess.StartInfo.UseShellExecute = false;
                        m_remoteCommandProcess.StartInfo.RedirectStandardInput = true;
                        m_remoteCommandProcess.StartInfo.RedirectStandardOutput = true;
                        m_remoteCommandProcess.StartInfo.RedirectStandardError = true;
                        m_remoteCommandProcess.Start();
                        m_remoteCommandProcess.BeginOutputReadLine();
                        m_remoteCommandProcess.BeginErrorReadLine();

                        UpdateStatus(UpdateType.Information, "Remote command session established - status updates are suspended.\r\n\r\n");

                        m_remoteCommandClientID = requestinfo.Sender.ClientID;
                        SendResponse(requestinfo.Sender.ClientID, new ServiceResponse("TelnetSession", "Established"));
                    }
                    else
                    {
                        UpdateStatus(requestinfo.Sender.ClientID, UpdateType.Alarm, "Failed to establish remote command session - Password is invalid.\r\n\r\n");
                    }
                }
                else if (string.Compare(requestinfo.Request.Command, "Telnet", StringComparison.OrdinalIgnoreCase) == 0 && (object)m_remoteCommandProcess != null && disconnectSession)
                {
                    // User wants to terminate an established remote command session.                   
                    m_remoteCommandProcess.ErrorDataReceived -= RemoteCommandProcess_ErrorDataReceived;
                    m_remoteCommandProcess.OutputDataReceived -= RemoteCommandProcess_OutputDataReceived;

                    if (!m_remoteCommandProcess.HasExited)
                        m_remoteCommandProcess.Kill();

                    m_remoteCommandProcess.Dispose();
                    m_remoteCommandProcess = null;

                    m_remoteCommandClientID = Guid.Empty;
                    SendResponse(requestinfo.Sender.ClientID, new ServiceResponse("TelnetSession", "Terminated"));

                    UpdateStatus(UpdateType.Information, "Remote command session terminated - status updates are resumed.\r\n\r\n");
                }
                else if ((object)m_remoteCommandProcess != null)
                {
                    // User has entered commands that must be redirected to the established command session.
                    string input = requestinfo.Request.Command + " " + requestinfo.Request.Arguments;
                    m_remoteCommandProcess.StandardInput.WriteLine(input);
                }
                else
                {
                    // User has provided insufficient information.
                    requestinfo.Request = ClientRequest.Parse("Telnet /?");
                    RemoteTelnetSession(requestinfo);
                }
            }
        }
        private void UpdateClientFilter(ClientRequestInfo requestInfo)
        {
            const int HighPriority = 2;

            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Filters status messages coming from the service.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Filter [ { -List |");
                helpMessage.AppendLine();
                helpMessage.Append("                  -Include <FilterDefinition> |");
                helpMessage.AppendLine();
                helpMessage.Append("                  -Exclude <FilterDefinition> |");
                helpMessage.AppendLine();
                helpMessage.Append("                  -Remove <ID> } ... ]");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("       Filter -?");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("       FilterDefinition ::= Type { Alarm | Warning | Information } |");
                helpMessage.AppendLine();
                helpMessage.Append("                            Message <FilterSpec> |");
                helpMessage.AppendLine();
                helpMessage.Append("                            Regex <FilterSpec>");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -List".PadRight(20));
                helpMessage.Append("Displays a list of the client's active filters");
                helpMessage.AppendLine();
                helpMessage.Append("       -Include".PadRight(20));
                helpMessage.Append("Defines a filter matching messages to be displayed");
                helpMessage.AppendLine();
                helpMessage.Append("       -Exclude".PadRight(20));
                helpMessage.Append("Defines a filter matching messages to be suppressed");
                helpMessage.AppendLine();
                helpMessage.Append("       -Remove".PadRight(20));
                helpMessage.Append("Removes a filter");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "{0}", helpMessage.ToString());

                return;
            }

            string[] args = Arguments.ToArgs(requestInfo.Request.Arguments.ToString());

            ClientFilter mergeFilter = new ClientFilter();
            List<int> removalIDs = new List<int>();
            bool argsContainsList = !args.Any();

            int i = 0;

            while (i < args.Length)
            {
                if (args[i].Equals("-List", StringComparison.OrdinalIgnoreCase))
                {
                    // Set the boolean flag indicating that
                    // the client requested a list of filters
                    argsContainsList = true;
                    i++;
                }
                else if (args[i].Equals("-Remove", StringComparison.OrdinalIgnoreCase))
                {
                    int filterID;

                    // Check for parsing errors with the number of arguments
                    if (i + 1 >= args.Length)
                        throw new FormatException("Malformed expression - Missing ID argument in 'Filter -Remove <ID>' command. Type 'Filter -?' to get help with this command.");

                    // Check for parsing errors in the filter ID
                    if (!int.TryParse(args[i + 1], out filterID))
                        throw new FormatException("Malformed expression - ID argument supplied to 'Filter -Remove <ID>' must be an integer. Type 'Filter -?' to get help with this command.");

                    // Add the ID to the list of filter IDs to be removed from the client's filter
                    if (i + 1 < args.Length && int.TryParse(args[i + 1], out filterID))
                        removalIDs.Add(filterID);

                    i += 2;
                }
                else if (args[i].Equals("-Include", StringComparison.OrdinalIgnoreCase))
                {
                    string filterType;
                    string filterSpec;
                    UpdateType updateType;

                    // Validate the number of arguments
                    // associated with the filter
                    if (i + 2 >= args.Length)
                        throw new FormatException("Malformed expression - Missing arguments in 'Filter -Include <FilterDefinition>' command. Type 'Filter -?' to get help with this command.");

                    filterType = args[i + 1];
                    filterSpec = args[i + 2];

                    if (filterType.Equals("Message", StringComparison.OrdinalIgnoreCase))
                    {
                        // Add message filters to the merge filter
                        mergeFilter.PatternInclusionFilters.Add(Regex.Escape(filterSpec));
                    }
                    else if (args[i + 1].Equals("Type", StringComparison.OrdinalIgnoreCase))
                    {
                        // Add type filters to the merge filter
                        if (!Enum.TryParse(filterSpec, true, out updateType))
                            throw new FormatException($"Malformed expression - Unrecognized message type '{filterSpec}' in 'Filter -Include <FilterDefinition>' command. Type 'Filter -?' to get help with this command.");

                        mergeFilter.TypeInclusionFilters.Add(updateType);
                    }
                    else if (args[i + 1].Equals("Regex", StringComparison.OrdinalIgnoreCase))
                    {
                        // Add pattern filters to the merge filter
                        mergeFilter.PatternInclusionFilters.Add(filterSpec);
                    }
                    else
                    {
                        throw new FormatException($"Malformed expression - Unrecognized filter type '{filterType}' in 'Filter -Include <FilterDefinition>' command. Type 'Filter -?' to get help with this command.");
                    }

                    i += 3;
                }
                else if (args[i].Equals("-Exclude", StringComparison.OrdinalIgnoreCase))
                {
                    string filterType;
                    string filterSpec;
                    UpdateType updateType;

                    // Validate the number of arguments
                    // associated with the filter
                    if (i + 2 >= args.Length)
                        throw new FormatException("Malformed expression - Missing arguments in 'Filter -Exclude <FilterDefinition>' command. Type 'Filter -?' to get help with this command.");

                    filterType = args[i + 1];
                    filterSpec = args[i + 2];

                    if (filterType.Equals("Message", StringComparison.OrdinalIgnoreCase))
                    {
                        // Add message filters to the merge filter
                        mergeFilter.PatternExclusionFilters.Add(Regex.Escape(filterSpec));
                    }
                    else if (filterType.Equals("Type", StringComparison.OrdinalIgnoreCase))
                    {
                        // Add type filters to the merge filter
                        if (!Enum.TryParse(filterSpec, true, out updateType))
                            throw new FormatException($"Malformed expression - Unrecognized message type '{filterSpec}' in 'Filter -Exclude <FilterDefinition>' command. Type 'Filter -?' to get help with this command.");

                        mergeFilter.TypeExclusionFilters.Add(updateType);
                    }
                    else if (filterType.Equals("Regex", StringComparison.OrdinalIgnoreCase))
                    {
                        // Add pattern filters to the merge filter
                        mergeFilter.PatternExclusionFilters.Add(filterSpec);
                    }
                    else
                    {
                        throw new FormatException($"Malformed expression - Unrecognized filter type '{filterType}' in 'Filter -Exclude <FilterDefinition>' command. Type 'Filter -?' to get help with this command.");
                    }

                    i += 3;
                }
                else
                {
                    throw new FormatException($"Malformed expression - Unrecognized argument '{args[i]}'. Type 'Filter -?' to get help with this command.");
                }
            }

            // Determine whether the filter was actually updated
            bool filterUpdated = mergeFilter.TypeInclusionFilters.Any() || mergeFilter.TypeExclusionFilters.Any() || mergeFilter.PatternInclusionFilters.Any() || mergeFilter.PatternExclusionFilters.Any() || removalIDs.Any();

            if (!filterUpdated && !argsContainsList)
                return;

            // Use the status update thread to get the
            // client's config, then update the filters
            m_statusUpdateThread.Push(HighPriority, () =>
            {
                ClientStatusUpdateConfiguration clientConfig = m_clientStatusUpdateLookup.GetOrAdd(requestInfo.Sender.ClientID, id => new ClientStatusUpdateConfiguration(id, this));

                if (filterUpdated)
                    clientConfig.UpdateFilters(mergeFilter, removalIDs);

                if (argsContainsList)
                    clientConfig.ListFilters(requestInfo);
            });
        }
        private void TransferFile(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest || requestInfo.Request.Arguments.OrderedArgCount < 2)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Transfers files to and from the server.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Transfer \"Source File Path\" \"Target File Path\" -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -upload".PadRight(20));
                helpMessage.Append("Uploads file from local machine to server");
                helpMessage.AppendLine();
                helpMessage.Append("       -download".PadRight(20));
                helpMessage.Append("Downloads file from server to local machine");
                helpMessage.AppendLine();
                helpMessage.Append("       -overwrite".PadRight(20));
                helpMessage.Append("Overwrites file if one exists in the target location");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string source = requestInfo.Request.Arguments["orderedarg1"];
                string target = requestInfo.Request.Arguments["orderedarg2"];
                bool upload = requestInfo.Request.Arguments.Exists("upload");
                bool download = requestInfo.Request.Arguments.Exists("download");
                bool overwrite = requestInfo.Request.Arguments.Exists("overwrite");

                if (upload)
                {
                    // Request is for uploading a file.
                    if (requestInfo.Request.Attachments.Count == 1)
                    {
                        // File content is present.
                        target = FilePath.GetAbsolutePath(target);

                        if (!File.Exists(target) || overwrite)
                        {
                            // Save the received file.
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Saving file '{0}'...\r\n\r\n", target);
                            File.WriteAllBytes(target, (byte[])requestInfo.Request.Attachments[0]);
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "File '{0}' saved successfully.\r\n\r\n", target);
                        }
                        else
                        {
                            // File exists and cannot be overwritten.
                            UpdateStatus(UpdateType.Alarm, "File '{0}' already exists.\r\n\r\n", target);
                        }
                    }
                    else
                    {
                        // File content is not present.
                        UpdateStatus(UpdateType.Alarm, "Content for file '{0}' is missing.\r\n\r\n", target);
                    }
                }
                else if (download)
                {
                    // Request is for uploading a file.
                    source = FilePath.GetAbsolutePath(source);

                    if (File.Exists(source))
                    {
                        // Send file to client.
                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Sending file '{0}'...\r\n\r\n", source);
                        SendActionableResponse(requestInfo, true, File.ReadAllBytes(source));
                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "File '{0}' sent successfully.\r\n\r\n", source);
                    }
                    else
                    {
                        // File does not exist.
                        UpdateStatus(UpdateType.Alarm, "File '{0}' does not exist.\r\n\r\n", source);
                    }
                }
                else
                {
                    // Invalid command option specified.
                    UpdateStatus(UpdateType.Alarm, "Command option is not valid.\r\n\r\n");
                }
            }
        }
        private void ResetHealthMonitor(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Resets the system resource utilization monitor.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       ResetHealthMonitor -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                try
                {
                    // Dispose existing performance monitor
                    if ((object)m_performanceMonitor != null)
                        m_performanceMonitor.Dispose();

                    // Recreate the performance monitor
                    m_performanceMonitor = new PerformanceMonitor(m_healthMonitorInterval * 1000.0D);

                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "System health monitor successfully reset.\r\n\r\n");
                }
                catch (Exception ex)
                {
                    LogException(ex);
                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to reset system health monitor: {0}\r\n\r\n", ex.Message);
                }
            }
        }
            public void ListFilters(ClientRequestInfo requestInfo)
            {
                m_thread.Push(HighPriority, () =>
                {
                    StringBuilder messageBuilder = new StringBuilder();
                    StringBuilder commandBuilder = new StringBuilder();
                    int i = 0;

                    commandBuilder.Append("Filter");

                    // List type inclusion filters
                    if (m_filter.TypeInclusionFilters.Any())
                    {
                        messageBuilder.AppendLine("Type Inclusion Filters:");

                        foreach (UpdateType filter in m_filter.TypeInclusionFilters)
                        {
                            messageBuilder.AppendLine($"[{i++}] {filter}");
                            commandBuilder.Append($" -Include Type {Arguments.Escape(filter.ToString())}");
                        }
                    }

                    // List type exclusion filters
                    if (m_filter.TypeExclusionFilters.Any())
                    {
                        if (messageBuilder.Length > 0)
                            messageBuilder.AppendLine();

                        messageBuilder.AppendLine("Type Exclusion Filters:");

                        foreach (UpdateType filter in m_filter.TypeExclusionFilters)
                        {
                            messageBuilder.AppendLine($"[{i++}] {filter}");
                            commandBuilder.Append($" -Exclude Type {Arguments.Escape(filter.ToString())}");
                        }
                    }

                    // List pattern exclusion filters
                    if (m_filter.PatternInclusionFilters.Any())
                    {
                        if (messageBuilder.Length > 0)
                            messageBuilder.AppendLine();

                        messageBuilder.AppendLine("Pattern Inclusion Filters:");

                        foreach (string filter in m_filter.PatternInclusionFilters)
                        {
                            messageBuilder.AppendLine($"[{i++}] {filter}");
                            commandBuilder.Append($" -Include Regex {Arguments.Escape(filter)}");
                        }
                    }

                    // List pattern exclusion filters
                    if (m_filter.PatternExclusionFilters.Any())
                    {
                        if (messageBuilder.Length > 0)
                            messageBuilder.AppendLine();

                        messageBuilder.AppendLine("Pattern Exclusion Filters:");

                        foreach (string filter in m_filter.PatternExclusionFilters)
                        {
                            messageBuilder.AppendLine($"[{i++}] {filter}");
                            commandBuilder.Append($" -Exclude Regex {Arguments.Escape(filter)}");
                        }
                    }

                    // Display a message if no filters are defined
                    if (messageBuilder.Length == 0)
                    {
                        messageBuilder.AppendLine("No filters defined.");
                    }
                    else
                    {
                        string command = commandBuilder.ToString();
                        string argument = Arguments.Escape(command);
                        string url = HttpUtility.UrlEncode(command);

                        messageBuilder.AppendLine();
                        messageBuilder.AppendLine("Command:");
                        messageBuilder.AppendLine(command);
                        messageBuilder.AppendLine();
                        messageBuilder.AppendLine("Argument:");
                        messageBuilder.AppendLine(argument);
                        messageBuilder.AppendLine();
                        messageBuilder.AppendLine("URL:");
                        messageBuilder.AppendLine(url);
                    }


                    // Send the message to the client
                    m_serviceHelper.SendActionableResponse(requestInfo, true, null, messageBuilder.ToString().TrimEnd());
                });
            }
        private void ShowRequestHelp(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Displays a list of commands supported by the service.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Help -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                bool showAdvancedHelp = requestInfo.Request.Arguments.Exists("advanced");

                StringBuilder responseMessage = new StringBuilder();

                responseMessage.AppendFormat("Commands supported by {0}:", Name);
                responseMessage.AppendLine();
                responseMessage.AppendLine();
                responseMessage.Append("Command".PadRight(20));
                responseMessage.Append(' ');
                responseMessage.Append("Description".PadRight(55));
                responseMessage.AppendLine();
                responseMessage.Append(new string('-', 20));
                responseMessage.Append(' ');
                responseMessage.Append(new string('-', 55));

                lock (m_clientRequestHandlers)
                {
                    foreach (ClientRequestHandler handler in m_clientRequestHandlers)
                    {
                        if (m_secureRemoteInteractions && SecurityProviderUtility.IsResourceSecurable(handler.Command) && !SecurityProviderUtility.IsResourceAccessible(handler.Command))
                            continue;

                        if (!handler.IsAdvertised && !showAdvancedHelp)
                            continue;

                        responseMessage.AppendLine();
                        responseMessage.Append(handler.Command.PadRight(20));
                        responseMessage.Append(' ');
                        responseMessage.Append(handler.CommandDescription.PadRight(55));
                    }
                }
                responseMessage.AppendLine();
                responseMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, responseMessage.ToString());
            }
        }
        private void ShowHealthReport(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Displays a resource utilization report for the service.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Health -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -lifetime".PadRight(20));
                helpMessage.Append("Shows utilization over entire service lifetime");
                helpMessage.AppendLine();
                helpMessage.Append("       -actionable".PadRight(20));
                helpMessage.Append("Returns results via an actionable event");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string message;
                bool success;

                if ((object)m_performanceMonitor != null)
                {
                    try
                    {
                        if (requestInfo.Request.Arguments.Exists("lifetime"))
                            message = m_performanceMonitor.LifetimeStatus;
                        else
                            message = m_performanceMonitor.Status;

                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "\r\n" + message + "\r\n");
                        success = true;
                    }
                    catch (Exception ex)
                    {
                        LogException(ex);
                        message = "Failed to query system health monitor status: " + ex.Message;
                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, message + "\r\n\r\n");
                        success = false;
                    }
                }
                else
                {
                    message = "System health monitor is unavailable.";
                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Warning, message + "\r\n\r\n");
                    success = false;
                }

                // Also allow consumers to directly consume message via event in response to a health request
                if (requestInfo.Request.Arguments.Exists("actionable"))
                    SendActionableResponse(requestInfo, success, null, message);
            }
        }
        private void ShowRequestHistory(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Displays a list of recent requests received from the clients.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       History -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                StringBuilder responseMessage = new StringBuilder();

                responseMessage.AppendFormat("History of requests received by {0}:", Name);
                responseMessage.AppendLine();
                responseMessage.AppendLine();
                responseMessage.Append("Command".PadRight(20));
                responseMessage.Append(' ');
                responseMessage.Append("Received".PadRight(25));
                responseMessage.Append(' ');
                responseMessage.Append("Sender".PadRight(30));
                responseMessage.AppendLine();
                responseMessage.Append(new string('-', 20));
                responseMessage.Append(' ');
                responseMessage.Append(new string('-', 25));
                responseMessage.Append(' ');
                responseMessage.Append(new string('-', 30));

                lock (m_clientRequestHistory)
                {
                    foreach (ClientRequestInfo historicRequest in m_clientRequestHistory)
                    {
                        responseMessage.AppendLine();
                        responseMessage.Append(historicRequest.Request.Command.PadRight(20));
                        responseMessage.Append(' ');
                        responseMessage.Append(historicRequest.ReceivedAt.ToString(CultureInfo.InvariantCulture).PadRight(25));
                        responseMessage.Append(' ');
                        responseMessage.Append($"{historicRequest.Sender.ClientUser.Identity.Name} from {historicRequest.Sender.MachineName}".PadRight(30));
                    }
                }
                responseMessage.AppendLine();
                responseMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, responseMessage.ToString());
            }
        }
        private void ShowSchedules(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Displays a list of schedules for processes defined in the service.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Schedules -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                if (m_processScheduler.Schedules.Count > 0)
                {
                    // Display info about all the process schedules defined in the service.
                    StringBuilder responseMessage = new StringBuilder();

                    responseMessage.AppendFormat("Process schedules defined in {0}:", Name);
                    responseMessage.AppendLine();
                    responseMessage.AppendLine();
                    responseMessage.Append("Name".PadRight(25));
                    responseMessage.Append(' ');
                    responseMessage.Append("Rule".PadRight(20));
                    responseMessage.Append(' ');
                    responseMessage.Append("Last Due".PadRight(30));
                    responseMessage.AppendLine();
                    responseMessage.Append(new string('-', 25));
                    responseMessage.Append(' ');
                    responseMessage.Append(new string('-', 20));
                    responseMessage.Append(' ');
                    responseMessage.Append(new string('-', 30));

                    foreach (Schedule schedule in m_processScheduler.Schedules)
                    {
                        responseMessage.AppendLine();
                        responseMessage.Append(schedule.Name.PadRight(25));
                        responseMessage.Append(' ');
                        responseMessage.Append(schedule.Rule.PadRight(20));
                        responseMessage.Append(' ');

                        if (schedule.LastDueAt != DateTime.MinValue)
                            responseMessage.Append(schedule.LastDueAt.ToString(CultureInfo.InvariantCulture).PadRight(30));
                        else
                            responseMessage.Append("[Never]".PadRight(30));
                    }
                    responseMessage.AppendLine();
                    responseMessage.AppendLine();

                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, responseMessage.ToString());
                }
                else
                {
                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "No process schedules are defined in {0}.\r\n\r\n", Name);
                }
            }
        }
        private void ShowProcesses(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                bool showAdvancedHelp = requestInfo.Request.Arguments.Exists("advanced");

                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Displays a list of defined service processes or running system processes.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Processes -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                if (m_supportSystemCommands && showAdvancedHelp)
                {
                    helpMessage.AppendLine();
                    helpMessage.Append("       -system".PadRight(20));
                    helpMessage.Append("Displays system processes instead of service processes");
                }
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                bool listSystemProcesses = requestInfo.Request.Arguments.Exists("system");
                if (listSystemProcesses && m_supportSystemCommands)
                {
                    // Enumerate "system" processes when -system parameter is specified
                    StringBuilder responseMessage = new StringBuilder();

                    responseMessage.AppendFormat("Processes running on {0}:", Environment.MachineName);
                    responseMessage.AppendLine();
                    responseMessage.AppendLine();
                    responseMessage.Append("ID".PadRight(5));
                    responseMessage.Append(' ');
                    responseMessage.Append("Name".PadRight(25));
                    responseMessage.Append(' ');
                    responseMessage.Append("Priority".PadRight(15));
                    responseMessage.Append(' ');
                    responseMessage.Append("Responding".PadRight(10));
                    responseMessage.Append(' ');
                    responseMessage.Append("Start Time".PadRight(20));
                    responseMessage.AppendLine();
                    responseMessage.Append(new string('-', 5));
                    responseMessage.Append(' ');
                    responseMessage.Append(new string('-', 25));
                    responseMessage.Append(' ');
                    responseMessage.Append(new string('-', 15));
                    responseMessage.Append(' ');
                    responseMessage.Append(new string('-', 10));
                    responseMessage.Append(' ');
                    responseMessage.Append(new string('-', 20));

                    foreach (Process process in Process.GetProcesses())
                    {
                        try
                        {
                            responseMessage.Append(process.StartInfo.UserName);
                            responseMessage.AppendLine();
                            responseMessage.Append(process.Id.ToString().PadRight(5));
                            responseMessage.Append(' ');
                            responseMessage.Append(process.ProcessName.PadRight(25));
                            responseMessage.Append(' ');
#if MONO
                            responseMessage.Append("Undetermined".PadRight(15));
                            responseMessage.Append(' ');
                            responseMessage.Append("N/A".PadRight(10));
                            responseMessage.Append(' ');
#else
                            responseMessage.Append(process.PriorityClass.ToString().PadRight(15));
                            responseMessage.Append(' ');
                            responseMessage.Append((process.Responding ? "Yes" : "No").PadRight(10));
                            responseMessage.Append(' ');
#endif
                            responseMessage.Append(process.StartTime.ToString("MM/dd/yy hh:mm:ss tt").PadRight(20));
                        }
                        // ReSharper disable once EmptyGeneralCatchClause
                        catch
                        { }
                    }
                    responseMessage.AppendLine();
                    responseMessage.AppendLine();

                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, responseMessage.ToString());
                }
                else
                {
                    if (m_processes.Count > 0)
                    {
                        // Display info about all the processes defined in the service.
                        StringBuilder responseMessage = new StringBuilder();

                        responseMessage.AppendFormat("Processes defined in {0}:", Name);
                        responseMessage.AppendLine();
                        responseMessage.AppendLine();
                        responseMessage.Append("Name".PadRight(20));
                        responseMessage.Append(' ');
                        responseMessage.Append("State".PadRight(15));
                        responseMessage.Append(' ');
                        responseMessage.Append("Last Exec. Start".PadRight(20));
                        responseMessage.Append(' ');
                        responseMessage.Append("Last Exec. Stop".PadRight(20));
                        responseMessage.AppendLine();
                        responseMessage.Append(new string('-', 20));
                        responseMessage.Append(' ');
                        responseMessage.Append(new string('-', 15));
                        responseMessage.Append(' ');
                        responseMessage.Append(new string('-', 20));
                        responseMessage.Append(' ');
                        responseMessage.Append(new string('-', 20));

                        lock (m_processes)
                        {
                            foreach (ServiceProcess process in m_processes)
                            {
                                responseMessage.AppendLine();
                                responseMessage.Append(process.Name.PadRight(20));
                                responseMessage.Append(' ');
                                responseMessage.Append(process.CurrentState.ToString().PadRight(15));
                                responseMessage.Append(' ');

                                if (process.ExecutionStartTime != DateTime.MinValue)
                                    responseMessage.Append(process.ExecutionStartTime.ToString("MM/dd/yy hh:mm:ss tt").PadRight(20));
                                else
                                    responseMessage.Append("[Not Executed]".PadRight(20));

                                responseMessage.Append(' ');

                                if (process.ExecutionStopTime != DateTime.MinValue)
                                {
                                    responseMessage.Append(process.ExecutionStopTime.ToString("MM/dd/yy hh:mm:ss tt").PadRight(20));
                                }
                                else
                                {
                                    if (process.ExecutionStartTime != DateTime.MinValue)
                                        responseMessage.Append("[Executing]".PadRight(20));
                                    else
                                        responseMessage.Append("[Not Executed]".PadRight(20));
                                }
                            }
                        }
                        responseMessage.AppendLine();
                        responseMessage.AppendLine();

                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, responseMessage.ToString());
                    }
                    else
                    {
                        // No processes defined in the service to be displayed.
                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "No processes are defined in {0}.\r\n\r\n", Name);
                    }
                }
            }
        }
        private void UnscheduleProcess(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest || requestInfo.Request.Arguments.OrderedArgCount < 1)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Unschedules a scheduled process defined in the service.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Unschedule \"Process Name\" -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -save".PadRight(20));
                helpMessage.Append("Saves all process schedules to the config file");
                helpMessage.AppendLine();
                helpMessage.Append("       -list".PadRight(20));
                helpMessage.Append("Displays list of all process schedules");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string processName = requestInfo.Request.Arguments["orderedarg1"];
                bool saveSchedules = requestInfo.Request.Arguments.Exists("save");
                bool listSchedules = requestInfo.Request.Arguments.Exists("list");

                Schedule scheduleToRemove = m_processScheduler.FindSchedule(processName);

                if ((object)scheduleToRemove != null)
                {
                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Attempting to unschedule process \"{0}\"...\r\n\r\n", processName);
                    m_processScheduler.Schedules.Remove(scheduleToRemove);
                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully unscheduled process \"{0}\".\r\n\r\n", processName);

                    if (saveSchedules)
                    {
                        requestInfo.Request = ClientRequest.Parse("SaveSchedules");
                        SaveSchedules(requestInfo);
                    }
                }
                else
                {
                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to unschedule process \"{0}\". Process is not scheduled.\r\n\r\n", processName);
                }

                if (!listSchedules)
                    return;

                requestInfo.Request = ClientRequest.Parse("Schedules");
                ShowSchedules(requestInfo);
            }
        }
        private void ShowServiceStatus(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Displays status of this service and its components.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Status -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -actionable".PadRight(20));
                helpMessage.Append("Returns results via an actionable event");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string message = Status;
                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, message);

                // Also allow consumers to directly consume message via event in response to a status request
                if (requestInfo.Request.Arguments.Exists("actionable"))
                    SendActionableResponse(requestInfo, true, null, message);
            }
        }
        private void LoadSchedules(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Loads all process schedules from the config file.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       LoadSchedules -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -list".PadRight(20));
                helpMessage.Append("Displays list of all process schedules");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                bool listSchedules = requestInfo.Request.Arguments.Exists("list");

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Attempting to load process schedules from the config file...\r\n\r\n");
                m_processScheduler.LoadSettings();
                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully loaded process schedules from the config file.\r\n\r\n");

                if (!listSchedules)
                    return;

                requestInfo.Request = ClientRequest.Parse("Schedules");
                ShowSchedules(requestInfo);
            }
        }
        private void ReloadCryptoCache(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Reloads the local system cryptography cache with data from the common cryptography cache.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       ReloadCryptoCache -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                Cipher.ReloadCache();
                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Crypto cache successfully reloaded.\r\n\r\n");
            }
        }
        private void ManageFiles(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest || requestInfo.Request.Arguments.OrderedArgCount < 2)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Manages files on the server.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Files \"Source Path\" \"Target Path\" -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -copy".PadRight(20));
                helpMessage.Append("Copies files from one location to another");
                helpMessage.AppendLine();
                helpMessage.Append("       -move".PadRight(20));
                helpMessage.Append("Moves files from one location to another");
                helpMessage.AppendLine();
                helpMessage.Append("       -overwrite".PadRight(20));
                helpMessage.Append("Overwrites files if they exist in the target location");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string source = FilePath.GetAbsolutePath(requestInfo.Request.Arguments["orderedarg1"]);
                string target = FilePath.GetDirectoryName(FilePath.GetAbsolutePath(requestInfo.Request.Arguments["orderedarg2"]));
                string directory = FilePath.GetDirectoryName(source);
                string filePattern = FilePath.GetFileName(source);
                bool copy = requestInfo.Request.Arguments.Exists("copy");
                bool move = requestInfo.Request.Arguments.Exists("move");
                bool overwrite = requestInfo.Request.Arguments.Exists("overwrite");

                string targetFile;
                foreach (string sourceFile in Directory.GetFiles(directory, filePattern))
                {
                    targetFile = Path.Combine(target, FilePath.GetFileName(sourceFile));
                    if (!File.Exists(targetFile) || overwrite)
                    {
                        // File can be copied or moved.
                        if (copy)
                        {
                            // Copy the file.
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Copying file '{0}'...\r\n\r\n", target);
                            File.Copy(sourceFile, targetFile, true);
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "File '{0}' copied successfully.\r\n\r\n", target);
                        }
                        else if (move)
                        {
                            // Move the file.
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Moving file '{0}'...\r\n\r\n", target);
                            File.Delete(targetFile);
                            File.Move(sourceFile, targetFile);
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "File '{0}' moved successfully.\r\n\r\n", target);
                        }
                        else
                        {
                            // Invalid command option specified.
                            UpdateStatus(UpdateType.Alarm, "Command option is not valid.\r\n\r\n");
                        }
                    }
                    else
                    {
                        // File already exists.
                        UpdateStatus(UpdateType.Alarm, "File '{0}' already exists.\r\n\r\n", targetFile);
                    }
                }
            }
        }
        private void ReloadSettings(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest || requestInfo.Request.Arguments.OrderedArgCount < 1)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Reloads settings of the component whose settings are saved under the specified category in the config file.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       ReloadSettings \"Category Name\" -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("IMPORTANT: Only settings under the categories listed by the \"Settings\" command can be reloaded.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string categoryName = requestInfo.Request.Arguments["orderedarg1"];

                IPersistSettings typedComponent;
                lock (m_serviceComponents)
                {
                    foreach (object component in m_serviceComponents)
                    {
                        typedComponent = component as IPersistSettings;

                        if ((object)typedComponent == null || string.Compare(categoryName, typedComponent.SettingsCategory, StringComparison.OrdinalIgnoreCase) != 0)
                            continue;

                        typedComponent.LoadSettings();
                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully loaded settings from category \"{0}\".\r\n\r\n", categoryName);
                        return;
                    }
                }

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to load settings from category \"{0}\". No corresponding component exists.\r\n\r\n", categoryName);
            }
        }
        private void ShowVersion(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Shows the current service version.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Version -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -actionable".PadRight(20));
                helpMessage.Append("Returns results via an actionable event");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                StringBuilder versionInfo = new StringBuilder();
                AssemblyInfo serviceAssembly = AssemblyInfo.EntryAssembly;
                string serviceName;

                if ((object)m_parentService != null && !string.IsNullOrWhiteSpace(m_parentService.ServiceName))
                    serviceName = m_parentService.ServiceName;
                else
                    serviceName = AppDomain.CurrentDomain.FriendlyName;

                // Get current process memory usage
                long processMemory = Common.GetProcessMemory();

                versionInfo.AppendFormat("{0} Service Version:{1}{1}", serviceName, Environment.NewLine);
                versionInfo.AppendFormat("      App Domain: {0}, running on .NET {1}{2}", AppDomain.CurrentDomain.FriendlyName, Environment.Version, Environment.NewLine);
                versionInfo.AppendFormat("    Machine Name: {0}{1}", Environment.MachineName, Environment.NewLine);
                versionInfo.AppendFormat("      OS Version: {0}{1}", Environment.OSVersion.VersionString, Environment.NewLine);
                versionInfo.AppendFormat("    Product Name: {0}{1}", Common.GetOSProductName(), Environment.NewLine);
                versionInfo.AppendFormat("  Working Memory: {0}{1}", processMemory > 0 ? SI2.ToScaledString(processMemory, 4, "B", SI2.IECSymbols) : "Undetermined", Environment.NewLine);
                versionInfo.AppendFormat("  Execution Mode: {0}-bit{1}", IntPtr.Size * 8, Environment.NewLine);
                versionInfo.AppendFormat("      Processors: {0}{1}", Environment.ProcessorCount, Environment.NewLine);
                versionInfo.AppendFormat("       Code Base: {0}{1}", serviceAssembly.CodeBase, Environment.NewLine);
                versionInfo.AppendFormat("      Build Date: {0}{1}", serviceAssembly.BuildDate, Environment.NewLine);
                versionInfo.AppendFormat("         Version: {0}", serviceAssembly.Version);

                string message = versionInfo.ToString();
                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, message + "{0}{0}", Environment.NewLine);

                // Also allow consumers to directly consume message via event in response to a version request
                if (requestInfo.Request.Arguments.Exists("actionable"))
                    SendActionableResponse(requestInfo, true, null, message);
            }
        }
        private void UpdateSettings(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest || requestInfo.Request.Arguments.OrderedArgCount < 3)
            {
                // We'll display help about the request since we either don't have the required arguments or the user
                // has explicitly requested for the help to be displayed for this request type.
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Updates the specified setting under the specified category in the config file.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       UpdateSettings \"Category Name\" \"Setting Name\" \"Setting Value\" -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -add".PadRight(20));
                helpMessage.Append("Adds specified setting to the specified category");
                helpMessage.AppendLine();
                helpMessage.Append("       -delete".PadRight(20));
                helpMessage.Append("Deletes specified setting from the specified category");
                helpMessage.AppendLine();
                helpMessage.Append("       -reload".PadRight(20));
                helpMessage.Append("Causes corresponding component to reload settings");
                helpMessage.AppendLine();
                helpMessage.Append("       -list".PadRight(20));
                helpMessage.Append("Displays list all of the queryable settings");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("IMPORTANT: Only settings under the categories listed by the \"Settings\" command can be updated.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string categoryName = requestInfo.Request.Arguments["orderedarg1"];
                string settingName = requestInfo.Request.Arguments["orderedarg2"];
                string settingValue = requestInfo.Request.Arguments["orderedarg3"];
                bool addSetting = requestInfo.Request.Arguments.Exists("add");
                bool deleteSetting = requestInfo.Request.Arguments.Exists("delete");
                bool reloadSettings = requestInfo.Request.Arguments.Exists("reload");
                bool listSettings = requestInfo.Request.Arguments.Exists("list");

                IPersistSettings typedComponent;
                lock (m_serviceComponents)
                {
                    foreach (object component in m_serviceComponents)
                    {
                        typedComponent = component as IPersistSettings;

                        if ((object)typedComponent == null || string.Compare(categoryName, typedComponent.SettingsCategory, StringComparison.OrdinalIgnoreCase) != 0)
                            continue;

                        ConfigurationFile config = ConfigurationFile.Current;
                        CategorizedSettingsElementCollection settings = config.Settings[categoryName];
                        CategorizedSettingsElement setting = settings[settingName];

                        if (addSetting)
                        {
                            // Add new setting.
                            if ((object)setting == null)
                            {
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Attempting to add setting \"{0}\" under category \"{1}\"...\r\n\r\n", settingName, categoryName);
                                settings.Add(settingName, settingValue);
                                config.Save();
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully added setting \"{0}\" under category \"{1}\".\r\n\r\n", settingName, categoryName);
                            }
                            else
                            {
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to add setting \"{0}\" under category \"{1}\". Setting already exists.\r\n\r\n", settingName, categoryName);
                                return;
                            }
                        }
                        else if (deleteSetting)
                        {
                            // Delete existing setting.
                            if ((object)setting != null)
                            {
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Attempting to delete setting \"{0}\" under category \"{1}\"...\r\n\r\n", settingName, categoryName);
                                settings.Remove(setting);
                                config.Save();
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully deleted setting \"{0}\" under category \"{1}\".\r\n\r\n", settingName, categoryName);
                            }
                            else
                            {
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to delete setting \"{0}\" under category \"{1}\". Setting does not exist.\r\n\r\n", settingName, categoryName);
                                return;
                            }
                        }
                        else
                        {
                            // Update existing setting.
                            if ((object)setting != null)
                            {
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Attempting to update setting \"{0}\" under category \"{1}\"...\r\n\r\n", settingName, categoryName);
                                setting.Value = settingValue;
                                config.Save();
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully updated setting \"{0}\" under category \"{1}\".\r\n\r\n", settingName, categoryName);
                            }
                            else
                            {
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to update value of setting \"{0}\" under category \"{1}\" . Setting does not exist.\r\n\r\n", settingName, categoryName);
                                return;
                            }
                        }

                        if (reloadSettings)
                        {
                            // The user has requested to reload settings for all the components.
                            requestInfo.Request = ClientRequest.Parse($"ReloadSettings {categoryName}");
                            ReloadSettings(requestInfo);
                        }

                        if (!listSettings)
                            return;

                        // The user has requested to list all of the queryable settings.
                        requestInfo.Request = ClientRequest.Parse("Settings");
                        ShowSettings(requestInfo);

                        return;
                    }
                }

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to update settings under category \"{0}\". No corresponding component exists.\r\n\r\n", categoryName);
            }
        }
        private void ShowUser(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Shows the current user information.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       User -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -actionable".PadRight(20));
                helpMessage.Append("Returns results via an actionable event");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                //          1         2         3         4         5         6         7         8
                // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
                //   Current user: ABC\john
                //    Client name: openPDCConsole
                //   From machine: JohnPC
                // Connected time: xx days yy hours zz minutes ii seconds
                //  Authenticated: true

                ClientInfo info = requestInfo.Sender;

                string message = $"  Current user: {info.ClientUser.Identity.Name.ToNonNullNorEmptyString("Undetermined")}\r\n" + $"   Client name: {info.ClientName.ToNonNullNorEmptyString("Undetermined")}\r\n" + $"  From machine: {info.MachineName.ToNonNullNorEmptyString("Undetermined")}\r\n" + $"Connected time: {(info.ConnectedAt > DateTime.MinValue ? (DateTime.UtcNow - info.ConnectedAt).ToElapsedTimeString() : m_remotingServer.RunTime.ToString())}\r\n" + $" Authenticated: {info.ClientUser.Identity.IsAuthenticated}";

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, message + "\r\n\r\n");

                // Also allow consumers to directly consume message via event in response to a user info request
                if (requestInfo.Request.Arguments.Exists("actionable"))
                    SendActionableResponse(requestInfo, true, null, message);
            }
        }
        private void StartProcess(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest || requestInfo.Request.Arguments.OrderedArgCount < 1)
            {
                bool showAdvancedHelp = requestInfo.Request.Arguments.Exists("advanced");

                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Starts execution of the specified service or system process.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Start \"Process Name\" -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -args".PadRight(20));
                helpMessage.Append("Arguments to be passed in to the process");
                helpMessage.AppendLine();
                helpMessage.Append("       -restart".PadRight(20));
                helpMessage.Append("Aborts the process if executing and start it again");
                helpMessage.AppendLine();
                helpMessage.Append("       -list".PadRight(20));
                helpMessage.Append("Displays list of all service or system processes");
                if (m_supportSystemCommands && showAdvancedHelp)
                {
                    helpMessage.AppendLine();
                    helpMessage.Append("       -system".PadRight(20));
                    helpMessage.Append("Treats the specified process as a system process");
                }
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string processName = requestInfo.Request.Arguments["orderedarg1"];
                string processArgs = requestInfo.Request.Arguments["args"];
                bool systemProcess = requestInfo.Request.Arguments.Exists("system");
                bool restartProcess = requestInfo.Request.Arguments.Exists("restart");
                bool listProcesses = requestInfo.Request.Arguments.Exists("list");

                if (restartProcess)
                {
                    requestInfo.Request = ClientRequest.Parse($"Abort \"{processName}\" {(systemProcess ? "-system" : "")}");
                    AbortProcess(requestInfo);
                }

                if (systemProcess && m_supportSystemCommands)
                {
                    // Start system process.
                    try
                    {
                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Attempting to start system process \"{0}\"...\r\n\r\n", processName);
                        Process startedProcess = Process.Start(processName, processArgs);

                        if ((object)startedProcess != null)
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully started system process \"{0}\".\r\n\r\n", processName);
                        else
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to start system process \"{0}\".\r\n\r\n", processName);
                    }
                    catch (Exception ex)
                    {
                        LogException(ex);
                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to start system process \"{0}\". {1}.\r\n\r\n", processName, ex.Message);
                    }
                }
                else
                {
                    // Start service process.
                    ServiceProcess processToStart = FindProcess(processName);

                    if ((object)processToStart != null)
                    {
                        if (processToStart.CurrentState != ServiceProcessState.Processing)
                        {
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Attempting to start service process \"{0}\"...\r\n\r\n", processName);

                            if (string.IsNullOrEmpty(processArgs))
                            {
                                processToStart.Start();
                            }
                            else
                            {
                                // Prepare the arguments.
                                string[] splitArgs = processArgs.Split(',');

                                for (int i = 0; i < splitArgs.Length; i++)
                                {
                                    splitArgs[i] = splitArgs[i].Trim();
                                }

                                // Start the service process.
                                processToStart.Start(splitArgs.Cast<object>().ToArray());
                            }
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully started service process \"{0}\".\r\n\r\n", processName);
                        }
                        else
                        {
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to start process \"{0}\". Process is already executing.\r\n\r\n", processName);
                        }
                    }
                    else
                    {
                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to start service process \"{0}\". Process is not defined.\r\n\r\n", processName);
                    }
                }

                if (!listProcesses)
                    return;

                requestInfo.Request = ClientRequest.Parse($"Processes {(systemProcess ? "-system" : "")}");
                ShowProcesses(requestInfo);
            }
        }
 /// <summary>
 /// Displays a response message to client requestor.
 /// </summary>
 /// <param name="requestInfo"><see cref="ClientRequestInfo"/> instance containing the client request.</param>
 /// <param name="status">Formatted status message to send to client.</param>
 /// <param name="args">Arguments of the formatted status message.</param>
 protected virtual void DisplayResponseMessage(ClientRequestInfo requestInfo, string status, params object[] args)
 {
     try
     {
         m_serviceHelper.UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, string.Format("{0}\r\n\r\n", status), args);
     }
     catch (Exception ex)
     {
         string message = string.Format("Failed to update client status \"{0}\" due to an exception: {1}", status.ToNonNullString(), ex.Message);
         HandleException(new InvalidOperationException(message, ex));
     }
 }
        private void AbortProcess(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest || requestInfo.Request.Arguments.OrderedArgCount < 1)
            {
                bool showAdvancedHelp = requestInfo.Request.Arguments.Exists("advanced");

                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Aborts the specified service or system process if executing.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Abort \"Process Name\" -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -list".PadRight(20));
                helpMessage.Append("Displays list of all service or system processes");
                if (m_supportSystemCommands && showAdvancedHelp)
                {
                    helpMessage.AppendLine();
                    helpMessage.Append("       -system".PadRight(20));
                    helpMessage.Append("Treats the specified process as a system process");
                    helpMessage.AppendLine();
                    helpMessage.AppendLine();
                    helpMessage.Append("NOTE: Specify process name of \"Me\" to kill current service process. ");
                }
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string processName = requestInfo.Request.Arguments["orderedarg1"];
                bool systemProcess = requestInfo.Request.Arguments.Exists("system");
                bool listProcesses = requestInfo.Request.Arguments.Exists("list");

                if (systemProcess && m_supportSystemCommands)
                {
                    // Abort system process.
                    Process processToAbort = null;

                    if (string.Compare(processName, "Me", StringComparison.OrdinalIgnoreCase) == 0)
                        processName = Process.GetCurrentProcess().ProcessName;

                    foreach (Process process in Process.GetProcessesByName(processName))
                    {
                        // Lookup for the system process by name.
                        processToAbort = process;
                        break;
                    }

                    if ((object)processToAbort == null)
                    {
                        int processID;

                        if (int.TryParse(processName, out processID) && processID > 0)
                        {
                            processToAbort = Process.GetProcessById(processID);
                            processName = processToAbort.ProcessName;
                        }
                    }

                    if ((object)processToAbort != null)
                    {
                        try
                        {
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Attempting to abort system process \"{0}\"...\r\n\r\n", processName);
                            processToAbort.Kill();
                            if (processToAbort.WaitForExit(10000))
                            {
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully aborted system process \"{0}\".\r\n\r\n", processName);
                            }
                            else
                            {
                                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to abort system process \"{0}\". Process not responding.\r\n\r\n", processName);
                            }
                        }
                        catch (Exception ex)
                        {
                            LogException(ex);
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to abort system process \"{0}\". {1}.\r\n\r\n", processName, ex.Message);
                        }
                    }
                    else
                    {
                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to abort system process \"{0}\". Process is not running.\r\n\r\n", processName);
                    }
                }
                else
                {
                    // Abort service process.
                    ServiceProcess processToAbort = FindProcess(processName);

                    if ((object)processToAbort != null)
                    {
                        if (processToAbort.CurrentState == ServiceProcessState.Processing)
                        {
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Attempting to abort service process \"{0}\"...\r\n\r\n", processName);
                            processToAbort.Abort();
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully aborted service process \"{0}\".\r\n\r\n", processName);
                        }
                        else
                        {
                            UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to abort service process \"{0}\". Process is not executing.\r\n\r\n", processName);
                        }
                    }
                    else
                    {
                        UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to abort service process \"{0}\". Process is not defined.\r\n\r\n", processName);
                    }
                }

                if (!listProcesses)
                    return;

                requestInfo.Request = ClientRequest.Parse($"Processes {(systemProcess ? "-system" : "")}");
                ShowProcesses(requestInfo);
            }
        }
        /// <summary>
        /// Sends an actionable response to client with a formatted message and attachment.
        /// </summary>
        /// <param name="requestInfo"><see cref="ClientRequestInfo"/> instance containing the client request.</param>
        /// <param name="success">Flag that determines if this response to client request was a success.</param>
        /// <param name="attachment">Attachment to send with response.</param>
        /// <param name="status">Formatted status message to send with response.</param>
        /// <param name="args">Arguments of the formatted status message.</param>
        protected virtual void SendResponseWithAttachment(ClientRequestInfo requestInfo, bool success, object attachment, string status, params object[] args)
        {
            try
            {
                // Send actionable response
                m_serviceHelper.SendActionableResponse(requestInfo, success, attachment, status, args);

                // Log details of client request as well as response
                if (m_serviceHelper.LogStatusUpdates && m_serviceHelper.StatusLog.IsOpen)
                {
                    string responseType = requestInfo.Request.Command + (success ? ":Success" : ":Failure");
                    string arguments = requestInfo.Request.Arguments.ToString();
                    string message = responseType + (string.IsNullOrWhiteSpace(arguments) ? "" : "(" + arguments + ")");

                    if (status != null)
                    {
                        if (args.Length == 0)
                            message += " - " + status;
                        else
                            message += " - " + string.Format(status, args);
                    }

                    m_serviceHelper.StatusLog.WriteTimestampedLine(message);
                }
            }
            catch (Exception ex)
            {
                string message = string.Format("Failed to send client response due to an exception: {0}", ex.Message);
                HandleException(new InvalidOperationException(message, ex));
            }
        }
        private void RescheduleProcess(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest || requestInfo.Request.Arguments.OrderedArgCount < 2)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Schedules or re-schedules an existing process defined in the service.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Reschedule \"Process Name\" \"Schedule Rule\" -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.Append("       -save".PadRight(20));
                helpMessage.Append("Saves all process schedules to the config file");
                helpMessage.AppendLine();
                helpMessage.Append("       -list".PadRight(20));
                helpMessage.Append("Displays list of all process schedules");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("NOTE: The schedule rule uses UNIX crontab syntax which consists of 5 parts (For example, \"* * * * *\"). ");
                helpMessage.Append("Following is a brief description of each of the 5 parts that make up the rule:");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Part 1 - Minute part; value range 0 to 59. ");
                helpMessage.AppendLine();
                helpMessage.Append("   Part 2 - Hour part; value range 0 to 23. ");
                helpMessage.AppendLine();
                helpMessage.Append("   Part 3 - Day of month part; value range 1 to 31. ");
                helpMessage.AppendLine();
                helpMessage.Append("   Part 4 - Month part; value range 1 to 12. ");
                helpMessage.AppendLine();
                helpMessage.Append("   Part 5 - Day of week part; value range 0 to 6 (0 = Sunday). ");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("Following is a description of valid syntax for all parts of the rule:");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   *       - Any value in the range for the date-time part.");
                helpMessage.AppendLine();
                helpMessage.Append("   */n     - Every nth value for the data-time part.");
                helpMessage.AppendLine();
                helpMessage.Append("   n1-n2   - Range of values (inclusive) for the date-time part.");
                helpMessage.AppendLine();
                helpMessage.Append("   n1,n2   - 1 or more specific values for the date-time part.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("Examples:");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   \"* * * * *\"       - Process executes every minute.");
                helpMessage.AppendLine();
                helpMessage.Append("   \"*/5 * * * *\"     - Process executes every 5 minutes.");
                helpMessage.AppendLine();
                helpMessage.Append("   \"5 * * * *\"       - Process executes 5 past every hour.");
                helpMessage.AppendLine();
                helpMessage.Append("   \"0 0 * * *\"       - Process executes every day at midnight.");
                helpMessage.AppendLine();
                helpMessage.Append("   \"0 0 1 * *\"       - Process executes 1st of every month at midnight.");
                helpMessage.AppendLine();
                helpMessage.Append("   \"0 0 * * 0\"       - Process executes every Sunday at midnight.");
                helpMessage.AppendLine();
                helpMessage.Append("   \"0 0 31 12 *\"     - Process executes on December 31 at midnight.");
                helpMessage.AppendLine();
                helpMessage.Append("   \"5,10 0-2 * * *\"  - Process executes 5 and 10 past hours 12am to 2am.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                string processName = requestInfo.Request.Arguments["orderedarg1"];
                string scheduleRule = requestInfo.Request.Arguments["orderedarg2"];
                bool saveSchedules = requestInfo.Request.Arguments.Exists("save");
                bool listSchedules = requestInfo.Request.Arguments.Exists("list");

                try
                {
                    // Schedule the process if not scheduled or update its schedule if scheduled.
                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Attempting to schedule process \"{0}\" with rule \"{1}\"...\r\n\r\n", processName, scheduleRule);
                    ScheduleProcess(processName, scheduleRule, true);
                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "Successfully scheduled process \"{0}\" with rule \"{1}\".\r\n\r\n", processName, scheduleRule);

                    if (saveSchedules)
                    {
                        requestInfo.Request = ClientRequest.Parse("SaveSchedules");
                        SaveSchedules(requestInfo);
                    }
                }
                catch (Exception ex)
                {
                    LogException(ex);
                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Alarm, "Failed to schedule process \"{0}\". {1}\r\n\r\n", processName, ex.Message);
                }

                if (!listSchedules)
                    return;

                requestInfo.Request = ClientRequest.Parse("Schedules");
                ShowSchedules(requestInfo);
            }
        }
        // Reload the device definitions file on request
        private void ReloadDeviceDefsRequestHandler(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Reloads the device definitions file.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       ReloadDeviceDefs [Options]");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");

                DisplayResponseMessage(requestInfo, helpMessage.ToString());
            }
            else
            {
                m_faultLocationEngine.ReloadDeviceDefinitionsFile();
                SendResponse(requestInfo, true);
            }
        }
        private void ShowClients(ClientRequestInfo requestInfo)
        {
            if (requestInfo.Request.Arguments.ContainsHelpRequest)
            {
                StringBuilder helpMessage = new StringBuilder();

                helpMessage.Append("Displays a list of clients currently connected to the service.");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Usage:");
                helpMessage.AppendLine();
                helpMessage.Append("       Clients -options");
                helpMessage.AppendLine();
                helpMessage.AppendLine();
                helpMessage.Append("   Options:");
                helpMessage.AppendLine();
                helpMessage.Append("       -?".PadRight(20));
                helpMessage.Append("Displays this help message");
                helpMessage.AppendLine();
                helpMessage.AppendLine();

                UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, helpMessage.ToString());
            }
            else
            {
                if (m_remoteClients.Count > 0)
                {
                    // Display info about all of the clients connected to the service.
                    StringBuilder responseMessage = new StringBuilder();

                    responseMessage.AppendFormat("Clients connected to {0}:", Name);
                    responseMessage.AppendLine();
                    responseMessage.AppendLine();
                    responseMessage.Append("Client".PadRight(25));
                    responseMessage.Append(' ');
                    responseMessage.Append("Machine".PadRight(15));
                    responseMessage.Append(' ');
                    responseMessage.Append("User".PadRight(15));
                    responseMessage.Append(' ');
                    responseMessage.Append("Connected".PadRight(20));
                    responseMessage.AppendLine();
                    responseMessage.Append(new string('-', 25));
                    responseMessage.Append(' ');
                    responseMessage.Append(new string('-', 15));
                    responseMessage.Append(' ');
                    responseMessage.Append(new string('-', 15));
                    responseMessage.Append(' ');
                    responseMessage.Append(new string('-', 20));

                    lock (m_remoteClients)
                    {
                        foreach (ClientInfo clientInfo in m_remoteClients)
                        {
                            responseMessage.AppendLine();

                            if (!string.IsNullOrEmpty(clientInfo.ClientName))
                                responseMessage.Append(clientInfo.ClientName.PadRight(25));
                            else
                                responseMessage.Append("[Not Available]".PadRight(25));

                            responseMessage.Append(' ');
                            if (!string.IsNullOrEmpty(clientInfo.MachineName))
                                responseMessage.Append(clientInfo.MachineName.PadRight(15));
                            else
                                responseMessage.Append("[Not Available]".PadRight(15));

                            responseMessage.Append(' ');
                            if (!string.IsNullOrEmpty(clientInfo.ClientUser.Identity.Name))
                                responseMessage.Append(clientInfo.ClientUser.Identity.Name.PadRight(15));
                            else
                                responseMessage.Append("[Not Available]".PadRight(15));

                            responseMessage.Append(' ');
                            responseMessage.Append(clientInfo.ConnectedAt.ToString("MM/dd/yy hh:mm:ss tt").PadRight(20));
                        }
                    }
                    responseMessage.AppendLine();
                    responseMessage.AppendLine();

                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, responseMessage.ToString());
                }
                else
                {
                    UpdateStatus(requestInfo.Sender.ClientID, UpdateType.Information, "No clients are connected to {0}\r\n\r\n", Name);
                }
            }
        }