From eb1f0a8cdbe253c45c134a740991a09394f99a05 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Tue, 26 Oct 2021 16:37:21 -0700 Subject: [PATCH 01/20] Added support for native Windows web sockets when available. --- FileViewer.cs | 5 +- KVMViewer.cs | 3 +- MainForm.cs | 22 ++ MeshCentralRouter.csproj | 2 +- MeshCentralServer.cs | 509 +++++---------------------------------- MeshMapper.cs | 6 +- WebSocketClient.cs | 403 +++++++++++++++++++++---------- app.config | 2 +- 8 files changed, 373 insertions(+), 579 deletions(-) diff --git a/FileViewer.cs b/FileViewer.cs index b872d11..b6fd7fd 100644 --- a/FileViewer.cs +++ b/FileViewer.cs @@ -327,7 +327,8 @@ namespace MeshCentralRouter wc.onStateChanged += Wc_onStateChanged; wc.onBinaryData += Wc_onBinaryData; wc.onStringData += Wc_onStringData; - wc.Start(u, server.wshash); + wc.TLSCertCheck = webSocketClient.TLSCertificateCheck.Fingerprint; + wc.Start(u, server.wshash, null); } private void Wc_onStateChanged(webSocketClient sender, webSocketClient.ConnectionStates wsstate) @@ -1250,7 +1251,7 @@ namespace MeshCentralRouter localFilePath = (string)uploadFileArray[uploadFileArrayPtr]; localFileName = Path.GetFileName(localFilePath); } - try { uploadFileStream = File.OpenRead(localFilePath); } catch (Exception ex) + try { uploadFileStream = File.OpenRead(localFilePath); } catch (Exception) { // Display the error if (transferStatusForm != null) { transferStatusForm.addErrorMessage(String.Format(Translate.T(Properties.Resources.UnableToOpenFileX), localFileName)); } diff --git a/KVMViewer.cs b/KVMViewer.cs index 0233f7d..120ce9c 100644 --- a/KVMViewer.cs +++ b/KVMViewer.cs @@ -184,7 +184,8 @@ namespace MeshCentralRouter wc.onStateChanged += Wc_onStateChanged; wc.onBinaryData += Wc_onBinaryData; wc.onStringData += Wc_onStringData; - wc.Start(u, server.wshash); + wc.TLSCertCheck = webSocketClient.TLSCertificateCheck.Fingerprint; + wc.Start(u, server.wshash, null); } private void Wc_onStateChanged(webSocketClient sender, webSocketClient.ConnectionStates wsstate) diff --git a/MainForm.cs b/MainForm.cs index 4f710f2..172920d 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -170,11 +170,32 @@ namespace MeshCentralRouter [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)]string lParam); + private bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors) + { + if (meshcentral.ignoreCert) return true; + if (meshcentral.connectionState < 2) + { + // Normal certificate check + if (chain.Build(new X509Certificate2(certificate)) == true) { meshcentral.certHash = webSocketClient.GetMeshKeyHash(certificate); return true; } + if ((meshcentral.okCertHash != null) && ((meshcentral.okCertHash == certificate.GetCertHashString()) || (meshcentral.okCertHash == webSocketClient.GetMeshKeyHash(certificate)) || (meshcentral.okCertHash == webSocketClient.GetMeshCertHash(certificate)))) { meshcentral.certHash = webSocketClient.GetMeshKeyHash(certificate); return true; } + if ((meshcentral.okCertHash2 != null) && ((meshcentral.okCertHash2 == certificate.GetCertHashString()) || (meshcentral.okCertHash2 == webSocketClient.GetMeshKeyHash(certificate)) || (meshcentral.okCertHash2 == webSocketClient.GetMeshCertHash(certificate)))) { meshcentral.certHash = webSocketClient.GetMeshKeyHash(certificate); return true; } + meshcentral.certHash = null; + meshcentral.disconnectMsg = "cert"; + meshcentral.disconnectCert = new X509Certificate2(certificate); + } + else + { + if ((meshcentral.certHash != null) && ((meshcentral.certHash == certificate.GetCertHashString()) || (meshcentral.certHash == webSocketClient.GetMeshKeyHash(certificate)) || (meshcentral.certHash == webSocketClient.GetMeshCertHash(certificate)))) { return true; } + } + return false; + } + public MainForm(string[] args) { // Set TLS 1.2 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(RemoteCertificateValidationCallback); this.args = args; InitializeComponent(); @@ -215,6 +236,7 @@ namespace MeshCentralRouter if (arg.ToLower() == "-all") { inaddrany = true; } if (arg.ToLower() == "-inaddrany") { inaddrany = true; } if (arg.ToLower() == "-tray") { notifyIcon.Visible = true; this.ShowInTaskbar = false; this.MinimizeBox = false; } + if (arg.ToLower() == "-nonative") { webSocketClient.nativeWebSocketFirst = false; } if (arg.Length > 6 && arg.Substring(0, 6).ToLower() == "-host:") { serverNameComboBox.Text = arg.Substring(6); argflags |= 1; } if (arg.Length > 6 && arg.Substring(0, 6).ToLower() == "-user:") { userNameTextBox.Text = arg.Substring(6); argflags |= 2; } if (arg.Length > 6 && arg.Substring(0, 6).ToLower() == "-pass:") { passwordTextBox.Text = arg.Substring(6); argflags |= 4; } diff --git a/MeshCentralRouter.csproj b/MeshCentralRouter.csproj index 7ba5a07..f327c63 100644 --- a/MeshCentralRouter.csproj +++ b/MeshCentralRouter.csproj @@ -10,7 +10,7 @@ Properties MeshCentralRouter MeshCentralRouter - v4.5 + v4.7.2 512 MeshCentralRouter.Program MeshServer.ico diff --git a/MeshCentralServer.cs b/MeshCentralServer.cs index 3e40085..ecd131d 100644 --- a/MeshCentralServer.cs +++ b/MeshCentralServer.cs @@ -17,11 +17,7 @@ limitations under the License. using System; using System.IO; using System.Web; -using System.Text; using System.Collections; -using System.Net.Sockets; -using System.Net.Security; -using System.Windows.Forms; using System.Collections.Generic; using System.Security.Cryptography; using System.Deployment.Application; @@ -39,7 +35,7 @@ namespace MeshCentralRouter private string user = null; private string pass = null; private string token = null; - private xwebclient wc = null; + private webSocketClient wc = null; //private System.Timers.Timer procTimer = new System.Timers.Timer(5000); private int constate = 0; public Dictionary nodes = null; @@ -70,6 +66,8 @@ namespace MeshCentralRouter public int features = 0; // Bit flags of server features public int features2 = 0; // Bit flags of server features + public int connectionState { get { return constate; } } + // Mesh Rights /* const MESHRIGHT_EDITMESH = 1; @@ -146,13 +144,25 @@ namespace MeshCentralRouter this.token = token; this.wsurl = wsurl; - wc = new xwebclient(); + // Setup extra headers if needed + Dictionary extraHeaders = new Dictionary(); + if (user != null && pass != null && token != null) { + extraHeaders.Add("x-meshauth", Base64Encode(user) + "," + Base64Encode(pass) + "," + Base64Encode(token)); + } else if (user != null && pass != null) { + extraHeaders.Add("x-meshauth", Base64Encode(user) + "," + Base64Encode(pass)); + } + + wc = new webSocketClient(); + wc.extraHeaders = extraHeaders; + wc.onStateChanged += new webSocketClient.onStateChangedHandler(changeStateEx); + wc.onStringData += new webSocketClient.onStringDataHandler(processServerData); //Debug("#" + counter + ": Connecting web socket to: " + wsurl.ToString()); - wc.Start(this, wsurl, user, pass, token, wshash); + wc.TLSCertCheck = webSocketClient.TLSCertificateCheck.Verify; + wc.Start(wsurl, okCertHash, okCertHash2); if (debug || tlsdump) { try { File.AppendAllText("debug.log", "Connect-" + wsurl + "\r\n"); } catch (Exception) { } } - wc.xdebug = debug; - wc.xtlsdump = tlsdump; - wc.xignoreCert = ignoreCert; + wc.debug = debug; + wc.tlsdump = tlsdump; + wc.TLSCertCheck = (ignoreCert) ? webSocketClient.TLSCertificateCheck.Ignore : webSocketClient.TLSCertificateCheck.Verify; } public void disconnect() @@ -170,7 +180,7 @@ namespace MeshCentralRouter if (wc != null) { if (debug) { try { File.AppendAllText("debug.log", "sendCommand: " + cmd + "\r\n"); } catch (Exception) { } } - wc.WriteStringWebSocket(cmd); + wc.SendString(cmd); } } @@ -178,8 +188,8 @@ namespace MeshCentralRouter { if (wc != null) { if (debug) { try { File.AppendAllText("debug.log", "RefreshCookies\r\n"); } catch (Exception) { } } - wc.WriteStringWebSocket("{\"action\":\"authcookie\"}"); - wc.WriteStringWebSocket("{\"action\":\"logincookie\"}"); + wc.SendString("{\"action\":\"authcookie\"}"); + wc.SendString("{\"action\":\"logincookie\"}"); } } @@ -188,11 +198,11 @@ namespace MeshCentralRouter if (wc != null) { if (debug) { try { File.AppendAllText("debug.log", "SetRdpPort\r\n"); } catch (Exception) { } } - wc.WriteStringWebSocket("{\"action\":\"changedevice\",\"nodeid\":\"" + node.nodeid + "\",\"rdpport\":" + port + "}"); + wc.SendString("{\"action\":\"changedevice\",\"nodeid\":\"" + node.nodeid + "\",\"rdpport\":" + port + "}"); } } - public void processServerData(string data) + public void processServerData(webSocketClient sender, string data, int orglen) { if (debug) { try { File.AppendAllText("debug.log", "ServerData-" + data + "\r\n"); } catch (Exception) { } } @@ -223,7 +233,7 @@ namespace MeshCentralRouter case "ping": { // Send pong back - if (wc != null) { wc.WriteStringWebSocket("{\"action\":\"pong\"}"); } + if (wc != null) { wc.SendString("{\"action\":\"pong\"}"); } break; } case "close": @@ -245,12 +255,12 @@ namespace MeshCentralRouter if (serverinfo.ContainsKey("features2") && (serverinfo["features2"].GetType() == typeof(int))) { features2 = (int)serverinfo["features2"]; } // Ask for a lot of things from the server - wc.WriteStringWebSocket("{\"action\":\"usergroups\"}"); - wc.WriteStringWebSocket("{\"action\":\"meshes\"}"); - wc.WriteStringWebSocket("{\"action\":\"nodes\"}"); - wc.WriteStringWebSocket("{\"action\":\"authcookie\"}"); - wc.WriteStringWebSocket("{\"action\":\"logincookie\"}"); - wc.WriteStringWebSocket("{\"action\":\"meshToolInfo\",\"name\":\"MeshCentralRouter\"}"); + wc.SendString("{\"action\":\"usergroups\"}"); + wc.SendString("{\"action\":\"meshes\"}"); + wc.SendString("{\"action\":\"nodes\"}"); + wc.SendString("{\"action\":\"authcookie\"}"); + wc.SendString("{\"action\":\"logincookie\"}"); + wc.SendString("{\"action\":\"meshToolInfo\",\"name\":\"MeshCentralRouter\"}"); break; } case "authcookie": @@ -258,6 +268,12 @@ namespace MeshCentralRouter authCookie = jsonAction["cookie"].ToString(); rauthCookie = jsonAction["rcookie"].ToString(); changeState(2); + + if (sender.RemoteCertificate != null) + { + certHash = webSocketClient.GetMeshCertHash(new X509Certificate2(sender.RemoteCertificate)); + } + break; } case "logincookie": @@ -362,7 +378,7 @@ namespace MeshCentralRouter mesh.links = newlinks; meshes[meshid] = mesh; } - wc.WriteStringWebSocket("{\"action\":\"nodes\"}"); + wc.SendString("{\"action\":\"nodes\"}"); if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(false); break; } @@ -427,7 +443,7 @@ namespace MeshCentralRouter } else { - wc.WriteStringWebSocket("{\"action\":\"nodes\"}"); + wc.SendString("{\"action\":\"nodes\"}"); } break; } @@ -449,8 +465,8 @@ namespace MeshCentralRouter } case "usergroupchange": { - wc.WriteStringWebSocket("{\"action\":\"usergroups\"}"); - wc.WriteStringWebSocket("{\"action\":\"nodes\"}"); + wc.SendString("{\"action\":\"usergroups\"}"); + wc.SendString("{\"action\":\"nodes\"}"); break; } } @@ -697,6 +713,16 @@ namespace MeshCentralRouter public event onStateChangedHandler onStateChanged; public void changeState(int newState) { if (constate != newState) { constate = newState; if (onStateChanged != null) { onStateChanged(constate); } } } + private void changeStateEx(webSocketClient sender, webSocketClient.ConnectionStates newState) + { + if (newState == webSocketClient.ConnectionStates.Disconnected) { + if (sender.failedTlsCert != null) { certHash = null; disconnectMsg = "cert"; disconnectCert = sender.failedTlsCert; } + changeState(0); + } + if (newState == webSocketClient.ConnectionStates.Connecting) { changeState(1); } + if (newState == webSocketClient.ConnectionStates.Connected) { } + } + public delegate void onNodeListChangedHandler(bool fullRefresh); public event onNodeListChangedHandler onNodesChanged; public delegate void onLoginTokenChangedHandler(); @@ -708,431 +734,16 @@ namespace MeshCentralRouter public delegate void toolUpdateHandler(string url, string hash, int size, string serverhash); public event toolUpdateHandler onToolUpdate; - public class xwebclient : IDisposable + public string Base64Encode(string plainText) { - private MeshCentralServer parent = null; - private TcpClient wsclient = null; - private SslStream wsstream = null; - private NetworkStream wsrawstream = null; - private int state = 0; - private Uri url = null; - private byte[] readBuffer = new Byte[500]; - private int readBufferLen = 0; - private int accopcodes = 0; - private bool accmask = false; - private int acclen = 0; - private bool proxyInUse = false; - private string user = null; - private string pass = null; - private string token = null; - public bool xdebug = false; - public bool xtlsdump = false; - public bool xignoreCert = false; - - public void Dispose() { - try { wsstream.Close(); } catch (Exception) { } - try { wsstream.Dispose(); } catch (Exception) { } - wsstream = null; - wsclient = null; - state = -1; - parent.changeState(0); - parent.wshash = null; - } - - public void Debug(string msg) { if (xdebug) { try { File.AppendAllText("debug.log", "Debug-" + msg + "\r\n"); } catch (Exception) { } } } - public void TlsDump(string direction, byte[] data, int offset, int len) { if (xtlsdump) { try { File.AppendAllText("debug.log", direction + ": " + BitConverter.ToString(data, offset, len).Replace("-", string.Empty) + "\r\n"); } catch (Exception) { } } } - - public bool Start(MeshCentralServer parent, Uri url, string user, string pass, string token, string fingerprint) - { - if (state != 0) return false; - parent.changeState(1); - state = 1; - this.parent = parent; - this.url = url; - this.user = user; - this.pass = pass; - this.token = token; - Uri proxyUri = null; - - // Check if we need to use a HTTP proxy (Auto-proxy way) - try { - RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); - Object x = registryKey.GetValue("AutoConfigURL", null); - if ((x != null) && (x.GetType() == typeof(string))) { - string proxyStr = GetProxyForUrlUsingPac("http" + ((url.Port == 80) ? "" : "s") + "://" + url.Host + ":" + url.Port, x.ToString()); - if (proxyStr != null) { proxyUri = new Uri("http://" + proxyStr); } - } - } catch (Exception) { proxyUri = null; } - - // Check if we need to use a HTTP proxy (Normal way) - if (proxyUri == null) { - var proxy = System.Net.HttpWebRequest.GetSystemWebProxy(); - proxyUri = proxy.GetProxy(url); - if ((url.Host.ToLower() == proxyUri.Host.ToLower()) && (url.Port == proxyUri.Port)) { proxyUri = null; } - } - - if (proxyUri != null) - { - // Proxy in use - proxyInUse = true; - wsclient = new TcpClient(); - Debug("Connecting with proxy in use: " + proxyUri.ToString()); - wsclient.BeginConnect(proxyUri.Host, proxyUri.Port, new AsyncCallback(OnConnectSink), this); - } - else - { - // No proxy in use - proxyInUse = false; - wsclient = new TcpClient(); - Debug("Connecting without proxy"); - wsclient.BeginConnect(url.Host, url.Port, new AsyncCallback(OnConnectSink), this); - } - return true; - } - - private void OnConnectSink(IAsyncResult ar) - { - if (wsclient == null) return; - - // Accept the connection - try - { - wsclient.EndConnect(ar); - } catch (Exception ex) { - Debug("Websocket TCP failed to connect: " + ex.ToString()); - Dispose(); - return; - } - - if (proxyInUse == true) - { - // Send proxy connection request - wsrawstream = wsclient.GetStream(); - byte[] proxyRequestBuf = UTF8Encoding.UTF8.GetBytes("CONNECT " + url.Host + ":" + url.Port + " HTTP/1.1\r\nHost: " + url.Host + ":" + url.Port + "\r\n\r\n"); - TlsDump("OutRaw", proxyRequestBuf, 0, proxyRequestBuf.Length); - try { wsrawstream.Write(proxyRequestBuf, 0, proxyRequestBuf.Length); } catch (Exception ex) { Debug(ex.ToString()); } - wsrawstream.BeginRead(readBuffer, readBufferLen, readBuffer.Length - readBufferLen, new AsyncCallback(OnProxyResponseSink), this); - } - else - { - // Start TLS connection - Debug("Websocket TCP connected, doing TLS..."); - wsstream = new SslStream(wsclient.GetStream(), false, VerifyServerCertificate, null); - wsstream.BeginAuthenticateAsClient(url.Host, null, System.Security.Authentication.SslProtocols.Tls12, false, new AsyncCallback(OnTlsSetupSink), this); - } - } - - private void OnProxyResponseSink(IAsyncResult ar) - { - if (wsrawstream == null) return; - - int len = 0; - try { len = wsrawstream.EndRead(ar); } catch (Exception) { } - if (len == 0) - { - // Disconnect - Debug("Websocket proxy disconnected, length = 0."); - Dispose(); - return; - } - - TlsDump("InRaw", readBuffer, 0, readBufferLen); - - readBufferLen += len; - string proxyResponse = UTF8Encoding.UTF8.GetString(readBuffer, 0, readBufferLen); - if (proxyResponse.IndexOf("\r\n\r\n") >= 0) - { - // We get a full proxy response, we should get something like "HTTP/1.1 200 Connection established\r\n\r\n" - if (proxyResponse.StartsWith("HTTP/1.1 200 ")) - { - // All good, start TLS setup. - readBufferLen = 0; - Debug("Websocket TCP connected, doing TLS..."); - wsstream = new SslStream(wsrawstream, false, VerifyServerCertificate, null); - wsstream.BeginAuthenticateAsClient(url.Host, null, System.Security.Authentication.SslProtocols.Tls12, false, new AsyncCallback(OnTlsSetupSink), this); - } - else - { - // Invalid response - Debug("Proxy connection failed: " + proxyResponse); - Dispose(); - } - } else { - if (readBufferLen == readBuffer.Length) - { - // Buffer overflow - Debug("Proxy connection failed"); - Dispose(); - } - else - { - // Read more proxy data - wsrawstream.BeginRead(readBuffer, readBufferLen, readBuffer.Length - readBufferLen, new AsyncCallback(OnProxyResponseSink), this); - } - } - } - - public string Base64Encode(string plainText) - { - var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText); - return System.Convert.ToBase64String(plainTextBytes); - } - - public string Base64Decode(string base64EncodedData) - { - var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData); - return System.Text.Encoding.UTF8.GetString(base64EncodedBytes); - } - - private void OnTlsSetupSink(IAsyncResult ar) - { - if (wsstream == null) return; - - // Accept the connection - try - { - wsstream.EndAuthenticateAsClient(ar); - } - catch (Exception ex) - { - // Disconnect - if (ex.InnerException != null) { - MessageBox.Show(ex.Message + ", Inner: " + ex.InnerException.ToString(), "MeshCentral Router"); - } else { - MessageBox.Show(ex.Message, "MeshCentral Router"); - } - Debug("Websocket TLS failed: " + ex.ToString()); - Dispose(); - return; - } - - // Fetch remote certificate - parent.wshash = wsstream.RemoteCertificate.GetCertHashString(); - - // Setup extra headers if needed - string extraHeaders = ""; - if (user != null && pass != null && token != null) { extraHeaders = "x-meshauth: " + Base64Encode(user) + "," + Base64Encode(pass) + "," + Base64Encode(token) + "\r\n"; } - else if (user != null && pass != null) { extraHeaders = "x-meshauth: " + Base64Encode(user) + "," + Base64Encode(pass) + "\r\n"; } - - // Send the HTTP headers - Debug("Websocket TLS setup, sending HTTP header..."); - string header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n" + extraHeaders + "\r\n"; - try { wsstream.Write(UTF8Encoding.UTF8.GetBytes(header)); } catch (Exception ex) { Debug(ex.ToString()); } - - // Start receiving data - wsstream.BeginRead(readBuffer, readBufferLen, readBuffer.Length - readBufferLen, new AsyncCallback(OnTlsDataSink), this); - } - - private void OnTlsDataSink(IAsyncResult ar) - { - if (wsstream == null) return; - - int len = 0; - try { len = wsstream.EndRead(ar); } catch (Exception) { } - if (len == 0) - { - // Disconnect - Debug("Websocket disconnected, length = 0."); - Dispose(); - return; - } - //parent.Debug("#" + counter + ": Websocket got new data: " + len); - readBufferLen += len; - TlsDump("In", readBuffer, 0, len); - - // Consume all of the data - int consumed = 0; - int ptr = 0; - do - { - consumed = ProcessBuffer(readBuffer, ptr, readBufferLen - ptr); - if (consumed < 0) { Dispose(); return; } // Error, close the connection - ptr += consumed; - } while ((consumed > 0) && ((readBufferLen - consumed) > 0)); - - // Move the data forward - if ((ptr > 0) && (readBufferLen - ptr) > 0) { - //Console.Write("MOVE FORWARD\r\n"); - Array.Copy(readBuffer, ptr, readBuffer, 0, (readBufferLen - ptr)); - } - readBufferLen = (readBufferLen - ptr); - - // If the buffer is too small, double the size here. - if (readBuffer.Length - readBufferLen == 0) - { - Debug("Increasing the read buffer size from " + readBuffer.Length + " to " + (readBuffer.Length * 2) + "."); - byte[] readBuffer2 = new byte[readBuffer.Length * 2]; - Array.Copy(readBuffer, 0, readBuffer2, 0, readBuffer.Length); - readBuffer = readBuffer2; - } - - // Receive more data - try { wsstream.BeginRead(readBuffer, readBufferLen, readBuffer.Length - readBufferLen, new AsyncCallback(OnTlsDataSink), this); } catch (Exception) { } - } - - private int ProcessBuffer(byte[] buffer, int offset, int len) - { - string ss = UTF8Encoding.UTF8.GetString(buffer, offset, len); - - if (state == 1) - { - // Look for the end of the http header - string header = UTF8Encoding.UTF8.GetString(buffer, offset, len); - int i = header.IndexOf("\r\n\r\n"); - if (i == -1) return 0; - Dictionary parsedHeader = ParseHttpHeader(header.Substring(0, i)); - if ((parsedHeader == null) || (parsedHeader["_Path"] != "101")) { Debug("Websocket bad header."); return -1; } // Bad header, close the connection - Debug("Websocket got setup upgrade header."); - state = 2; - return len; // TODO: Technically we need to return the header length before UTF8 convert. - } else if (state == 2) { - // Parse a websocket fragment header - if (len < 2) return 0; - int headsize = 2; - accopcodes = buffer[offset]; - accmask = ((buffer[offset + 1] & 0x80) != 0); - acclen = (buffer[offset + 1] & 0x7F); - - if ((accopcodes & 0x0F) == 8) - { - // Close the websocket - Debug("Websocket got closed fragment."); - return -1; - } - - if (acclen == 126) - { - if (len < 4) return 0; - headsize = 4; - acclen = (buffer[offset + 2] << 8) + (buffer[offset + 3]); - } - else if (acclen == 127) - { - if (len < 10) return 0; - headsize = 10; - acclen = (buffer[offset + 6] << 24) + (buffer[offset + 7] << 16) + (buffer[offset + 8] << 8) + (buffer[offset + 9]); - Debug("Websocket receive large fragment: " + acclen); - } - if (accmask == true) - { - // TODO: Do unmasking here. - headsize += 4; - } - //parent.Debug("#" + counter + ": Websocket frag header - FIN: " + ((accopcodes & 0x80) != 0) + ", OP: " + (accopcodes & 0x0F) + ", LEN: " + acclen + ", MASK: " + accmask); - state = 3; - return headsize; - } - else if (state == 3) - { - // Parse a websocket fragment data - if (len < acclen) return 0; - //Console.Write("WSREAD: " + acclen + "\r\n"); - ProcessWsBuffer(buffer, offset, acclen, accopcodes); - state = 2; - return acclen; - } - return 0; - } - - private void ProcessWsBuffer(byte[] data, int offset, int len, int op) - { - Debug("Websocket got data."); - //try { parent.processServerData(UTF8Encoding.UTF8.GetString(data, offset, len)); } catch (Exception ex) { } - parent.processServerData(UTF8Encoding.UTF8.GetString(data, offset, len)); - } - - private Dictionary ParseHttpHeader(string header) - { - string[] lines = header.Replace("\r\n", "\r").Split('\r'); - if (lines.Length < 2) { return null; } - string[] directive = lines[0].Split(' '); - Dictionary values = new Dictionary(); - values["_Action"] = directive[0]; - values["_Path"] = directive[1]; - values["_Protocol"] = directive[2]; - for (int i = 1; i < lines.Length; i++) - { - var j = lines[i].IndexOf(":"); - values[lines[i].Substring(0, j).ToLower()] = lines[i].Substring(j + 1).Trim(); - } - return values; - } - - // Return a modified base64 SHA384 hash string of the certificate public key - public static string GetMeshKeyHash(X509Certificate cert) - { - return ByteArrayToHexString(new SHA384Managed().ComputeHash(cert.GetPublicKey())); - } - - // Return a modified base64 SHA384 hash string of the certificate - public static string GetMeshCertHash(X509Certificate cert) - { - return ByteArrayToHexString(new SHA384Managed().ComputeHash(cert.GetRawCertData())); - } - - public static string ByteArrayToHexString(byte[] Bytes) - { - StringBuilder Result = new StringBuilder(Bytes.Length * 2); - string HexAlphabet = "0123456789ABCDEF"; - foreach (byte B in Bytes) { Result.Append(HexAlphabet[(int)(B >> 4)]); Result.Append(HexAlphabet[(int)(B & 0xF)]); } - return Result.ToString(); - } - - private bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { - parent.certHash = GetMeshKeyHash(certificate); - Debug("Verify cert: " + parent.certHash); - if (xignoreCert) return true; - if (chain.Build(new X509Certificate2(certificate)) == true) return true; - - // Check that the remote certificate is the expected one - if ((parent.okCertHash != null) && (parent.okCertHash == certificate.GetCertHashString())) return true; - - // Check that the remote certificate is the expected one - if ((parent.okCertHash2 != null) && ((parent.okCertHash2 == GetMeshKeyHash(certificate)) || (parent.okCertHash2 == GetMeshCertHash(certificate)))) { return true; } - - parent.certHash = null; - parent.disconnectMsg = "cert"; - parent.disconnectCert = new X509Certificate2(certificate); - return false; - } - - public void WriteStringWebSocket(string data) - { - // Convert the string into a buffer with 4 byte of header space. - int len = UTF8Encoding.UTF8.GetByteCount(data); - byte[] buf = new byte[4 + len]; - UTF8Encoding.UTF8.GetBytes(data, 0, data.Length, buf, 4); - len = buf.Length - 4; - - // Check that everything is ok - if ((state < 2) || (len < 1) || (len > 65535)) { Dispose(); return; } - - //Console.Write("Length: " + len + "\r\n"); - //System.Threading.Thread.Sleep(0); - - if (len < 126) - { - // Small fragment - buf[2] = 130; // Fragment op code (129 = text, 130 = binary) - buf[3] = (byte)(len & 0x7F); - //try { wsstream.BeginWrite(buf, 2, len + 2, new AsyncCallback(WriteWebSocketAsyncDone), args); } catch (Exception) { Dispose(); return; } - TlsDump("Out", buf, 2, len + 2); - try { wsstream.Write(buf, 2, len + 2); } catch (Exception ex) { Debug(ex.ToString()); } - } - else - { - // Large fragment - buf[0] = 130; // Fragment op code (129 = text, 130 = binary) - buf[1] = 126; - buf[2] = (byte)((len >> 8) & 0xFF); - buf[3] = (byte)(len & 0xFF); - //try { wsstream.BeginWrite(buf, 0, len + 4, new AsyncCallback(WriteWebSocketAsyncDone), args); } catch (Exception) { Dispose(); return; } - TlsDump("Out", buf, 0, len + 4); - try { wsstream.Write(buf, 0, len + 4); } catch (Exception ex) { Debug(ex.ToString()); } - } - } + var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText); + return System.Convert.ToBase64String(plainTextBytes); + } + public string Base64Decode(string base64EncodedData) + { + var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData); + return System.Text.Encoding.UTF8.GetString(base64EncodedBytes); } } diff --git a/MeshMapper.cs b/MeshMapper.cs index 2a9476f..a4bf003 100644 --- a/MeshMapper.cs +++ b/MeshMapper.cs @@ -216,7 +216,6 @@ namespace MeshCentralRouter Uri wsurl = new Uri(url + "&auth=" + Uri.EscapeDataString(parent.authCookie)); Debug("#" + counter + ": Connecting web socket to: " + wsurl.ToString()); wc.debug = xdebug; - wc.Start(wsurl, certhash); wc.tag = client; wc.id = counter; wc.tunneling = false; @@ -224,6 +223,8 @@ namespace MeshCentralRouter wc.onBinaryData += Wc_onBinaryData; wc.onStringData += Wc_onStringData; wc.onSendOk += Wc_onSendOk; + wc.TLSCertCheck = webSocketClient.TLSCertificateCheck.Fingerprint; + wc.Start(wsurl, certhash, null); } private void ConnectWS(UdpClient client, int counter) @@ -232,7 +233,6 @@ namespace MeshCentralRouter Uri wsurl = new Uri(url + "&auth=" + Uri.EscapeDataString(parent.authCookie)); Debug("#" + counter + ": Connecting web socket to: " + wsurl.ToString()); wc.debug = xdebug; - wc.Start(wsurl, certhash); wc.tag = client; wc.id = counter; wc.tunneling = false; @@ -240,6 +240,8 @@ namespace MeshCentralRouter wc.onBinaryData += Wc_onBinaryData; wc.onStringData += Wc_onStringData; wc.onSendOk += Wc_onSendOk; + wc.TLSCertCheck = webSocketClient.TLSCertificateCheck.Fingerprint; + wc.Start(wsurl, certhash, null); } private void Wc_onSendOk(webSocketClient sender) diff --git a/WebSocketClient.cs b/WebSocketClient.cs index b504478..c3d8534 100644 --- a/WebSocketClient.cs +++ b/WebSocketClient.cs @@ -18,9 +18,12 @@ using System; using System.IO; using System.Net; using System.Text; +using System.Threading; using System.Net.Sockets; using System.Net.Security; +using System.Net.WebSockets; using System.IO.Compression; +using System.Threading.Tasks; using System.Collections.Generic; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -30,6 +33,9 @@ namespace MeshCentralRouter { public class webSocketClient : IDisposable { + private ClientWebSocket ws = null; // Native Windows WebSocket + private CancellationTokenSource CTS; + public bool AllowCompression = true; private TcpClient wsclient = null; private SslStream wsstream = null; @@ -44,10 +50,11 @@ namespace MeshCentralRouter private int acclen = 0; private bool proxyInUse = false; private string tlsCertFingerprint = null; + private string tlsCertFingerprint2 = null; //private ConnectionErrors lastError = ConnectionErrors.NoError; public bool debug = false; - public bool xignoreCert = false; - public string extraHeaders = null; + public bool tlsdump = false; + public Dictionary extraHeaders = null; private MemoryStream inflateMemory; private DeflateStream inflate; private MemoryStream deflateMemory; @@ -64,6 +71,10 @@ namespace MeshCentralRouter private bool shouldRead = false; private RNGCryptoServiceProvider CryptoRandom = new RNGCryptoServiceProvider(); private object mainLock = new object(); + public TLSCertificateCheck TLSCertCheck = TLSCertificateCheck.Verify; + public X509Certificate2 failedTlsCert = null; + static public bool nativeWebSocketFirst = true; + // Outside variables public object tag = null; @@ -79,11 +90,20 @@ namespace MeshCentralRouter Connected = 2 } + public enum TLSCertificateCheck + { + Ignore = 0, + Fingerprint = 1, + Verify = 2 + } + public enum ConnectionErrors { NoError = 0 } + private void TlsDump(string direction, byte[] data, int offset, int len) { if (tlsdump) { try { File.AppendAllText("debug.log", direction + ": " + BitConverter.ToString(data, offset, len).Replace("-", string.Empty) + "\r\n"); } catch (Exception) { } } } + public delegate void onBinaryDataHandler(webSocketClient sender, byte[] data, int offset, int length, int orglen); public event onBinaryDataHandler onBinaryData; public delegate void onStringDataHandler(webSocketClient sender, string data, int orglen); @@ -97,12 +117,7 @@ namespace MeshCentralRouter public ConnectionStates State { get { return state; } } - public X509Certificate RemoteCertificate { - get - { - try { return wsstream.RemoteCertificate; } catch (Exception) { return null; } - } - } + public X509Certificate RemoteCertificate { get { try { return wsstream.RemoteCertificate; } catch (Exception) { return null; } } } private void SetState(ConnectionStates newstate) { @@ -113,6 +128,17 @@ namespace MeshCentralRouter public void Dispose() { + if (ws != null) + { + if (ws.State == WebSocketState.Open) + { + CTS.CancelAfter(TimeSpan.FromSeconds(2)); + ws.CloseOutputAsync(WebSocketCloseStatus.Empty, "", CancellationToken.None); + ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None); + } + try { if (ws != null) { ws.Dispose(); ws = null; } } catch (Exception) { } + try { if (CTS != null) { CTS.Dispose(); CTS = null; } } catch (Exception) { } + } if (pingTimer != null) { pingTimer.Dispose(); pingTimer = null; } if (pongTimer != null) { pongTimer.Dispose(); pongTimer = null; } if (wsstream != null) { try { wsstream.Close(); } catch (Exception) { } try { wsstream.Dispose(); } catch (Exception) { } wsstream = null; } @@ -128,56 +154,91 @@ namespace MeshCentralRouter if (debug) { try { File.AppendAllText("debug.log", DateTime.Now.ToString("HH:mm:tt.ffff") + ": WebSocket: " + msg + "\r\n"); } catch (Exception) { } } } - public bool Start(Uri url, string tlsCertFingerprint) + private async Task ConnectAsync(Uri url) + { + if (CTS != null) CTS.Dispose(); + CTS = new CancellationTokenSource(); + try { await ws.ConnectAsync(url, CTS.Token); } catch (Exception) { SetState(0); return; } + await Task.Factory.StartNew(ReceiveLoop, CTS.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); + } + + public async Task DisconnectAsync() + { + if (ws == null) return; + if (ws.State == WebSocketState.Open) + { + CTS.CancelAfter(TimeSpan.FromSeconds(2)); + await ws.CloseOutputAsync(WebSocketCloseStatus.Empty, "", CancellationToken.None); + await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None); + } + ws.Dispose(); + ws = null; + CTS.Dispose(); + CTS = null; + } + + public bool Start(Uri url, string tlsCertFingerprint, string tlsCertFingerprint2) { if (state != ConnectionStates.Disconnected) return false; SetState(ConnectionStates.Connecting); this.url = url; if (tlsCertFingerprint != null) { this.tlsCertFingerprint = tlsCertFingerprint.ToUpper(); } - Uri proxyUri = null; + if (tlsCertFingerprint2 != null) { this.tlsCertFingerprint2 = tlsCertFingerprint2.ToUpper(); } - Log("Websocket Start, URL=" + ((url == null) ? "(NULL)" : url.ToString())); - - // Check if we need to use a HTTP proxy (Auto-proxy way) - try + if (nativeWebSocketFirst) { try { ws = new ClientWebSocket(); } catch (Exception) { } } + if (ws != null) { - RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); - Object x = registryKey.GetValue("AutoConfigURL", null); - if ((x != null) && (x.GetType() == typeof(string))) - { - string proxyStr = GetProxyForUrlUsingPac("http" + ((url.Port == 80) ? "" : "s") + "://" + url.Host + ":" + url.Port, x.ToString()); - if (proxyStr != null) { proxyUri = new Uri("http://" + proxyStr); } - } - } - catch (Exception) { proxyUri = null; } - - // Check if we need to use a HTTP proxy (Normal way) - if (proxyUri == null) - { - var proxy = System.Net.HttpWebRequest.GetSystemWebProxy(); - proxyUri = proxy.GetProxy(url); - if ((url.Host.ToLower() == proxyUri.Host.ToLower()) && (url.Port == proxyUri.Port)) { proxyUri = null; } - } - - if (proxyUri != null) - { - // Proxy in use - Log("Websocket proxyUri: " + proxyUri.ToString()); - proxyInUse = true; - wsclient = new TcpClient(); - wsclient.BeginConnect(proxyUri.Host, proxyUri.Port, new AsyncCallback(OnConnectSink), this); + // Use Windows native websockets + Log("Websocket (native) Start, URL=" + ((url == null) ? "(NULL)" : url.ToString())); + if (extraHeaders != null) { foreach (var key in extraHeaders.Keys) { ws.Options.SetRequestHeader(key, extraHeaders[key]); } } + Task t = ConnectAsync(url); } else { - // No proxy in use - Log("Websocket noProxy"); - proxyInUse = false; - wsclient = new TcpClient(); - string h = url.Host; - if (h.StartsWith("[") && h.EndsWith("]")) { h = h.Substring(1, h.Length - 2); } - wsclient.BeginConnect(h, url.Port, new AsyncCallback(OnConnectSink), this); - } + // Use C# coded websockets + Uri proxyUri = null; + Log("Websocket Start, URL=" + ((url == null) ? "(NULL)" : url.ToString())); + // Check if we need to use a HTTP proxy (Auto-proxy way) + try + { + RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); + Object x = registryKey.GetValue("AutoConfigURL", null); + if ((x != null) && (x.GetType() == typeof(string))) + { + string proxyStr = GetProxyForUrlUsingPac("http" + ((url.Port == 80) ? "" : "s") + "://" + url.Host + ":" + url.Port, x.ToString()); + if (proxyStr != null) { proxyUri = new Uri("http://" + proxyStr); } + } + } + catch (Exception) { proxyUri = null; } + + // Check if we need to use a HTTP proxy (Normal way) + if (proxyUri == null) + { + var proxy = System.Net.HttpWebRequest.GetSystemWebProxy(); + proxyUri = proxy.GetProxy(url); + if ((url.Host.ToLower() == proxyUri.Host.ToLower()) && (url.Port == proxyUri.Port)) { proxyUri = null; } + } + + if (proxyUri != null) + { + // Proxy in use + Log("Websocket proxyUri: " + proxyUri.ToString()); + proxyInUse = true; + wsclient = new TcpClient(); + wsclient.BeginConnect(proxyUri.Host, proxyUri.Port, new AsyncCallback(OnConnectSink), this); + } + else + { + // No proxy in use + Log("Websocket noProxy"); + proxyInUse = false; + wsclient = new TcpClient(); + string h = url.Host; + if (h.StartsWith("[") && h.EndsWith("]")) { h = h.Substring(1, h.Length - 2); } + wsclient.BeginConnect(h, url.Port, new AsyncCallback(OnConnectSink), this); + } + } return true; } @@ -296,13 +357,20 @@ namespace MeshCentralRouter pendingSendBuffer = new MemoryStream(); pendingSendCall = false; + // Build extra headers + string extraHeadersStr = ""; + if (extraHeaders != null) + { + foreach (string key in extraHeaders.Keys) { extraHeadersStr += key + ": " + extraHeaders[key] + "\r\n"; } + } + // Send the HTTP headers Log("Websocket TLS setup, sending HTTP header..."); string header; if (AllowCompression) { - header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Extensions: permessage-deflate; client_no_context_takeover\r\n" + extraHeaders + "\r\n"; + header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Extensions: permessage-deflate; client_no_context_takeover\r\n" + extraHeadersStr + "\r\n"; } else { - header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n" + extraHeaders + "\r\n"; + header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n" + extraHeadersStr + "\r\n"; } SendData(UTF8Encoding.UTF8.GetBytes(header)); @@ -397,6 +465,7 @@ namespace MeshCentralRouter private int ProcessBuffer(byte[] buffer, int offset, int len) { + TlsDump("InRaw", buffer, offset, len); string ss = UTF8Encoding.UTF8.GetString(buffer, offset, len); if (state == ConnectionStates.Connecting) @@ -503,12 +572,14 @@ namespace MeshCentralRouter case 0x01: // This is a text frame { Log("Websocket got string data, len = " + len); + TlsDump("InStr", data, offset, len); if (onStringData != null) { onStringData(this, UTF8Encoding.UTF8.GetString(data, offset, len), orglen); } break; } case 0x02: // This is a birnay frame { Log("Websocket got binary data, len = " + len); + TlsDump("InBin", data, offset, len); if (onBinaryData != null) { onBinaryData(this, data, offset, len, orglen); } break; } @@ -564,20 +635,42 @@ namespace MeshCentralRouter private bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { - if (tlsCertFingerprint == null) return true; - if ((tlsCertFingerprint.Length == 32) && (certificate.GetCertHashString().Equals(tlsCertFingerprint))) { return true; } - if (tlsCertFingerprint.Length == 96) - { - if (GetMeshCertHash(certificate).Equals(tlsCertFingerprint)) { return true; } - if (GetMeshKeyHash(certificate).Equals(tlsCertFingerprint)) { return true; } - } - string hash1 = GetMeshCertHash(certificate); string hash2 = certificate.GetCertHashString(); - Log("VerifyServerCertificate: tlsCertFingerprint = " + tlsCertFingerprint); - Log("VerifyServerCertificate: Hash1 = " + hash1); - Log("VerifyServerCertificate: Hash2 = " + hash2); - return ((tlsCertFingerprint == GetMeshKeyHash(certificate)) || (tlsCertFingerprint == certificate.GetCertHashString())); + //Debug("Verify cert: " + hash1); + + if (TLSCertCheck == TLSCertificateCheck.Ignore) + { + // Ignore certificate check + return true; + } + else if (TLSCertCheck == TLSCertificateCheck.Fingerprint) + { + // Fingerprint certificate check + if (tlsCertFingerprint == null) return true; + if ((tlsCertFingerprint.Length == 32) && (certificate.GetCertHashString().Equals(tlsCertFingerprint))) { return true; } + if (tlsCertFingerprint.Length == 96) + { + if (GetMeshCertHash(certificate).Equals(tlsCertFingerprint)) { return true; } + if (GetMeshKeyHash(certificate).Equals(tlsCertFingerprint)) { return true; } + } + + Log("VerifyServerCertificate: tlsCertFingerprint = " + tlsCertFingerprint); + Log("VerifyServerCertificate: Hash1 = " + hash1); + Log("VerifyServerCertificate: Hash2 = " + hash2); + return ((tlsCertFingerprint == GetMeshKeyHash(certificate)) || (tlsCertFingerprint == certificate.GetCertHashString())); + } + else + { + // Normal certificate check + if (chain.Build(new X509Certificate2(certificate)) == true) return true; + + // Check that the remote certificate is the expected one + if ((tlsCertFingerprint != null) && ((tlsCertFingerprint == certificate.GetCertHashString()) || (tlsCertFingerprint == GetMeshKeyHash(certificate)) || (tlsCertFingerprint == GetMeshCertHash(certificate)))) { return true; } + if ((tlsCertFingerprint2 != null) && ((tlsCertFingerprint2 == certificate.GetCertHashString()) || (tlsCertFingerprint2 == GetMeshKeyHash(certificate)) || (tlsCertFingerprint2 == GetMeshCertHash(certificate)))) { return true; } + failedTlsCert = new X509Certificate2(certificate); + return false; + } } public int SendString(string data) @@ -611,84 +704,103 @@ namespace MeshCentralRouter return SendFragment(null, 0, 0, 138); } + Task pendingSend = null; + // Fragment op code (129 = text, 130 = binary) public int SendFragment(byte[] data, int offset, int len, byte op) { - lock (mainLock) + TlsDump("Out(" + op + ")", data, offset, len); + if (ws != null) { - if (state != ConnectionStates.Connected) return 0; - byte[] buf; - - // If deflate is active, attempt to compress the data here. - if ((deflateMemory != null) && (len > 32) && (AllowCompression)) + // Using native websocket + lock (this) { - deflateMemory.SetLength(0); - deflateMemory.Write(inflateStart, 0, 14); - DeflateStream deflate = new DeflateStream(deflateMemory, CompressionMode.Compress, true); - deflate.Write(data, offset, len); - deflate.Dispose(); - deflate = null; - if (deflateMemory.Length < len) + if ((pendingSend != null) && (pendingSend.IsCompleted == false)) { pendingSend.Wait(); } + ArraySegment arr = new ArraySegment(data, offset, len); + WebSocketMessageType msgType = ((op == 129) ? WebSocketMessageType.Text : WebSocketMessageType.Binary); + pendingSend = ws.SendAsync(arr, msgType, true, CTS.Token); + } + return len; + } + else + { + // Using C# websocket + lock (mainLock) + { + if (state != ConnectionStates.Connected) return 0; + byte[] buf; + + // If deflate is active, attempt to compress the data here. + if ((deflateMemory != null) && (len > 32) && (AllowCompression)) { - // Use the compressed data - int newlen = (int)deflateMemory.Length; - buf = deflateMemory.GetBuffer(); - len = newlen - 14; - op |= 0x40; // Add compression op + deflateMemory.SetLength(0); + deflateMemory.Write(inflateStart, 0, 14); + DeflateStream deflate = new DeflateStream(deflateMemory, CompressionMode.Compress, true); + deflate.Write(data, offset, len); + deflate.Dispose(); + deflate = null; + if (deflateMemory.Length < len) + { + // Use the compressed data + int newlen = (int)deflateMemory.Length; + buf = deflateMemory.GetBuffer(); + len = newlen - 14; + op |= 0x40; // Add compression op + } + else + { + // Don't use the compress data + // Convert the string into a buffer with 4 byte of header space. + buf = new byte[14 + len]; + Array.Copy(data, offset, buf, 14, len); + } } else { - // Don't use the compress data // Convert the string into a buffer with 4 byte of header space. buf = new byte[14 + len]; - Array.Copy(data, offset, buf, 14, len); + if (len > 0) { Array.Copy(data, offset, buf, 14, len); } } - } - else - { - // Convert the string into a buffer with 4 byte of header space. - buf = new byte[14 + len]; - if (len > 0) { Array.Copy(data, offset, buf, 14, len); } - } - // Check that everything is ok - if (len < 0) { Dispose(); return 0; } + // Check that everything is ok + if (len < 0) { Dispose(); return 0; } - // Set the mask to a cryptographic random value and XOR the data - byte[] rand = new byte[4]; - CryptoRandom.GetBytes(rand); - Array.Copy(rand, 0, buf, 10, 4); - for (int x = 0; x < len; x++) { buf[x + 14] ^= rand[x % 4]; } + // Set the mask to a cryptographic random value and XOR the data + byte[] rand = new byte[4]; + CryptoRandom.GetBytes(rand); + Array.Copy(rand, 0, buf, 10, 4); + for (int x = 0; x < len; x++) { buf[x + 14] ^= rand[x % 4]; } - if (len < 126) - { - // Small fragment - buf[8] = op; - buf[9] = (byte)((len & 0x7F) + 128); // Add 128 to indicate the mask is present - SendData(buf, 8, len + 6); - } - else if (len < 65535) - { - // Medium fragment - buf[6] = op; - buf[7] = 126 + 128; // Add 128 to indicate the mask is present - buf[8] = (byte)((len >> 8) & 0xFF); - buf[9] = (byte)(len & 0xFF); - SendData(buf, 6, len + 8); - } - else - { - // Large fragment - buf[0] = op; - buf[1] = 127 + 128; // Add 128 to indicate the mask is present - buf[6] = (byte)((len >> 24) & 0xFF); - buf[7] = (byte)((len >> 16) & 0xFF); - buf[8] = (byte)((len >> 8) & 0xFF); - buf[9] = (byte)(len & 0xFF); - SendData(buf, 0, len + 14); - } + if (len < 126) + { + // Small fragment + buf[8] = op; + buf[9] = (byte)((len & 0x7F) + 128); // Add 128 to indicate the mask is present + SendData(buf, 8, len + 6); + } + else if (len < 65535) + { + // Medium fragment + buf[6] = op; + buf[7] = 126 + 128; // Add 128 to indicate the mask is present + buf[8] = (byte)((len >> 8) & 0xFF); + buf[9] = (byte)(len & 0xFF); + SendData(buf, 6, len + 8); + } + else + { + // Large fragment + buf[0] = op; + buf[1] = 127 + 128; // Add 128 to indicate the mask is present + buf[6] = (byte)((len >> 24) & 0xFF); + buf[7] = (byte)((len >> 16) & 0xFF); + buf[8] = (byte)((len >> 8) & 0xFF); + buf[9] = (byte)(len & 0xFF); + SendData(buf, 0, len + 14); + } - return len; + return len; + } } } @@ -696,6 +808,7 @@ namespace MeshCentralRouter private void SendData(byte[] buf, int off, int len) { + TlsDump("OutRaw", buf, off, len); if (pendingSendCall) { lock (pendingSendBuffer) { pendingSendBuffer.Write(buf, off, len); } @@ -752,6 +865,50 @@ namespace MeshCentralRouter } } + private async Task ReceiveLoop() + { + SetState(ConnectionStates.Connected); + var loopToken = CTS.Token; + MemoryStream outputStream = null; + WebSocketReceiveResult receiveResult = null; + var buffer = new byte[8192]; + ArraySegment bufferEx = new ArraySegment(buffer); + try + { + while (!loopToken.IsCancellationRequested) + { + outputStream = new MemoryStream(8192); + do + { + receiveResult = await ws.ReceiveAsync(bufferEx, CTS.Token); + if (receiveResult.MessageType != WebSocketMessageType.Close) + outputStream.Write(buffer, 0, receiveResult.Count); + } + while (!receiveResult.EndOfMessage); + if (receiveResult.MessageType == WebSocketMessageType.Close) break; + outputStream.Position = 0; + if (receiveResult.MessageType == WebSocketMessageType.Text) + { + Log("Websocket got string data, len = " + (int)outputStream.Length); + TlsDump("InStr", outputStream.GetBuffer(), 0, (int)outputStream.Length); + if (onStringData != null) { onStringData(this, UTF8Encoding.UTF8.GetString(outputStream.GetBuffer(), 0, (int)outputStream.Length), (int)outputStream.Length); } + } + else if (receiveResult.MessageType == WebSocketMessageType.Binary) + { + Log("Websocket got binary data, len = " + (int)outputStream.Length); + TlsDump("InBin", outputStream.GetBuffer(), 0, (int)outputStream.Length); + if (onBinaryData != null) { onBinaryData(this, outputStream.GetBuffer(), 0, (int)outputStream.Length, (int)outputStream.Length); } + } + } + } + catch (TaskCanceledException) { } + finally + { + outputStream?.Dispose(); + SetState(0); + } + } + } } diff --git a/app.config b/app.config index e56d694..37bb3f3 100644 --- a/app.config +++ b/app.config @@ -39,4 +39,4 @@ - + From 0bcb7a0164943e11a28ffdff65537bb75b0c4390 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 28 Oct 2021 16:47:05 -0700 Subject: [PATCH 02/20] Windows native websocket fixes. --- MeshMapper.cs | 26 ---------------- WebSocketClient.cs | 75 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 65 insertions(+), 36 deletions(-) diff --git a/MeshMapper.cs b/MeshMapper.cs index a4bf003..398cf9f 100644 --- a/MeshMapper.cs +++ b/MeshMapper.cs @@ -50,32 +50,6 @@ namespace MeshCentralRouter public delegate void onStateMsgChangedHandler(string statemsg); public event onStateMsgChangedHandler onStateMsgChanged; - public static string GetProxyForUrlUsingPac(string DestinationUrl, string PacUri) - { - IntPtr WinHttpSession = Win32Api.WinHttpOpen("User", Win32Api.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, IntPtr.Zero, IntPtr.Zero, 0); - - Win32Api.WINHTTP_AUTOPROXY_OPTIONS ProxyOptions = new Win32Api.WINHTTP_AUTOPROXY_OPTIONS(); - Win32Api.WINHTTP_PROXY_INFO ProxyInfo = new Win32Api.WINHTTP_PROXY_INFO(); - - ProxyOptions.dwFlags = Win32Api.WINHTTP_AUTOPROXY_CONFIG_URL; - ProxyOptions.dwAutoDetectFlags = (Win32Api.WINHTTP_AUTO_DETECT_TYPE_DHCP | Win32Api.WINHTTP_AUTO_DETECT_TYPE_DNS_A); - ProxyOptions.lpszAutoConfigUrl = PacUri; - - // Get Proxy - bool IsSuccess = Win32Api.WinHttpGetProxyForUrl(WinHttpSession, DestinationUrl, ref ProxyOptions, ref ProxyInfo); - Win32Api.WinHttpCloseHandle(WinHttpSession); - - if (IsSuccess) - { - return ProxyInfo.lpszProxy; - } - else - { - Console.WriteLine("Error: {0}", Win32Api.GetLastError()); - return null; - } - } - // Starts the routing server, called when the start button is pressed public void start(MeshCentralServer parent, int protocol, int localPort, string url, int remotePort, string remoteIP) { diff --git a/WebSocketClient.cs b/WebSocketClient.cs index c3d8534..3bf39db 100644 --- a/WebSocketClient.cs +++ b/WebSocketClient.cs @@ -74,7 +74,7 @@ namespace MeshCentralRouter public TLSCertificateCheck TLSCertCheck = TLSCertificateCheck.Verify; public X509Certificate2 failedTlsCert = null; static public bool nativeWebSocketFirst = true; - + private SemaphoreSlim receiveLock = new SemaphoreSlim(1, 1); // Outside variables public object tag = null; @@ -704,7 +704,17 @@ namespace MeshCentralRouter return SendFragment(null, 0, 0, 138); } - Task pendingSend = null; + // This controls the flow of fragments being sent, queuing send operations if needed + private Task pendingSend = null; + private List pendingSends = new List(); + private class pendingSendClass + { + public pendingSendClass(byte[] data, int offset, int len, byte op) { this.data = data; this.offset = offset; this.len = len; this.op = op; } + public byte[] data; + public int offset; + public int len; + public byte op; + } // Fragment op code (129 = text, 130 = binary) public int SendFragment(byte[] data, int offset, int len, byte op) @@ -713,12 +723,21 @@ namespace MeshCentralRouter if (ws != null) { // Using native websocket - lock (this) + lock (pendingSends) { - if ((pendingSend != null) && (pendingSend.IsCompleted == false)) { pendingSend.Wait(); } - ArraySegment arr = new ArraySegment(data, offset, len); - WebSocketMessageType msgType = ((op == 129) ? WebSocketMessageType.Text : WebSocketMessageType.Binary); - pendingSend = ws.SendAsync(arr, msgType, true, CTS.Token); + if (pendingSend != null) + { + // A send operating is already being processes, queue this send. + pendingSends.Add(new pendingSendClass(data, offset, len, op)); + } + else + { + // No send operations being performed now, send this fragment now. + ArraySegment arr = new ArraySegment(data, offset, len); + WebSocketMessageType msgType = ((op == 129) ? WebSocketMessageType.Text : WebSocketMessageType.Binary); + pendingSend = ws.SendAsync(arr, msgType, true, CTS.Token); + pendingSend.ContinueWith(antecedent => SendFragmentDone()); + } } return len; } @@ -804,6 +823,29 @@ namespace MeshCentralRouter } } + + // Called when a fragment is done sending. We look to send the next one or signal that we can accept more data + private void SendFragmentDone() + { + bool q = false; + lock (pendingSends) + { + pendingSend = null; + if (pendingSends.Count > 0) + { + // There is more send operation pending, send the next one now. + pendingSendClass p = pendingSends[0]; + pendingSends.RemoveAt(0); + ArraySegment arr = new ArraySegment(p.data, p.offset, p.len); + WebSocketMessageType msgType = ((p.op == 129) ? WebSocketMessageType.Text : WebSocketMessageType.Binary); + pendingSend = ws.SendAsync(arr, msgType, true, CTS.Token); + pendingSend.ContinueWith(antecedent => SendFragmentDone()); + } + else { q = true; } // No pending send operations, signal ok to send more. + } + if ((q == true) && (onSendOk != null)) { onSendOk(this); } + } + private void SendData(byte[] buf) { SendData(buf, 0, buf.Length); } private void SendData(byte[] buf, int off, int len) @@ -847,7 +889,9 @@ namespace MeshCentralRouter { lock (mainLock) { + if (readPaused == true) return; readPaused = true; + if (ws != null) { receiveLock.Wait(); } } } @@ -857,10 +901,17 @@ namespace MeshCentralRouter { if (readPaused == false) return; readPaused = false; - if (shouldRead == true) + if (ws != null) { - shouldRead = false; - try { wsstream.BeginRead(readBuffer, readBufferLen, readBuffer.Length - readBufferLen, new AsyncCallback(OnTlsDataSink), this); } catch (Exception) { } + receiveLock.Release(); + } + else + { + if (shouldRead == true) + { + shouldRead = false; + try { wsstream.BeginRead(readBuffer, readBufferLen, readBuffer.Length - readBufferLen, new AsyncCallback(OnTlsDataSink), this); } catch (Exception) { } + } } } } @@ -887,6 +938,10 @@ namespace MeshCentralRouter while (!receiveResult.EndOfMessage); if (receiveResult.MessageType == WebSocketMessageType.Close) break; outputStream.Position = 0; + + receiveLock.Wait(); // Pause reading if needed + receiveLock.Release(); + if (receiveResult.MessageType == WebSocketMessageType.Text) { Log("Websocket got string data, len = " + (int)outputStream.Length); From 4f2401a7961e312b40b4408a9584d11ab5d739c0 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Sat, 30 Oct 2021 12:07:54 -0700 Subject: [PATCH 03/20] Native web socket improvements. --- KVMViewer.cs | 1 - WebSocketClient.cs | 100 ++++++++++++++++++++++++++++++--------------- 2 files changed, 67 insertions(+), 34 deletions(-) diff --git a/KVMViewer.cs b/KVMViewer.cs index 120ce9c..2e8ca98 100644 --- a/KVMViewer.cs +++ b/KVMViewer.cs @@ -20,7 +20,6 @@ using System.Windows.Forms; using System.Collections.Generic; using System.Security.Cryptography; using System.Web.Script.Serialization; -using Microsoft.Win32; using System.Threading; namespace MeshCentralRouter diff --git a/WebSocketClient.cs b/WebSocketClient.cs index 3bf39db..70ddf6b 100644 --- a/WebSocketClient.cs +++ b/WebSocketClient.cs @@ -66,12 +66,12 @@ namespace MeshCentralRouter private System.Threading.Timer pongTimer = null; private bool pendingSendCall = false; private MemoryStream pendingSendBuffer = null; - public long PendingSendLength { get { return (pendingSendBuffer == null)? 0 : pendingSendBuffer.Length; } } private bool readPaused = false; private bool shouldRead = false; private RNGCryptoServiceProvider CryptoRandom = new RNGCryptoServiceProvider(); private object mainLock = new object(); public TLSCertificateCheck TLSCertCheck = TLSCertificateCheck.Verify; + public X509Certificate2 tlsCert = null; public X509Certificate2 failedTlsCert = null; static public bool nativeWebSocketFirst = true; private SemaphoreSlim receiveLock = new SemaphoreSlim(1, 1); @@ -102,6 +102,8 @@ namespace MeshCentralRouter NoError = 0 } + public long PendingSendLength { get { if (ws != null) { lock (pendingSends) { return pendingSends.Count; } } else { return (pendingSendBuffer == null) ? 0 : pendingSendBuffer.Length; } } } + private void TlsDump(string direction, byte[] data, int offset, int len) { if (tlsdump) { try { File.AppendAllText("debug.log", direction + ": " + BitConverter.ToString(data, offset, len).Replace("-", string.Empty) + "\r\n"); } catch (Exception) { } } } public delegate void onBinaryDataHandler(webSocketClient sender, byte[] data, int offset, int length, int orglen); @@ -117,7 +119,7 @@ namespace MeshCentralRouter public ConnectionStates State { get { return state; } } - public X509Certificate RemoteCertificate { get { try { return wsstream.RemoteCertificate; } catch (Exception) { return null; } } } + public X509Certificate RemoteCertificate { get { if (tlsCert != null) return tlsCert; try { return wsstream.RemoteCertificate; } catch (Exception) { return null; } } } private void SetState(ConnectionStates newstate) { @@ -320,7 +322,7 @@ namespace MeshCentralRouter else { // Read more proxy data - try { wsrawstream.BeginRead(readBuffer, readBufferLen, readBuffer.Length - readBufferLen, new AsyncCallback(OnProxyResponseSink), this); } catch (Exception) { Dispose(); } + try { wsrawstream.BeginRead(readBuffer, readBufferLen, readBuffer.Length - readBufferLen, new AsyncCallback(OnProxyResponseSink), this); } catch (Exception) { Dispose(); } } } } @@ -367,9 +369,12 @@ namespace MeshCentralRouter // Send the HTTP headers Log("Websocket TLS setup, sending HTTP header..."); string header; - if (AllowCompression) { + if (AllowCompression) + { header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Extensions: permessage-deflate; client_no_context_takeover\r\n" + extraHeadersStr + "\r\n"; - } else { + } + else + { header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n" + extraHeadersStr + "\r\n"; } SendData(UTF8Encoding.UTF8.GetBytes(header)); @@ -556,15 +561,18 @@ namespace MeshCentralRouter if (((op & 0x40) != 0) && (inflateMemory != null)) { // This is a deflate compressed frame - inflateMemory.SetLength(0); - inflateMemory.Write(data, offset, len); - inflateMemory.Write(inflateEnd, 0, 4); - inflateMemory.Seek(0, SeekOrigin.Begin); - MemoryStream memoryStream = new MemoryStream(); - inflate.CopyTo(memoryStream); - data = memoryStream.GetBuffer(); - offset = 0; - len = (int)memoryStream.Length; + lock (inflateMemory) + { + inflateMemory.SetLength(0); + inflateMemory.Write(data, offset, len); + inflateMemory.Write(inflateEnd, 0, 4); + inflateMemory.Seek(0, SeekOrigin.Begin); + MemoryStream memoryStream = new MemoryStream(); + inflate.CopyTo(memoryStream); + data = memoryStream.GetBuffer(); + offset = 0; + len = (int)memoryStream.Length; + } } switch (op & 0x0F) @@ -678,30 +686,31 @@ namespace MeshCentralRouter if (state != ConnectionStates.Connected) return 0; Log("WebSocketClient-SEND-String: " + data); byte[] buf = UTF8Encoding.UTF8.GetBytes(data); - return SendFragment(buf, 0, buf.Length, 129); + return SendFragment(buf, 0, buf.Length, 129, true); } public int SendBinary(byte[] data) { Log("WebSocketClient-SEND-Binary-Len:" + data.Length); - return SendFragment(data, 0, data.Length, 130); + return SendFragment(data, 0, data.Length, 130, false); } - public int SendBinary(byte[] data, int offset, int len) { + public int SendBinary(byte[] data, int offset, int len) + { Log("WebSocketClient-SEND-Binary-Len:" + len); - return SendFragment(data, offset, len, 130); + return SendFragment(data, offset, len, 130, false); } public int SendPing(byte[] data, int offset, int len) { Log("WebSocketClient-SEND-Ping"); - return SendFragment(null, 0, 0, 137); + return SendFragment(null, 0, 0, 137, true); } public int SendPong(byte[] data, int offset, int len) { Log("WebSocketClient-SEND-Pong"); - return SendFragment(null, 0, 0, 138); + return SendFragment(null, 0, 0, 138, true); } // This controls the flow of fragments being sent, queuing send operations if needed @@ -717,18 +726,30 @@ namespace MeshCentralRouter } // Fragment op code (129 = text, 130 = binary) - public int SendFragment(byte[] data, int offset, int len, byte op) + // ownershipReleased = True is the memory in data is not owned anymore. + private int SendFragment(byte[] data, int offset, int len, byte op, bool ownershipReleased) { TlsDump("Out(" + op + ")", data, offset, len); if (ws != null) { + if ((data == null) || (len == 0)) return 0; + + if (ownershipReleased == false) + { + // Since this is going into a aynsc send or in a queue, copy the outgoing data into a new buffer. + byte[] buf = new byte[len]; + Array.Copy(data, offset, buf, 0, len); + data = buf; + offset = 0; + } + // Using native websocket lock (pendingSends) { if (pendingSend != null) { // A send operating is already being processes, queue this send. - pendingSends.Add(new pendingSendClass(data, offset, len, op)); + pendingSends.Add(new pendingSendClass(data, 0, len, op)); } else { @@ -753,17 +774,17 @@ namespace MeshCentralRouter if ((deflateMemory != null) && (len > 32) && (AllowCompression)) { deflateMemory.SetLength(0); - deflateMemory.Write(inflateStart, 0, 14); DeflateStream deflate = new DeflateStream(deflateMemory, CompressionMode.Compress, true); deflate.Write(data, offset, len); deflate.Dispose(); deflate = null; if (deflateMemory.Length < len) { - // Use the compressed data + // Copy to a new buffer, this is needed because we do async send operation int newlen = (int)deflateMemory.Length; - buf = deflateMemory.GetBuffer(); - len = newlen - 14; + buf = new byte[14 + newlen]; + Array.Copy(deflateMemory.GetBuffer(), 0, buf, 14, newlen); + len = newlen; op |= 0x40; // Add compression op } else @@ -776,7 +797,7 @@ namespace MeshCentralRouter } else { - // Convert the string into a buffer with 4 byte of header space. + // Convert the string into a buffer with 14 bytea of header space. buf = new byte[14 + len]; if (len > 0) { Array.Copy(data, offset, buf, 14, len); } } @@ -877,9 +898,12 @@ namespace MeshCentralRouter bool IsSuccess = Win32Api.WinHttpGetProxyForUrl(WinHttpSession, DestinationUrl, ref ProxyOptions, ref ProxyInfo); Win32Api.WinHttpCloseHandle(WinHttpSession); - if (IsSuccess) { + if (IsSuccess) + { return ProxyInfo.lpszProxy; - } else { + } + else + { Console.WriteLine("Error: {0}", Win32Api.GetLastError()); return null; } @@ -916,7 +940,7 @@ namespace MeshCentralRouter } } - private async Task ReceiveLoop() + private void ReceiveLoop() { SetState(ConnectionStates.Connected); var loopToken = CTS.Token; @@ -931,9 +955,19 @@ namespace MeshCentralRouter outputStream = new MemoryStream(8192); do { - receiveResult = await ws.ReceiveAsync(bufferEx, CTS.Token); - if (receiveResult.MessageType != WebSocketMessageType.Close) - outputStream.Write(buffer, 0, receiveResult.Count); + try + { + Task t = ws.ReceiveAsync(bufferEx, CTS.Token); + t.Wait(); + receiveResult = t.Result; + if (receiveResult.MessageType != WebSocketMessageType.Close) { outputStream.Write(buffer, 0, receiveResult.Count); } + } + catch (Exception) + { + outputStream?.Dispose(); + SetState(0); + return; + } } while (!receiveResult.EndOfMessage); if (receiveResult.MessageType == WebSocketMessageType.Close) break; From 83d64597fcf9250cde663ac64dd5ff5fbd2c35e9 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Tue, 16 Nov 2021 10:09:35 -0800 Subject: [PATCH 04/20] Switched back to using built-in sockets with compression. --- MeshCentralServer.cs | 2 +- WebSocketClient.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MeshCentralServer.cs b/MeshCentralServer.cs index ecd131d..f637cf7 100644 --- a/MeshCentralServer.cs +++ b/MeshCentralServer.cs @@ -677,7 +677,7 @@ namespace MeshCentralRouter // Get login key string url = jsonAction["url"] + "&auth=" + authCookie; - if (url.StartsWith("*/")) { url = "wss://" + wsurl.Authority + url.Substring(1); } + if (url.StartsWith("*/")) { url = "https://" + wsurl.Authority + url.Substring(1); } string loginkey = getValueFromQueryString(wsurl.Query, "key"); if (loginkey != null) { url += ("&key=" + loginkey); } diff --git a/WebSocketClient.cs b/WebSocketClient.cs index 70ddf6b..ccaa446 100644 --- a/WebSocketClient.cs +++ b/WebSocketClient.cs @@ -187,7 +187,7 @@ namespace MeshCentralRouter if (tlsCertFingerprint != null) { this.tlsCertFingerprint = tlsCertFingerprint.ToUpper(); } if (tlsCertFingerprint2 != null) { this.tlsCertFingerprint2 = tlsCertFingerprint2.ToUpper(); } - if (nativeWebSocketFirst) { try { ws = new ClientWebSocket(); } catch (Exception) { } } + //if (nativeWebSocketFirst) { try { ws = new ClientWebSocket(); } catch (Exception) { } } if (ws != null) { // Use Windows native websockets From c1947f81a8802bf673957a4dfde0fdb019b6e9d5 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Wed, 24 Nov 2021 20:55:09 -0800 Subject: [PATCH 05/20] Added auto fallback to native sockets. --- MainForm.cs | 2 +- WebSocketClient.cs | 41 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/MainForm.cs b/MainForm.cs index 172920d..fc1eaf0 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -236,7 +236,7 @@ namespace MeshCentralRouter if (arg.ToLower() == "-all") { inaddrany = true; } if (arg.ToLower() == "-inaddrany") { inaddrany = true; } if (arg.ToLower() == "-tray") { notifyIcon.Visible = true; this.ShowInTaskbar = false; this.MinimizeBox = false; } - if (arg.ToLower() == "-nonative") { webSocketClient.nativeWebSocketFirst = false; } + if (arg.ToLower() == "-native") { webSocketClient.nativeWebSocketFirst = true; } if (arg.Length > 6 && arg.Substring(0, 6).ToLower() == "-host:") { serverNameComboBox.Text = arg.Substring(6); argflags |= 1; } if (arg.Length > 6 && arg.Substring(0, 6).ToLower() == "-user:") { userNameTextBox.Text = arg.Substring(6); argflags |= 2; } if (arg.Length > 6 && arg.Substring(0, 6).ToLower() == "-pass:") { passwordTextBox.Text = arg.Substring(6); argflags |= 4; } diff --git a/WebSocketClient.cs b/WebSocketClient.cs index ccaa446..0e3fd73 100644 --- a/WebSocketClient.cs +++ b/WebSocketClient.cs @@ -64,6 +64,7 @@ namespace MeshCentralRouter public int pongTimeSeconds = 0; private System.Threading.Timer pingTimer = null; private System.Threading.Timer pongTimer = null; + private System.Threading.Timer connectTimer = null; private bool pendingSendCall = false; private MemoryStream pendingSendBuffer = null; private bool readPaused = false; @@ -73,7 +74,7 @@ namespace MeshCentralRouter public TLSCertificateCheck TLSCertCheck = TLSCertificateCheck.Verify; public X509Certificate2 tlsCert = null; public X509Certificate2 failedTlsCert = null; - static public bool nativeWebSocketFirst = true; + static public bool nativeWebSocketFirst = false; private SemaphoreSlim receiveLock = new SemaphoreSlim(1, 1); // Outside variables @@ -143,6 +144,7 @@ namespace MeshCentralRouter } if (pingTimer != null) { pingTimer.Dispose(); pingTimer = null; } if (pongTimer != null) { pongTimer.Dispose(); pongTimer = null; } + if (connectTimer != null) { try { connectTimer.Dispose(); } catch (Exception) { } connectTimer = null; } if (wsstream != null) { try { wsstream.Close(); } catch (Exception) { } try { wsstream.Dispose(); } catch (Exception) { } wsstream = null; } if (wsclient != null) { wsclient = null; } if (pendingSendBuffer != null) { pendingSendBuffer.Dispose(); pendingSendBuffer = null; } @@ -179,15 +181,15 @@ namespace MeshCentralRouter CTS = null; } - public bool Start(Uri url, string tlsCertFingerprint, string tlsCertFingerprint2) + public bool Start(Uri url, string tlsCertFingerprint, string tlsCertFingerprint2, bool force = false) { - if (state != ConnectionStates.Disconnected) return false; + if ((force == false) && (state != ConnectionStates.Disconnected)) return false; SetState(ConnectionStates.Connecting); this.url = url; if (tlsCertFingerprint != null) { this.tlsCertFingerprint = tlsCertFingerprint.ToUpper(); } if (tlsCertFingerprint2 != null) { this.tlsCertFingerprint2 = tlsCertFingerprint2.ToUpper(); } - //if (nativeWebSocketFirst) { try { ws = new ClientWebSocket(); } catch (Exception) { } } + if (nativeWebSocketFirst) { try { ws = new ClientWebSocket(); } catch (Exception) { } } if (ws != null) { // Use Windows native websockets @@ -240,12 +242,18 @@ namespace MeshCentralRouter if (h.StartsWith("[") && h.EndsWith("]")) { h = h.Substring(1, h.Length - 2); } wsclient.BeginConnect(h, url.Port, new AsyncCallback(OnConnectSink), this); } + + // Start a timer that will fallback to native sockets automatically. + // For some proxy types, native websockets are the only way to connect. + if (connectTimer != null) { try { connectTimer.Dispose(); } catch (Exception) { } connectTimer = null; } + connectTimer = new System.Threading.Timer(new System.Threading.TimerCallback(ConnectTimerCallback), null, 3000, 3000); } return true; } private void OnConnectSink(IAsyncResult ar) { + if (connectTimer != null) { try { connectTimer.Dispose(); } catch (Exception) { } connectTimer = null; } if (wsclient == null) return; // Accept the connection @@ -256,7 +264,14 @@ namespace MeshCentralRouter catch (Exception ex) { Log("Websocket TCP failed to connect: " + ex.ToString()); - Dispose(); + if (nativeWebSocketFirst == false) + { + ConnectTimerCallback(null); + } + else + { + Dispose(); + } return; } @@ -468,6 +483,22 @@ namespace MeshCentralRouter private void PongTimerCallback(object state) { SendPong(null, 0, 0); } + private void ConnectTimerCallback(object state) { + // Switch from C# sockets to native sockets + if ((nativeWebSocketFirst == false) && (this.state == ConnectionStates.Connecting)) + { + Log("Switching to native Websocket"); + if (pingTimer != null) { try { pingTimer.Dispose(); } catch (Exception) { } pingTimer = null; } + if (pongTimer != null) { try { pongTimer.Dispose(); } catch (Exception) { } pongTimer = null; } + if (connectTimer != null) { try { connectTimer.Dispose(); } catch (Exception) { } connectTimer = null; } + if (wsstream != null) { try { wsstream.Close(); } catch (Exception) { } try { wsstream.Dispose(); } catch (Exception) { } wsstream = null; } + if (wsclient != null) { wsclient = null; } + if (pendingSendBuffer != null) { pendingSendBuffer.Dispose(); pendingSendBuffer = null; } + nativeWebSocketFirst = true; + Start(this.url, this.tlsCertFingerprint, this.tlsCertFingerprint2, true); + } + } + private int ProcessBuffer(byte[] buffer, int offset, int len) { TlsDump("InRaw", buffer, offset, len); From e4c3af06824af2612899328fad2e9940b43a67ba Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Sun, 23 Jan 2022 23:14:02 -0800 Subject: [PATCH 06/20] Updated translations and headers. --- AddPortMapForm.cs | 2 +- AddRelayMapForm.cs | 2 +- AppLaunchForm.cs | 2 +- DeviceSettingsForm.cs | 2 +- DeviceUserControl.cs | 2 +- FileDeletePromptForm.cs | 2 +- FileTransferStatusForm.cs | 2 +- FileViewer.cs | 2 +- FilenamePromptForm.cs | 2 +- InstallForm.cs | 2 +- KVMControl.cs | 2 +- KVMControlHook.cs | 2 +- KVMResizeControl.cs | 2 +- KVMSettingsForm.cs | 2 +- KVMStats.cs | 2 +- KVMViewer.cs | 2 +- LocalPipe.cs | 2 +- MainForm.Designer.cs | 20 +- MainForm.cs | 3 +- MainForm.resx | 524 ++- MapUserControl.cs | 2 +- MappingHelpForm.cs | 2 +- MappingStats.cs | 2 +- MeshCentralServer.cs | 821 ++-- MeshDiscovery.cs | 2 +- MeshMapper.cs | 2 +- NodeClass.cs | 2 +- Program.cs | 2 +- ServerUserControl.cs | 2 +- Settings.cs | 2 +- SettingsForm.cs | 2 +- SshUsernameForm.cs | 2 +- Translate.cs | 7431 ++++++++++++++++++++++--------------- UpdateForm.cs | 2 +- WebSocketClient.cs | 2 +- Win32Api.cs | 2 +- altPortForm.cs | 2 +- rdpPortForm.cs | 2 +- 38 files changed, 5320 insertions(+), 3545 deletions(-) diff --git a/AddPortMapForm.cs b/AddPortMapForm.cs index ac734e7..4205ea7 100644 --- a/AddPortMapForm.cs +++ b/AddPortMapForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/AddRelayMapForm.cs b/AddRelayMapForm.cs index 2e3e477..0f02405 100644 --- a/AddRelayMapForm.cs +++ b/AddRelayMapForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/AppLaunchForm.cs b/AppLaunchForm.cs index bf5e2a3..027a8e8 100644 --- a/AppLaunchForm.cs +++ b/AppLaunchForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/DeviceSettingsForm.cs b/DeviceSettingsForm.cs index 705a22f..0d0f8ab 100644 --- a/DeviceSettingsForm.cs +++ b/DeviceSettingsForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/DeviceUserControl.cs b/DeviceUserControl.cs index f799a6d..41e685a 100644 --- a/DeviceUserControl.cs +++ b/DeviceUserControl.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/FileDeletePromptForm.cs b/FileDeletePromptForm.cs index 7d77b4c..8853ff5 100644 --- a/FileDeletePromptForm.cs +++ b/FileDeletePromptForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/FileTransferStatusForm.cs b/FileTransferStatusForm.cs index 06df3c6..f74d392 100644 --- a/FileTransferStatusForm.cs +++ b/FileTransferStatusForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/FileViewer.cs b/FileViewer.cs index b6fd7fd..dc1d44f 100644 --- a/FileViewer.cs +++ b/FileViewer.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/FilenamePromptForm.cs b/FilenamePromptForm.cs index eec6202..cdf0a24 100644 --- a/FilenamePromptForm.cs +++ b/FilenamePromptForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/InstallForm.cs b/InstallForm.cs index 55a2965..1c9cf17 100644 --- a/InstallForm.cs +++ b/InstallForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/KVMControl.cs b/KVMControl.cs index 1075cde..af53a5a 100644 --- a/KVMControl.cs +++ b/KVMControl.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/KVMControlHook.cs b/KVMControlHook.cs index 72575a7..de71aef 100644 --- a/KVMControlHook.cs +++ b/KVMControlHook.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/KVMResizeControl.cs b/KVMResizeControl.cs index f66c325..ba7da4b 100644 --- a/KVMResizeControl.cs +++ b/KVMResizeControl.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/KVMSettingsForm.cs b/KVMSettingsForm.cs index 9e10a5d..033dccd 100644 --- a/KVMSettingsForm.cs +++ b/KVMSettingsForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/KVMStats.cs b/KVMStats.cs index 494f905..4d62f2d 100644 --- a/KVMStats.cs +++ b/KVMStats.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/KVMViewer.cs b/KVMViewer.cs index 2e8ca98..e681e61 100644 --- a/KVMViewer.cs +++ b/KVMViewer.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LocalPipe.cs b/LocalPipe.cs index 6e83fe3..90dc3a2 100644 --- a/LocalPipe.cs +++ b/LocalPipe.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index c42ab5a..a4e9858 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -48,6 +48,7 @@ this.nextButton1 = new System.Windows.Forms.Button(); this.pictureBox3 = new System.Windows.Forms.PictureBox(); this.label1 = new System.Windows.Forms.Label(); + this.pictureBox2 = new System.Windows.Forms.PictureBox(); this.tabPage2 = new System.Windows.Forms.TabPage(); this.panel2 = new System.Windows.Forms.Panel(); this.tokenRememberCheckBox = new System.Windows.Forms.CheckBox(); @@ -135,13 +136,13 @@ this.settingsToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.openMapFileDialog = new System.Windows.Forms.OpenFileDialog(); this.saveMapFileDialog = new System.Windows.Forms.SaveFileDialog(); - this.pictureBox2 = new System.Windows.Forms.PictureBox(); this.panel5.SuspendLayout(); this.mainPanel.SuspendLayout(); this.mainTabControl.SuspendLayout(); this.tabPage1.SuspendLayout(); this.panel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit(); this.tabPage2.SuspendLayout(); this.panel2.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox6)).BeginInit(); @@ -164,7 +165,6 @@ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.trayIconContextMenuStrip.SuspendLayout(); this.mappingsContextMenuStrip.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit(); this.SuspendLayout(); // // panel5 @@ -304,6 +304,13 @@ this.label1.Name = "label1"; this.label1.UseMnemonic = false; // + // pictureBox2 + // + resources.ApplyResources(this.pictureBox2, "pictureBox2"); + this.pictureBox2.Image = global::MeshCentralRouter.Properties.Resources.MeshCentral; + this.pictureBox2.Name = "pictureBox2"; + this.pictureBox2.TabStop = false; + // // tabPage2 // this.tabPage2.Controls.Add(this.panel2); @@ -958,13 +965,6 @@ this.saveMapFileDialog.DefaultExt = "mcrouter"; resources.ApplyResources(this.saveMapFileDialog, "saveMapFileDialog"); // - // pictureBox2 - // - resources.ApplyResources(this.pictureBox2, "pictureBox2"); - this.pictureBox2.Image = global::MeshCentralRouter.Properties.Resources.MeshCentral; - this.pictureBox2.Name = "pictureBox2"; - this.pictureBox2.TabStop = false; - // // MainForm // resources.ApplyResources(this, "$this"); @@ -984,6 +984,7 @@ this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit(); this.tabPage2.ResumeLayout(false); this.panel2.ResumeLayout(false); this.panel2.PerformLayout(); @@ -1009,7 +1010,6 @@ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.trayIconContextMenuStrip.ResumeLayout(false); this.mappingsContextMenuStrip.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit(); this.ResumeLayout(false); } diff --git a/MainForm.cs b/MainForm.cs index fc1eaf0..60524d3 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -560,6 +560,7 @@ namespace MeshCentralRouter private void Meshcentral_onTwoFactorCookie(string cookie) { if (this.InvokeRequired) { this.Invoke(new MeshCentralServer.twoFactorCookieHandler(Meshcentral_onTwoFactorCookie), cookie); return; } + if (debug) { try { File.AppendAllText("debug.log", "Saving 2FA cookie\r\n"); } catch (Exception) { } } Settings.SetRegValue("TwoFactorCookie", cookie); } diff --git a/MainForm.resx b/MainForm.resx index 1f7b561..8f90901 100644 --- a/MainForm.resx +++ b/MainForm.resx @@ -129,10 +129,13 @@ - 11, 285 + 15, 354 + + + 4, 4, 4, 4 - 95, 23 + 127, 28 @@ -169,10 +172,13 @@ NoControl - 241, 225 + 321, 277 + + + 4, 0, 4, 0 - 88, 13 + 114, 17 19 @@ -202,10 +208,13 @@ NoControl - 238, 176 + 317, 217 + + + 4, 0, 4, 0 - 53, 13 + 69, 17 18 @@ -232,10 +241,13 @@ NoControl - 238, 135 + 317, 166 + + + 4, 0, 4, 0 - 55, 13 + 73, 17 17 @@ -262,10 +274,13 @@ NoControl - 238, 92 + 317, 113 + + + 4, 0, 4, 0 - 38, 13 + 50, 17 16 @@ -289,13 +304,16 @@ Top, Left, Right - 241, 192 + 321, 236 + + + 4, 4, 4, 4 - 214, 20 + 287, 22 102 @@ -319,10 +337,13 @@ meshcentral.com - 241, 110 + 321, 135 + + + 4, 4, 4, 4 - 214, 21 + 287, 24 100 @@ -343,10 +364,13 @@ Top, Left, Right - 241, 151 + 321, 186 + + + 4, 4, 4, 4 - 214, 20 + 287, 22 101 @@ -370,10 +394,13 @@ NoControl - 174, 260 + 235, 323 + + + 4, 0, 4, 0 - 303, 13 + 404, 16 103 @@ -406,10 +433,13 @@ NoControl - 3, 260 + 4, 323 + + + 4, 0, 4, 0 - 37, 13 + 47, 17 11 @@ -436,10 +466,13 @@ NoControl - 371, 285 + 498, 354 + + + 4, 4, 4, 4 - 95, 23 + 127, 28 105 @@ -466,10 +499,13 @@ NoControl - 0, 276 + 0, 343 + + + 4, 4, 4, 4 - 478, 40 + 640, 49 StretchImage @@ -496,10 +532,13 @@ NoControl - 12, 9 + 16, 11 + + + 4, 0, 4, 0 - 454, 56 + 608, 69 6 @@ -526,10 +565,13 @@ NoControl - 15, 68 + 20, 84 + + + 4, 4, 4, 4 - 217, 170 + 292, 212 Zoom @@ -553,10 +595,13 @@ Fill - 3, 3 + 4, 4 + + + 4, 4, 4, 4 - 478, 316 + 640, 392 6 @@ -574,13 +619,16 @@ 0 - 4, 25 + 4, 28 + + + 4, 4, 4, 4 - 3, 3, 3, 3 + 4, 4, 4, 4 - 484, 322 + 648, 400 0 @@ -607,10 +655,13 @@ NoControl - 241, 221 + 321, 272 + + + 4, 4, 4, 4 - 131, 17 + 170, 21 204 @@ -637,10 +688,13 @@ NoControl - 241, 177 + 321, 218 + + + 4, 4, 4, 4 - 95, 23 + 127, 28 202 @@ -667,10 +721,13 @@ NoControl - 342, 177 + 456, 218 + + + 4, 4, 4, 4 - 95, 23 + 127, 28 203 @@ -700,10 +757,13 @@ NoControl - 238, 182 + 317, 224 + + + 4, 0, 4, 0 - 55, 13 + 73, 17 21 @@ -733,10 +793,13 @@ NoControl - 238, 135 + 317, 166 + + + 4, 0, 4, 0 - 38, 13 + 48, 17 19 @@ -760,10 +823,13 @@ Top, Left, Right - 241, 151 + 321, 186 + + + 4, 4, 4, 4 - 214, 20 + 287, 22 201 @@ -787,10 +853,13 @@ NoControl - 15, 68 + 20, 84 + + + 4, 4, 4, 4 - 202, 170 + 272, 212 Zoom @@ -817,10 +886,13 @@ NoControl - 270, 285 + 363, 354 + + + 4, 4, 4, 4 - 95, 23 + 127, 28 205 @@ -847,10 +919,13 @@ NoControl - 371, 285 + 498, 354 + + + 4, 4, 4, 4 - 95, 23 + 127, 28 206 @@ -877,10 +952,13 @@ NoControl - 0, 276 + 0, 343 + + + 4, 4, 4, 4 - 478, 40 + 640, 49 StretchImage @@ -907,10 +985,13 @@ NoControl - 12, 9 + 16, 11 + + + 4, 0, 4, 0 - 454, 56 + 608, 69 6 @@ -934,10 +1015,13 @@ Fill - 3, 3 + 4, 4 + + + 4, 4, 4, 4 - 478, 316 + 640, 392 7 @@ -955,13 +1039,16 @@ 0 - 4, 25 + 4, 28 + + + 4, 4, 4, 4 - 3, 3, 3, 3 + 4, 4, 4, 4 - 484, 322 + 648, 400 1 @@ -988,10 +1075,13 @@ True - 208, 255 + 277, 318 + + + 4, 4, 4, 4 - 145, 17 + 190, 21 302 @@ -1015,7 +1105,10 @@ Top, Bottom, Left, Right - 15, 82 + 20, 101 + + + 4, 4, 4, 4 True @@ -1024,7 +1117,7 @@ Vertical - 450, 162 + 602, 202 25 @@ -1048,10 +1141,13 @@ NoControl - 14, 251 + 19, 313 + + + 4, 4, 4, 4 - 188, 23 + 251, 28 301 @@ -1081,10 +1177,13 @@ NoControl - 8, 6 + 11, 7 + + + 4, 0, 4, 0 - 468, 22 + 627, 27 23 @@ -1114,10 +1213,13 @@ NoControl - 12, 34 + 16, 42 + + + 4, 0, 4, 0 - 454, 45 + 608, 55 22 @@ -1144,10 +1246,13 @@ NoControl - 276, 291 + 371, 362 + + + 4, 4, 4, 4 - 95, 23 + 127, 28 303 @@ -1174,10 +1279,13 @@ NoControl - 377, 291 + 506, 362 + + + 4, 4, 4, 4 - 95, 23 + 127, 28 304 @@ -1204,10 +1312,13 @@ NoControl - 0, 282 + 0, 351 + + + 4, 4, 4, 4 - 484, 40 + 648, 49 StretchImage @@ -1233,8 +1344,11 @@ 0, 0 + + 4, 4, 4, 4 + - 484, 322 + 648, 400 8 @@ -1252,10 +1366,13 @@ 0 - 4, 25 + 4, 28 + + + 4, 4, 4, 4 - 484, 322 + 648, 400 2 @@ -1285,43 +1402,43 @@ 613, 17 - 185, 22 + 218, 26 Show &Group Names - 185, 22 + 218, 26 Show &Offline Devices - 182, 6 + 215, 6 - 185, 22 + 218, 26 Sort by &Name - 185, 22 + 218, 26 Sort by G&roup - 182, 6 + 215, 6 - 185, 22 + 218, 26 S&ettings... - 186, 126 + 219, 146 mainContextMenuStrip @@ -1336,10 +1453,13 @@ NoControl - 454, 2 + 608, 2 + + + 4, 0, 4, 0 - 25, 25 + 31, 31 403 @@ -1363,10 +1483,13 @@ Top, Right - 306, 5 + 411, 6 + + + 4, 4, 4, 4 - 146, 20 + 193, 22 402 @@ -1399,10 +1522,13 @@ Bottom, Left - 4, 174 + 5, 210 + + + 4, 4, 4, 4 - 168, 35 + 224, 43 405 @@ -1444,82 +1570,82 @@ Segoe UI, 9pt, style=Bold - 170, 22 + 198, 24 Add &Map... - 170, 22 + 198, 24 Add &Relay Map... - 167, 6 + 195, 6 - 171, 22 + 204, 26 Ask Consent + Bar - 171, 22 + 204, 26 Ask Consent - 171, 22 + 204, 26 Privacy Bar - 170, 22 + 198, 24 Remote Desktop... - 170, 22 + 198, 24 Remote Files... - 170, 22 + 198, 24 HTTP - 170, 22 + 198, 24 HTTPS - 170, 22 + 198, 24 RDP - 170, 22 + 198, 24 SSH - 170, 22 + 198, 24 SCP - 171, 208 + 199, 226 devicesContextMenuStrip @@ -1535,7 +1661,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADg - HQAAAk1TRnQBSQFMAgEBEAEAAXgBAAF4AQABEAEAARABAAT/ARkBAAj/AUIBTQE2BwABNgMAASgDAAFA + HQAAAk1TRnQBSQFMAgEBEAEAAYABAAGAAQABEAEAARABAAT/ARkBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABUAMAAQEBAAEYBgABPP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AJYAA/0D+AP3A/sD/yEAA/0D+gP5 A/wD/xgAAfoB+wH6A/4qAAP9A/8tAAP7A88D1QPbA88D1AO+A9QYAAP8A90D4APjA90D4APUA+MSAAP8 AZEBjwF9AU4BaAEhAfQB9QH0JAAD/gPRA8YD+ioAAcYCxwHPAtAB2ALZA90DywPBA68DmgP3FQAD2APd @@ -1666,10 +1792,13 @@ - 10, 4 + 13, 5 + + + 4, 4, 4, 4 - 446, 210 + 593, 258 404 @@ -1699,10 +1828,13 @@ NoControl - 2, 88 + 3, 108 + + + 4, 0, 4, 0 - 399, 52 + 530, 64 5 @@ -1738,10 +1870,13 @@ NoControl - 2, 88 + 3, 108 + + + 4, 0, 4, 0 - 399, 52 + 530, 64 4 @@ -1767,8 +1902,11 @@ 0, 0 + + 4, 4, 4, 4 + - 470, 248 + 628, 305 50 @@ -1786,13 +1924,16 @@ 0 - 4, 25 + 4, 28 + + + 4, 4, 4, 4 - 3, 3, 3, 3 + 4, 4, 4, 4 - 470, 250 + 632, 315 0 @@ -1819,10 +1960,13 @@ NoControl - 4, 185 + 5, 217 + + + 4, 4, 4, 4 - 168, 35 + 224, 43 55 @@ -1861,10 +2005,13 @@ NoControl - 6, 79 + 8, 97 + + + 4, 0, 4, 0 - 453, 52 + 595, 64 4 @@ -1892,8 +2039,11 @@ Click "Add" to get started. 0, 0 + + 4, 4, 4, 4 + - 473, 224 + 625, 264 49 @@ -1917,10 +2067,13 @@ Click "Add" to get started. NoControl - 1, 229 + 1, 271 + + + 4, 4, 4, 4 - 20, 20 + 27, 25 54 @@ -1944,10 +2097,13 @@ Click "Add" to get started. NoControl - 241, 229 + 317, 271 + + + 4, 4, 4, 4 - 20, 20 + 27, 25 5 @@ -1974,10 +2130,13 @@ Click "Add" to get started. NoControl - 373, 227 + 493, 268 + + + 4, 4, 4, 4 - 100, 23 + 133, 28 50 @@ -2007,10 +2166,13 @@ Click "Add" to get started. NoControl - 267, 227 + 352, 268 + + + 4, 4, 4, 4 - 100, 23 + 133, 28 52 @@ -2031,13 +2193,16 @@ Click "Add" to get started. 5 - 4, 25 + 4, 28 + + + 4, 4, 4, 4 - 3, 3, 3, 3 + 4, 4, 4, 4 - 473, 256 + 629, 311 1 @@ -2058,10 +2223,13 @@ Click "Add" to get started. 1 - 3, 3 + 4, 4 + + + 4, 4, 4, 4 - 478, 279 + 640, 347 401 @@ -2085,10 +2253,13 @@ Click "Add" to get started. NoControl - 15, 291 + 20, 362 + + + 4, 4, 4, 4 - 109, 23 + 145, 28 406 @@ -2118,10 +2289,13 @@ Click "Add" to get started. NoControl - 276, 291 + 371, 362 + + + 4, 4, 4, 4 - 95, 23 + 127, 28 407 @@ -2148,10 +2322,13 @@ Click "Add" to get started. NoControl - 377, 291 + 506, 362 + + + 4, 4, 4, 4 - 95, 23 + 127, 28 408 @@ -2178,10 +2355,13 @@ Click "Add" to get started. NoControl - 0, 282 + 0, 351 + + + 4, 4, 4, 4 - 484, 40 + 648, 49 StretchImage @@ -2207,8 +2387,11 @@ Click "Add" to get started. 0, 0 + + 4, 4, 4, 4 + - 484, 322 + 648, 400 8 @@ -2226,10 +2409,13 @@ Click "Add" to get started. 0 - 4, 25 + 4, 28 + + + 4, 4, 4, 4 - 484, 322 + 648, 400 4 @@ -2259,7 +2445,7 @@ Click "Add" to get started. 0, 0, 0, 0 - 492, 351 + 656, 432 8 @@ -2283,10 +2469,13 @@ Click "Add" to get started. Fill - 0, 65 + 0, 80 + + + 4, 4, 4, 4 - 492, 351 + 656, 432 9 @@ -2312,8 +2501,11 @@ Click "Add" to get started. 0, 0 + + 4, 4, 4, 4 + - 492, 65 + 656, 80 Zoom @@ -2339,8 +2531,11 @@ Click "Add" to get started. 0, 0 + + 4, 4, 4, 4 + - 492, 416 + 656, 512 8 @@ -2370,22 +2565,22 @@ Click "Add" to get started. 418, 17 - 112, 22 + 123, 24 &Open... - 109, 6 + 120, 6 - 112, 22 + 123, 24 E&xit - 113, 54 + 124, 58 trayIconContextMenuStrip @@ -4097,28 +4292,28 @@ Click "Add" to get started. 905, 17 - 168, 22 + 193, 24 &Open Mappings... - 168, 22 + 193, 24 &Save Mappings... - 165, 6 + 190, 6 - 168, 22 + 193, 24 S&ettings... - 169, 76 + 194, 82 mappingsContextMenuStrip @@ -4148,10 +4343,10 @@ Click "Add" to get started. True - 6, 13 + 8, 16 - 492, 416 + 656, 512 @@ -5847,6 +6042,9 @@ Click "Add" to get started. AADAPwAAwD8AAMA/AADAPwAA + + 4, 4, 4, 4 + MeshCentral Router diff --git a/MapUserControl.cs b/MapUserControl.cs index d382914..3a78f6b 100644 --- a/MapUserControl.cs +++ b/MapUserControl.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MappingHelpForm.cs b/MappingHelpForm.cs index 5b71305..3709375 100644 --- a/MappingHelpForm.cs +++ b/MappingHelpForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MappingStats.cs b/MappingStats.cs index 559738b..45a76d5 100644 --- a/MappingStats.cs +++ b/MappingStats.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MeshCentralServer.cs b/MeshCentralServer.cs index f637cf7..51fd03d 100644 --- a/MeshCentralServer.cs +++ b/MeshCentralServer.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -222,199 +222,354 @@ namespace MeshCentralRouter } if (jsonAction == null || jsonAction["action"].GetType() != typeof(string)) return; - string action = jsonAction["action"].ToString(); - switch (action) + try { - case "pong": - { - // NOP - break; - } - case "ping": - { - // Send pong back - if (wc != null) { wc.SendString("{\"action\":\"pong\"}"); } - break; - } - case "close": - { - disconnectCause = jsonAction["cause"].ToString(); - disconnectMsg = jsonAction["msg"].ToString(); - if (jsonAction.ContainsKey("email2fa")) { disconnectEmail2FA = (bool)jsonAction["email2fa"]; } else { disconnectEmail2FA = false; } - if (jsonAction.ContainsKey("email2fasent")) { disconnectEmail2FASent = (bool)jsonAction["email2fasent"]; } else { disconnectEmail2FASent = false; } - if (jsonAction.ContainsKey("sms2fa")) { disconnectSms2FA = (bool)jsonAction["sms2fa"]; } else { disconnectSms2FA = false; } - if (jsonAction.ContainsKey("sms2fasent")) { disconnectSms2FASent = (bool)jsonAction["sms2fasent"]; } else { disconnectSms2FASent = false; } - if (jsonAction.ContainsKey("twoFactorCookieDays") && (jsonAction["twoFactorCookieDays"].GetType() == typeof(int))) { twoFactorCookieDays = (int)jsonAction["twoFactorCookieDays"]; } - break; - } - case "serverinfo": - { - // Get the bit flags of server features - Dictionary serverinfo = (Dictionary)jsonAction["serverinfo"]; - if (serverinfo.ContainsKey("features") && (serverinfo["features"].GetType() == typeof(int))) { features = (int)serverinfo["features"]; } - if (serverinfo.ContainsKey("features2") && (serverinfo["features2"].GetType() == typeof(int))) { features2 = (int)serverinfo["features2"]; } - - // Ask for a lot of things from the server - wc.SendString("{\"action\":\"usergroups\"}"); - wc.SendString("{\"action\":\"meshes\"}"); - wc.SendString("{\"action\":\"nodes\"}"); - wc.SendString("{\"action\":\"authcookie\"}"); - wc.SendString("{\"action\":\"logincookie\"}"); - wc.SendString("{\"action\":\"meshToolInfo\",\"name\":\"MeshCentralRouter\"}"); - break; - } - case "authcookie": - { - authCookie = jsonAction["cookie"].ToString(); - rauthCookie = jsonAction["rcookie"].ToString(); - changeState(2); - - if (sender.RemoteCertificate != null) + string action = jsonAction["action"].ToString(); + switch (action) + { + case "pong": { - certHash = webSocketClient.GetMeshCertHash(new X509Certificate2(sender.RemoteCertificate)); + // NOP + break; } - - break; - } - case "logincookie": - { - loginCookie = jsonAction["cookie"].ToString(); - if (onLoginTokenChanged != null) { onLoginTokenChanged(); } - break; - } - case "userinfo": - { - Dictionary userinfo = (Dictionary)jsonAction["userinfo"]; - userid = (string)userinfo["_id"]; - if (userinfo.ContainsKey("name")) { username = (string)userinfo["name"]; } - userRights = new Dictionary(); - if (userinfo.ContainsKey("links")) + case "ping": { - Dictionary userLinks = (Dictionary)userinfo["links"]; - foreach (string i in userLinks.Keys) + // Send pong back + if (wc != null) { wc.SendString("{\"action\":\"pong\"}"); } + break; + } + case "close": + { + disconnectCause = jsonAction["cause"].ToString(); + disconnectMsg = jsonAction["msg"].ToString(); + if (jsonAction.ContainsKey("email2fa")) { disconnectEmail2FA = (bool)jsonAction["email2fa"]; } else { disconnectEmail2FA = false; } + if (jsonAction.ContainsKey("email2fasent")) { disconnectEmail2FASent = (bool)jsonAction["email2fasent"]; } else { disconnectEmail2FASent = false; } + if (jsonAction.ContainsKey("sms2fa")) { disconnectSms2FA = (bool)jsonAction["sms2fa"]; } else { disconnectSms2FA = false; } + if (jsonAction.ContainsKey("sms2fasent")) { disconnectSms2FASent = (bool)jsonAction["sms2fasent"]; } else { disconnectSms2FASent = false; } + if (jsonAction.ContainsKey("twoFactorCookieDays") && (jsonAction["twoFactorCookieDays"].GetType() == typeof(int))) { twoFactorCookieDays = (int)jsonAction["twoFactorCookieDays"]; } + break; + } + case "serverinfo": + { + // Get the bit flags of server features + Dictionary serverinfo = (Dictionary)jsonAction["serverinfo"]; + if (serverinfo.ContainsKey("features") && (serverinfo["features"].GetType() == typeof(int))) { features = (int)serverinfo["features"]; } + if (serverinfo.ContainsKey("features2") && (serverinfo["features2"].GetType() == typeof(int))) { features2 = (int)serverinfo["features2"]; } + + // Ask for a lot of things from the server + wc.SendString("{\"action\":\"usergroups\"}"); + wc.SendString("{\"action\":\"meshes\"}"); + wc.SendString("{\"action\":\"nodes\"}"); + wc.SendString("{\"action\":\"authcookie\"}"); + wc.SendString("{\"action\":\"logincookie\"}"); + wc.SendString("{\"action\":\"meshToolInfo\",\"name\":\"MeshCentralRouter\"}"); + break; + } + case "authcookie": + { + authCookie = jsonAction["cookie"].ToString(); + rauthCookie = jsonAction["rcookie"].ToString(); + changeState(2); + + if (sender.RemoteCertificate != null) { - Dictionary userLinksEx = (Dictionary)userLinks[i]; - if (userLinksEx.ContainsKey("rights")) + certHash = webSocketClient.GetMeshCertHash(new X509Certificate2(sender.RemoteCertificate)); + } + + break; + } + case "logincookie": + { + loginCookie = jsonAction["cookie"].ToString(); + if (onLoginTokenChanged != null) { onLoginTokenChanged(); } + break; + } + case "userinfo": + { + Dictionary userinfo = (Dictionary)jsonAction["userinfo"]; + userid = (string)userinfo["_id"]; + if (userinfo.ContainsKey("name")) { username = (string)userinfo["name"]; } + userRights = new Dictionary(); + if (userinfo.ContainsKey("links")) + { + Dictionary userLinks = (Dictionary)userinfo["links"]; + foreach (string i in userLinks.Keys) { - userRights[i] = ulong.Parse(userLinksEx["rights"].ToString()); + Dictionary userLinksEx = (Dictionary)userLinks[i]; + if (userLinksEx.ContainsKey("rights")) + { + userRights[i] = ulong.Parse(userLinksEx["rights"].ToString()); + } } } + break; } - break; - } - case "usergroups": - { - userGroups = new Dictionary(); - if (jsonAction.ContainsKey("ugroups")) + case "usergroups": { - Dictionary usergroups = (Dictionary)jsonAction["ugroups"]; - if (usergroups != null) + userGroups = new Dictionary(); + if (jsonAction.ContainsKey("ugroups")) { - foreach (string i in usergroups.Keys) + Dictionary usergroups = (Dictionary)jsonAction["ugroups"]; + if (usergroups != null) { - Dictionary usergroupsEx = (Dictionary)usergroups[i]; - if (usergroupsEx.ContainsKey("name")) + foreach (string i in usergroups.Keys) { - userGroups.Add(i, usergroupsEx["name"].ToString()); - } - } - if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(false); - } - } - break; - } - case "event": - { - Dictionary ev = (Dictionary)jsonAction["event"]; - string action2 = ev["action"].ToString(); - switch (action2) - { - case "meshchange": - { - // Get the new values - string meshid = ev["meshid"].ToString(); - string meshname = (string)ev["name"]; - string meshdesc = (string)ev["desc"]; - int meshtype = (int)ev["mtype"]; - ulong meshrights = 0; - Dictionary links = ((Dictionary)ev["links"]); - if (links.ContainsKey(userid)) - { - Dictionary urights = ((Dictionary)links[userid]); - if (urights != null) + Dictionary usergroupsEx = (Dictionary)usergroups[i]; + if (usergroupsEx.ContainsKey("name")) { - if (urights["rights"].GetType() == typeof(int)) { meshrights = (ulong)((int)urights["rights"]); } - if (urights["rights"].GetType() == typeof(Int64)) { meshrights = (ulong)((Int64)urights["rights"]); } + userGroups.Add(i, usergroupsEx["name"].ToString()); } } - - Dictionary newlinks = new Dictionary(); - foreach (string j in links.Keys) - { - Dictionary urights = ((Dictionary)links[j]); - if (urights != null) - { - if (urights["rights"].GetType() == typeof(int)) { newlinks[j] = (ulong)((int)urights["rights"]); } - if (urights["rights"].GetType() == typeof(Int64)) { newlinks[j] = (ulong)((Int64)urights["rights"]); } - } - } - - // Update the mesh - if (meshes.ContainsKey(meshid)) - { - MeshClass mesh = (MeshClass)meshes[meshid]; - mesh.name = meshname; - mesh.desc = meshdesc; - mesh.rights = meshrights; - mesh.links = newlinks; - } - else - { - MeshClass mesh = new MeshClass(); - mesh.name = meshname; - mesh.desc = meshdesc; - mesh.rights = meshrights; - mesh.type = meshtype; - mesh.links = newlinks; - meshes[meshid] = mesh; - } - wc.SendString("{\"action\":\"nodes\"}"); if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(false); - break; } - case "changenode": - { - if (nodes == null) return; - Dictionary node = (Dictionary)ev["node"]; - string nodeid = (string)node["_id"]; - if (nodes.ContainsKey(nodeid)) + } + break; + } + case "event": + { + Dictionary ev = (Dictionary)jsonAction["event"]; + string action2 = ev["action"].ToString(); + switch (action2) + { + case "meshchange": { - // Change existing node - lock (nodes) + // Get the new values + string meshid = ev["meshid"].ToString(); + string meshname = (string)ev["name"]; + string meshdesc = (string)ev["desc"]; + int meshtype = (int)ev["mtype"]; + ulong meshrights = 0; + Dictionary links = ((Dictionary)ev["links"]); + if (links.ContainsKey(userid)) + { + Dictionary urights = ((Dictionary)links[userid]); + if (urights != null) + { + if (urights["rights"].GetType() == typeof(int)) { meshrights = (ulong)((int)urights["rights"]); } + if (urights["rights"].GetType() == typeof(Int64)) { meshrights = (ulong)((Int64)urights["rights"]); } + } + } + + Dictionary newlinks = new Dictionary(); + foreach (string j in links.Keys) + { + Dictionary urights = ((Dictionary)links[j]); + if (urights != null) + { + if (urights["rights"].GetType() == typeof(int)) { newlinks[j] = (ulong)((int)urights["rights"]); } + if (urights["rights"].GetType() == typeof(Int64)) { newlinks[j] = (ulong)((Int64)urights["rights"]); } + } + } + + // Update the mesh + if (meshes.ContainsKey(meshid)) + { + MeshClass mesh = (MeshClass)meshes[meshid]; + mesh.name = meshname; + mesh.desc = meshdesc; + mesh.rights = meshrights; + mesh.links = newlinks; + } + else + { + MeshClass mesh = new MeshClass(); + mesh.name = meshname; + mesh.desc = meshdesc; + mesh.rights = meshrights; + mesh.type = meshtype; + mesh.links = newlinks; + meshes[meshid] = mesh; + } + wc.SendString("{\"action\":\"nodes\"}"); + if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(false); + break; + } + case "changenode": + { + if (nodes == null) return; + Dictionary node = (Dictionary)ev["node"]; + string nodeid = (string)node["_id"]; + if (nodes.ContainsKey(nodeid)) + { + // Change existing node + lock (nodes) + { + NodeClass n = (NodeClass)nodes[nodeid]; + n.name = (string)node["name"]; + if (node.ContainsKey("agent")) + { + n.agentid = (int)((Dictionary)node["agent"])["id"]; + n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; + } + if (node.ContainsKey("conn")) { n.conn = (int)node["conn"]; } + n.icon = 1; + if (node.ContainsKey("icon")) { n.icon = (int)node["icon"]; } + if (node.ContainsKey("users")) { n.users = (string[])((ArrayList)node["users"]).ToArray(typeof(string)); } else { n.users = null; } + if (node.ContainsKey("rdpport")) { n.rdpport = (int)node["rdpport"]; } + ulong nodeRights = 0; + if (node.ContainsKey("links")) + { + Dictionary links = ((Dictionary)node["links"]); + if (links.ContainsKey(userid)) + { + Dictionary linksEx = ((Dictionary)links[userid]); + if (linksEx.ContainsKey("rights")) { nodeRights = (ulong)(int)linksEx["rights"]; } + } + + n.links = new Dictionary(); + foreach (string j in links.Keys) + { + Dictionary linksEx = ((Dictionary)links[j]); + if (linksEx.ContainsKey("rights")) + { + n.links.Add(j, ulong.Parse(linksEx["rights"].ToString())); + } + } + } + n.rights = nodeRights; + + // Compute rights on this device + ulong rights = n.rights; // Direct device rights + if (meshes.ContainsKey(n.meshid)) { rights |= meshes[n.meshid].rights; } // Device group rights + foreach (string i in n.links.Keys) { if (userGroups.ContainsKey(i)) { rights |= n.links[i]; } } // Take a look at group rights + + if (rights == 0) + { + // We have no rights to this device, remove it + nodes.Remove(n.nodeid); + } + else + { + // Update the node + nodes[n.nodeid] = n; + } + } + if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(false); + } + else + { + wc.SendString("{\"action\":\"nodes\"}"); + } + break; + } + case "nodeconnect": + { + if (nodes == null) return; + string nodeid = (string)ev["nodeid"]; + if (nodes.ContainsKey(nodeid)) + { + lock (nodes) + { + NodeClass n = (NodeClass)nodes[nodeid]; + if (ev.ContainsKey("conn")) { n.conn = (int)ev["conn"]; } + nodes[n.nodeid] = n; + } + if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(false); + } + break; + } + case "usergroupchange": + { + wc.SendString("{\"action\":\"usergroups\"}"); + wc.SendString("{\"action\":\"nodes\"}"); + break; + } + } + break; + } + case "meshes": + { + meshes = new Dictionary(); + + ArrayList meshList = (ArrayList)jsonAction["meshes"]; + for (int i = 0; i < meshList.Count; i++) + { + Dictionary mesh = (Dictionary)meshList[i]; + MeshClass m = new MeshClass(); + m.meshid = (string)mesh["_id"]; + m.name = (string)mesh["name"]; + if (mesh.ContainsKey("desc")) { m.desc = (string)mesh["desc"]; } + m.rights = 0; + m.links = new Dictionary(); + + Dictionary links = ((Dictionary)mesh["links"]); + if (links.ContainsKey(userid)) + { + Dictionary urights = ((Dictionary)links[userid]); + if (urights != null) + { + if (urights["rights"].GetType() == typeof(int)) { m.rights = (ulong)((int)urights["rights"]); } + if (urights["rights"].GetType() == typeof(Int64)) { m.rights = (ulong)((Int64)urights["rights"]); } + } + } + + foreach (string j in links.Keys) + { + Dictionary urights = ((Dictionary)links[j]); + if (urights != null) + { + if (urights["rights"].GetType() == typeof(int)) { m.links[j] = (ulong)((int)urights["rights"]); } + if (urights["rights"].GetType() == typeof(Int64)) { m.links[j] = (ulong)((Int64)urights["rights"]); } + } + } + + if (mesh["mtype"].GetType() == typeof(string)) { m.type = int.Parse((string)mesh["mtype"]); } + if (mesh["mtype"].GetType() == typeof(int)) { m.type = (int)mesh["mtype"]; } + meshes[m.meshid] = m; + } + + break; + } + case "nodes": + { + if (nodes == null) { nodes = new Dictionary(); } + Dictionary nodes2 = new Dictionary(); + lock (nodes) + { + Dictionary groups = (Dictionary)jsonAction["nodes"]; + foreach (string meshid in groups.Keys) + { + ArrayList nodesinMesh = (ArrayList)groups[meshid]; + for (int i = 0; i < nodesinMesh.Count; i++) + { + Dictionary node = (Dictionary)nodesinMesh[i]; + string nodeid = (string)node["_id"]; + if (nodes.ContainsKey(nodeid)) { NodeClass n = (NodeClass)nodes[nodeid]; - n.name = (string)node["name"]; + n.nodeid = nodeid; if (node.ContainsKey("agent")) { n.agentid = (int)((Dictionary)node["agent"])["id"]; n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; } - if (node.ContainsKey("conn")) { n.conn = (int)node["conn"]; } - n.icon = 1; - if (node.ContainsKey("icon")) { n.icon = (int)node["icon"]; } + else + { + n.agentid = -1; + n.agentcaps = 0; + } + n.name = (string)node["name"]; + n.meshid = meshid; + if (node.ContainsKey("mtype")) + { + if (node["mtype"].GetType() == typeof(string)) { n.mtype = int.Parse((string)node["mtype"]); } + if (node["mtype"].GetType() == typeof(int)) { n.mtype = (int)node["mtype"]; } + } if (node.ContainsKey("users")) { n.users = (string[])((ArrayList)node["users"]).ToArray(typeof(string)); } else { n.users = null; } - if (node.ContainsKey("rdpport")) { n.rdpport = (int)node["rdpport"]; } - ulong nodeRights = 0; + if (node.ContainsKey("rdpport")) { n.rdpport = (int)node["rdpport"]; } else { n.rdpport = 3389; } + if (node.ContainsKey("conn")) { n.conn = (int)node["conn"]; } else { n.conn = 0; } + if (node.ContainsKey("icon")) { n.icon = (int)node["icon"]; } + if (n.icon == 0) { n.icon = 1; } + n.rights = 0; + n.links = new Dictionary(); if (node.ContainsKey("links")) { Dictionary links = ((Dictionary)node["links"]); if (links.ContainsKey(userid)) { Dictionary linksEx = ((Dictionary)links[userid]); - if (linksEx.ContainsKey("rights")) { nodeRights = (ulong)(int)linksEx["rights"]; } + if (linksEx.ContainsKey("rights")) { n.rights = (ulong)(int)linksEx["rights"]; } } - - n.links = new Dictionary(); foreach (string j in links.Keys) { Dictionary linksEx = ((Dictionary)links[j]); @@ -424,276 +579,144 @@ namespace MeshCentralRouter } } } - n.rights = nodeRights; - - // Compute rights on this device - ulong rights = n.rights; // Direct device rights - if (meshes.ContainsKey(n.meshid)) { rights |= meshes[n.meshid].rights; } // Device group rights - foreach (string i in n.links.Keys) { if (userGroups.ContainsKey(i)) { rights |= n.links[i]; } } // Take a look at group rights - - if (rights == 0) { - // We have no rights to this device, remove it - nodes.Remove(n.nodeid); - } else { - // Update the node - nodes[n.nodeid] = n; - } + nodes2[n.nodeid] = n; } - if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(false); - } - else - { - wc.SendString("{\"action\":\"nodes\"}"); - } - break; - } - case "nodeconnect": - { - if (nodes == null) return; - string nodeid = (string)ev["nodeid"]; - if (nodes.ContainsKey(nodeid)) - { - lock (nodes) + else { - NodeClass n = (NodeClass)nodes[nodeid]; - if (ev.ContainsKey("conn")) { n.conn = (int)ev["conn"]; } - nodes[n.nodeid] = n; - } - if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(false); - } - break; - } - case "usergroupchange": - { - wc.SendString("{\"action\":\"usergroups\"}"); - wc.SendString("{\"action\":\"nodes\"}"); - break; - } - } - break; - } - case "meshes": - { - meshes = new Dictionary(); - - ArrayList meshList = (ArrayList)jsonAction["meshes"]; - for (int i = 0; i < meshList.Count; i++) - { - Dictionary mesh = (Dictionary)meshList[i]; - MeshClass m = new MeshClass(); - m.meshid = (string)mesh["_id"]; - m.name = (string)mesh["name"]; - if (mesh.ContainsKey("desc")) { m.desc = (string)mesh["desc"]; } - m.rights = 0; - m.links = new Dictionary(); - - Dictionary links = ((Dictionary)mesh["links"]); - if (links.ContainsKey(userid)) - { - Dictionary urights = ((Dictionary)links[userid]); - if (urights != null) - { - if (urights["rights"].GetType() == typeof(int)) { m.rights = (ulong)((int)urights["rights"]); } - if (urights["rights"].GetType() == typeof(Int64)) { m.rights = (ulong)((Int64)urights["rights"]); } - } - } - - foreach (string j in links.Keys) - { - Dictionary urights = ((Dictionary)links[j]); - if (urights != null) - { - if (urights["rights"].GetType() == typeof(int)) { m.links[j] = (ulong)((int)urights["rights"]); } - if (urights["rights"].GetType() == typeof(Int64)) { m.links[j] = (ulong)((Int64)urights["rights"]); } - } - } - - if (mesh["mtype"].GetType() == typeof(string)) { m.type = int.Parse((string)mesh["mtype"]); } - if (mesh["mtype"].GetType() == typeof(int)) { m.type = (int)mesh["mtype"]; } - meshes[m.meshid] = m; - } - - break; - } - case "nodes": - { - if (nodes == null) { nodes = new Dictionary(); } - Dictionary nodes2 = new Dictionary(); - lock (nodes) - { - Dictionary groups = (Dictionary)jsonAction["nodes"]; - foreach (string meshid in groups.Keys) - { - ArrayList nodesinMesh = (ArrayList)groups[meshid]; - for (int i = 0; i < nodesinMesh.Count; i++) - { - Dictionary node = (Dictionary)nodesinMesh[i]; - string nodeid = (string)node["_id"]; - if (nodes.ContainsKey(nodeid)) - { - NodeClass n = (NodeClass)nodes[nodeid]; - n.nodeid = nodeid; - if (node.ContainsKey("agent")) { - n.agentid = (int)((Dictionary)node["agent"])["id"]; - n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; - } else { - n.agentid = -1; - n.agentcaps = 0; - } - n.name = (string)node["name"]; - n.meshid = meshid; - if (node.ContainsKey("mtype")) - { - if (node["mtype"].GetType() == typeof(string)) { n.mtype = int.Parse((string)node["mtype"]); } - if (node["mtype"].GetType() == typeof(int)) { n.mtype = (int)node["mtype"]; } - } - if (node.ContainsKey("users")) { n.users = (string[])((ArrayList)node["users"]).ToArray(typeof(string)); } else { n.users = null; } - if (node.ContainsKey("rdpport")) { n.rdpport = (int)node["rdpport"]; } else { n.rdpport = 3389; } - if (node.ContainsKey("conn")) { n.conn = (int)node["conn"]; } else { n.conn = 0; } - if (node.ContainsKey("icon")) { n.icon = (int)node["icon"]; } - if (n.icon == 0) { n.icon = 1; } - n.rights = 0; - n.links = new Dictionary(); - if (node.ContainsKey("links")) - { - Dictionary links = ((Dictionary)node["links"]); - if (links.ContainsKey(userid)) + NodeClass n = new NodeClass(); + n.nodeid = nodeid; + if (node.ContainsKey("agent")) { - Dictionary linksEx = ((Dictionary)links[userid]); - if (linksEx.ContainsKey("rights")) { n.rights = (ulong)(int)linksEx["rights"]; } + n.agentid = (int)((Dictionary)node["agent"])["id"]; + n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; } - foreach (string j in links.Keys) + else { - Dictionary linksEx = ((Dictionary)links[j]); - if (linksEx.ContainsKey("rights")) + n.agentid = -1; + n.agentcaps = 0; + } + n.name = (string)node["name"]; + n.meshid = meshid; + + if (node.ContainsKey("mtype")) + { + if (node["mtype"].GetType() == typeof(string)) { n.mtype = int.Parse((string)node["mtype"]); } + if (node["mtype"].GetType() == typeof(int)) { n.mtype = (int)node["mtype"]; } + } + if (node.ContainsKey("users")) + { + if (node["users"].GetType() == typeof(ArrayList)) { - n.links.Add(j, ulong.Parse(linksEx["rights"].ToString())); + n.users = (string[])((ArrayList)node["users"]).ToArray(typeof(string)); + } + else if (node["users"].GetType() == typeof(Dictionary)) + { + Dictionary users = (Dictionary)node["users"]; + ArrayList users2 = new ArrayList(); + foreach (string u in users.Keys) { if (users[u].GetType() == typeof(string)) { users2.Add((string)users[u]); } } + n.users = (string[])users2.ToArray(typeof(string)); + } + else + { + n.users = null; } } - } - nodes2[n.nodeid] = n; - } - else - { - NodeClass n = new NodeClass(); - n.nodeid = nodeid; - if (node.ContainsKey("agent")) { - n.agentid = (int)((Dictionary)node["agent"])["id"]; - n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; - } else { - n.agentid = -1; - n.agentcaps = 0; - } - n.name = (string)node["name"]; - n.meshid = meshid; - - if (node.ContainsKey("mtype")) - { - if (node["mtype"].GetType() == typeof(string)) { n.mtype = int.Parse((string)node["mtype"]); } - if (node["mtype"].GetType() == typeof(int)) { n.mtype = (int)node["mtype"]; } - } - if (node.ContainsKey("users")) { - if (node["users"].GetType() == typeof(ArrayList)) { - n.users = (string[])((ArrayList)node["users"]).ToArray(typeof(string)); - } else if (node["users"].GetType() == typeof(Dictionary)) { - Dictionary users = (Dictionary)node["users"]; - ArrayList users2 = new ArrayList(); - foreach (string u in users.Keys) { if (users[u].GetType() == typeof(string)) { users2.Add((string)users[u]); } } - n.users = (string[])users2.ToArray(typeof(string)); - } else { + else + { n.users = null; } - } else { - n.users = null; - } - if (node.ContainsKey("rdpport")) { n.rdpport = (int)node["rdpport"]; } else { n.rdpport = 3389; } - if (node.ContainsKey("conn")) { n.conn = (int)node["conn"]; } else { n.conn = 0; } - if (node.ContainsKey("icon")) { n.icon = (int)node["icon"]; } - if (n.icon == 0) { n.icon = 1; } - n.rights = 0; - n.links = new Dictionary(); - if (node.ContainsKey("links")) - { - Dictionary links = ((Dictionary)node["links"]); - if (links.ContainsKey(userid)) + if (node.ContainsKey("rdpport")) { n.rdpport = (int)node["rdpport"]; } else { n.rdpport = 3389; } + if (node.ContainsKey("conn")) { n.conn = (int)node["conn"]; } else { n.conn = 0; } + if (node.ContainsKey("icon")) { n.icon = (int)node["icon"]; } + if (n.icon == 0) { n.icon = 1; } + n.rights = 0; + n.links = new Dictionary(); + if (node.ContainsKey("links")) { - Dictionary linksEx = ((Dictionary)links[userid]); - if (linksEx.ContainsKey("rights")) { n.rights = (ulong)(int)linksEx["rights"]; } - } - foreach (string j in links.Keys) - { - Dictionary linksEx = ((Dictionary)links[j]); - if (linksEx.ContainsKey("rights")) + Dictionary links = ((Dictionary)node["links"]); + if (links.ContainsKey(userid)) { - n.links.Add(j, ulong.Parse(linksEx["rights"].ToString())); + Dictionary linksEx = ((Dictionary)links[userid]); + if (linksEx.ContainsKey("rights")) { n.rights = (ulong)(int)linksEx["rights"]; } + } + foreach (string j in links.Keys) + { + Dictionary linksEx = ((Dictionary)links[j]); + if (linksEx.ContainsKey("rights")) + { + n.links.Add(j, ulong.Parse(linksEx["rights"].ToString())); + } } } + nodes2[n.nodeid] = n; } - nodes2[n.nodeid] = n; } } } + nodes = nodes2; + if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(true); + break; } - nodes = nodes2; - if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(true); - break; - } - case "msg": - { - if (jsonAction.ContainsKey("type")) + case "msg": { - string type = (string)jsonAction["type"]; - if ((type == "getclip") && (jsonAction.ContainsKey("data")) && (jsonAction.ContainsKey("nodeid"))) + if (jsonAction.ContainsKey("type")) { - // We requested the remote clipboard - string nodeid = (string)jsonAction["nodeid"]; - string clipData = (string)jsonAction["data"]; - if (onClipboardData != null) { onClipboardData(nodeid, clipData); } + string type = (string)jsonAction["type"]; + if ((type == "getclip") && (jsonAction.ContainsKey("data")) && (jsonAction.ContainsKey("nodeid"))) + { + // We requested the remote clipboard + string nodeid = (string)jsonAction["nodeid"]; + string clipData = (string)jsonAction["data"]; + if (onClipboardData != null) { onClipboardData(nodeid, clipData); } + } } + break; } - break; - } - case "twoFactorCookie": - { - if (jsonAction.ContainsKey("cookie")) + case "twoFactorCookie": { - string cookie = (string)jsonAction["cookie"]; - if (onTwoFactorCookie != null) { onTwoFactorCookie(cookie); } + if (jsonAction.ContainsKey("cookie")) + { + string cookie = (string)jsonAction["cookie"]; + if (onTwoFactorCookie != null) { onTwoFactorCookie(cookie); } + } + break; } - break; - } - case "meshToolInfo": - { - if (onToolUpdate == null) return; - if (jsonAction.ContainsKey("hash") && jsonAction.ContainsKey("url")) + case "meshToolInfo": { - // MeshCentral Router hash on the server - string hash = (string)jsonAction["hash"]; + if (onToolUpdate == null) return; + if (jsonAction.ContainsKey("hash") && jsonAction.ContainsKey("url")) + { + // MeshCentral Router hash on the server + string hash = (string)jsonAction["hash"]; - // Hash our own executable - byte[] selfHash; - using (var sha384 = SHA384Managed.Create()) { using (var stream = File.OpenRead(System.Reflection.Assembly.GetEntryAssembly().Location)) { selfHash = sha384.ComputeHash(stream); } } - string selfExecutableHashHex = BitConverter.ToString(selfHash).Replace("-", string.Empty).ToLower(); + // Hash our own executable + byte[] selfHash; + using (var sha384 = SHA384Managed.Create()) { using (var stream = File.OpenRead(System.Reflection.Assembly.GetEntryAssembly().Location)) { selfHash = sha384.ComputeHash(stream); } } + string selfExecutableHashHex = BitConverter.ToString(selfHash).Replace("-", string.Empty).ToLower(); - // Get login key - string url = jsonAction["url"] + "&auth=" + authCookie; - if (url.StartsWith("*/")) { url = "https://" + wsurl.Authority + url.Substring(1); } - string loginkey = getValueFromQueryString(wsurl.Query, "key"); - if (loginkey != null) { url += ("&key=" + loginkey); } + // Get login key + string url = jsonAction["url"] + "&auth=" + authCookie; + if (url.StartsWith("*/")) { url = "https://" + wsurl.Authority + url.Substring(1); } + string loginkey = getValueFromQueryString(wsurl.Query, "key"); + if (loginkey != null) { url += ("&key=" + loginkey); } - // Server TLS certificate hash - string serverhash = null; - if (jsonAction.ContainsKey("serverhash")) { serverhash = jsonAction["serverhash"].ToString(); } + // Server TLS certificate hash + string serverhash = null; + if (jsonAction.ContainsKey("serverhash")) { serverhash = jsonAction["serverhash"].ToString(); } - // If the hashes don't match, event the tool update with URL - if (selfExecutableHashHex != hash) { onToolUpdate((string)url, (string)jsonAction["hash"], (int)jsonAction["size"], serverhash); } + // If the hashes don't match, event the tool update with URL + if (selfExecutableHashHex != hash) { onToolUpdate((string)url, (string)jsonAction["hash"], (int)jsonAction["size"], serverhash); } + } + break; } - break; - } - default: - { - break; - } + default: + { + break; + } + } + } catch (Exception ex) + { + if (debug) { try { File.AppendAllText("debug.log", ex.ToString() + "\r\n"); } catch (Exception) { } } } } diff --git a/MeshDiscovery.cs b/MeshDiscovery.cs index 08077a0..1389a49 100644 --- a/MeshDiscovery.cs +++ b/MeshDiscovery.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MeshMapper.cs b/MeshMapper.cs index 398cf9f..25f7640 100644 --- a/MeshMapper.cs +++ b/MeshMapper.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/NodeClass.cs b/NodeClass.cs index 3d25663..98579ed 100644 --- a/NodeClass.cs +++ b/NodeClass.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Program.cs b/Program.cs index 7c961d1..4f59844 100644 --- a/Program.cs +++ b/Program.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/ServerUserControl.cs b/ServerUserControl.cs index e1b42bb..fe9c918 100644 --- a/ServerUserControl.cs +++ b/ServerUserControl.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Settings.cs b/Settings.cs index 7b4e9f0..fae005a 100644 --- a/Settings.cs +++ b/Settings.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/SettingsForm.cs b/SettingsForm.cs index 49e6143..f010b53 100644 --- a/SettingsForm.cs +++ b/SettingsForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/SshUsernameForm.cs b/SshUsernameForm.cs index 8c3ab42..f505270 100644 --- a/SshUsernameForm.cs +++ b/SshUsernameForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Translate.cs b/Translate.cs index b95c37b..3a20c82 100644 --- a/Translate.cs +++ b/Translate.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,126 +22,1332 @@ namespace MeshCentralRouter { public class Translate { + // Do not edit the translations below, instead change the master "translate.json" file of MeshCentral. + // This file is auto-generated from the "translate.json" file. + // *** TRANSLATION TABLE START *** static private Dictionary> translationTable = new Dictionary>() { { - "Failed to start remote terminal session", + "Site", new Dictionary() { - {"nl","Kan externe terminalsessie niet starten"}, - {"ko","원격 터미널 세션을 시작하지 못했습니다."}, - {"fr","Échec du démarrage de la session de terminal distant"}, - {"it","Impossibile avviare la sessione del terminale remoto"}, - {"zh-chs","无法启动远程终端会话"}, - {"pt-br","Falha ao iniciar sessão de terminal remoto"}, - {"sv","Det gick inte att starta fjärrterminsessionen"}, - {"es","No se pudo iniciar la sesión de terminal remota"}, - {"hi","दूरस्थ टर्मिनल सत्र प्रारंभ करने में विफल"}, - {"de","Fehler beim Starten der Remote-Terminal-Sitzung"} + {"de","Seite? ˅"}, + {"hi","साइट"}, + {"fr","Placer"}, + {"zh-chs","地点"}, + {"fi","Sivusto"}, + {"tr","Alan"}, + {"cs","Stránky"}, + {"ja","サイト"}, + {"es","Sitio"}, + {"pl","Strona"}, + {"pt","Local"}, + {"nl","Lokatie"}, + {"pt-br","Local"}, + {"sv","Webbplats"}, + {"da","Websted"}, + {"ko","대지"}, + {"it","Sito"}, + {"ru","Сайт"} } }, { - "{0} Byte", + ", Recorded Session", new Dictionary() { - {"ko","{0} 바이트"}, - {"fr","{0} octet"}, - {"zh-chs","{0} 字节"}, - {"hi","{0} बाइट"} + {"de",", Aufgezeichnete Sitzung"}, + {"hi",", रिकॉर्ड किया गया सत्र"}, + {"fr",", Séance enregistrée"}, + {"zh-chs",", 录制会话"}, + {"fi",", Tallennettu istunto"}, + {"tr",", Kaydedilmiş Oturum"}, + {"cs",", Nahraná relace"}, + {"ja","、記録されたセッション"}, + {"es",", Sesión grabada"}, + {"pl",", Nagrana Sesja"}, + {"pt",", Sessão Gravada"}, + {"nl",", opgenomen sessie"}, + {"pt-br",", Sessão Gravada"}, + {"sv",", Inspelad session"}, + {"da",", Optaget session"}, + {"ko",", 녹화 된 세션"}, + {"it",", Sessione registrata"}, + {"ru",", Записанный сеанс"} } }, { - "Certificate", + "All Displays", new Dictionary() { - {"nl","Certificaat"}, - {"ko","증명서"}, - {"fr","Certificat"}, - {"it","Certificato"}, - {"zh-chs","证书"}, - {"pt-br","Certificado"}, - {"sv","Certifikat"}, - {"es","Certificado"}, - {"hi","प्रमाणपत्र"}, - {"de","Zertifikat"} + {"de","Alle Bildschirme"}, + {"hi","सभी प्रदर्शित करता है"}, + {"fr","Tous affichages"}, + {"zh-cht","所有顯示"}, + {"zh-chs","所有显示"}, + {"fi","Kaikki näytöt"}, + {"tr","Tüm Ekranlar"}, + {"cs","Všechny displeje"}, + {"ja","すべてのディスプレイ"}, + {"es","Todas las Pantallas"}, + {"pl","Wszystkie Ekrany"}, + {"pt","Todas as telas"}, + {"nl","Alle schermen"}, + {"pt-br","Todos os monitores"}, + {"sv","Alla skärmar"}, + {"da","Alle skærme"}, + {"ko","모든 디스플레이"}, + {"it","Tutti i display"}, + {"ru","Все экраны"} } }, { - "Stats...", + "MeshCentral", new Dictionary() { - {"nl","Statistieken..."}, - {"ko","통계 ..."}, - {"fr","Statistiques..."}, - {"it","Statistiche..."}, - {"zh-chs","统计..."}, - {"pt-br","Estatísticas..."}, - {"sv","Statistik ..."}, - {"es","Estadísticas ..."}, - {"hi","आँकड़े..."}, - {"de","Statistiken..."} + {"hi","मेशसेंट्रल"}, + {"zh-chs","网格中心"} } }, { - "R&efresh", + "Incoming Bytes", new Dictionary() { - {"nl","Vernieuwen"}, - {"ko","새롭게 하다"}, - {"fr","Rafraîchir"}, - {"zh-chs","刷新"}, - {"pt-br","R & efresh"}, - {"sv","R & efresh"}, - {"es","Actualizar"}, - {"hi","ताज़ा करें"}, - {"de","Aktualisierung"} + {"de","Eingehende Bytes"}, + {"hi","आने वाली बाइट्स"}, + {"fr","Octets entrants"}, + {"zh-chs","传入字节"}, + {"fi","Saapuvat tavut"}, + {"tr","Gelen Bayt"}, + {"cs","Příchozí bajty"}, + {"ja","着信バイト"}, + {"es","Bytes entrantes"}, + {"pl","Bajty Przychodzące"}, + {"pt","Bytes de entrada"}, + {"nl","Inkomende Bytes"}, + {"pt-br","Bytes de entrada"}, + {"sv","Inkommande byte"}, + {"da","Indkommende byte"}, + {"ko","들어오는 바이트"}, + {"it","Byte in entrata"}, + {"ru","Входящие байты"} + } + }, + { + "Invalid download.", + new Dictionary() { + {"de","Ungültiger Download."}, + {"hi","अमान्य डाउनलोड।"}, + {"fr","Téléchargement non valide."}, + {"zh-chs","下载无效。"}, + {"fi","Virheellinen lataus."}, + {"tr","Geçersiz indirme."}, + {"cs","Neplatné stahování."}, + {"ja","ダウンロードが無効です。"}, + {"es","Descarga no válida."}, + {"pl","Nieprawidłowe pobieranie."}, + {"pt","Download inválido."}, + {"nl","Ongeldige download."}, + {"pt-br","Download inválido."}, + {"sv","Ogiltig nedladdning."}, + {"da","Ugyldig download."}, + {"ko","다운로드가 잘못되었습니다."}, + {"it","Download non valido."}, + {"ru","Неверная загрузка."} + } + }, + { + "Relay", + new Dictionary() { + {"de","Weiterleitung"}, + {"hi","रिले"}, + {"fr","Relais"}, + {"zh-cht","中繼"}, + {"zh-chs","中继"}, + {"fi","Rele"}, + {"tr","Yayın"}, + {"cs","Předávání (relay)"}, + {"ja","リレー"}, + {"es","Relé"}, + {"pl","Przekierowanie"}, + {"pt","Retransmissão"}, + {"pt-br","Retransmissão"}, + {"sv","Relä"}, + {"ko","전달(Relay)"}, + {"it","Ritrasmissioni"}, + {"ru","Ретранслятор"} + } + }, + { + "Port {0} to {1}:{2}", + new Dictionary() { + {"de","Port {0} nach {1}:{2}"}, + {"hi","पोर्ट {0} से {1}:{2}"}, + {"fr","Port {0} vers {1} :{2}"}, + {"zh-chs","端口 {0} 到 {1}:{2}"}, + {"fi","Portti {0} kohteeseen {1}: {2}"}, + {"tr","{0} bağlantı noktası {1}:{2}"}, + {"cs","Port {0} do {1}: {2}"}, + {"ja","ポート{0}から{1}:{2}"}, + {"es","Puerto {0} a {1}: {2}"}, + {"pl","Port {0} do {1}:{2}"}, + {"pt","Porta {0} para {1}: {2}"}, + {"nl","Poort {0} naar {1}:{2}"}, + {"pt-br","Porta {0} para {1}: {2}"}, + {"sv","Port {0} till {1}: {2}"}, + {"da","Port {0} til {1}:{2}"}, + {"ko","{0}에서 {1}로 포트 : {2}"}, + {"it","Porta {0} a {1}:{2}"}, + {"ru","Порт {0} в {1}: {2}"} + } + }, + { + "Remote - {0}", + new Dictionary() { + {"de","Fernbedienung - {0}"}, + {"hi","रिमोट - {0}"}, + {"fr","À distance - {0}"}, + {"zh-chs","远程 - {0}"}, + {"fi","Kaukosäädin - {0}"}, + {"tr","Uzak - {0}"}, + {"cs","Dálkové ovládání - {0}"}, + {"ja","リモート-{0}"}, + {"es","Remoto: {0}"}, + {"pl","Zdalny - {0}"}, + {"pt","Remoto - {0}"}, + {"nl","Afstandsbediening - {0}"}, + {"pt-br","Remoto - {0}"}, + {"sv","Fjärrkontroll - {0}"}, + {"ko","원격-{0}"}, + {"it","Remoto - {0}"}, + {"ru","Удаленный - {0}"} + } + }, + { + "Very slow", + new Dictionary() { + {"de","Sehr langsam"}, + {"hi","बहुत धीमी गति से"}, + {"fr","Très lent"}, + {"zh-cht","非常慢"}, + {"zh-chs","非常慢"}, + {"fi","Hyvin hidas"}, + {"tr","Çok yavaş"}, + {"cs","Velmi pomalu"}, + {"ja","非常に遅い"}, + {"es","Muy lento"}, + {"pl","Bardzo powoli"}, + {"pt","Muito devagar"}, + {"nl","Erg traag"}, + {"pt-br","Muito lento"}, + {"sv","Väldigt långsam"}, + {"da","Meget langsom"}, + {"ko","아주 느린"}, + {"it","Molto lento"}, + {"ru","Очень медленно"} + } + }, + { + "OpenSSH", + new Dictionary() { + {"hi","अधिभारित"}, + {"zh-chs","开放式SSH"} + } + }, + { + "Confirm Delete", + new Dictionary() { + {"de","Löschen bestätigen"}, + {"hi","हटाने की पुष्टि करें"}, + {"fr","Confirmation de la suppression"}, + {"zh-chs","确认删除"}, + {"fi","Vahvista poistaminen"}, + {"tr","Silmeyi Onayla"}, + {"cs","Potvrďte smazání"}, + {"ja","削除の確認"}, + {"es","Confirmar Eliminación"}, + {"pl","Potwierdzić Usunięcie"}, + {"pt","Confirmar exclusão"}, + {"nl","Verwijderen bevestigen"}, + {"pt-br","Confirmar exclusão"}, + {"sv","Bekräfta radering"}, + {"da","Bekræft sletning"}, + {"ko","삭제 확인"}, + {"it","Conferma cancellazione"}, + {"ru","Подтвердите удаление"} + } + }, + { + "Estimating...", + new Dictionary() { + {"de","Schätzung..."}, + {"hi","अनुमान लगाया जा रहा है..."}, + {"fr","Estimation ..."}, + {"zh-chs","估计..."}, + {"fi","Arvioidaan ..."}, + {"tr","tahmin ediliyor..."}, + {"cs","Odhadování ..."}, + {"ja","見積もり..."}, + {"es","Estimando ..."}, + {"pl","Doceniający..."}, + {"pt","Estimando ..."}, + {"nl","geschat..."}, + {"pt-br","Estimando..."}, + {"sv","Uppskattar ..."}, + {"da","Estimerer..."}, + {"ko","추정 중..."}, + {"it","Stima..."}, + {"ru","Оценка ..."} + } + }, + { + "Remote IP", + new Dictionary() { + {"de","Remote-IP"}, + {"hi","दूरदराज़ के आई. पी"}, + {"fr","IP distante"}, + {"zh-chs","远程IP"}, + {"fi","Etä -IP"}, + {"tr","uzak IP"}, + {"cs","Vzdálená IP"}, + {"ja","リモートIP"}, + {"es","IP Remota"}, + {"pl","Zdalny IP"}, + {"pt","IP Remoto"}, + {"nl","Extern IP"}, + {"pt-br","IP Remoto"}, + {"sv","Fjärr-IP"}, + {"da","Fjern-IP"}, + {"ko","원격 IP"}, + {"it","IP remoto"}, + {"ru","Удаленный IP"} + } + }, + { + "Open Web Site", + new Dictionary() { + {"de","Website öffnen"}, + {"hi","वेब साइट खोलें"}, + {"fr","Ouvrir le site Web"}, + {"zh-chs","打开网站"}, + {"fi","Avaa verkkosivusto"}, + {"tr","Web Sitesini Aç"}, + {"cs","Otevřete web"}, + {"ja","Webサイトを開く"}, + {"es","Abrir Sitio Web"}, + {"pl","Otwórz Stronę"}, + {"pt","Abra o site"}, + {"nl","Website openen"}, + {"pt-br","Abra o site"}, + {"sv","Öppna webbplatsen"}, + {"da","Åbn webstedet"}, + {"ko","웹 사이트 열기"}, + {"it","Apri sito web"}, + {"ru","Открыть веб-сайт"} + } + }, + { + "ComputerName", + new Dictionary() { + {"de","Computername"}, + {"hi","कंप्यूटर का नाम"}, + {"fr","Nom de l'ordinateur"}, + {"zh-chs","计算机名"}, + {"fi","Tietokoneen nimi"}, + {"tr","Bilgisayar adı"}, + {"cs","Název počítače"}, + {"ja","コンピュータネーム"}, + {"es","Nombre de la Computadora"}, + {"pl","Nazwa komputera"}, + {"pt","Nome do computador"}, + {"nl","Computernaam"}, + {"pt-br","Nome do computador"}, + {"sv","Datornamn"}, + {"da","Computernavn"}, + {"it","Nome del computer"}, + {"ru","Имя компьютера"} + } + }, + { + "Create Folder", + new Dictionary() { + {"de","Ordner erstellen"}, + {"hi","फोल्डर बनाएं"}, + {"fr","Créer le dossier"}, + {"zh-chs","创建文件夹"}, + {"fi","Luo kansio"}, + {"tr","Klasör oluşturun"}, + {"cs","Vytvořit složku"}, + {"ja","フォルダーを作る"}, + {"es","Crear Carpeta"}, + {"pl","Utwórz Folder"}, + {"pt","Criar pasta"}, + {"nl","Map aanmaken"}, + {"pt-br","Criar pasta"}, + {"sv","Skapa mapp"}, + {"da","Opret mappe"}, + {"ko","폴더 생성"}, + {"it","Creare una cartella"}, + {"ru","Создать папку"} + } + }, + { + "Cancel Auto-Close", + new Dictionary() { + {"de","Automatisches Schließen abbrechen"}, + {"hi","रद्द करें स्वतः बंद"}, + {"fr","Annuler la fermeture automatique"}, + {"zh-chs","取消自动关闭"}, + {"fi","Peruuta automaattinen sulkeminen"}, + {"tr","Otomatik Kapatmayı İptal Et"}, + {"cs","Zrušit automatické zavírání"}, + {"ja","自動クローズをキャンセルする"}, + {"es","Cancelar Cierre Automático"}, + {"pl","Anuluj Auto-Zamknięcie"}, + {"pt","Cancelar fechamento automático"}, + {"nl","Automatisch sluiten annuleren"}, + {"pt-br","Cancelar fechamento automático"}, + {"sv","Avbryt automatisk stängning"}, + {"da","Annuller auto-luk"}, + {"ko","자동 닫기 취소"}, + {"it","Annulla chiusura automatica"}, + {"ru","Отменить автоматическое закрытие"} + } + }, + { + ", 1 connection.", + new Dictionary() { + {"de",", 1 Verbindung."}, + {"hi",", 1 कनेक्शन।"}, + {"fr",", 1 connexion."}, + {"zh-chs",", 1 个连接。"}, + {"fi",", 1 liitäntä."}, + {"tr",", 1 bağlantı."}, + {"cs",", 1 připojení."}, + {"ja","、1接続。"}, + {"es",", 1 conexión."}, + {"pl",", 1 połączenie."}, + {"pt",", 1 conexão."}, + {"nl",", 1 verbinding."}, + {"pt-br",", 1 conexão."}, + {"sv",", 1 anslutning."}, + {"da",", 1 forbindelse."}, + {"ko",", 1 촌."}, + {"it",", 1 connessione."}, + {"ru",", 1 соединение."} + } + }, + { + "Connecting...", + new Dictionary() { + {"de","Verbinden..."}, + {"hi","कनेक्ट ..."}, + {"fr","En cours de connexion ..."}, + {"zh-cht","正在連線..."}, + {"zh-chs","正在连线..."}, + {"fi","Yhdistetään..."}, + {"tr","Bağlanıyor..."}, + {"cs","Připojování…"}, + {"ja","接続しています..."}, + {"es","Conectando...."}, + {"pl","Łączenie..."}, + {"pt","Conectando..."}, + {"nl","Verbinden..."}, + {"pt-br","Conectando ..."}, + {"sv","Ansluter..."}, + {"da","Forbinder..."}, + {"ko","연결 중 ..."}, + {"it","Collegamento ..."}, + {"ru","Подключение..."} + } + }, + { + "&Open Mappings...", + new Dictionary() { + {"de","&Zuordnungen öffnen..."}, + {"hi","&ओपन मैपिंग..."}, + {"fr","&Ouvrir les mappages..."}, + {"zh-chs","打开映射 (&O)..."}, + {"fi","& Avaa kartoitukset ..."}, + {"tr","&Eşlemeleri Aç..."}, + {"cs","& Otevřít mapování ..."}, + {"ja","&Open Mapping .. .."}, + {"es","&Abrir mapeos ..."}, + {"pl","&Otwórz Mapowania..."}, + {"pt","& Abrir mapeamentos ..."}, + {"nl","&toewijzingen openen..."}, + {"pt-br","&Abrir mapeamentos ..."}, + {"sv","& Öppna kartläggningar ..."}, + {"ko","매핑 열기 ..."}, + {"it","&Apri mappature..."}, + {"ru","&Открыть, сопоставить..."} + } + }, + { + "TCP", + new Dictionary() { + {"hi","टीसीपी"} + } + }, + { + "Remote Desktop Data", + new Dictionary() { + {"de","Remotedesktopdaten"}, + {"hi","दूरस्थ डेस्कटॉप डेटा"}, + {"fr","Données de bureau à distance"}, + {"zh-chs","远程桌面数据"}, + {"fi","Etätyöpöydän tiedot"}, + {"tr","Uzak Masaüstü Verileri"}, + {"cs","Data vzdálené plochy"}, + {"ja","リモートデスクトップデータ"}, + {"es","Datos de Escritorio Remoto"}, + {"pl","Dane Pulpitu Zdalnego"}, + {"pt","Dados da área de trabalho remota"}, + {"nl","Extern bureaublad gegevens"}, + {"pt-br","Dados da área de trabalho remota"}, + {"sv","Fjärrskrivbordsdata"}, + {"da","Fjernskrivebordsdata"}, + {"ko","원격 데스크톱 데이터"}, + {"it","Dati desktop remoto"}, + {"ru","Данные удаленного рабочего стола"} + } + }, + { + "Add Relay Map...", + new Dictionary() { + {"de","Relaiskarte hinzufügen..."}, + {"hi","रिले मैप जोड़ें..."}, + {"fr","Ajouter une carte de relais..."}, + {"zh-chs","添加中继地图..."}, + {"fi","Lisää välityskartta ..."}, + {"tr","Geçiş Haritası Ekle..."}, + {"cs","Přidat mapu relé ..."}, + {"ja","リレーマップを追加..."}, + {"es","Agregar mapa de retransmisiones ..."}, + {"pl","Dodaj Mapę Przekierowania..."}, + {"pt","Adicionar mapa de retransmissão ..."}, + {"nl","Toevoegen relay kaart..."}, + {"pt-br","Adicionar mapa de retransmissão ..."}, + {"sv","Lägg till reläkarta ..."}, + {"da","Tilføj Relay kort"}, + {"ko","릴레이 맵 추가 ..."}, + {"it","Aggiungi mappa di rilancio..."}, + {"ru","Добавить карту реле ..."} + } + }, + { + "Send token to registered email address?", + new Dictionary() { + {"de","Token an registrierte E-Mail-Adresse senden?"}, + {"hi","प्राप्त ईमेल पते पर टोकन भेजें?"}, + {"fr","Envoyer un jeton à une adresse e-mail enregistrée?"}, + {"zh-cht","將保安編碼發送到註冊的電郵地址?"}, + {"zh-chs","将保安编码发送到注册的电邮地址?"}, + {"fi","Lähetetäänkö tunnus rekisteröityyn sähköpostiosoitteeseen?"}, + {"tr","Belirteç kayıtlı e-posta adresine gönderilsin mi?"}, + {"cs","Odeslat token na zaregistrovanou e-mailovou adresu?"}, + {"ja","登録済みのメールアドレスにトークンを送信しますか?"}, + {"es","¿Enviar token a la dirección de correo electrónico registrada?"}, + {"pl","Wysłać token na zarejestrowany adres email?"}, + {"pt","Enviar token para o endereço de e-mail registrado?"}, + {"nl","Token verzenden naar geregistreerd e-mailadres?"}, + {"pt-br","Enviar token para o endereço de e-mail registrado?"}, + {"sv","Skicka token till registrerad e-postadress?"}, + {"da","Send token til registreret e-mailadresse?"}, + {"ko","등록된 이메일 주소로 토큰을 보내시겠습니까?"}, + {"it","Invia token all'indirizzo email registrato?"}, + {"ru","Отправить токен на зарегистрированный адрес электронной почты?"} + } + }, + { + "HTTP", + new Dictionary() { + {"hi","एचटीटीपी"} + } + }, + { + "Denied", + new Dictionary() { + {"de","Verweigert"}, + {"hi","निषेध"}, + {"fr","Refusée"}, + {"zh-cht","被拒絕"}, + {"zh-chs","被拒绝"}, + {"fi","Evätty"}, + {"tr","Reddedildi"}, + {"cs","Odepřeno"}, + {"ja","拒否されました"}, + {"es","Denegado"}, + {"pl","Zabronione"}, + {"pt","Negado"}, + {"nl","Geweigerd"}, + {"pt-br","Negado"}, + {"sv","Förnekad"}, + {"da","Afslået"}, + {"ko","거부"}, + {"it","Negato"}, + {"ru","Отказано"} + } + }, + { + "Slow", + new Dictionary() { + {"de","Langsam"}, + {"hi","धीरे"}, + {"fr","Lent"}, + {"zh-cht","慢"}, + {"zh-chs","慢"}, + {"fi","Hidas"}, + {"tr","Yavaş"}, + {"cs","Pomalu"}, + {"ja","スロー"}, + {"es","Lento"}, + {"pl","Powoli"}, + {"pt","Lento"}, + {"nl","Traag"}, + {"pt-br","Lento"}, + {"sv","Långsam"}, + {"da","Langsom"}, + {"ko","느린"}, + {"it","Lento"}, + {"ru","Медленно"} + } + }, + { + "Privacy Bar", + new Dictionary() { + {"de","Datenschutzleiste"}, + {"hi","गोपनीयता बार"}, + {"fr","Barre de confidentialité"}, + {"zh-cht","隱私欄"}, + {"zh-chs","隐私栏"}, + {"fi","Tietosuojapalkki"}, + {"tr","Gizlilik Çubuğu"}, + {"cs","Bar ochrany osobních údajů"}, + {"ja","プライバシーバー"}, + {"es","Barra de Privacidad"}, + {"pl","Pasek Prywatności"}, + {"pt","Barra de Privacidade"}, + {"nl","Privacy balk"}, + {"pt-br","Barra de Privacidade"}, + {"sv","Sekretessfält"}, + {"ko","프라이버시 바"}, + {"it","Privacy bar"}, + {"ru","Панель конфиденциальности"} + } + }, + { + "Display {0}", + new Dictionary() { + {"de","Anzeige {0}"}, + {"hi","प्रदर्शन {0}"}, + {"fr","Affichage {0}"}, + {"zh-chs","显示{0}"}, + {"fi","Näyttö {0}"}, + {"tr","{0} göster"}, + {"cs","Zobrazit {0}"}, + {"ja","{0}を表示"}, + {"es","Mostrar {0}"}, + {"pl","Ekran {0}"}, + {"pt","Exibir {0}"}, + {"nl","Scherm {0}"}, + {"pt-br","Exibir {0}"}, + {"sv","Visa {0}"}, + {"da","Vis {0}"}, + {"ko","{0} 디스플레이"}, + {"ru","Экран {0}"} + } + }, + { + "Add &Map...", + new Dictionary() { + {"de","&Zuordnen hinzufügen..."}, + {"hi","नक्शा जोड़ें..."}, + {"fr","Ajouter une &carte..."}, + {"zh-chs","添加地图 (&M)..."}, + {"fi","Lisää & kartta ..."}, + {"tr","&Harita ekle..."}, + {"cs","Přidat a mapovat ..."}, + {"ja","&Mapを追加..."}, + {"es","Agregar & mapa ..."}, + {"pl","Dodaj &Mapę..."}, + {"pt","Adicionar & mapear ..."}, + {"nl","&Toewijzing toevoegen..."}, + {"pt-br","Adicionar & mapear ..."}, + {"sv","Lägg till & mappa ..."}, + {"da","Tilføj &Map..."}, + {"ko","지도 추가 ..."}, + {"it","Aggiungi &mappa..."}, + {"ru","Добавить & карту ..."} + } + }, + { + "Error downloading file: {0}", + new Dictionary() { + {"de","Fehler beim Herunterladen der Datei: {0}"}, + {"hi","फ़ाइल डाउनलोड करने में त्रुटि: {0}"}, + {"fr","Erreur lors du téléchargement du fichier : {0}"}, + {"zh-chs","下载文件时出错:{0}"}, + {"fi","Virhe tiedoston lataamisessa: {0}"}, + {"tr","Dosya indirilirken hata oluştu: {0}"}, + {"cs","Chyba při stahování souboru: {0}"}, + {"ja","ファイルのダウンロード中にエラーが発生しました:{0}"}, + {"es","Error al descargar el archivo: {0}"}, + {"pl","Błąd podczas pobierania pliku: {0}"}, + {"pt","Erro ao fazer download do arquivo: {0}"}, + {"nl","Fout bij downloaden van bestand: {0}"}, + {"pt-br","Erro ao baixar arquivo: {0}"}, + {"sv","Fel vid nedladdning av fil: {0}"}, + {"da","Fejl ved download af fil: {0}"}, + {"ko","파일 다운로드 중 오류: {0}"}, + {"it","Errore durante il download del file: {0}"}, + {"ru","Ошибка при загрузке файла: {0}"} + } + }, + { + "OK", + new Dictionary() { + {"hi","ठीक"}, + {"fr","ОК"}, + {"tr","Tamam"}, + {"pt","Ok"}, + {"ko","확인"}, + {"ru","ОК"} + } + }, + { + "Port Mapping Help", + new Dictionary() { + {"de","Hilfe zur Portzuordnung"}, + {"hi","पोर्ट मैपिंग सहायता"}, + {"fr","Aide sur le mappage de ports"}, + {"zh-chs","端口映射帮助"}, + {"fi","Portin kartoitusohje"}, + {"tr","Bağlantı Noktası Eşleme Yardımı"}, + {"cs","Nápověda k mapování portů"}, + {"ja","ポートマッピングヘルプ"}, + {"es","Ayuda de Mapeo de Puertos"}, + {"pl","Pomoc Mapowania Portu"}, + {"pt","Ajuda para mapeamento de portas"}, + {"nl","Hulp bij poorttoewijzing"}, + {"pt-br","Ajuda para mapeamento de portas"}, + {"sv","Portmappning Hjälp"}, + {"da","Port Mapping hjælp"}, + {"ko","포트 매핑 도움말"}, + {"it","Aiuto per la mappatura delle porte"}, + {"ru","Справка по отображению портов"} + } + }, + { + "Show &Offline Devices", + new Dictionary() { + {"de","&Offline-Geräte anzeigen"}, + {"hi","दिखाएँ &ऑफ़लाइन उपकरण"}, + {"fr","Afficher les appareils &hors ligne"}, + {"zh-chs","显示离线设备 (&A)"}, + {"fi","Näytä ja offline -laitteet"}, + {"tr","&Çevrimdışı Cihazları Göster"}, + {"cs","Zobrazit a offline zařízení"}, + {"ja","デバイスの表示とオフライン"}, + {"es","Mostrar y dispositivos sin conexión"}, + {"pl","Pokaż Urządzenia &Offline"}, + {"pt","Mostrar dispositivos off-line"}, + {"nl","Toon &Offline apparaten"}, + {"pt-br","Mostrar dispositivos off-line"}, + {"sv","Visa & Offline-enheter"}, + {"da","Vis &Offline enheder"}, + {"ko","오프라인 장치 표시 (& O)"}, + {"it","Mostra dispositivi offline"}, + {"ru","Показать и автономные устройства"} + } + }, + { + "MeshCentral Router Update", + new Dictionary() { + {"de","MeshCentral Router-Update"}, + {"hi","मेशसेंट्रल राउटर अपडेट"}, + {"fr","Mise à jour du routeur MeshCentral"}, + {"zh-chs","MeshCentral 路由器更新"}, + {"fi","MeshCentral -reitittimen päivitys"}, + {"tr","MeshCentral Yönlendirici Güncellemesi"}, + {"cs","Aktualizace routeru MeshCentral"}, + {"ja","MeshCentralルーターの更新"}, + {"es","Actualización del enrutador MeshCentral"}, + {"pl","Aktualizacja MeshCentral Router"}, + {"pt","Atualização do roteador MeshCentral"}, + {"pt-br","Atualização do MeshCentral Router"}, + {"sv","MeshCentral routeruppdatering"}, + {"da","MeshCentral routeropdatering"}, + {"ko","MeshCentral 라우터 업데이트"}, + {"it","Aggiornamento del router MeshCentral"}, + {"ru","Обновление MeshCentral Router"} + } + }, + { + "Size", + new Dictionary() { + {"de","Größe"}, + {"hi","आकार"}, + {"fr","Taille"}, + {"zh-cht","尺寸"}, + {"zh-chs","尺寸"}, + {"fi","Koko"}, + {"tr","Boyut"}, + {"cs","Velikost"}, + {"ja","サイズ"}, + {"es","Tamaño"}, + {"pl","Rozmiar"}, + {"pt","Tamanho"}, + {"nl","Grootte"}, + {"pt-br","Tamanho"}, + {"sv","Storlek"}, + {"da","Størrelse"}, + {"ko","크기"}, + {"it","Dimensione"}, + {"ru","Размер"} + } + }, + { + "CIRA", + new Dictionary() { + {"hi","सीआईआरए"} + } + }, + { + "Use Alternate Port...", + new Dictionary() { + {"de","Alternativer Port verwenden..."}, + {"hi","वैकल्पिक पोर्ट का उपयोग करें..."}, + {"fr","Utiliser un autre port..."}, + {"zh-chs","使用备用端口..."}, + {"fi","Käytä vaihtoehtoista porttia ..."}, + {"tr","Alternatif Bağlantı Noktasını Kullan..."}, + {"cs","Použít alternativní port ..."}, + {"ja","代替ポートを使用..."}, + {"es","Usar Puerto Alternativo ..."}, + {"pl","Użyj Alternatywnego Portu..."}, + {"pt","Usar porta alternativa ..."}, + {"nl","Alternatieve poort gebruiken..."}, + {"pt-br","Usar porta alternativa ..."}, + {"sv","Använd alternativ port ..."}, + {"da","Brug alternativ port..."}, + {"ko","대체 포트 사용 ..."}, + {"it","Usa porta alternativa..."}, + {"ru","Использовать альтернативный порт ..."} + } + }, + { + "Unable to open file: {0}", + new Dictionary() { + {"de","Datei kann nicht geöffnet werden: {0}"}, + {"hi","फ़ाइल खोलने में असमर्थ: {0}"}, + {"fr","Impossible d'ouvrir le fichier : {0}"}, + {"zh-chs","无法打开文件:{0}"}, + {"fi","Tiedostoa ei voi avata: {0}"}, + {"tr","Dosya açılamıyor: {0}"}, + {"cs","Soubor nelze otevřít: {0}"}, + {"ja","ファイルを開くことができません:{0}"}, + {"es","No se puede abrir el archivo: {0}"}, + {"pl","Nie można otworzyć pliku: {0}"}, + {"pt","Não foi possível abrir o arquivo: {0}"}, + {"nl","Kan bestand: {0} niet openen"}, + {"pt-br","No se puede abrir el archivo: {0}"}, + {"sv","Det gick inte att öppna filen: {0}"}, + {"da","Kan ikke åbne filen: {0}"}, + {"ko","파일을 열 수 없음: {0}"}, + {"it","Impossibile aprire il file: {0}"}, + {"ru","Невозможно открыть файл: {0}"} + } + }, + { + "Connect", + new Dictionary() { + {"de","Verbinden"}, + {"hi","जुडिये"}, + {"fr","Se connecter"}, + {"zh-cht","連接"}, + {"zh-chs","连接"}, + {"fi","Yhdistä"}, + {"tr","Bağlan"}, + {"cs","Připojit"}, + {"ja","つなぐ"}, + {"es","Conectar"}, + {"pl","Połącz"}, + {"pt","Conectar"}, + {"nl","Verbinden"}, + {"pt-br","Conectar"}, + {"sv","Anslut"}, + {"da","Forbind"}, + {"ko","연결"}, + {"it","Connetti"}, + {"ru","Подключиться"} + } + }, + { + "MeshCentral Router Installation", + new Dictionary() { + {"de","Installation des MeshCentral-Routers"}, + {"hi","मेशसेंट्रल राउटर इंस्टालेशन"}, + {"fr","Installation du routeur MeshCentral"}, + {"zh-chs","MeshCentral 路由器安装"}, + {"fi","MeshCentral -reitittimen asennus"}, + {"tr","MeshCentral Yönlendirici Kurulumu"}, + {"cs","Instalace routeru MeshCentral"}, + {"ja","MeshCentralルーターのインストール"}, + {"es","Instalación del enrutador MeshCentral"}, + {"pl","Instalacja MeshCentral Router"}, + {"pt","Instalação do roteador MeshCentral"}, + {"nl","MeshCentral Router Installatie"}, + {"pt-br","Instalação do MeshCentral Router"}, + {"ko","MeshCentral 라우터 설치"}, + {"it","Installazione del router MeshCentral"}, + {"ru","Установка MeshCentral Router"} + } + }, + { + "Double Click Action", + new Dictionary() { + {"de","Doppelklick-Aktion"}, + {"hi","डबल क्लिक एक्शन"}, + {"fr","Action de double-clic"}, + {"zh-chs","双击操作"}, + {"fi","Kaksoisnapsauta toimintoa"}, + {"tr","Çift Tıklama İşlemi"}, + {"cs","Akce dvojitým kliknutím"}, + {"ja","ダブルクリックアクション"}, + {"es","Acción de doble clic"}, + {"pl","Akcja Podwójnego Kliknięcia"}, + {"pt","Ação de duplo clique"}, + {"nl","Dubbelklik actie"}, + {"pt-br","Ação de duplo clique"}, + {"sv","Dubbelklicka på åtgärd"}, + {"da","Dobbeltklik på handling"}, + {"ko","더블 클릭 동작"}, + {"it","Azione doppio clic"}, + {"ru","Действие двойного щелчка"} + } + }, + { + "(Individual Devices)", + new Dictionary() { + {"de","(Einzelgeräte)"}, + {"hi","(व्यक्तिगत उपकरण)"}, + {"fr","(Appareils individuels)"}, + {"zh-chs","(个别设备)"}, + {"fi","(Yksittäiset laitteet)"}, + {"tr","(Bireysel Cihazlar)"}, + {"cs","(Jednotlivá zařízení)"}, + {"ja","(個別のデバイス)"}, + {"es","(Dispositivos individuales)"}, + {"pl","(Poszczególne urządzenia)"}, + {"pt","(Dispositivos Individuais)"}, + {"nl","(Individuele apparaten)"}, + {"pt-br","(Dispositivos Individuais)"}, + {"sv","(Enskilda enheter)"}, + {"da","(Individuelle enheder)"}, + {"ko","(개별 기기)"}, + {"it","(Dispositivi individuali)"}, + {"ru","(Отдельные устройства)"} + } + }, + { + "Path", + new Dictionary() { + {"de","Pfad"}, + {"hi","पथ"}, + {"fr","Chemin"}, + {"zh-chs","小路"}, + {"fi","Polku"}, + {"tr","Yol"}, + {"cs","Cesta"}, + {"ja","道"}, + {"es","Camino"}, + {"pl","Ścieżka"}, + {"pt","Caminho"}, + {"nl","Pad"}, + {"pt-br","Caminho"}, + {"sv","Väg"}, + {"da","Sti"}, + {"ko","통로"}, + {"it","Percorso"}, + {"ru","Дорожка"} + } + }, + { + "Desktop Settings", + new Dictionary() { + {"de","Desktop-Einstellungen"}, + {"hi","डेस्कटॉप सेटिंग्स"}, + {"fr","Paramètres du bureau"}, + {"zh-chs","桌面设置"}, + {"fi","Työpöydän asetukset"}, + {"tr","Masaüstü Ayarları"}, + {"cs","Nastavení plochy"}, + {"ja","デスクトップ設定"}, + {"es","Configuración de escritorio"}, + {"pl","Ustawienia Pulpitu"}, + {"pt","Configurações da área de trabalho"}, + {"nl","Bureaubladinstellingen"}, + {"pt-br","Configurações da área de trabalho"}, + {"sv","Skrivbordsinställningar"}, + {"da","Skrivebordsindstillninger"}, + {"ko","데스크탑 설정"}, + {"it","Impostazioni del desktop"}, + {"ru","Настройки рабочего стола"} + } + }, + { + "Remote Desktop Settings", + new Dictionary() { + {"de","Einstellungen des entfernten Desktops"}, + {"hi","दूरस्थ डेस्कटॉप सेटिंग्स"}, + {"fr","Paramètres du bureau à distance"}, + {"zh-cht","遠程桌面設置"}, + {"zh-chs","远程桌面设置"}, + {"fi","Etätyöpöydän asetukset"}, + {"tr","Uzak Masaüstü Ayarları"}, + {"cs","Nastavení vzdálené plochy"}, + {"ja","リモートデスクトップ設定"}, + {"es","Opciones de Escritorio Remoto"}, + {"pl","Ustawienia Pulpitu Zdalnego"}, + {"pt","Configurações da área de trabalho remota"}, + {"nl","Instellingen extern bureaublad"}, + {"pt-br","Configurações de área de trabalho remota"}, + {"sv","Fjärrskrivbordsinställningar"}, + {"da","Indstillinger for fjernskrivebord"}, + {"ko","원격 데스크톱 설정"}, + {"it","Impostazioni desktop remoto"}, + {"ru","Настройки удаленного рабочего стола"} + } + }, + { + "Relay Device", + new Dictionary() { + {"de","Relaisgerät"}, + {"hi","रिले डिवाइस"}, + {"fr","Dispositif de relais"}, + {"zh-chs","中继装置"}, + {"fi","Relelaite"}, + {"tr","Röle Cihazı"}, + {"cs","Reléové zařízení"}, + {"ja","リレー装置"}, + {"es","Dispositivo de Retransmisión"}, + {"pl","Urządzenie Przekazujące"}, + {"pt","Dispositivo de Relé"}, + {"nl","Doorstuur apparaat"}, + {"pt-br","Dispositivo de Retransmissão"}, + {"sv","Reläenhet"}, + {"da","Relay enhed"}, + {"ko","릴레이 장치"}, + {"it","Dispositivo ripetitore"}, + {"ru","Релейное устройство"} + } + }, + { + "Setup...", + new Dictionary() { + {"de","Aufbau..."}, + {"hi","सेट अप..."}, + {"fr","Traitement..."}, + {"zh-cht","設定..."}, + {"zh-chs","设定..."}, + {"fi","Asennus..."}, + {"tr","Kurmak..."}, + {"cs","Nastavení…"}, + {"ja","セットアップ..."}, + {"es","Configurar..."}, + {"pl","Instalacja..."}, + {"pt","Configurando..."}, + {"pt-br","Configurando..."}, + {"sv","Uppstart..."}, + {"da","Opsætning..."}, + {"ko","설치..."}, + {"it","Impostare..."}, + {"ru","Установка..."} + } + }, + { + "Unable to bind to local port", + new Dictionary() { + {"de","Kann nicht an lokalen Port binden"}, + {"hi","स्थानीय पोर्ट से जुड़ने में असमर्थ"}, + {"fr","Impossible de se lier au port local"}, + {"zh-chs","无法绑定到本地端口"}, + {"fi","Ei voi yhdistää paikalliseen porttiin"}, + {"tr","Yerel bağlantı noktasına bağlanamıyor"}, + {"cs","Nelze se vázat na místní port"}, + {"ja","ローカルポートにバインドできません"}, + {"es","No se puede vincular al puerto local"}, + {"pl","Nie można przypisać do portu lokalnego"}, + {"pt","Incapaz de ligar à porta local"}, + {"nl","Kan niet binden aan lokale poort"}, + {"pt-br","Não foi possível conectar à porta local"}, + {"sv","Det gick inte att binda till lokal port"}, + {"da","Kan ikke binde til lokal port"}, + {"ko","로컬 포트에 바인딩 할 수 없습니다."}, + {"it","Impossibile eseguire il binding alla porta locale"}, + {"ru","Невозможно подключиться к локальному порту"} + } + }, + { + "Rename File", + new Dictionary() { + {"de","Datei umbenennen"}, + {"hi","फाइल का नाम बदलो"}, + {"fr","Renommer le fichier"}, + {"zh-chs","重新命名文件"}, + {"fi","Nimeä tiedosto uudelleen"}, + {"tr","Dosyayı yeniden adlandır"}, + {"cs","Přejmenuj soubor"}, + {"ja","ファイルの名前を変更"}, + {"es","Renombrar Archivo"}, + {"pl","Zmień Nazwę Pliku"}, + {"pt","Renomear arquivo"}, + {"nl","Bestand hernoemen"}, + {"pt-br","Renomear arquivo"}, + {"sv","Döp om fil"}, + {"da","Omdøb fil"}, + {"ko","파일명 변경"}, + {"it","Rinomina il file"}, + {"ru","Переименуйте файл"} + } + }, + { + "Push local clipboard to remote device", + new Dictionary() { + {"de","Lokale Zwischenablage auf Remote-Gerät übertragen"}, + {"hi","स्थानीय क्लिपबोर्ड को दूरस्थ डिवाइस पर पुश करें"}, + {"fr","Transférer le presse-papiers local vers l'appareil distant"}, + {"zh-chs","将本地剪贴板推送到远程设备"}, + {"fi","Työnnä paikallinen leikepöytä etälaitteeseen"}, + {"tr","Yerel panoyu uzak cihaza itin"}, + {"cs","Přesuňte místní schránku do vzdáleného zařízení"}, + {"ja","ローカルクリップボードをリモートデバイスにプッシュする"}, + {"es","Empuje el portapapeles local al dispositivo remoto"}, + {"pl","Prześlij lokalny schowek do urządzenia zdalnego"}, + {"pt","Envie a área de transferência local para o dispositivo remoto"}, + {"nl","Verplaats lokaal klembord naar extern apparaat"}, + {"pt-br","Envie a área de transferência local para o dispositivo remoto"}, + {"sv","Tryck lokalt urklipp till fjärrenheten"}, + {"da","Skub den lokale udklipsholder til fjernenheden"}, + {"ko","로컬 클립 보드를 원격 장치로 푸시"}, + {"it","Spingi gli appunti locali sul dispositivo remoto"}, + {"ru","Перенести локальный буфер обмена на удаленное устройство"} + } + }, + { + "Overwrite {0} files?", + new Dictionary() { + {"de","{0} Dateien überschreiben?"}, + {"hi","{0} फ़ाइलें अधिलेखित करें?"}, + {"fr","Écraser {0} fichiers ?"}, + {"zh-chs","覆盖 {0} 个文件?"}, + {"fi","Korvataanko {0} tiedostoa?"}, + {"tr","{0} dosyanın üzerine yazılsın mı?"}, + {"cs","Přepsat {0} souborů?"}, + {"ja","{0}ファイルを上書きしますか?"}, + {"es","¿Sobrescribir {0} archivos?"}, + {"pl","Zastąpić {0} plików?"}, + {"pt","Substituir {0} arquivos?"}, + {"nl","{0} bestanden overschrijven?"}, + {"pt-br","¿Sobrescribir {0} archivos?"}, + {"sv","Skriv över {0} filer?"}, + {"da","Overskriv {0} filer?"}, + {"ko","{0} 파일을 덮어쓰시겠습니까?"}, + {"it","Sovrascrivere {0} file?"}, + {"ru","Перезаписать {0} файлы?"} + } + }, + { + "Two-factor Authentication", + new Dictionary() { + {"de","Zwei-Faktor-Authentifizierung"}, + {"hi","दो तरीकों से प्रमाणीकरण"}, + {"fr","Authentification à deux facteurs"}, + {"zh-chs","两因素身份验证"}, + {"fi","Kaksivaiheinen todennus"}, + {"tr","İki Faktörlü Kimlik Doğrulama"}, + {"cs","Dvoufaktorové ověřování"}, + {"ja","二要素認証"}, + {"es","Autenticación de Dos Factores"}, + {"pl","Uwierzytelnianie Dwuskładnikowe"}, + {"pt","Autenticação de dois fatores"}, + {"nl","Twee-factor authenticatie"}, + {"pt-br","Autenticação de dois fatores"}, + {"sv","Tvåfaktorsautentisering"}, + {"da","2-faktor godkendelse"}, + {"ko","2 단계 인증"}, + {"it","Autenticazione a due fattori"}, + {"ru","Двухфакторная аутентификация"} + } + }, + { + "label1", + new Dictionary() { + {"de","Etikett1"}, + {"hi","लेबल1"}, + {"fr","étiquette1"}, + {"zh-chs","标签 1"}, + {"fi","etiketti 1"}, + {"tr","etiket1"}, + {"cs","štítek 1"}, + {"es","etiqueta1"}, + {"pl","etykieta1"}, + {"pt","etiqueta1"}, + {"pt-br","etiqueta1"}, + {"sv","etikett1"}, + {"it","etichetta1"} + } + }, + { + "Email sent", + new Dictionary() { + {"de","E-Mail gesendet"}, + {"hi","ईमेल भेजा"}, + {"fr","Email envoyé"}, + {"zh-chs","邮件已发送"}, + {"fi","Sähköposti lähetetty"}, + {"tr","E-posta gönderildi"}, + {"cs","Email odeslán"}, + {"ja","送信された電子メール"}, + {"es","Correo electrónico enviado"}, + {"pl","Email wysłano"}, + {"pt","Email enviado"}, + {"nl","E-mail verzonden"}, + {"pt-br","Email enviado"}, + {"sv","Email skickat"}, + {"da","E-mail sendt"}, + {"ko","이메일을 보냈습니다."}, + {"it","Email inviata"}, + {"ru","Письмо отправлено"} } }, { "Sort by &Name", new Dictionary() { - {"nl","Sorteer op &Naam"}, - {"ko","이름으로 분류하다"}, + {"de","Nach Name sortieren"}, + {"hi","नाम द्वारा क्रमबद्ध करें"}, {"fr","Trier par nom"}, - {"it","Ordina per nome"}, {"zh-chs","按名称分类"}, + {"fi","Lajittele nimen mukaan"}, + {"tr","İsme göre sırala"}, + {"cs","Seřaď dle jména"}, + {"ja","名前順"}, + {"es","Ordenar por nombre"}, + {"pl","Sortuj po &Nazwie"}, + {"pt","Classificar por & nome"}, + {"nl","Sorteer op &Naam"}, {"pt-br","Classificar por & nome"}, {"sv","Sortera efter &Namn"}, - {"es","Ordenar por nombre"}, - {"hi","नाम द्वारा क्रमबद्ध करें"}, - {"de","Nach Name sortieren"} + {"da","Sortér efter &navn"}, + {"ko","이름으로 분류하다"}, + {"it","Ordina per nome"}, + {"ru","Сортировать по имени"} } }, { - "Changing language will close this tool. Are you sure?", + "Token", new Dictionary() { - {"nl","Als u de taal wijzigt, wordt deze tool gesloten.Weet je het zeker?"}, - {"ko","언어를 변경하면이 도구가 닫힙니다. 확실합니까?"}, - {"fr","Le changement de langue fermera cet outil. Êtes-vous sûr?"}, - {"it","La modifica della lingua chiuderà questo strumento. Sei sicuro?"}, - {"zh-chs","更改语言将关闭此工具。你确定吗?"}, - {"pt-br","Alterar o idioma fechará esta ferramenta. Tem certeza?"}, - {"sv","Om du byter språk kommer detta verktyg att stängas. Är du säker?"}, - {"es","El cambio de idioma cerrará esta herramienta. ¿Está seguro?"}, - {"hi","भाषा बदलने से यह टूल बंद हो जाएगा। क्या आपको यकीन है?"}, - {"de","Wenn Sie die Sprache ändern, wird dieses Tool geschlossen. Bist du sicher?"} + {"de","Zeichen"}, + {"hi","टोकन"}, + {"fr","Jeton"}, + {"zh-cht","代幣"}, + {"zh-chs","代币"}, + {"fi","Tunnus"}, + {"tr","Anahtar"}, + {"cs","Žeton"}, + {"ja","トークン"}, + {"pt","Símbolo"}, + {"pt-br","Símbolo"}, + {"sv","Tecken"}, + {"ko","토큰"}, + {"it","Gettone"}, + {"ru","Токен"} } }, { - "Device Group", + "Medium", new Dictionary() { - {"de","Gerätegruppe"}, - {"hi","डिवाइस समूह"}, - {"fr","Groupe d'appareils"}, - {"zh-cht","裝置群"}, - {"zh-chs","设备组"}, - {"fi","Laiteryhmä"}, - {"tr","Cihaz Grubu"}, - {"cs","Skupina zařízení"}, - {"ja","デバイスグループ"}, - {"es","Grupo de Dispositivos"}, - {"pt","Grupo de dispositivos"}, - {"nl","Apparaat groep"}, - {"pt-br","Grupo de Dispositivos"}, - {"sv","Enhetsgrupp"}, - {"ko","장치 그룹"}, - {"it","Gruppo di dispositivi"}, - {"ru","Группа устройства"} + {"de","Mittel"}, + {"hi","मध्यम"}, + {"fr","Moyen"}, + {"zh-cht","中"}, + {"zh-chs","中"}, + {"fi","Keskikokoinen"}, + {"tr","Orta"}, + {"cs","Středně"}, + {"ja","中"}, + {"es","Medio"}, + {"pl","Średnio"}, + {"pt","Médio"}, + {"nl","Gemiddeld"}, + {"pt-br","Médio"}, + {"ko","중간"}, + {"it","medio"}, + {"ru","Средний"} + } + }, + { + "Remote Files", + new Dictionary() { + {"de","Remote-Dateien"}, + {"hi","दूरस्थ फ़ाइलें"}, + {"fr","Fichiers distants"}, + {"zh-chs","远程文件"}, + {"fi","Etätiedostot"}, + {"tr","Uzak Dosyalar"}, + {"cs","Vzdálené soubory"}, + {"ja","リモートファイル"}, + {"es","Archivos Remotos"}, + {"pl","Zdalne Pliki"}, + {"pt","Arquivos Remotos"}, + {"nl","Externe bestanden"}, + {"pt-br","Arquivos Remotos"}, + {"sv","Fjärrfiler"}, + {"da","Fjernfiler"}, + {"ko","원격 파일"}, + {"it","File remoti"}, + {"ru","Удаленные файлы"} + } + }, + { + "RDP Port", + new Dictionary() { + {"de","RDP-Port"}, + {"hi","आरडीपी पोर्ट"}, + {"fr","Port RDP"}, + {"zh-chs","RDP 端口"}, + {"fi","RDP -portti"}, + {"tr","RDP Bağlantı Noktası"}, + {"cs","Port RDP"}, + {"ja","RDPポート"}, + {"es","Puerto RDP"}, + {"pl","Port RDP"}, + {"pt","Porta RDP"}, + {"nl","RDP poort"}, + {"pt-br","Porta RDP"}, + {"sv","RDP-port"}, + {"da","RDP port"}, + {"ko","RDP 포트"}, + {"it","Porta RDP"}, + {"ru","Порт RDP"} + } + }, + { + "Updating...", + new Dictionary() { + {"de","Aktualisierung..."}, + {"hi","अपडेट हो रहा है..."}, + {"fr","Mise à jour..."}, + {"zh-chs","正在更新..."}, + {"fi","Päivitetään ..."}, + {"tr","güncelleniyor..."}, + {"cs","Aktualizace ..."}, + {"ja","更新中..."}, + {"es","Actualizando ..."}, + {"pl","Aktualizacja..."}, + {"pt","Atualizando ..."}, + {"nl","Bijwerken..."}, + {"pt-br","Atualizando ..."}, + {"sv","Uppdaterar ..."}, + {"da","Opdaterer..."}, + {"ko","업데이트 중 ..."}, + {"it","In aggiornamento..."}, + {"ru","Обновление ..."} } }, { @@ -157,127 +1363,453 @@ namespace MeshCentralRouter {"cs","Čekání na povolení přístupu uživatelem ..."}, {"ja","ユーザーがアクセスを許可するのを待っています..."}, {"es","Esperando a que el usuario otorgue acceso..."}, + {"pl","Oczekiwanie na przyznanie dostępu przez użytkownika..."}, {"pt","Esperando que o usuário conceda acesso ..."}, {"nl","Wachten op toestemming van de gebruiker..."}, {"pt-br","Esperando que o usuário conceda acesso ..."}, {"sv","Väntar på att användaren ska ge åtkomst ..."}, + {"da","Venter på, at brugeren giver adgang..."}, {"ko","사용자가 액세스 권한을 부여하기를 기다리는 중 ..."}, {"it","In attesa che l'utente conceda l'accesso... "}, {"ru","Ожидание предоставления доступа пользователем ..."} } }, { - "Remote desktop quality, scaling and frame rate settings. These can be adjusted depending on the quality of the network connection.", + " MeshCentral Router", new Dictionary() { - {"nl","Instellingen voor kwaliteit, schaal en framesnelheid van het externe bureaublad. Deze kunnen worden aangepast afhankelijk van de kwaliteit van de netwerkverbinding."}, - {"ko","원격 데스크톱 품질, 크기 조정 및 프레임 속도 설정. 네트워크 연결 품질에 따라 조정할 수 있습니다."}, - {"fr","Paramètres de qualité, de mise à l'échelle et de fréquence d'images du bureau à distance. Ceux-ci peuvent être ajustés en fonction de la qualité de la connexion réseau."}, - {"it","Impostazioni di qualità, ridimensionamento e frame rate del desktop remoto. Questi possono essere regolati in base alla qualità della connessione di rete."}, - {"zh-chs","远程桌面质量、缩放和帧速率设置。这些可以根据网络连接的质量进行调整。"}, - {"pt-br","Configurações de qualidade, escala e taxa de quadros da área de trabalho remota. Eles podem ser ajustados dependendo da qualidade da conexão de rede."}, - {"sv","Fjärrskrivbords kvalitet, skalning och bildfrekvensinställningar. Dessa kan justeras beroende på nätverksanslutningens kvalitet."}, - {"es","Configuración de la calidad del escritorio remoto, la escala y la velocidad de fotogramas. Estos se pueden ajustar en función de la calidad de la conexión de red."}, - {"hi","दूरस्थ डेस्कटॉप गुणवत्ता, स्केलिंग और फ्रेम दर सेटिंग्स। इन्हें नेटवर्क कनेक्शन की गुणवत्ता के आधार पर समायोजित किया जा सकता है।"}, - {"de","Remote-Desktop-Qualität, Skalierung und Bildrateneinstellungen. Diese können je nach Qualität der Netzwerkverbindung angepasst werden."} + {"de"," MeshCentral-Router"}, + {"hi"," मेशसेंट्रल राउटर"}, + {"fr"," Routeur MeshCentral"}, + {"zh-chs"," MeshCentral 路由器"}, + {"fi","MeshCentral -reititin"}, + {"tr"," MeshCentral Yönlendirici"}, + {"cs","MeshCentral Router"}, + {"ja","MeshCentralルーター"}, + {"es"," Enrutador MeshCentral"}, + {"pt","Roteador MeshCentral"}, + {"ko"," MeshCentral 라우터"}, + {"it","MeshCentral Router"}, + {"ru","MeshCentral Маршрутизатор"} } }, { - "Use Alternate Port...", + "Remote", new Dictionary() { - {"nl","Alternatieve poort gebruiken..."}, - {"ko","대체 포트 사용 ..."}, - {"fr","Utiliser un autre port..."}, - {"it","Usa porta alternativa..."}, - {"zh-chs","使用备用端口..."}, - {"pt-br","Usar porta alternativa ..."}, - {"sv","Använd alternativ port ..."}, - {"es","Usar Puerto Alternativo ..."}, - {"hi","वैकल्पिक पोर्ट का उपयोग करें..."}, - {"de","Alternativer Port verwenden..."} + {"de","Entfernt"}, + {"hi","रिमोट"}, + {"fr","Éloigné"}, + {"zh-cht","遠程"}, + {"zh-chs","远程"}, + {"fi","Etä"}, + {"tr","Uzaktan kumanda"}, + {"cs","Vzdálené"}, + {"ja","リモート"}, + {"es","Remoto"}, + {"pl","Zdalny"}, + {"pt","Remoto"}, + {"nl","Extern"}, + {"pt-br","Controle remoto"}, + {"sv","Avlägsen"}, + {"ko","원격"}, + {"it","Remoto"}, + {"ru","Удаленно"} } }, { - "No Port Mappings\r\n\r\nClick \"Add\" to get started.", + "Remove", new Dictionary() { - {"nl","Geen poorttoewijzingen\r\n\r\nKlik op \"Toevoegen\" om te beginnen."}, - {"ko","포트 매핑 없음\r\n\r\n시작하려면 \"추가\"를 클릭하십시오."}, - {"fr","Aucun mappage de port\r\n\r\nCliquez sur \"Ajouter\" pour commencer."}, - {"it","Nessuna mappatura delle porte.\r\n\r\nFai clic su \"Aggiungi\" per iniziare."}, - {"zh-chs","无端口映射\r\n\r\n单击“添加”开始。"}, - {"pt-br","Sem mapeamentos de portas\r\n\r\nClique em \"Adicionar\" para começar."}, - {"sv","Inga portkartor\r\n\r\nKlicka på \"Lägg till\" för att komma igång."}, - {"es","Sin Asignaciones de Puertos\r\n\r\nHaz clic en \"Agregar\" para comenzar."}, - {"hi","कोई पोर्ट मैपिंग नहीं\r\n\r\nआरंभ करने के लिए \"जोड़ें\" पर क्लिक करें।"}, - {"de","Keine Portzuordnungen\r\n\r\nKlicken Sie auf \"Hinzufügen\", um zu beginnen."} + {"de","Entfernen"}, + {"hi","हटाना"}, + {"fr","Retirer"}, + {"zh-cht","删除"}, + {"zh-chs","删除"}, + {"fi","Poista"}, + {"tr","Kaldırmak"}, + {"cs","Odstranit"}, + {"ja","削除する"}, + {"es","Remover"}, + {"pl","Usuń"}, + {"pt","Remover"}, + {"nl","Verwijderen"}, + {"pt-br","Remover"}, + {"sv","Avlägsna"}, + {"da","Fjern"}, + {"ko","제거"}, + {"it","Rimuovere"}, + {"ru","Удалить"} } }, { - "label1", + "Failed to start remote terminal session", new Dictionary() { - {"fr","étiquette1"}, - {"it","etichetta1"}, - {"zh-chs","标签 1"}, - {"pt-br","etiqueta1"}, - {"sv","etikett1"}, - {"es","etiqueta1"}, - {"hi","लेबल1"}, - {"de","Etikett1"} + {"de","Fehler beim Starten der Remote-Terminal-Sitzung"}, + {"hi","दूरस्थ टर्मिनल सत्र प्रारंभ करने में विफल"}, + {"fr","Échec du démarrage de la session de terminal distant"}, + {"zh-chs","无法启动远程终端会话"}, + {"fi","Etäpääteistunnon käynnistäminen epäonnistui"}, + {"tr","Uzak terminal oturumu başlatılamadı"}, + {"cs","Spuštění relace vzdáleného terminálu se nezdařilo"}, + {"ja","リモートターミナルセッションの開始に失敗しました"}, + {"es","No se pudo iniciar la sesión de terminal remota"}, + {"pl","Nie udało się uruchomić sesji zdalnego terminala"}, + {"pt","Falha ao iniciar sessão de terminal remoto"}, + {"nl","Kan externe terminalsessie niet starten"}, + {"pt-br","Falha ao iniciar sessão de terminal remoto"}, + {"sv","Det gick inte att starta fjärrterminsessionen"}, + {"da","Kunne ikke starte fjernterminalsession"}, + {"ko","원격 터미널 세션을 시작하지 못했습니다."}, + {"it","Impossibile avviare la sessione del terminale remoto"}, + {"ru","Не удалось запустить сеанс удаленного терминала"} } }, { - "Server", + "Relay Mapping", new Dictionary() { - {"ko","서버"}, - {"fr","Serveur"}, - {"zh-chs","服务器"}, - {"pt-br","Servidor"}, - {"es","Servidor"}, - {"hi","सर्वर"} + {"de","Relaiszuordnung"}, + {"hi","रिले मैपिंग"}, + {"fr","Cartographie des relais"}, + {"zh-chs","中继映射"}, + {"fi","Relekartoitus"}, + {"tr","Röle Haritalama"}, + {"cs","Reléové mapování"}, + {"ja","リレーマッピング"}, + {"es","Mapeo de Relés"}, + {"pl","Mapowanie Przekierowania"}, + {"pt","Mapeamento de retransmissão"}, + {"nl","Doorstuurtoewijzing"}, + {"pt-br","Mapeamento de retransmissão"}, + {"sv","Relämappning"}, + {"ko","릴레이 매핑"}, + {"it","Mappatura ritrasmissione"}, + {"ru","Отображение реле"} } }, { - "Log out", + ", {0} users", new Dictionary() { - {"nl","Uitloggen"}, - {"ko","로그 아웃"}, - {"fr","Se déconnecter"}, - {"it","Disconnettersi"}, - {"zh-chs","登出"}, - {"pt-br","Sair"}, - {"sv","Logga ut"}, - {"es","Cerrar sesión"}, - {"hi","लॉग आउट"}, - {"de","Ausloggen"} + {"de",", {0} Nutzer"}, + {"hi",", {0} उपयोगकर्ता"}, + {"fr",", {0} utilisateurs"}, + {"zh-chs",", {0} 个用户"}, + {"fi",", {0} käyttäjää"}, + {"tr",", {0} kullanıcı"}, + {"cs",", Uživatelé: {0}"}, + {"ja","、{0}ユーザー"}, + {"es",", {0} usuarios"}, + {"pl",", {0} użytkowników"}, + {"pt",", {0} usuários"}, + {"nl",", {0} gebruikers"}, + {"pt-br",", {0} usuários"}, + {"sv",", {0} användare"}, + {"da",", {0} brugere"}, + {"ko",", {0} 명의 사용자"}, + {"it",", {0} utenti"}, + {"ru",", Пользователей: {0}"} } }, { - "Don't ask for {0} days.", + "SMS sent", new Dictionary() { - {"nl","Niet vragen voor {0} dagen."}, - {"ko","{0} 일을 요구하지 마세요."}, - {"fr","Ne demandez pas {0} jours."}, - {"it","Non chiedere per {0} giorni."}, - {"zh-chs","不要要求 {0} 天。"}, - {"pt-br","Não pergunte por {0} dias."}, - {"sv","Be inte om {0} dagar."}, - {"es","No pedir por {0} días."}, - {"hi","{0} दिनों के लिए मत पूछो।"}, - {"de","Frag nicht nach {0} Tagen."} + {"de","SMS gesendet"}, + {"hi","एसएमएस भेजा गया"}, + {"fr","SMS envoyé"}, + {"zh-chs","短信发送"}, + {"fi","SMS lähetetty"}, + {"tr","SMS gönderildi"}, + {"cs","SMS odeslána"}, + {"ja","SMSが送信されました"}, + {"es","SMS enviado"}, + {"pl","SMS wysłany"}, + {"pt","SMS enviado"}, + {"nl","SMS verzonden"}, + {"pt-br","SMS enviado"}, + {"sv","SMS skickat"}, + {"da","SMS sendt"}, + {"ko","SMS 전송"}, + {"it","SMS inviato"}, + {"ru","SMS отправлено"} } }, { - "Forward all keyboard keys", + "Remote Desktop Stats", new Dictionary() { - {"nl","Alle toetsenbordtoetsen doorsturen"}, - {"ko","모든 키보드 키 전달"}, - {"fr","Transférer toutes les touches du clavier"}, - {"it","Inoltra tutti i tasti della tastiera"}, - {"zh-chs","转发所有键盘键"}, - {"pt-br","Encaminhar todas as teclas do teclado"}, - {"sv","Vidarebefordra alla tangentbordstangenter"}, - {"es","Reenviar todas las teclas del teclado"}, - {"hi","सभी कीबोर्ड कुंजियों को अग्रेषित करें"}, - {"de","Alle Tastaturtasten weiterleiten"} + {"de","Remotedesktop-Statistiken"}, + {"hi","दूरस्थ डेस्कटॉप आँकड़े"}, + {"fr","Statistiques du bureau à distance"}, + {"zh-chs","远程桌面统计"}, + {"fi","Etätyöpöydän tilastot"}, + {"tr","Uzak Masaüstü İstatistikleri"}, + {"cs","Statistiky vzdálené plochy"}, + {"ja","リモートデスクトップ統計"}, + {"es","Estadísticas de Escritorio Remoto"}, + {"pl","Statystyki Zdalnego Pulpitu"}, + {"pt","Estatísticas da área de trabalho remota"}, + {"nl","Extern bureaublad statistieken"}, + {"pt-br","Estatísticas da área de trabalho remota"}, + {"sv","Statistik för fjärrskrivbord"}, + {"da","Statistik for fjernskrivebord"}, + {"ko","원격 데스크톱 통계"}, + {"it","Statistiche desktop remoto"}, + {"ru","Статистика удаленного рабочего стола"} + } + }, + { + "PuTTY SSH client", + new Dictionary() { + {"de","PuTTY SSH-Client"}, + {"hi","पुटी एसएसएच क्लाइंट"}, + {"fr","Client SSH PuTTY"}, + {"zh-chs","PuTTY SSH 客户端"}, + {"fi","PuTTY SSH -asiakas"}, + {"tr","PuTTY SSH istemcisi"}, + {"cs","Klient PuTTY SSH"}, + {"ja","PuTTYSSHクライアント"}, + {"es","Cliente PuTTY SSH"}, + {"pl","Klient PuTTY SSH"}, + {"pt","Cliente PuTTY SSH"}, + {"pt-br","Cliente PuTTY SSH"}, + {"sv","PuTTY SSH-klient"}, + {"da","PuTTY SSH-klient"}, + {"ko","PuTTY SSH 클라이언트"}, + {"ru","Клиент PuTTY SSH"} + } + }, + { + "SMS", + new Dictionary() { + {"hi","एसएमएस"}, + {"zh-cht","短信"}, + {"zh-chs","短信"}, + {"fi","Tekstiviesti"}, + {"ru","смс"} + } + }, + { + "Login", + new Dictionary() { + {"de","Anmeldung"}, + {"hi","लॉग इन करें"}, + {"fr","Connexion"}, + {"zh-cht","登入"}, + {"zh-chs","登录"}, + {"fi","Kirjaudu sisään"}, + {"tr","Oturum aç"}, + {"cs","Přihlášení"}, + {"ja","ログイン"}, + {"es","Iniciar sesión"}, + {"pl","Logowanie"}, + {"pt","Entrar"}, + {"nl","Inloggen"}, + {"pt-br","Conecte-se"}, + {"sv","Logga in"}, + {"ko","로그인"}, + {"ru","Войти"} + } + }, + { + "SSH Username", + new Dictionary() { + {"de","SSH-Benutzername"}, + {"hi","एसएसएच उपयोगकर्ता नाम"}, + {"fr","Nom d'utilisateur SSH"}, + {"zh-chs","SSH 用户名"}, + {"fi","SSH -käyttäjänimi"}, + {"tr","SSH Kullanıcı Adı"}, + {"cs","Uživatelské jméno SSH"}, + {"ja","SSHユーザー名"}, + {"es","Nombre de usuario SSH"}, + {"pl","Nazwa Użytkownika SSH"}, + {"pt","Nome de usuário SSH"}, + {"nl","SSH gebruikersnaam"}, + {"pt-br","Nome de usuário SSH"}, + {"sv","SSH-användarnamn"}, + {"da","SSH brugernavn"}, + {"ko","SSH 사용자 이름"}, + {"it","Nome utente SSH"}, + {"ru","Имя пользователя SSH"} + } + }, + { + "Set RDP port...", + new Dictionary() { + {"de","RDP-Port einstellen..."}, + {"hi","आरडीपी पोर्ट सेट करें..."}, + {"fr","Définir le port RDP..."}, + {"zh-chs","设置 RDP 端口..."}, + {"fi","Aseta RDP -portti ..."}, + {"tr","RDP bağlantı noktasını ayarla..."}, + {"cs","Nastavit port RDP ..."}, + {"ja","RDPポートを設定します。"}, + {"es","Establecer puerto RDP ..."}, + {"pl","Ustaw port RDP..."}, + {"pt","Definir porta RDP ..."}, + {"nl","RDP poort instellen..."}, + {"pt-br","Definir porta RDP ..."}, + {"sv","Ställ in RDP-port ..."}, + {"da","Sæt RDP port..."}, + {"ko","RDP 포트 설정 ..."}, + {"it","Imposta porta RDP..."}, + {"ru","Установить порт RDP ..."} + } + }, + { + "Transfer Errors", + new Dictionary() { + {"de","Übertragungsfehler"}, + {"hi","स्थानांतरण त्रुटियाँ"}, + {"fr","Erreurs de transfert "}, + {"zh-chs","传输错误"}, + {"fi","Siirtovirheet"}, + {"tr","Aktarım Hataları"}, + {"cs","Chyby přenosu"}, + {"ja","転送エラー"}, + {"es","Errores de transferencia"}, + {"pl","Błędy transferu"}, + {"pt","Erros de transferência"}, + {"nl","Overdrachtsfouten"}, + {"pt-br","Errores de transferencia"}, + {"sv","Överföringsfel"}, + {"da","Overførselsfejl"}, + {"ko","전송 오류"}, + {"it","Errori di trasferimento"}, + {"ru","Ошибки передачи"} + } + }, + { + "S&ettings...", + new Dictionary() { + {"de","Die Einstellungen..."}, + {"hi","समायोजन..."}, + {"fr","Paramètres..."}, + {"zh-chs","设置(&E)..."}, + {"fi","Asetukset..."}, + {"tr","&ayarlar..."}, + {"cs","S & ettings ..."}, + {"ja","設定..."}, + {"es","A&justes..."}, + {"pl","U&stawienia..."}, + {"pt","Definições..."}, + {"nl","Instellingen..."}, + {"pt-br","Configurações..."}, + {"sv","Inställningar..."}, + {"ko","설정 (& E) ..."}, + {"ru","Настройки..."} + } + }, + { + "Password", + new Dictionary() { + {"de","Passwort"}, + {"hi","कुंजिका"}, + {"fr","Mot de passe"}, + {"zh-cht","密碼"}, + {"zh-chs","密码"}, + {"fi","Salasana"}, + {"tr","Parola"}, + {"cs","Heslo"}, + {"ja","パスワード"}, + {"es","Contraseña"}, + {"pl","Hasło"}, + {"pt","Senha"}, + {"nl","Wachtwoord"}, + {"pt-br","Senha"}, + {"sv","Lösenord"}, + {"da","Kodeord"}, + {"ko","암호"}, + {"ru","Пароль"} + } + }, + { + "Name", + new Dictionary() { + {"hi","नाम"}, + {"fr","Nom"}, + {"zh-cht","名稱"}, + {"zh-chs","名称"}, + {"fi","Nimi"}, + {"tr","İsim"}, + {"cs","Jméno/název"}, + {"ja","名"}, + {"es","Nombre"}, + {"pl","Nazwa"}, + {"pt","Nome"}, + {"nl","Naam"}, + {"pt-br","Nome"}, + {"sv","Namn"}, + {"da","Navn"}, + {"ko","이름"}, + {"it","Nome"}, + {"ru","Имя"} + } + }, + { + "Add Map...", + new Dictionary() { + {"de","Karte hinzufügen..."}, + {"hi","नक्शा जोड़ें..."}, + {"fr","Ajouter une carte..."}, + {"zh-chs","添加地图..."}, + {"fi","Lisää kartta ..."}, + {"tr","Harita Ekle..."}, + {"cs","Přidat mapu ..."}, + {"ja","地図を追加..."}, + {"es","Agregar mapa ..."}, + {"pl","Dodaj Mapę..."}, + {"pt","Adicionar mapa ..."}, + {"nl","Kaart toevoegen..."}, + {"pt-br","Adicionar mapa ..."}, + {"sv","Lägg till karta ..."}, + {"da","Tilføj kort..."}, + {"ko","지도 추가 ..."}, + {"it","Aggiungi mappa..."}, + {"ru","Добавить карту ..."} + } + }, + { + "Outgoing Bytes", + new Dictionary() { + {"de","Ausgehende Bytes"}, + {"hi","आउटगोइंग बाइट्स"}, + {"fr","Octets sortants"}, + {"zh-chs","传出字节"}, + {"fi","Lähtevät tavut"}, + {"tr","Giden Bayt"}, + {"cs","Odchozí bajty"}, + {"ja","発信バイト"}, + {"es","Bytes Salientes"}, + {"pl","Bajty Wychodzące"}, + {"pt","Bytes de saída"}, + {"nl","Uitgaande Bytes"}, + {"pt-br","Bytes de saída"}, + {"sv","Utgående byte"}, + {"da","Udgående bytes"}, + {"ko","나가는 바이트"}, + {"it","Byte in uscita"}, + {"ru","Исходящие байты"} + } + }, + { + "Swap Mouse Buttons", + new Dictionary() { + {"de","Maustasten vertauschen"}, + {"hi","माउस माउस को स्वैप करें"}, + {"fr","Echanger les boutons de la souris"}, + {"zh-cht","交換鼠標按鈕"}, + {"zh-chs","交换鼠标按钮"}, + {"fi","Vaihda hiiren painikkeet"}, + {"tr","Fare Düğmelerini Değiştirin"}, + {"cs","Zaměňte tlačítka myši"}, + {"ja","マウスボタンを交換する"}, + {"es","Cambiar Botones del Mouse"}, + {"pl","Zamień Przyciski Myszy"}, + {"pt","Botões de troca do mouse"}, + {"nl","Wissel muisknoppen"}, + {"pt-br","Trocar botões do mouse"}, + {"sv","Byt musknappar"}, + {"da","Byt museknapper"}, + {"ko","마우스 버튼 교체"}, + {"it","Scambia i pulsanti del mouse"}, + {"ru","Поменять местами кнопки мыши"} } }, { @@ -298,1747 +1830,26 @@ namespace MeshCentralRouter } }, { - "Ask Consent", - new Dictionary() { - {"de","Einwilligung anfordern"}, - {"hi","सहमति से पूछें"}, - {"fr","Demander le consentement"}, - {"zh-cht","詢問同意"}, - {"zh-chs","询问同意"}, - {"fi","Pyydä Hyväksyntää"}, - {"tr","Onay isteyin"}, - {"cs","Požádat o souhlas"}, - {"ja","同意を求める"}, - {"es","Pedir Consentimiento"}, - {"pt","Peça consentimento"}, - {"nl","Vraag toestemming"}, - {"pt-br","Peça consentimento"}, - {"sv","Fråga samtycke"}, - {"ko","연결 요청"}, - {"it","Chiedi il consenso"}, - {"ru","Спросите согласия"} - } - }, - { - "Add &Map...", - new Dictionary() { - {"nl","&Toewijzing toevoegen..."}, - {"ko","지도 추가 ..."}, - {"fr","Ajouter une &carte..."}, - {"it","Aggiungi &mappa..."}, - {"zh-chs","添加地图 (&M)..."}, - {"pt-br","Adicionar & mapear ..."}, - {"sv","Lägg till & mappa ..."}, - {"es","Agregar & mapa ..."}, - {"hi","नक्शा जोड़ें..."}, - {"de","&Zuordnen hinzufügen..."} - } - }, - { - "Stopped", - new Dictionary() { - {"nl","Gestopt"}, - {"ko","중지됨"}, - {"fr","Arrêté"}, - {"it","Fermato"}, - {"zh-chs","停止"}, - {"pt-br","Parou"}, - {"sv","Stannade"}, - {"es","Detenido"}, - {"hi","रोका हुआ"}, - {"de","Gestoppt"} - } - }, - { - "Two-factor Authentication", - new Dictionary() { - {"nl","Twee-factor authenticatie"}, - {"ko","2 단계 인증"}, - {"fr","Authentification à deux facteurs"}, - {"it","Autenticazione a due fattori"}, - {"zh-chs","两因素身份验证"}, - {"pt-br","Autenticação de dois fatores"}, - {"sv","Tvåfaktorsautentisering"}, - {"es","Autenticación de Dos Factores"}, - {"hi","दो तरीकों से प्रमाणीकरण"}, - {"de","Zwei-Faktor-Authentifizierung"} - } - }, - { - "Update", - new Dictionary() { - {"de","Updates"}, - {"hi","अपडेट करें"}, - {"fr","Mettre à jour"}, - {"zh-cht","更新資料"}, - {"zh-chs","更新资料"}, - {"fi","Päivittää"}, - {"tr","Güncelleme"}, - {"cs","Aktualizace"}, - {"ja","更新"}, - {"es","Actualizar"}, - {"pt","Atualizar"}, - {"nl","Bijwerken"}, - {"pt-br","Atualizar"}, - {"sv","Uppdatering"}, - {"ko","개조하다"}, - {"it","Aggiornamenti"}, - {"ru","Обновить"} - } - }, - { - "Quality", - new Dictionary() { - {"de","Qualität"}, - {"hi","गुणवत्ता"}, - {"fr","Qualité"}, - {"zh-cht","品質"}, - {"zh-chs","质量"}, - {"fi","Laatu"}, - {"tr","Kalite"}, - {"cs","Kvalita"}, - {"ja","品質"}, - {"es","Calidad"}, - {"pt","Qualidade"}, - {"nl","Kwaliteit"}, - {"pt-br","Qualidade"}, - {"sv","Kvalitet"}, - {"ko","품질"}, - {"it","Qualità"}, - {"ru","Качество"} - } - }, - { - "View Certificate Details...", - new Dictionary() { - {"nl","Certificaatdetails bekijken..."}, - {"ko","인증서 세부 정보보기 ..."}, - {"fr","Afficher les détails du certificat..."}, - {"it","Visualizza dettagli certificato..."}, - {"zh-chs","查看证书详细信息..."}, - {"pt-br","Exibir detalhes do certificado ..."}, - {"sv","Visa certifikatinformation ..."}, - {"es","Ver Detalles del Certificado ..."}, - {"hi","प्रमाणपत्र विवरण देखें..."}, - {"de","Zertifikatdetails anzeigen..."} - } - }, - { - "Remote Files...", - new Dictionary() { - {"nl","Externe bestanden..."}, - {"ko","원격 파일 ..."}, - {"fr","Fichiers distants..."}, - {"it","File remoti..."}, - {"zh-chs","远程文件..."}, - {"pt-br","Arquivos remotos ..."}, - {"sv","Fjärrfiler ..."}, - {"es","Archivos Remotos ..."}, - {"hi","दूरस्थ फ़ाइलें..."}, - {"de","Remote-Dateien..."} - } - }, - { - ", Recorded Session", - new Dictionary() { - {"nl",", opgenomen sessie"}, - {"ko",", 녹화 된 세션"}, - {"fr",", Séance enregistrée"}, - {"it",", Sessione registrata"}, - {"zh-chs",", 录制会话"}, - {"pt-br",", Sessão Gravada"}, - {"sv",", Inspelad session"}, - {"es",", Sesión grabada"}, - {"hi",", रिकॉर्ड किया गया सत्र"}, - {"de",", Aufgezeichnete Sitzung"} - } - }, - { - "Email verification required", - new Dictionary() { - {"nl","E-mailverificatie vereist"}, - {"ko","이메일 확인 필요"}, - {"fr","Vérification de l'e-mail requise"}, - {"it","Verifica e-mail richiesta"}, - {"zh-chs","需要电子邮件验证"}, - {"pt-br","Verificação de e-mail necessária"}, - {"sv","Verifiering av e-post krävs"}, - {"es","Se requiere verificación de correo electrónico"}, - {"hi","ईमेल सत्यापन आवश्यक"}, - {"de","E-Mail-Verifizierung erforderlich"} - } - }, - { - "Ignore", - new Dictionary() { - {"nl","Negeren"}, - {"ko","무시"}, - {"fr","Ignorer"}, - {"it","Ignorare"}, - {"zh-chs","忽略"}, - {"pt-br","Ignorar"}, - {"sv","Strunta i"}, - {"es","Ignorar"}, - {"hi","नज़रअंदाज़ करना"}, - {"de","Ignorieren"} - } - }, - { - "Relay Mapping", - new Dictionary() { - {"nl","Doorstuurtoewijzing"}, - {"ko","릴레이 매핑"}, - {"fr","Cartographie des relais"}, - {"it","Mappatura ritrasmissione"}, - {"zh-chs","中继映射"}, - {"pt-br","Mapeamento de retransmissão"}, - {"sv","Relämappning"}, - {"es","Mapeo de Relés"}, - {"hi","रिले मैपिंग"}, - {"de","Relaiszuordnung"} - } - }, - { - ", {0} connections.", - new Dictionary() { - {"nl",", {0} verbindingen."}, - {"ko",", {0} 명 연결."}, - {"fr",", {0} connexions."}, - {"it",", {0} connessioni."}, - {"zh-chs",", {0} 个连接。"}, - {"pt-br",", {0} conexões."}, - {"sv",", {0} anslutningar."}, - {"es",", {0} conexiones."}, - {"hi",", {0} कनेक्शन।"}, - {"de",", {0} Verbindungen."} - } - }, - { - "Enter the RDP port of the remote computer, the default RDP port is 3389.", - new Dictionary() { - {"nl","Voer de RDP poort van de externe computer in, de standaard RDP poort is 3389."}, - {"ko","원격 컴퓨터의 RDP 포트를 입력합니다. 기본 RDP 포트는 3389입니다."}, - {"fr","Entrez le port RDP de l'ordinateur distant, le port RDP par défaut est 3389."}, - {"it","Immettere la porta RDP del computer remoto, la porta RDP predefinita è 3389."}, - {"zh-chs","输入远程计算机的RDP端口,默认RDP端口为3389。"}, - {"pt-br","Insira a porta RDP do computador remoto, a porta RDP padrão é 3389."}, - {"sv","Ange RDP-porten på fjärrdatorn, standard-RDP-porten är 3389."}, - {"es","Ingresa el puerto RDP de la computadora remota, el puerto RDP predeterminado es 3389."}, - {"hi","दूरस्थ कंप्यूटर का RDP पोर्ट दर्ज करें, डिफ़ॉल्ट RDP पोर्ट 3389 है।"}, - {"de","Geben Sie den RDP-Port des Remote-Computers ein, der Standard-RDP-Port ist 3389."} - } - }, - { - "Confirm Delete", - new Dictionary() { - {"nl","Verwijderen bevestigen"}, - {"ko","삭제 확인"}, - {"fr","Confirmation de la suppression"}, - {"it","Conferma cancellazione"}, - {"zh-chs","确认删除"}, - {"pt-br","Confirmar exclusão"}, - {"sv","Bekräfta radering"}, - {"es","Confirmar Eliminación"}, - {"hi","हटाने की पुष्टि करें"}, - {"de","Löschen bestätigen"} - } - }, - { - "Updating...", - new Dictionary() { - {"nl","Bijwerken..."}, - {"ko","업데이트 중 ..."}, - {"fr","Mise à jour..."}, - {"it","In aggiornamento..."}, - {"zh-chs","正在更新..."}, - {"pt-br","Atualizando ..."}, - {"sv","Uppdaterar ..."}, - {"es","Actualizando ..."}, - {"hi","अपडेट हो रहा है..."}, - {"de","Aktualisierung..."} - } - }, - { - "&Delete", - new Dictionary() { - {"nl","&Verwijderen"}, - {"ko","&지우다"}, - {"fr","&Effacer"}, - {"it","&Elimina"}, - {"zh-chs","&删除"}, - {"pt-br","&Excluir"}, - {"sv","&Radera"}, - {"es","&Borrar"}, - {"hi","&हटाएं"}, - {"de","&Löschen"} - } - }, - { - "&Info...", - new Dictionary() { - {"ko","정보 ..."}, - {"zh-chs","&信息..."}, - {"pt-br","& Info ..."}, - {"es","&Info ..."}, - {"hi","जानकारी..."} - } - }, - { - "Invalid username or password", - new Dictionary() { - {"nl","Ongeldige gebruikersnaam of wachtwoord"}, - {"ko","잘못된 사용자 이름 또는 비밀번호"}, - {"fr","Nom d'utilisateur ou mot de passe invalide"}, - {"it","Username o password non validi"}, - {"zh-chs","无效的用户名或密码"}, - {"pt-br","nome de usuário ou senha inválidos"}, - {"sv","Ogiltigt användarnamn eller lösenord"}, - {"es","Usuario o contraseña invalido"}, - {"hi","अमान्य उपयोगकर्ता नाम या पासवर्ड"}, - {"de","ungültiger Benutzername oder Passwort"} - } - }, - { - "Rename File", - new Dictionary() { - {"nl","Bestand hernoemen"}, - {"ko","파일명 변경"}, - {"fr","Renommer le fichier"}, - {"it","Rinomina il file"}, - {"zh-chs","重新命名文件"}, - {"pt-br","Renomear arquivo"}, - {"sv","Döp om fil"}, - {"es","Renombrar Archivo"}, - {"hi","फाइल का नाम बदलो"}, - {"de","Datei umbenennen"} - } - }, - { - "Email", - new Dictionary() { - {"de","E-Mail"}, - {"hi","ईमेल"}, - {"zh-cht","電郵"}, - {"zh-chs","电邮"}, - {"fi","Sähköposti"}, - {"tr","E-posta"}, - {"cs","E-mail"}, - {"ja","Eメール"}, - {"es","Correo electrónico"}, - {"nl","E-mail"}, - {"pt-br","E-mail"}, - {"sv","E-post"}, - {"ko","이메일"}, - {"it","E-mail"} - } - }, - { - "Display connection statistics", - new Dictionary() { - {"nl","Verbindingsstatistieken weergeven"}, - {"ko","연결 통계 표시"}, - {"fr","Afficher les statistiques de connexion"}, - {"it","Visualizza le statistiche di connessione"}, - {"zh-chs","显示连接统计"}, - {"pt-br","Exibir estatísticas de conexão"}, - {"sv","Visa anslutningsstatistik"}, - {"es","Mostrar estadísticas de conexión"}, - {"hi","कनेक्शन आंकड़े प्रदर्शित करें"}, - {"de","Verbindungsstatistik anzeigen"} - } - }, - { - "ServerName", - new Dictionary() { - {"nl","Servernaam"}, - {"ko","서버 이름"}, - {"fr","Nom du serveur"}, - {"it","Nome del server"}, - {"zh-chs","服务器名称"}, - {"pt-br","Nome do servidor"}, - {"sv","Server namn"}, - {"es","Nombre del Servidor"}, - {"hi","सर्वर का नाम"}, - {"de","Servername"} - } - }, - { - "0 Bytes", - new Dictionary() { - {"ko","0 바이트"}, - {"fr","0 octet"}, - {"zh-chs","0 字节"}, - {"sv","0 byte"}, - {"es","0 bytes"}, - {"hi","0 बाइट्स"}, - {"de","0 Byte"} - } - }, - { - "Received invalid network data", - new Dictionary() { - {"de","Ungültige Netzwerkdaten empfangen"}, - {"hi","अमान्य नेटवर्क डेटा प्राप्त किया"}, - {"fr","Données réseau reçues non valides"}, - {"zh-cht","收到無效的網絡數據"}, - {"zh-chs","收到无效的网络数据"}, - {"fi","Vastaanotettu virheellisiä verkkotietoja"}, - {"tr","Geçersiz ağ verileri alındı"}, - {"cs","Přijata neplatná síťová data"}, - {"ja","無効なネットワークデータを受信しました"}, - {"es","Se recibieron datos de red inválidos"}, - {"pt","Dados de rede inválidos recebidos"}, - {"nl","Ongeldige netwerkgegevens ontvangen"}, - {"pt-br","Dados de rede inválidos recebidos"}, - {"sv","Mottog ogiltig nätverksdata"}, - {"ko","잘못된 네트워크 데이터를 받았습니다."}, - {"it","Dati di rete non validi ricevuti"}, - {"ru","Получены неверные сетевые данные"} - } - }, - { - "Port {0} to port {1}", - new Dictionary() { - {"nl","Poort {0} naar poort {1}"}, - {"ko","포트 {0}에서 포트 {1}로"}, - {"fr","Port {0} vers port {1}"}, - {"it","Porta {0} a porta {1}"}, - {"zh-chs","端口 {0} 到端口 {1}"}, - {"pt-br","Porta {0} para porta {1}"}, - {"sv","Porta {0} till port {1}"}, - {"es","Puerto {0} al puerto {1}"}, - {"hi","पोर्ट {0} से पोर्ट {1}"}, - {"de","Port {0} zu Port {1}"} - } - }, - { - "Desktop Settings", - new Dictionary() { - {"nl","Bureaubladinstellingen"}, - {"ko","데스크탑 설정"}, - {"fr","Paramètres du bureau"}, - {"it","Impostazioni del desktop"}, - {"zh-chs","桌面设置"}, - {"pt-br","Configurações da área de trabalho"}, - {"sv","Skrivbordsinställningar"}, - {"es","Configuración de escritorio"}, - {"hi","डेस्कटॉप सेटिंग्स"}, - {"de","Desktop-Einstellungen"} - } - }, - { - "Connecting...", - new Dictionary() { - {"de","Verbinden..."}, - {"hi","कनेक्ट ..."}, - {"fr","En cours de connexion ..."}, - {"zh-cht","正在連線..."}, - {"zh-chs","正在连线..."}, - {"fi","Yhdistetään..."}, - {"tr","Bağlanıyor..."}, - {"cs","Připojování…"}, - {"ja","接続しています..."}, - {"es","Conectando...."}, - {"pt","Conectando..."}, - {"nl","Verbinden..."}, - {"pt-br","Conectando ..."}, - {"sv","Ansluter..."}, - {"ko","연결 중 ..."}, - {"it","Collegamento ..."}, - {"ru","Подключение..."} - } - }, - { - "Server information", - new Dictionary() { - {"nl","Server informatie"}, - {"ko","서버 정보"}, - {"fr","Informations sur le serveur"}, - {"it","Informazioni sul server"}, - {"zh-chs","服务器信息"}, - {"pt-br","Informação do servidor"}, - {"sv","Serverinformation"}, - {"es","Información del Servidor"}, - {"hi","सर्वर जानकारी"}, - {"de","Serverinformation"} - } - }, - { - "Push local clipboard to remote device", - new Dictionary() { - {"nl","Verplaats lokaal klembord naar extern apparaat"}, - {"ko","로컬 클립 보드를 원격 장치로 푸시"}, - {"fr","Transférer le presse-papiers local vers l'appareil distant"}, - {"it","Spingi gli appunti locali sul dispositivo remoto"}, - {"zh-chs","将本地剪贴板推送到远程设备"}, - {"pt-br","Envie a área de transferência local para o dispositivo remoto"}, - {"sv","Tryck lokalt urklipp till fjärrenheten"}, - {"es","Empuje el portapapeles local al dispositivo remoto"}, - {"hi","स्थानीय क्लिपबोर्ड को दूरस्थ डिवाइस पर पुश करें"}, - {"de","Lokale Zwischenablage auf Remote-Gerät übertragen"} - } - }, - { - "Incoming Bytes", - new Dictionary() { - {"nl","Inkomende Bytes"}, - {"ko","들어오는 바이트"}, - {"fr","Octets entrants"}, - {"it","Byte in entrata"}, - {"zh-chs","传入字节"}, - {"pt-br","Bytes de entrada"}, - {"sv","Inkommande byte"}, - {"es","Bytes entrantes"}, - {"hi","आने वाली बाइट्स"}, - {"de","Eingehende Bytes"} - } - }, - { - "MeshCentral", - new Dictionary() { - {"zh-chs","网格中心"}, - {"hi","मेशसेंट्रल"} - } - }, - { - "Show on system tray", - new Dictionary() { - {"nl","Weergeven in systeemvak"}, - {"ko","시스템 트레이에 표시"}, - {"fr","Afficher sur la barre d'état système"}, - {"it","Mostra sulla barra delle applicazioni"}, - {"zh-chs","在系统托盘上显示"}, - {"pt-br","Mostrar na bandeja do sistema"}, - {"sv","Visa i systemfältet"}, - {"es","Mostrar en la bandeja del sistema"}, - {"hi","सिस्टम ट्रे पर दिखाएं"}, - {"de","In der Taskleiste anzeigen"} - } - }, - { - "E&xit", - new Dictionary() { - {"nl","Sluiten"}, - {"ko","출구"}, - {"fr","Sortir"}, - {"zh-chs","出口"}, - {"pt-br","Saída"}, - {"sv","Utgång"}, - {"es","Salida"}, - {"hi","बाहर जाएं"}, - {"de","Beenden"} - } - }, - { - "Remote - {0}", - new Dictionary() { - {"nl","Afstandsbediening - {0}"}, - {"ko","원격-{0}"}, - {"fr","À distance - {0}"}, - {"it","Remoto - {0}"}, - {"zh-chs","远程 - {0}"}, - {"pt-br","Remoto - {0}"}, - {"sv","Fjärrkontroll - {0}"}, - {"es","Remoto: {0}"}, - {"hi","रिमोट - {0}"}, - {"de","Fernbedienung - {0}"} - } - }, - { - "Size", - new Dictionary() { - {"de","Größe"}, - {"hi","आकार"}, - {"fr","Taille"}, - {"zh-cht","尺寸"}, - {"zh-chs","尺寸"}, - {"fi","Koko"}, - {"tr","Boyut"}, - {"cs","Velikost"}, - {"ja","サイズ"}, - {"es","Tamaño"}, - {"pt","Tamanho"}, - {"nl","Grootte"}, - {"pt-br","Tamanho"}, - {"sv","Storlek"}, - {"ko","크기"}, - {"it","Dimensione"}, - {"ru","Размер"} - } - }, - { - "Site", - new Dictionary() { - {"nl","Lokatie"}, - {"ko","대지"}, - {"fr","Placer"}, - {"it","Sito"}, - {"zh-chs","地点"}, - {"pt-br","Local"}, - {"sv","Webbplats"}, - {"es","Sitio"}, - {"hi","साइट"}, - {"de","Seite? ˅"} - } - }, - { - "Bind local port to all network interfaces", - new Dictionary() { - {"nl","Bind lokale poort aan alle netwerkinterfaces"}, - {"ko","모든 네트워크 인터페이스에 로컬 포트 ​​바인딩"}, - {"fr","Lier le port local à toutes les interfaces réseau"}, - {"it","Associa la porta locale a tutte le interfacce di rete"}, - {"zh-chs","将本地端口绑定到所有网络接口"}, - {"pt-br","Vincule a porta local a todas as interfaces de rede"}, - {"sv","Binda lokal port till alla nätverksgränssnitt"}, - {"es","Vincular el puerto local a todas las interfaces de red"}, - {"hi","स्थानीय पोर्ट को सभी नेटवर्क इंटरफेस से बाइंड करें"}, - {"de","Binden Sie den lokalen Port an alle Netzwerkschnittstellen"} - } - }, - { - "Failed to start remote desktop session", - new Dictionary() { - {"nl","Kan extern bureaubladsessie niet starten"}, - {"ko","원격 데스크톱 세션을 시작하지 못했습니다."}, - {"fr","Échec du démarrage de la session de bureau à distance"}, - {"it","Impossibile avviare la sessione desktop remoto"}, - {"zh-chs","无法启动远程桌面会话"}, - {"pt-br","Falha ao iniciar sessão de área de trabalho remota"}, - {"sv","Det gick inte att starta fjärrskrivbordssessionen"}, - {"es","No se pudo iniciar la sesión de escritorio remoto"}, - {"hi","दूरस्थ डेस्कटॉप सत्र प्रारंभ करने में विफल"}, - {"de","Fehler beim Starten der Remote-Desktop-Sitzung"} - } - }, - { - "Connection", - new Dictionary() { - {"nl","Verbinding"}, - {"ko","연결"}, - {"fr","Lien"}, - {"it","Connessione"}, - {"zh-chs","联系"}, - {"pt-br","Conexão"}, - {"sv","Förbindelse"}, - {"es","Conexión"}, - {"hi","संबंध"}, - {"de","Verbindung"} - } - }, - { - "Click ok to register MeshCentral Router on your system as the handler for the \"mcrouter://\" protocol. This will allow the MeshCentral web site to launch this application when needed.", - new Dictionary() { - {"nl","Klik op ok om MeshCentral Router op uw systeem te registreren als de handler voor het \"mcrouter://\" protocol. Hierdoor kan de MeshCentral-website deze applicatie starten wanneer dat nodig is."}, - {"ko","확인을 클릭하여 \"mcrouter : //\"프로토콜의 핸들러로 시스템에 MeshCentral 라우터를 등록하십시오. 이렇게하면 필요할 때 MeshCentral 웹 사이트에서이 응용 프로그램을 시작할 수 있습니다."}, - {"fr","Cliquez sur ok pour enregistrer MeshCentral Router sur votre système en tant que gestionnaire du protocole « mcrouter:// ». Cela permettra au site Web MeshCentral de lancer cette application en cas de besoin."}, - {"it","Fare clic su OK per registrare MeshCentral Router sul sistema come gestore per il protocollo \"mcrouter://\". Ciò consentirà al sito Web MeshCentral di avviare questa applicazione quando necessario."}, - {"zh-chs","单击确定在您的系统上注册 MeshCentral Router 作为“mcrouter://”协议的处理程序。这将允许 MeshCentral 网站在需要时启动此应用程序。"}, - {"pt-br","Clique em ok para registrar o MeshCentral Router em seu sistema como o manipulador do protocolo \"mcrouter: //\". Isso permitirá que o site MeshCentral inicie esse aplicativo quando necessário."}, - {"sv","Klicka på ok för att registrera MeshCentral Router på ditt system som hanterare för \"mcrouter: //\" -protokollet. Detta gör att MeshCentral-webbplatsen kan starta den här applikationen vid behov."}, - {"es","Haz clic en Aceptar para registrar MeshCentral Router en tu sistema como el controlador del protocolo \"mcrouter: //\". Esto permitirá que el sitio web de MeshCentral inicie esta aplicación cuando sea necesario."}, - {"hi","MeshCentral राउटर को अपने सिस्टम पर \"mcrouter: //\" प्रोटोकॉल के लिए हैंडलर के रूप में पंजीकृत करने के लिए ओके पर क्लिक करें। यह मेशसेंट्रल वेब साइट को जरूरत पड़ने पर इस एप्लिकेशन को लॉन्च करने की अनुमति देगा।"}, - {"de","Klicken Sie auf OK, um MeshCentral Router auf Ihrem System als Handler für das Protokoll \"mcrouter://\" zu registrieren. Dadurch kann die MeshCentral-Website diese Anwendung bei Bedarf starten."} - } - }, - { - "HTTP", - new Dictionary() { - {"hi","एचटीटीपी"} - } - }, - { - "Local Port", - new Dictionary() { - {"nl","Lokale poort"}, - {"ko","로컬 포트"}, - {"fr","Port local"}, - {"it","Porta locale"}, - {"zh-chs","本地端口"}, - {"pt-br","Porto Local"}, - {"sv","Lokal hamn"}, - {"es","Puerto Local"}, - {"hi","स्थानीय बंदरगाह"}, - {"de","Lokaler Hafen"} - } - }, - { - "Open Web Site", - new Dictionary() { - {"nl","Website openen"}, - {"ko","웹 사이트 열기"}, - {"fr","Ouvrir le site Web"}, - {"it","Apri sito web"}, - {"zh-chs","打开网站"}, - {"pt-br","Abra o site"}, - {"sv","Öppna webbplatsen"}, - {"es","Abrir Sitio Web"}, - {"hi","वेब साइट खोलें"}, - {"de","Website öffnen"} - } - }, - { - "Enter the second factor authentication token.", - new Dictionary() { - {"nl","Voer de tweede factor authenticatie token in."}, - {"ko","두 번째 요소 인증 토큰을 입력하십시오."}, - {"fr","Saisissez le jeton d'authentification du deuxième facteur."}, - {"it","Immettere il token di autenticazione del secondo fattore."}, - {"zh-chs","输入第二个因素身份验证令牌。"}, - {"pt-br","Insira o token de autenticação de segundo fator."}, - {"sv","Ange den andra faktor-autentiseringstoken."}, - {"es","Ingresa el token del segundo factor de autenticación."}, - {"hi","दूसरा कारक प्रमाणीकरण टोकन दर्ज करें।"}, - {"de","Geben Sie das zweite Faktor-Authentifizierungstoken ein."} - } - }, - { - "Remote Desktop...", - new Dictionary() { - {"nl","Extern bureaublad..."}, - {"ko","원격 데스크탑..."}, - {"fr","Bureau à distance..."}, - {"it","Desktop remoto..."}, - {"zh-chs","远程桌面..."}, - {"pt-br","Área de trabalho remota..."}, - {"sv","Fjärrskrivbord..."}, - {"es","Escritorio Remoto..."}, - {"hi","रिमोट डेस्कटॉप..."}, - {"de","Remotedesktop..."} - } - }, - { - "Remote Desktop", - new Dictionary() { - {"de","Remotedesktop"}, - {"hi","रिमोट डेस्कटॉप"}, - {"fr","Bureau distant"}, - {"zh-cht","遠程桌面"}, - {"zh-chs","远程桌面"}, - {"fi","Etätyöpöytä"}, - {"tr","Uzak Masaüstü"}, - {"cs","Vzdálená plocha"}, - {"ja","リモートデスクトップ"}, - {"es","Escritorio Remoto"}, - {"pt","Área de trabalho remota"}, - {"nl","Extern bureaublad"}, - {"pt-br","Área de trabalho remota"}, - {"sv","Fjärrskrivbord"}, - {"ko","원격 데스크탑"}, - {"it","Desktop remoto"}, - {"ru","Удаленного рабочего стола"} - } - }, - { - "&Open...", - new Dictionary() { - {"ko","&열다..."}, - {"fr","&Ouvert..."}, - {"it","&Apri..."}, - {"zh-chs","&打开..."}, - {"pt-br","&Aberto..."}, - {"sv","&Öppna..."}, - {"es","&Abierto..."}, - {"hi","&खुला हुआ..."}, - {"de","&Öffnen..."} - } - }, - { - "Tunnelling Data", - new Dictionary() { - {"nl","Gegevens tunnelen"}, - {"ko","터널링 데이터"}, - {"fr","Données de tunneling"}, - {"it","Dati di tunneling"}, - {"zh-chs","隧道数据"}, - {"pt-br","Dados de tunelamento"}, - {"sv","Tunneldata"}, - {"es","Datos de Tunelización"}, - {"hi","टनलिंग डेटा"}, - {"de","Tunneling-Daten"} - } - }, - { - "Device Settings", - new Dictionary() { - {"nl","Apparaat instellingen"}, - {"ko","기기 설정"}, - {"fr","Réglages de l'appareil"}, - {"it","Impostazioni del dispositivo"}, - {"zh-chs","设备设置"}, - {"pt-br","Configurações do dispositivo"}, - {"sv","Enhetsinställningar"}, - {"es","Configuración de dispositivo"}, - {"hi","उपकरण सेटिंग्स"}, - {"de","Geräteeinstellungen"} - } - }, - { - "MeshCentral Router Installation", - new Dictionary() { - {"nl","MeshCentral Router Installatie"}, - {"ko","MeshCentral 라우터 설치"}, - {"fr","Installation du routeur MeshCentral"}, - {"it","Installazione del router MeshCentral"}, - {"zh-chs","MeshCentral 路由器安装"}, - {"pt-br","Instalação do roteador MeshCentral"}, - {"es","Instalación del enrutador MeshCentral"}, - {"hi","मेशसेंट्रल राउटर इंस्टालेशन"}, - {"de","Installation des MeshCentral-Routers"} - } - }, - { - "Remote Files", - new Dictionary() { - {"nl","Externe bestanden"}, - {"ko","원격 파일"}, - {"fr","Fichiers distants"}, - {"it","File remoti"}, - {"zh-chs","远程文件"}, - {"pt-br","Arquivos Remotos"}, - {"sv","Fjärrfiler"}, - {"es","Archivos Remotos"}, - {"hi","दूरस्थ फ़ाइलें"}, - {"de","Remote-Dateien"} - } - }, - { - "Incoming Compression", - new Dictionary() { - {"nl","Inkomende compressie"}, - {"ko","들어오는 압축"}, - {"fr","Compression entrante"}, - {"it","Compressione in entrata"}, - {"zh-chs","传入压缩"}, - {"pt-br","Compressão de entrada"}, - {"sv","Inkommande kompression"}, - {"es","Compresión entrante"}, - {"hi","आने वाली संपीड़न"}, - {"de","Eingehende Kompression"} - } - }, - { - "0%", - new Dictionary() { - {"ko","0 %"} - } - }, - { - "Remote Device", - new Dictionary() { - {"nl","Extern apparaat"}, - {"ko","원격 장치"}, - {"fr","Périphérique distant"}, - {"it","Dispositivo remoto"}, - {"zh-chs","遥控装置"}, - {"pt-br","Dispositivo Remoto"}, - {"sv","Fjärrenhet"}, - {"es","Dispositivo Remoto"}, - {"hi","रिमोट डिवाइस"}, - {"de","Remote-Gerät"} - } - }, - { - "Unable to connect", - new Dictionary() { - {"nl","Niet in staat te verbinden"}, - {"ko","연결할 수 없습니다"}, - {"fr","Impossible de se connecter"}, - {"it","Impossibile connetersi"}, - {"zh-chs","无法连接"}, - {"pt-br","Incapaz de conectar "}, - {"sv","Kan inte ansluta"}, - {"es","No se puede conectar"}, - {"hi","कनेक्ट करने में असमर्थ"}, - {"de","Verbindung konnte nicht hergestellt werden"} - } - }, - { - "MQTT", - new Dictionary() { - {"it","MQTT "} - } - }, - { - "Ask Consent + Bar", - new Dictionary() { - {"de","Einwilligung anfordern + DS-Leiste"}, - {"hi","सहमति + बार पूछें"}, - {"fr","Demander le consentement + le bar"}, - {"zh-cht","詢問同意+工具欄"}, - {"zh-chs","询问同意+工具栏"}, - {"fi","Pyydä Hyväksyntää + Ilmoitus"}, - {"tr","Onay Sor + Bar"}, - {"cs","Zeptejte se souhlasu + bar"}, - {"ja","同意を求める+バー"}, - {"es","Pedir Consentimiento + Barra"}, - {"pt","Peça Consentimento + Bar"}, - {"nl","Vraag toestemming + informatiebalk"}, - {"pt-br","Peça Consentimento + Bar"}, - {"sv","Fråga samtycke + bar"}, - {"ko","연결 요청 + Bar"}, - {"it","Chiedi Consenso + Bar"}, - {"ru","Спросите согласия + бар"} - } - }, - { - "{0} Bytes", - new Dictionary() { - {"ko","{0} 바이트"}, - {"fr","{0} octets"}, - {"zh-chs","{0} 字节"}, - {"pt-br","{0} bytes"}, - {"sv","{0} Byte"}, - {"es","{0} bytes"}, - {"hi","{0} बाइट्स"}, - {"de","{0} Byte"} - } - }, - { - "Show &Group Names", - new Dictionary() { - {"nl","Toon &groepsnamen"}, - {"ko","그룹 이름 표시"}, - {"fr","Afficher les noms de &groupes"}, - {"it","Mostra i nomi dei gruppi"}, - {"zh-chs","显示组名称(&G)"}, - {"pt-br","Mostrar nomes de grupos"}, - {"sv","Visa & gruppnamn"}, - {"es","Mostrar y nombres de grupos"}, - {"hi","समूह के नाम दिखाएं"}, - {"de","&Gruppennamen anzeigen"} - } - }, - { - "Username", - new Dictionary() { - {"de","Benutzername"}, - {"hi","उपयोगकर्ता नाम"}, - {"fr","Nom d'utilisateur"}, - {"zh-cht","用戶名"}, - {"zh-chs","用户名"}, - {"fi","Käyttäjätunnus"}, - {"tr","Kullanıcı adı"}, - {"cs","Uživatelské jméno"}, - {"ja","ユーザー名"}, - {"es","Nombre de Usuario"}, - {"pt","Nome de usuário"}, - {"nl","Gebruikersnaam"}, - {"pt-br","Nome do usuário"}, - {"sv","Användarnamn"}, - {"ko","사용자 이름"}, - {"it","Nome utente"}, - {"ru","Имя пользователя"} - } - }, - { - "Disconnected", - new Dictionary() { - {"de","Getrennt"}, - {"hi","डिस्कनेक्ट किया गया"}, - {"fr","Débranché"}, - {"zh-cht","已斷線"}, - {"zh-chs","已断线"}, - {"fi","Yhteys katkaistu"}, - {"tr","Bağlantı kesildi"}, - {"cs","Odpojeno"}, - {"ja","切断されました"}, - {"es","Desconectado"}, - {"pt","Desconectado"}, - {"nl","Verbroken"}, - {"pt-br","Desconectado"}, - {"sv","Frånkopplad"}, - {"ko","연결 해제"}, - {"it","Disconnesso"}, - {"ru","Отключен"} - } - }, - { - "No Devices", - new Dictionary() { - {"nl","Geen apparaten"}, - {"ko","장치 없음"}, - {"fr","Aucun appareil"}, - {"it","Nessun Dispositivo"}, - {"zh-chs","没有设备"}, - {"pt-br","Sem dispositivos"}, - {"sv","Inga enheter"}, - {"es","Sin Dispositivos"}, - {"hi","कोई उपकरण नहीं"}, - {"de","Keine Geräte"} - } - }, - { - "State", - new Dictionary() { - {"de","Zustand"}, - {"hi","राज्य"}, - {"fr","Etat"}, - {"zh-cht","狀態"}, - {"zh-chs","状况"}, - {"fi","Tila"}, - {"tr","Durum"}, - {"cs","Stav"}, - {"ja","状態"}, - {"es","Estado"}, - {"pt","Estado"}, - {"nl","Status"}, - {"pt-br","Estado"}, - {"sv","stat"}, - {"ko","상태"}, - {"it","Stato"}, - {"ru","Состояние"} - } - }, - { - "Email sent", - new Dictionary() { - {"nl","E-mail verzonden"}, - {"ko","이메일을 보냈습니다."}, - {"fr","Email envoyé"}, - {"it","Email inviata"}, - {"zh-chs","邮件已发送"}, - {"pt-br","Email enviado"}, - {"sv","Email skickat"}, - {"es","Correo electrónico enviado"}, - {"hi","ईमेल भेजा"}, - {"de","E-Mail gesendet"} - } - }, - { - "Add Map...", - new Dictionary() { - {"nl","Kaart toevoegen..."}, - {"ko","지도 추가 ..."}, - {"fr","Ajouter une carte..."}, - {"it","Aggiungi mappa..."}, - {"zh-chs","添加地图..."}, - {"pt-br","Adicionar mapa ..."}, - {"sv","Lägg till karta ..."}, - {"es","Agregar mapa ..."}, - {"hi","नक्शा जोड़ें..."}, - {"de","Karte hinzufügen..."} - } - }, - { - "SMS sent", - new Dictionary() { - {"nl","SMS verzonden"}, - {"ko","SMS 전송"}, - {"fr","SMS envoyé"}, - {"it","SMS inviato"}, - {"zh-chs","短信发送"}, - {"pt-br","SMS enviado"}, - {"sv","SMS skickat"}, - {"es","SMS enviado"}, - {"hi","एसएमएस भेजा गया"}, - {"de","SMS gesendet"} - } - }, - { - "Ctrl-Alt-Del", - new Dictionary() { - {"de","Strg-Alt-Entf"} - } - }, - { - "&Open Mappings...", - new Dictionary() { - {"nl","&toewijzingen openen..."}, - {"ko","매핑 열기 ..."}, - {"fr","&Ouvrir les mappages..."}, - {"it","&Apri mappature..."}, - {"zh-chs","打开映射 (&O)..."}, - {"pt-br","& Abrir mapeamentos ..."}, - {"sv","& Öppna kartläggningar ..."}, - {"es","&Abrir mapeos ..."}, - {"hi","&ओपन मैपिंग..."}, - {"de","&Zuordnungen öffnen..."} - } - }, - { - "PuTTY SSH client", - new Dictionary() { - {"ko","PuTTY SSH 클라이언트"}, - {"fr","Client SSH PuTTY"}, - {"zh-chs","PuTTY SSH 客户端"}, - {"pt-br","Cliente PuTTY SSH"}, - {"sv","PuTTY SSH-klient"}, - {"es","Cliente PuTTY SSH"}, - {"hi","पुटी एसएसएच क्लाइंट"}, - {"de","PuTTY SSH-Client"} - } - }, - { - "Invalid download.", - new Dictionary() { - {"nl","Ongeldige download."}, - {"ko","다운로드가 잘못되었습니다."}, - {"fr","Téléchargement non valide."}, - {"it","Download non valido."}, - {"zh-chs","下载无效。"}, - {"pt-br","Download inválido."}, - {"sv","Ogiltig nedladdning."}, - {"es","Descarga no válida."}, - {"hi","अमान्य डाउनलोड।"}, - {"de","Ungültiger Download."} - } - }, - { - "File Operation", - new Dictionary() { - {"de","Dateivorgang"}, - {"hi","फ़ाइल ऑपरेशन"}, - {"fr","Opération sur les fichiers"}, - {"zh-cht","檔案操作"}, - {"zh-chs","档案操作"}, - {"fi","Tiedoston käyttö"}, - {"tr","Dosya İşlemi"}, - {"cs","Provoz souboru"}, - {"ja","ファイル操作"}, - {"es","Operación de Archivo"}, - {"pt","Operação de arquivo"}, - {"nl","Bestandsbewerking"}, - {"pt-br","Operação de arquivo"}, - {"sv","Filhantering"}, - {"ko","파일 작업"}, - {"it","Operazione sui file"}, - {"ru","Работа с файлами"} - } - }, - { - "Cancel", - new Dictionary() { - {"de","Abbrechen"}, - {"hi","रद्द करना"}, - {"fr","Annuler"}, - {"zh-cht","取消"}, - {"zh-chs","取消"}, - {"fi","Peruuta"}, - {"tr","İptal etmek"}, - {"cs","Storno"}, - {"ja","キャンセル"}, - {"es","Cancelar"}, - {"pt","Cancelar"}, - {"nl","Annuleren"}, - {"pt-br","Cancelar"}, - {"sv","Avbryt"}, - {"ko","취소"}, - {"it","Annulla"}, - {"ru","Отмена"} - } - }, - { - "Connected", - new Dictionary() { - {"de","Verbunden"}, - {"hi","जुड़े हुए"}, - {"fr","Connecté"}, - {"zh-cht","已連接"}, - {"zh-chs","已连接"}, - {"fi","Yhdistetty"}, - {"tr","Bağlandı"}, - {"cs","Připojeno"}, - {"ja","接続済み"}, - {"es","Conectado"}, - {"pt","Conectado"}, - {"nl","Verbonden"}, - {"pt-br","Conectado"}, - {"sv","Ansluten"}, - {"ko","연결됨"}, - {"it","Collegato"}, - {"ru","Подключено"} - } - }, - { - "Display {0}", - new Dictionary() { - {"de","Anzeige {0}"}, - {"hi","प्रदर्शन {0}"}, - {"fr","Affichage {0}"}, - {"es","Mostrar {0}"}, - {"zh-chs","显示{0}"}, - {"nl","Scherm {0}"}, - {"pt-br","Exibir {0}"}, - {"ru","Экран {0}"}, - {"sv","Visa {0}"}, - {"ko","{0} 디스플레이"} - } - }, - { - "Application Link", - new Dictionary() { - {"nl","Applicatielink"}, - {"ko","응용 프로그램 링크"}, - {"fr","Lien d'application"}, - {"it","Collegamento all'applicazione"}, - {"zh-chs","申请链接"}, - {"pt-br","Link do aplicativo"}, - {"sv","Applikationslänk"}, - {"es","Enlace de aplicación"}, - {"hi","आवेदन लिंक"}, - {"de","Bewerbungslink"} - } - }, - { - "SMS", - new Dictionary() { - {"hi","एसएमएस"}, - {"zh-cht","短信"}, - {"zh-chs","短信"}, - {"fi","Tekstiviesti"}, - {"ru","смс"} - } - }, - { - "Routing Status", - new Dictionary() { - {"nl","Routeringsstatus"}, - {"ko","라우팅 상태"}, - {"fr","État du routage"}, - {"it","Stato del percorso"}, - {"zh-chs","路由状态"}, - {"pt-br","Status de roteamento"}, - {"sv","Ruttstatus"}, - {"es","Estado de Enrutamiento"}, - {"hi","रूटिंग स्थिति"}, - {"de","Routing-Status"} - } - }, - { - "Add Relay Map...", - new Dictionary() { - {"nl","Toevoegen relay kaart..."}, - {"ko","릴레이 맵 추가 ..."}, - {"fr","Ajouter une carte de relais..."}, - {"it","Aggiungi mappa di rilancio..."}, - {"zh-chs","添加中继地图..."}, - {"pt-br","Adicionar mapa de retransmissão ..."}, - {"sv","Lägg till reläkarta ..."}, - {"es","Agregar mapa de retransmisiones ..."}, - {"hi","रिले मैप जोड़ें..."}, - {"de","Relaiskarte hinzufügen..."} - } - }, - { - "Add &Relay Map...", - new Dictionary() { - {"nl","&Relay toewijzing toevoegen..."}, - {"ko","릴레이 맵 추가 ..."}, - {"fr","Ajouter une carte de &relais..."}, - {"it","Aggiungi &mappa di inoltro..."}, - {"zh-chs","添加中继地图 (&R)..."}, - {"pt-br","Adicionar & retransmitir mapa ..."}, - {"sv","Lägg till & vidarebefordra karta ..."}, - {"es","Agregar y retransmitir mapa ..."}, - {"hi","मानचित्र &रिले जोड़ें..."}, - {"de","&Relay-Karte hinzufügen..."} - } - }, - { - "Starting...", - new Dictionary() { - {"nl","Starten..."}, - {"ko","시작하는 중 ..."}, - {"fr","Départ..."}, - {"it","In Avvio"}, - {"zh-chs","开始..."}, - {"pt-br","Iniciando..."}, - {"sv","Startande..."}, - {"es","A partir de..."}, - {"hi","शुरुआत..."}, - {"de","Beginnend..."} - } - }, - { - "Remote IP", - new Dictionary() { - {"nl","Extern IP"}, - {"ko","원격 IP"}, - {"fr","IP distante"}, - {"it","IP remoto"}, - {"zh-chs","远程IP"}, - {"pt-br","IP Remoto"}, - {"sv","Fjärr-IP"}, - {"es","IP Remota"}, - {"hi","दूरदराज़ के आई. पी"}, - {"de","Remote-IP"} - } - }, - { - "Relay Device", - new Dictionary() { - {"nl","Doorstuur apparaat"}, - {"ko","릴레이 장치"}, - {"fr","Dispositif de relais"}, - {"it","Dispositivo ripetitore"}, - {"zh-chs","中继装置"}, - {"pt-br","Dispositivo de Relé"}, - {"sv","Reläenhet"}, - {"es","Dispositivo de Retransmisión"}, - {"hi","रिले डिवाइस"}, - {"de","Relaisgerät"} - } - }, - { - "&Rename", - new Dictionary() { - {"nl","&Hernoemen"}, - {"ko","이름 바꾸기"}, - {"fr","&Renommer"}, - {"it","&Rinominare"}, - {"zh-chs","&改名"}, - {"pt-br","& Renomear"}, - {"sv","&Döp om"}, - {"es","&Renombrar"}, - {"hi","&नाम बदलें"}, - {"de","&Umbenennen"} - } - }, - { - "Port {0} to {1}:{2}", - new Dictionary() { - {"nl","Poort {0} naar {1}:{2}"}, - {"ko","{0}에서 {1}로 포트 : {2}"}, - {"fr","Port {0} vers {1} :{2}"}, - {"it","Porta {0} a {1}:{2}"}, - {"zh-chs","端口 {0} 到 {1}:{2}"}, - {"pt-br","Porta {0} para {1}: {2}"}, - {"sv","Port {0} till {1}: {2}"}, - {"es","Puerto {0} a {1}: {2}"}, - {"hi","पोर्ट {0} से {1}:{2}"}, - {"de","Port {0} nach {1}:{2}"} - } - }, - { - "Create Folder", - new Dictionary() { - {"nl","Map aanmaken"}, - {"ko","폴더 생성"}, - {"fr","Créer le dossier"}, - {"it","Creare una cartella"}, - {"zh-chs","创建文件夹"}, - {"pt-br","Criar pasta"}, - {"sv","Skapa mapp"}, - {"es","Crear Carpeta"}, - {"hi","फोल्डर बनाएं"}, - {"de","Ordner erstellen"} - } - }, - { - "Fast", - new Dictionary() { - {"de","Schnell"}, - {"hi","तेज"}, - {"fr","Vite"}, - {"zh-cht","快速"}, - {"zh-chs","快速"}, - {"fi","Nopea"}, - {"tr","Hızlı"}, - {"cs","Rychle"}, - {"ja","速い"}, - {"es","Rápido"}, - {"pt","Rápido"}, - {"nl","Snel"}, - {"pt-br","Rápido"}, - {"sv","Snabb"}, - {"ko","빠른"}, - {"it","Veloce"}, - {"ru","Быстро"} - } - }, - { - "Set RDP port...", - new Dictionary() { - {"nl","RDP poort instellen..."}, - {"ko","RDP 포트 설정 ..."}, - {"fr","Définir le port RDP..."}, - {"it","Imposta porta RDP..."}, - {"zh-chs","设置 RDP 端口..."}, - {"pt-br","Definir porta RDP ..."}, - {"sv","Ställ in RDP-port ..."}, - {"es","Establecer puerto RDP ..."}, - {"hi","आरडीपी पोर्ट सेट करें..."}, - {"de","RDP-Port einstellen..."} - } - }, - { - "Application Launch", - new Dictionary() { - {"nl","Toepassing starten"}, - {"ko","응용 프로그램 시작"}, - {"fr","Lancement de l'application"}, - {"it","Lancio dell'applicazione"}, - {"zh-chs","应用启动"}, - {"pt-br","Lançamento do aplicativo"}, - {"sv","Applikationsstart"}, - {"es","Lanzamiento de la aplicación"}, - {"hi","एप्लिकेशन लॉन्च"}, - {"de","Anwendungsstart"} - } - }, - { - "No tools allowed", - new Dictionary() { - {"nl","Geen gereedschap toegestaan"}, - {"fr","Aucun utilitaire autorisé"}, - {"pt-br","Nenhuma ferramenta permitida"}, - {"sv","Inga verktyg tillåtna"}, - {"es","No se permiten herramientas"} - } - }, - { - "File Transfer", - new Dictionary() { - {"de","Datei Übertragung"}, - {"hi","फ़ाइल स्थानांतरण"}, - {"fr","Transfert de fichiers"}, - {"es","Transferencia de Archivos"}, - {"zh-chs","文件传输"}, - {"nl","Bestandsoverdracht"}, - {"pt-br","Transferência de arquivo"}, - {"ru","Передача файлов"}, - {"sv","Filöverföring"}, - {"ko","파일 전송"}, - {"it","Trasferimento di file"} - } - }, - { - "Transfer Progress", - new Dictionary() { - {"nl","Voortgang overdracht"}, - {"ko","전송 진행"}, - {"fr","Progression du transfert"}, - {"it","Avanzamento del trasferimento"}, - {"zh-chs","转学进度"}, - {"pt-br","Progresso da Transferência"}, - {"sv","Överför framsteg"}, - {"es","Progreso de la Transferencia"}, - {"hi","स्थानांतरण प्रगति"}, - {"de","Übertragungsfortschritt"} - } - }, - { - "WinSCP client", - new Dictionary() { - {"ko","WinSCP 클라이언트"}, - {"fr","Client WinSCP"}, - {"it","Client WinSCP"}, - {"zh-chs","WinSCP客户端 "}, - {"pt-br","Cliente WinSCP"}, - {"sv","WinSCP-klient"}, - {"es","Cliente WinSCP"}, - {"hi","विनएससीपी क्लाइंट"}, - {"de","WinSCP-Client"} - } - }, - { - "Back", - new Dictionary() { - {"de","Zurück"}, - {"hi","वापस"}, - {"fr","Retour"}, - {"zh-cht","返回"}, - {"zh-chs","返回"}, - {"fi","Takaisin"}, - {"tr","Geri"}, - {"cs","Zpět"}, - {"ja","バック"}, - {"es","Atrás"}, - {"pt","Voltar"}, - {"nl","Terug"}, - {"pt-br","Voltar"}, - {"sv","Tillbaka"}, - {"ko","뒤로"}, - {"it","Indietro"}, - {"ru","Назад"} - } - }, - { - "Show &Offline Devices", - new Dictionary() { - {"nl","Toon &Offline apparaten"}, - {"ko","오프라인 장치 표시 (& O)"}, - {"fr","Afficher les appareils &hors ligne"}, - {"it","Mostra dispositivi offline"}, - {"zh-chs","显示离线设备 (&A)"}, - {"pt-br","Mostrar dispositivos off-line"}, - {"sv","Visa & Offline-enheter"}, - {"es","Mostrar y dispositivos sin conexión"}, - {"hi","दिखाएँ &ऑफ़लाइन उपकरण"}, - {"de","&Offline-Geräte anzeigen"} - } - }, - { - "Application", - new Dictionary() { - {"nl","Toepassing"}, - {"ko","신청"}, - {"it","Applicazione"}, - {"zh-chs","应用"}, - {"pt-br","Aplicativo"}, - {"sv","Ansökan"}, - {"es","Solicitud"}, - {"hi","आवेदन"}, - {"de","Anwendung"} - } - }, - { - "Rename", - new Dictionary() { - {"de","Umbenennen"}, - {"hi","नाम बदलें"}, - {"fr","Renommer"}, - {"zh-cht","改名"}, - {"zh-chs","改名"}, - {"fi","Nimeä uudelleen"}, - {"tr","Adını değiştirmek"}, - {"cs","Přejmenovat"}, - {"ja","リネーム"}, - {"es","Renombrar"}, - {"pt","Renomear"}, - {"nl","Hernoemen"}, - {"pt-br","Renomear"}, - {"sv","Döp om"}, - {"ko","이름 바꾸기"}, - {"it","Rinominare"}, - {"ru","Переименовать"} - } - }, - { - "Remove", - new Dictionary() { - {"de","Entfernen"}, - {"hi","हटाना"}, - {"fr","Retirer"}, - {"zh-cht","删除"}, - {"zh-chs","删除"}, - {"fi","Poista"}, - {"tr","Kaldırmak"}, - {"cs","Odstranit"}, - {"ja","削除する"}, - {"es","Remover"}, - {"pt","Remover"}, - {"nl","Verwijderen"}, - {"pt-br","Remover"}, - {"sv","Avlägsna"}, - {"ko","제거"}, - {"it","Rimuovere"}, - {"ru","Удалить"} - } - }, - { - "Routing Stats", - new Dictionary() { - {"nl","Routeringsstatistieken"}, - {"ko","라우팅 통계"}, - {"fr","Statistiques de routage"}, - {"it","Statistiche di instradamento"}, - {"zh-chs","路由统计"}, - {"pt-br","Estatísticas de roteamento"}, - {"es","Estadísticas de Enrutamiento"}, - {"hi","रूटिंग आँकड़े"}, - {"de","Routing-Statistiken"} - } - }, - { - "No Search Results", - new Dictionary() { - {"nl","geen resultaten gevonden"}, - {"ko","검색 결과 없음"}, - {"fr","aucun résultat trouvé"}, - {"it","nessun risultato trovato"}, - {"zh-chs","没有搜索结果"}, - {"pt-br","Sem resultados de pesquisa"}, - {"sv","inga sökresultat"}, - {"es","Sin Resultados de Búsqueda"}, - {"hi","खोजने पर कोई परिणाम नहीं मिला"}, - {"de","keine Suchergebnisse"} - } - }, - { - "Close", - new Dictionary() { - {"de","Schließen"}, - {"hi","बंद करे"}, - {"fr","Fermer"}, - {"zh-cht","關"}, - {"zh-chs","关"}, - {"fi","Sulje"}, - {"tr","Kapat"}, - {"cs","Zavřít"}, - {"ja","閉じる"}, - {"es","Cerrar"}, - {"pt","Fechar"}, - {"nl","Sluiten"}, - {"pt-br","Perto"}, - {"sv","Stäng"}, - {"ko","닫기"}, - {"it","Chiudere"}, - {"ru","Закрыть"} - } - }, - { - "RDP", - new Dictionary() { - {"hi","आरडीपी"} - } - }, - { - "OpenSSH", - new Dictionary() { - {"zh-chs","开放式SSH"}, - {"hi","अधिभारित"} - } - }, - { - "Search", - new Dictionary() { - {"de","Suche"}, - {"hi","खोज"}, - {"fr","Chercher"}, - {"zh-cht","搜尋"}, - {"zh-chs","搜寻"}, - {"fi","Etsi"}, - {"tr","Arama"}, - {"cs","Hledat"}, - {"ja","サーチ"}, - {"es","Buscar"}, - {"pt","Procurar"}, - {"nl","Zoeken"}, - {"pt-br","Procurar"}, - {"sv","Sök"}, - {"ko","검색"}, - {"it","Ricerca"}, - {"ru","Поиск"} - } - }, - { - "statusStrip1", - new Dictionary() { - {"it","statoStrip1"}, - {"zh-chs","状态条1"}, - {"hi","स्थिति पट्टी1"} - } - }, - { - "SSH Username", - new Dictionary() { - {"nl","SSH gebruikersnaam"}, - {"ko","SSH 사용자 이름"}, - {"fr","Nom d'utilisateur SSH"}, - {"it","Nome utente SSH"}, - {"zh-chs","SSH 用户名"}, - {"pt-br","Nome de usuário SSH"}, - {"sv","SSH-användarnamn"}, - {"es","Nombre de usuario SSH"}, - {"hi","एसएसएच उपयोगकर्ता नाम"}, - {"de","SSH-Benutzername"} - } - }, - { - "Medium", - new Dictionary() { - {"de","Mittel"}, - {"hi","मध्यम"}, - {"fr","Moyen"}, - {"zh-cht","中"}, - {"zh-chs","中"}, - {"fi","Keskikokoinen"}, - {"tr","Orta"}, - {"cs","Středně"}, - {"ja","中"}, - {"es","Medio"}, - {"pt","Médio"}, - {"nl","Gemiddeld"}, - {"pt-br","Médio"}, - {"ko","중간"}, - {"it","medio"}, - {"ru","Средний"} - } - }, - { - "OK", - new Dictionary() { - {"hi","ठीक"}, - {"fr","ОК"}, - {"tr","tamam"}, - {"pt","Ok"}, - {"ko","확인"}, - {"ru","ОК"} - } - }, - { - "Local - {0}", - new Dictionary() { - {"nl","Lokaal - {0}"}, - {"ko","지역-{0}"}, - {"fr","Locale - {0}"}, - {"it","Locale - {0}"}, - {"zh-chs","本地 - {0}"}, - {"sv","Lokalt - {0}"}, - {"es","Local: {0}"}, - {"hi","स्थानीय - {0}"}, - {"de","Lokal - {0}"} - } - }, - { - "Send token to registered email address?", - new Dictionary() { - {"de","Token an registrierte E-Mail-Adresse senden?"}, - {"hi","प्राप्त ईमेल पते पर टोकन भेजें?"}, - {"fr","Envoyer un jeton à une adresse e-mail enregistrée?"}, - {"zh-cht","將保安編碼發送到註冊的電郵地址?"}, - {"zh-chs","将保安编码发送到注册的电邮地址?"}, - {"fi","Lähetetäänkö tunnus rekisteröityyn sähköpostiosoitteeseen?"}, - {"tr","Belirteç kayıtlı e-posta adresine gönderilsin mi?"}, - {"cs","Odeslat token na zaregistrovanou e-mailovou adresu?"}, - {"ja","登録済みのメールアドレスにトークンを送信しますか?"}, - {"es","¿Enviar token a la dirección de correo electrónico registrada?"}, - {"pt","Enviar token para o endereço de e-mail registrado?"}, - {"nl","Token verzenden naar geregistreerd e-mailadres?"}, - {"pt-br","Enviar token para o endereço de e-mail registrado?"}, - {"sv","Skicka token till registrerad e-postadress?"}, - {"ko","등록된 이메일 주소로 토큰을 보내시겠습니까?"}, - {"it","Invia token all'indirizzo email registrato?"}, - {"ru","Отправить токен на зарегистрированный адрес электронной почты?"} - } - }, - { - "Device Status", - new Dictionary() { - {"nl","Apparaatstatus"}, - {"ko","장치 상태"}, - {"fr","Statut du périphérique"}, - {"it","Stato del dispositivo"}, - {"zh-chs","设备状态"}, - {"pt-br","Status do dispositivo"}, - {"sv","Enhets status"}, - {"es","Estado del dispositivo"}, - {"hi","उपकरण की स्थिति"}, - {"de","Gerätestatus"} - } - }, - { - "Send token to registered phone number?", - new Dictionary() { - {"de","Token an registrierte Telefonnummer senden?"}, - {"hi","विनियमित फोन नंबर पर टोकन भेजें?"}, - {"fr","Envoyer un jeton au numéro de téléphone enregistré?"}, - {"zh-cht","將保安編碼發送到註冊電話號碼?"}, - {"zh-chs","将保安编码发送到注册电话号码?"}, - {"fi","Lähetetäänkö tunnus rekisteröityyn puhelinnumeroon?"}, - {"tr","Belirteç kayıtlı telefon numarasına gönderilsin mi?"}, - {"cs","Poslat token na registrované telefonní číslo?"}, - {"ja","登録した電話番号にトークンを送信しますか?"}, - {"es","¿Enviar token al número de teléfono registrado?"}, - {"pt","Enviar token para o número de telefone registrado?"}, - {"nl","Token naar geregistreerd telefoonnummer verzenden?"}, - {"pt-br","Enviar token para o número de telefone registrado?"}, - {"sv","Skicka token till registrerat telefonnummer?"}, - {"ko","등록된 휴대폰 번호로 토큰을 보내시겠습니까?"}, - {"it","Invia token al numero di telefono registrato?"}, - {"ru","Отправить токен на зарегистрированный номер телефона?"} + "Log out", + new Dictionary() { + {"de","Ausloggen"}, + {"hi","लॉग आउट"}, + {"fr","Se déconnecter"}, + {"zh-chs","登出"}, + {"fi","Kirjautua ulos"}, + {"tr","Çıkış Yap"}, + {"cs","Odhlásit se"}, + {"ja","ログアウト"}, + {"es","Cerrar sesión"}, + {"pl","Wylogowanie"}, + {"pt","Sair"}, + {"nl","Uitloggen"}, + {"pt-br","Sair"}, + {"sv","Logga ut"}, + {"da","Log ud"}, + {"ko","로그 아웃"}, + {"it","Disconnettersi"}, + {"ru","Выйти"} } }, { @@ -2054,179 +1865,397 @@ namespace MeshCentralRouter {"cs","Snímková frekvence"}, {"ja","フレームレート"}, {"es","Cuadros por segundo"}, + {"pl","Liczba klatek na sekundę"}, {"pt","Taxa de quadros"}, {"nl","Frameverhouding"}, {"pt-br","Taxa de quadros"}, {"sv","Bildhastighet"}, + {"da","Billedhastighed"}, {"ko","프레임 속도"}, {"it","Frequenza dei fotogrammi"}, {"ru","Частота кадров"} } }, { - "Scaling", + "Tunnelling Data", new Dictionary() { - {"de","Skalierung"}, - {"hi","स्केलिंग"}, - {"fr","Mise à l'échelle"}, - {"zh-cht","縮放比例"}, - {"zh-chs","缩放比例"}, - {"fi","Skaalaus"}, - {"tr","Ölçeklendirme"}, - {"cs","Škálování"}, - {"ja","スケーリング"}, - {"es","Escala"}, - {"pt","Dimensionamento"}, - {"nl","Schalen"}, - {"pt-br","Dimensionamento"}, - {"sv","Skalning"}, - {"ko","비율"}, - {"it","Ridimensionamento"}, - {"ru","Маштабирование"} + {"de","Tunneling-Daten"}, + {"hi","टनलिंग डेटा"}, + {"fr","Données de tunneling"}, + {"zh-chs","隧道数据"}, + {"fi","Tunnelin tiedot"}, + {"tr","Tünel Açma Verileri"}, + {"cs","Data o tunelování"}, + {"ja","トンネリングデータ"}, + {"es","Datos de Tunelización"}, + {"pl","Dane tunelowania"}, + {"pt","Dados de tunelamento"}, + {"nl","Gegevens tunnelen"}, + {"pt-br","Dados de tunelamento"}, + {"sv","Tunneldata"}, + {"da","Tunneldata"}, + {"ko","터널링 데이터"}, + {"it","Dati di tunneling"}, + {"ru","Данные туннелирования"} } }, { - "UDP", + "Unable to connect", new Dictionary() { - {"hi","यूडीपी"} - } - }, - { - "Next", - new Dictionary() { - {"nl","Volgende"}, - {"ko","다음"}, - {"fr","Suivant"}, - {"it","Prossimo"}, - {"zh-chs","下一个"}, - {"pt-br","Próximo"}, - {"sv","Nästa"}, - {"es","Próximo"}, - {"hi","अगला"}, - {"de","Nächster"} - } - }, - { - "Use Remote Keyboard Map", - new Dictionary() { - {"de","Entfernte Tastaturbelegung verwenden"}, - {"hi","रिमोट कीबोर्ड मैप का उपयोग करें"}, - {"fr","Utiliser la configuration du clavier distant"}, - {"zh-cht","使用遠程鍵盤映射"}, - {"zh-chs","使用远程键盘映射"}, - {"fi","Käytä kaukonäppäimistökarttaa"}, - {"tr","Uzak Klavye Haritasını Kullan"}, - {"cs","Použijte Mapu vzdálené klávesnice"}, - {"ja","リモートキーボードマップを使用する"}, - {"es","Usar Mapa de Teclado Remoto"}, - {"pt","Use o mapa do teclado remoto"}, - {"nl","Gebruik de externe toetsenbord instelling"}, - {"pt-br","Use o mapa do teclado remoto"}, - {"sv","Använd Remote Keyboard Map"}, - {"ko","원격 키보드 맵 사용"}, - {"it","Usa mappa tastiera remota "}, - {"ru","Использовать карту удаленной клавиатуры"} - } - }, - { - "Stats", - new Dictionary() { - {"de","Statistiken"}, - {"hi","आँकड़े"}, - {"fr","Statistiques"}, - {"zh-cht","統計"}, - {"zh-chs","统计"}, - {"fi","Tilastot"}, - {"tr","İstatistikler"}, - {"cs","Statistiky"}, - {"ja","統計"}, - {"es","Estadísticas"}, - {"pt","Estatísticas"}, - {"nl","Statistieken"}, - {"pt-br","Estatísticas"}, - {"sv","Statistik"}, - {"ko","통계"}, - {"ru","Статистика"} - } - }, - { - "Enhanced keyboard capture", - new Dictionary() { - {"nl","Verbeterde toetsenbordopname"}, - {"ko","향상된 키보드 캡처"}, - {"fr","Capture de clavier améliorée"}, - {"it","Acquisizione avanzata della tastiera"}, - {"zh-chs","增强的键盘捕获"}, - {"pt-br","Captura de teclado aprimorada"}, - {"sv","Förbättrad tangentbordsfångst"}, - {"es","Captura de teclado mejorada"}, - {"hi","उन्नत कीबोर्ड कैप्चर"}, - {"de","Verbesserte Tastaturerfassung"} - } - }, - { - "MeshCentral Router Update", - new Dictionary() { - {"ko","MeshCentral 라우터 업데이트"}, - {"fr","Mise à jour du routeur MeshCentral"}, - {"it","Aggiornamento del router MeshCentral"}, - {"zh-chs","MeshCentral 路由器更新"}, - {"pt-br","Atualização do roteador MeshCentral"}, - {"sv","MeshCentral routeruppdatering"}, - {"es","Actualización del enrutador MeshCentral"}, - {"hi","मेशसेंट्रल राउटर अपडेट"}, - {"de","MeshCentral Router-Update"} - } - }, - { - "Denied", - new Dictionary() { - {"de","Verweigert"}, - {"hi","निषेध"}, - {"fr","Refusée"}, - {"zh-cht","被拒絕"}, - {"zh-chs","被拒绝"}, - {"fi","Evätty"}, - {"tr","Reddedildi"}, - {"cs","Odepřeno"}, - {"ja","拒否されました"}, - {"es","Denegado"}, - {"pt","Negado"}, - {"nl","Geweigerd"}, - {"pt-br","Negado"}, - {"sv","Förnekad"}, - {"ko","거부"}, - {"it","Negato"}, - {"ru","Отказано"} - } - }, - { - "ComputerName", - new Dictionary() { - {"nl","Computernaam"}, - {"fr","Nom de l'ordinateur"}, - {"it","Nome del computer"}, - {"zh-chs","计算机名"}, - {"pt-br","Nome do computador"}, - {"sv","Datornamn"}, - {"es","Nombre de la Computadora"}, - {"hi","कंप्यूटर का नाम"}, - {"de","Computername"} + {"de","Verbindung konnte nicht hergestellt werden"}, + {"hi","कनेक्ट करने में असमर्थ"}, + {"fr","Impossible de se connecter"}, + {"zh-chs","无法连接"}, + {"fi","Yhteyden muodostaminen ei onnistu"}, + {"tr","Bağlanılamıyor"}, + {"cs","Nelze se připojit"}, + {"ja","つなげられない"}, + {"es","No se puede conectar"}, + {"pl","Nie można się połączyć"}, + {"pt","Incapaz de conectar"}, + {"nl","Niet in staat te verbinden"}, + {"pt-br","Não foi possível conectar "}, + {"sv","Kan inte ansluta"}, + {"da","Kan ikke oprette forbindelse"}, + {"ko","연결할 수 없습니다"}, + {"it","Impossibile connetersi"}, + {"ru","Невозможно подключиться"} } }, { "Recursive Delete", new Dictionary() { - {"nl","Recursief verwijderen"}, - {"ko","재귀 삭제"}, + {"de","Rekursives Löschen"}, + {"hi","पुनरावर्ती हटाएं"}, {"fr","Suppression récursive"}, - {"it","Cancellazione ricorsiva"}, {"zh-chs","递归删除"}, + {"fi","Rekursiivinen poisto"}, + {"tr","Özyinelemeli Silme"}, + {"cs","Rekurzivní odstranění"}, + {"ja","再帰的削除"}, + {"es","Eliminación Recursiva"}, + {"pl","Usuwanie Rekursywne"}, + {"pt","Exclusão recursiva"}, + {"nl","Recursief verwijderen"}, {"pt-br","Exclusão recursiva"}, {"sv","Rekursivt Radera"}, - {"es","Eliminación Recursiva"}, - {"hi","पुनरावर्ती हटाएं"}, - {"de","Rekursives Löschen"} + {"da","Rekursiv Sletning"}, + {"ko","재귀 삭제"}, + {"it","Cancellazione ricorsiva"}, + {"ru","Рекурсивное удаление"} + } + }, + { + "Port {0} to port {1}", + new Dictionary() { + {"de","Port {0} zu Port {1}"}, + {"hi","पोर्ट {0} से पोर्ट {1}"}, + {"fr","Port {0} vers port {1}"}, + {"zh-chs","端口 {0} 到端口 {1}"}, + {"fi","Portti {0} porttiin {1}"}, + {"tr","{0} numaralı bağlantı noktasını {1} numaralı bağlantı noktasına"}, + {"cs","Z portu {0} na port {1}"}, + {"ja","ポート{0}からポート{1}"}, + {"es","Puerto {0} al puerto {1}"}, + {"pl","Port {0} do portu {1}"}, + {"pt","Porta {0} para porta {1}"}, + {"nl","Poort {0} naar poort {1}"}, + {"pt-br","Porta {0} para porta {1}"}, + {"sv","Porta {0} till port {1}"}, + {"da","Port {0} til port {1}"}, + {"ko","포트 {0}에서 포트 {1}로"}, + {"it","Porta {0} a porta {1}"}, + {"ru","Порт {0} в порт {1}"} + } + }, + { + "&Info...", + new Dictionary() { + {"hi","जानकारी..."}, + {"zh-chs","&信息..."}, + {"fi","&Tiedot..."}, + {"tr","&Bilgi..."}, + {"cs","& Informace ..."}, + {"ja","&情報..."}, + {"es","&Info ..."}, + {"pt","& Info ..."}, + {"pt-br","&Info ..."}, + {"ko","정보 ..."}, + {"ru","&Инфо..."} + } + }, + { + "Automatically Send Clipboard", + new Dictionary() { + {"de","Zwischenablage automatisch senden"}, + {"hi","स्वचालित रूप से क्लिपबोर्ड भेजें"}, + {"fr","Envoyer automatiquement dans le presse-papier"}, + {"zh-chs","自动发送剪贴板"}, + {"fi","Lähetä leikepöytä automaattisesti"}, + {"tr","Panoyu Otomatik Olarak Gönder"}, + {"cs","Automaticky odeslat schránku"}, + {"ja","クリップボードを自動的に送信する"}, + {"es","Enviar portapapeles automáticamente"}, + {"pl","Automatycznie wyślij schowek"}, + {"pt","Enviar área de transferência automaticamente"}, + {"nl","Automatisch klembord verzenden"}, + {"pt-br","Enviar Área de Transferência Automaticamente"}, + {"sv","Skicka urklipp automatiskt"}, + {"da","Automatisk sende udklipsholder"}, + {"ko","자동으로 클립보드 보내기"}, + {"it","Invia automaticamente appunti"}, + {"ru","Автоматически отправлять буфер обмена"} + } + }, + { + "&Delete", + new Dictionary() { + {"de","&Löschen"}, + {"hi","&हटाएं"}, + {"fr","&Effacer"}, + {"zh-chs","&删除"}, + {"fi","&Poistaa"}, + {"tr","&Silmek"}, + {"cs","&Vymazat"}, + {"ja","&消去"}, + {"es","&Borrar"}, + {"pl","&Usuń"}, + {"pt","&Excluir"}, + {"nl","&Verwijderen"}, + {"pt-br","&Excluir"}, + {"sv","&Radera"}, + {"ko","&지우다"}, + {"it","&Elimina"}, + {"ru","&Удалить"} + } + }, + { + "Open...", + new Dictionary() { + {"de","Öffnen..."}, + {"hi","खुला हुआ..."}, + {"fr","Ouvert..."}, + {"zh-chs","打开..."}, + {"fi","Avata..."}, + {"tr","Açık..."}, + {"cs","Otevřeno..."}, + {"ja","開ける..."}, + {"es","Abierto..."}, + {"pl","Otwórz..."}, + {"pt","Abrir..."}, + {"pt-br","Abrir..."}, + {"sv","Öppna..."}, + {"da","Åben..."}, + {"ko","열다..."}, + {"it","Aperto..."}, + {"ru","Открытым..."} + } + }, + { + "Toggle remote desktop connection", + new Dictionary() { + {"de","Remotedesktopverbindung umschalten"}, + {"hi","दूरस्थ डेस्कटॉप कनेक्शन टॉगल करें"}, + {"fr","Basculer la connexion au bureau à distance"}, + {"zh-chs","切换远程桌面连接"}, + {"fi","Vaihda etätyöpöytäyhteys"}, + {"tr","Uzak masaüstü bağlantısını değiştir"}, + {"cs","Přepnout připojení ke vzdálené ploše"}, + {"ja","リモートデスクトップ接続を切り替えます"}, + {"es","Alternar la conexión de escritorio remoto"}, + {"pl","Przełącz zdalnego połączenia pulpitu"}, + {"pt","Alternar conexão de área de trabalho remota"}, + {"nl","Verbinding met extern bureaublad wisselen"}, + {"pt-br","Alternar conexão de área de trabalho remota"}, + {"sv","Växla fjärrskrivbordsanslutning"}, + {"da","Skift fjernskrivebordsforbindelse"}, + {"ko","원격 데스크톱 연결 전환"}, + {"it","Attiva/disattiva connessione desktop remoto"}, + {"ru","Переключить подключение к удаленному рабочему столу"} + } + }, + { + "Starting...", + new Dictionary() { + {"de","Beginnend..."}, + {"hi","शुरुआत..."}, + {"fr","Départ..."}, + {"zh-chs","开始..."}, + {"fi","Aloitetaan ..."}, + {"tr","Başlangıç..."}, + {"cs","Začínající..."}, + {"ja","起動..."}, + {"es","A partir de..."}, + {"pl","Start..."}, + {"pt","Iniciando..."}, + {"nl","Starten..."}, + {"pt-br","Iniciando..."}, + {"sv","Startande..."}, + {"da","Starter..."}, + {"ko","시작하는 중 ..."}, + {"it","In Avvio"}, + {"ru","Пуск ..."} + } + }, + { + "MeshCentral Router allows mapping of TCP and UDP ports on this computer to any computer in your MeshCentral server account. Start by logging into your account.", + new Dictionary() { + {"de","MeshCentral Router ermöglicht die Zuordnung von TCP- und UDP-Ports auf diesem Computer zu jedem Computer in Ihrem MeshCentral-Serverkonto. Melden Sie sich zunächst bei Ihrem Konto an."}, + {"hi","MeshCentral राउटर इस कंप्यूटर पर आपके MeshCentral सर्वर खाते के किसी भी कंप्यूटर पर TCP और UDP पोर्ट की मैपिंग की अनुमति देता है। अपने खाते में लॉग इन करके प्रारंभ करें।"}, + {"fr","Le routeur MeshCentral permet de mapper les ports TCP et UDP de cet ordinateur sur n'importe quel ordinateur de votre compte de serveur MeshCentral. Commencez par vous connecter à votre compte."}, + {"zh-chs","MeshCentral 路由器允许将此计算机上的 TCP 和 UDP 端口映射到您的 MeshCentral 服务器帐户中的任何计算机。首先登录您的帐户。"}, + {"fi","MeshCentral Router mahdollistaa tämän tietokoneen TCP- ja UDP -porttien yhdistämisen mihin tahansa MeshCentral -palvelintilisi tietokoneeseen. Aloita kirjautumalla tilillesi."}, + {"tr","MeshCentral Router, bu bilgisayardaki TCP ve UDP bağlantı noktalarının MeshCentral sunucu hesabınızdaki herhangi bir bilgisayara eşlenmesine izin verir. Hesabınıza giriş yaparak başlayın."}, + {"cs","MeshCentral Router umožňuje mapování portů TCP a UDP na tomto počítači na jakýkoli počítač ve vašem účtu serveru MeshCentral. Začněte přihlášením ke svému účtu."}, + {"ja","MeshCentralルーターを使用すると、このコンピューターのTCPポートとUDPポートをMeshCentralサーバーアカウントの任意のコンピューターにマッピングできます。アカウントにログインすることから始めます。"}, + {"es","MeshCentral Router permite la asignación de puertos TCP y UDP en esta computadora a cualquier computadora en tu cuenta de servidor MeshCentral. Empieza por iniciar sesión en tu cuenta."}, + {"pl","MeshCentral Router pozwala na mapowanie portów TCP i UDP na tym komputerze do dowolnego komputera w twoim koncie serwera MeshCentral. Zacznij od zalogowania się na swoje konto."}, + {"pt","O roteador MeshCentral permite o mapeamento das portas TCP e UDP neste computador para qualquer computador em sua conta do servidor MeshCentral. Comece fazendo login em sua conta."}, + {"nl","Met MeshCentral Router kunnen TCP en UDP poorten op deze computer worden toegewezen aan elke computer in uw MeshCentral-serveraccount. Begin door in te loggen op uw account."}, + {"pt-br","O MeshCentral Router permite o mapeamento das portas TCP e UDP neste computador para qualquer computador em sua conta do servidor MeshCentral. Comece fazendo login em sua conta."}, + {"sv","MeshCentral Router tillåter mappning av TCP- och UDP-portar på den här datorn till vilken dator som helst i ditt MeshCentral-serverkonto. Börja med att logga in på ditt konto."}, + {"da","MeshCentral Router tillader kortlægning af TCP- og UDP-porte på denne computer til enhver computer på din MeshCentral-serverkonto. Start med at logge ind på din konto."}, + {"ko","MeshCentral 라우터를 사용하면이 컴퓨터의 TCP 및 UDP 포트를 MeshCentral 서버 계정의 모든 컴퓨터에 매핑 할 수 있습니다. 계정에 로그인하여 시작하십시오."}, + {"it","MeshCentral Router consente la mappatura delle porte TCP e UDP su questo computer su qualsiasi computer nell'account del server MeshCentral. Inizia accedendo al tuo account."}, + {"ru","Маршрутизатор MeshCentral позволяет сопоставить порты TCP и UDP на этом компьютере с любым компьютером в вашей учетной записи сервера MeshCentral. Начните с входа в свою учетную запись."} + } + }, + { + "ServerName", + new Dictionary() { + {"de","Servername"}, + {"hi","सर्वर का नाम"}, + {"fr","Nom du serveur"}, + {"zh-chs","服务器名称"}, + {"fi","Palvelimen nimi"}, + {"tr","Sunucu adı"}, + {"cs","Název serveru"}, + {"ja","サーバーの名前"}, + {"es","Nombre del Servidor"}, + {"pl","Nazwa serwera"}, + {"pt","Nome do servidor"}, + {"nl","Servernaam"}, + {"pt-br","Nome do servidor"}, + {"sv","Server namn"}, + {"ko","서버 이름"}, + {"it","Nome del server"}, + {"ru","Название сервера"} + } + }, + { + "Sort by G&roup", + new Dictionary() { + {"de","Nach Gruppe sortieren"}, + {"hi","समूह के आधार पर छाँटें"}, + {"fr","Trier par groupe"}, + {"zh-chs","按组(&O) 排序"}, + {"fi","Lajittele G & roup"}, + {"tr","G&grubuna göre sırala"}, + {"cs","Seřadit podle G & roup"}, + {"ja","G&roupで並べ替え"}, + {"es","Ordenar por grupo y grupo"}, + {"pl","Sortuj po G&rupie"}, + {"pt","Classificar por G & Rupo"}, + {"nl","Sorteer op G&roep"}, + {"pt-br","Classificar por G & Rupo"}, + {"sv","Sortera efter G & roup"}, + {"da","Sortér efter G&roup"}, + {"ko","그룹 별 정렬 (& R)"}, + {"it","Ordina per gruppo"}, + {"ru","Сортировать по группе"} + } + }, + { + "Quality", + new Dictionary() { + {"de","Qualität"}, + {"hi","गुणवत्ता"}, + {"fr","Qualité"}, + {"zh-cht","品質"}, + {"zh-chs","质量"}, + {"fi","Laatu"}, + {"tr","Kalite"}, + {"cs","Kvalita"}, + {"ja","品質"}, + {"es","Calidad"}, + {"pl","Jakość"}, + {"pt","Qualidade"}, + {"nl","Kwaliteit"}, + {"pt-br","Qualidade"}, + {"sv","Kvalitet"}, + {"da","Kvalitet"}, + {"ko","품질"}, + {"it","Qualità"}, + {"ru","Качество"} + } + }, + { + "Remember this certificate", + new Dictionary() { + {"de","Merken Sie sich dieses Zertifikat"}, + {"hi","यह प्रमाणपत्र याद रखें"}, + {"fr","Rappelez-vous ce certificat"}, + {"zh-chs","记住这个证书"}, + {"fi","Muista tämä todistus"}, + {"tr","Bu sertifikayı hatırla"}, + {"cs","Zapamatujte si tento certifikát"}, + {"ja","この証明書を覚えておいてください"}, + {"es","Recuerda este certificado"}, + {"pl","Zapamiętaj ten certyfikat"}, + {"pt","Lembre-se deste certificado"}, + {"nl","Onthoud dit certificaat"}, + {"pt-br","Lembrar deste certificado"}, + {"sv","Kom ihåg detta certifikat"}, + {"da","Husk dette certifikat"}, + {"ko","이 인증서 기억"}, + {"it","Ricorda questo certificato"}, + {"ru","Запомни этот сертификат"} + } + }, + { + "Incoming Compression", + new Dictionary() { + {"de","Eingehende Kompression"}, + {"hi","आने वाली संपीड़न"}, + {"fr","Compression entrante"}, + {"zh-chs","传入压缩"}, + {"fi","Saapuva pakkaus"}, + {"tr","Gelen Sıkıştırma"}, + {"cs","Příchozí komprese"}, + {"ja","着信圧縮"}, + {"es","Compresión entrante"}, + {"pl","Kompresja Wejściowa"}, + {"pt","Compressão de entrada"}, + {"nl","Inkomende compressie"}, + {"pt-br","Compressão de entrada"}, + {"sv","Inkommande kompression"}, + {"da","Indkommende kompression"}, + {"ko","들어오는 압축"}, + {"it","Compressione in entrata"}, + {"ru","Входящее сжатие"} + } + }, + { + "Languages", + new Dictionary() { + {"de","Sprachen"}, + {"hi","बोली"}, + {"fr","Langues"}, + {"zh-chs","语言"}, + {"fi","Kieli (kielet"}, + {"tr","Diller"}, + {"cs","Jazyky"}, + {"ja","言語"}, + {"es","Idiomas"}, + {"pl","Języki"}, + {"pt","línguas"}, + {"nl","Talen"}, + {"pt-br","Idiomas"}, + {"sv","språk"}, + {"da","Sprog"}, + {"ko","언어"}, + {"it","Linguaggi"}, + {"ru","Языки"} } }, { @@ -2239,567 +2268,185 @@ namespace MeshCentralRouter {"tr","MeshCentral Yönlendirici"}, {"ja","MeshCentralルーター"}, {"es","Router de MeshCentral "}, - {"pt-br","Roteador MeshCentral"}, {"ko","MeshCentral 라우터"}, {"it","Router MeshCentral"}, {"ru","MeshCentral Router "} } }, { - "Name", + "&Open...", new Dictionary() { - {"hi","नाम"}, - {"fr","Nom"}, - {"zh-cht","名稱"}, - {"zh-chs","名称"}, - {"fi","Nimi"}, - {"tr","İsim"}, - {"cs","Jméno/název"}, - {"ja","名"}, - {"es","Nombre"}, - {"pt","Nome"}, - {"nl","Naam"}, - {"pt-br","Nome"}, - {"sv","Namn"}, - {"ko","이름"}, - {"it","Nome"}, - {"ru","Имя"} + {"de","&Öffnen..."}, + {"hi","&खुला हुआ..."}, + {"fr","&Ouvert..."}, + {"zh-chs","&打开..."}, + {"fi","&Avata..."}, + {"tr","&Açık..."}, + {"cs","&Otevřeno..."}, + {"ja","&開ける..."}, + {"es","&Abierto..."}, + {"pl","&Otwórz..."}, + {"pt","&Abrir..."}, + {"pt-br","&Abrir..."}, + {"sv","&Öppna..."}, + {"ko","&열다..."}, + {"it","&Apri..."}, + {"ru","&Открыть"} } }, { - "Remote Desktop Data", + "{0} Byte", new Dictionary() { - {"nl","Extern bureaublad gegevens"}, - {"ko","원격 데스크톱 데이터"}, - {"fr","Données de bureau à distance"}, - {"it","Dati desktop remoto"}, - {"zh-chs","远程桌面数据"}, - {"pt-br","Dados da área de trabalho remota"}, - {"sv","Fjärrskrivbordsdata"}, - {"es","Datos de Escritorio Remoto"}, - {"hi","दूरस्थ डेस्कटॉप डेटा"}, - {"de","Remotedesktopdaten"} + {"hi","{0} बाइट"}, + {"fr","{0} octet"}, + {"zh-chs","{0} 字节"}, + {"fi","{0} Tavu"}, + {"tr","{0} Bayt"}, + {"ja","{0}バイト"}, + {"pl","{0} Bajt"}, + {"ko","{0} 바이트"}, + {"ru","{0} байт"} } }, { - "Port Mapping", + "statusStrip1", new Dictionary() { - {"nl","Poorttoewijzing"}, - {"ko","포트 매핑"}, - {"fr","Mappage des ports"}, - {"it","Mappatura delle porte"}, - {"zh-chs","端口映射"}, - {"pt-br","Mapeamento de portas"}, - {"sv","Portmappning"}, - {"es","Mapeo de Puertos"}, - {"hi","पोर्ट मानचित्रण"}, - {"de","Port-Mapping"} + {"hi","स्थिति पट्टी1"}, + {"zh-chs","状态条1"}, + {"tr","durumStrip1"}, + {"it","statoStrip1"} } }, { - "Application Name", + "No Port Mappings\r\n\r\nClick \"Add\" to get started.", new Dictionary() { - {"nl","Naam van de toepassing"}, - {"ko","응용 프로그램 이름"}, - {"fr","Nom de l'application"}, - {"it","Nome dell'applicazione"}, - {"zh-chs","应用名称"}, - {"pt-br","Nome da Aplicação"}, - {"sv","applikationsnamn"}, - {"es","Nombre de la aplicación"}, - {"hi","आवेदन का नाम"}, - {"de","Anwendungsname"} + {"de","Keine Portzuordnungen\r\n\r\nKlicken Sie auf \"Hinzufügen\", um zu beginnen."}, + {"hi","कोई पोर्ट मैपिंग नहीं\r\n\r\nआरंभ करने के लिए \"जोड़ें\" पर क्लिक करें।"}, + {"fr","Aucun mappage de port\r\n\r\nCliquez sur \"Ajouter\" pour commencer."}, + {"zh-chs","无端口映射\r\n\r\n单击“添加”开始。"}, + {"fi","Ei satamakartoituksia\r\n\r\nAloita napsauttamalla \"Lisää\"."}, + {"tr","Bağlantı Noktası Eşleme Yok\r\n\r\nBaşlamak için \"Ekle\"yi tıklayın."}, + {"cs","Žádné mapování portů\r\n\r\nZačněte kliknutím na „Přidat“."}, + {"ja","ポートマッピングなし\r\n\r\n「追加」をクリックして開始します。"}, + {"es","Sin Asignaciones de Puertos\r\n\r\nHaz clic en \"Agregar\" para comenzar."}, + {"pl","Brak Mapowań Portów\n\nKliknij \"Dodaj\", aby rozpocząć."}, + {"pt","Sem mapeamentos de portas\r\n\r\nClique em \"Adicionar\" para começar."}, + {"nl","Geen poorttoewijzingen\r\n\r\nKlik op \"Toevoegen\" om te beginnen."}, + {"pt-br","Sem mapeamentos de portas\r\n\r\nClique em \"Adicionar\" para começar."}, + {"sv","Inga portkartor\r\n\r\nKlicka på \"Lägg till\" för att komma igång."}, + {"da","Ingen portmapninger\n\nKlik på \"Tilføj\" for at komme i gang."}, + {"ko","포트 매핑 없음\r\n\r\n시작하려면 \"추가\"를 클릭하십시오."}, + {"it","Nessuna mappatura delle porte.\r\n\r\nFai clic su \"Aggiungi\" per iniziare."}, + {"ru","Нет сопоставления портов\r\n\r\nНажмите «Добавить», чтобы начать."} } }, { - "Error Message", + "Server", new Dictionary() { - {"nl","Foutmelding"}, - {"ko","에러 메시지"}, - {"fr","Message d'erreur"}, - {"it","Messaggio di errore"}, - {"zh-chs","错误信息"}, - {"pt-br","Mensagem de erro"}, - {"sv","Felmeddelande"}, - {"es","Mensaje de error"}, - {"hi","त्रुटि संदेश"}, - {"de","Fehlermeldung"} + {"hi","सर्वर"}, + {"fr","Serveur"}, + {"zh-chs","服务器"}, + {"fi","Palvelin"}, + {"tr","sunucu"}, + {"ja","サーバ"}, + {"es","Servidor"}, + {"pl","Serwer"}, + {"pt","Servidor"}, + {"pt-br","Servidor"}, + {"ko","서버"}, + {"ru","Сервер"} } }, { - "Path", + "Connected", new Dictionary() { - {"nl","Pad"}, - {"ko","통로"}, - {"fr","Chemin"}, - {"it","Percorso"}, - {"zh-chs","小路"}, - {"pt-br","Caminho"}, - {"sv","Väg"}, - {"es","Camino"}, - {"hi","पथ"}, - {"de","Pfad"} + {"de","Verbunden"}, + {"hi","जुड़े हुए"}, + {"fr","Connecté"}, + {"zh-cht","已連接"}, + {"zh-chs","已连接"}, + {"fi","Yhdistetty"}, + {"tr","Bağlandı"}, + {"cs","Připojeno"}, + {"ja","接続済み"}, + {"es","Conectado"}, + {"pl","Połączono"}, + {"pt","Conectado"}, + {"nl","Verbonden"}, + {"pt-br","Conectado"}, + {"sv","Ansluten"}, + {"da","Forbundet"}, + {"ko","연결됨"}, + {"it","Collegato"}, + {"ru","Подключено"} } }, { - "Token", + "Close", new Dictionary() { - {"de","Zeichen"}, - {"hi","टोकन"}, - {"fr","Jeton"}, - {"zh-cht","代幣"}, - {"zh-chs","代币"}, - {"fi","Tunnus"}, - {"tr","Jeton"}, - {"cs","Žeton"}, - {"ja","トークン"}, - {"pt","Símbolo"}, - {"pt-br","Símbolo"}, - {"sv","Tecken"}, - {"ko","토큰"}, - {"it","Gettone"}, - {"ru","Токен"} + {"de","Schließen"}, + {"hi","बंद करे"}, + {"fr","Fermer"}, + {"zh-cht","關"}, + {"zh-chs","关"}, + {"fi","Sulje"}, + {"tr","Kapat"}, + {"cs","Zavřít"}, + {"ja","閉じる"}, + {"es","Cerrar"}, + {"pl","Zamknij"}, + {"pt","Fechar"}, + {"nl","Sluiten"}, + {"pt-br","Fechar"}, + {"sv","Stäng"}, + {"da","Luk"}, + {"ko","닫기"}, + {"it","Chiudere"}, + {"ru","Закрыть"} } }, { - " MeshCentral Router", + "Local - {0}", new Dictionary() { - {"ko"," MeshCentral 라우터"}, - {"fr"," Routeur MeshCentral"}, - {"it","MeshCentral Router"}, - {"zh-chs"," MeshCentral 路由器"}, - {"pt-br"," Roteador MeshCentral"}, - {"es"," Enrutador MeshCentral"}, - {"hi"," मेशसेंट्रल राउटर"}, - {"de"," MeshCentral-Router"} + {"de","Lokal - {0}"}, + {"hi","स्थानीय - {0}"}, + {"fr","Locale - {0}"}, + {"zh-chs","本地 - {0}"}, + {"fi","Paikallinen - {0}"}, + {"tr","Yerel - {0}"}, + {"cs","Místní - {0}"}, + {"ja","ローカル-{0}"}, + {"es","Local: {0}"}, + {"pl","Lokalny - {0}"}, + {"nl","Lokaal - {0}"}, + {"sv","Lokalt - {0}"}, + {"da","Lokalt - {0}"}, + {"ko","지역-{0}"}, + {"it","Locale - {0}"}, + {"ru","Местный - {0}"} } }, { - "Swap Mouse Buttons", + "No Search Results", new Dictionary() { - {"de","Maustasten vertauschen"}, - {"hi","माउस माउस को स्वैप करें"}, - {"fr","Echanger les boutons de la souris"}, - {"zh-cht","交換鼠標按鈕"}, - {"zh-chs","交换鼠标按钮"}, - {"fi","Vaihda hiiren painikkeet"}, - {"tr","Fare Düğmelerini Değiştirin"}, - {"cs","Zaměňte tlačítka myši"}, - {"ja","マウスボタンを交換する"}, - {"es","Cambiar Botones del Mouse"}, - {"pt","Botões de troca do mouse"}, - {"nl","Wissel muisknoppen"}, - {"pt-br","Botões de troca do mouse"}, - {"sv","Byt musknappar"}, - {"ko","마우스 버튼 교체"}, - {"it","Scambia i pulsanti del mouse"}, - {"ru","Поменять местами кнопки мыши"} - } - }, - { - "Change remote desktop settings", - new Dictionary() { - {"nl","Instellingen voor extern bureaublad wijzigen"}, - {"ko","원격 데스크톱 설정 변경"}, - {"fr","Modifier les paramètres du bureau à distance"}, - {"it","Modifica le impostazioni del desktop remoto"}, - {"zh-chs","更改远程桌面设置"}, - {"pt-br","Alterar as configurações da área de trabalho remota"}, - {"sv","Ändra fjärrskrivbordsinställningar"}, - {"es","Cambiar la configuración del escritorio remoto"}, - {"hi","दूरस्थ डेस्कटॉप सेटिंग बदलें"}, - {"de","Remote-Desktop-Einstellungen ändern"} - } - }, - { - "Relay", - new Dictionary() { - {"de","Weiterleitung"}, - {"hi","रिले"}, - {"fr","Relais"}, - {"zh-cht","中繼"}, - {"zh-chs","中继"}, - {"fi","Rele"}, - {"tr","Röle"}, - {"cs","Předávání (relay)"}, - {"ja","リレー"}, - {"es","Relé"}, - {"pt","Retransmissão"}, - {"pt-br","Retransmissão"}, - {"sv","Relä"}, - {"ko","전달(Relay)"}, - {"it","Ritrasmissioni"}, - {"ru","Ретранслятор"} - } - }, - { - "Remote Desktop Stats", - new Dictionary() { - {"nl","Extern bureaublad statistieken"}, - {"ko","원격 데스크톱 통계"}, - {"fr","Statistiques du bureau à distance"}, - {"it","Statistiche desktop remoto"}, - {"zh-chs","远程桌面统计"}, - {"pt-br","Estatísticas da área de trabalho remota"}, - {"sv","Statistik för fjärrskrivbord"}, - {"es","Estadísticas de Escritorio Remoto"}, - {"hi","दूरस्थ डेस्कटॉप आँकड़े"}, - {"de","Remotedesktop-Statistiken"} - } - }, - { - "Alternative Port", - new Dictionary() { - {"nl","Alternatieve poort"}, - {"ko","대체 포트"}, - {"fr","Port alternatif"}, - {"it","Porta alternativa"}, - {"zh-chs","替代端口"}, - {"pt-br","Porto Alternativo"}, - {"sv","Alternativ hamn"}, - {"es","Puerto Alternativo"}, - {"hi","वैकल्पिक बंदरगाह"}, - {"de","Alternativer Hafen"} - } - }, - { - "Toggle zoom-to-fit mode", - new Dictionary() { - {"nl","Schakel inzoemen naar passend modus in"}, - {"ko","확대 / 축소 모드 전환"}, - {"fr","Basculer en mode zoom pour ajuster"}, - {"it","Attiva/disattiva la modalità zoom per adattare"}, - {"zh-chs","切换缩放至适合模式"}, - {"pt-br","Alternar modo de zoom para ajustar"}, - {"sv","Växla zoom-to-fit-läge"}, - {"es","Alternar el modo de zoom para ajustar"}, - {"hi","ज़ूम-टू-फ़िट मोड टॉगल करें"}, - {"de","Zoom-to-Fit-Modus umschalten"} - } - }, - { - "Protocol", - new Dictionary() { - {"de","Protokoll"}, - {"hi","मसविदा बनाना"}, - {"fr","Protocole"}, - {"zh-cht","協議"}, - {"zh-chs","协议"}, - {"fi","Protokolla"}, - {"tr","Protokol"}, - {"cs","Protokol"}, - {"ja","プロトコル"}, - {"es","Protocolo"}, - {"pt","Protocolo"}, - {"pt-br","Protocolo"}, - {"sv","Protokoll"}, - {"ko","프로토콜"}, - {"it","Protocollo"}, - {"ru","Протокол"} - } - }, - { - "Send Ctrl-Alt-Del to remote device", - new Dictionary() { - {"nl","Stuur Ctrl-Alt-Del naar extern apparaat"}, - {"ko","Ctrl-Alt-Del을 원격 장치로 보내기"}, - {"fr","Envoyer Ctrl-Alt-Suppr à l'appareil distant"}, - {"it","Invia Ctrl-Alt-Canc al dispositivo remoto"}, - {"zh-chs","发送 Ctrl-Alt-Del 到远程设备"}, - {"pt-br","Envie Ctrl-Alt-Del para o dispositivo remoto"}, - {"sv","Skicka Ctrl-Alt-Del till fjärrenhet"}, - {"es","Enviar Ctrl-Alt-Del al dispositivo remoto"}, - {"hi","रिमोट डिवाइस पर Ctrl-Alt-Del भेजें"}, - {"de","Strg-Alt-Entf an Remote-Gerät senden"} - } - }, - { - "Sort by G&roup", - new Dictionary() { - {"nl","Sorteer op G&roep"}, - {"ko","그룹 별 정렬 (& R)"}, - {"fr","Trier par groupe"}, - {"it","Ordina per gruppo"}, - {"zh-chs","按组(&O) 排序"}, - {"pt-br","Classificar por G & Rupo"}, - {"sv","Sortera efter G & roup"}, - {"es","Ordenar por grupo y grupo"}, - {"hi","समूह के आधार पर छाँटें"}, - {"de","Nach Gruppe sortieren"} - } - }, - { - "Remove 1 item?", - new Dictionary() { - {"nl","1 artikel verwijderen?"}, - {"ko","항목 1 개를 삭제 하시겠습니까?"}, - {"fr","Supprimer 1 élément ?"}, - {"it","Rimuovere 1 elemento?"}, - {"zh-chs","删除 1 项?"}, - {"pt-br","Remover 1 item?"}, - {"sv","Ta bort ett objekt?"}, - {"es","¿Eliminar 1 artículo?"}, - {"hi","1 आइटम निकालें?"}, - {"de","1 Artikel entfernen?"} - } - }, - { - "Local", - new Dictionary() { - {"de","Lokal"}, - {"hi","स्थानीय"}, - {"zh-cht","本地"}, - {"zh-chs","本地"}, - {"fi","Paikallinen"}, - {"tr","Yerel"}, - {"cs","Lokální"}, - {"ja","地元"}, - {"nl","Lokaal"}, - {"sv","Lokal"}, - {"ko","로컬"}, - {"it","Locale"}, - {"ru","Локальный"} - } - }, - { - "Unable to bind to local port", - new Dictionary() { - {"nl","Kan niet binden aan lokale poort"}, - {"ko","로컬 포트에 바인딩 할 수 없습니다."}, - {"fr","Impossible de se lier au port local"}, - {"it","Impossibile eseguire il binding alla porta locale"}, - {"zh-chs","无法绑定到本地端口"}, - {"pt-br","Incapaz de ligar à porta local"}, - {"sv","Det gick inte att binda till lokal port"}, - {"es","No se puede vincular al puerto local"}, - {"hi","स्थानीय पोर्ट से जुड़ने में असमर्थ"}, - {"de","Kann nicht an lokalen Port binden"} - } - }, - { - "Outgoing Bytes", - new Dictionary() { - {"nl","Uitgaande Bytes"}, - {"ko","나가는 바이트"}, - {"fr","Octets sortants"}, - {"it","Byte in uscita"}, - {"zh-chs","传出字节"}, - {"pt-br","Bytes de saída"}, - {"sv","Utgående byte"}, - {"es","Bytes Salientes"}, - {"hi","आउटगोइंग बाइट्स"}, - {"de","Ausgehende Bytes"} - } - }, - { - "Open...", - new Dictionary() { - {"ko","열다..."}, - {"fr","Ouvert..."}, - {"it","Aperto..."}, - {"zh-chs","打开..."}, - {"pt-br","Aberto..."}, - {"sv","Öppna..."}, - {"es","Abierto..."}, - {"hi","खुला हुआ..."}, - {"de","Öffnen..."} - } - }, - { - "Languages", - new Dictionary() { - {"nl","Talen"}, - {"ko","언어"}, - {"fr","Langues"}, - {"it","Linguaggi"}, - {"zh-chs","语言"}, - {"pt-br","línguas"}, - {"sv","språk"}, - {"es","Idiomas"}, - {"hi","बोली"}, - {"de","Sprachen"} - } - }, - { - "S&ettings...", - new Dictionary() { - {"nl","Instellingen..."}, - {"ko","설정 (& E) ..."}, - {"fr","Paramètres..."}, - {"zh-chs","设置(&E)..."}, - {"pt-br","Configurações..."}, - {"sv","Inställningar..."}, - {"es","A&justes..."}, - {"hi","समायोजन..."}, - {"de","Die Einstellungen..."} - } - }, - { - "Port Mapping Help", - new Dictionary() { - {"nl","Hulp bij poorttoewijzing"}, - {"ko","포트 매핑 도움말"}, - {"fr","Aide sur le mappage de ports"}, - {"it","Aiuto per la mappatura delle porte"}, - {"zh-chs","端口映射帮助"}, - {"pt-br","Ajuda para mapeamento de portas"}, - {"sv","Portmappning Hjälp"}, - {"es","Ayuda de Mapeo de Puertos"}, - {"hi","पोर्ट मैपिंग सहायता"}, - {"de","Hilfe zur Portzuordnung"} - } - }, - { - "Very slow", - new Dictionary() { - {"de","Sehr langsam"}, - {"hi","बहुत धीमी गति से"}, - {"fr","Très lent"}, - {"zh-cht","非常慢"}, - {"zh-chs","非常慢"}, - {"fi","Hyvin hidas"}, - {"tr","Çok yavaş"}, - {"cs","Velmi pomalu"}, - {"ja","非常に遅い"}, - {"es","Muy lento"}, - {"pt","Muito devagar"}, - {"nl","Erg traag"}, - {"pt-br","Muito devagar"}, - {"sv","Väldigt långsam"}, - {"ko","아주 느린"}, - {"it","Molto lento"}, - {"ru","Очень медленно"} - } - }, - { - "WARNING - Invalid Server Certificate", - new Dictionary() { - {"nl","WAARSCHUWING - Ongeldig servercertificaat"}, - {"ko","경고-잘못된 서버 인증서"}, - {"fr","AVERTISSEMENT - Certificat de serveur non valide"}, - {"it","AVVISO - Certificato del server non valido"}, - {"zh-chs","警告 - 服务器证书无效"}, - {"pt-br","AVISO - Certificado de servidor inválido"}, - {"sv","VARNING - Ogiltigt servercertifikat"}, - {"es","ADVERTENCIA: Certificado de Servidor No Válido"}, - {"hi","चेतावनी - अमान्य सर्वर प्रमाणपत्र"}, - {"de","WARNUNG - Ungültiges Serverzertifikat"} - } - }, - { - "Setup...", - new Dictionary() { - {"de","Aufbau..."}, - {"hi","सेट अप..."}, - {"fr","Traitement..."}, - {"zh-cht","設定..."}, - {"zh-chs","设定..."}, - {"fi","Asennus..."}, - {"tr","Kurmak..."}, - {"cs","Nastavení…"}, - {"ja","セットアップ..."}, - {"es","Configurar..."}, - {"pt","Configurando..."}, - {"pt-br","Configurar..."}, - {"sv","Uppstart..."}, - {"ko","설치..."}, - {"it","Impostare..."}, - {"ru","Установка..."} - } - }, - { - "Remember this certificate", - new Dictionary() { - {"nl","Onthoud dit certificaat"}, - {"ko","이 인증서 기억"}, - {"fr","Rappelez-vous ce certificat"}, - {"it","Ricorda questo certificato"}, - {"zh-chs","记住这个证书"}, - {"pt-br","Lembre-se deste certificado"}, - {"sv","Kom ihåg detta certifikat"}, - {"es","Recuerda este certificado"}, - {"hi","यह प्रमाणपत्र याद रखें"}, - {"de","Merken Sie sich dieses Zertifikat"} - } - }, - { - "RDP Port", - new Dictionary() { - {"nl","RDP poort"}, - {"ko","RDP 포트"}, - {"fr","Port RDP"}, - {"it","Porta RDP"}, - {"zh-chs","RDP 端口"}, - {"pt-br","Porta RDP"}, - {"sv","RDP-port"}, - {"es","Puerto RDP"}, - {"hi","आरडीपी पोर्ट"}, - {"de","RDP-Port"} - } - }, - { - "Slow", - new Dictionary() { - {"de","Langsam"}, - {"hi","धीरे"}, - {"fr","Lent"}, - {"zh-cht","慢"}, - {"zh-chs","慢"}, - {"fi","Hidas"}, - {"tr","Yavaş"}, - {"cs","Pomalu"}, - {"ja","スロー"}, - {"es","Lento"}, - {"pt","Lento"}, - {"nl","Traag"}, - {"pt-br","Lento"}, - {"sv","Långsam"}, - {"ko","느린"}, - {"it","Lento"}, - {"ru","Медленно"} - } - }, - { - "Pull clipboard from remote device", - new Dictionary() { - {"nl","Trek het klembord van het externe apparaat"}, - {"ko","원격 장치에서 클립 보드 가져 오기"}, - {"fr","Extraire le presse-papiers de l'appareil distant"}, - {"it","Estrai gli appunti dal dispositivo remoto"}, - {"zh-chs","从远程设备拉剪贴板"}, - {"pt-br","Puxe a área de transferência do dispositivo remoto"}, - {"sv","Dra urklipp från fjärrenheten"}, - {"es","Extraer el Portapapeles del dispositivo remoto"}, - {"hi","दूरस्थ डिवाइस से क्लिपबोर्ड खींचे"}, - {"de","Zwischenablage von Remote-Gerät ziehen"} - } - }, - { - "Remote", - new Dictionary() { - {"de","Entfernt"}, - {"hi","रिमोट"}, - {"fr","Éloigné"}, - {"zh-cht","遠程"}, - {"zh-chs","远程"}, - {"fi","Etä"}, - {"tr","Uzaktan kumanda"}, - {"cs","Vzdálené"}, - {"ja","リモート"}, - {"es","Remoto"}, - {"pt","Remoto"}, - {"nl","Extern"}, - {"pt-br","Controlo remoto"}, - {"sv","Avlägsen"}, - {"ko","원격"}, - {"it","Remoto"}, - {"ru","Удаленно"} - } - }, - { - "TCP", - new Dictionary() { - {"hi","टीसीपी"} + {"de","keine Suchergebnisse"}, + {"hi","खोजने पर कोई परिणाम नहीं मिला"}, + {"fr","aucun résultat trouvé"}, + {"zh-chs","没有搜索结果"}, + {"fi","Ei hakutuloksia"}, + {"tr","arama sonucu bulunamadı"}, + {"cs","Žádné výsledky vyhledávání"}, + {"ja","検索結果がありません"}, + {"es","Sin Resultados de Búsqueda"}, + {"pl","Brak Wyników Szukania"}, + {"pt","Sem resultados de pesquisa"}, + {"nl","geen resultaten gevonden"}, + {"pt-br","Sem resultados de pesquisa"}, + {"sv","inga sökresultat"}, + {"da","Ingen søgeresultater"}, + {"ko","검색 결과 없음"}, + {"it","nessun risultato trovato"}, + {"ru","Нет Результатов Поиска"} } }, { @@ -2815,395 +2462,497 @@ namespace MeshCentralRouter {"cs","Nastavení"}, {"ja","設定"}, {"es","Opciones"}, + {"pl","Ustawienia"}, {"pt","Configurações"}, {"nl","Instellingen"}, {"pt-br","Configurações"}, {"sv","inställningar"}, + {"da","Indstillinger"}, {"ko","설정"}, {"it","impostazioni"}, {"ru","Настройки"} } }, { - "MeshCentral Router allows mapping of TCP and UDP ports on this computer to any computer in your MeshCentral server account. Start by logging into your account.", + "No tools allowed", new Dictionary() { - {"nl","Met MeshCentral Router kunnen TCP en UDP poorten op deze computer worden toegewezen aan elke computer in uw MeshCentral-serveraccount. Begin door in te loggen op uw account."}, - {"ko","MeshCentral 라우터를 사용하면이 컴퓨터의 TCP 및 UDP 포트를 MeshCentral 서버 계정의 모든 컴퓨터에 매핑 할 수 있습니다. 계정에 로그인하여 시작하십시오."}, - {"fr","Le routeur MeshCentral permet de mapper les ports TCP et UDP de cet ordinateur sur n'importe quel ordinateur de votre compte de serveur MeshCentral. Commencez par vous connecter à votre compte."}, - {"it","MeshCentral Router consente la mappatura delle porte TCP e UDP su questo computer su qualsiasi computer nell'account del server MeshCentral. Inizia accedendo al tuo account."}, - {"zh-chs","MeshCentral 路由器允许将此计算机上的 TCP 和 UDP 端口映射到您的 MeshCentral 服务器帐户中的任何计算机。首先登录您的帐户。"}, - {"pt-br","O roteador MeshCentral permite o mapeamento das portas TCP e UDP neste computador para qualquer computador em sua conta do servidor MeshCentral. Comece fazendo login em sua conta."}, - {"sv","MeshCentral Router tillåter mappning av TCP- och UDP-portar på den här datorn till vilken dator som helst i ditt MeshCentral-serverkonto. Börja med att logga in på ditt konto."}, - {"es","MeshCentral Router permite la asignación de puertos TCP y UDP en esta computadora a cualquier computadora en tu cuenta de servidor MeshCentral. Empieza por iniciar sesión en tu cuenta."}, - {"hi","MeshCentral राउटर इस कंप्यूटर पर आपके MeshCentral सर्वर खाते के किसी भी कंप्यूटर पर TCP और UDP पोर्ट की मैपिंग की अनुमति देता है। अपने खाते में लॉग इन करके प्रारंभ करें।"}, - {"de","MeshCentral Router ermöglicht die Zuordnung von TCP- und UDP-Ports auf diesem Computer zu jedem Computer in Ihrem MeshCentral-Serverkonto. Melden Sie sich zunächst bei Ihrem Konto an."} + {"de","Kein Werkzeug erlaubt"}, + {"hi","किसी उपकरण की अनुमति नहीं है"}, + {"fr","Aucun utilitaire autorisé"}, + {"zh-chs","不允许使用工具"}, + {"fi","Ei työkaluja"}, + {"tr","Hiçbir alete izin verilmez"}, + {"cs","Nejsou povoleny žádné nástroje"}, + {"ja","ツールは許可されていません"}, + {"es","No se permiten herramientas"}, + {"pl","Żadne narzędzia nie są dozwolone"}, + {"pt","Nenhuma ferramenta permitida"}, + {"nl","Geen gereedschap toegestaan"}, + {"pt-br","Nenhuma ferramenta permitida"}, + {"sv","Inga verktyg tillåtna"}, + {"da","Ingen værktøj tilladt"}, + {"ko","도구가 허용되지 않음"}, + {"it","Nessuno strumento consentito"}, + {"ru","Инструменты не разрешены"} } }, { - "Outgoing Compression", + "{0} minutes left", new Dictionary() { - {"nl","Uitgaande compressie"}, - {"ko","나가는 압축"}, - {"fr","Compression sortante"}, - {"it","Compressione in uscita"}, - {"zh-chs","输出压缩"}, - {"pt-br","Compressão de saída"}, - {"sv","Utgående kompression"}, - {"es","Compresión Saliente"}, - {"hi","आउटगोइंग संपीड़न"}, - {"de","Ausgehende Komprimierung"} + {"de","noch {0} Minuten"}, + {"hi","{0} मिनट शेष"}, + {"fr","{0} minutes restantes"}, + {"zh-chs","还剩 {0} 分钟"}, + {"fi","{0} minuuttia jäljellä"}, + {"tr","{0} dakika kaldı"}, + {"cs","Zbývají {0} minuty"}, + {"ja","残り{0}分"}, + {"es","Quedan {0} minutos"}, + {"pl","Pozostało {0} minut"}, + {"pt","Faltam {0} minutos"}, + {"nl","{0} minuten resterend"}, + {"pt-br","Quedan {0} minutos"}, + {"sv","{0} minuter kvar"}, + {"da","{0} minutter tilbage"}, + {"ko","{0}분 남음"}, + {"it","{0} minuti rimasti"}, + {"ru","Осталось {0} минут"} } }, { - ", {0} users", + "Pull clipboard from remote device", new Dictionary() { - {"nl",", {0} gebruikers"}, - {"ko",", {0} 명의 사용자"}, - {"fr",", {0} utilisateurs"}, - {"it",", {0} utenti"}, - {"zh-chs",", {0} 个用户"}, - {"pt-br",", {0} usuários"}, - {"sv",", {0} användare"}, - {"es",", {0} usuarios"}, - {"hi",", {0} उपयोगकर्ता"}, - {"de",", {0} Nutzer"} + {"de","Zwischenablage von Remote-Gerät ziehen"}, + {"hi","दूरस्थ डिवाइस से क्लिपबोर्ड खींचे"}, + {"fr","Extraire le presse-papiers de l'appareil distant"}, + {"zh-chs","从远程设备拉剪贴板"}, + {"fi","Vedä leikepöytä etälaitteesta"}, + {"tr","Panoyu uzak cihazdan çekin"}, + {"cs","Vytáhněte schránku ze vzdáleného zařízení"}, + {"ja","リモートデバイスからクリップボードを引き出す"}, + {"es","Extraer el Portapapeles del dispositivo remoto"}, + {"pl","Wyciągnij schowek z urządzenia zdalnego"}, + {"pt","Puxe a área de transferência do dispositivo remoto"}, + {"nl","Trek het klembord van het externe apparaat"}, + {"pt-br","Puxe a área de transferência do dispositivo remoto"}, + {"sv","Dra urklipp från fjärrenheten"}, + {"da","Hent udklipsholderen fra fjernenheden"}, + {"ko","원격 장치에서 클립 보드 가져 오기"}, + {"it","Estrai gli appunti dal dispositivo remoto"}, + {"ru","Извлечь буфер обмена с удаленного устройства"} } }, { - "This MeshCentral Server uses a different version of this tool. Click ok to download and update.", + "Error uploading file: {0}", new Dictionary() { - {"nl","Deze MeshCentral Server gebruikt een andere versie van deze tool. Klik op OK om te downloaden en bij te werken."}, - {"ko","이 MeshCentral 서버는이 도구의 다른 버전을 사용합니다. 확인을 클릭하여 다운로드하고 업데이트하십시오."}, - {"fr","Ce serveur MeshCentral utilise une version différente de cet outil. Cliquez sur ok pour télécharger et mettre à jour."}, - {"it","Questo server MeshCentral utilizza una versione diversa di questo strumento.Fare clic su OK per scaricare e aggiornare."}, - {"zh-chs","此 MeshCentral Server 使用此工具的不同版本。单击“确定”进行下载和更新。"}, - {"pt-br","Este servidor MeshCentral usa uma versão diferente desta ferramenta. Clique em ok para baixar e atualizar."}, - {"sv","Denna MeshCentral Server använder en annan version av detta verktyg. Klicka på ok för att ladda ner och uppdatera."}, - {"es","Este servidor MeshCentral utiliza una versión diferente de esta herramienta. Haz clic en Aceptar para descargar y actualizar."}, - {"hi","यह MeshCentral सर्वर इस टूल के भिन्न संस्करण का उपयोग करता है। डाउनलोड और अपडेट करने के लिए ओके पर क्लिक करें।"}, - {"de","Dieser MeshCentral Server verwendet eine andere Version dieses Tools. Klicken Sie auf OK, um herunterzuladen und zu aktualisieren."} + {"de","Fehler beim Hochladen der Datei: {0}"}, + {"hi","फ़ाइल अपलोड करने में त्रुटि: {0}"}, + {"fr","Erreur lors du chargement du fichier : {0}"}, + {"zh-chs","上传文件时出错:{0}"}, + {"fi","Virhe tiedoston lataamisessa: {0}"}, + {"tr","Dosya yüklenirken hata oluştu: {0}"}, + {"cs","Chyba při nahrávání souboru: {0}"}, + {"ja","ファイルのアップロード中にエラーが発生しました:{0}"}, + {"es","Error al cargar el archivo: {0}"}, + {"pl","Błąd podczas przesyłania pliku: {0}"}, + {"pt","Erro ao enviar arquivo: {0}"}, + {"nl","Fout bij uploaden van bestand: {0}"}, + {"pt-br","Erro ao carregar arquivo: {0}"}, + {"sv","Fel vid överföring av fil: {0}"}, + {"da","Fejl ved upload af fil: {0}"}, + {"ko","파일 업로드 오류: {0}"}, + {"it","Errore durante il caricamento del file: {0}"}, + {"ru","Ошибка при загрузке файла: {0}"} } }, { - "Cancel Auto-Close", + "Add &Relay Map...", new Dictionary() { - {"nl","Automatisch sluiten annuleren"}, - {"ko","자동 닫기 취소"}, - {"fr","Annuler la fermeture automatique"}, - {"it","Annulla chiusura automatica"}, - {"zh-chs","取消自动关闭"}, - {"pt-br","Cancelar fechamento automático"}, - {"sv","Avbryt automatisk stängning"}, - {"es","Cancelar Cierre Automático"}, - {"hi","रद्द करें स्वतः बंद"}, - {"de","Automatisches Schließen abbrechen"} + {"de","&Relay-Karte hinzufügen..."}, + {"hi","मानचित्र &रिले जोड़ें..."}, + {"fr","Ajouter une carte de &relais..."}, + {"zh-chs","添加中继地图 (&R)..."}, + {"fi","Lisää ja välitä kartta ..."}, + {"tr","Haritayı &Geçerek Ekle..."}, + {"cs","Přidat a znovu odeslat mapu ..."}, + {"ja","&リレーマップを追加..."}, + {"es","Agregar y retransmitir mapa ..."}, + {"pl","Dodaj Mapę $Przekierowania..."}, + {"pt","Adicionar & retransmitir mapa ..."}, + {"nl","&Relay toewijzing toevoegen..."}, + {"pt-br","Adicionar & retransmitir mapa ..."}, + {"sv","Lägg till & vidarebefordra karta ..."}, + {"da","Tilføj &Relay Map..."}, + {"ko","릴레이 맵 추가 ..."}, + {"it","Aggiungi &mappa di inoltro..."}, + {"ru","Добавить & карту реле ..."} } }, { - "Open Source, Apache 2.0 License", + "Email verification required", new Dictionary() { - {"nl","Open Source, Apache 2.0 Licentie"}, - {"ko","오픈 소스, Apache 2.0 라이선스"}, - {"fr","Open Source, licence Apache 2.0"}, - {"it","Open Source, licenza Apache 2.0"}, - {"zh-chs","开源,Apache 2.0 许可"}, - {"pt-br","Código aberto, licença Apache 2.0"}, - {"sv","Open Source, Apache 2.0-licens"}, - {"es","Código Abierto, licencia Apache 2.0"}, - {"hi","ओपन सोर्स, अपाचे 2.0 लाइसेंस"}, - {"de","Open Source, Apache 2.0-Lizenz"} + {"de","E-Mail-Verifizierung erforderlich"}, + {"hi","ईमेल सत्यापन आवश्यक"}, + {"fr","Vérification de l'e-mail requise"}, + {"zh-chs","需要电子邮件验证"}, + {"fi","Sähköpostin vahvistus vaaditaan"}, + {"tr","E-posta doğrulaması gerekli"}, + {"cs","Je vyžadováno ověření e -mailem"}, + {"ja","メールによる確認が必要"}, + {"es","Se requiere verificación de correo electrónico"}, + {"pl","Wymagana weryfikacja email"}, + {"pt","Verificação de e-mail necessária"}, + {"nl","E-mailverificatie vereist"}, + {"pt-br","Verificação de e-mail necessária"}, + {"sv","Verifiering av e-post krävs"}, + {"da","E-mail bekræftelse påkrævet"}, + {"ko","이메일 확인 필요"}, + {"it","Verifica e-mail richiesta"}, + {"ru","Требуется подтверждение по электронной почте"} } }, { - "Mappings", + "&Rename", new Dictionary() { - {"nl","Toewijzingen"}, - {"ko","매핑"}, - {"fr","Mappages"}, - {"it","Mappature"}, - {"zh-chs","映射"}, - {"pt-br","Mapeamentos"}, - {"sv","Kartläggningar"}, - {"es","Mapeos"}, - {"hi","मानचित्रण"}, - {"de","Zuordnungen"} + {"de","&Umbenennen"}, + {"hi","&नाम बदलें"}, + {"fr","&Renommer"}, + {"zh-chs","&改名"}, + {"fi","&Nimeä uudelleen"}, + {"tr","&Yeniden isimlendirmek"}, + {"cs","&Přejmenovat"}, + {"ja","&名前の変更"}, + {"es","&Renombrar"}, + {"pl","&Zmień nazwę"}, + {"pt","& Renomear"}, + {"nl","&Hernoemen"}, + {"pt-br","&Renomear"}, + {"sv","&Döp om"}, + {"ko","이름 바꾸기"}, + {"it","&Rinominare"}, + {"ru","&Переименовать"} } }, { - "Devices", + "Unable to write file: {0}", new Dictionary() { - {"de","Geräte"}, - {"hi","उपकरण"}, - {"fr","Dispositifs"}, - {"zh-cht","裝置"}, - {"zh-chs","设备"}, - {"fi","Laitteet"}, - {"tr","Cihazlar"}, - {"cs","Zařízení"}, - {"ja","デバイス"}, - {"es","Dispositivos"}, - {"pt","Dispositivos"}, - {"nl","Apparaten"}, - {"pt-br","Dispositivos"}, - {"sv","Enheter"}, - {"ko","여러 장치"}, - {"it","Dispositivi"}, - {"ru","Устройства"} + {"de","Datei kann nicht geschrieben werden: {0}"}, + {"hi","फ़ाइल लिखने में असमर्थ: {0}"}, + {"fr","Impossible d'écrire dans le fichier : {0}"}, + {"zh-chs","无法写入文件:{0}"}, + {"fi","Tiedoston kirjoittaminen ei onnistu: {0}"}, + {"tr","Dosya yazılamıyor: {0}"}, + {"cs","Nelze zapsat soubor: {0}"}, + {"ja","ファイルを書き込めません:{0}"}, + {"es","No se puede escribir el archivo: {0}"}, + {"pl","Nie można zapisać pliku: {0}"}, + {"pt","Não foi possível gravar o arquivo: {0}"}, + {"nl","Kan bestand: {0} niet schrijven"}, + {"pt-br","No se puede escribir el archivo: {0}"}, + {"sv","Det gick inte att skriva filen: {0}"}, + {"da","Kan ikke skrive fil: {0}"}, + {"ko","파일을 쓸 수 없음: {0}"}, + {"it","Impossibile scrivere il file: {0}"}, + {"ru","Невозможно записать файл: {0}"} } }, { - "(Individual Devices)", + "Application Name", new Dictionary() { - {"nl","(Individuele apparaten)"}, - {"ko","(개별 기기)"}, - {"fr","(Appareils individuels)"}, - {"it","(Dispositivi individuali)"}, - {"zh-chs","(个别设备)"}, - {"pt-br","(Dispositivos Individuais)"}, - {"sv","(Enskilda enheter)"}, - {"es","(Dispositivos individuales)"}, - {"hi","(व्यक्तिगत उपकरण)"}, - {"de","(Einzelgeräte)"} + {"de","Anwendungsname"}, + {"hi","आवेदन का नाम"}, + {"fr","Nom de l'application"}, + {"zh-chs","应用名称"}, + {"fi","sovelluksen nimi"}, + {"tr","Uygulama Adı"}, + {"cs","název aplikace"}, + {"ja","アプリケーション名"}, + {"es","Nombre de la aplicación"}, + {"pl","Nazwa Aplikacji"}, + {"pt","Nome da Aplicação"}, + {"nl","Naam van de toepassing"}, + {"pt-br","Nome do Aplicativo"}, + {"sv","applikationsnamn"}, + {"da","applikationsnavn"}, + {"ko","응용 프로그램 이름"}, + {"it","Nome dell'applicazione"}, + {"ru","Имя приложения"} } }, { - "Privacy Bar", + "WinSCP client", new Dictionary() { - {"de","Datenschutzleiste"}, - {"hi","गोपनीयता बार"}, - {"fr","Barre de confidentialité"}, - {"zh-cht","隱私欄"}, - {"zh-chs","隐私栏"}, - {"fi","Tietosuojapalkki"}, - {"tr","Gizlilik Çubuğu"}, - {"cs","Bar ochrany osobních údajů"}, - {"ja","プライバシーバー"}, - {"es","Barra de Privacidad"}, - {"pt","Barra de Privacidade"}, - {"nl","Privacy balk"}, - {"pt-br","Barra de Privacidade"}, - {"sv","Sekretessfält"}, - {"ko","프라이버시 바"}, - {"it","Privacy bar"}, - {"ru","Панель конфиденциальности"} + {"de","WinSCP-Client"}, + {"hi","विनएससीपी क्लाइंट"}, + {"fr","Client WinSCP"}, + {"zh-chs","WinSCP客户端 "}, + {"fi","WinSCP -asiakas"}, + {"tr","WinSCP istemcisi"}, + {"cs","Klient WinSCP"}, + {"ja","WinSCPクライアント"}, + {"es","Cliente WinSCP"}, + {"pt","Cliente WinSCP"}, + {"pt-br","Cliente WinSCP"}, + {"sv","WinSCP-klient"}, + {"da","WinSCP-klient"}, + {"ko","WinSCP 클라이언트"}, + {"it","Client WinSCP"}, + {"ru","Клиент WinSCP"} } }, { - "Remove {0} items?", + "Device Group", new Dictionary() { - {"nl","{0} items verwijderen?"}, - {"ko","{0} 개 항목을 삭제 하시겠습니까?"}, - {"fr","Supprimer {0} éléments ?"}, - {"it","Rimuovere {0} elementi?"}, - {"zh-chs","删除 {0} 项?"}, - {"pt-br","Remover {0} itens?"}, - {"sv","Ta bort {0} objekt?"}, - {"es","¿Eliminar {0} elementos?"}, - {"hi","{0} आइटम निकालें?"}, - {"de","{0} Elemente entfernen?"} + {"de","Gerätegruppe"}, + {"hi","डिवाइस समूह"}, + {"fr","Groupe d'appareils"}, + {"zh-cht","裝置群"}, + {"zh-chs","设备组"}, + {"fi","Laiteryhmä"}, + {"tr","Cihaz Grubu"}, + {"cs","Skupina zařízení"}, + {"ja","デバイスグループ"}, + {"es","Grupo de Dispositivos"}, + {"pl","Grupa Urządzeń"}, + {"pt","Grupo de dispositivos"}, + {"nl","Apparaat groep"}, + {"pt-br","Grupo de Dispositivos"}, + {"sv","Enhetsgrupp"}, + {"da","Enhedsgruppe"}, + {"ko","장치 그룹"}, + {"it","Gruppo di dispositivi"}, + {"ru","Группа устройства"} } }, { - "This server presented a un-trusted certificate. This may indicate that this is not the correct server or that the server does not have a valid certificate. It is not recommanded, but you can press the ignore button to continue connection to this server.", + "Certificate", new Dictionary() { - {"nl","Deze server heeft een niet-vertrouwd certificaat gepresenteerd. Dit kan erop wijzen dat dit niet de juiste server is of dat de server geen geldig certificaat heeft. Het wordt niet aanbevolen, maar u kunt op de negeren drukken om de verbinding met deze server voort te zetten."}, - {"ko","이 서버는 신뢰할 수없는 인증서를 제공했습니다. 이는 올바른 서버가 아니거나 서버에 유효한 인증서가 없음을 나타낼 수 있습니다. 권장되지는 않지만 무시 버튼을 눌러이 서버에 계속 연결할 수 있습니다."}, - {"fr","Ce serveur a présenté un certificat non approuvé. Cela peut indiquer qu'il ne s'agit pas du bon serveur ou que le serveur n'a pas de certificat valide. Ce n'est pas recommandé, mais vous pouvez appuyer sur le bouton ignorer pour continuer la connexion à ce serveur."}, - {"it","Questo server ha presentato un certificato non attendibile.Questo potrebbe indicare che questo non è il server corretto o che il server non ha un certificato valido.Non è raccomandato, ma puoi premere il pulsante Ignora per continuare la connessione a questo server."}, - {"zh-chs","此服务器提供了不受信任的证书。这可能表明这不是正确的服务器或服务器没有有效的证书。不推荐,但您可以按忽略按钮继续连接到此服务器。"}, - {"pt-br","Este servidor apresentou um certificado não confiável. Isso pode indicar que este não é o servidor correto ou que o servidor não possui um certificado válido. Não é recomendado, mas você pode pressionar o botão de ignorar para continuar a conexão com este servidor."}, - {"sv","Denna server presenterade ett otillförlitligt certifikat. Detta kan indikera att detta inte är rätt server eller att servern inte har ett giltigt certifikat. Det rekommenderas inte, men du kan trycka på ignorera-knappen för att fortsätta anslutningen till den här servern."}, - {"es","Este servidor presentó un certificado no confiable. Esto puede indicar que este no es el servidor correcto o que el servidor no tiene un certificado válido. No se recomienda, pero puedes presionar el botón ignorar para continuar la conexión a este servidor."}, - {"hi","इस सर्वर ने एक अविश्वसनीय प्रमाणपत्र प्रस्तुत किया। यह संकेत दे सकता है कि यह सही सर्वर नहीं है या सर्वर के पास वैध प्रमाणपत्र नहीं है। यह अनुशंसित नहीं है, लेकिन आप इस सर्वर से कनेक्शन जारी रखने के लिए अनदेखा करें बटन दबा सकते हैं।"}, - {"de","Dieser Server hat ein nicht vertrauenswürdiges Zertifikat vorgelegt. Dies kann darauf hinweisen, dass dies nicht der richtige Server ist oder dass der Server nicht über ein gültiges Zertifikat verfügt. Es wird nicht empfohlen, aber Sie können die Ignorieren-Taste drücken, um die Verbindung zu diesem Server fortzusetzen."} + {"de","Zertifikat"}, + {"hi","प्रमाणपत्र"}, + {"fr","Certificat"}, + {"zh-chs","证书"}, + {"fi","Todistus"}, + {"tr","sertifika"}, + {"cs","Osvědčení"}, + {"ja","証明書"}, + {"es","Certificado"}, + {"pl","Certyfikat"}, + {"pt","Certificado"}, + {"nl","Certificaat"}, + {"pt-br","Certificado"}, + {"sv","Certifikat"}, + {"da","Certifikat"}, + {"ko","증명서"}, + {"it","Certificato"}, + {"ru","Сертификат"} } }, { - "Password", + "Changing language will close this tool. Are you sure?", new Dictionary() { - {"de","Passwort"}, - {"hi","कुंजिका"}, - {"fr","Mot de passe"}, - {"zh-cht","密碼"}, - {"zh-chs","密码"}, - {"fi","Salasana"}, - {"tr","Parola"}, - {"cs","Heslo"}, - {"ja","パスワード"}, - {"es","Contraseña"}, - {"pt","Senha"}, - {"nl","Wachtwoord"}, - {"pt-br","Senha"}, - {"sv","Lösenord"}, - {"ko","암호"}, - {"ru","Пароль"} + {"de","Wenn Sie die Sprache ändern, wird dieses Tool geschlossen. Bist du sicher?"}, + {"hi","भाषा बदलने से यह टूल बंद हो जाएगा। क्या आपको यकीन है?"}, + {"fr","Le changement de langue fermera cet outil. Êtes-vous sûr?"}, + {"zh-chs","更改语言将关闭此工具。你确定吗?"}, + {"fi","Kielen vaihtaminen sulkee tämän työkalun. Oletko varma?"}, + {"tr","Dili değiştirmek bu aracı kapatacaktır. Emin misin?"}, + {"cs","Změnou jazyka se tento nástroj zavře. Jsi si jistá?"}, + {"ja","言語を変更すると、このツールは閉じます。本気ですか?"}, + {"es","El cambio de idioma cerrará esta herramienta. ¿Está seguro?"}, + {"pl","Zmiana języka spowoduje zamknięcie tego narzędzia. Czy jesteś pewien?"}, + {"pt","Alterar o idioma fechará esta ferramenta. Tem certeza?"}, + {"nl","Als u de taal wijzigt, wordt deze tool gesloten.Weet je het zeker?"}, + {"pt-br","Alterar o idioma fechará esta ferramenta. Tem certeza?"}, + {"sv","Om du byter språk kommer detta verktyg att stängas. Är du säker?"}, + {"da","Skift af sprog vil lukke dette værktøj. Er du sikker?"}, + {"ko","언어를 변경하면이 도구가 닫힙니다. 확실합니까?"}, + {"it","La modifica della lingua chiuderà questo strumento. Sei sicuro?"}, + {"ru","При изменении языка этот инструмент закроется. Вы уверены?"} } }, { - "Login", + "Enter the second factor authentication token.", new Dictionary() { - {"de","Anmeldung"}, - {"hi","लॉग इन करें"}, - {"fr","Connexion"}, - {"zh-cht","登入"}, - {"zh-chs","登录"}, - {"fi","Kirjaudu sisään"}, - {"tr","Oturum aç"}, - {"cs","Přihlášení"}, - {"ja","ログイン"}, - {"es","Iniciar sesión"}, - {"pt","Entrar"}, - {"nl","Inloggen"}, - {"pt-br","Conecte-se"}, - {"sv","Logga in"}, - {"ko","로그인"}, - {"ru","Войти"} + {"de","Geben Sie das zweite Faktor-Authentifizierungstoken ein."}, + {"hi","दूसरा कारक प्रमाणीकरण टोकन दर्ज करें।"}, + {"fr","Saisissez le jeton d'authentification du deuxième facteur."}, + {"zh-chs","输入第二个因素身份验证令牌。"}, + {"fi","Syötä toinen tekijän todennustunnus."}, + {"tr","İkinci faktörlü kimlik doğrulama belirtecini girin."}, + {"cs","Zadejte druhý ověřovací token faktoru."}, + {"ja","2要素認証トークンを入力します。"}, + {"es","Ingresa el token del segundo factor de autenticación."}, + {"pl","Wprowadź token drugiego elementu uwierzytelniającego."}, + {"pt","Insira o token de autenticação de segundo fator."}, + {"nl","Voer de tweede factor authenticatie token in."}, + {"pt-br","Insira o token de autenticação de segundo fator."}, + {"sv","Ange den andra faktor-autentiseringstoken."}, + {"da","Indtast den anden faktor godkendelsestoken."}, + {"ko","두 번째 요소 인증 토큰을 입력하십시오."}, + {"it","Immettere il token di autenticazione del secondo fattore."}, + {"ru","Введите токен аутентификации второго фактора."} } }, { - "&Save Mappings...", + "Search", new Dictionary() { - {"nl","&Toewijzingen opslaan..."}, - {"ko","매핑 저장 ..."}, - {"fr","&Enregistrer les mappages..."}, - {"it","&Salva mappature..."}, - {"zh-chs","保存映射(&S)..."}, - {"pt-br","& Salvar mapeamentos ..."}, - {"sv","& Spara kartor ..."}, - {"es","&Guardar asignaciones ..."}, - {"hi","&मैपिंग सहेजें..."}, - {"de","&Zuordnungen speichern..."} + {"de","Suche"}, + {"hi","खोज"}, + {"fr","Chercher"}, + {"zh-cht","搜尋"}, + {"zh-chs","搜寻"}, + {"fi","Etsi"}, + {"tr","Arama"}, + {"cs","Hledat"}, + {"ja","サーチ"}, + {"es","Buscar"}, + {"pl","Szukaj"}, + {"pt","Procurar"}, + {"nl","Zoeken"}, + {"pt-br","Procurar"}, + {"sv","Sök"}, + {"da","Søg"}, + {"ko","검색"}, + {"it","Ricerca"}, + {"ru","Поиск"} } }, { - "All Displays", + "Application Link", new Dictionary() { - {"de","Alle Bildschirme"}, - {"hi","सभी प्रदर्शित करता है"}, - {"fr","Tous affichages"}, - {"zh-cht","所有顯示"}, - {"zh-chs","所有显示"}, - {"fi","Kaikki näytöt"}, - {"tr","Tüm Ekranlar"}, - {"cs","Všechny displeje"}, - {"ja","すべてのディスプレイ"}, - {"es","Todas las Pantallas"}, - {"pt","Todas as telas"}, - {"nl","Alle schermen"}, - {"pt-br","Todos os monitores"}, - {"sv","Alla skärmar"}, - {"ko","모든 디스플레이"}, - {"it","Tutti i display"}, - {"ru","Все экраны"} + {"de","Bewerbungslink"}, + {"hi","आवेदन लिंक"}, + {"fr","Lien d'application"}, + {"zh-chs","申请链接"}, + {"fi","Sovelluslinkki"}, + {"tr","Başvuru Bağlantısı"}, + {"cs","Odkaz na aplikaci"}, + {"ja","アプリケーションリンク"}, + {"es","Enlace de aplicación"}, + {"pl","Link Aplikacji"}, + {"pt","Link do aplicativo"}, + {"nl","Applicatielink"}, + {"pt-br","Link do aplicativo"}, + {"sv","Applikationslänk"}, + {"da","Applikationslink"}, + {"ko","응용 프로그램 링크"}, + {"it","Collegamento all'applicazione"}, + {"ru","Ссылка на приложение"} } }, { - "Double Click Action", + "Installation", new Dictionary() { - {"nl","Dubbelklik actie"}, - {"ko","더블 클릭 동작"}, - {"fr","Action de double-clic"}, - {"it","Azione doppio clic"}, - {"zh-chs","双击操作"}, - {"pt-br","Ação de duplo clique"}, - {"sv","Dubbelklicka på åtgärd"}, - {"es","Acción de doble clic"}, - {"hi","डबल क्लिक एक्शन"}, - {"de","Doppelklick-Aktion"} + {"hi","इंस्टालेशन"}, + {"zh-chs","安装"}, + {"fi","Asennus"}, + {"tr","Kurulum"}, + {"cs","Instalace"}, + {"ja","インストール"}, + {"es","Instalación"}, + {"pl","Instalacja"}, + {"pt","Instalação"}, + {"nl","Installatie"}, + {"pt-br","Instalação"}, + {"ko","설치"}, + {"it","Installazione"}, + {"ru","Установка"} } }, { - "Toggle remote desktop connection", + "Application", new Dictionary() { - {"nl","Verbinding met extern bureaublad wisselen"}, - {"ko","원격 데스크톱 연결 전환"}, - {"fr","Basculer la connexion au bureau à distance"}, - {"it","Attiva/disattiva connessione desktop remoto"}, - {"zh-chs","切换远程桌面连接"}, - {"pt-br","Alternar conexão de área de trabalho remota"}, - {"sv","Växla fjärrskrivbordsanslutning"}, - {"es","Alternar la conexión de escritorio remoto"}, - {"hi","दूरस्थ डेस्कटॉप कनेक्शन टॉगल करें"}, - {"de","Remotedesktopverbindung umschalten"} + {"de","Anwendung"}, + {"hi","आवेदन"}, + {"zh-chs","应用"}, + {"fi","Sovellus"}, + {"tr","Başvuru"}, + {"cs","aplikace"}, + {"ja","応用"}, + {"es","Solicitud"}, + {"pl","Aplikacja"}, + {"pt","Aplicativo"}, + {"nl","Toepassing"}, + {"pt-br","Aplicativo"}, + {"sv","Ansökan"}, + {"da","Applikation"}, + {"ko","신청"}, + {"it","Applicazione"}, + {"ru","заявка"} } }, { - "Connect", + "Application Launch", new Dictionary() { - {"de","Verbinden"}, - {"hi","जुडिये"}, - {"fr","Se connecter"}, - {"zh-cht","連接"}, - {"zh-chs","连接"}, - {"fi","Yhdistä"}, - {"tr","Bağlan"}, - {"cs","Připojit"}, - {"ja","つなぐ"}, - {"es","Conectar"}, - {"pt","Conectar"}, - {"nl","Verbinden"}, - {"pt-br","Conectar"}, - {"sv","Anslut"}, - {"ko","연결"}, - {"it","Connetti"}, - {"ru","Подключиться"} + {"de","Anwendungsstart"}, + {"hi","एप्लिकेशन लॉन्च"}, + {"fr","Lancement de l'application"}, + {"zh-chs","应用启动"}, + {"fi","Sovelluksen käynnistäminen"}, + {"tr","Uygulama Başlatma"}, + {"cs","Spuštění aplikace"}, + {"ja","アプリケーションの起動"}, + {"es","Lanzamiento de la aplicación"}, + {"pl","Uruchomienie Aplikacji"}, + {"pt","Lançamento do aplicativo"}, + {"nl","Toepassing starten"}, + {"pt-br","Abrir aplicativo"}, + {"sv","Applikationsstart"}, + {"da","Applikationsstart"}, + {"ko","응용 프로그램 시작"}, + {"it","Lancio dell'applicazione"}, + {"ru","Запуск приложения"} } }, { - "CIRA", + "Timeout", new Dictionary() { - {"hi","सीआईआरए"} + {"de","Auszeit"}, + {"hi","समय समाप्त"}, + {"zh-cht","超時"}, + {"zh-chs","超时"}, + {"fi","Aikakatkaisu"}, + {"tr","Zaman aşımı"}, + {"cs","Časový limit"}, + {"ja","タイムアウト"}, + {"pl","Czas minął"}, + {"pt","Tempo esgotado"}, + {"nl","Time-out"}, + {"pt-br","Tempo esgotado"}, + {"sv","Paus"}, + {"ko","타임 아웃"}, + {"it","Tempo scaduto"}, + {"ru","Тайм-аут"} } }, { - "Mapping Settings", + "0%", new Dictionary() { - {"nl","Kaartinstellingen"}, - {"ko","매핑 설정"}, - {"fr","Paramètres de mappage"}, - {"it","Impostazioni di mappatura"}, - {"zh-chs","映射设置"}, - {"pt-br","Configurações de mapeamento"}, - {"sv","Kartläggningsinställningar"}, - {"es","Configuración de Mapeo"}, - {"hi","मैपिंग सेटिंग्स"}, - {"de","Zuordnungseinstellungen"} + {"ja","0%"}, + {"ko","0 %"} } }, { - ", 1 connection.", + "Failed to start remote desktop session", new Dictionary() { - {"nl",", 1 verbinding."}, - {"ko",", 1 촌."}, - {"fr",", 1 connexion."}, - {"it",", 1 connessione."}, - {"zh-chs",", 1 个连接。"}, - {"pt-br",", 1 conexão."}, - {"sv",", 1 anslutning."}, - {"es",", 1 conexión."}, - {"hi",", 1 कनेक्शन।"}, - {"de",", 1 Verbindung."} - } - }, - { - "HTTPS", - new Dictionary() { - {"hi","HTTPS के"} - } - }, - { - "Install...", - new Dictionary() { - {"nl","Installeren..."}, - {"ko","설치..."}, - {"fr","Installer..."}, - {"it","Installare..."}, - {"zh-chs","安装..."}, - {"pt-br","Instalar..."}, - {"sv","Installera..."}, - {"es","Instalar en pc..."}, - {"hi","इंस्टॉल..."}, - {"de","Installieren..."} + {"de","Fehler beim Starten der Remote-Desktop-Sitzung"}, + {"hi","दूरस्थ डेस्कटॉप सत्र प्रारंभ करने में विफल"}, + {"fr","Échec du démarrage de la session de bureau à distance"}, + {"zh-chs","无法启动远程桌面会话"}, + {"fi","Etätyöpöytäistunnon käynnistäminen epäonnistui"}, + {"tr","Uzak masaüstü oturumu başlatılamadı"}, + {"cs","Spuštění relace vzdálené plochy se nezdařilo"}, + {"ja","リモートデスクトップセッションの開始に失敗しました"}, + {"es","No se pudo iniciar la sesión de escritorio remoto"}, + {"pl","Nie udało się uruchomić sesji pulpitu zdalnego"}, + {"pt","Falha ao iniciar sessão de área de trabalho remota"}, + {"nl","Kan extern bureaubladsessie niet starten"}, + {"pt-br","Falha ao iniciar sessão de área de trabalho remota"}, + {"sv","Det gick inte att starta fjärrskrivbordssessionen"}, + {"da","Kunne ikke starte fjernskrivebordssession"}, + {"ko","원격 데스크톱 세션을 시작하지 못했습니다."}, + {"it","Impossibile avviare la sessione desktop remoto"}, + {"ru","Не удалось запустить сеанс удаленного рабочего стола"} } }, { @@ -3218,7 +2967,7 @@ namespace MeshCentralRouter {"ja","オフライン"}, {"es","Desconectado"}, {"pt","desligada"}, - {"pt-br","desligada"}, + {"pt-br","Desconectado"}, {"sv","Off-line"}, {"ko","오프라인"}, {"it","Disconnesso"}, @@ -3226,38 +2975,791 @@ namespace MeshCentralRouter } }, { - "Timeout", + "&Save Mappings...", new Dictionary() { - {"de","Auszeit"}, - {"hi","समय समाप्त"}, - {"zh-cht","超時"}, - {"zh-chs","超时"}, - {"fi","Aikakatkaisu"}, - {"tr","Zaman aşımı"}, - {"cs","Časový limit"}, - {"ja","タイムアウト"}, - {"pt","Tempo esgotado"}, - {"nl","Time-out"}, - {"pt-br","Tempo esgotado"}, - {"sv","Paus"}, - {"ko","타임 아웃"}, - {"it","Tempo scaduto"}, - {"ru","Тайм-аут"} + {"de","&Zuordnungen speichern..."}, + {"hi","&मैपिंग सहेजें..."}, + {"fr","&Enregistrer les mappages..."}, + {"zh-chs","保存映射(&S)..."}, + {"fi","& Tallenna kartoitukset ..."}, + {"tr","&Eşlemeleri Kaydet..."}, + {"cs","& Uložit mapování ..."}, + {"ja","&マッピングの保存..."}, + {"es","&Guardar asignaciones ..."}, + {"pl","&Zapisz Mapowania..."}, + {"pt","& Salvar mapeamentos ..."}, + {"nl","&Toewijzingen opslaan..."}, + {"pt-br","&Salvar mapeamentos ..."}, + {"sv","& Spara kartor ..."}, + {"ko","매핑 저장 ..."}, + {"it","&Salva mappature..."}, + {"ru","&Сохранить сопоставления..."} + } + }, + { + "Ctrl-Alt-Del", + new Dictionary() { + {"de","Strg-Alt-Entf"} + } + }, + { + "No Devices", + new Dictionary() { + {"de","Keine Geräte"}, + {"hi","कोई उपकरण नहीं"}, + {"fr","Aucun appareil"}, + {"zh-chs","没有设备"}, + {"fi","Ei laitteita"}, + {"tr","Cihaz Yok"}, + {"cs","Žádná zařízení"}, + {"ja","デバイスなし"}, + {"es","Sin Dispositivos"}, + {"pl","Brak Urządzeń"}, + {"pt","Sem dispositivos"}, + {"nl","Geen apparaten"}, + {"pt-br","Sem dispositivos"}, + {"sv","Inga enheter"}, + {"da","Ingen enheder"}, + {"ko","장치 없음"}, + {"it","Nessun Dispositivo"}, + {"ru","Нет устройств"} + } + }, + { + "Click ok to register MeshCentral Router on your system as the handler for the \"mcrouter://\" protocol. This will allow the MeshCentral web site to launch this application when needed.", + new Dictionary() { + {"de","Klicken Sie auf OK, um MeshCentral Router auf Ihrem System als Handler für das Protokoll \"mcrouter://\" zu registrieren. Dadurch kann die MeshCentral-Website diese Anwendung bei Bedarf starten."}, + {"hi","MeshCentral राउटर को अपने सिस्टम पर \"mcrouter: //\" प्रोटोकॉल के लिए हैंडलर के रूप में पंजीकृत करने के लिए ओके पर क्लिक करें। यह मेशसेंट्रल वेब साइट को जरूरत पड़ने पर इस एप्लिकेशन को लॉन्च करने की अनुमति देगा।"}, + {"fr","Cliquez sur ok pour enregistrer MeshCentral Router sur votre système en tant que gestionnaire du protocole « mcrouter:// ». Cela permettra au site Web MeshCentral de lancer cette application en cas de besoin."}, + {"zh-chs","单击确定在您的系统上注册 MeshCentral Router 作为“mcrouter://”协议的处理程序。这将允许 MeshCentral 网站在需要时启动此应用程序。"}, + {"fi","Napsauta ok rekisteröidäksesi MeshCentral Router järjestelmääsi \"mcrouter: //\" -protokollan käsittelijäksi. Tämä antaa MeshCentral -verkkosivuston käynnistää tämän sovelluksen tarvittaessa."}, + {"tr","MeshCentral Router'ı sisteminizde \"mcrouter://\" protokolü için işleyici olarak kaydetmek için Tamam'a tıklayın. Bu, MeshCentral web sitesinin gerektiğinde bu uygulamayı başlatmasını sağlayacaktır."}, + {"cs","Kliknutím na ok zaregistrujete MeshCentral Router ve vašem systému jako obslužný nástroj pro protokol „mcrouter: //“. To umožní webu MeshCentral spustit tuto aplikaci v případě potřeby."}, + {"ja","[OK]をクリックして、システムにMeshCentralルーターを「mcrouter://」プロトコルのハンドラーとして登録します。これにより、MeshCentralWebサイトは必要に応じてこのアプリケーションを起動できるようになります。"}, + {"es","Haz clic en Aceptar para registrar MeshCentral Router en tu sistema como el controlador del protocolo \"mcrouter: //\". Esto permitirá que el sitio web de MeshCentral inicie esta aplicación cuando sea necesario."}, + {"pl","Kliknij ok, aby zarejestrować MeshCentral Router w twoim systemie jako obsługujący protokół \"mcrouter://\". Pozwoli to stronie MeshCentral na uruchomienie tej aplikacji w razie potrzeby."}, + {"pt","Clique em ok para registrar o MeshCentral Router em seu sistema como o manipulador do protocolo \"mcrouter: //\". Isso permitirá que o site MeshCentral inicie esse aplicativo quando necessário."}, + {"nl","Klik op ok om MeshCentral Router op uw systeem te registreren als de handler voor het \"mcrouter://\" protocol. Hierdoor kan de MeshCentral-website deze applicatie starten wanneer dat nodig is."}, + {"pt-br","Clique em ok para registrar o MeshCentral Router em seu sistema como o gerenciador do protocolo \"mcrouter: //\". Isso permitirá que o site MeshCentral inicie esse aplicativo quando necessário."}, + {"sv","Klicka på ok för att registrera MeshCentral Router på ditt system som hanterare för \"mcrouter: //\" -protokollet. Detta gör att MeshCentral-webbplatsen kan starta den här applikationen vid behov."}, + {"da","Klik på ok for at registrere MeshCentral Router på dit system for håndtering af \"mcrouter://\"-protokollen. Dette vil gøre det muligt for MeshCentral-webstedet at starte denne applikation, når det er nødvendigt."}, + {"ko","확인을 클릭하여 \"mcrouter : //\"프로토콜의 핸들러로 시스템에 MeshCentral 라우터를 등록하십시오. 이렇게하면 필요할 때 MeshCentral 웹 사이트에서이 응용 프로그램을 시작할 수 있습니다."}, + {"it","Fare clic su OK per registrare MeshCentral Router sul sistema come gestore per il protocollo \"mcrouter://\". Ciò consentirà al sito Web MeshCentral di avviare questa applicazione quando necessario."}, + {"ru","Нажмите ОК, чтобы зарегистрировать MeshCentral Router в вашей системе в качестве обработчика протокола «mcrouter: //». Это позволит веб-сайту MeshCentral запускать это приложение при необходимости."} + } + }, + { + "Show &Group Names", + new Dictionary() { + {"de","&Gruppennamen anzeigen"}, + {"hi","समूह के नाम दिखाएं"}, + {"fr","Afficher les noms de &groupes"}, + {"zh-chs","显示组名称(&G)"}, + {"fi","Näytä & ryhmien nimet"}, + {"tr","&Grup Adlarını Göster"}, + {"cs","Zobrazit a seskupit jména"}, + {"ja","&グループ名を表示"}, + {"es","Mostrar y nombres de grupos"}, + {"pl","Pokaż Nazwy &Grup"}, + {"pt","Mostrar nomes de grupos"}, + {"nl","Toon &groepsnamen"}, + {"pt-br","Mostrar nomes de grupos"}, + {"sv","Visa & gruppnamn"}, + {"da","Vis &Group navne"}, + {"ko","그룹 이름 표시"}, + {"it","Mostra i nomi dei gruppi"}, + {"ru","Показать и названия групп"} + } + }, + { + "Fast", + new Dictionary() { + {"de","Schnell"}, + {"hi","तेज"}, + {"fr","Vite"}, + {"zh-cht","快速"}, + {"zh-chs","快速"}, + {"fi","Nopea"}, + {"tr","Hızlı"}, + {"cs","Rychle"}, + {"ja","速い"}, + {"es","Rápido"}, + {"pl","Szybko"}, + {"pt","Rápido"}, + {"nl","Snel"}, + {"pt-br","Rápido"}, + {"sv","Snabb"}, + {"da","Hurtig"}, + {"ko","빠른"}, + {"it","Veloce"}, + {"ru","Быстро"} + } + }, + { + "This server presented a un-trusted certificate. This may indicate that this is not the correct server or that the server does not have a valid certificate. It is not recommanded, but you can press the ignore button to continue connection to this server.", + new Dictionary() { + {"de","Dieser Server hat ein nicht vertrauenswürdiges Zertifikat vorgelegt. Dies kann darauf hinweisen, dass dies nicht der richtige Server ist oder dass der Server nicht über ein gültiges Zertifikat verfügt. Es wird nicht empfohlen, aber Sie können die Ignorieren-Taste drücken, um die Verbindung zu diesem Server fortzusetzen."}, + {"hi","इस सर्वर ने एक अविश्वसनीय प्रमाणपत्र प्रस्तुत किया। यह संकेत दे सकता है कि यह सही सर्वर नहीं है या सर्वर के पास वैध प्रमाणपत्र नहीं है। यह अनुशंसित नहीं है, लेकिन आप इस सर्वर से कनेक्शन जारी रखने के लिए अनदेखा करें बटन दबा सकते हैं।"}, + {"fr","Ce serveur a présenté un certificat non approuvé. Cela peut indiquer qu'il ne s'agit pas du bon serveur ou que le serveur n'a pas de certificat valide. Ce n'est pas recommandé, mais vous pouvez appuyer sur le bouton ignorer pour continuer la connexion à ce serveur."}, + {"zh-chs","此服务器提供了不受信任的证书。这可能表明这不是正确的服务器或服务器没有有效的证书。不推荐,但您可以按忽略按钮继续连接到此服务器。"}, + {"fi","Tämä palvelin esitti epäluotettavan varmenteen. Tämä voi tarkoittaa, että tämä ei ole oikea palvelin tai että palvelimella ei ole kelvollista varmennetta. Sitä ei suositella, mutta voit jatkaa yhteyttä tähän palvelimeen painamalla ohituspainiketta."}, + {"tr","Bu sunucu güvenilmeyen bir sertifika sundu. Bu, bunun doğru sunucu olmadığını veya sunucunun geçerli bir sertifikası olmadığını gösterebilir. Tavsiye edilmez, ancak bu sunucuyla bağlantıya devam etmek için yoksay düğmesine basabilirsiniz."}, + {"cs","Tento server předložil nedůvěryhodný certifikát. Může to znamenat, že to není správný server nebo že server nemá platný certifikát. Nedoporučuje se to, ale můžete pokračovat v připojení k tomuto serveru stisknutím tlačítka ignorovat."}, + {"ja","このサーバーは、信頼できない証明書を提示しました。これは、これが正しいサーバーではないか、サーバーに有効な証明書がないことを示している可能性があります。推奨されていませんが、無視ボタンを押してこのサーバーへの接続を続行できます。"}, + {"es","Este servidor presentó un certificado no confiable. Esto puede indicar que este no es el servidor correcto o que el servidor no tiene un certificado válido. No se recomienda, pero puedes presionar el botón ignorar para continuar la conexión a este servidor."}, + {"pl","Ten serwer przedstawił niezaufany certyfikat. Może to oznaczać, że nie jest to właściwy serwer lub że serwer nie posiada ważnego certyfikatu. Nie jest to zalecane, ale możesz nacisnąć przycisk ignoruj, aby kontynuować połączenie z tym serwerem."}, + {"pt","Este servidor apresentou um certificado não confiável. Isso pode indicar que este não é o servidor correto ou que o servidor não possui um certificado válido. Não é recomendado, mas você pode pressionar o botão de ignorar para continuar a conexão com este servidor."}, + {"nl","Deze server heeft een niet-vertrouwd certificaat gepresenteerd. Dit kan erop wijzen dat dit niet de juiste server is of dat de server geen geldig certificaat heeft. Het wordt niet aanbevolen, maar u kunt op de negeren drukken om de verbinding met deze server voort te zetten."}, + {"pt-br","Este servidor apresentou um certificado não confiável. Isso pode indicar que este não é o servidor correto ou que o servidor não possui um certificado válido. Não é recomendado, mas você pode pressionar o botão de ignorar para continuar a conexão com este servidor."}, + {"sv","Denna server presenterade ett otillförlitligt certifikat. Detta kan indikera att detta inte är rätt server eller att servern inte har ett giltigt certifikat. Det rekommenderas inte, men du kan trycka på ignorera-knappen för att fortsätta anslutningen till den här servern."}, + {"da","Denne server præsenterede et certifikat, der ikke er tillid til. Dette kan indikere, at dette ikke er den rigtige server, eller at serveren ikke har et gyldigt certifikat. Det anbefales ikke, men du kan trykke på ignorer-knappen for at fortsætte forbindelsen til denne server."}, + {"ko","이 서버는 신뢰할 수없는 인증서를 제공했습니다. 이는 올바른 서버가 아니거나 서버에 유효한 인증서가 없음을 나타낼 수 있습니다. 권장되지는 않지만 무시 버튼을 눌러이 서버에 계속 연결할 수 있습니다."}, + {"it","Questo server ha presentato un certificato non attendibile.Questo potrebbe indicare che questo non è il server corretto o che il server non ha un certificato valido.Non è raccomandato, ma puoi premere il pulsante Ignora per continuare la connessione a questo server."}, + {"ru","Этот сервер представил ненадежный сертификат. Это может означать, что это неправильный сервер или что у сервера нет действующего сертификата. Это не рекомендуется, но вы можете нажать кнопку игнорирования, чтобы продолжить подключение к этому серверу."} + } + }, + { + "R&efresh", + new Dictionary() { + {"de","Aktualisierung"}, + {"hi","ताज़ा करें"}, + {"fr","Rafraîchir"}, + {"zh-chs","刷新"}, + {"fi","Virkistää"}, + {"tr","¥ile"}, + {"cs","Obnovit"}, + {"ja","R&efresh"}, + {"es","Actualizar"}, + {"pl","Odśwież (R&)"}, + {"pt","R & efresh"}, + {"nl","Vernieuwen"}, + {"pt-br","Atualizar"}, + {"sv","R & efresh"}, + {"ko","새롭게 하다"}, + {"ru","R & efresh"} + } + }, + { + "Scaling", + new Dictionary() { + {"de","Skalierung"}, + {"hi","स्केलिंग"}, + {"fr","Mise à l'échelle"}, + {"zh-cht","縮放比例"}, + {"zh-chs","缩放比例"}, + {"fi","Skaalaus"}, + {"tr","Ölçeklendirme"}, + {"cs","Škálování"}, + {"ja","スケーリング"}, + {"es","Escala"}, + {"pl","Skalowanie"}, + {"pt","Dimensionamento"}, + {"nl","Schalen"}, + {"pt-br","Dimensionamento"}, + {"sv","Skalning"}, + {"da","Skalering"}, + {"ko","비율"}, + {"it","Ridimensionamento"}, + {"ru","Маштабирование"} + } + }, + { + "Send token to registered phone number?", + new Dictionary() { + {"de","Token an registrierte Telefonnummer senden?"}, + {"hi","विनियमित फोन नंबर पर टोकन भेजें?"}, + {"fr","Envoyer un jeton au numéro de téléphone enregistré?"}, + {"zh-cht","將保安編碼發送到註冊電話號碼?"}, + {"zh-chs","将保安编码发送到注册电话号码?"}, + {"fi","Lähetetäänkö tunnus rekisteröityyn puhelinnumeroon?"}, + {"tr","Belirteç kayıtlı telefon numarasına gönderilsin mi?"}, + {"cs","Poslat token na registrované telefonní číslo?"}, + {"ja","登録した電話番号にトークンを送信しますか?"}, + {"es","¿Enviar token al número de teléfono registrado?"}, + {"pl","Wysłać token na zarejestrowany numer telefonu?"}, + {"pt","Enviar token para o número de telefone registrado?"}, + {"nl","Token naar geregistreerd telefoonnummer verzenden?"}, + {"pt-br","Enviar token para o número de telefone registrado?"}, + {"sv","Skicka token till registrerat telefonnummer?"}, + {"da","Send token til registreret telefonnummer?"}, + {"ko","등록된 휴대폰 번호로 토큰을 보내시겠습니까?"}, + {"it","Invia token al numero di telefono registrato?"}, + {"ru","Отправить токен на зарегистрированный номер телефона?"} + } + }, + { + "{0} Kbytes/sec", + new Dictionary() { + {"de","{0} Kbyte/s"}, + {"hi","{0} किलोबाइट/सेकंड"}, + {"zh-chs","{0} KB/秒"}, + {"fi","{0} Kt/sek"}, + {"tr","{0} Kbayt/sn"}, + {"cs","{0} kB/s"}, + {"ja","{0}キロバイト/秒"}, + {"es","{0} Kbytes / seg"}, + {"pl","{0} KB/s"}, + {"pt","{0} Kbytes / s"}, + {"pt-br","{0} Kbytes / seg"}, + {"sv","{0} Kbyte/sek"}, + {"da","{0} Kbytes/sek"}, + {"ko","{0}KB/초"}, + {"it","{0} Kbyte/sec"}, + {"ru","{0} Кбайт / с"} + } + }, + { + "Ignore", + new Dictionary() { + {"de","Ignorieren"}, + {"hi","नज़रअंदाज़ करना"}, + {"fr","Ignorer"}, + {"zh-chs","忽略"}, + {"fi","Jättää huomiotta"}, + {"tr","Görmezden gelmek"}, + {"cs","Ignorovat"}, + {"ja","無視"}, + {"es","Ignorar"}, + {"pl","Ignoruj"}, + {"pt","Ignorar"}, + {"nl","Negeren"}, + {"pt-br","Ignorar"}, + {"sv","Strunta i"}, + {"da","Ignorér"}, + {"ko","무시"}, + {"it","Ignorare"}, + {"ru","Игнорировать"} + } + }, + { + "Port Mapping", + new Dictionary() { + {"de","Port-Mapping"}, + {"hi","पोर्ट मानचित्रण"}, + {"fr","Mappage des ports"}, + {"zh-chs","端口映射"}, + {"fi","Portin kartoitus"}, + {"tr","Liman Haritalama"}, + {"cs","Mapování portů"}, + {"ja","ポートマッピング"}, + {"es","Mapeo de Puertos"}, + {"pl","Mapowanie Portu"}, + {"pt","Mapeamento de portas"}, + {"nl","Poorttoewijzing"}, + {"pt-br","Mapeamento de portas"}, + {"sv","Portmappning"}, + {"ko","포트 매핑"}, + {"it","Mappatura delle porte"}, + {"ru","Отображение портов"} + } + }, + { + "Update", + new Dictionary() { + {"de","Updates"}, + {"hi","अपडेट करें"}, + {"fr","Mettre à jour"}, + {"zh-cht","更新資料"}, + {"zh-chs","更新资料"}, + {"fi","Päivittää"}, + {"tr","Güncelleme"}, + {"cs","Aktualizace"}, + {"ja","更新"}, + {"es","Actualizar"}, + {"pl","Aktualizacja"}, + {"pt","Atualizar"}, + {"nl","Bijwerken"}, + {"pt-br","Atualizar"}, + {"sv","Uppdatering"}, + {"da","Opdatering"}, + {"ko","개조하다"}, + {"it","Aggiornamenti"}, + {"ru","Обновить"} + } + }, + { + "RDP", + new Dictionary() { + {"hi","आरडीपी"} + } + }, + { + "Almost done", + new Dictionary() { + {"de","Fast fertig"}, + {"hi","लगभग हो गया"}, + {"fr","Bientôt terminé"}, + {"zh-chs","快完成了"}, + {"fi","Melkein valmis"}, + {"tr","Neredeyse bitti"}, + {"cs","Skoro hotovo"}, + {"ja","ほぼ完了しました"}, + {"es","Casi termino"}, + {"pl","Prawie skończone"}, + {"pt","Quase pronto"}, + {"nl","Bijna klaar"}, + {"pt-br","Quase Pronto"}, + {"sv","Nästan klar"}, + {"da","Næsten klar"}, + {"ko","거의 완료"}, + {"it","Quasi fatto"}, + {"ru","Почти сделано"} + } + }, + { + "Remove {0} items?", + new Dictionary() { + {"de","{0} Elemente entfernen?"}, + {"hi","{0} आइटम निकालें?"}, + {"fr","Supprimer {0} éléments ?"}, + {"zh-chs","删除 {0} 项?"}, + {"fi","Poistetaanko {0} kohdetta?"}, + {"tr","{0} öğe kaldırılsın mı?"}, + {"cs","Odstranit {0} položek?"}, + {"ja","{0}アイテムを削除しますか?"}, + {"es","¿Eliminar {0} elementos?"}, + {"pl","Usunać {0} elementów?"}, + {"pt","Remover {0} itens?"}, + {"nl","{0} items verwijderen?"}, + {"pt-br","Remover {0} itens?"}, + {"sv","Ta bort {0} objekt?"}, + {"da","Fjern {0} elementer?"}, + {"ko","{0} 개 항목을 삭제 하시겠습니까?"}, + {"it","Rimuovere {0} elementi?"}, + {"ru","Удалить элементы ({0})?"} + } + }, + { + "Remote Port", + new Dictionary() { + {"de","Remote-Port"}, + {"hi","रिमोट पोर्ट"}, + {"fr","Port distant"}, + {"zh-chs","远程端口"}, + {"fi","Etäportti"}, + {"tr","Uzak Bağlantı Noktası"}, + {"cs","Vzdálený port"}, + {"ja","リモートポート"}, + {"es","Puerto Remoto"}, + {"pl","Zdalny Port"}, + {"pt","Porta Remota"}, + {"nl","Externe poort"}, + {"pt-br","Porta Remota"}, + {"sv","Fjärrport"}, + {"da","Fjernport"}, + {"ko","원격 포트"}, + {"it","Porta remota"}, + {"ru","Удаленный порт"} + } + }, + { + "Cancel", + new Dictionary() { + {"de","Abbrechen"}, + {"hi","रद्द करना"}, + {"fr","Annuler"}, + {"zh-cht","取消"}, + {"zh-chs","取消"}, + {"fi","Peruuta"}, + {"tr","İptal"}, + {"cs","Storno"}, + {"ja","キャンセル"}, + {"es","Cancelar"}, + {"pl","Anuluj"}, + {"pt","Cancelar"}, + {"nl","Annuleren"}, + {"pt-br","Cancelar"}, + {"sv","Avbryt"}, + {"da","Annuller"}, + {"ko","취소"}, + {"it","Annulla"}, + {"ru","Отмена"} + } + }, + { + "Alternative Port", + new Dictionary() { + {"de","Alternativer Hafen"}, + {"hi","वैकल्पिक बंदरगाह"}, + {"fr","Port alternatif"}, + {"zh-chs","替代端口"}, + {"fi","Vaihtoehtoinen portti"}, + {"tr","Alternatif Bağlantı Noktası"}, + {"cs","Alternativní port"}, + {"ja","代替ポート"}, + {"es","Puerto Alternativo"}, + {"pl","Alternatywny Port"}, + {"pt","Porto Alternativo"}, + {"nl","Alternatieve poort"}, + {"pt-br","Porta Alternativa"}, + {"sv","Alternativ hamn"}, + {"da","Alternativ port"}, + {"ko","대체 포트"}, + {"it","Porta alternativa"}, + {"ru","Альтернативный порт"} + } + }, + { + "Toggle zoom-to-fit mode", + new Dictionary() { + {"de","Zoom-to-Fit-Modus umschalten"}, + {"hi","ज़ूम-टू-फ़िट मोड टॉगल करें"}, + {"fr","Basculer en mode zoom pour ajuster"}, + {"zh-chs","切换缩放至适合模式"}, + {"fi","Vaihda sovitustila"}, + {"tr","Sığdırmak için yakınlaştırma modunu değiştir"}, + {"cs","Přepnout režim přiblížení a přizpůsobení"}, + {"ja","ズームしてフィットモードを切り替えます"}, + {"es","Alternar el modo de zoom para ajustar"}, + {"pl","Przełączanie trybu powiększania na dopasowanie"}, + {"pt","Alternar modo de zoom para ajustar"}, + {"nl","Schakel inzoemen naar passend modus in"}, + {"pt-br","Alternar modo de zoom para ajustar"}, + {"sv","Växla zoom-to-fit-läge"}, + {"da","Skift zoom-for-tilpasning tilstand"}, + {"ko","확대 / 축소 모드 전환"}, + {"it","Attiva/disattiva la modalità zoom per adattare"}, + {"ru","Переключить режим масштабирования по размеру"} + } + }, + { + "Remote Files...", + new Dictionary() { + {"de","Remote-Dateien..."}, + {"hi","दूरस्थ फ़ाइलें..."}, + {"fr","Fichiers distants..."}, + {"zh-chs","远程文件..."}, + {"fi","Etätiedostot ..."}, + {"tr","Uzak Dosyalar..."}, + {"cs","Vzdálené soubory ..."}, + {"ja","リモートファイル..."}, + {"es","Archivos Remotos ..."}, + {"pl","Zdalne Pliki..."}, + {"pt","Arquivos remotos ..."}, + {"nl","Externe bestanden..."}, + {"pt-br","Arquivos remotos ..."}, + {"sv","Fjärrfiler ..."}, + {"da","Fjernfiler..."}, + {"ko","원격 파일 ..."}, + {"it","File remoti..."}, + {"ru","Удаленные файлы ..."} + } + }, + { + "HTTPS", + new Dictionary() { + {"hi","HTTPS के"} } }, { "Compressed Network Traffic", new Dictionary() { - {"nl","Gecomprimeerd netwerkverkeer"}, - {"ko","압축 된 네트워크 트래픽"}, + {"de","Komprimierter Netzwerkverkehr"}, + {"hi","संपीडित नेटवर्क यातायात"}, {"fr","Trafic réseau compressé"}, - {"it","Traffico di rete compresso"}, {"zh-chs","压缩网络流量"}, + {"fi","Pakattu verkkoliikenne"}, + {"tr","Sıkıştırılmış Ağ Trafiği"}, + {"cs","Komprimovaný síťový provoz"}, + {"ja","圧縮されたネットワークトラフィック"}, + {"es","Tráfico de red comprimido"}, + {"pl","Skompresowany Ruch Sieciowy"}, + {"pt","Tráfego de rede comprimido"}, + {"nl","Gecomprimeerd netwerkverkeer"}, {"pt-br","Tráfego de rede comprimido"}, {"sv","Komprimerad nätverkstrafik"}, - {"es","Tráfico de red comprimido"}, - {"hi","संपीडित नेटवर्क यातायात"}, - {"de","Komprimierter Netzwerkverkehr"} + {"da","Komprimeret netværkstrafik"}, + {"ko","압축 된 네트워크 트래픽"}, + {"it","Traffico di rete compresso"}, + {"ru","Сжатый сетевой трафик"} + } + }, + { + "Received invalid network data", + new Dictionary() { + {"de","Ungültige Netzwerkdaten empfangen"}, + {"hi","अमान्य नेटवर्क डेटा प्राप्त किया"}, + {"fr","Données réseau reçues non valides"}, + {"zh-cht","收到無效的網絡數據"}, + {"zh-chs","收到无效的网络数据"}, + {"fi","Vastaanotettu virheellisiä verkkotietoja"}, + {"tr","Geçersiz ağ verileri alındı"}, + {"cs","Přijata neplatná síťová data"}, + {"ja","無効なネットワークデータを受信しました"}, + {"es","Se recibieron datos de red inválidos"}, + {"pl","Odebrano nieprawidłowe dane sieciowe"}, + {"pt","Dados de rede inválidos recebidos"}, + {"nl","Ongeldige netwerkgegevens ontvangen"}, + {"pt-br","Dados de rede inválidos recebidos"}, + {"sv","Mottog ogiltig nätverksdata"}, + {"da","Modtog ugyldige netværksdata"}, + {"ko","잘못된 네트워크 데이터를 받았습니다."}, + {"it","Dati di rete non validi ricevuti"}, + {"ru","Получены неверные сетевые данные"} + } + }, + { + "UDP", + new Dictionary() { + {"hi","यूडीपी"} + } + }, + { + "Invalid username or password", + new Dictionary() { + {"de","ungültiger Benutzername oder Passwort"}, + {"hi","अमान्य उपयोगकर्ता नाम या पासवर्ड"}, + {"fr","Nom d'utilisateur ou mot de passe invalide"}, + {"zh-chs","无效的用户名或密码"}, + {"fi","väärä käyttäjänimi tai salasana"}, + {"tr","Geçersiz kullanıcı adı veya şifre"}, + {"cs","neplatné uživatelské jméno nebo heslo"}, + {"ja","無効なユーザー名またはパスワード"}, + {"es","Usuario o contraseña invalido"}, + {"pl","Nieprawidłowa nazwa użytkownika lub hasło"}, + {"pt","nome de usuário ou senha inválidos"}, + {"nl","Ongeldige gebruikersnaam of wachtwoord"}, + {"pt-br","nome de usuário ou senha inválidos"}, + {"sv","Ogiltigt användarnamn eller lösenord"}, + {"da","Ugyldigt brugernavn eller kodeord"}, + {"ko","잘못된 사용자 이름 또는 비밀번호"}, + {"it","Username o password non validi"}, + {"ru","неправильное имя пользователя или пароль"} + } + }, + { + "Bind local port to all network interfaces", + new Dictionary() { + {"de","Binden Sie den lokalen Port an alle Netzwerkschnittstellen"}, + {"hi","स्थानीय पोर्ट को सभी नेटवर्क इंटरफेस से बाइंड करें"}, + {"fr","Lier le port local à toutes les interfaces réseau"}, + {"zh-chs","将本地端口绑定到所有网络接口"}, + {"fi","Sido paikallinen portti kaikkiin verkkoliitäntöihin"}, + {"tr","Yerel bağlantı noktasını tüm ağ arabirimlerine bağlayın"}, + {"cs","Vázat místní port na všechna síťová rozhraní"}, + {"ja","ローカルポートをすべてのネットワークインターフェイスにバインドする"}, + {"es","Vincular el puerto local a todas las interfaces de red"}, + {"pl","Przypisz port lokalny do wszystkich interfejsów sieciowych"}, + {"pt","Vincule a porta local a todas as interfaces de rede"}, + {"nl","Bind lokale poort aan alle netwerkinterfaces"}, + {"pt-br","Vincule a porta local a todas as interfaces de rede"}, + {"sv","Binda lokal port till alla nätverksgränssnitt"}, + {"da","Bind lokal port til alle netværksinterfaces"}, + {"ko","모든 네트워크 인터페이스에 로컬 포트 ​​바인딩"}, + {"it","Associa la porta locale a tutte le interfacce di rete"}, + {"ru","Привязать локальный порт ко всем сетевым интерфейсам"} + } + }, + { + "Outgoing Compression", + new Dictionary() { + {"de","Ausgehende Komprimierung"}, + {"hi","आउटगोइंग संपीड़न"}, + {"fr","Compression sortante"}, + {"zh-chs","输出压缩"}, + {"fi","Lähtevä pakkaus"}, + {"tr","Giden Sıkıştırma"}, + {"cs","Odchozí komprese"}, + {"ja","発信圧縮"}, + {"es","Compresión Saliente"}, + {"pl","Kompresja Wychodząca"}, + {"pt","Compressão de saída"}, + {"nl","Uitgaande compressie"}, + {"pt-br","Compressão de saída"}, + {"sv","Utgående kompression"}, + {"da","Udgående kompression"}, + {"ko","나가는 압축"}, + {"it","Compressione in uscita"}, + {"ru","Исходящее сжатие"} + } + }, + { + "Mapping Settings", + new Dictionary() { + {"de","Zuordnungseinstellungen"}, + {"hi","मैपिंग सेटिंग्स"}, + {"fr","Paramètres de mappage"}, + {"zh-chs","映射设置"}, + {"fi","Kartoitusasetukset"}, + {"tr","Eşleme Ayarları"}, + {"cs","Nastavení mapování"}, + {"ja","マッピング設定"}, + {"es","Configuración de Mapeo"}, + {"pl","Ustawienia Mapowania"}, + {"pt","Configurações de mapeamento"}, + {"nl","Kaartinstellingen"}, + {"pt-br","Configurações de mapeamento"}, + {"sv","Kartläggningsinställningar"}, + {"da","Indstillinger for kortlægning"}, + {"ko","매핑 설정"}, + {"it","Impostazioni di mappatura"}, + {"ru","Настройки отображения"} + } + }, + { + "Back", + new Dictionary() { + {"de","Zurück"}, + {"hi","वापस"}, + {"fr","Retour"}, + {"zh-cht","返回"}, + {"zh-chs","返回"}, + {"fi","Takaisin"}, + {"tr","Geri"}, + {"cs","Zpět"}, + {"ja","バック"}, + {"es","Atrás"}, + {"pl","Powrót"}, + {"pt","Voltar"}, + {"nl","Terug"}, + {"pt-br","Voltar"}, + {"sv","Tillbaka"}, + {"da","Tilbage"}, + {"ko","뒤로"}, + {"it","Indietro"}, + {"ru","Назад"} + } + }, + { + "{0} bytes/sec", + new Dictionary() { + {"de","{0} Byte/Sek."}, + {"hi","{0} बाइट्स/सेकंड"}, + {"zh-chs","{0} 字节/秒"}, + {"fi","{0} tavua/sek"}, + {"tr","{0} bayt/sn"}, + {"cs","{0} bajtů/s"}, + {"ja","{0}バイト/秒"}, + {"es","{0} bytes / seg"}, + {"pl","{0} bajtów/s"}, + {"pt","{0} bytes / s"}, + {"pt-br","{0} bytes / seg"}, + {"sv","{0} byte/sek"}, + {"da","{0} bytes/sek"}, + {"ko","{0}바이트/초"}, + {"it","{0} byte/sec"}, + {"ru","{0} байт / сек"} + } + }, + { + "Enhanced keyboard capture", + new Dictionary() { + {"de","Verbesserte Tastaturerfassung"}, + {"hi","उन्नत कीबोर्ड कैप्चर"}, + {"fr","Capture de clavier améliorée"}, + {"zh-chs","增强的键盘捕获"}, + {"fi","Parannettu näppäimistön sieppaus"}, + {"tr","Gelişmiş klavye yakalama"}, + {"cs","Vylepšené snímání klávesnice"}, + {"ja","強化されたキーボードキャプチャ"}, + {"es","Captura de teclado mejorada"}, + {"pl","Ulepszone przechwytywanie klawiatury"}, + {"pt","Captura de teclado aprimorada"}, + {"nl","Verbeterde toetsenbordopname"}, + {"pt-br","Captura de teclado aprimorada"}, + {"sv","Förbättrad tangentbordsfångst"}, + {"da","Forbedret tastatur optagelse"}, + {"ko","향상된 키보드 캡처"}, + {"it","Acquisizione avanzata della tastiera"}, + {"ru","Улучшенный захват клавиатуры"} + } + }, + { + "Display connection statistics", + new Dictionary() { + {"de","Verbindungsstatistik anzeigen"}, + {"hi","कनेक्शन आंकड़े प्रदर्शित करें"}, + {"fr","Afficher les statistiques de connexion"}, + {"zh-chs","显示连接统计"}, + {"fi","Näytä yhteystilastot"}, + {"tr","Bağlantı istatistiklerini görüntüle"}, + {"cs","Zobrazit statistiky připojení"}, + {"ja","接続統計を表示する"}, + {"es","Mostrar estadísticas de conexión"}, + {"pl","Wyświetl statystyki połączeń"}, + {"pt","Exibir estatísticas de conexão"}, + {"nl","Verbindingsstatistieken weergeven"}, + {"pt-br","Exibir estatísticas de conexão"}, + {"sv","Visa anslutningsstatistik"}, + {"da","Vis forbindelsesstatistikker"}, + {"ko","연결 통계 표시"}, + {"it","Visualizza le statistiche di connessione"}, + {"ru","Показать статистику подключений"} + } + }, + { + "Install...", + new Dictionary() { + {"de","Installieren..."}, + {"hi","इंस्टॉल..."}, + {"fr","Installer..."}, + {"zh-chs","安装..."}, + {"fi","Asentaa..."}, + {"tr","Düzenlemek..."}, + {"cs","Nainstalujte..."}, + {"ja","インストール..."}, + {"es","Instalar en pc..."}, + {"pl","Instaluj..."}, + {"pt","Instalar..."}, + {"nl","Installeren..."}, + {"pt-br","Instalar..."}, + {"sv","Installera..."}, + {"da","Installere..."}, + {"ko","설치..."}, + {"it","Installare..."}, + {"ru","Установить..."} + } + }, + { + "MQTT", + new Dictionary() { + {"it","MQTT "} + } + }, + { + "Server information", + new Dictionary() { + {"de","Serverinformation"}, + {"hi","सर्वर जानकारी"}, + {"fr","Informations sur le serveur"}, + {"zh-chs","服务器信息"}, + {"fi","Palvelimen tiedot"}, + {"tr","Sunucu bilgileri"}, + {"cs","Informace o serveru"}, + {"ja","サーバー情報"}, + {"es","Información del Servidor"}, + {"pl","Informacje o Serwerze"}, + {"pt","Informação do servidor"}, + {"nl","Server informatie"}, + {"pt-br","Informação do servidor"}, + {"sv","Serverinformation"}, + {"ko","서버 정보"}, + {"it","Informazioni sul server"}, + {"ru","Информация о сервере"} + } + }, + { + "Use Remote Keyboard Map", + new Dictionary() { + {"de","Entfernte Tastaturbelegung verwenden"}, + {"hi","रिमोट कीबोर्ड मैप का उपयोग करें"}, + {"fr","Utiliser la configuration du clavier distant"}, + {"zh-cht","使用遠程鍵盤映射"}, + {"zh-chs","使用远程键盘映射"}, + {"fi","Käytä kaukonäppäimistökarttaa"}, + {"tr","Uzak Klavye Haritasını Kullan"}, + {"cs","Použijte Mapu vzdálené klávesnice"}, + {"ja","リモートキーボードマップを使用する"}, + {"es","Usar Mapa de Teclado Remoto"}, + {"pl","Użyj Mapy Klawiatury Zdalnego Urządzenia"}, + {"pt","Use o mapa do teclado remoto"}, + {"nl","Gebruik de externe toetsenbord instelling"}, + {"pt-br","Use o mapa do teclado remoto"}, + {"sv","Använd Remote Keyboard Map"}, + {"da","Brug fjerntastatur mapning"}, + {"ko","원격 키보드 맵 사용"}, + {"it","Usa mappa tastiera remota "}, + {"ru","Использовать карту удаленной клавиатуры"} } }, { @@ -3273,76 +3775,1127 @@ namespace MeshCentralRouter {"cs","Odpojit"}, {"ja","切断する"}, {"es","Desconectar"}, + {"pl","Rozłącz"}, {"pt","Desconectar"}, {"nl","Verbreken"}, - {"pt-br","desconectar"}, + {"pt-br","Desconectar"}, {"sv","Koppla ifrån"}, + {"da","Afbryd"}, {"ko","연결 해제"}, {"it","Disconnetti"}, {"ru","Разъединить"} } }, { - "Remote Desktop Settings", + "Overwrite 1 file?", new Dictionary() { - {"de","Einstellungen des entfernten Desktops"}, - {"hi","दूरस्थ डेस्कटॉप सेटिंग्स"}, - {"fr","Paramètres du bureau à distance"}, - {"zh-cht","遠程桌面設置"}, - {"zh-chs","远程桌面设置"}, - {"fi","Etätyöpöydän asetukset"}, - {"tr","Uzak Masaüstü Ayarları"}, - {"cs","Nastavení vzdálené plochy"}, - {"ja","リモートデスクトップ設定"}, - {"es","Opciones de Escritorio Remoto"}, - {"pt","Configurações da área de trabalho remota"}, - {"nl","Instellingen extern bureaublad"}, - {"pt-br","Configurações de área de trabalho remota"}, - {"sv","Fjärrskrivbordsinställningar"}, - {"ko","원격 데스크톱 설정"}, - {"it","Impostazioni desktop remoto"}, - {"ru","Настройки удаленного рабочего стола"} + {"de","1 Datei überschreiben?"}, + {"hi","1 फ़ाइल को अधिलेखित करें?"}, + {"fr","Écraser 1 fichier ?"}, + {"zh-chs","覆盖 1 个文件?"}, + {"fi","Korvataanko 1 tiedosto?"}, + {"tr","1 dosyanın üzerine yazılsın mı?"}, + {"cs","Přepsat 1 soubor?"}, + {"ja","1つのファイルを上書きしますか?"}, + {"es","¿Sobrescribir 1 archivo?"}, + {"pl","Zastąpić 1 plik?"}, + {"pt","Substituir 1 arquivo?"}, + {"nl","1 bestand overschrijven?"}, + {"pt-br","Sobrescrever 1 arquivo?"}, + {"sv","Skriv över 1 fil?"}, + {"da","Overskriv 1 fil?"}, + {"ko","파일 1개를 덮어쓰시겠습니까?"}, + {"it","Sovrascrivere 1 file?"}, + {"ru","Перезаписать 1 файл?"} } }, { - "Installation", + "Send Ctrl-Alt-Del to remote device", new Dictionary() { - {"nl","Installatie"}, - {"ko","설치"}, - {"it","Installazione"}, - {"zh-chs","安装"}, - {"pt-br","Instalação"}, - {"es","Instalación"}, - {"hi","इंस्टालेशन"} + {"de","Strg-Alt-Entf an Remote-Gerät senden"}, + {"hi","रिमोट डिवाइस पर Ctrl-Alt-Del भेजें"}, + {"fr","Envoyer Ctrl-Alt-Suppr à l'appareil distant"}, + {"zh-chs","发送 Ctrl-Alt-Del 到远程设备"}, + {"fi","Lähetä Ctrl-Alt-Del etälaitteeseen"}, + {"tr","Uzak cihaza Ctrl-Alt-Del gönder"}, + {"cs","Odeslat Ctrl-Alt-Del na vzdálené zařízení"}, + {"ja","Ctrl-Alt-Delをリモートデバイスに送信します"}, + {"es","Enviar Ctrl-Alt-Del al dispositivo remoto"}, + {"pl","Wyślij Ctrl-Alt-Del do urządzenia zdalnego"}, + {"pt","Envie Ctrl-Alt-Del para o dispositivo remoto"}, + {"nl","Stuur Ctrl-Alt-Del naar extern apparaat"}, + {"pt-br","Envie Ctrl-Alt-Del para o dispositivo remoto"}, + {"sv","Skicka Ctrl-Alt-Del till fjärrenhet"}, + {"da","Send Ctrl-Alt-Del til fjernenhed"}, + {"ko","Ctrl-Alt-Del을 원격 장치로 보내기"}, + {"it","Invia Ctrl-Alt-Canc al dispositivo remoto"}, + {"ru","Отправить Ctrl-Alt-Del на удаленное устройство"} } }, { - "Remote Port", + "Show on system tray", new Dictionary() { - {"nl","Externe poort"}, - {"ko","원격 포트"}, - {"fr","Port distant"}, - {"it","Porta remota"}, - {"zh-chs","远程端口"}, - {"pt-br","Porta Remota"}, - {"sv","Fjärrport"}, - {"es","Puerto Remoto"}, - {"hi","रिमोट पोर्ट"}, - {"de","Remote-Port"} + {"de","In der Taskleiste anzeigen"}, + {"hi","सिस्टम ट्रे पर दिखाएं"}, + {"fr","Afficher sur la barre d'état système"}, + {"zh-chs","在系统托盘上显示"}, + {"fi","Näytä ilmaisinalueella"}, + {"tr","Sistem tepsisinde göster"}, + {"cs","Zobrazit na hlavním panelu"}, + {"ja","システムトレイに表示"}, + {"es","Mostrar en la bandeja del sistema"}, + {"pl","Pokaż w zasobniku systemowym"}, + {"pt","Mostrar na bandeja do sistema"}, + {"nl","Weergeven in systeemvak"}, + {"pt-br","Mostrar na bandeja do sistema"}, + {"sv","Visa i systemfältet"}, + {"da","Vis i systembakken"}, + {"ko","시스템 트레이에 표시"}, + {"it","Mostra sulla barra delle applicazioni"}, + {"ru","Показать на панели задач"} + } + }, + { + "File Transfer", + new Dictionary() { + {"de","Datei Übertragung"}, + {"hi","फ़ाइल स्थानांतरण"}, + {"fr","Transfert de fichiers"}, + {"zh-chs","文件传输"}, + {"fi","Tiedostonsiirto"}, + {"tr","Dosya transferi"}, + {"cs","Přenos souboru"}, + {"ja","ファイル転送"}, + {"es","Transferencia de Archivos"}, + {"pl","Transfer Pliku"}, + {"pt","Transferência de arquivo"}, + {"nl","Bestandsoverdracht"}, + {"pt-br","Transferência de arquivo"}, + {"sv","Filöverföring"}, + {"da","Filoverførsel"}, + {"ko","파일 전송"}, + {"it","Trasferimento di file"}, + {"ru","Передача файлов"} + } + }, + { + "Ask Consent + Bar", + new Dictionary() { + {"de","Einwilligung anfordern + DS-Leiste"}, + {"hi","सहमति + बार पूछें"}, + {"fr","Demander le consentement + le bar"}, + {"zh-cht","詢問同意+工具欄"}, + {"zh-chs","询问同意+工具栏"}, + {"fi","Pyydä Hyväksyntää + Ilmoitus"}, + {"tr","Onay Sor + Bar"}, + {"cs","Zeptejte se souhlasu + bar"}, + {"ja","同意を求める+バー"}, + {"es","Pedir Consentimiento + Barra"}, + {"pl","Zapytaj o zgodę + Bar"}, + {"pt","Peça Consentimento + Bar"}, + {"nl","Vraag toestemming + informatiebalk"}, + {"pt-br","Peça Autorização + Bar"}, + {"sv","Fråga samtycke + bar"}, + {"da","Spørg om samtykke + bar"}, + {"ko","연결 요청 + Bar"}, + {"it","Chiedi Consenso + Bar"}, + {"ru","Спросите согласия + бар"} + } + }, + { + "State", + new Dictionary() { + {"de","Zustand"}, + {"hi","राज्य"}, + {"fr","Etat"}, + {"zh-cht","狀態"}, + {"zh-chs","状况"}, + {"fi","Tila"}, + {"tr","Durum"}, + {"cs","Stav"}, + {"ja","状態"}, + {"es","Estado"}, + {"pl","Stan"}, + {"pt","Estado"}, + {"nl","Status"}, + {"pt-br","Estado"}, + {"sv","stat"}, + {"da","Tilstand"}, + {"ko","상태"}, + {"it","Stato"}, + {"ru","Состояние"} + } + }, + { + "Forward all keyboard keys", + new Dictionary() { + {"de","Alle Tastaturtasten weiterleiten"}, + {"hi","सभी कीबोर्ड कुंजियों को अग्रेषित करें"}, + {"fr","Transférer toutes les touches du clavier"}, + {"zh-chs","转发所有键盘键"}, + {"fi","Lähetä kaikki näppäimistön näppäimet eteenpäin"}, + {"tr","Tüm klavye tuşlarını ilet"}, + {"cs","Přeposlat všechny klávesy na klávesnici"}, + {"ja","すべてのキーボードキーを転送する"}, + {"es","Reenviar todas las teclas del teclado"}, + {"pl","Przekaż wszystkie klawisze klawiatury"}, + {"pt","Encaminhar todas as teclas do teclado"}, + {"nl","Alle toetsenbordtoetsen doorsturen"}, + {"pt-br","Encaminhar todas as teclas do teclado"}, + {"sv","Vidarebefordra alla tangentbordstangenter"}, + {"da","Videresend alle tastatur taster"}, + {"ko","모든 키보드 키 전달"}, + {"it","Inoltra tutti i tasti della tastiera"}, + {"ru","Переслать все клавиши клавиатуры"} + } + }, + { + "Stats", + new Dictionary() { + {"de","Statistiken"}, + {"hi","आँकड़े"}, + {"fr","Statistiques"}, + {"zh-cht","統計"}, + {"zh-chs","统计"}, + {"fi","Tilastot"}, + {"tr","İstatistikler"}, + {"cs","Statistiky"}, + {"ja","統計"}, + {"es","Estadísticas"}, + {"pl","Statystyki"}, + {"pt","Estatísticas"}, + {"nl","Statistieken"}, + {"pt-br","Estatísticas"}, + {"sv","Statistik"}, + {"da","Statistik"}, + {"ko","통계"}, + {"ru","Статистика"} + } + }, + { + "Error Message", + new Dictionary() { + {"de","Fehlermeldung"}, + {"hi","त्रुटि संदेश"}, + {"fr","Message d'erreur"}, + {"zh-chs","错误信息"}, + {"fi","Virheviesti"}, + {"tr","Hata mesajı"}, + {"cs","Chybové hlášení"}, + {"ja","エラーメッセージ"}, + {"es","Mensaje de error"}, + {"pl","Komunikat Błędu"}, + {"pt","Mensagem de erro"}, + {"nl","Foutmelding"}, + {"pt-br","Mensagem de erro"}, + {"sv","Felmeddelande"}, + {"da","Fejlmeddelelse"}, + {"ko","에러 메시지"}, + {"it","Messaggio di errore"}, + {"ru","Сообщение об ошибке"} + } + }, + { + "Device Status", + new Dictionary() { + {"de","Gerätestatus"}, + {"hi","उपकरण की स्थिति"}, + {"fr","Statut du périphérique"}, + {"zh-chs","设备状态"}, + {"fi","Laitteen tila"}, + {"tr","Cihaz durumu"}, + {"cs","Stav zařízení"}, + {"ja","デバイスステータス"}, + {"es","Estado del dispositivo"}, + {"pl","Status Urządzenia"}, + {"pt","Status do dispositivo"}, + {"nl","Apparaatstatus"}, + {"pt-br","Status do dispositivo"}, + {"sv","Enhets status"}, + {"da","Enheds status"}, + {"ko","장치 상태"}, + {"it","Stato del dispositivo"}, + {"ru","Состояние устройства"} + } + }, + { + "{0} seconds left", + new Dictionary() { + {"de","noch {0} Sekunden"}, + {"hi","{0} सेकंड शेष"}, + {"fr","{0} secondes restantes"}, + {"zh-chs","还剩 {0} 秒"}, + {"fi","{0} sekuntia jäljellä"}, + {"tr","{0} saniye kaldı"}, + {"cs","Zbývá {0} sekund"}, + {"ja","残り{0}秒"}, + {"es","Quedan {0} segundos"}, + {"pl","Pozostało {0} sekund"}, + {"pt","Faltam {0} segundos"}, + {"nl","{0} seconden resterend"}, + {"pt-br","Quedan {0} segundos"}, + {"sv","{0} sekunder kvar"}, + {"da","{0} sekunder tilbage"}, + {"ko","{0}초 남음"}, + {"it","{0} secondi rimasti"}, + {"ru","Осталось {0} секунд"} + } + }, + { + "Routing Stats", + new Dictionary() { + {"de","Routing-Statistiken"}, + {"hi","रूटिंग आँकड़े"}, + {"fr","Statistiques de routage"}, + {"zh-chs","路由统计"}, + {"fi","Reititilastot"}, + {"tr","Yönlendirme İstatistikleri"}, + {"cs","Směrovací statistiky"}, + {"ja","ルーティング統計"}, + {"es","Estadísticas de Enrutamiento"}, + {"pl","Statystyki Routingu"}, + {"pt","Estatísticas de roteamento"}, + {"nl","Routeringsstatistieken"}, + {"pt-br","Estatísticas de roteamento"}, + {"ko","라우팅 통계"}, + {"it","Statistiche di instradamento"}, + {"ru","Статистика маршрутизации"} + } + }, + { + "Ask Consent", + new Dictionary() { + {"de","Einwilligung anfordern"}, + {"hi","सहमति से पूछें"}, + {"fr","Demander le consentement"}, + {"zh-cht","詢問同意"}, + {"zh-chs","询问同意"}, + {"fi","Pyydä Hyväksyntää"}, + {"tr","Onay isteyin"}, + {"cs","Požádat o souhlas"}, + {"ja","同意を求める"}, + {"es","Pedir Consentimiento"}, + {"pl","Zapytaj o zgodę"}, + {"pt","Peça consentimento"}, + {"nl","Vraag toestemming"}, + {"pt-br","Peça autorização"}, + {"sv","Fråga samtycke"}, + {"da","Spørg om samtykke"}, + {"ko","연결 요청"}, + {"it","Chiedi il consenso"}, + {"ru","Спросите согласия"} + } + }, + { + "Remote Desktop...", + new Dictionary() { + {"de","Remotedesktop..."}, + {"hi","रिमोट डेस्कटॉप..."}, + {"fr","Bureau à distance..."}, + {"zh-chs","远程桌面..."}, + {"fi","Etätyöpöytä..."}, + {"tr","Uzak Masaüstü..."}, + {"cs","Vzdálená plocha..."}, + {"ja","リモートデスクトップ..."}, + {"es","Escritorio Remoto..."}, + {"pl","Zdalny Pulpit..."}, + {"pt","Área de trabalho remota..."}, + {"nl","Extern bureaublad..."}, + {"pt-br","Área de trabalho remota..."}, + {"sv","Fjärrskrivbord..."}, + {"da","Fjernskrivebord..."}, + {"ko","원격 데스크탑..."}, + {"it","Desktop remoto..."}, + {"ru","Удаленного рабочего стола..."} + } + }, + { + "Devices", + new Dictionary() { + {"de","Geräte"}, + {"hi","उपकरण"}, + {"fr","Dispositifs"}, + {"zh-cht","裝置"}, + {"zh-chs","设备"}, + {"fi","Laitteet"}, + {"tr","Cihazlar"}, + {"cs","Zařízení"}, + {"ja","デバイス"}, + {"es","Dispositivos"}, + {"pl","Urządzenia"}, + {"pt","Dispositivos"}, + {"nl","Apparaten"}, + {"pt-br","Dispositivos"}, + {"sv","Enheter"}, + {"da","Enheder"}, + {"ko","여러 장치"}, + {"it","Dispositivi"}, + {"ru","Устройства"} + } + }, + { + "Rename", + new Dictionary() { + {"de","Umbenennen"}, + {"hi","नाम बदलें"}, + {"fr","Renommer"}, + {"zh-cht","改名"}, + {"zh-chs","改名"}, + {"fi","Nimeä uudelleen"}, + {"tr","Yeniden adlandır"}, + {"cs","Přejmenovat"}, + {"ja","リネーム"}, + {"es","Renombrar"}, + {"pl","Zmień nazwę"}, + {"pt","Renomear"}, + {"nl","Hernoemen"}, + {"pt-br","Renomear"}, + {"sv","Döp om"}, + {"da","Omdøb"}, + {"ko","이름 바꾸기"}, + {"it","Rinominare"}, + {"ru","Переименовать"} + } + }, + { + "0 Bytes", + new Dictionary() { + {"de","0 Byte"}, + {"hi","0 बाइट्स"}, + {"fr","0 octet"}, + {"zh-chs","0 字节"}, + {"fi","0 tavua"}, + {"tr","0 Bayt"}, + {"cs","0 bajtů"}, + {"ja","0バイト"}, + {"es","0 bytes"}, + {"pl","0 Bajtów"}, + {"sv","0 byte"}, + {"da","0 bytes"}, + {"ko","0 바이트"}, + {"ru","0 байт"} + } + }, + { + "Disconnected", + new Dictionary() { + {"de","Getrennt"}, + {"hi","डिस्कनेक्ट किया गया"}, + {"fr","Débranché"}, + {"zh-cht","已斷線"}, + {"zh-chs","已断线"}, + {"fi","Yhteys katkaistu"}, + {"tr","Bağlantı kesildi"}, + {"cs","Odpojeno"}, + {"ja","切断されました"}, + {"es","Desconectado"}, + {"pl","Rozłączony"}, + {"pt","Desconectado"}, + {"nl","Verbroken"}, + {"pt-br","Desconectado"}, + {"sv","Frånkopplad"}, + {"da","Afbrudt"}, + {"ko","연결 해제"}, + {"it","Disconnesso"}, + {"ru","Отключен"} + } + }, + { + "E&xit", + new Dictionary() { + {"de","Beenden"}, + {"hi","बाहर जाएं"}, + {"fr","Sortir"}, + {"zh-chs","出口"}, + {"fi","E & xit"}, + {"tr","Çıkış"}, + {"cs","Výstup"}, + {"ja","出口"}, + {"es","Salida"}, + {"pl","Wyjdź (&x)"}, + {"pt","Saída"}, + {"nl","Sluiten"}, + {"pt-br","Saída"}, + {"sv","Utgång"}, + {"ko","출구"}, + {"ru","Выход"} + } + }, + { + "Remote Desktop", + new Dictionary() { + {"de","Remotedesktop"}, + {"hi","रिमोट डेस्कटॉप"}, + {"fr","Bureau distant"}, + {"zh-cht","遠程桌面"}, + {"zh-chs","远程桌面"}, + {"fi","Etätyöpöytä"}, + {"tr","Uzak Masaüstü"}, + {"cs","Vzdálená plocha"}, + {"ja","リモートデスクトップ"}, + {"es","Escritorio Remoto"}, + {"pl","Zdalny Pulpit"}, + {"pt","Área de trabalho remota"}, + {"nl","Extern bureaublad"}, + {"pt-br","Área de trabalho remota"}, + {"sv","Fjärrskrivbord"}, + {"da","Fjernskrivebord"}, + {"ko","원격 데스크탑"}, + {"it","Desktop remoto"}, + {"ru","Удаленного рабочего стола"} + } + }, + { + "View Certificate Details...", + new Dictionary() { + {"de","Zertifikatdetails anzeigen..."}, + {"hi","प्रमाणपत्र विवरण देखें..."}, + {"fr","Afficher les détails du certificat..."}, + {"zh-chs","查看证书详细信息..."}, + {"fi","Näytä varmenteen tiedot ..."}, + {"tr","Sertifika Ayrıntılarını Görüntüle..."}, + {"cs","Zobrazit podrobnosti o certifikátu ..."}, + {"ja","証明書の詳細を表示..."}, + {"es","Ver Detalles del Certificado ..."}, + {"pl","Pokaż Szczegóły Certyfikatu..."}, + {"pt","Exibir detalhes do certificado ..."}, + {"nl","Certificaatdetails bekijken..."}, + {"pt-br","Exibir detalhes do certificado ..."}, + {"sv","Visa certifikatinformation ..."}, + {"da","Vis certifikatinformation ..."}, + {"ko","인증서 세부 정보보기 ..."}, + {"it","Visualizza dettagli certificato..."}, + {"ru","Просмотреть сведения о сертификате ..."} + } + }, + { + "Routing Status", + new Dictionary() { + {"de","Routing-Status"}, + {"hi","रूटिंग स्थिति"}, + {"fr","État du routage"}, + {"zh-chs","路由状态"}, + {"fi","Reitityksen tila"}, + {"tr","Yönlendirme Durumu"}, + {"cs","Stav směrování"}, + {"ja","ルーティングステータス"}, + {"es","Estado de Enrutamiento"}, + {"pl","Status routingu"}, + {"pt","Status de roteamento"}, + {"nl","Routeringsstatus"}, + {"pt-br","Status de roteamento"}, + {"sv","Ruttstatus"}, + {"ko","라우팅 상태"}, + {"it","Stato del percorso"}, + {"ru","Статус маршрутизации"} + } + }, + { + ", {0} connections.", + new Dictionary() { + {"de",", {0} Verbindungen."}, + {"hi",", {0} कनेक्शन।"}, + {"fr",", {0} connexions."}, + {"zh-chs",", {0} 个连接。"}, + {"fi",", {0} yhteyttä."}, + {"tr",", {0} bağlantı."}, + {"cs",", {0} připojení."}, + {"ja","、{0}接続。"}, + {"es",", {0} conexiones."}, + {"pl",", {0} połączeń."}, + {"pt",", {0} conexões."}, + {"nl",", {0} verbindingen."}, + {"pt-br",", {0} conexões."}, + {"sv",", {0} anslutningar."}, + {"da",", {0} forbindelser."}, + {"ko",", {0} 명 연결."}, + {"it",", {0} connessioni."}, + {"ru",", Подключений: {0}."} + } + }, + { + "{0} Gbytes/sec", + new Dictionary() { + {"de","{0} Gbyte/s"}, + {"hi","{0} गीबाइट्स/सेकंड"}, + {"zh-chs","{0} GB/秒"}, + {"fi","{0} Tavu/s"}, + {"tr","{0} Gbayt/sn"}, + {"cs","{0} Gb/s"}, + {"ja","{0}ギガバイト/秒"}, + {"es","{0} Gbytes / seg"}, + {"pl","{0} GB/s"}, + {"pt","{0} Gbytes / s"}, + {"pt-br","{0} Gbytes / seg"}, + {"sv","{0} Gbyte/sek"}, + {"da","{0} Gbytes/sek"}, + {"ko","{0}GB/초"}, + {"it","{0} Gbyte/sec"}, + {"ru","{0} Гбайт / с"} + } + }, + { + "{0} Mbytes/sec", + new Dictionary() { + {"de","{0} Mbyte/s"}, + {"hi","{0}एमबाइट्स/सेकंड"}, + {"zh-chs","{0} 兆字节/秒"}, + {"fi","{0} Megatavua/sek"}, + {"tr","{0} Mbayt/sn"}, + {"cs","{0} MB/s"}, + {"ja","{0}メガバイト/秒"}, + {"es","{0} Mbytes / seg"}, + {"pl","{0} MB/s"}, + {"pt","{0} Mbytes / s"}, + {"pt-br","{0} Mbytes / seg"}, + {"sv","{0} Mbytes/sek"}, + {"da","{0} Mbytes/sek"}, + {"ko","{0}MB/초"}, + {"it","{0} Mbyte/sec"}, + {"ru","{0} Мбайт / с"} } }, { "Stopped.", new Dictionary() { - {"nl","Gestopt."}, - {"ko","중지되었습니다."}, + {"de","Gestoppt."}, + {"hi","रोका हुआ।"}, {"fr","Arrêté."}, {"zh-chs","停了。"}, - {"pt-br","Parou."}, - {"sv","Stannade."}, + {"fi","Pysähtyi."}, + {"tr","Durdu."}, + {"cs","Zastavil."}, + {"ja","停止。"}, {"es","Detenido."}, - {"hi","रोका हुआ।"}, - {"de","Gestoppt."} + {"pl","Zatrzymany."}, + {"pt","Parado."}, + {"nl","Gestopt."}, + {"pt-br","Parado."}, + {"sv","Stannade."}, + {"da","Stoppet."}, + {"ko","중지되었습니다."}, + {"ru","Остановился."} + } + }, + { + "File Operation", + new Dictionary() { + {"de","Dateivorgang"}, + {"hi","फ़ाइल ऑपरेशन"}, + {"fr","Opération sur les fichiers"}, + {"zh-cht","檔案操作"}, + {"zh-chs","档案操作"}, + {"fi","Tiedoston käyttö"}, + {"tr","Dosya İşlemi"}, + {"cs","Provoz souboru"}, + {"ja","ファイル操作"}, + {"es","Operación de Archivo"}, + {"pl","Operacja na Pliku"}, + {"pt","Operação de arquivo"}, + {"nl","Bestandsbewerking"}, + {"pt-br","Operação de arquivo"}, + {"sv","Filhantering"}, + {"da","Filhåndtering"}, + {"ko","파일 작업"}, + {"it","Operazione sui file"}, + {"ru","Работа с файлами"} + } + }, + { + "{0} Bytes", + new Dictionary() { + {"de","{0} Byte"}, + {"hi","{0} बाइट्स"}, + {"fr","{0} octets"}, + {"zh-chs","{0} 字节"}, + {"fi","{0} Tavua"}, + {"tr","{0} Bayt"}, + {"cs","{0} bajtů"}, + {"ja","{0}バイト"}, + {"es","{0} bytes"}, + {"pl","{0} Bajtów"}, + {"pt","{0} bytes"}, + {"pt-br","{0} bytes"}, + {"sv","{0} Byte"}, + {"ko","{0} 바이트"}, + {"ru","{0} байтов"} + } + }, + { + "Stopped", + new Dictionary() { + {"de","Gestoppt"}, + {"hi","रोका हुआ"}, + {"fr","Arrêté"}, + {"zh-chs","停止"}, + {"fi","Pysähtyi"}, + {"tr","durduruldu"}, + {"cs","Zastavil"}, + {"ja","停止"}, + {"es","Detenido"}, + {"pl","Zatrzymany"}, + {"pt","Parado"}, + {"nl","Gestopt"}, + {"pt-br","Parado"}, + {"sv","Stannade"}, + {"da","Stoppet"}, + {"ko","중지됨"}, + {"it","Fermato"}, + {"ru","Остановлен"} + } + }, + { + "Mappings", + new Dictionary() { + {"de","Zuordnungen"}, + {"hi","मानचित्रण"}, + {"fr","Mappages"}, + {"zh-chs","映射"}, + {"fi","Kartoitukset"}, + {"tr","Eşlemeler"}, + {"cs","Mapování"}, + {"ja","マッピング"}, + {"es","Mapeos"}, + {"pl","Mapowanie"}, + {"pt","Mapeamentos"}, + {"nl","Toewijzingen"}, + {"pt-br","Mapeamentos"}, + {"sv","Kartläggningar"}, + {"da","Kortlægninger"}, + {"ko","매핑"}, + {"it","Mappature"}, + {"ru","Сопоставления"} + } + }, + { + "Don't ask for {0} days.", + new Dictionary() { + {"de","Frag nicht nach {0} Tagen."}, + {"hi","{0} दिनों के लिए मत पूछो।"}, + {"fr","Ne demandez pas {0} jours."}, + {"zh-chs","不要要求 {0} 天。"}, + {"fi","Älä kysy {0} päivää."}, + {"tr","{0} gün sormayın."}, + {"cs","Nepožadujte {0} dny."}, + {"ja","{0}日を要求しないでください。"}, + {"es","No pedir por {0} días."}, + {"pl","Nie pytaj przez {0} dni."}, + {"pt","Não pergunte por {0} dias."}, + {"nl","Niet vragen voor {0} dagen."}, + {"pt-br","Não pergunte por {0} dias."}, + {"sv","Be inte om {0} dagar."}, + {"da","Spørg ikke i {0} dage."}, + {"ko","{0} 일을 요구하지 마세요."}, + {"it","Non chiedere per {0} giorni."}, + {"ru","Не просите {0} дней."} + } + }, + { + "Remove 1 item?", + new Dictionary() { + {"de","1 Artikel entfernen?"}, + {"hi","1 आइटम निकालें?"}, + {"fr","Supprimer 1 élément ?"}, + {"zh-chs","删除 1 项?"}, + {"fi","Poistetaanko 1 kohde?"}, + {"tr","1 öğe kaldırılsın mı?"}, + {"cs","Odebrat 1 položku?"}, + {"ja","1つのアイテムを削除しますか?"}, + {"es","¿Eliminar 1 artículo?"}, + {"pl","Usunąć 1 pozycję?"}, + {"pt","Remover 1 item?"}, + {"nl","1 artikel verwijderen?"}, + {"pt-br","Remover 1 item?"}, + {"sv","Ta bort ett objekt?"}, + {"da","Fjern 1 element?"}, + {"ko","항목 1 개를 삭제 하시겠습니까?"}, + {"it","Rimuovere 1 elemento?"}, + {"ru","Удалить 1 элемент?"} + } + }, + { + "Remote Device", + new Dictionary() { + {"de","Remote-Gerät"}, + {"hi","रिमोट डिवाइस"}, + {"fr","Périphérique distant"}, + {"zh-chs","遥控装置"}, + {"fi","Etälaite"}, + {"tr","Uzak Cihaz"}, + {"cs","Vzdálené zařízení"}, + {"ja","リモートデバイス"}, + {"es","Dispositivo Remoto"}, + {"pl","Urządzenie Zdalne"}, + {"pt","Dispositivo Remoto"}, + {"nl","Extern apparaat"}, + {"pt-br","Dispositivo Remoto"}, + {"sv","Fjärrenhet"}, + {"da","Fjernenhed"}, + {"ko","원격 장치"}, + {"it","Dispositivo remoto"}, + {"ru","Удаленное устройство"} + } + }, + { + "Remote desktop quality, scaling and frame rate settings. These can be adjusted depending on the quality of the network connection.", + new Dictionary() { + {"de","Remote-Desktop-Qualität, Skalierung und Bildrateneinstellungen. Diese können je nach Qualität der Netzwerkverbindung angepasst werden."}, + {"hi","दूरस्थ डेस्कटॉप गुणवत्ता, स्केलिंग और फ्रेम दर सेटिंग्स। इन्हें नेटवर्क कनेक्शन की गुणवत्ता के आधार पर समायोजित किया जा सकता है।"}, + {"fr","Paramètres de qualité, de mise à l'échelle et de fréquence d'images du bureau à distance. Ceux-ci peuvent être ajustés en fonction de la qualité de la connexion réseau."}, + {"zh-chs","远程桌面质量、缩放和帧速率设置。这些可以根据网络连接的质量进行调整。"}, + {"fi","Etätyöpöydän laatu-, skaalaus- ja kuvataajuusasetukset. Näitä voidaan säätää verkkoyhteyden laadun mukaan."}, + {"tr","Uzak masaüstü kalitesi, ölçekleme ve kare hızı ayarları. Bunlar, ağ bağlantısının kalitesine bağlı olarak ayarlanabilir."}, + {"cs","Kvalita vzdálené plochy, měřítko a nastavení snímkové frekvence. Ty lze upravit v závislosti na kvalitě síťového připojení."}, + {"ja","リモートデスクトップの品質、スケーリング、フレームレートの設定。これらは、ネットワーク接続の品質に応じて調整できます。"}, + {"es","Configuración de la calidad del escritorio remoto, la escala y la velocidad de fotogramas. Estos se pueden ajustar en función de la calidad de la conexión de red."}, + {"pl","Ustawienia jakości pulpitu zdalnego, skalowania i częstotliwości odświeżania. Można je dostosować w zależności od jakości połączenia sieciowego."}, + {"pt","Configurações de qualidade, escala e taxa de quadros da área de trabalho remota. Eles podem ser ajustados dependendo da qualidade da conexão de rede."}, + {"nl","Instellingen voor kwaliteit, schaal en framesnelheid van het externe bureaublad. Deze kunnen worden aangepast afhankelijk van de kwaliteit van de netwerkverbinding."}, + {"pt-br","Configurações de qualidade, escala e taxa de quadros da área de trabalho remota. Eles podem ser ajustados dependendo da qualidade da conexão de rede."}, + {"sv","Fjärrskrivbords kvalitet, skalning och bildfrekvensinställningar. Dessa kan justeras beroende på nätverksanslutningens kvalitet."}, + {"da","Indstillinger for fjernskrivebordskvalitet, skalering og billedhastighed. Disse kan justeres afhængigt af kvaliteten af netværksforbindelsen."}, + {"ko","원격 데스크톱 품질, 크기 조정 및 프레임 속도 설정. 네트워크 연결 품질에 따라 조정할 수 있습니다."}, + {"it","Impostazioni di qualità, ridimensionamento e frame rate del desktop remoto. Questi possono essere regolati in base alla qualità della connessione di rete."}, + {"ru","Настройки качества, масштабирования и частоты кадров удаленного рабочего стола. Их можно настроить в зависимости от качества сетевого подключения."} + } + }, + { + "Local Port", + new Dictionary() { + {"de","Lokaler Hafen"}, + {"hi","स्थानीय बंदरगाह"}, + {"fr","Port local"}, + {"zh-chs","本地端口"}, + {"fi","Paikallinen satama"}, + {"tr","Yerel Liman"}, + {"cs","Místní přístav"}, + {"ja","ローカルポート"}, + {"es","Puerto Local"}, + {"pl","Port Lokalny"}, + {"pt","Porto Local"}, + {"nl","Lokale poort"}, + {"pt-br","Porta Local"}, + {"sv","Lokal hamn"}, + {"da","Lokal Port"}, + {"ko","로컬 포트"}, + {"it","Porta locale"}, + {"ru","Местный порт"} + } + }, + { + "Stats...", + new Dictionary() { + {"de","Statistiken..."}, + {"hi","आँकड़े..."}, + {"fr","Statistiques..."}, + {"zh-chs","统计..."}, + {"fi","Tilastot ..."}, + {"tr","İstatistikler..."}, + {"cs","Statistiky ..."}, + {"ja","統計..."}, + {"es","Estadísticas ..."}, + {"pl","Statystyki..."}, + {"pt","Estatísticas..."}, + {"nl","Statistieken..."}, + {"pt-br","Estatísticas..."}, + {"sv","Statistik ..."}, + {"da","Statistik ..."}, + {"ko","통계 ..."}, + {"it","Statistiche..."}, + {"ru","Статистика ..."} + } + }, + { + "This MeshCentral Server uses a different version of this tool. Click ok to download and update.", + new Dictionary() { + {"de","Dieser MeshCentral Server verwendet eine andere Version dieses Tools. Klicken Sie auf OK, um herunterzuladen und zu aktualisieren."}, + {"hi","यह MeshCentral सर्वर इस टूल के भिन्न संस्करण का उपयोग करता है। डाउनलोड और अपडेट करने के लिए ओके पर क्लिक करें।"}, + {"fr","Ce serveur MeshCentral utilise une version différente de cet outil. Cliquez sur ok pour télécharger et mettre à jour."}, + {"zh-chs","此 MeshCentral Server 使用此工具的不同版本。单击“确定”进行下载和更新。"}, + {"fi","Tämä MeshCentral -palvelin käyttää eri versiota tästä työkalusta. Lataa ja päivitä napsauttamalla OK."}, + {"tr","Bu MeshCentral Sunucusu, bu aracın farklı bir sürümünü kullanır. İndirmek ve güncellemek için Tamam'a tıklayın."}, + {"cs","Tento server MeshCentral používá jinou verzi tohoto nástroje. Kliknutím na ok stáhnete a aktualizujete."}, + {"ja","このMeshCentralサーバーは、このツールの異なるバージョンを使用します。 [OK]をクリックして、ダウンロードして更新します。"}, + {"es","Este servidor MeshCentral utiliza una versión diferente de esta herramienta. Haz clic en Aceptar para descargar y actualizar."}, + {"pl","Ten MeshCentral Server używa innej wersji tego narzędzia. Kliknij ok, aby pobrać i zaktualizować."}, + {"pt","Este servidor MeshCentral usa uma versão diferente desta ferramenta. Clique em ok para baixar e atualizar."}, + {"nl","Deze MeshCentral Server gebruikt een andere versie van deze tool. Klik op OK om te downloaden en bij te werken."}, + {"pt-br","Este servidor MeshCentral usa uma versão diferente desta ferramenta. Clique em ok para baixar e atualizar."}, + {"sv","Denna MeshCentral Server använder en annan version av detta verktyg. Klicka på ok för att ladda ner och uppdatera."}, + {"da","Denne MeshCentral Server bruger en anden version af dette værktøj. Klik på ok for at downloade og opdatere."}, + {"ko","이 MeshCentral 서버는이 도구의 다른 버전을 사용합니다. 확인을 클릭하여 다운로드하고 업데이트하십시오."}, + {"it","Questo server MeshCentral utilizza una versione diversa di questo strumento.Fare clic su OK per scaricare e aggiornare."}, + {"ru","Этот MeshCentral Server использует другую версию этого инструмента. Нажмите ОК, чтобы загрузить и обновить."} + } + }, + { + "Next", + new Dictionary() { + {"de","Nächster"}, + {"hi","अगला"}, + {"fr","Suivant"}, + {"zh-chs","下一个"}, + {"fi","Seuraava"}, + {"tr","Sonraki"}, + {"cs","další"}, + {"ja","次"}, + {"es","Próximo"}, + {"pl","Dalej"}, + {"pt","Próximo"}, + {"nl","Volgende"}, + {"pt-br","Próximo"}, + {"sv","Nästa"}, + {"da","Næste"}, + {"ko","다음"}, + {"it","Prossimo"}, + {"ru","Следующий"} + } + }, + { + "Email", + new Dictionary() { + {"de","E-Mail"}, + {"hi","ईमेल"}, + {"zh-cht","電郵"}, + {"zh-chs","电邮"}, + {"fi","Sähköposti"}, + {"tr","E-posta"}, + {"cs","E-mail"}, + {"ja","Eメール"}, + {"es","Correo electrónico"}, + {"pl","E-mail"}, + {"nl","E-mail"}, + {"pt-br","E-mail"}, + {"sv","E-post"}, + {"da","E-mail"}, + {"ko","이메일"}, + {"it","E-mail"} + } + }, + { + "WARNING - Invalid Server Certificate", + new Dictionary() { + {"de","WARNUNG - Ungültiges Serverzertifikat"}, + {"hi","चेतावनी - अमान्य सर्वर प्रमाणपत्र"}, + {"fr","AVERTISSEMENT - Certificat de serveur non valide"}, + {"zh-chs","警告 - 服务器证书无效"}, + {"fi","VAROITUS - Virheellinen palvelinvarmenne"}, + {"tr","UYARI - Geçersiz Sunucu Sertifikası"}, + {"cs","UPOZORNĚNÍ - Neplatný certifikát serveru"}, + {"ja","警告-無効なサーバー証明書"}, + {"es","ADVERTENCIA: Certificado de Servidor No Válido"}, + {"pl","OSTRZEŻENIE - Nieprawidłowy certyfikat serwera"}, + {"pt","AVISO - Certificado de servidor inválido"}, + {"nl","WAARSCHUWING - Ongeldig servercertificaat"}, + {"pt-br","AVISO - Certificado de servidor inválido"}, + {"sv","VARNING - Ogiltigt servercertifikat"}, + {"da","ADVARSEL - Ugyldigt servercertifikat"}, + {"ko","경고-잘못된 서버 인증서"}, + {"it","AVVISO - Certificato del server non valido"}, + {"ru","ВНИМАНИЕ! Недействительный сертификат сервера."} + } + }, + { + "Username", + new Dictionary() { + {"de","Benutzername"}, + {"hi","उपयोगकर्ता नाम"}, + {"fr","Nom d'utilisateur"}, + {"zh-cht","用戶名"}, + {"zh-chs","用户名"}, + {"fi","Käyttäjätunnus"}, + {"tr","Kullanıcı adı"}, + {"cs","Uživatelské jméno"}, + {"ja","ユーザー名"}, + {"es","Nombre de Usuario"}, + {"pl","Nazwa użytkownika"}, + {"pt","Nome de usuário"}, + {"nl","Gebruikersnaam"}, + {"pt-br","Nome do usuário"}, + {"sv","Användarnamn"}, + {"da","Brugernavn"}, + {"ko","사용자 이름"}, + {"it","Nome utente"}, + {"ru","Имя пользователя"} + } + }, + { + "Change remote desktop settings", + new Dictionary() { + {"de","Remote-Desktop-Einstellungen ändern"}, + {"hi","दूरस्थ डेस्कटॉप सेटिंग बदलें"}, + {"fr","Modifier les paramètres du bureau à distance"}, + {"zh-chs","更改远程桌面设置"}, + {"fi","Muuta etätyöpöydän asetuksia"}, + {"tr","Uzak masaüstü ayarlarını değiştir"}, + {"cs","Změňte nastavení vzdálené plochy"}, + {"ja","リモートデスクトップ設定を変更する"}, + {"es","Cambiar la configuración del escritorio remoto"}, + {"pl","Zmień ustawienia pulpitu zdalnego"}, + {"pt","Alterar as configurações da área de trabalho remota"}, + {"nl","Instellingen voor extern bureaublad wijzigen"}, + {"pt-br","Alterar as configurações da área de trabalho remota"}, + {"sv","Ändra fjärrskrivbordsinställningar"}, + {"da","Skift indstillinger for fjernskrivebord"}, + {"ko","원격 데스크톱 설정 변경"}, + {"it","Modifica le impostazioni del desktop remoto"}, + {"ru","Изменить настройки удаленного рабочего стола"} + } + }, + { + "Enter the RDP port of the remote computer, the default RDP port is 3389.", + new Dictionary() { + {"de","Geben Sie den RDP-Port des Remote-Computers ein, der Standard-RDP-Port ist 3389."}, + {"hi","दूरस्थ कंप्यूटर का RDP पोर्ट दर्ज करें, डिफ़ॉल्ट RDP पोर्ट 3389 है।"}, + {"fr","Entrez le port RDP de l'ordinateur distant, le port RDP par défaut est 3389."}, + {"zh-chs","输入远程计算机的RDP端口,默认RDP端口为3389。"}, + {"fi","Anna etätietokoneen RDP -portti, oletusarvoinen RDP -portti on 3389."}, + {"tr","Uzak bilgisayarın RDP bağlantı noktasını girin, varsayılan RDP bağlantı noktası 3389'dur."}, + {"cs","Zadejte port RDP vzdáleného počítače, výchozí port RDP je 3389."}, + {"ja","リモートコンピューターのRDPポートを入力します。デフォルトのRDPポートは3389です。"}, + {"es","Ingresa el puerto RDP de la computadora remota, el puerto RDP predeterminado es 3389."}, + {"pl","Wprowadź port RDP komputera zdalnego, domyślny port RDP to 3389."}, + {"pt","Insira a porta RDP do computador remoto; a porta RDP padrão é 3389."}, + {"nl","Voer de RDP poort van de externe computer in, de standaard RDP poort is 3389."}, + {"pt-br","Insira a porta RDP do computador remoto, a porta RDP padrão é 3389."}, + {"sv","Ange RDP-porten på fjärrdatorn, standard-RDP-porten är 3389."}, + {"da","Indtast RDP-porten på fjerncomputeren, standard RDP-porten er 3389."}, + {"ko","원격 컴퓨터의 RDP 포트를 입력합니다. 기본 RDP 포트는 3389입니다."}, + {"it","Immettere la porta RDP del computer remoto, la porta RDP predefinita è 3389."}, + {"ru","Введите порт RDP удаленного компьютера, порт RDP по умолчанию - 3389."} + } + }, + { + "Device Settings", + new Dictionary() { + {"de","Geräteeinstellungen"}, + {"hi","उपकरण सेटिंग्स"}, + {"fr","Réglages de l'appareil"}, + {"zh-chs","设备设置"}, + {"fi","Laite asetukset"}, + {"tr","Cihaz ayarları"}, + {"cs","Nastavení zařízení"}, + {"ja","デバイスの設定"}, + {"es","Configuración de dispositivo"}, + {"pl","Ustawienia Urządzenia"}, + {"pt","Configurações do dispositivo"}, + {"nl","Apparaat instellingen"}, + {"pt-br","Configurações do dispositivo"}, + {"sv","Enhetsinställningar"}, + {"da","Enhedsindstillinger"}, + {"ko","기기 설정"}, + {"it","Impostazioni del dispositivo"}, + {"ru","Настройки устройства"} + } + }, + { + "Open Source, Apache 2.0 License", + new Dictionary() { + {"de","Open Source, Apache 2.0-Lizenz"}, + {"hi","ओपन सोर्स, अपाचे 2.0 लाइसेंस"}, + {"fr","Open Source, licence Apache 2.0"}, + {"zh-chs","开源,Apache 2.0 许可"}, + {"fi","Avoimen lähdekoodin Apache 2.0 -lisenssi"}, + {"tr","Açık Kaynak, Apache 2.0 Lisansı"}, + {"cs","Open Source, licence Apache 2.0"}, + {"ja","オープンソース、Apache2.0ライセンス"}, + {"es","Código Abierto, licencia Apache 2.0"}, + {"pt","Código aberto, licença Apache 2.0"}, + {"nl","Open Source, Apache 2.0 Licentie"}, + {"pt-br","Código aberto, licença Apache 2.0"}, + {"sv","Open Source, Apache 2.0-licens"}, + {"da","Open Source, Apache 2.0-licens"}, + {"ko","오픈 소스, Apache 2.0 라이선스"}, + {"it","Open Source, licenza Apache 2.0"}, + {"ru","Открытый исходный код, лицензия Apache 2.0"} + } + }, + { + "Connection", + new Dictionary() { + {"de","Verbindung"}, + {"hi","संबंध"}, + {"fr","Lien"}, + {"zh-chs","联系"}, + {"fi","Yhteys"}, + {"tr","Bağlantı"}, + {"cs","Spojení"}, + {"ja","繋がり"}, + {"es","Conexión"}, + {"pl","Połączenie"}, + {"pt","Conexão"}, + {"nl","Verbinding"}, + {"pt-br","Conexão"}, + {"sv","Förbindelse"}, + {"da","Forbindelse"}, + {"ko","연결"}, + {"it","Connessione"}, + {"ru","Связь"} + } + }, + { + "Local", + new Dictionary() { + {"de","Lokal"}, + {"hi","स्थानीय"}, + {"zh-cht","本地"}, + {"zh-chs","本地"}, + {"fi","Paikallinen"}, + {"tr","Yerel"}, + {"cs","Lokální"}, + {"ja","地元"}, + {"pl","Lokalny"}, + {"nl","Lokaal"}, + {"sv","Lokal"}, + {"da","Lokal"}, + {"ko","로컬"}, + {"it","Locale"}, + {"ru","Локальный"} + } + }, + { + "Protocol", + new Dictionary() { + {"de","Protokoll"}, + {"hi","मसविदा बनाना"}, + {"fr","Protocole"}, + {"zh-cht","協議"}, + {"zh-chs","协议"}, + {"fi","Protokolla"}, + {"tr","Protokol"}, + {"cs","Protokol"}, + {"ja","プロトコル"}, + {"es","Protocolo"}, + {"pl","Protokół"}, + {"pt","Protocolo"}, + {"pt-br","Protocolo"}, + {"sv","Protokoll"}, + {"ko","프로토콜"}, + {"it","Protocollo"}, + {"ru","Протокол"} + } + }, + { + "Transfer Progress", + new Dictionary() { + {"de","Übertragungsfortschritt"}, + {"hi","स्थानांतरण प्रगति"}, + {"fr","Progression du transfert"}, + {"zh-chs","转学进度"}, + {"fi","Siirron eteneminen"}, + {"tr","Transfer İlerlemesi"}, + {"cs","Průběh přenosu"}, + {"ja","転送の進行状況"}, + {"es","Progreso de la Transferencia"}, + {"pl","Postęp Transferu"}, + {"pt","Progresso da Transferência"}, + {"nl","Voortgang overdracht"}, + {"pt-br","Progresso da Transferência"}, + {"sv","Överför framsteg"}, + {"da","Overførselsfremgang"}, + {"ko","전송 진행"}, + {"it","Avanzamento del trasferimento"}, + {"ru","Прогресс передачи"} } } }; diff --git a/UpdateForm.cs b/UpdateForm.cs index 61194b5..cbfa04b 100644 --- a/UpdateForm.cs +++ b/UpdateForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/WebSocketClient.cs b/WebSocketClient.cs index 0e3fd73..b1bfe2f 100644 --- a/WebSocketClient.cs +++ b/WebSocketClient.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Win32Api.cs b/Win32Api.cs index 493d854..6e2643b 100644 --- a/Win32Api.cs +++ b/Win32Api.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/altPortForm.cs b/altPortForm.cs index 29a2f21..353fc90 100644 --- a/altPortForm.cs +++ b/altPortForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/rdpPortForm.cs b/rdpPortForm.cs index af56790..07469ef 100644 --- a/rdpPortForm.cs +++ b/rdpPortForm.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2021 Intel Corporation +Copyright 2009-2022 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 6bf01d069cd2e182e50efd98da36e1978592e3ed Mon Sep 17 00:00:00 2001 From: Flynn Date: Thu, 27 Jan 2022 10:52:26 +0100 Subject: [PATCH 07/20] Changed the region of the tiles to float, using fatser Win32 BitBlt for much faster memory paint --- KVMControl.cs | 133 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 127 insertions(+), 6 deletions(-) diff --git a/KVMControl.cs b/KVMControl.cs index af53a5a..81af4c7 100644 --- a/KVMControl.cs +++ b/KVMControl.cs @@ -22,6 +22,8 @@ using System.Drawing; using System.Windows.Forms; using System.ComponentModel; using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Diagnostics; namespace MeshCentralRouter { @@ -57,7 +59,58 @@ namespace MeshCentralRouter private long killNextKeyPress = 0; - private enum KvmCommands + + //System level functions to be used for hook and unhook keyboard input + private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam); + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr SetWindowsHookEx(int id, LowLevelKeyboardProc callback, IntPtr hMod, uint dwThreadId); + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern bool UnhookWindowsHookEx(IntPtr hook); + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr CallNextHookEx(IntPtr hook, int nCode, IntPtr wp, IntPtr lp); + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr GetModuleHandle(string name); + [DllImport("user32.dll", CharSet = CharSet.Auto)] + private static extern short GetAsyncKeyState(Keys key); + [DllImport("user32.dll")] + static extern IntPtr GetForegroundWindow(); + + + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] public static extern IntPtr CreateCompatibleDC(IntPtr hDC); + [DllImport("gdi32.dll", ExactSpelling = true)] public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); + [DllImport("gdi32.dll", ExactSpelling = true)] public static extern IntPtr DeleteObject(IntPtr hObject); + [DllImport("gdi32.dll")] private static extern bool BitBlt(IntPtr hdcDest, Int32 nXDest, Int32 nYDest, Int32 nWidth, Int32 nHeight, IntPtr hdcSrc, Int32 nXSrc, Int32 nYSrc, TernaryRasterOperations dwRop); + [DllImport("gdi32.dll")] private static extern bool StretchBlt(IntPtr hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, TernaryRasterOperations dwRop); + [DllImport("gdi32.dll")] static extern bool SetStretchBltMode(IntPtr hdc, StretchMode iStretchMode); + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] private static extern bool DeleteDC(IntPtr hdc); + public enum StretchMode + { + STRETCH_ANDSCANS = 1, + STRETCH_ORSCANS = 2, + STRETCH_DELETESCANS = 3, + STRETCH_HALFTONE = 4, + } + + public enum TernaryRasterOperations + { + SRCCOPY = 0x00CC0020, /* dest = source*/ + SRCPAINT = 0x00EE0086, /* dest = source OR dest*/ + SRCAND = 0x008800C6, /* dest = source AND dest*/ + SRCINVERT = 0x00660046, /* dest = source XOR dest*/ + SRCERASE = 0x00440328, /* dest = source AND (NOT dest )*/ + NOTSRCCOPY = 0x00330008, /* dest = (NOT source)*/ + NOTSRCERASE = 0x001100A6, /* dest = (NOT src) AND (NOT dest) */ + MERGECOPY = 0x00C000CA, /* dest = (source AND pattern)*/ + MERGEPAINT = 0x00BB0226, /* dest = (NOT source) OR dest*/ + PATCOPY = 0x00F00021, /* dest = pattern*/ + PATPAINT = 0x00FB0A09, /* dest = DPSnoo*/ + PATINVERT = 0x005A0049, /* dest = pattern XOR dest*/ + DSTINVERT = 0x00550009, /* dest = (NOT dest)*/ + BLACKNESS = 0x00000042, /* dest = BLACK*/ + WHITENESS = 0x00FF0062, /* dest = WHITE*/ + }; + + private enum KvmCommands { Nop = 0, Key = 1, @@ -218,7 +271,7 @@ namespace MeshCentralRouter ushort tile_y = (ushort)((buffer[off + 6] << 8) + buffer[off + 7]); try { newtile = Image.FromStream(new System.IO.MemoryStream(buffer, off + 8, blen - 8)); } catch (Exception) { return blen; } Rectangle r = new Rectangle((int)tile_x, (int)tile_y, newtile.Width, newtile.Height); - Rectangle r3 = new Rectangle((int)((double)tile_x / (double)scalefactor) - 2, (int)((double)tile_y / (double)scalefactor) - 2, (int)((double)newtile.Width / (double)scalefactor) + 4, (int)((double)newtile.Height / (double)scalefactor) + 4); + Rectangle r3 = new Rectangle((int)Math.Round((double)tile_x / (double)scalefactor) - 2, (int)Math.Round((double)tile_y / (double)scalefactor) - 2, (int)Math.Round((double)newtile.Width / (double)scalefactor) + 4, (int)Math.Round((double)newtile.Height / (double)scalefactor) + 4); tilecount++; // Winform mode @@ -226,8 +279,21 @@ namespace MeshCentralRouter { lock (desktop) { - desktopGraphics.DrawImage(newtile, new Rectangle((int)tile_x, (int)tile_y, newtile.Width, newtile.Height), new Rectangle(0, 0, newtile.Width, newtile.Height), GraphicsUnit.Pixel); - if (debugmode) + Graphics MemGraphics = Graphics.FromImage(newtile); + + IntPtr hBitmap = ((Bitmap)newtile).GetHbitmap(); + IntPtr memdc = MemGraphics.GetHdc(); + IntPtr pOrig = SelectObject(memdc, hBitmap); + IntPtr dcDst = desktopGraphics.GetHdc(); + + + bool bok = BitBlt(dcDst, (int)tile_x, (int)tile_y, (int)newtile.Width, (int)newtile.Height, memdc, (int)0, (int)0, TernaryRasterOperations.SRCCOPY); + + IntPtr pNew = SelectObject(memdc, pOrig); // == hBitmap + DeleteObject(pNew); + desktopGraphics.ReleaseHdc(dcDst); + MemGraphics.ReleaseHdc(memdc); + if(debugmode) { desktopGraphics.DrawRectangle(RedPen, new Rectangle((int)tile_x, (int)tile_y, newtile.Width - 1, newtile.Height - 1)); desktopGraphics.DrawString(string.Format("{0} / {1}kb", tilecount, blen / 2014), DebugFont, RedPen.Brush, new Point((int)tile_x, (int)tile_y)); @@ -362,7 +428,7 @@ namespace MeshCentralRouter else { //g.DrawImage((Image)desktop, new Rectangle(0, 0, Width, Height), 0, 0, screenWidth, screenHeight, GraphicsUnit.Pixel); - g.DrawImage((Image)desktop, e.ClipRectangle, (int)((double)e.ClipRectangle.Left * (double)scalefactor), (int)((double)e.ClipRectangle.Top * (double)scalefactor), (int)((double)e.ClipRectangle.Width * (double)scalefactor), (int)((double)e.ClipRectangle.Height * (double)scalefactor), GraphicsUnit.Pixel); + g.DrawImage((Image)desktop, e.ClipRectangle, (float)((double)e.ClipRectangle.Left * (double)scalefactor), (float)((double)e.ClipRectangle.Top * (double)scalefactor), (float)((double)e.ClipRectangle.Width * (double)scalefactor), (float)((double)e.ClipRectangle.Height * (double)scalefactor), GraphicsUnit.Pixel); } } } @@ -422,7 +488,7 @@ namespace MeshCentralRouter if (remoteKeyboardMap == true) { SendKey((byte)e.KeyCode, action); return; } // Use old key system that uses the remote keyboard mapping. string keycode = e.KeyCode.ToString(); - if ((action == 0) && (e.Control == false) && (e.Alt == false) && (((e.KeyValue >= 48) && (e.KeyValue <= 57)) || (keycode.Length == 1) || (keycode.StartsWith("Oem") == true))) return; + if ((action == 0) && (e.Control == false) && (e.Alt == false) && (((e.KeyValue >= 48) && (e.KeyValue <= 57))|| ((e.KeyValue >= 96) && (e.KeyValue <= 105)) || (keycode.Length == 1) || (keycode.StartsWith("Oem") == true))) return; if ((e.Control == true) || (e.Alt == true)) { killNextKeyPress = DateTime.Now.Ticks; } SendKey((byte)e.KeyCode, action); e.Handled = true; @@ -738,5 +804,60 @@ namespace MeshCentralRouter return false; } + + // Structure contain information about low-level keyboard input event + private struct KBDLLHOOKSTRUCT + { + public Keys key; + public int scanCode; + public int flags; + public int time; + public IntPtr extra; } + + + + //Declaring Global objects + private IntPtr ptrHook; + private LowLevelKeyboardProc objKeyboardProcess; + + private IntPtr captureKey(int nCode, IntPtr wp, IntPtr lp) + { + bool bIsForegroundWindow = false; + try { bIsForegroundWindow = GetForegroundWindow() == this.ParentForm.Handle; } catch { } + if(nCode >= 0 && bIsForegroundWindow) + { + KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lp, typeof(KBDLLHOOKSTRUCT)); + + // Disabling Windows keys + + if(objKeyInfo.key == Keys.RWin || objKeyInfo.key == Keys.LWin) + { + bool bKeyDown = wp == (IntPtr)0x0100/*WM_KEYDOWN*/; + SendKey(new KeyEventArgs((Keys)objKeyInfo.key), (byte)(bKeyDown ? 0 : 1)); + // SendKey(new KeyEventArgs((Keys)objKeyInfo.key), 0); + return (IntPtr)1; // if 0 is returned then All the above keys will be enabled + // return (IntPtr)0; // if 0 is returned then All the above keys will be enabled + + + } + } + return CallNextHookEx(ptrHook, nCode, wp, lp); + } + + bool HasAltModifier(int flags) + { + return (flags & 0x20) == 0x20; + } + + private void KVMControl_Load(object sender, EventArgs e) + { + ProcessModule objCurrentModule = Process.GetCurrentProcess().MainModule; + objKeyboardProcess = new LowLevelKeyboardProc(captureKey); + ptrHook = SetWindowsHookEx(13, objKeyboardProcess, GetModuleHandle(objCurrentModule.ModuleName), 0); + } + + /* Code to Disable WinKey, Alt+Tab, Ctrl+Esc Ends Here */ + + } } From cd2401989276e00938be4e0ab676e2d4084ae459 Mon Sep 17 00:00:00 2001 From: Flynn Date: Thu, 27 Jan 2022 10:53:26 +0100 Subject: [PATCH 08/20] Keaboard hook - OnLoad (for remote Win-Key) --- KVMControl.Designer.cs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/KVMControl.Designer.cs b/KVMControl.Designer.cs index 07e2537..fe2cda6 100644 --- a/KVMControl.Designer.cs +++ b/KVMControl.Designer.cs @@ -28,23 +28,24 @@ /// private void InitializeComponent() { - this.SuspendLayout(); - // - // KVMControl - // - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; - this.BackColor = System.Drawing.SystemColors.Control; - this.Margin = new System.Windows.Forms.Padding(4); - this.Name = "KVMControl"; - this.Size = new System.Drawing.Size(585, 364); - this.Paint += new System.Windows.Forms.PaintEventHandler(this.KVMControl_Paint); - this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.KVMControl_KeyDown); - this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.KVMControl_KeyPress); - this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.KVMControl_KeyUp); - this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.KVMControl_MouseDown); - this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.KVMControl_MouseMove); - this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.KVMControl_MouseUp); - this.ResumeLayout(false); + this.SuspendLayout(); + // + // KVMControl + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.SystemColors.Control; + this.Margin = new System.Windows.Forms.Padding(4); + this.Name = "KVMControl"; + this.Size = new System.Drawing.Size(585, 364); + this.Load += new System.EventHandler(this.KVMControl_Load); + this.Paint += new System.Windows.Forms.PaintEventHandler(this.KVMControl_Paint); + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.KVMControl_KeyDown); + this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.KVMControl_KeyPress); + this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.KVMControl_KeyUp); + this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.KVMControl_MouseDown); + this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.KVMControl_MouseMove); + this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.KVMControl_MouseUp); + this.ResumeLayout(false); } From 8743d00519d6c40d2792a75ee8ab1e7ea58b9351 Mon Sep 17 00:00:00 2001 From: ylianst Date: Fri, 28 Jan 2022 13:16:04 -0800 Subject: [PATCH 09/20] Added remote desktop split screen mode --- KVMControl.Designer.cs | 1 + KVMControl.cs | 170 ++++++++- KVMResizeControl.Designer.cs | 4 + KVMResizeControl.cs | 2 + KVMViewer.Designer.cs | 13 + KVMViewer.cs | 63 +++- KVMViewer.resx | 158 +++++--- KVMViewerExtra.Designer.cs | 65 ++++ KVMViewerExtra.cs | 116 ++++++ KVMViewerExtra.resx | 599 +++++++++++++++++++++++++++++++ MeshCentralRouter.csproj | 9 + Properties/Resources.Designer.cs | 18 + Properties/Resources.resx | 6 + Settings.cs | 6 +- 14 files changed, 1166 insertions(+), 64 deletions(-) create mode 100644 KVMViewerExtra.Designer.cs create mode 100644 KVMViewerExtra.cs create mode 100644 KVMViewerExtra.resx diff --git a/KVMControl.Designer.cs b/KVMControl.Designer.cs index 07e2537..d8aac7c 100644 --- a/KVMControl.Designer.cs +++ b/KVMControl.Designer.cs @@ -37,6 +37,7 @@ this.Margin = new System.Windows.Forms.Padding(4); this.Name = "KVMControl"; this.Size = new System.Drawing.Size(585, 364); + this.Load += new System.EventHandler(this.KVMControl_Load); this.Paint += new System.Windows.Forms.PaintEventHandler(this.KVMControl_Paint); this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.KVMControl_KeyDown); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.KVMControl_KeyPress); diff --git a/KVMControl.cs b/KVMControl.cs index af53a5a..447bc7c 100644 --- a/KVMControl.cs +++ b/KVMControl.cs @@ -28,7 +28,7 @@ namespace MeshCentralRouter public partial class KVMControl : UserControl { private bool remotepause = true; - private Bitmap desktop = null; + public Bitmap desktop = null; private Graphics desktopGraphics = null; public uint screenWidth = 0; public uint screenHeight = 0; @@ -49,13 +49,17 @@ namespace MeshCentralRouter public double DpiX = 96; public double DpiY = 96; public KVMViewer parent = null; + public KVMViewerExtra parentEx = null; private readonly KVMControlHook ControlHook; private readonly KVMControlHook.KVMCallback KeyboardCallback; private bool isHookWanted; private bool isHookPriority; private bool keyboardIsAttached; private long killNextKeyPress = 0; - + private bool controlLoaded = false; + public Rectangle[] displayInfo = null; + public Rectangle displayCrop = Rectangle.Empty; + public Point displayOrigin = Point.Empty; private enum KvmCommands { @@ -79,6 +83,7 @@ namespace MeshCentralRouter Jumbo = 27, Disconnect = 59, Alert = 65, + DisplayInfo = 82, KeyUnicode = 85, MouseCursor = 88 } @@ -101,6 +106,9 @@ namespace MeshCentralRouter [Description("Fires when it receives the display list.")] public event EventHandler DisplaysReceived; + public delegate void ScreenAreaUpdatedHandler(Bitmap desktop, Rectangle r); + public event ScreenAreaUpdatedHandler ScreenAreaUpdated; + public enum ConnectState { Disconnected, @@ -118,8 +126,14 @@ namespace MeshCentralRouter public double ScaleFactor { get { return scalefactor; } set { scalefactor = value; } } public void SetCompressionParams(int level, int scaling, int framerate) { compressionlevel = level; scalinglevel = scaling; frameRate = framerate; SendCompressionLevel(); } - public int DesktopWidth { get { return (int)screenWidth; } } - public int DesktopHeight { get { return (int)screenHeight; } } + public int DesktopWidth + { + get { if (displayCrop == Rectangle.Empty) { return (int)screenWidth; } else { return displayCrop.Width; } } + } + public int DesktopHeight + { + get { if (displayCrop == Rectangle.Empty) { return (int)screenHeight; } else { return displayCrop.Height; } } + } // Debug public int bytesent = 0; @@ -217,8 +231,6 @@ namespace MeshCentralRouter ushort tile_x = (ushort)((buffer[off + 4] << 8) + buffer[off + 5]); ushort tile_y = (ushort)((buffer[off + 6] << 8) + buffer[off + 7]); try { newtile = Image.FromStream(new System.IO.MemoryStream(buffer, off + 8, blen - 8)); } catch (Exception) { return blen; } - Rectangle r = new Rectangle((int)tile_x, (int)tile_y, newtile.Width, newtile.Height); - Rectangle r3 = new Rectangle((int)((double)tile_x / (double)scalefactor) - 2, (int)((double)tile_y / (double)scalefactor) - 2, (int)((double)newtile.Width / (double)scalefactor) + 4, (int)((double)newtile.Height / (double)scalefactor) + 4); tilecount++; // Winform mode @@ -233,7 +245,40 @@ namespace MeshCentralRouter desktopGraphics.DrawString(string.Format("{0} / {1}kb", tilecount, blen / 2014), DebugFont, RedPen.Brush, new Point((int)tile_x, (int)tile_y)); } } - if (scalefactor == 1) Invalidate(r, false); else Invalidate(r3, false); + + // Update extra displays if needed + Rectangle r = new Rectangle((int)tile_x, (int)tile_y, newtile.Width, newtile.Height); + Rectangle rx = new Rectangle(r.X + displayOrigin.X, r.Y + displayOrigin.Y, r.Width, r.Height); + if (ScreenAreaUpdated != null) ScreenAreaUpdated(desktop, rx); + + if (displayCrop == Rectangle.Empty) + { + if (scalefactor == 1) + { + Invalidate(r, false); + } + else + { + Rectangle r3 = new Rectangle((int)((double)tile_x / (double)scalefactor) - 2, (int)((double)tile_y / (double)scalefactor) - 2, (int)((double)newtile.Width / (double)scalefactor) + 4, (int)((double)newtile.Height / (double)scalefactor) + 4); + Invalidate(r3, false); + } + } + else if (displayCrop.IntersectsWith(rx) == true) + { + Rectangle r2 = new Rectangle(rx.X, rx.Y, rx.Width, rx.Height); + r2.Intersect(displayCrop); + + if (scalefactor == 1) + { + Rectangle r3 = new Rectangle(r2.X - displayCrop.X, r2.Y - displayCrop.Y, r2.Width, r2.Height); + Invalidate(r, false); + } + else + { + Rectangle r3 = new Rectangle((int)((double)(r2.X - displayCrop.X) / (double)scalefactor) - 2, (int)((double)(r2.Y - displayCrop.Y) / (double)scalefactor) - 2, (int)((double)r2.Width / (double)scalefactor) + 4, (int)((double)r2.Height / (double)scalefactor) + 4); + Invalidate(r3, false); + } + } } return blen + jumboHeaderSize; @@ -289,6 +334,31 @@ namespace MeshCentralRouter ChangeMouseCursor(buffer[off + 4]); break; } + case KvmCommands.DisplayInfo: + { + if ((blen < 4) || (((blen - 4) % 10) != 0)) break; + int screenCount = ((blen - 4) / 10); + int ptr = off + 4; + Rectangle[] xDisplayInfo = new Rectangle[screenCount]; + + for (var i = 0; i < screenCount; i++) + { + int id = ((buffer[ptr + 0] << 8) + buffer[ptr + 1]); + int x = ((buffer[ptr + 2] << 8) + buffer[ptr + 3]); + int y = ((buffer[ptr + 4] << 8) + buffer[ptr + 5]); + int w = ((buffer[ptr + 6] << 8) + buffer[ptr + 7]); + int h = ((buffer[ptr + 8] << 8) + buffer[ptr + 9]); + if (x > 32766) { x -= 65536; } + if (y > 32766) { y -= 65536; } + Rectangle r = new Rectangle(x, y, w, h); + xDisplayInfo[id - 1] = r; + ptr += 10; + } + + // Set display information + displayInfo = xDisplayInfo; + break; + } default: { // MessageBox.Show("Should never happen!"); @@ -333,6 +403,11 @@ namespace MeshCentralRouter Invalidate(region); } + public void Repaint(Rectangle rect) + { + Invalidate(rect); + } + protected override void OnPaintBackground(PaintEventArgs e) { // Do not paint background. @@ -355,14 +430,28 @@ namespace MeshCentralRouter { lock (desktop) { - if (scalefactor == 1) + if (displayCrop == Rectangle.Empty) // No cropping { - g.DrawImage(desktop, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel); + if (scalefactor == 1) + { + g.DrawImage(desktop, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel); + } + else + { + g.DrawImage((Image)desktop, e.ClipRectangle, (int)((double)e.ClipRectangle.Left * (double)scalefactor), (int)((double)e.ClipRectangle.Top * (double)scalefactor), (int)((double)e.ClipRectangle.Width * (double)scalefactor), (int)((double)e.ClipRectangle.Height * (double)scalefactor), GraphicsUnit.Pixel); + } } else { - //g.DrawImage((Image)desktop, new Rectangle(0, 0, Width, Height), 0, 0, screenWidth, screenHeight, GraphicsUnit.Pixel); - g.DrawImage((Image)desktop, e.ClipRectangle, (int)((double)e.ClipRectangle.Left * (double)scalefactor), (int)((double)e.ClipRectangle.Top * (double)scalefactor), (int)((double)e.ClipRectangle.Width * (double)scalefactor), (int)((double)e.ClipRectangle.Height * (double)scalefactor), GraphicsUnit.Pixel); + if (scalefactor == 1) // Cropping in effect, this is when we show different displays in different windows + { + g.DrawImage(desktop, e.ClipRectangle, new Rectangle(e.ClipRectangle.X - displayOrigin.X + displayCrop.X, e.ClipRectangle.Y - displayOrigin.Y + displayCrop.Y, e.ClipRectangle.Width, e.ClipRectangle.Height), GraphicsUnit.Pixel); + } + else + { + Rectangle srcRect = new Rectangle((int)((double)(e.ClipRectangle.Left) * (double)scalefactor) - displayOrigin.X + displayCrop.X, (int)((double)(e.ClipRectangle.Top) * (double)scalefactor) - displayOrigin.Y + displayCrop.Y, (int)((double)e.ClipRectangle.Width * (double)scalefactor), (int)((double)e.ClipRectangle.Height * (double)scalefactor)); + g.DrawImage((Image)desktop, e.ClipRectangle, srcRect, GraphicsUnit.Pixel); + } } } } @@ -479,8 +568,16 @@ namespace MeshCentralRouter } } - LastX = (short)((double)e.X * (double)scalefactor); - LastY = (short)((double)e.Y * (double)scalefactor); + if (displayCrop == Rectangle.Empty) + { + LastX = (short)((double)e.X * (double)scalefactor); + LastY = (short)((double)e.Y * (double)scalefactor); + } + else + { + LastX = (short)((int)((double)e.X * (double)scalefactor) - displayOrigin.X + displayCrop.X); + LastY = (short)((int)((double)e.Y * (double)scalefactor) - displayOrigin.Y + displayCrop.Y); + } BinaryWriter bw = GetBinaryWriter(); bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.Mouse)); @@ -563,9 +660,16 @@ namespace MeshCentralRouter //if (state == ConnectState.Disconnected) return; try { - parent.bytesOut += buffer.Length; - parent.bytesOutCompressed += parent.wc.SendBinary(buffer, 0, buffer.Length); - bytesent += buffer.Length; + if (parent != null) + { + parent.bytesOut += buffer.Length; + parent.bytesOutCompressed += parent.wc.SendBinary(buffer, 0, buffer.Length); + bytesent += buffer.Length; + } + else if (parentEx != null) + { + parentEx.mainKvmControl.Send(buffer); + } } catch (Exception) { } } @@ -575,9 +679,16 @@ namespace MeshCentralRouter //if (state == ConnectState.Disconnected) return; try { - parent.bytesOut += str.Length; - parent.bytesOutCompressed += parent.wc.SendString(str); - bytesent += str.Length; + if (parent != null) + { + parent.bytesOut += str.Length; + parent.bytesOutCompressed += parent.wc.SendString(str); + bytesent += str.Length; + } + else if (parentEx != null) + { + parentEx.mainKvmControl.Send(str); + } } catch (Exception) { } } @@ -595,6 +706,10 @@ namespace MeshCentralRouter } catch (Exception) { } } + else if (parentEx != null) + { + parentEx.mainKvmControl.Send(bw); + } RecycleBinaryWriter(bw); } @@ -738,5 +853,22 @@ namespace MeshCentralRouter return false; } + + public void cropDisplay(Point o, Rectangle r) + { + if (IsDisposed || Disposing) return; + displayCrop = r; + displayOrigin = o; + if (controlLoaded) + { + Invoke(new SetSizeHandler(SetSize)); + Invalidate(); + } + } + + private void KVMControl_Load(object sender, EventArgs e) + { + controlLoaded = true; + } } } diff --git a/KVMResizeControl.Designer.cs b/KVMResizeControl.Designer.cs index b60fc9b..6bcc1a3 100644 --- a/KVMResizeControl.Designer.cs +++ b/KVMResizeControl.Designer.cs @@ -89,14 +89,18 @@ // // kvmControl // + this.kvmControl.AutoSendClipboard = false; this.kvmControl.BackColor = System.Drawing.Color.LightCoral; this.kvmControl.CompressionLevel = 60; + this.kvmControl.FrameRate = 100; this.kvmControl.Location = new System.Drawing.Point(33, 31); this.kvmControl.Margin = new System.Windows.Forms.Padding(4); this.kvmControl.Name = "kvmControl"; + this.kvmControl.RemoteKeyboardMap = false; this.kvmControl.ScaleFactor = 1D; this.kvmControl.ScalingLevel = 1024; this.kvmControl.Size = new System.Drawing.Size(450, 314); + this.kvmControl.SwamMouseButtons = false; this.kvmControl.TabIndex = 14; this.kvmControl.DesktopSizeChanged += new System.EventHandler(this.kvmControl_DesktopSizeChanged); this.kvmControl.Resize += new System.EventHandler(this.kvmControl_Resize); diff --git a/KVMResizeControl.cs b/KVMResizeControl.cs index ba7da4b..c1369bb 100644 --- a/KVMResizeControl.cs +++ b/KVMResizeControl.cs @@ -47,6 +47,7 @@ namespace MeshCentralRouter CenterKvmControl(false); } + /* void KVM_StateChanged(object sender, EventArgs e) { if (InvokeRequired) { Invoke(new EventHandler(KVM_StateChanged), sender, e); return; } @@ -55,6 +56,7 @@ namespace MeshCentralRouter //kvmControl.Visible = (kvmControl.State == KVMControl.ConnectState.Connected); if (StateChanged != null) StateChanged(this, e); } + */ void KVM_DisplaysReceived(object sender, EventArgs e) { diff --git a/KVMViewer.Designer.cs b/KVMViewer.Designer.cs index 8e24a40..c57a6e4 100644 --- a/KVMViewer.Designer.cs +++ b/KVMViewer.Designer.cs @@ -51,6 +51,7 @@ namespace MeshCentralRouter this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.updateTimer = new System.Windows.Forms.Timer(this.components); this.topPanel = new System.Windows.Forms.Panel(); + this.splitButton = new System.Windows.Forms.Button(); this.clipOutboundButton = new System.Windows.Forms.Button(); this.clipInboundButton = new System.Windows.Forms.Button(); this.statsButton = new System.Windows.Forms.Button(); @@ -75,6 +76,7 @@ namespace MeshCentralRouter // mainStatusStrip // this.mainStatusStrip.BackColor = System.Drawing.SystemColors.Menu; + this.mainStatusStrip.ImageScalingSize = new System.Drawing.Size(20, 20); this.mainStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.mainToolStripStatusLabel, this.toolStripStatusLabel1}); @@ -101,6 +103,7 @@ namespace MeshCentralRouter // topPanel // this.topPanel.BackColor = System.Drawing.SystemColors.Control; + this.topPanel.Controls.Add(this.splitButton); this.topPanel.Controls.Add(this.clipOutboundButton); this.topPanel.Controls.Add(this.clipInboundButton); this.topPanel.Controls.Add(this.statsButton); @@ -112,6 +115,14 @@ namespace MeshCentralRouter resources.ApplyResources(this.topPanel, "topPanel"); this.topPanel.Name = "topPanel"; // + // splitButton + // + resources.ApplyResources(this.splitButton, "splitButton"); + this.splitButton.Name = "splitButton"; + this.splitButton.TabStop = false; + this.splitButton.UseVisualStyleBackColor = true; + this.splitButton.Click += new System.EventHandler(this.splitButton_Click); + // // clipOutboundButton // resources.ApplyResources(this.clipOutboundButton, "clipOutboundButton"); @@ -183,6 +194,7 @@ namespace MeshCentralRouter // // consentContextMenuStrip // + this.consentContextMenuStrip.ImageScalingSize = new System.Drawing.Size(20, 20); this.consentContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.askConsentBarToolStripMenuItem, this.askConsentToolStripMenuItem, @@ -277,6 +289,7 @@ namespace MeshCentralRouter private ToolStripMenuItem askConsentBarToolStripMenuItem; private ToolStripMenuItem askConsentToolStripMenuItem; private ToolStripMenuItem privacyBarToolStripMenuItem; + private Button splitButton; } } diff --git a/KVMViewer.cs b/KVMViewer.cs index e681e61..6bc7eb9 100644 --- a/KVMViewer.cs +++ b/KVMViewer.cs @@ -41,6 +41,8 @@ namespace MeshCentralRouter private string lastClipboardSent = null; private DateTime lastClipboardTime = DateTime.MinValue; public string lang = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; + private bool splitMode = false; + private KVMViewerExtra[] extraDisplays = null; // Stats public long bytesIn = 0; @@ -69,6 +71,7 @@ namespace MeshCentralRouter kvmControl = resizeKvmControl.KVM; kvmControl.parent = this; kvmControl.DesktopSizeChanged += KvmControl_DesktopSizeChanged; + kvmControl.ScreenAreaUpdated += KvmControl_ScreenAreaUpdated; resizeKvmControl.ZoomToFit = true; UpdateStatus(); this.MouseWheel += MainForm_MouseWheel; @@ -84,6 +87,12 @@ namespace MeshCentralRouter kvmControl.AutoSendClipboard = Settings.GetRegValue("kvmAutoClipboard", "0").Equals("1"); } + private void KvmControl_ScreenAreaUpdated(Bitmap desktop, Rectangle r) + { + if (extraDisplays == null) return; + foreach (KVMViewerExtra x in extraDisplays) { x.UpdateScreenArea(desktop, r); } + } + private void Parent_ClipboardChanged() { if (state != 3) return; @@ -301,6 +310,8 @@ namespace MeshCentralRouter if (wc != null) { // Disconnect + if (splitMode) { splitButton_Click(this, null); } + splitButton.Visible = false; state = 0; wc.Dispose(); wc = null; @@ -392,6 +403,9 @@ namespace MeshCentralRouter // Save window location Settings.SetRegValue("kvmlocation", Location.X + "," + Location.Y + "," + Size.Width + "," + Size.Height); + + // Close any extra windows + extraScreenClosed(); } private void toolStripMenuItem2_DropDownOpening(object sender, EventArgs e) @@ -484,11 +498,15 @@ namespace MeshCentralRouter displaySelectComboBox.Visible = false; displaySelectComboBox.Items.Clear(); } + + // If there are many displays and all displays is selected, enable split/join button. + splitButton.Visible = ((kvmControl.currentDisp == 65535) && (kvmControl.displays.Count > 1)); } private void displaySelectComboBox_SelectionChangeCommitted(object sender, EventArgs e) { - if (kvmControl != null) kvmControl.SendDisplay(((displayTag)displaySelectComboBox.SelectedItem).num); + if (splitMode) { splitButton_Click(this, null); } + if (kvmControl != null) { kvmControl.SendDisplay(((displayTag)displaySelectComboBox.SelectedItem).num); } } private void resizeKvmControl_TouchEnabledChanged(object sender, EventArgs e) @@ -630,5 +648,48 @@ namespace MeshCentralRouter { if (wc != null) { e.Cancel = true; } } + + public void extraScreenClosed() + { + if (splitMode) { splitButton_Click(this, null); } + } + + private void splitButton_Click(object sender, EventArgs e) + { + if (splitMode) + { + kvmControl.cropDisplay(Point.Empty, Rectangle.Empty); + splitButton.Text = Translate.T(Properties.Resources.Split, lang); + splitMode = false; + if (extraDisplays != null) + { + // Close all extra displays + for (int i = 0; i < extraDisplays.Length; i++) + { + KVMViewerExtra extraDisplay = extraDisplays[i]; + extraDisplay.Close(); + } + extraDisplays = null; + } + } + else if ((kvmControl.displayInfo != null) && (kvmControl.displayInfo.Length > 1)) + { + int minx = 0; + int miny = 0; + foreach (Rectangle r in kvmControl.displayInfo) { if (r.X < minx) { minx = r.X; } if (r.Y < miny) { miny = r.Y; } } + kvmControl.cropDisplay(new Point(minx, miny), kvmControl.displayInfo[0]); + splitButton.Text = Translate.T(Properties.Resources.Join, lang); + splitMode = true; + + // Open extra displays + extraDisplays = new KVMViewerExtra[kvmControl.displayInfo.Length - 1]; + for (int i = 1; i < kvmControl.displayInfo.Length; i++) + { + KVMViewerExtra extraDisplay = new KVMViewerExtra(parent, this, node, kvmControl, i); + extraDisplays[i - 1] = extraDisplay; + extraDisplay.Show(parent); + } + } + } } } diff --git a/KVMViewer.resx b/KVMViewer.resx index 482f5f7..270e7a6 100644 --- a/KVMViewer.resx +++ b/KVMViewer.resx @@ -122,7 +122,7 @@ - 1029, 17 + 1372, 20 --- @@ -131,7 +131,7 @@ MiddleLeft - 13, 17 + 16, 20 v @@ -141,10 +141,14 @@ False - 0, 727 + 0, 897 + + + + 1, 0, 19, 0 - 1044, 22 + 1392, 25 9 @@ -167,7 +171,42 @@ 154, 17 - + + Top, Right + + + NoControl + + + 1048, 4 + + + 4, 4, 4, 4 + + + 119, 32 + + + 8 + + + Split + + + False + + + splitButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + topPanel + + + 0 + Top, Right @@ -178,10 +217,13 @@ NoControl - 881, 3 + 1175, 4 + + + 4, 4, 4, 4 - 30, 26 + 40, 32 3 @@ -196,7 +238,7 @@ topPanel - 0 + 1 Top, Right @@ -208,10 +250,13 @@ NoControl - 917, 3 + 1223, 4 + + + 4, 4, 4, 4 - 30, 26 + 40, 32 4 @@ -232,7 +277,7 @@ topPanel - 1 + 2 Top, Right @@ -241,10 +286,13 @@ NoControl - 989, 3 + 1319, 4 + + + 4, 4, 4, 4 - 52, 26 + 69, 32 7 @@ -262,16 +310,19 @@ topPanel - 2 + 3 - 13 + 16 - 288, 5 + 384, 6 + + + 4, 4, 4, 4 - 128, 21 + 169, 24 5 @@ -289,16 +340,19 @@ topPanel - 3 + 4 NoControl - 193, 3 + 257, 4 + + + 4, 4, 4, 4 - 89, 26 + 119, 32 2 @@ -316,7 +370,7 @@ topPanel - 4 + 5 Top, Right @@ -325,10 +379,13 @@ NoControl - 953, 3 + 1271, 4 + + + 4, 4, 4, 4 - 30, 26 + 40, 32 6 @@ -343,7 +400,7 @@ topPanel - 5 + 6 False @@ -352,10 +409,13 @@ NoControl - 98, 3 + 131, 4 + + + 4, 4, 4, 4 - 89, 26 + 119, 32 1 @@ -373,31 +433,31 @@ topPanel - 6 + 7 518, 17 - 171, 22 + 198, 24 Ask Consent + Bar - 171, 22 + 198, 24 Ask Consent - 171, 22 + 198, 24 Privacy Bar - 172, 70 + 199, 76 consentContextMenuStrip @@ -409,10 +469,13 @@ NoControl - 3, 3 + 4, 4 + + + 4, 4, 4, 4 - 89, 26 + 119, 32 0 @@ -430,7 +493,7 @@ topPanel - 7 + 8 Top @@ -438,8 +501,11 @@ 0, 0 + + 4, 4, 4, 4 + - 1044, 32 + 1392, 39 11 @@ -469,10 +535,13 @@ NoControl - 12, 59 + 16, 73 + + + 4, 0, 4, 0 - 70, 25 + 86, 31 12 @@ -502,10 +571,13 @@ Fill - 0, 32 + 0, 39 + + + 4, 4, 4, 4 - 1044, 695 + 1392, 858 10 @@ -514,7 +586,7 @@ resizeKvmControl - MeshCentralRouter.KVMResizeControl, MeshCentralRouter, Version=1.7.7835.29677, Culture=neutral, PublicKeyToken=null + MeshCentralRouter.KVMResizeControl, MeshCentralRouter, Version=1.8.8063.22517, Culture=neutral, PublicKeyToken=null $this @@ -526,10 +598,10 @@ True - 6, 13 + 8, 16 - 1044, 749 + 1392, 922 @@ -957,7 +1029,7 @@ - 2, 2, 2, 2 + 3, 2, 3, 2 CenterScreen diff --git a/KVMViewerExtra.Designer.cs b/KVMViewerExtra.Designer.cs new file mode 100644 index 0000000..ca0b3c7 --- /dev/null +++ b/KVMViewerExtra.Designer.cs @@ -0,0 +1,65 @@ +using System.Windows.Forms; + +namespace MeshCentralRouter +{ + partial class KVMViewerExtra + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(KVMViewerExtra)); + this.resizeKvmControl = new MeshCentralRouter.KVMResizeControl(); + this.SuspendLayout(); + // + // resizeKvmControl + // + this.resizeKvmControl.BackColor = System.Drawing.Color.Gray; + resources.ApplyResources(this.resizeKvmControl, "resizeKvmControl"); + this.resizeKvmControl.Name = "resizeKvmControl"; + this.resizeKvmControl.ZoomToFit = false; + this.resizeKvmControl.Enter += new System.EventHandler(this.resizeKvmControl_Enter); + this.resizeKvmControl.Leave += new System.EventHandler(this.resizeKvmControl_Leave); + // + // KVMViewerExtra + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Gray; + this.Controls.Add(this.resizeKvmControl); + this.Name = "KVMViewerExtra"; + this.Activated += new System.EventHandler(this.KVMViewer_Activated); + this.Deactivate += new System.EventHandler(this.KVMViewer_Deactivate); + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.KVMViewerExtra_FormClosed); + this.Load += new System.EventHandler(this.MainForm_Load); + this.ResumeLayout(false); + + } + + #endregion + private KVMResizeControl resizeKvmControl; + } +} + diff --git a/KVMViewerExtra.cs b/KVMViewerExtra.cs new file mode 100644 index 0000000..faea83a --- /dev/null +++ b/KVMViewerExtra.cs @@ -0,0 +1,116 @@ +/* +Copyright 2009-2022 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +using System; +using System.Drawing; +using System.Windows.Forms; +using System.Threading; + +namespace MeshCentralRouter +{ + public partial class KVMViewerExtra : Form + { + private MainForm parent = null; + private KVMViewer mainViewer = null; + private KVMControl kvmControl = null; + public KVMControl mainKvmControl = null; + private int displayId; + public string lang = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; + + public KVMViewerExtra(MainForm parent, KVMViewer mainViewer, NodeClass node, KVMControl mainKvmControl, int displayId) + { + this.parent = parent; + this.mainViewer = mainViewer; + this.mainKvmControl = mainKvmControl; + this.displayId = displayId; + InitializeComponent(); + Translate.TranslateControl(this); + this.Text += " - " + node.name + " (" + displayId + ")"; + kvmControl = resizeKvmControl.KVM; + kvmControl.desktop = mainKvmControl.desktop; + kvmControl.parentEx = this; + //kvmControl.Visible = true; + kvmControl.DesktopSizeChanged += KvmControl_DesktopSizeChanged; + kvmControl.cropDisplay(mainKvmControl.displayOrigin, mainKvmControl.displayInfo[displayId]); + resizeKvmControl.ZoomToFit = true; + this.MouseWheel += MainForm_MouseWheel; + } + + public void UpdateScreenArea(Bitmap desktop, Rectangle r) + { + if (kvmControl.displayCrop.IntersectsWith(r) == false) return; + Rectangle r2 = new Rectangle(r.X, r.Y, r.Width, r.Height); + r2.Intersect(kvmControl.displayCrop); + //kvmControl.Repaint(new Rectangle(r2.X - kvmControl.displayCrop.X, r2.Y - kvmControl.displayCrop.Y, r2.Width, r2.Height)); + kvmControl.Repaint(null); + } + + private void KvmControl_DesktopSizeChanged(object sender, EventArgs e) + { + //kvmControl.Visible = true; + } + + void MainForm_MouseWheel(object sender, MouseEventArgs e) + { + if (e.Delta == 0) return; + Control c = this.GetChildAtPoint(e.Location); + if (c != null && c == resizeKvmControl) resizeKvmControl.MouseWheelEx(sender, e); + } + + private void MainForm_Load(object sender, EventArgs e) + { + this.Size = new Size(820, 480); + resizeKvmControl.CenterKvmControl(false); + kvmControl.Repaint(null); + } + + public void OnScreenChanged() + { + resizeKvmControl.CenterKvmControl(true); + } + + private void resizeKvmControl_Enter(object sender, EventArgs e) + { + kvmControl.AttachKeyboard(); + } + + private void resizeKvmControl_Leave(object sender, EventArgs e) + { + kvmControl.DetacheKeyboard(); + } + + private void KVMViewer_Deactivate(object sender, EventArgs e) + { + kvmControl.DetacheKeyboard(); + } + + private void KVMViewer_Activated(object sender, EventArgs e) + { + kvmControl.AttachKeyboard(); + } + + bool isPointVisibleOnAScreen(Point p) + { + foreach (Screen s in Screen.AllScreens) { if ((p.X < s.Bounds.Right) && (p.X > s.Bounds.Left) && (p.Y > s.Bounds.Top) && (p.Y < s.Bounds.Bottom)) return true; } + return false; + } + + private void KVMViewerExtra_FormClosed(object sender, FormClosedEventArgs e) + { + mainViewer.extraScreenClosed(); + } + } +} diff --git a/KVMViewerExtra.resx b/KVMViewerExtra.resx new file mode 100644 index 0000000..d47f4c9 --- /dev/null +++ b/KVMViewerExtra.resx @@ -0,0 +1,599 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Fill + + + + 0, 0 + + + 4, 4, 4, 4 + + + 826, 522 + + + + 10 + + + resizeKvmControl + + + MeshCentralRouter.KVMResizeControl, MeshCentralRouter, Version=1.8.8062.29471, Culture=neutral, PublicKeyToken=null + + + $this + + + 0 + + + True + + + 8, 16 + + + 826, 522 + + + + AAABAAkAEBAQAAEABAAoAQAAlgAAABAQAAABAAgAaAUAAL4BAAAgIBAAAQAEAOgCAAAmBwAAICAAAAEA + CACoCAAADgoAADAwEAABAAQAaAYAALYSAAAwMAAAAQAIAKgOAAAeGQAAEBAAAAEAIABoBAAAxicAACAg + AAABACAAqBAAAC4sAAAwMAAAAQAgAKglAADWPAAAKAAAABAAAAAgAAAAAQAEAAAAAACAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8A + AAD/AP8A//8AAP///wAACIiHh4eAAAAPiIh4eAAAAAAIh3eAAACIiIiIiIh4eI+IiIiIiIiIiEREREZE + Z4iIRGRMfIyMiIhlxMTIeMeIiFZEbHjIjoiIbExMiIiHiIhWxsyIiIiIiExMx4iIiIiITGzIj4+IiIhM + TM6I6OiIiHiIiIeIiIgI+IiIiIiIiOAHAADgDwAA+B8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAoAAAAEAAAACAAAAABAAgAAAAAAAABAAAAAAAAAAAAAAAB + AAAAAQAAAAAAAIAAAACGCwkAlAAAAJQNAgCfEQAAnBsQAJgdEQCiDgAAqQ0AAKgSAACqFQAApxkNAKUc + DwCyEgAAsRUAALQXAAC/FgIAuBgAAL0YAACaJhwArCcVAKMnHQC7Mh8AmDAoAJ42LACqMCMApTctAKU+ + MwDAGwAAwRwAAMUdAADKGgAAyh4FANIbAADdGQAA4RoAAOcaAADRIQAA1SMAAPEnCQDkMxMAvkwqALpI + OADMSjYA81A1AKVIQACtSkEAr1ZMAM5dTADUXUgA1GZKANhgSwDdYUwA3WpXAON5ZgDgfWsA6HxoAPp9 + aADmgWgA7IBrAPiKawDqi3oA8JtyAPahdwD6qH8AiYuLAIyOjgCXmpoAmp2dAJ6fnwCeoaEAoKGhAKOj + pACipKQApKamAKaoqQCoqqoAqaytAKyurwCvsbEAsbS1ALO3uAC1uLkAtru8ALm+vgDvk4IA7ZuNAPOX + hQDzn4oA9ZyLAPuuiQD3qpsA+q6eAPu0kQD0saYA+7KjAPi1oAD+sqQA+7+iAP7DswD6xrQA/8a2AP7G + ugD/yboA+s2+ALzBwQC+xMQAvsvNAL/MzQDFyMkAwczNAMnMzADDztAAxM7QAMbQ0QDJ0dIAytLUAMzT + 1QDN1NUA1NbXANjY2ADc3NwA/9LGAP/UxgD/1cgA/9rLAP/i2QD/5twA/+nfAN7h4QDo6OgA/+rgAP/r + 5gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA////AAAAAFVVUk1GRkZGRkYAAAAAAACDeXduU0tGTUYAAAAAAAAAAAB5T0RDQ24AAAAAAIJr + a1VVU1JPT09NTEtLRm53d3J0cnNuc3JucW1tbW1Ld08BAQIBAQMVFRUVFSttS3dNBxQHBAUKFzEyNDUq + bUt3TRgYBwoKDyw4Nzk8NG1Ld0wuHAcPDxE2V1ZYWjtuTXdLMBsIDxIhPl9cXWJZc013Sy8WDxIiKWJn + ZGRoX21Pd0saCR0nJC17fXt+fmVtT3dGDRAdJyU6hX9/hIRoc093SwwRISMoPWNeW0FAP3NSd0ZGRktL + S01PT09SUlNzUgB3d3d3d3d3d3d3c3dzcnjgBwAA4A8AAPgfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAKAAAACAAAABAAAAAAQAEAAAAAAAAAgAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8A + AAD/AP8A//8AAP///wAAAAAAAAAAj4AAAAAAAAAAAAAAAAAIj4iIiAAAAAAAAAAAAAAIj4+Pj4iIAAAA + AAAAAAAAiIj4+I+IiIcAAAAAAAAACIiIj4iIiIh4cAAAAAAAAAiIiPiPiIiHeAAAAAAAAAAIiIiIiIiH + d4cAAAAAAAAAAAiIiId3d3eIiIAAAAAAAAAAh3d3d3eIiIiAAAAAAAAAAACHd3iIiIiIgAAAAAAAAIeH + iIiIh8fEeHAAAAAId4iIiId3xExETH+AAAAAeIiId3RExExsbGx4gAAAD3d3RERERExnx8fHz3AAAACE + RERETExEx8fIx8+IAAAAhERkTERGxnyMjI54iAAAAIR8VkRGxEyMjnjIyIgAAACHRkxExEzGh3fIjIiI + AAAAh0d8RkxsTIeIh4joiAAAAIfHx0xExMiHd46HiIgAAACIR3xExsbHiI6IiHiHAAAAiEjERMTMyI6I + iIiIiAAAAAhHxMbGzGiIiIiIiIiAAAAIbEZMzGzPiIiIiIiIgAAACFZMTGzMj4+Pj4+IiIAAAAhsTGxM + bIj4+Pj/+PiAAAAIVETEzMz/+P+Pj4iIgAAACHTGzGzOiIiIiIiIj3AAAAiETEzGx4iIiIiI+PgAAAAI + hHd3iIiIj4//AAAAAAAACIiIj4+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/8f///4A///4AD//8A + AP/+AAB//gAA//4AAP//gAAf/8AAH//wAB//AAAf4AAAH8AAAB+AAAAfwAAAD8AAAA/AAAAPwAAAD8AA + AA/AAAAPwAAAD8AAAA/gAAAH4AAAB+AAAAfgAAAH4AAAB+AAAAfgAAAP4AAD/+AH////////KAAAACAA + AABAAAAAAQAIAAAAAAAABAAAAAAAAAAAAAAAAQAAAAEAAAAAAAB+AQAAZmdmAGlpagB2dnYAfX1+AIIA + AACMAgAAhQsCAIwMAQCSAAAAmAcAAJMLAQCbDgAAkwwIAIsUCgCUEgUAnRAAAJIYDACLHBQAkB4WAJoe + EgCmAAAAqgYAAKELAAC5CAAApBIAAKsUAACqGAYArBwJALIVAAC5EwAAsxgBALsZAACNJBwAkyQcAKYg + DwC2IA0AoCATAKwjEQCgJxoAsy0bALcxHgCSJiAAliskAJYvKACfMCUAmjIqAI85NACZNjAAmz01AJc+ + OAC0MiEAvDUhAL0/LQDFEwAAwhsAAMsdAADQHAAA2BwAAO8UAADkGwAA6x0AANMgAADbIgAA2iQMAMAs + FQDlIQAA5S4LAPIqAwDhLhgA9j8dAMs8JQDOPygAmUQ8AKhANgCgQTkAr0U6AMNCLwDDRTIAyUYyAMxI + MwDBTD8AzVI/ANZROQDaVj8A8UQiAP5UMgCZU00Al1RRAKRKRACuVUwAsVJHALBUSgCiWlUArFhRALFc + VQCzZF0AmmtqALFvZgC5a2QAr3FtALdwawC+dWsAoHVyALZ4cQDHU0IAzF1MANFWQQDVWUQA2FpFANVe + SAD1X0IAxGlaANVlUgDcZlIA3WhUANhuXQDiY0kA4mZQAOJqVADpcFoAxnRoAN10YgDjd2QA5nllAOp8 + ZgDyfGYA6IBtAPqFbgDjhHQA6YZ0AOyIdgDuingA8Y16APqNeQCDhIQAi4yOAIuOkgCOlZoAlZWVAJSV + mACWm5wAnZ2dAKGFhQCzhIEAp5KSAKCfnwCqnZ4AspOTAL2VkwC5nJsAuaGcAJeepACVoaYAnKCmAJit + qgCfrrEAoqKiAKukpwCmpqgApqmrAKurqwCyp6kAsKqsAKyssAClsLMArbKzAKS6tgCttbkAs7O0ALW5 + vAC6ursA0ZWSAO2WhgDrmIoA8piHAPWbigD7nowAy6KcAOKqnADtrJ0A8qOVAPikkwDwqZ0A/KubAPG1 + ngD/sJ0A9bieAMCtrADbtKoAwre0AMq1sQDFuLYAwbu9ANG1sADbuLMA4K6jAOu8pwDgtKgA57+tAPWw + ogD7tKUA+b+mAPS3qwD+vK0A/r+xANXCvgD1wKoA+8euAOjGuAD+xLIA/sm1AP7EuQD9y7sAvb/DAMG/ + wQC3wcQAvMLDALnGyAC+y8wAw8PDAMTFyADDyswAy8vLANXKxgDSzcsA2M/LAMLP0ADMz9AAx9XWAMzT + 1ADK1tgA09PTANLW2ADU2twA29zcAOzPwgD/zsEA/9LDAP/VyQD/2coA5NvXAOvc1gDs3tgA/93SAP/h + 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 + AADwAAAAAB8AAPAAAAAAHwAA8AAAAAAfAADwAAAAAB8AAPAAAAAAHwAA8AAAAAAfAADwAAAAAB8AAPgA + AAAAHwAA+AAAAAAPAAD4AAAAAB8AAPgAAAAAPwAA+AAAAD//AAD4AAA///8AAPgAP////wAA/D////// + AAD///////8AACgAAAAwAAAAYAAAAAEACAAAAAAAAAkAAAAAAAAAAAAAAAEAAAABAAAAAAAAX19fAGVl + ZQBrbGsAdHR1AHp6egCDAQAAhAoBAIsMAACUBgAAmQYAAJMNAACaDQAAhxEIAIoUCwCOGAwAlBIEAJwQ + AQCTFgkAnhsNAIwaEgCnDAAAtAYAAKMSAACqFAAAphgGAKMbCwCqHgwAshUAALYYAAC7GQAAsR4LAIsj + GgCVJRsAtSILALkgCwCnJBUAqyQSAK4oFwCxJRIAsCoXALsrFwCzLBoAuS4aALIwHwC6MBwAii8oAJUq + IwCJMCkAmTAnAJkzKwCcOS8Aijs0AJw8NACvNicApTYrALUzIAC8NSIAtzopALo7KQClPDIAwxsAAMsd + AADTHQAA5RoAAMYjCADYIQAAzzAVAOckAADwKAIA9TEKAO85FgD0OBIAwTciAMI5JADBPisAyT4oANY8 + IgClQzsAvUQ0ALdKNwDFQS0AykQvANBDLADCRjQAykUwAMRINgDKSjYAwko6AM5NOADXTjYA0VA8APRK + KACNSUEAk0pFAJtTTgCXWFQApktEAKpRSgCzUEUAuVBCALFWTAC4VEoArVdQAKtYUgCmXVgAtF1TALBf + WgCbY14At2BUAJVlYQCcfHkAomZhALhrYwC7c2wAoHRzAL54cAC2f3sAylVDANVaRgDiWkIA12JOANlo + VQDpZUwA+GFDAORrVQDncl0AxHVqAM56bgDRcGIA3XRiAN57awDBfHUA5XpnAPt+ZQCugXsA3oFvAMWF + fADYinwA5oBuAPOBawDqiHYA9Yp1APaRfQCCgoMAioqMAJ2EgwCIkI4AgJ2MAIyNkQCOkZUAjJOYAJKS + lACWlpkAmpqbAKSKigC0iIUAs42LALGSjgCmmJgAh6SYAJ2eogCaoaYAnaWpAJ+trACjo6MApKaqAKim + qACjqawAq6urALWpqQCurrAArLK1AK+4uwC0tLQAurO0ALW2uAC8t7gAtby/ALu7uwDOkIUAyZaPAMSf + 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 + 1v+kpab/r1ZM/6U3Lf+iDgD/sBYA/70YAP/KHgX/6ot6//Sxpv/3qpv/+q6e//6ypP/zn4r/ws3O/6iq + qv/O1NX/oqSk/61KQf+jJx3/sBQA/8EcAP/SGwD/5DMT//uyo//+xrr//sOz///Gtv//ybr/+LWg/8LO + z/+qrKz/zdTW/6Gjo/+qMCP/qQ0A/8AbAP/RIQD/4RoA//NQNf//0sb//9TI///Uxv//18j//9rL//rG + tP/Dzs//rK6v/87U1v+goaH/pRwP/7MWAP/FHQD/1SMA/+caAP/6fWj//+vm///i2f//5tz//+nf///q + 4P/6zb7/xM7Q/6+ysv/O1Nb/oKGh/6cZDf+4GAD/yhoA/90ZAP/xJwn/+Ipr//u/ov/7tJH/+66J//qo + f//2oXf/8Jty/8XO0P+xtLX/ztTW/6Chof+goaH/oKGh/6Gio/+jpaX/paen/6epqf+prKz/rK+v/6+x + sf+xtLX/tLi4/7a7vP/Fz9H/s7e4/87U1njO1Nb/ztTW/87U1v/N1Nb/zdPV/83T1f/M09X/y9LU/8rS + 1P/K0tP/ydHT/8jR0v/H0NH/xs/R/7a6u5XgBwAA4AcAAPAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAAAABAAAAAAQAgAAAAAACAEAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjo6MDurq6I7S0 + tFatra18t7e3hbm5uYeoqKiGjo6Of4KCgmB7e3stg4ODCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkJCQHbCw + sHzHx8fIzs7O8NXV1fvZ2dn+1tbW/s7Ozv7MzMz8wsLC9Kurq9WUlJRrjo6OMAAAAAAAAAAAAAAAAAAA + AAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJWV + lWu+vr7r0tLS/9fX1//b29v/3t7e/9zc3P/U1NT/zc3N/93d3f/b29v/wcHB/8XFxf+4uLj+eXl5UBMT + ExMAAAAMAAAAGgAAABQAAAAHAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACenp5gxsbG/8rKyv/Kysr/z8/P/9fX1//c3Nz/3d3d/9TU1P/MzMz/39/f/8zMzP++vr7/x8fH/7e3 + t/+8vLz/fHx8ygEBAUIAAAA1AAAAKwAAABkAAAAMAAAABAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAmZmZHbm5uf+/v7//wcHB/8bGxv/MzMz/1tbW/93d3f/d3d3/0tLS/8nJyf/S0tL/xMTE/8LC + wv+0tLT/qamp/5+fn/+urq7/KysrgAAAADwAAAAyAAAAJAAAABUAAAAMAAAABAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC4uLggt7e3/7m5uf+9vb3/wcHB/8bGxv/Ozs7/1dXV/9XV1f/Nzc3/xcXF/8PD + w/+9vb3/s7Oz/6Wlpf+Wlpb/lJSU/6ysrP8xMTF1AAAAKwAAAC8AAAAhAAAAFgAAAAwAAAAEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLCwgG2traAwMDA/8DAwP++vr7/wcHB/8XFxf/Jycn/ycnJ/8TE + xP+6urr/sbGx/5+fn/+Ghob/gICA/46Ojv+hoaH/kZGR4xwcHE0rKyxLMDAwMQAAABcAAAAQAAAACAAA + AAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHJycgpzc3NKrKys9r+/v/+2trb/rq6u/6ys + rP+mpqb/lpWV/4WFhf92dnb/Zmdm/2lpav+FhYX/oaGi/7O1tf+pqanks7Kz6Li4uf6UlJS1FhYWBAAA + AAUAAAADAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyMjItW1takYaG + hdCbm5vvl5eX/39/f/98e33/fX1//4KEhv+Wlpj/pqep/6yxs/+3wML/vsvM/8nX2f/N09T/v8DB/5ub + m9kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA+PD8cSkpMUHx8f62MjZD/iIqO/4mOk/+OlZr/pbCz/7nGyP/Cz9D/ydDR/8/Lyv/RtbD/0ZWS/8q1 + sf/Ax8f/nZ2d6IuLixEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE9QAYcHB0dPz5AOF9f + YWp4eXygjY+SzpWZn+yXnqT/laGm/5+usf+ttbn/t7i6/8G/wf/FuLb/y6Kc/8Z0aP/BTD//tioZ/64Q + AP+mAAD/tnhx/8fV1v+enp72paWlJAAAAAAAAAAAAAAAAAAAAAAAAAAAj4+TM4GAhXd/hIWoh42O3pGT + mPulq6//sru+/7fCxv+5w8b/u8LE/7y4uP/Araz/vZWT/7dwa/+vRTr/qSQT/6gYB/+oFAL/qBMA/6oW + A/+sHAn/ryMQ/7EZBP++dWv/ytfZ/6Chof+ZmZk7AAAAAAAAAAAAAAAAAAAAAAAAAACjoqZ6jo+V/5it + qv+kurb/tbq8/8C9v//Durz/uZyb/69xbf+iSUf/lyUf/5EJAP+PAAD/kgAA/5gHAP+mIA//sC4c/7Mv + Hf+3MR7/uTMh/7w1Iv+/NyL/wSwV/8RpWv/L1tj/o6Sk/5iYmE4AAAAAAAAAAAAAAAAAAAAAAAAAAMXH + y4ukoaT/spOT/7KDg/+iWlX/kSYg/4IAAP+BAAD/fwAA/4MAAP+KBQD/kAoA/5gOAP+fEAD/phQA/7Qy + If+7Py7/vz8t/8NCL//GRDD/yUYy/8xIM//OPyj/y19P/83U1f+oq6v/l5eXYwAAAAAAAAAAAAAAAAAA + AAAAAAAAz9LWbqmkp/9+AgH/hAEB/4gMA/+GDgX/hQwD/4QKAP+GCwD/jg0A/5MOAP+aEAD/ohEA/6YR + AP+tGQX/wEY1/8dTQv/NUj//0FVB/9NXQv/VWUT/2FpF/9pWP//VXkj/0MzL/6+0tf+YmJiBAAAAAAAA + AAAAAAAAAAAAAAAAAADc3+FFrKyw/4gfFv+QHhb/kSIa/44dFf+LGRH/ixQK/44NAP+UDgD/mg8A/6IS + AP+oFQD/qxEA/7YgDf/OW0n/02ZT/9dlUf/aZ1P/3WhU/+BqVf/ia1b/5mpT/+JmUP/Vycb/tby9/5mY + mKkAAAAAAAAAAAAAAAAAAAAAAAAAANTW1yiws7b7jzk0/5IiGv+XLSf/kycg/5MnHv+SGAz/kgsA/5kP + AP+iEgD/qBQA/60VAP+wEQD/wC0W/9huXf/cdWP/33Ri/+N3ZP/leGT/53pm/+l8Z//rfGb/6XBa/9fD + v/+7w8T/mZmZyQAAAAAAAAAAAAAAAAAAAAAAAAAA3N3fErS3u/OXVFH/lCYe/507NP+aNjD/nTIo/5QS + Bf+XDAD/oREA/6cVAP+sFQD/tBcA/7kTAP/LPCX/4oR0/+WFdP/ohXT/6od1/+yIdv/uinj/8Ix5//OP + e//yfGb/27iz/8HKy/+ZmZniAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAt7q+6Zprav+WKSL/pUtE/6VK + Qv+fMCX/kwsA/54QAP+nFAD/rBUA/7QXAP+8GQD/wRQA/9ZROf/rmIr/7JaG/+6Whv/xmIf/85mH//Wb + iv/2nIv/+J+O//qNef/grqP/zNXX/5ucnO8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6vsLXoYWF/5Us + I/+sWFH/rlVM/5oeEv+XCwD/pBMA/6oVAP+xFgD/uRgA/8IZAP/HFgD/32ZR//Cpnf/wopX/86OV//Wl + lv/4p5f/+amY//uqmf/9rJ7//56K/+uqnf/S2t3/np6e9ZqamhAAAAAAAAAAAAAAAAAAAAAAAAAAAL3A + w8CqnZ7/li8o/7NkXf+wVEr/lg4B/58OAP+nFAD/rRUA/7UXAP+/GgD/xRoA/84cAP/ogG3/9Ler//Ww + ov/4sKP/+rOk//u0pf/9tqb//7en//+6rP//sJ3/766e/9bd3/+goKD8mJiYPwAAAAAAAAAAAAAAAAAA + AAAAAAAAvcDEoLKnqf+YMy3/uW1m/6hANv+YBwD/pBMA/60VAP+4GQD/wxwA/88fAP/YHAD/5S4L//ii + kP/+xLn//r+x//7Asv//w7P//8S0///Gtf//yLb//8u6///Gsf/xtZ7/297f/6Ojo/+YmJhuAAAAAAAA + AAAAAAAAAAAAAAAAAADAw8Z9sKqs/5k2MP+6amL/oCAT/6IMAP+vFgD/vBkA/8gdAP/RHwD/2yIA/+Ub + AP/xRCL//r6v///Ow///yr7//8y+///PwP//0MD//9HB///Twv//1MT//9XC//W4nv/e3dz/p6io/5iY + mJEAAAAAAAAAAAAAAAAAAAAAAAAAAL2/wlSysLL/mj83/7FSR/+eDAD/qhIA/7UYAP/AGwD/yh4A/9Qh + AP/eIwD/6hoA//VfQv//0sn//9XK///Tx///1cj//9fJ///Yyf//2sv//9vM///czv//4NH/+b+m/+Tb + 1/+tsbH/l5iYqQAAAAAAAAAAAAAAAAAAAAAAAAAAubq9LrS2uveZRDz/oCca/6ALAP+tFQD/uRkA/8Mc + AP/OHgD/2CEA/+MjAP/uHgD/+oVu///i3P//3NP//9zR///d0v//39P//+DT///i1f//49f//+Ta///o + 3f/9yrX/7N7Y/7q9vv+Yl5e8AAAAAAAAAAAAAAAAAAAAAAAAAACtrrEQtLe77pc+OP+UCAb/pRIA/7AW + AP+8GgD/xhwA/9EgAP/bIwD/5yAA//IqA///r5///+vm///i2v//4tr//+Ta///m2///597//+rg///r + 4///7eX///Hq///YyP/v3db/ys7P/5eXl9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACytbnnmVNN/5MK + B/+nEwD/sxcA/70aAP/IHQD/1SAA/94jAP/pHwD/9j8d///Rxv//8e3//+rl///r5v//7ub//+3m///u + 5f//7OT//+rf///m2v//4tX/+8eu/+zPwv/Z3+H/mJeX65mZmQ4AAAAAAAAAAAAAAAAAAAAAAAAAALO2 + udegdXL/kwsI/6kUAP+1GAD/wBsA/8scAP/ZHQD/4xwA/+8UAP/+VDL//93V///k2///18r//9HD//vN + vP/5yrj/+sey//XAqv/rvKf/57+t/+nHuP/oxrj/6NzX/+bp6v+goKDhqampDgAAAAAAAAAAAAAAAAAA + AAAAAAAAsrS4w6eSkv+TDQn/qgYA/7UHAP++CgD/xxAA/9AaAP/aJAz/4S4Y/+JjSf/iqpz/37Gm/+C0 + qP/XuK//1MK9/9bMx//Yz8v/1c/M/tLS0vDT1tfg0dXXxtHW2LbV2dmv1NbWn8XHyE8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACxs7esrqWn/40kHP+gQTn/sVxV/7FvZv+0hoD/uaGc/8K3tP/GxcX/xczO/cnN + zvDJz9LmytDS1srQ0srLzs+4yMzNo8jLzKPIzM2cyczNf8jMzHDHy8xWx8vMTcfLzEHHy8wzx8vMIQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAK6vs5C5u738vMPE/8HKzPTFzs/oxs/R2cfO0NHHzs/Fx87PrMjN + zpjIzM14yMvMXcfLzEXHy8wzx8vMLcfLzBrHy8wYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAm5ueCMHDxGHHystiw8bHS8THyCnHy8wdAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAf//4ADn/8AAAf+AAAB/AAAAfwAAAH8AAAB/gAAAP+A + AB//wAAP8AAAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAA/AAAAPwAAAB8AAAAfAAAAHwAAAB8AA + AAfAAAAHwAAAB+AAAAPgAAAD4AAAB+AAAAfgAA//4H///ygAAAAwAAAAYAAAAAEAIAAAAAAAgCUAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAALm5uRO0tLREo6OjbKurq32urq6Grq6uia+vr4qioqKIh4eHgoCA + gHV3d3dYdHR0KnR0dAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJaWlhmnp6dvuLi4vMjIyOfNzc3/1tbW/9/f3//h4eH/4ODg/9zc + 3P/Y2Nj/1tbW/9TU1P/Hx8f/u7u7+KamptSNjY2fg4ODQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA + AAIAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBgYEJj4+Pdr29verQ0ND/1tbW/9ra2v/b29v/3Nzc/9vb + 2//Z2dn/1tbW/9HR0f/Ly8v/zs7O/9ra2v/a2tr/ysrK/8HBwf+9vb3/t7e3/5ubm7g1NTU6AAAAAAAA + AAIAAAAJAAAADQAAAA8AAAAOAAAACQAAAAMAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIiCyqqqrOzc3N/83Nzf/Ly8v/z8/P/9PT + 0//X19f/2tra/9vb2//a2tr/19fX/9LS0v/MzMz/0dHR/9/f3//Z2dn/wMDA/7e3t/++vr7/ycnJ/7i4 + uP+wsLD9WVlZiAAAABYAAAAjAAAAKwAAACsAAAAlAAAAGQAAAA0AAAAGAAAAAwAAAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAi4uLJbS0tOfIyMj/w8PD/8bG + xv/Ly8v/zs7O/9LS0v/X19f/29vb/9zc3P/c3Nz/2NjY/9HR0f/Kysr/09PT/+Hh4f/Q0ND/ubm5/8DA + wP/Pz8//urq6/62trf+urq7/ubm5/2FhYawAAABDAAAARgAAAEAAAAA2AAAAKQAAABwAAAARAAAACQAA + AAQAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACJiYkDq6urvcDA + wP++vr7/wsLC/8TExP/IyMj/zMzM/9HR0f/X19f/29vb/93d3f/c3Nz/2NjY/9HR0f/Jycn/0tLS/9vb + 2//FxcX/wcHB/8nJyf+6urr/sLCw/66urv+oqKj/oqKi/6qqqv8fHx93AAAATgAAAEkAAAA+AAAAMwAA + ACYAAAAbAAAAEQAAAAoAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAChoaEXtra29Lm5uf+8vLz/v7+//8LCwv/FxcX/ycnJ/87Ozv/U1NT/2dnZ/9zc3P/b29v/1tbW/87O + zv/Hx8f/zMzM/8zMzP/AwMD/w8PD/7e3t/+ysrL/rq6u/6SkpP+ampr/l5eX/6qqqv9GRkaXAAAARwAA + AEgAAABAAAAANQAAACgAAAAfAAAAFgAAAA4AAAAHAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC6uroWtLS08be3t/+5ubn/vLy8/7+/v//BwcH/xcXF/8nJyf/Pz8//1NTU/9bW + 1v/V1dX/0dHR/8rKyv/ExMT/xcXF/8DAwP++vr7/t7e3/7Gxsf+pqan/n5+f/5WVlf+SkpL/mJiY/6ur + q/9RUVGcAAAAPAAAAEEAAAA6AAAAMQAAACcAAAAeAAAAFgAAAA4AAAAHAAAAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0tLQCtbW1y7W1tf+3t7f/ubm5/729vf+/v7//wcHB/8TE + xP/Hx8f/y8vL/83Nzf/MzMz/ycnJ/8XFxf/BwcH/v7+//7q6uv+ysrL/qamp/6Ghof+Xl5f/kpKS/5OT + k/+YmJj/nZ2d/6urq/8pKSltAAAALgAAADQAAAAzAAAALAAAACMAAAAaAAAAEwAAAAwAAAAHAAAAAgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqampQrOzs/e7u7v/t7e3/7q6 + uv+8vLz/vr6+/8DAwP/CwsL/xMTE/8bGxv/FxcX/wsLC/7y8vP+1tbX/ra2t/6ampv+bm5v/jIyM/3t7 + e/95eXn/ioqK/5SUlP+bm5v/pqam/4GBgcoWFhZFODk5YTk5Olpubm5aEhISKQAAABwAAAAWAAAADgAA + AAgAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdn + Z0WZmZnNu7u7/7a2tv+zs7P/tLS0/7S0tP+zs7P/srKy/7CwsP+tra3/pqam/5ubm/+SkpL/iIiI/3x8 + fP9qamn/X19f/2VlZf97e3z/jY6O/56en/+sra3/tre3/pubnM6urq/iycrK/7a2t+6IiIi+Z2dnKwAA + ABEAAAALAAAABwAAAAMAAAACAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAICAgGTk5ObJ2dneiurq7/qamp/6Ojo/+enp7/m5ub/5ycnP+Pj4//goGB/3p6 + ev9zc3P/bm5u/2tsbP91dnf/hIWG/5iYmv+goaL/sLCx/7e3uP+3t7f/u7u7/8HBwf/AwMD/v7+//L6+ + vv+Xl5ftgICAMQAAAAMAAAADAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAABAAAAAwAAAAYAAAAGAAAAABAQECNGRkZ0eXl5v4+PjuKgoKD4o6Oj/ouL + iv97e3v/gICB/4SEhf+IiYv/kJCT/5manP+oqKv/rq6w/66ur/+vr7D/r6+w/7a3t/+1t7f/u8LD/8LM + zf/Jzs//wcDA/by8vPyfn5/6b29vUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAGAAAACQAAAAwAAAAOAAAADQAAAAUAAAAAFhYXC0BA + QjBvb3GBjo+R7oqKjf+OjpL/kJCU/4+QlP+Skpb/lpaZ/56eof+lpaf/p6mr/6yxtP+1vsD/wMnL/87T + 1P/W09P/2cnG/9+4tP/Wvrn/wMXF/cHBwfyioqL8jIyMbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBAQEARQUFQgtLS8XSkpMNWpq + bGaCgoaYj4+TxJSUmOWQkJT4jY2R/42Nkf+MjJH/i42R/4uOk/+Nkpf/nKSo/6+4u//Dycv/z87P/9TH + xv/Usq7/2p+U/9FwYv/HQS7/wBwE/7QGAP+zX1X/w87P/sTExPyhoaH+n5+fiwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaGhoHJCQlHT8/QTBbW15MfX2AgY6O + kbCYmJ3anJyh+Zubn/+Xl5v/jo6S/4yMkf+KjpL/jJOY/5ihpf+hqKv/rauv/7mwsv/HvLz/yK2q/8mW + j//Oem7/wko6/7kgC/+0FAD/rBAA/6URAP+lFgP/phoI/6YTAf+yVkv/xczN/8fHx/2kpKT/nJycqwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI+PkxNwcHM3dHV4ZouIjqKOjZHTkZGW7piY + nPufn6P/oKCk/5+fov+fn6P/nZ+j/5mfpP+fp6v/oquu/6usr/+8tbb/xra1/8SfnP++eHD/uFRK/682 + J/+nHg7/phgH/6UTAv+lFQP/phoJ/6gfDv+qIRD/rCMR/68kEf+wJRL/sSYT/7EeC/+5UEL/x8vM/8nJ + yf6pqan/nJycxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkZGVao+Pk+aTk5f/kpCW/4Cd + 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 + T//kiXr/5ol5/+iKef/qjHv/7I17/+2OfP/vj33/8JB+//KRf//zkoD/9JOB//WVgv/3kX7/7H1n/9TI + xv/W2dn/ra2t/5mZmdwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOfn5zO5vsH+noSE/4wc + Ff+mS0T/pEhB/6JGP/+kRj7/pkA2/5UWCP+VDQD/mw8A/6ISAP+nFAD/qhUA/64VAP+0FwD/uRkA/74a + AP/DGgD/yScM/+B0Yv/plYb/65SF/+yVhf/ulob/8JeH//GZiP/zmYj/9JqJ//abiv/2nIv/952M//ie + jf/5noz/84Jr/9W8uP/Y3N3/t7e3/5mZmeoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO7u + 7xe9wMLwqJyd/4ojHP+pUEn/qFFK/6dOR/+sUUj/pDYs/5MOAP+ZDwD/nxEA/6YTAP+pFAD/rBUA/7IW + AP+4GAD/vhoA/8McAP/GGwD/zzAV/+aFdP/tn5H/7p2P//Cej//xn5D/86GR//Whkf/2o5L/96ST//il + lP/5ppX/+qaW//unl//8p5f/+4t0/9q0rP/Y3uD/vr6+/5mZmfSenp4HAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPLy8ge/wMLbs7Gz/4ovKP+qUUv/q1hS/61YT/+wV07/nCQX/5UMAP+cEAD/ohIA/6gU + AP+rFQD/sBYA/7YYAP+7GQD/whsA/8YcAP/KGwD/1jwi/+uVhv/wp5v/8aaY//Onmf/1qJr/9qma//iq + m//5q5z/+ayc//utnv/8rp7//a+f//6woP//sKD//5aA/+SzqP/Y4OH/w8PD/5mZmfucnJwiAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGxsi/vMDC/48+Of+qUEr/sF9a/7NhWf+xVUv/lhQG/5kN + AP+gEQD/pRMA/6kVAP+uFQD/tBcA/7kYAP+/GgD/xBwA/8gdAP/NHQD/3Ewz/++jlv/yr6P/86+i//Wv + ov/3sKP/+LGk//mypP/7s6X//LSm//62pv//tqf//7ao//+4qf//uar//6KN/+Wvo//a4eL/yMjI/5mZ + mf6bm5tJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNzs+bw8jL/5hNSP+oTkj/tmpi/7lr + Y/+rRDr/lgwA/50QAP+jEgD/pxQA/6sVAP+xFgD/txgA/78aAP/GHQD/zB4A/9MfAP/aIwL/6WVM//e0 + p//5ua3/+7mr//y6rP/9u63//b2u//6+rv/+v6///8Gw///CsP//w7H//8Sy///Esv//xrT//7Sc/+iv + nP/b4OL/zc3N/5qamv+bm5tzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADW1th3w8nM/5tT + Tv+oTET/u3Ns/7tsZP+eKBv/mAsA/6ERAP+oFAD/rhUA/7cYAP+/GwD/xx0A/88fAP/XIQD/3iIA/+Qj + AP/sLgn/9oFq//3Btf//wrX//8K1///Etv//xbb//8e3///IuP//ybj//8m5///Luv//zLv//827///O + vP//0L3//8Oq/+yulf/c3t//0dHR/5ubm/+ampqcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADc3N5TxMvN/5dYVP+mR0D/wXx1/7ZbUv+aEgT/oxEA/6oUAP+xFgD/uRkA/8EbAP/HHQD/zR4A/9Qg + AP/aIgD/4CMA/+cjAP/vORb/+ZmF//7Jvv//yL3//8m9///Kvf//zL7//82////Ov///z8D//9DA///R + wf//0sH//9PC///Uw///1cT//8y2//Guk//b2tn/2NnZ/56env+ampq6AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADh4eI4xs3P/5dlYv+lQjn/xoF5/6s9Mf+eDAD/qBQA/6wVAP+0FwD/uxkA/8Ib + AP/JHQD/0B8A/9YhAP/cIwD/5CQA/+sjAP/ySyn//K6f///Pxv//zsP//8/E///QxP//0sX//9PF///U + xv//1cb//9bH///Xx///2Mj//9jJ///Zyv//28z//9XD//Wxlv/b09D/3+Dh/6Ghof+ZmZnTAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADU1NYbyc/R85x8ef+iPTP/wnZt/6AeD/+hDwD/qRQA/68V + AP+3GAD/vhoA/8QcAP/LHgD/0yAA/9ghAP/fIwD/6CQA/+0lAP/2YUP//8K2///VzP//1Mr//9XK///W + yv//18v//9jL///ZzP//2sz//9vN///czv//3c///93Q///f0f//4NP//93O//q5nv/dz8n/4+bn/6mp + qf+ZmZnkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADt7e4Jys3Q3qmZmP+cOS//s1BF/5sO + AP+kEgD/qxUA/7EWAP+5GQD/vxsA/8cdAP/OHgD/1SAA/9siAP/jJAD/6yUA//ArBP/6fmX//9LI///a + 0f//2dD//9rQ///b0f//3NH//93S///e0v//39L//+DT///h1f//4tb//+PX///k2P//5dn//+LW//3C + qf/lz8b/6Ozu/7Ozs/+YmJjynp6eBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzM7QuLq0 + tf+SKB7/nhsN/50PAP+mEwD/rBUA/7QXAP+8GQD/wRsA/8kdAP/RHwD/1yEA/90jAP/mJQD/7SQA//Q4 + Ev/+oI3//97X///e1///39b//9/X///g1///4df//+LY///j2P//5Nn//+Xa///m2///593//+fe///o + 3v//6d///+je///Mtv/mzMH/7fHz/8HBwf+Xl5f6nJycJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAwMHDlcPExf+NIxn/lwkA/6ARAP+nFAD/rhUA/7YXAP+9GgD/wxwA/8sdAP/TIAD/2SIA/98j + AP/oJQD/7iUA//dKJ///uq3//+Pd///i2///49v//+Pb///j2///5dz//+bc///n3P//597//+je///p + 4P//6uH//+vi///r4///7OT//+zk///Uwv/lyLz/7/P1/8zMzP+YmJj+nJycSQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAy8vNdsLJyv+KMSj/mQgA/6ERAP+oFAD/rxYA/7gYAP++GgD/xBwA/80e + AP/VIAD/2yIA/+EkAP/pJQD/8CUA//piQ///z8X//+fh///l3///5t///+bf///n4P//6OD//+nh///q + 4f//6+L//+vj///s5P//7OT//+3l///s5P//7OT//+rg///Uv//owK7/8fX3/9bW1v+YmJj/m5ubawAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArq6xVcjR0/+NSUH/mQYA/6MSAP+pFAD/sBYA/7kY + AP+/GwD/xhwA/84eAP/WIQD/3CIA/+MkAP/rJQD/8ioC//x+Zf//39j//+rl///p5P//6uT//+rk///q + 4///6uH//+nf///m3P//5Nj//+HU///czP//18T//9G8//3JtP/5w6v/9ryk//Gtjv/WppL/7/P1/+Xl + 5f+YmJj/np6ejAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0tLUNsXNz/6UZWD/lwUA/6QS + AP+pFAD/sRYA/7oZAP/AGwD/xh0A/9AfAP/WIQD/3SIA/+QkAP/sJAD/9TEK//+TfP//39f//9/W///X + y///0MH//8m4//3DsP/3vqn/9Lqk//S5of/0tp3/9LOY/+mulv/frpr/2LOj/9i+tP/cy8T/4tbR/+bh + 3//m5ub/8fHx/+jo6P+mpqb6s7OzTQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAubm7F8HG + yO+dhIL/lAcA/6USAP+qFAD/sxYA/7wZAP/DGgD/yhsA/9UaAP/bGgD/4BoA/+YaAP/rGwD/7CsE/+1s + Uv/qmYf/4pyM/+GgkP/hpZX/2qqd/9Gxp//Rvrn/1MrH/9nSz//c19b/2dfX/9jZ2v/X29z/297f/9zf + 4Pvb3d3u2tvc39XW1tnb29vG3Nzcst7e3o3MzMxLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAw8PGBby/wdeomZn/lQcA/6YJAP+oCwD/rw0A/7URAP+1GAD/tSIL/7c1IP+3Sjf/vGBQ/8Z1 + aP/Fin//wKCa/8W3tP/LxsX/zs/Q/9HW1//T2Nr/0tfZ/9PX2f/T1db50dPT7NDR0d3Nzs7Xz8/Pwc/P + z63U1NSP0NDQdNLS0k/Ozs8rysrKFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAALCytb2zra7/hTgw/5FKQ/+cZV//roF7/7GSjv+xoaD/tLGy/7vB + w/+/ys3/xdDT/8rU1v/N1db/ztPU983P0OvNzs7dy8vL1MvLy8HKysqmzs7Oj8vLzHnOzs5Oy8vLM8rK + yhrKysoDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK2tr7PCw8P/t7/C/73Fx//Dy83/xMrM/cXJ + y/XHycrqxsfI3MbGx83Hx8jAx8fHp8rKyovIyMhzy8vLUsrKyjnKysoaysrKCwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKCgo3a5ubvAvLy9wr+/ + wK28vL6NwMDBb8LCw1fHx8g8ysrKIMrKyhQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADKysoOysrKAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//4AD//8AAP/8 + AAD4fwAA//AAACAPAAD/4AAAAAcAAP/AAAAAAQAA/4AAAAABAAD/gAAAAAEAAP+AAAAAAQAA/4AAAAAB + AAD/wAAAAAEAAP/gAAAAAAAA//AAAAAHAAD/hAAAAH8AAP4BAAAAfwAA/4AAAAB/AAD8AAAAAH8AAMAA + AAAAfwAAgAAAAAB/AACAAAAAAH8AAIAAAAAAPwAAgAAAAAA/AACAAAAAAD8AAIAAAAAAPwAAwAAAAAA/ + AADAAAAAAD8AAMAAAAAAPwAAwAAAAAA/AADAAAAAAD8AAMAAAAAAHwAAwAAAAAAfAADgAAAAAB8AAOAA + AAAAHwAA4AAAAAAfAADgAAAAAB8AAOAAAAAAHwAA4AAAAAAfAADgAAAAAA8AAPAAAAAADwAA8AAAAAAP + AADwAAAAAA8AAPAAAAAADwAA8AAAAAAPAADwAAAAAB8AAPAAAAAD/wAA+AAAAf//AAD4AAH///8AAPgB + /////wAA/P//////AAA= + + + + 3, 2, 3, 2 + + + CenterScreen + + + Remote Desktop + + + KVMViewerExtra + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/MeshCentralRouter.csproj b/MeshCentralRouter.csproj index f327c63..341f63f 100644 --- a/MeshCentralRouter.csproj +++ b/MeshCentralRouter.csproj @@ -106,6 +106,12 @@ FileDialogMsgForm.cs + + Form + + + KVMViewerExtra.cs + Form @@ -274,6 +280,9 @@ FileDialogMsgForm.cs + + KVMViewerExtra.cs + SshUsernameForm.cs diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index 42538eb..ab5d15a 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -481,6 +481,15 @@ namespace MeshCentralRouter.Properties { } } + /// + /// Looks up a localized string similar to Join. + /// + internal static string Join { + get { + return ResourceManager.GetString("Join", resourceCulture); + } + } + /// /// Looks up a localized string similar to Changing language will close this tool. Are you sure?. /// @@ -835,6 +844,15 @@ namespace MeshCentralRouter.Properties { } } + /// + /// Looks up a localized string similar to Split. + /// + internal static string Split { + get { + return ResourceManager.GetString("Split", resourceCulture); + } + } + /// /// Looks up a localized string similar to Starting.... /// diff --git a/Properties/Resources.resx b/Properties/Resources.resx index dd15f0e..e1b095e 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -448,4 +448,10 @@ ZIP Selected Files + + Join + + + Split + \ No newline at end of file diff --git a/Settings.cs b/Settings.cs index fae005a..27583fc 100644 --- a/Settings.cs +++ b/Settings.cs @@ -37,7 +37,11 @@ namespace MeshCentralRouter /// public static string GetRegValue(string name, string value) { - try { return Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router", name, value).ToString(); } catch (Exception) { return value; } + try { + String v = (String)Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router", name, value); + if (v == null) return value; + return v.ToString(); + } catch (Exception) { return value; } } /// /// This function querys the registry. If the key is found it returns the value as a boolean From 2c66ddc2c2379a3c3c3ca6527a3cc051ccfb57cd Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Fri, 28 Jan 2022 14:11:37 -0800 Subject: [PATCH 10/20] Remote desktop split fixes. --- KVMControl.cs | 1 + KVMViewer.cs | 4 +++- KVMViewerExtra.cs | 13 +++++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/KVMControl.cs b/KVMControl.cs index 447bc7c..e20d9d9 100644 --- a/KVMControl.cs +++ b/KVMControl.cs @@ -249,6 +249,7 @@ namespace MeshCentralRouter // Update extra displays if needed Rectangle r = new Rectangle((int)tile_x, (int)tile_y, newtile.Width, newtile.Height); Rectangle rx = new Rectangle(r.X + displayOrigin.X, r.Y + displayOrigin.Y, r.Width, r.Height); + //Console.WriteLine(rx.ToString()); if (ScreenAreaUpdated != null) ScreenAreaUpdated(desktop, rx); if (displayCrop == Rectangle.Empty) diff --git a/KVMViewer.cs b/KVMViewer.cs index 6bc7eb9..249f39a 100644 --- a/KVMViewer.cs +++ b/KVMViewer.cs @@ -90,7 +90,9 @@ namespace MeshCentralRouter private void KvmControl_ScreenAreaUpdated(Bitmap desktop, Rectangle r) { if (extraDisplays == null) return; - foreach (KVMViewerExtra x in extraDisplays) { x.UpdateScreenArea(desktop, r); } + foreach (KVMViewerExtra x in extraDisplays) { + if (x != null) { x.UpdateScreenArea(desktop, r); } + } } private void Parent_ClipboardChanged() diff --git a/KVMViewerExtra.cs b/KVMViewerExtra.cs index faea83a..1ea595e 100644 --- a/KVMViewerExtra.cs +++ b/KVMViewerExtra.cs @@ -54,8 +54,17 @@ namespace MeshCentralRouter if (kvmControl.displayCrop.IntersectsWith(r) == false) return; Rectangle r2 = new Rectangle(r.X, r.Y, r.Width, r.Height); r2.Intersect(kvmControl.displayCrop); - //kvmControl.Repaint(new Rectangle(r2.X - kvmControl.displayCrop.X, r2.Y - kvmControl.displayCrop.Y, r2.Width, r2.Height)); - kvmControl.Repaint(null); + kvmControl.desktop = desktop; + if (kvmControl.ScaleFactor == 1) + { + Rectangle r3 = new Rectangle(r2.X - kvmControl.displayCrop.X, r2.Y - kvmControl.displayCrop.Y, r2.Width, r2.Height); + kvmControl.Repaint(r3); + } + else + { + Rectangle r3 = new Rectangle((int)(((double)(r2.X - kvmControl.displayCrop.X)) / kvmControl.ScaleFactor) - 2, (int)(((double)(r2.Y - kvmControl.displayCrop.Y)) / kvmControl.ScaleFactor) - 2, (int)(((double)r2.Width) / kvmControl.ScaleFactor) + 4, (int)(((double)r2.Height) / kvmControl.ScaleFactor) + 4); + kvmControl.Repaint(r3); + } } private void KvmControl_DesktopSizeChanged(object sender, EventArgs e) From 5e0a9ae108d48d43de2038846c8f5582140e4a8e Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Mon, 31 Jan 2022 12:45:54 -0800 Subject: [PATCH 11/20] Fixed exception when agent does not have capabilities field. --- MeshCentralServer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MeshCentralServer.cs b/MeshCentralServer.cs index 51fd03d..a2363e7 100644 --- a/MeshCentralServer.cs +++ b/MeshCentralServer.cs @@ -399,7 +399,7 @@ namespace MeshCentralRouter if (node.ContainsKey("agent")) { n.agentid = (int)((Dictionary)node["agent"])["id"]; - n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; + if (((Dictionary)node["agent"]).ContainsKey("caps")) { n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; } else { n.agentcaps = 0; } } if (node.ContainsKey("conn")) { n.conn = (int)node["conn"]; } n.icon = 1; @@ -541,7 +541,7 @@ namespace MeshCentralRouter if (node.ContainsKey("agent")) { n.agentid = (int)((Dictionary)node["agent"])["id"]; - n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; + if (((Dictionary)node["agent"]).ContainsKey("caps")) { n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; } else { n.agentcaps = 0; } } else { @@ -588,7 +588,7 @@ namespace MeshCentralRouter if (node.ContainsKey("agent")) { n.agentid = (int)((Dictionary)node["agent"])["id"]; - n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; + if (((Dictionary)node["agent"]).ContainsKey("caps")) { n.agentcaps = (int)((Dictionary)node["agent"])["caps"]; } else { n.agentcaps = 0; } } else { From ec8672cae527e8b3607c9b3ea2200fb402103a3a Mon Sep 17 00:00:00 2001 From: Flynn Date: Tue, 1 Feb 2022 09:01:02 +0100 Subject: [PATCH 12/20] Listview Grouping --- ListViewExtended.cs | 393 +++++++++++++++++++++++++++++++++++++++ MainForm.Designer.cs | 4 +- MainForm.cs | 47 ++++- MeshCentralRouter.csproj | 3 + 4 files changed, 443 insertions(+), 4 deletions(-) create mode 100644 ListViewExtended.cs diff --git a/ListViewExtended.cs b/ListViewExtended.cs new file mode 100644 index 0000000..0f9241a --- /dev/null +++ b/ListViewExtended.cs @@ -0,0 +1,393 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Reflection; + +namespace MeshCentralRouter +{ + public class ListViewExtended : ListView + { + private const int LVM_FIRST = 0x1000; // ListView messages + private const int LVM_SETGROUPINFO = (LVM_FIRST + 147); // ListView messages Setinfo on Group + private const int WM_LBUTTONUP = 0x0202; // Windows message left button + + private delegate void CallBackSetGroupState(ListViewGroup lstvwgrp, ListViewGroupState state); + private delegate void CallbackSetGroupString(ListViewGroup lstvwgrp, string value); + + /// + /// Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message. + /// To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread's message queue and return immediately, use the PostMessage or PostThreadMessage function. + /// + /// + /// [in] Handle to the window whose window procedure will receive the message. + /// If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows. + /// Microsoft Windows Vista and later. Message sending is subject to User Interface Privilege Isolation (UIPI). The thread of a process can send messages only to message queues of threads in processes of lesser or equal integrity level. + /// + /// [in] Specifies the message to be sent. + /// [in] Specifies additional message-specific information. + /// [in] Type of LVGROUP, Specifies additional message-specific information. + /// + /// Microsoft Windows Vista and later. When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied). + /// Applications that need to communicate using HWND_BROADCAST should use the RegisterWindowMessage function to obtain a unique message for inter-application communication. + /// The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshalling. + /// If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message. However, the sending thread will process incoming nonqueued messages while waiting for its message to be processed. To prevent this, use SendMessageTimeout with SMTO_BLOCK set. For more information on nonqueued messages, see Nonqueued Messages. + /// Windows 95/98/Me: SendMessageW is supported by the Microsoft Layer for Unicode (MSLU). To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows 95/98/Me Systems. + /// + [DllImport("User32.dll"), Description("Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message. To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread's message queue and return immediately, use the PostMessage or PostThreadMessage function.")] + private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, LVGROUP lParam); + + private static int? GetGroupID(ListViewGroup lstvwgrp) + { + int? rtnval = null; + Type GrpTp = lstvwgrp.GetType(); + if (GrpTp != null) + { + PropertyInfo pi = GrpTp.GetProperty("ID", BindingFlags.NonPublic | BindingFlags.Instance); + if (pi != null) + { + object tmprtnval = pi.GetValue(lstvwgrp, null); + if (tmprtnval != null) + { + rtnval = tmprtnval as int?; + } + } + } + return rtnval; + } + + public static void setGrpState(ListViewGroup lstvwgrp, ListViewGroupState state) + { + if (Environment.OSVersion.Version.Major < 6) //Only Vista and forward allows collaps of ListViewGroups + return; + if (lstvwgrp == null || lstvwgrp.ListView == null) + return; + if (lstvwgrp.ListView.InvokeRequired) + lstvwgrp.ListView.Invoke(new CallBackSetGroupState(setGrpState), lstvwgrp, state); + else + { + int? GrpId = GetGroupID(lstvwgrp); + int gIndex = lstvwgrp.ListView.Groups.IndexOf(lstvwgrp); + LVGROUP group = new LVGROUP(); + group.CbSize = Marshal.SizeOf(group); + group.State = state; + group.Mask = ListViewGroupMask.State; + if (GrpId != null) + { + group.IGroupId = GrpId.Value; + SendMessage(lstvwgrp.ListView.Handle, LVM_SETGROUPINFO, GrpId.Value, group); + SendMessage(lstvwgrp.ListView.Handle, LVM_SETGROUPINFO, GrpId.Value, group); + } + else + { + group.IGroupId = gIndex; + SendMessage(lstvwgrp.ListView.Handle, LVM_SETGROUPINFO, gIndex, group); + SendMessage(lstvwgrp.ListView.Handle, LVM_SETGROUPINFO, gIndex, group); + } + lstvwgrp.ListView.Refresh(); + } + } + + private static void setGrpFooter(ListViewGroup lstvwgrp, string footer) + { + if (Environment.OSVersion.Version.Major < 6) //Only Vista and forward allows footer on ListViewGroups + return; + if (lstvwgrp == null || lstvwgrp.ListView == null) + return; + if (lstvwgrp.ListView.InvokeRequired) + lstvwgrp.ListView.Invoke(new CallbackSetGroupString(setGrpFooter), lstvwgrp, footer); + else + { + int? GrpId = GetGroupID(lstvwgrp); + int gIndex = lstvwgrp.ListView.Groups.IndexOf(lstvwgrp); + LVGROUP group = new LVGROUP(); + group.CbSize = Marshal.SizeOf(group); + group.PszFooter = footer; + group.Mask = ListViewGroupMask.Footer; + if (GrpId != null) + { + group.IGroupId = GrpId.Value; + SendMessage(lstvwgrp.ListView.Handle, LVM_SETGROUPINFO, GrpId.Value, group); + } + else + { + group.IGroupId = gIndex; + SendMessage(lstvwgrp.ListView.Handle, LVM_SETGROUPINFO, gIndex, group); + } + } + } + + public void SetGroupState(ListViewGroupState state) + { + foreach (ListViewGroup lvg in this.Groups) + setGrpState(lvg, state); + } + + public void SetGroupFooter(ListViewGroup lvg, string footerText) + { + setGrpFooter(lvg, footerText); + } + + protected override void WndProc(ref Message m) + { + if (m.Msg == WM_LBUTTONUP) + base.DefWndProc(ref m); + base.WndProc(ref m); + } + } + + + /// + /// LVGROUP StructureUsed to set and retrieve groups. + /// + /// + /// LVGROUP myLVGROUP = new LVGROUP(); + /// myLVGROUP.CbSize // is of managed type uint + /// myLVGROUP.Mask // is of managed type uint + /// myLVGROUP.PszHeader // is of managed type string + /// myLVGROUP.CchHeader // is of managed type int + /// myLVGROUP.PszFooter // is of managed type string + /// myLVGROUP.CchFooter // is of managed type int + /// myLVGROUP.IGroupId // is of managed type int + /// myLVGROUP.StateMask // is of managed type uint + /// myLVGROUP.State // is of managed type uint + /// myLVGROUP.UAlign // is of managed type uint + /// myLVGROUP.PszSubtitle // is of managed type IntPtr + /// myLVGROUP.CchSubtitle // is of managed type uint + /// myLVGROUP.PszTask // is of managed type string + /// myLVGROUP.CchTask // is of managed type uint + /// myLVGROUP.PszDescriptionTop // is of managed type string + /// myLVGROUP.CchDescriptionTop // is of managed type uint + /// myLVGROUP.PszDescriptionBottom // is of managed type string + /// myLVGROUP.CchDescriptionBottom // is of managed type uint + /// myLVGROUP.ITitleImage // is of managed type int + /// myLVGROUP.IExtendedImage // is of managed type int + /// myLVGROUP.IFirstItem // is of managed type int + /// myLVGROUP.CItems // is of managed type IntPtr + /// myLVGROUP.PszSubsetTitle // is of managed type IntPtr + /// myLVGROUP.CchSubsetTitle // is of managed type IntPtr + /// + /// + /// The LVGROUP structure was created by Paw Jershauge + /// Created: Jan. 2008. + /// The LVGROUP structure code is based on information from Microsoft's MSDN2 website. + /// The structure is generated via an automated converter and is as is. + /// The structure may or may not hold errors inside the code, so use at own risk. + /// Reference url: http://msdn.microsoft.com/en-us/library/bb774769(VS.85).aspx + /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode), Description("LVGROUP StructureUsed to set and retrieve groups.")] + public struct LVGROUP + { + /// + /// Size of this structure, in bytes. + /// + [Description("Size of this structure, in bytes.")] + public int CbSize; + + /// + /// Mask that specifies which members of the structure are valid input. One or more of the following values:LVGF_NONENo other items are valid. + /// + [Description("Mask that specifies which members of the structure are valid input. One or more of the following values:LVGF_NONE No other items are valid.")] + public ListViewGroupMask Mask; + + /// + /// Pointer to a null-terminated string that contains the header text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the header text. + /// + [Description("Pointer to a null-terminated string that contains the header text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the header text.")] + [MarshalAs(UnmanagedType.LPWStr)] + public string PszHeader; + + /// + /// Size in TCHARs of the buffer pointed to by the pszHeader member. If the structure is not receiving information about a group, this member is ignored. + /// + [Description("Size in TCHARs of the buffer pointed to by the pszHeader member. If the structure is not receiving information about a group, this member is ignored.")] + public int CchHeader; + + /// + /// Pointer to a null-terminated string that contains the footer text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the footer text. + /// + [Description("Pointer to a null-terminated string that contains the footer text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the footer text.")] + [MarshalAs(UnmanagedType.LPWStr)] + public string PszFooter; + + /// + /// Size in TCHARs of the buffer pointed to by the pszFooter member. If the structure is not receiving information about a group, this member is ignored. + /// + [Description("Size in TCHARs of the buffer pointed to by the pszFooter member. If the structure is not receiving information about a group, this member is ignored.")] + public int CchFooter; + + /// + /// ID of the group. + /// + [Description("ID of the group.")] + public int IGroupId; + + /// + /// Mask used with LVM_GETGROUPINFO (Microsoft Windows XP and Windows Vista) and LVM_SETGROUPINFO (Windows Vista only) to specify which flags in the state value are being retrieved or set. + /// + [Description("Mask used with LVM_GETGROUPINFO (Microsoft Windows XP and Windows Vista) and LVM_SETGROUPINFO (Windows Vista only) to specify which flags in the state value are being retrieved or set.")] + public int StateMask; + + /// + /// Flag that can have one of the following values:LVGS_NORMALGroups are expanded, the group name is displayed, and all items in the group are displayed. + /// + [Description("Flag that can have one of the following values:LVGS_NORMAL Groups are expanded, the group name is displayed, and all items in the group are displayed.")] + public ListViewGroupState State; + + /// + /// Indicates the alignment of the header or footer text for the group. It can have one or more of the following values. Use one of the header flags. Footer flags are optional. Windows XP: Footer flags are reserved.LVGA_FOOTER_CENTERReserved. + /// + [Description("Indicates the alignment of the header or footer text for the group. It can have one or more of the following values. Use one of the header flags. Footer flags are optional. Windows XP: Footer flags are reserved.LVGA_FOOTER_CENTERReserved.")] + public uint UAlign; + + /// + /// Windows Vista. Pointer to a null-terminated string that contains the subtitle text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the subtitle text. This element is drawn under the header text. + /// + [Description("Windows Vista. Pointer to a null-terminated string that contains the subtitle text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the subtitle text. This element is drawn under the header text.")] + public IntPtr PszSubtitle; + + /// + /// Windows Vista. Size, in TCHARs, of the buffer pointed to by the pszSubtitle member. If the structure is not receiving information about a group, this member is ignored. + /// + [Description("Windows Vista. Size, in TCHARs, of the buffer pointed to by the pszSubtitle member. If the structure is not receiving information about a group, this member is ignored.")] + public uint CchSubtitle; + + /// + /// Windows Vista. Pointer to a null-terminated string that contains the text for a task link when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the task text. This item is drawn right-aligned opposite the header text. When clicked by the user, the task link generates an LVN_LINKCLICK notification. + /// + [Description("Windows Vista. Pointer to a null-terminated string that contains the text for a task link when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the task text. This item is drawn right-aligned opposite the header text. When clicked by the user, the task link generates an LVN_LINKCLICK notification.")] + [MarshalAs(UnmanagedType.LPWStr)] + public string PszTask; + + /// + /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszTask member. If the structure is not receiving information about a group, this member is ignored. + /// + [Description("Windows Vista. Size in TCHARs of the buffer pointed to by the pszTask member. If the structure is not receiving information about a group, this member is ignored.")] + public uint CchTask; + + /// + /// Windows Vista. Pointer to a null-terminated string that contains the top description text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the top description text. This item is drawn opposite the title image when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTER. + /// + [Description("Windows Vista. Pointer to a null-terminated string that contains the top description text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the top description text. This item is drawn opposite the title image when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTER.")] + [MarshalAs(UnmanagedType.LPWStr)] + public string PszDescriptionTop; + + /// + /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszDescriptionTop member. If the structure is not receiving information about a group, this member is ignored. + /// + [Description("Windows Vista. Size in TCHARs of the buffer pointed to by the pszDescriptionTop member. If the structure is not receiving information about a group, this member is ignored.")] + public uint CchDescriptionTop; + + /// + /// Windows Vista. Pointer to a null-terminated string that contains the bottom description text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the bottom description text. This item is drawn under the top description text when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTER. + /// + [Description("Windows Vista. Pointer to a null-terminated string that contains the bottom description text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the bottom description text. This item is drawn under the top description text when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTER.")] + [MarshalAs(UnmanagedType.LPWStr)] + public string PszDescriptionBottom; + + /// + /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszDescriptionBottom member. If the structure is not receiving information about a group, this member is ignored. + /// + [Description("Windows Vista. Size in TCHARs of the buffer pointed to by the pszDescriptionBottom member. If the structure is not receiving information about a group, this member is ignored.")] + public uint CchDescriptionBottom; + + /// + /// Windows Vista. Index of the title image in the control imagelist. + /// + [Description("Windows Vista. Index of the title image in the control imagelist.")] + public int ITitleImage; + + /// + /// Windows Vista. Index of the extended image in the control imagelist. + /// + [Description("Windows Vista. Index of the extended image in the control imagelist.")] + public int IExtendedImage; + + /// + /// Windows Vista. Read-only. + /// + [Description("Windows Vista. Read-only.")] + public int IFirstItem; + + /// + /// Windows Vista. Read-only in non-owner data mode. + /// + [Description("Windows Vista. Read-only in non-owner data mode.")] + public IntPtr CItems; + + /// + /// Windows Vista. NULL if group is not a subset. Pointer to a null-terminated string that contains the subset title text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the subset title text. + /// + [Description("Windows Vista. NULL if group is not a subset. Pointer to a null-terminated string that contains the subset title text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the subset title text.")] + public IntPtr PszSubsetTitle; + + /// + /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszSubsetTitle member. If the structure is not receiving information about a group, this member is ignored. + /// + [Description("Windows Vista. Size in TCHARs of the buffer pointed to by the pszSubsetTitle member. If the structure is not receiving information about a group, this member is ignored.")] + public IntPtr CchSubsetTitle; + } + + public enum ListViewGroupMask + { + None = 0x00000, + Header = 0x00001, + Footer = 0x00002, + State = 0x00004, + Align = 0x00008, + GroupId = 0x00010, + SubTitle = 0x00100, + Task = 0x00200, + DescriptionTop = 0x00400, + DescriptionBottom = 0x00800, + TitleImage = 0x01000, + ExtendedImage = 0x02000, + Items = 0x04000, + Subset = 0x08000, + SubsetItems = 0x10000 + } + + public enum ListViewGroupState + { + /// + /// Groups are expanded, the group name is displayed, and all items in the group are displayed. + /// + Normal = 0, + /// + /// The group is collapsed. + /// + Collapsed = 1, + /// + /// The group is hidden. + /// + Hidden = 2, + /// + /// Version 6.00 and Windows Vista. The group does not display a header. + /// + NoHeader = 4, + /// + /// Version 6.00 and Windows Vista. The group can be collapsed. + /// + Collapsible = 8, + /// + /// Version 6.00 and Windows Vista. The group has keyboard focus. + /// + Focused = 16, + /// + /// Version 6.00 and Windows Vista. The group is selected. + /// + Selected = 32, + /// + /// Version 6.00 and Windows Vista. The group displays only a portion of its items. + /// + SubSeted = 64, + /// + /// Version 6.00 and Windows Vista. The subset link of the group has keyboard focus. + /// + SubSetLinkFocused = 128, + + + } +} diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index a4e9858..2da4c48 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -88,7 +88,7 @@ this.devicesTabPage = new System.Windows.Forms.TabPage(); this.devicesPanel = new System.Windows.Forms.Panel(); this.cancelAutoCloseButton1 = new System.Windows.Forms.Button(); - this.devicesListView = new System.Windows.Forms.ListView(); + this.devicesListView = new ListViewExtended(); this.nameColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.stateColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.devicesContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); @@ -1093,7 +1093,7 @@ private System.Windows.Forms.ToolStripMenuItem saveMappingsToolStripMenuItem; private System.Windows.Forms.OpenFileDialog openMapFileDialog; private System.Windows.Forms.SaveFileDialog saveMapFileDialog; - private System.Windows.Forms.ListView devicesListView; + private ListViewExtended devicesListView; private System.Windows.Forms.ImageList devicesImageList; private System.Windows.Forms.ColumnHeader nameColumnHeader; private System.Windows.Forms.ColumnHeader stateColumnHeader; diff --git a/MainForm.cs b/MainForm.cs index 60524d3..4d0240e 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -649,7 +649,15 @@ namespace MeshCentralRouter if ((fullRefresh == true) && (mappingsToSetup != null)) { setupMappings(); } } - private void updateDeviceList() + class GroupComparer : IComparer + { + public int Compare(object objA, object objB) + { + return ((ListViewGroup)objA).Header.CompareTo(((ListViewGroup)objB).Header); + } + } + + private void updateDeviceList() { string search = searchTextBox.Text.ToLower(); if (deviceListViewMode) @@ -683,7 +691,42 @@ namespace MeshCentralRouter device.SubItems[0].Text = node.name; } - bool connVisible = ((showOfflineDevicesToolStripMenuItem.Checked) || ((node.conn & 1) != 0)) || (node.mtype == 3); + // *** Flynn Grouping start + bool bGroupExisting = false; + for(int i = 0; i < devicesListView.Groups.Count; i++) + if(devicesListView.Groups[i].Header == node.mesh.name) + { + bGroupExisting = true; + node.listitem.Group = devicesListView.Groups[i]; + break; + } + if(!bGroupExisting) + { + ListViewGroup grp = devicesListView.Groups.Add(devicesListView.Groups.Count.ToString(), node.mesh.name); + node.listitem.Group = grp; + + ListViewGroup[] groups = new ListViewGroup[this.devicesListView.Groups.Count]; + + this.devicesListView.Groups.CopyTo(groups, 0); + + Array.Sort(groups, new GroupComparer()); + + this.devicesListView.BeginUpdate(); + this.devicesListView.Groups.Clear(); + this.devicesListView.Groups.AddRange(groups); + this.devicesListView.EndUpdate(); + + foreach(ListViewGroup lvg in devicesListView.Groups) + { + if(lvg.Header == "Repos") + ListViewExtended.setGrpState(lvg, ListViewGroupState.Collapsible | ListViewGroupState.Normal); + else + ListViewExtended.setGrpState(lvg, ListViewGroupState.Collapsible | ListViewGroupState.Collapsed); + } + } + // *** Flynn Groupng end + + bool connVisible = ((showOfflineDevicesToolStripMenuItem.Checked) || ((node.conn & 1) != 0)) || (node.mtype == 3); int imageIndex = (node.icon - 1) * 2; if (((node.conn & 1) == 0) && (node.mtype != 3)) { imageIndex++; } device.ImageIndex = imageIndex; diff --git a/MeshCentralRouter.csproj b/MeshCentralRouter.csproj index f327c63..6bfe7aa 100644 --- a/MeshCentralRouter.csproj +++ b/MeshCentralRouter.csproj @@ -106,6 +106,9 @@ FileDialogMsgForm.cs + + Component + Form From edc79bebddba3a70407057d50817f3d013bbb68b Mon Sep 17 00:00:00 2001 From: Flynn Date: Tue, 1 Feb 2022 09:02:25 +0100 Subject: [PATCH 13/20] download Folders recursively --- FileViewer.cs | 3733 ++++++++++++++++++++++++++----------------------- 1 file changed, 1986 insertions(+), 1747 deletions(-) diff --git a/FileViewer.cs b/FileViewer.cs index dc1d44f..e0c2dcf 100644 --- a/FileViewer.cs +++ b/FileViewer.cs @@ -1,5 +1,5 @@ /* -Copyright 2009-2022 Intel Corporation +Copyright 2009-2021 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,1295 +27,581 @@ using System.Web.Script.Serialization; namespace MeshCentralRouter { - public partial class FileViewer : Form + public partial class FileViewer : Form + { + private MeshCentralServer server = null; + private NodeClass node = null; + private int state = 0; + private RandomNumberGenerator rand = RandomNumberGenerator.Create(); + private string randomIdHex = null; + public webSocketClient wc = null; + public Dictionary userSessions = null; + public bool sessionIsRecorded = false; + public DirectoryInfo localFolder = null; + public string remoteFolder = null; + public ArrayList remoteFolderList = null; + private static string rndString = getRandomString(12); + private bool skipExistingFiles = false; + private FileDialogMsgForm msgForm = null; + + // Stats + public long bytesIn = 0; + public long bytesInCompressed = 0; + public long bytesOut = 0; + public long bytesOutCompressed = 0; + + // Upload state + public FileTransferStatusForm transferStatusForm = null; + public bool uploadActive = false; + public bool uploadStop = false; + public int uploadFileArrayPtr = -1; + public ArrayList uploadFileArray; + public Hashtable uploadFileDuplicateArray; // Name --> Size + public DirectoryInfo uploadLocalPath; + public string uploadRemotePath; + public FileStream uploadFileStream = null; + public long uploadFilePtr = 0; + public long uploadFileStartPtr = 0; + public long uploadFileSize = 0; + public DateTime uploadFileStartTime = DateTime.MinValue; + public string uploadFileName = null; + + // Download state + public bool downloadActive = false; + public bool downloadStop = false; + public int downloadFileArrayPtr = -1; + public ArrayList downloadFileArray; + public ArrayList downloadFileSizeArray; + public DirectoryInfo downloadLocalPath; + public string downloadRemotePath; + public FileStream downloadFileStream = null; + public long downloadFilePtr = 0; + public long downloadFileSize = 0; + public DateTime downloadFileStartTime = DateTime.MinValue; + + public FileViewer(MeshCentralServer server, NodeClass node) { - private MeshCentralServer server = null; - private NodeClass node = null; - private int state = 0; - private RandomNumberGenerator rand = RandomNumberGenerator.Create(); - private string randomIdHex = null; - public webSocketClient wc = null; - public Dictionary userSessions = null; - public bool sessionIsRecorded = false; - public DirectoryInfo localFolder = null; - public string remoteFolder = null; - public ArrayList remoteFolderList = null; - private static string rndString = getRandomString(12); - private bool skipExistingFiles = false; - private FileDialogMsgForm msgForm = null; + InitializeComponent(); + Translate.TranslateControl(this); + if(node != null) { this.Text += " - " + node.name; } + this.node = node; + this.server = server; + UpdateStatus(); - // Stats - public long bytesIn = 0; - public long bytesInCompressed = 0; - public long bytesOut = 0; - public long bytesOutCompressed = 0; + rightListView.Columns[0].Width = rightListView.Width - rightListView.Columns[1].Width - 22; - // Upload state - public FileTransferStatusForm transferStatusForm = null; - public bool uploadActive = false; - public bool uploadStop = false; - public int uploadFileArrayPtr = -1; - public ArrayList uploadFileArray; - public Hashtable uploadFileDuplicateArray; // Name --> Size - public DirectoryInfo uploadLocalPath; - public string uploadRemotePath; - public FileStream uploadFileStream = null; - public long uploadFilePtr = 0; - public long uploadFileStartPtr = 0; - public long uploadFileSize = 0; - public DateTime uploadFileStartTime = DateTime.MinValue; - public string uploadFileName = null; + // Load the local path from the registry + string lp = Settings.GetRegValue("LocalPath", ""); + if((lp != "") && (Directory.Exists(lp))) { localFolder = new DirectoryInfo(lp); } + } - // Download state - public bool downloadActive = false; - public bool downloadStop = false; - public int downloadFileArrayPtr = -1; - public ArrayList downloadFileArray; - public ArrayList downloadFileSizeArray; - public DirectoryInfo downloadLocalPath; - public string downloadRemotePath; - public FileStream downloadFileStream = null; - public long downloadFilePtr = 0; - public long downloadFileSize = 0; - public DateTime downloadFileStartTime = DateTime.MinValue; + public bool updateLocalFileView() + { + // Save the list of selected items + List selectedItems = new List(); + foreach(ListViewItem l in leftListView.SelectedItems) { selectedItems.Add(l.Text); } - public FileViewer(MeshCentralServer server, NodeClass node) + // Refresh the list + leftListView.Items.Clear(); + if(localFolder == null) + { + localRootButton.Enabled = false; + localNewFolderButton.Enabled = false; + localDeleteButton.Enabled = false; + try { - InitializeComponent(); - Translate.TranslateControl(this); - if (node != null) { this.Text += " - " + node.name; } - this.node = node; - this.server = server; - UpdateStatus(); - - rightListView.Columns[0].Width = rightListView.Width - rightListView.Columns[1].Width - 22; - - // Load the local path from the registry - string lp = Settings.GetRegValue("LocalPath", ""); - if ((lp != "") && (Directory.Exists(lp))) { localFolder = new DirectoryInfo(lp); } + DriveInfo[] drives = DriveInfo.GetDrives(); + foreach(DriveInfo drive in drives) + { + ListViewItem x = new ListViewItem(drive.Name, 0); + x.Tag = drive; + leftListView.Items.Add(x); + } + localUpButton.Enabled = false; + localLabel.Text = Translate.T(Properties.Resources.Local); + mainToolTip.SetToolTip(localLabel, Translate.T(Properties.Resources.Local)); } - - public bool updateLocalFileView() + catch(Exception) { return false; } + } + else + { + localRootButton.Enabled = true; + localNewFolderButton.Enabled = true; + localDeleteButton.Enabled = false; + try { - // Save the list of selected items - List selectedItems = new List(); - foreach (ListViewItem l in leftListView.SelectedItems) { selectedItems.Add(l.Text); } + DirectoryInfo[] directories = localFolder.GetDirectories(); + foreach(DirectoryInfo directory in directories) + { + ListViewItem x = new ListViewItem(directory.Name, 1); + x.Tag = directory; + leftListView.Items.Add(x); + } + FileInfo[] files = localFolder.GetFiles(); + foreach(FileInfo file in files) + { + if(file.Attributes.HasFlag(FileAttributes.Hidden)) continue; + string[] si = new string[2]; + si[0] = file.Name; + si[1] = "" + file.Length; + ListViewItem x = new ListViewItem(si, 2); + x.Tag = file; + leftListView.Items.Add(x); + } + localUpButton.Enabled = true; + localLabel.Text = string.Format(Translate.T(Properties.Resources.LocalPlus), localFolder.FullName); + mainToolTip.SetToolTip(localLabel, string.Format(Translate.T(Properties.Resources.LocalPlus), localFolder.FullName)); + } + catch(Exception) { return false; } + } + updateTransferButtons(); - // Refresh the list - leftListView.Items.Clear(); - if (localFolder == null) + // Reselect items + foreach(ListViewItem l in leftListView.Items) { l.Selected = selectedItems.Contains(l.Text); } + + return true; + } + + public class ListViewItemSortClass : IComparer + { + int IComparer.Compare(Object x, Object y) + { + return ((new CaseInsensitiveComparer()).Compare(((ListViewItem)x).SubItems[0].Text, ((ListViewItem)y).SubItems[0].Text)); + } + } + + private delegate void updateRemoteFileViewHandler(); + public bool bDontupdateRemoteFileView = false; // Flynn + public void updateRemoteFileView() + { + if(bDontupdateRemoteFileView) return; // Flynn + if(this.InvokeRequired) { this.Invoke(new updateRemoteFileViewHandler(updateRemoteFileView)); return; } + + // Save the list of selected items + List selectedItems = new List(); + foreach(ListViewItem l in rightListView.SelectedItems) { selectedItems.Add(l.Text); } + + rightListView.Items.Clear(); + + if((remoteFolder == null) || (remoteFolder == "")) + { + remoteLabel.Text = Translate.T(Properties.Resources.Remote); + mainToolTip.SetToolTip(remoteLabel, Translate.T(Properties.Resources.Remote)); + } + else + { + if(node.agentid < 5) + { + remoteLabel.Text = string.Format(Translate.T(Properties.Resources.RemotePlus), remoteFolder.Replace("/", "\\")); + mainToolTip.SetToolTip(remoteLabel, string.Format(Translate.T(Properties.Resources.RemotePlus), remoteFolder.Replace("/", "\\"))); + } + else + { + remoteLabel.Text = string.Format(Translate.T(Properties.Resources.RemotePlus), remoteFolder); + mainToolTip.SetToolTip(remoteLabel, string.Format(Translate.T(Properties.Resources.RemotePlus), remoteFolder)); + } + } + + remoteRefreshButton.Enabled = true; + remoteRootButton.Enabled = !((remoteFolder == null) || (remoteFolder == "")); + remoteUpButton.Enabled = !((remoteFolder == null) || (remoteFolder == "")); + if(node.agentid < 5) + { + remoteNewFolderButton.Enabled = !((remoteFolder == null) || (remoteFolder == "")); + remoteDeleteButton.Enabled = remoteZipButton.Enabled = (!((remoteFolder == null) || (remoteFolder == ""))) && (rightListView.SelectedItems.Count > 0); + } + else + { + remoteNewFolderButton.Enabled = true; + remoteDeleteButton.Enabled = remoteZipButton.Enabled = (rightListView.SelectedItems.Count > 0); + } + + if(remoteFolderList != null) + { + ArrayList sortlist = new ArrayList(); + + // Display all folders + for(int i = 0; i < remoteFolderList.Count; i++) + { + Dictionary fileItem = (Dictionary)remoteFolderList[i]; + int fileIcon = 0; + string fileName = null; + string fileDate = null; + long fileSize = -1; + if(fileItem.ContainsKey("t")) { fileIcon = (int)fileItem["t"]; } + if(fileItem.ContainsKey("n")) { fileName = (string)fileItem["n"]; } + if(fileItem.ContainsKey("d")) { fileDate = (string)fileItem["d"]; } + if(fileItem.ContainsKey("s")) + { + if(fileItem["s"].GetType() == typeof(System.Int32)) { fileSize = (int)fileItem["s"]; } + if(fileItem["s"].GetType() == typeof(System.Int64)) { fileSize = (long)fileItem["s"]; } + } + if(fileIcon == 1) + { + sortlist.Add(new ListViewItem(fileName, 0)); // Drive + } + else if(fileIcon == 2) + { + sortlist.Add(new ListViewItem(fileName, 1)); // Folder + } + } + sortlist.Sort(new ListViewItemSortClass()); + foreach(ListViewItem l in sortlist) { rightListView.Items.Add(l); } + sortlist.Clear(); + + // Display all files + for(int i = 0; i < remoteFolderList.Count; i++) + { + Dictionary fileItem = (Dictionary)remoteFolderList[i]; + int fileIcon = 0; + string fileName = null; + string fileDate = null; + long fileSize = -1; + if(fileItem.ContainsKey("t")) { fileIcon = (int)fileItem["t"]; } + if(fileItem.ContainsKey("n")) { fileName = (string)fileItem["n"]; } + if(fileItem.ContainsKey("d")) { fileDate = (string)fileItem["d"]; } + if(fileItem.ContainsKey("s")) + { + if(fileItem["s"].GetType() == typeof(System.Int32)) { fileSize = (int)fileItem["s"]; } + if(fileItem["s"].GetType() == typeof(System.Int64)) { fileSize = (long)fileItem["s"]; } + } + if(fileIcon == 3) + { + // File + string[] si = new string[2]; + si[0] = fileName; + si[1] = "" + fileSize; + sortlist.Add(new ListViewItem(si, 2)); // File + } + } + sortlist.Sort(new ListViewItemSortClass()); + foreach(ListViewItem l in sortlist) { rightListView.Items.Add(l); } + } + updateTransferButtons(); + + // Reselect items + foreach(ListViewItem l in rightListView.Items) { l.Selected = selectedItems.Contains(l.Text); } + } + + private void Server_onStateChanged(int state) + { + UpdateStatus(); + } + + private void MainForm_Load(object sender, EventArgs e) + { + updateLocalFileView(); + + // Restore Window Location + string locationStr = Settings.GetRegValue("filelocation", ""); + if(locationStr != null) + { + string[] locationSplit = locationStr.Split(','); + if(locationSplit.Length == 4) + { + try + { + var x = int.Parse(locationSplit[0]); + var y = int.Parse(locationSplit[1]); + var w = int.Parse(locationSplit[2]); + var h = int.Parse(locationSplit[3]); + Point p = new Point(x, y); + if(isPointVisibleOnAScreen(p)) { - localRootButton.Enabled = false; - localNewFolderButton.Enabled = false; - localDeleteButton.Enabled = false; - try - { - DriveInfo[] drives = DriveInfo.GetDrives(); - foreach (DriveInfo drive in drives) - { - ListViewItem x = new ListViewItem(drive.Name, 0); - x.Tag = drive; - leftListView.Items.Add(x); - } - localUpButton.Enabled = false; - localLabel.Text = Translate.T(Properties.Resources.Local); - mainToolTip.SetToolTip(localLabel, Translate.T(Properties.Resources.Local)); - } - catch (Exception) { return false; } + Location = p; + if((w > 50) && (h > 50)) { Size = new Size(w, h); } } - else - { - localRootButton.Enabled = true; - localNewFolderButton.Enabled = true; - localDeleteButton.Enabled = false; - try - { - DirectoryInfo[] directories = localFolder.GetDirectories(); - foreach (DirectoryInfo directory in directories) - { - ListViewItem x = new ListViewItem(directory.Name, 1); - x.Tag = directory; - leftListView.Items.Add(x); - } - FileInfo[] files = localFolder.GetFiles(); - foreach (FileInfo file in files) - { - if (file.Attributes.HasFlag(FileAttributes.Hidden)) continue; - string[] si = new string[2]; - si[0] = file.Name; - si[1] = "" + file.Length; - ListViewItem x = new ListViewItem(si, 2); - x.Tag = file; - leftListView.Items.Add(x); - } - localUpButton.Enabled = true; - localLabel.Text = string.Format(Translate.T(Properties.Resources.LocalPlus), localFolder.FullName); - mainToolTip.SetToolTip(localLabel, string.Format(Translate.T(Properties.Resources.LocalPlus), localFolder.FullName)); - } - catch (Exception) { return false; } - } - updateTransferButtons(); - - // Reselect items - foreach (ListViewItem l in leftListView.Items) { l.Selected = selectedItems.Contains(l.Text); } - - return true; + } + catch(Exception) { } } + } + } - public class ListViewItemSortClass : IComparer - { - int IComparer.Compare(Object x, Object y) - { - return ((new CaseInsensitiveComparer()).Compare(((ListViewItem)x).SubItems[0].Text, ((ListViewItem)y).SubItems[0].Text)); - } - } + private void MenuItemExit_Click(object sender, EventArgs e) + { + Close(); + } - private delegate void updateRemoteFileViewHandler(); - public void updateRemoteFileView() - { - if (this.InvokeRequired) { this.Invoke(new updateRemoteFileViewHandler(updateRemoteFileView)); return; } + public void MenuItemConnect_Click(object sender, EventArgs e) + { + if((wc != null) || (node == null)) return; + byte[] randomid = new byte[10]; + rand.GetBytes(randomid); + randomIdHex = BitConverter.ToString(randomid).Replace("-", string.Empty); - // Save the list of selected items - List selectedItems = new List(); - foreach (ListViewItem l in rightListView.SelectedItems) { selectedItems.Add(l.Text); } - - rightListView.Items.Clear(); - - if ((remoteFolder == null) || (remoteFolder == "")) { - remoteLabel.Text = Translate.T(Properties.Resources.Remote); - mainToolTip.SetToolTip(remoteLabel, Translate.T(Properties.Resources.Remote)); - } else { - if (node.agentid < 5) - { - remoteLabel.Text = string.Format(Translate.T(Properties.Resources.RemotePlus), remoteFolder.Replace("/", "\\")); - mainToolTip.SetToolTip(remoteLabel, string.Format(Translate.T(Properties.Resources.RemotePlus), remoteFolder.Replace("/", "\\"))); - } - else - { - remoteLabel.Text = string.Format(Translate.T(Properties.Resources.RemotePlus), remoteFolder); - mainToolTip.SetToolTip(remoteLabel, string.Format(Translate.T(Properties.Resources.RemotePlus), remoteFolder)); - } - } - - remoteRefreshButton.Enabled = true; - remoteRootButton.Enabled = !((remoteFolder == null) || (remoteFolder == "")); - remoteUpButton.Enabled = !((remoteFolder == null) || (remoteFolder == "")); - if (node.agentid < 5) { - remoteNewFolderButton.Enabled = !((remoteFolder == null) || (remoteFolder == "")); - remoteDeleteButton.Enabled = remoteZipButton.Enabled = (!((remoteFolder == null) || (remoteFolder == ""))) && (rightListView.SelectedItems.Count > 0); - } else { - remoteNewFolderButton.Enabled = true; - remoteDeleteButton.Enabled = remoteZipButton.Enabled = (rightListView.SelectedItems.Count > 0); - } - - if (remoteFolderList != null) - { - ArrayList sortlist = new ArrayList(); - - // Display all folders - for (int i = 0; i < remoteFolderList.Count; i++) - { - Dictionary fileItem = (Dictionary)remoteFolderList[i]; - int fileIcon = 0; - string fileName = null; - string fileDate = null; - long fileSize = -1; - if (fileItem.ContainsKey("t")) { fileIcon = (int)fileItem["t"]; } - if (fileItem.ContainsKey("n")) { fileName = (string)fileItem["n"]; } - if (fileItem.ContainsKey("d")) { fileDate = (string)fileItem["d"]; } - if (fileItem.ContainsKey("s")) { - if (fileItem["s"].GetType() == typeof(System.Int32)) { fileSize = (int)fileItem["s"]; } - if (fileItem["s"].GetType() == typeof(System.Int64)) { fileSize = (long)fileItem["s"]; } - } - if (fileIcon == 1) { - sortlist.Add(new ListViewItem(fileName, 0)); // Drive - } else if (fileIcon == 2) { - sortlist.Add(new ListViewItem(fileName, 1)); // Folder - } - } - sortlist.Sort(new ListViewItemSortClass()); - foreach (ListViewItem l in sortlist) { rightListView.Items.Add(l); } - sortlist.Clear(); - - // Display all files - for (int i = 0; i < remoteFolderList.Count; i++) - { - Dictionary fileItem = (Dictionary)remoteFolderList[i]; - int fileIcon = 0; - string fileName = null; - string fileDate = null; - long fileSize = -1; - if (fileItem.ContainsKey("t")) { fileIcon = (int)fileItem["t"]; } - if (fileItem.ContainsKey("n")) { fileName = (string)fileItem["n"]; } - if (fileItem.ContainsKey("d")) { fileDate = (string)fileItem["d"]; } - if (fileItem.ContainsKey("s")) - { - if (fileItem["s"].GetType() == typeof(System.Int32)) { fileSize = (int)fileItem["s"]; } - if (fileItem["s"].GetType() == typeof(System.Int64)) { fileSize = (long)fileItem["s"]; } - } - if (fileIcon == 3) - { - // File - string[] si = new string[2]; - si[0] = fileName; - si[1] = "" + fileSize; - sortlist.Add(new ListViewItem(si, 2)); // File - } - } - sortlist.Sort(new ListViewItemSortClass()); - foreach (ListViewItem l in sortlist) { rightListView.Items.Add(l); } - } - updateTransferButtons(); - - // Reselect items - foreach (ListViewItem l in rightListView.Items) { l.Selected = selectedItems.Contains(l.Text); } - } - - private void Server_onStateChanged(int state) - { - UpdateStatus(); - } - - private void MainForm_Load(object sender, EventArgs e) - { - updateLocalFileView(); - - // Restore Window Location - string locationStr = Settings.GetRegValue("filelocation", ""); - if (locationStr != null) - { - string[] locationSplit = locationStr.Split(','); - if (locationSplit.Length == 4) - { - try - { - var x = int.Parse(locationSplit[0]); - var y = int.Parse(locationSplit[1]); - var w = int.Parse(locationSplit[2]); - var h = int.Parse(locationSplit[3]); - Point p = new Point(x, y); - if (isPointVisibleOnAScreen(p)) - { - Location = p; - if ((w > 50) && (h > 50)) { Size = new Size(w, h); } - } - } - catch (Exception) { } - } - } - } - - private void MenuItemExit_Click(object sender, EventArgs e) - { - Close(); - } - - public void MenuItemConnect_Click(object sender, EventArgs e) - { - if ((wc != null) || (node == null)) return; - byte[] randomid = new byte[10]; - rand.GetBytes(randomid); - randomIdHex = BitConverter.ToString(randomid).Replace("-", string.Empty); + state = 1; + string ux = server.wsurl.ToString().Replace("/control.ashx", "/"); + int i = ux.IndexOf("?"); + if(i >= 0) { ux = ux.Substring(0, i); } + Uri u = new Uri(ux + "meshrelay.ashx?browser=1&p=5&nodeid=" + node.nodeid + "&id=" + randomIdHex + "&auth=" + server.authCookie); + wc = new webSocketClient(); + wc.debug = server.debug; + wc.onStateChanged += Wc_onStateChanged; + wc.onBinaryData += Wc_onBinaryData; + wc.onStringData += Wc_onStringData; + wc.TLSCertCheck = webSocketClient.TLSCertificateCheck.Fingerprint; + wc.Start(u, server.wshash, null); + } + private void Wc_onStateChanged(webSocketClient sender, webSocketClient.ConnectionStates wsstate) + { + switch(wsstate) + { + case webSocketClient.ConnectionStates.Disconnected: + { + // Disconnect + state = 0; + wc.Dispose(); + wc = null; + break; + } + case webSocketClient.ConnectionStates.Connecting: + { state = 1; - string ux = server.wsurl.ToString().Replace("/control.ashx", "/"); - int i = ux.IndexOf("?"); - if (i >= 0) { ux = ux.Substring(0, i); } - Uri u = new Uri(ux + "meshrelay.ashx?browser=1&p=5&nodeid=" + node.nodeid + "&id=" + randomIdHex + "&auth=" + server.authCookie); - wc = new webSocketClient(); - wc.debug = server.debug; - wc.onStateChanged += Wc_onStateChanged; - wc.onBinaryData += Wc_onBinaryData; - wc.onStringData += Wc_onStringData; - wc.TLSCertCheck = webSocketClient.TLSCertificateCheck.Fingerprint; - wc.Start(u, server.wshash, null); - } + displayMessage(null); + break; + } + case webSocketClient.ConnectionStates.Connected: + { + // Reset stats + bytesIn = 0; + bytesInCompressed = 0; + bytesOut = 0; + bytesOutCompressed = 0; - private void Wc_onStateChanged(webSocketClient sender, webSocketClient.ConnectionStates wsstate) + state = 2; + + string u = "*" + server.wsurl.AbsolutePath.Replace("control.ashx", "meshrelay.ashx") + "?p=5&nodeid=" + node.nodeid + "&id=" + randomIdHex + "&rauth=" + server.rauthCookie; + server.sendCommand("{ \"action\": \"msg\", \"type\": \"tunnel\", \"nodeid\": \"" + node.nodeid + "\", \"value\": \"" + u.ToString() + "\", \"usage\": 5 }"); + displayMessage(null); + break; + } + } + UpdateStatus(); + updateTransferButtons(); + } + + private void requestRemoteFolder(string path) + { + // Send LS command + string cmd = "{\"action\":\"ls\",\"reqid\":1,\"path\":\"" + path.Replace("\\", "/") + "\"}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + } + + private void requestCreateFolder(string path) + { + // Send MKDIR command + string cmd = "{\"action\":\"mkdir\",\"reqid\":2,\"path\":\"" + path.Replace("\\", "/") + "\"}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + } + + public void requestCancel() + { + string cmd = "{\"action\":\"cancel\"}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + updateMsgForm(null, null, 0); + } + + private void requestCreateZipFileFolder(string path, string zip, string[] files) + { + // Send ZIP command + string cmd = "{\"action\":\"zip\",\"reqid\":5,\"path\":\"" + path.Replace("\\", "/") + "\",\"output\":\"" + zip.Replace("\\", "/") + "\",\"files\":["; + bool first = true; + foreach(string file in files) + { + if(first) { first = false; } else { cmd += ","; } + cmd += "\"" + file + "\""; + } + cmd += "]}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + } + + private void requestRename(string path, string oldname, string newname) + { + // Send RENAME command + string cmd = "{\"action\":\"rename\",\"reqid\":3,\"path\":\"" + path.Replace("\\", "/") + "\",\"oldname\":\"" + oldname + "\",\"newname\":\"" + newname + "\"}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + } + + private void requestDelete(string path, string[] files, bool recursive) + { + // Send RM command + string delfiles = ""; + foreach(string file in files) { if(delfiles.Length != 0) { delfiles += ","; } delfiles += "\"" + file + "\""; } + string cmd = "{\"action\":\"rm\",\"reqid\":4,\"path\":\"" + path.Replace("\\", "/") + "\",\"rec\":" + recursive.ToString().ToLower() + ",\"delfiles\":[" + delfiles + "]}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + } + + private void Wc_onStringData(webSocketClient sender, string data, int orglen) + { + bytesIn += data.Length; + bytesInCompressed += orglen; + + if((state == 2) && ((data == "c") || (data == "cr"))) + { + if(data == "cr") { sessionIsRecorded = true; } + state = 3; + UpdateStatus(); + displayMessage(null); + + // Send protocol + string cmd = "5"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + + // Ask for root level + requestRemoteFolder(""); + return; + } + if(state != 3) return; + + // Parse the received JSON + Dictionary jsonAction = new Dictionary(); + jsonAction = new JavaScriptSerializer().Deserialize>(data); + if(jsonAction == null) return; + + if(jsonAction.ContainsKey("action") && (jsonAction["action"].GetType() == typeof(string))) + { + string action = jsonAction["action"].ToString(); + switch(action) { - switch (wsstate) + case "download": { - case webSocketClient.ConnectionStates.Disconnected: - { - // Disconnect - state = 0; - wc.Dispose(); - wc = null; - break; - } - case webSocketClient.ConnectionStates.Connecting: - { - state = 1; - displayMessage(null); - break; - } - case webSocketClient.ConnectionStates.Connected: - { - // Reset stats - bytesIn = 0; - bytesInCompressed = 0; - bytesOut = 0; - bytesOutCompressed = 0; + if(downloadStop) { downloadCancel(); return; } - state = 2; - - string u = "*" + server.wsurl.AbsolutePath.Replace("control.ashx", "meshrelay.ashx") + "?p=5&nodeid=" + node.nodeid + "&id=" + randomIdHex + "&rauth=" + server.rauthCookie; - server.sendCommand("{ \"action\": \"msg\", \"type\": \"tunnel\", \"nodeid\": \"" + node.nodeid + "\", \"value\": \"" + u.ToString() + "\", \"usage\": 5 }"); - displayMessage(null); - break; - } - } - UpdateStatus(); - updateTransferButtons(); - } - - private void requestRemoteFolder(string path) - { - // Send LS command - string cmd = "{\"action\":\"ls\",\"reqid\":1,\"path\":\"" + path.Replace("\\","/") + "\"}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - - private void requestCreateFolder(string path) - { - // Send MKDIR command - string cmd = "{\"action\":\"mkdir\",\"reqid\":2,\"path\":\"" + path.Replace("\\", "/") + "\"}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - - public void requestCancel() - { - string cmd = "{\"action\":\"cancel\"}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - updateMsgForm(null, null, 0); - } - - private void requestCreateZipFileFolder(string path, string zip, string[] files) - { - // Send ZIP command - string cmd = "{\"action\":\"zip\",\"reqid\":5,\"path\":\"" + path.Replace("\\", "/") + "\",\"output\":\"" + zip.Replace("\\", "/") + "\",\"files\":["; - bool first = true; - foreach (string file in files) - { - if (first) { first = false; } else { cmd += ","; } - cmd += "\"" + file + "\""; - } - cmd += "]}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - - private void requestRename(string path, string oldname, string newname) - { - // Send RENAME command - string cmd = "{\"action\":\"rename\",\"reqid\":3,\"path\":\"" + path.Replace("\\", "/") + "\",\"oldname\":\"" + oldname + "\",\"newname\":\"" + newname + "\"}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - - private void requestDelete(string path, string[] files, bool recursive) - { - // Send RM command - string delfiles = ""; - foreach (string file in files) { if (delfiles.Length != 0) { delfiles += ","; } delfiles += "\"" + file + "\""; } - string cmd = "{\"action\":\"rm\",\"reqid\":4,\"path\":\"" + path.Replace("\\", "/") + "\",\"rec\":" + recursive.ToString().ToLower() + ",\"delfiles\":[" + delfiles + "]}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - - private void Wc_onStringData(webSocketClient sender, string data, int orglen) - { - bytesIn += data.Length; - bytesInCompressed += orglen; - - if ((state == 2) && ((data == "c") || (data == "cr"))) - { - if (data == "cr") { sessionIsRecorded = true; } - state = 3; - UpdateStatus(); - displayMessage(null); - - // Send protocol - string cmd = "5"; + string sub = null; + if(jsonAction.ContainsKey("sub")) { sub = (string)jsonAction["sub"]; } + if(sub == "start") + { + // Send DOWNLOAD startack command + string cmd = "{\"action\":\"download\",\"sub\":\"startack\",\"id\":" + (downloadFileArrayPtr + 1000) + "}"; byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); wc.SendBinary(bincmd, 0, bincmd.Length); + } + else if(sub == "cancel") + { + // Unable to download this file + if(transferStatusForm != null) { try { transferStatusForm.addErrorMessage(String.Format(Translate.T(Properties.Resources.ErrorDownloadingFileX), downloadFileArray[downloadFileArrayPtr].ToString())); } catch { } } - // Ask for root level - requestRemoteFolder(""); - return; - } - if (state != 3) return; + // Send DOWNLOAD command + string cmd = "{\"action\":\"download\",\"sub\":\"stop\",\"id\":" + (downloadFileArrayPtr + 1000) + "}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + if(downloadFileStream != null) { downloadFileStream.Close(); downloadFileStream = null; } // Close the file + try { File.Delete(Path.Combine(downloadLocalPath.FullName, Path.GetFileName((String)downloadFileArray[downloadFileArrayPtr]).ToString())); } catch(Exception) { } - // Parse the received JSON - Dictionary jsonAction = new Dictionary(); - jsonAction = new JavaScriptSerializer().Deserialize>(data); - if (jsonAction == null) return; - - if (jsonAction.ContainsKey("action") && (jsonAction["action"].GetType() == typeof(string))) - { - string action = jsonAction["action"].ToString(); - switch (action) + // Go to next file + if(downloadFileArray.Count > downloadFileArrayPtr + 1) { - case "download": - { - if (downloadStop) { downloadCancel(); return; } - - string sub = null; - if (jsonAction.ContainsKey("sub")) { sub = (string)jsonAction["sub"]; } - if (sub == "start") - { - // Send DOWNLOAD startack command - string cmd = "{\"action\":\"download\",\"sub\":\"startack\",\"id\":" + (downloadFileArrayPtr + 1000) + "}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - else if (sub == "cancel") - { - // Unable to download this file - if (transferStatusForm != null) { transferStatusForm.addErrorMessage(String.Format(Translate.T(Properties.Resources.ErrorDownloadingFileX), downloadFileArray[downloadFileArrayPtr].ToString())); } - - // Send DOWNLOAD command - string cmd = "{\"action\":\"download\",\"sub\":\"stop\",\"id\":" + (downloadFileArrayPtr + 1000) + "}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - if (downloadFileStream != null) { downloadFileStream.Close(); downloadFileStream = null; } // Close the file - try { File.Delete(Path.Combine(downloadLocalPath.FullName, downloadFileArray[downloadFileArrayPtr].ToString())); } catch (Exception) { } - - // Go to next file - if (downloadFileArray.Count > downloadFileArrayPtr + 1) - { - // Download the next file - downloadFileArrayPtr++; - downloadNextFile(); - } - else - { - // Done with all files - downloadActive = false; - downloadStop = false; - downloadFileArrayPtr = -1; - downloadFileArray = null; - downloadLocalPath = null; - downloadRemotePath = null; - closeTransferDialog(); - localRefresh(); - } - } - break; - } - } - } - else if (jsonAction.ContainsKey("type") && (jsonAction["type"].GetType() == typeof(string))) { - string action = jsonAction["type"].ToString(); - switch (action) - { - case "metadata": - { - if ((jsonAction.ContainsKey("users") == false) || (jsonAction["users"] == null)) return; - Dictionary usersex = (Dictionary)jsonAction["users"]; - userSessions = new Dictionary(); - foreach (string user in usersex.Keys) { userSessions.Add(user, (int)usersex[user]); } - UpdateStatus(); - break; - } - case "console": - { - string msg = null; - int msgid = -1; - if ((jsonAction.ContainsKey("msg")) && (jsonAction["msg"] != null)) { msg = jsonAction["msg"].ToString(); } - if (jsonAction.ContainsKey("msgid")) { msgid = (int)jsonAction["msgid"]; } - if (msgid == 1) { msg = Translate.T(Properties.Resources.WaitingForUserToGrantAccess); } - if (msgid == 2) { msg = Translate.T(Properties.Resources.Denied); } - if (msgid == 3) { msg = Translate.T(Properties.Resources.FailedToStartRemoteTerminalSession); } - if (msgid == 4) { msg = Translate.T(Properties.Resources.Timeout); } - if (msgid == 5) { msg = Translate.T(Properties.Resources.ReceivedInvalidNetworkData); } - displayMessage(msg); - break; - } - } - } - } - - private void Wc_onBinaryData(webSocketClient sender, byte[] data, int offset, int length, int orglen) - { - bytesIn += length; - bytesInCompressed += orglen; - - if (state != 3) return; - - if (data[offset] == 123) { - // Parse the received JSON - Dictionary jsonAction = new Dictionary(); - jsonAction = new JavaScriptSerializer().Deserialize>(UTF8Encoding.UTF8.GetString(data, offset, length)); - if (jsonAction == null) return; - int reqid = 0; - if (jsonAction.ContainsKey("reqid")) { reqid = (int)jsonAction["reqid"]; } - string action = null; - if (jsonAction.ContainsKey("action")) { action = (string)jsonAction["action"]; } - - if (action == "uploadstart") - { - if (uploadStop) { uploadCancel(); return; } - uploadNextPart(false); - for (var i = 0; i < 8; i++) { uploadNextPart(true); } - } - else if (action == "uploadack") - { - if (uploadStop) { uploadCancel(); return; } - uploadNextPart(false); - } - else if ((action == "uploaddone") || (action == "uploaderror")) - { - // Clean up current upload - uploadFilePtr = 0; - uploadFileStartPtr = 0; - uploadFileSize = 0; - if (uploadFileStream != null) { uploadFileStream.Close(); uploadFileStream = null; } - - // If this is an error, show it in the dialog - if ((action == "uploaderror") && (transferStatusForm != null)) { transferStatusForm.addErrorMessage(String.Format(Translate.T(Properties.Resources.ErrorUploadingFileX), uploadFileName)); } - - // Check if another file needs to be uploaded - if (uploadFileArray.Count > (uploadFileArrayPtr + 1)) - { - // Upload the next file - uploadFileArrayPtr++; - uploadNextFile(); - } - else - { - // Done with all files - uploadActive = false; - uploadStop = false; - uploadFileArrayPtr = -1; - uploadFileArray = null; - uploadFileDuplicateArray = null; - uploadLocalPath = null; - uploadRemotePath = null; - uploadFilePtr = 0; - uploadFileStartPtr = 0; - uploadFileSize = 0; - uploadFileName = null; - closeTransferDialog(); - remoteRefresh(); - } - } - else if (action == "uploadhash") - { - if (uploadStop) { uploadCancel(); return; } - string name = null; - if (jsonAction.ContainsKey("name")) { name = (string)jsonAction["name"]; } - string path = null; - if (jsonAction.ContainsKey("path")) { path = (string)jsonAction["path"]; } - string remoteHashHex = null; - if (jsonAction.ContainsKey("hash")) { remoteHashHex = (string)jsonAction["hash"]; } - long remoteFileSize = 0; - if (jsonAction.ContainsKey("tag")) { - if (jsonAction["tag"].GetType() == typeof(int)) { remoteFileSize = (int)jsonAction["tag"]; } - if (jsonAction["tag"].GetType() == typeof(long)) { remoteFileSize = (long)jsonAction["tag"]; } - } - if ((uploadRemotePath != path) || (uploadFileName != name)) { uploadCancel(); return; } - - // Hash the local file - string localHashHex = null; - try - { - string filePath = Path.Combine(localFolder.FullName, uploadFileName); - using (SHA384 SHA384 = SHA384Managed.Create()) - { - uploadFileStream.Seek(0, SeekOrigin.Begin); - byte[] buf = new byte[65536]; - long ptr = 0; - int len = 1; - while (len != 0) - { - int l = buf.Length; - if (l > (remoteFileSize - ptr)) { l = (int)(remoteFileSize - ptr); } - if (l == 0) { len = 0; } else { len = uploadFileStream.Read(buf, 0, l); } - if (len > 0) { SHA384.TransformBlock(buf, 0, len, buf, 0); } - ptr += len; - } - SHA384.TransformFinalBlock(buf, 0, 0); - localHashHex = BitConverter.ToString(SHA384.Hash).Replace("-", string.Empty); - uploadFileStream.Seek(0, SeekOrigin.Begin); - } - } - catch (Exception) { } - - if ((localHashHex != null) && (localHashHex.Equals(remoteHashHex))) - { - if (remoteFileSize == uploadFileStream.Length) - { - // Files are the same length, skip the file. - // Check if another file needs to be uploaded - if (uploadFileArray.Count > (uploadFileArrayPtr + 1)) - { - // Upload the next file - uploadFileArrayPtr++; - uploadNextFile(); - } - else - { - // Done with all files - uploadActive = false; - uploadStop = false; - uploadFileArrayPtr = -1; - uploadFileArray = null; - uploadFileDuplicateArray = null; - uploadLocalPath = null; - uploadRemotePath = null; - uploadFilePtr = 0; - uploadFileStartPtr = 0; - uploadFileSize = 0; - uploadFileName = null; - closeTransferDialog(); - remoteRefresh(); - } - } - else - { - // Files are not the same length, append the rest - uploadFileStream.Seek(remoteFileSize, SeekOrigin.Begin); - uploadFilePtr = uploadFileStartPtr = remoteFileSize; - - // Send UPLOAD command with append turned on - string cmd = "{\"action\":\"upload\",\"reqid\":" + (uploadFileArrayPtr + 1000) + ",\"path\":\"" + uploadRemotePath + "\",\"name\":\"" + name + "\",\"size\":" + uploadFileSize + ",\"append\":true}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - } - else - { - // Send UPLOAD command - string cmd = "{\"action\":\"upload\",\"reqid\":" + (uploadFileArrayPtr + 1000) + ",\"path\":\"" + uploadRemotePath + "\",\"name\":\"" + name + "\",\"size\":" + uploadFileSize + "}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - } - else if ((action == "dialogmessage")) - { - // Dialog box message - string msg = null; - string file = null; - int progress = 0; - if (jsonAction.ContainsKey("msg") && (jsonAction["msg"] == null)) { msg = ""; } - else if (jsonAction.ContainsKey("msg") && (jsonAction["msg"].GetType() == typeof(string))) { msg = (string)jsonAction["msg"]; } - if (jsonAction.ContainsKey("file") && (jsonAction["file"].GetType() == typeof(string))) { file = (string)jsonAction["file"]; } - if (jsonAction.ContainsKey("progress") && (jsonAction["progress"].GetType() == typeof(System.Int32))) { progress = (int)jsonAction["progress"]; } - updateMsgForm(msg, file, progress); - } - else if (reqid == 1) - { - // Result of a LS command - if (jsonAction.ContainsKey("path")) { remoteFolder = (string)jsonAction["path"]; } - if (jsonAction.ContainsKey("dir")) { remoteFolderList = (ArrayList)jsonAction["dir"]; } - updateRemoteFileView(); - } - } - else - { - if (downloadActive) { - if (downloadStop) { downloadCancel(); return; } - downloadGotBinaryData(data, offset, length); - } - } - } - - public delegate void updateMsgFormHandler(string msg, string file, int progress); - - private void updateMsgForm(string msg, string file, int progress) - { - if (this.InvokeRequired) { this.Invoke(new updateMsgFormHandler(updateMsgForm), msg, file, progress); return; } - if ((msg == null) || (msg == "")) - { - // Close the dialog box - if (msgForm != null) { msgForm.Close(); msgForm = null; remoteRefresh(); } - } - else - { - // Open or update the dialog box - if (msgForm == null) - { - msgForm = new FileDialogMsgForm(this); - msgForm.Show(this); - msgForm.UpdateStatus(msg, file, progress); - if (msgForm.StartPosition == FormStartPosition.CenterParent) - { - var x = Location.X + (Width - msgForm.Width) / 2; - var y = Location.Y + (Height - msgForm.Height) / 2; - msgForm.Location = new Point(Math.Max(x, 0), Math.Max(y, 0)); - } + // Download the next file + downloadFileArrayPtr++; + downloadNextFile(); } else { - msgForm.UpdateStatus(msg, file, progress); + // Done with all files + downloadActive = false; + downloadStop = false; + downloadFileArrayPtr = -1; + downloadFileArray = null; + downloadLocalPath = null; + downloadRemotePath = null; + closeTransferDialog(); + localRefresh(); } + } + break; } } - - private delegate void remoteRefreshHandler(); - - private void remoteRefresh() + } + else if(jsonAction.ContainsKey("type") && (jsonAction["type"].GetType() == typeof(string))) + { + string action = jsonAction["type"].ToString(); + switch(action) { - if (this.InvokeRequired) { this.Invoke(new remoteRefreshHandler(remoteRefresh)); return; } - updateTimer.Enabled = true; - } - - private delegate void localRefreshHandler(); - - private void localRefresh() - { - if (this.InvokeRequired) { this.Invoke(new localRefreshHandler(localRefresh)); return; } - updateLocalFileView(); - } - - private void MenuItemDisconnect_Click(object sender, EventArgs e) - { - if (wc != null) + case "metadata": { - // Disconnect - state = 0; - wc.Dispose(); - wc = null; - UpdateStatus(); + if((jsonAction.ContainsKey("users") == false) || (jsonAction["users"] == null)) return; + Dictionary usersex = (Dictionary)jsonAction["users"]; + userSessions = new Dictionary(); + foreach(string user in usersex.Keys) { userSessions.Add(user, (int)usersex[user]); } + UpdateStatus(); + break; } - else + case "console": { - // Connect - MenuItemConnect_Click(null, null); - } - displayMessage(null); - } - - - public delegate void UpdateStatusHandler(); - - private void UpdateStatus() - { - if (this.IsDisposed) return; - if (this.InvokeRequired) { this.Invoke(new UpdateStatusHandler(UpdateStatus)); return; } - - //if (kvmControl == null) return; - switch (state) - { - case 0: // Disconnected - mainToolStripStatusLabel.Text = Translate.T(Properties.Resources.Disconnected); - connectButton.Text = Translate.T(Properties.Resources.Connect); - remoteRefreshButton.Enabled = false; - remoteUpButton.Enabled = false; - remoteRootButton.Enabled = false; - remoteNewFolderButton.Enabled = false; - remoteDeleteButton.Enabled = false; - remoteZipButton.Enabled = false; - remoteFolder = null; - break; - case 1: // Connecting - mainToolStripStatusLabel.Text = Translate.T(Properties.Resources.Connecting); - connectButton.Text = Translate.T(Properties.Resources.Disconnect); - break; - case 2: // Setup - mainToolStripStatusLabel.Text = Translate.T(Properties.Resources.Setup); - connectButton.Text = Translate.T(Properties.Resources.Disconnect); - break; - case 3: // Connected - string label = Translate.T(Properties.Resources.Connected); - if (sessionIsRecorded) { label += Translate.T(Properties.Resources.RecordedSession); } - if ((userSessions != null) && (userSessions.Count > 1)) { label += string.Format(Translate.T(Properties.Resources.AddXUsers), userSessions.Count); } - label += "."; - mainToolStripStatusLabel.Text = label; - connectButton.Text = Translate.T(Properties.Resources.Disconnect); - break; - } - - rightListView.Enabled = (state == 3); - if (state != 3) { rightListView.Items.Clear(); } - } - - private void Main_FormClosing(object sender, FormClosingEventArgs e) - { - if (wc != null) - { - // Disconnect - state = 0; - wc.Dispose(); - wc = null; - UpdateStatus(); - } - node.fileViewer = null; - - // Clean up any downloads - if (downloadFileStream != null) { downloadFileStream.Close(); downloadFileStream = null; } - downloadFilePtr = 0; - downloadFileSize = 0; - downloadActive = false; - downloadStop = false; - downloadFileArrayPtr = -1; - downloadFileArray = null; - downloadLocalPath = null; - downloadRemotePath = null; - - // Clean up any uploads - uploadActive = false; - uploadStop = false; - uploadFileArrayPtr = -1; - uploadFileArray = null; - uploadFileDuplicateArray = null; - uploadLocalPath = null; - uploadRemotePath = null; - uploadFilePtr = 0; - uploadFileStartPtr = 0; - uploadFileSize = 0; - if (uploadFileStream != null) { uploadFileStream.Close(); uploadFileStream = null; } - - // Save window location - Settings.SetRegValue("filelocation", Location.X + "," + Location.Y + "," + Size.Width + "," + Size.Height); - } - - public delegate void displayMessageHandler(string msg); - public void displayMessage(string msg) - { - if (this.InvokeRequired) { this.Invoke(new displayMessageHandler(displayMessage), msg); return; } - if (msg == null) - { - consoleMessage.Visible = false; - consoleTimer.Enabled = false; - } - else - { - consoleMessage.Text = msg; - consoleMessage.Visible = true; - consoleTimer.Enabled = true; + string msg = null; + int msgid = -1; + if((jsonAction.ContainsKey("msg")) && (jsonAction["msg"] != null)) { msg = jsonAction["msg"].ToString(); } + if(jsonAction.ContainsKey("msgid")) { msgid = (int)jsonAction["msgid"]; } + if(msgid == 1) { msg = Translate.T(Properties.Resources.WaitingForUserToGrantAccess); } + if(msgid == 2) { msg = Translate.T(Properties.Resources.Denied); } + if(msgid == 3) { msg = Translate.T(Properties.Resources.FailedToStartRemoteTerminalSession); } + if(msgid == 4) { msg = Translate.T(Properties.Resources.Timeout); } + if(msgid == 5) { msg = Translate.T(Properties.Resources.ReceivedInvalidNetworkData); } + displayMessage(msg); + break; } } - private void consoleTimer_Tick(object sender, EventArgs e) + } + } + + private void Wc_onBinaryData(webSocketClient sender, byte[] data, int offset, int length, int orglen) + { + bytesIn += length; + bytesInCompressed += orglen; + + if(state != 3) return; + + if(data[offset] == 123) + { + // Parse the received JSON + Dictionary jsonAction = new Dictionary(); + jsonAction = new JavaScriptSerializer().Deserialize>(UTF8Encoding.UTF8.GetString(data, offset, length)); + if(jsonAction == null) return; + int reqid = 0; + if(jsonAction.ContainsKey("reqid")) { reqid = (int)jsonAction["reqid"]; } + string action = null; + if(jsonAction.ContainsKey("action")) { action = (string)jsonAction["action"]; } + + if(action == "uploadstart") { - consoleMessage.Visible = false; - consoleTimer.Enabled = false; + if(uploadStop) { uploadCancel(); return; } + uploadNextPart(false); + for(var i = 0; i < 8; i++) { uploadNextPart(true); } } - - private void connectButton_Click(object sender, EventArgs e) + else if(action == "uploadack") { - if (wc != null) - { - // Disconnect - state = 0; - wc.Dispose(); - wc = null; - UpdateStatus(); - } - else - { - // Connect - MenuItemConnect_Click(null, null); - } - displayMessage(null); + if(uploadStop) { uploadCancel(); return; } + uploadNextPart(false); } - - private void leftListView_MouseDoubleClick(object sender, MouseEventArgs e) + else if((action == "uploaddone") || (action == "uploaderror")) { - ListViewItem item = leftListView.GetItemAt(e.X, e.Y); - if (item != null) - { - if (item.Tag.GetType() == typeof(DriveInfo)) { - DirectoryInfo old = localFolder; - localFolder = ((DriveInfo)item.Tag).RootDirectory; - if (updateLocalFileView() == false) { localFolder = old; updateLocalFileView(); } - Settings.SetRegValue("LocalPath", (localFolder == null) ? "" : localFolder.FullName); - } - else if (item.Tag.GetType() == typeof(DirectoryInfo)) - { - DirectoryInfo old = localFolder; - localFolder = (DirectoryInfo)item.Tag; - if (updateLocalFileView() == false) { localFolder = old; updateLocalFileView(); } - Settings.SetRegValue("LocalPath", (localFolder == null) ? "" : localFolder.FullName); - } - } - } + // Clean up current upload + uploadFilePtr = 0; + uploadFileStartPtr = 0; + uploadFileSize = 0; + if(uploadFileStream != null) { uploadFileStream.Close(); uploadFileStream = null; } - private void localUpButton_Click(object sender, EventArgs e) - { - localFolder = localFolder.Parent; - Settings.SetRegValue("LocalPath", (localFolder == null)?"":localFolder.FullName); - updateLocalFileView(); - } - - private void rightListView_MouseDoubleClick(object sender, MouseEventArgs e) - { - ListViewItem item = rightListView.GetItemAt(e.X, e.Y); - if (item != null) - { - string r = remoteFolder; - if ((item.ImageIndex == 0) || (item.ImageIndex == 1)) { - if ((r == null) || (r == "")) { - r = item.Text; - } else { - if (remoteFolder.EndsWith("/")) { r = remoteFolder + item.Text; } else { r = remoteFolder + "/" + item.Text; } - } - requestRemoteFolder(r); - } - } - } - - private void remoteUpButton_Click(object sender, EventArgs e) - { - string r = remoteFolder; - if (r.EndsWith("/")) { r = r.Substring(0, r.Length - 1); } - int i = r.LastIndexOf("/"); - if (i >= 0) { r = r.Substring(0, i + 1); } else { r = ""; } - requestRemoteFolder(r); - } - - private void leftRefreshButton_Click(object sender, EventArgs e) - { - updateLocalFileView(); - } - - private void rightRefreshButton_Click(object sender, EventArgs e) - { - requestRemoteFolder(remoteFolder); - } - - private void remoteNewFolderButton_Click(object sender, EventArgs e) - { - if (remoteFolder == null) return; - FilenamePromptForm f = new FilenamePromptForm(Translate.T(Properties.Resources.CreateFolder), ""); - if (f.ShowDialog(this) == DialogResult.OK) - { - string r; - if (remoteFolder.EndsWith("/")) { r = remoteFolder + f.filename; } else { r = remoteFolder + "/" + f.filename; } - requestCreateFolder(r); - remoteRefresh(); - } - } - - private void remoteZipButton_Click(object sender, EventArgs e) - { - if (remoteFolder == null) return; - FilenamePromptForm f = new FilenamePromptForm(Translate.T(Properties.Resources.ZipSelectedFiles), ""); - if (f.ShowDialog(this) == DialogResult.OK) - { - string r = f.filename; - if (!r.ToLower().EndsWith(".zip")) { r += ".zip"; } - ArrayList filesArray = new ArrayList(); - foreach (ListViewItem l in rightListView.SelectedItems) { filesArray.Add(l.Text); } - string[] files = (string[])filesArray.ToArray(typeof(string)); - requestCreateZipFileFolder(remoteFolder, r, files); - } - } - - private void localRootButton_Click(object sender, EventArgs e) - { - localFolder = null; - Settings.SetRegValue("LocalPath", ""); - updateLocalFileView(); - } - - private void remoteRootButton_Click(object sender, EventArgs e) - { - requestRemoteFolder(""); - } - - private void rightListView_SelectedIndexChanged(object sender, EventArgs e) - { - if (node.agentid < 5) - { - remoteDeleteButton.Enabled = remoteZipButton.Enabled = (!((remoteFolder == null) || (remoteFolder == ""))) && (rightListView.SelectedItems.Count > 0); - } - else - { - remoteDeleteButton.Enabled = remoteZipButton.Enabled = (rightListView.SelectedItems.Count > 0); - } - updateTransferButtons(); - } - - private void rightListView_Resize(object sender, EventArgs e) - { - if (rightListView.Columns[0].Width != (rightListView.Width - rightListView.Columns[1].Width - 22)) - { - rightListView.Columns[0].Width = rightListView.Width - rightListView.Columns[1].Width - 22; - } - } - - private void rightListView_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e) - { - if (rightListView.Columns[0].Width != (rightListView.Width - rightListView.Columns[1].Width - 22)) - { - rightListView.Columns[0].Width = rightListView.Width - rightListView.Columns[1].Width - 22; - } - } - - private void leftListView_Resize(object sender, EventArgs e) - { - if (leftListView.Columns[0].Width != (leftListView.Width - leftListView.Columns[1].Width - 22)) - { - leftListView.Columns[0].Width = leftListView.Width - leftListView.Columns[1].Width - 22; - } - } - - private void leftListView_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e) - { - if (leftListView.Columns[0].Width != (leftListView.Width - leftListView.Columns[1].Width - 22)) - { - leftListView.Columns[0].Width = leftListView.Width - leftListView.Columns[1].Width - 22; - } - } - - private void updateTimer_Tick(object sender, EventArgs e) - { - updateTimer.Enabled = false; - if (remoteFolder != null) { requestRemoteFolder(remoteFolder); } - } - - private void remoteDeleteButton_Click(object sender, EventArgs e) - { - bool rec = false; - ArrayList filesArray = new ArrayList(); - foreach (ListViewItem l in rightListView.SelectedItems) { filesArray.Add(l.Text); if (l.ImageIndex == 1) { rec = true; } } - string[] files = (string[])filesArray.ToArray(typeof(string)); - string msg = string.Format(Translate.T(Properties.Resources.RemoveXItems), files.Length); - if (files.Length == 1) { msg = Translate.T(Properties.Resources.Remove1Item); } - FileDeletePromptForm f = new FileDeletePromptForm(msg, rec); - if (f.ShowDialog(this) == DialogResult.OK) - { - requestDelete(remoteFolder, files, f.recursive); - remoteRefresh(); - } - } - - private void remoteContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e) - { - if ((rightListView.SelectedItems.Count == 0) || ((node.agentid < 5) && ((remoteFolder == null) || (remoteFolder == "")))) - { - deleteToolStripMenuItem.Visible = toolStripMenuItem1.Visible = renameToolStripMenuItem.Visible = compressToolStripMenuItem.Visible = false; - } - else if (rightListView.SelectedItems.Count == 1) - { - deleteToolStripMenuItem.Visible = toolStripMenuItem1.Visible = renameToolStripMenuItem.Visible = compressToolStripMenuItem.Visible = true; - } - else if (rightListView.SelectedItems.Count > 1) - { - renameToolStripMenuItem.Visible = false; - deleteToolStripMenuItem.Visible = toolStripMenuItem1.Visible = compressToolStripMenuItem.Visible = true; - } - } - - private void renameToolStripMenuItem_Click(object sender, EventArgs e) - { - string oldname = rightListView.SelectedItems[0].Text; - if ((rightListView.SelectedItems.Count != 1) || (remoteFolder == null)) return; - FilenamePromptForm f = new FilenamePromptForm(Translate.T(Properties.Resources.Rename), oldname); - if (f.ShowDialog(this) == DialogResult.OK) - { - if (oldname == f.filename) return; - //string r; - //if (remoteFolder.EndsWith("/")) { r = remoteFolder + f.filename; } else { r = remoteFolder + "/" + f.filename; } - requestRename(remoteFolder, oldname, f.filename); - remoteRefresh(); - } - } - - private delegate void updateTransferButtonsHandler(); - - private void updateTransferButtons() - { - if (this.InvokeRequired) { this.Invoke(new updateTransferButtonsHandler(updateTransferButtons)); return; } - if ((wc == null) || (wc.State != webSocketClient.ConnectionStates.Connected)) - { - uploadButton.Enabled = false; - downloadButton.Enabled = false; - } - else - { - // Set upload button - bool uploadAllowed = true; - if (localFolder == null) { uploadAllowed = false; } - if (leftListView.SelectedItems.Count == 0) { uploadAllowed = false; } - foreach (ListViewItem l in leftListView.SelectedItems) { if (l.ImageIndex != 2) { uploadAllowed = false; } } - if ((node.agentid < 5) && ((remoteFolder == null) || (remoteFolder == ""))) { uploadAllowed = false; } - uploadButton.Enabled = uploadAllowed; - - // Set download button - bool downloadAllowed = true; - if (localFolder == null) { downloadAllowed = false; } - if (rightListView.SelectedItems.Count == 0) { downloadAllowed = false; } - foreach (ListViewItem l in rightListView.SelectedItems) { if (l.ImageIndex != 2) { downloadAllowed = false; } } - if ((node.agentid < 5) && ((remoteFolder == null) || (remoteFolder == ""))) { downloadAllowed = false; } - downloadButton.Enabled = downloadAllowed; - } - } - - private void leftListView_SelectedIndexChanged(object sender, EventArgs e) - { - updateTransferButtons(); - localDeleteButton.Enabled = ((localFolder != null) && (leftListView.SelectedItems.Count > 0)); - } - - private void uploadButton_Click(object sender, EventArgs e) - { - // If a transfer is currently active, ignore this. - if (uploadActive || downloadActive || (transferStatusForm != null)) return; - - // If any files are going to be overwritten - int overWriteCount = 0; - foreach (ListViewItem l in leftListView.SelectedItems) { - if (l.ImageIndex == 2) { - string filename = l.Text; - - foreach (ListViewItem l2 in rightListView.Items) - { - if (l2.ImageIndex == 2) - { - string filename2 = l2.Text; - if (node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } - if (filename.Equals(filename2)) { overWriteCount++; } - } - } - } - } - - skipExistingFiles = true; - if (overWriteCount > 0) - { - FileConfirmOverwriteForm f = new FileConfirmOverwriteForm(); - if (overWriteCount == 1) { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteOneFile), overWriteCount); } else { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteXfiles), overWriteCount); } - if (f.ShowDialog(this) != DialogResult.OK) return; - skipExistingFiles = f.skipExistingFiles; - } - - uploadFileArrayPtr = 0; - uploadFileArray = new ArrayList(); - uploadFileDuplicateArray = new Hashtable(); - - foreach (ListViewItem l in leftListView.SelectedItems) - { - if (l.ImageIndex == 2) - { - bool overwrite = false; - bool overwriteNotLarger = false; - long remoteLength = 0; - string filename = l.Text; - foreach (ListViewItem l2 in rightListView.Items) - { - if (l2.ImageIndex == 2) - { - string filename2 = l2.Text; - if (node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } - if (filename.Equals(filename2)) { - overwrite = true; - if (skipExistingFiles == false) - { - long localLength = new FileInfo(Path.Combine(localFolder.FullName, l.Text)).Length; - remoteLength = long.Parse(l2.SubItems[1].Text); - if (localLength >= remoteLength) { overwriteNotLarger = true; } - } - break; - } - } - } - if ((skipExistingFiles == false) || (overwrite == false)) - { - uploadFileArray.Add(l.Text); - if (overwriteNotLarger) { uploadFileDuplicateArray.Add(Path.Combine(localFolder.FullName, l.Text), remoteLength); } - } - } - } - - if (uploadFileArray.Count == 0) return; - uploadLocalPath = localFolder; - uploadRemotePath = remoteFolder; - uploadActive = true; - uploadStop = false; - - // Show transfer status dialog - transferStatusForm = new FileTransferStatusForm(this); - transferStatusForm.Show(this); + // If this is an error, show it in the dialog + if((action == "uploaderror") && (transferStatusForm != null)) { transferStatusForm.addErrorMessage(String.Format(Translate.T(Properties.Resources.ErrorUploadingFileX), uploadFileName)); } + // Check if another file needs to be uploaded + if(uploadFileArray.Count > (uploadFileArrayPtr + 1)) + { + // Upload the next file + uploadFileArrayPtr++; uploadNextFile(); - } - - private void uploadNextFile() - { - if ((uploadFileArray == null) || (uploadFileArray.Count == 0)) return; - - string localFilePath, localFileName; - if (uploadLocalPath != null) - { - localFilePath = Path.Combine(uploadLocalPath.FullName, (string)uploadFileArray[uploadFileArrayPtr]); - localFileName = (string)uploadFileArray[uploadFileArrayPtr]; - } - else - { - localFilePath = (string)uploadFileArray[uploadFileArrayPtr]; - localFileName = Path.GetFileName(localFilePath); - } - try { uploadFileStream = File.OpenRead(localFilePath); } catch (Exception) - { - // Display the error - if (transferStatusForm != null) { transferStatusForm.addErrorMessage(String.Format(Translate.T(Properties.Resources.UnableToOpenFileX), localFileName)); } - - // Skip to the next file - // Check if another file needs to be uploaded - if (uploadFileArray.Count > (uploadFileArrayPtr + 1)) - { - // Upload the next file - uploadFileArrayPtr++; - uploadNextFile(); - } - else - { - // Done with all files - uploadActive = false; - uploadStop = false; - uploadFileArrayPtr = -1; - uploadFileArray = null; - uploadFileDuplicateArray = null; - uploadLocalPath = null; - uploadRemotePath = null; - uploadFilePtr = 0; - uploadFileStartPtr = 0; - uploadFileSize = 0; - uploadFileName = null; - closeTransferDialog(); - remoteRefresh(); - } - return; - } - uploadFileSize = new FileInfo(localFilePath).Length; - uploadFilePtr = 0; - uploadFileStartPtr = 0; - uploadFileStartTime = DateTime.Now; - uploadFileName = localFileName; - - // Check if the files already exist on the remote side - if (uploadFileDuplicateArray[localFilePath] != null) - { - // Send UPLOADHASH command - string cmd = "{\"action\":\"uploadhash\",\"reqid\":" + (uploadFileArrayPtr + 1000) + ",\"path\":\"" + uploadRemotePath + "\",\"name\":\"" + localFileName + "\",\"tag\":" + uploadFileDuplicateArray[localFilePath] + "}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - else - { - // Send UPLOAD command - string cmd = "{\"action\":\"upload\",\"reqid\":" + (uploadFileArrayPtr + 1000) + ",\"path\":\"" + uploadRemotePath + "\",\"name\":\"" + localFileName + "\",\"size\":" + uploadFileSize + "}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - } - - public void uploadCancel() - { - if (uploadActive == false) return; - - // Send UPLOADCANCEL command - string cmd = "{\"action\":\"uploadcancel\",\"reqid\":" + (uploadFileArrayPtr + 1000) + "}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - - // Clear state + } + else + { + // Done with all files uploadActive = false; uploadStop = false; uploadFileArrayPtr = -1; @@ -1326,530 +612,1483 @@ namespace MeshCentralRouter uploadFilePtr = 0; uploadFileStartPtr = 0; uploadFileSize = 0; - if (uploadFileStream != null) { uploadFileStream.Close(); uploadFileStream = null; } + uploadFileName = null; closeTransferDialog(); remoteRefresh(); + } } - - private void uploadNextPart(bool dataPriming) + else if(action == "uploadhash") { - if (uploadActive == false) return; - byte[] buffer = new byte[16385]; - int len = uploadFileStream.Read(buffer, 1, buffer.Length - 1); - if (dataPriming && (len == 0)) return; - uploadFilePtr += len; + if(uploadStop) { uploadCancel(); return; } + string name = null; + if(jsonAction.ContainsKey("name")) { name = (string)jsonAction["name"]; } + string path = null; + if(jsonAction.ContainsKey("path")) { path = (string)jsonAction["path"]; } + string remoteHashHex = null; + if(jsonAction.ContainsKey("hash")) { remoteHashHex = (string)jsonAction["hash"]; } + long remoteFileSize = 0; + if(jsonAction.ContainsKey("tag")) + { + if(jsonAction["tag"].GetType() == typeof(int)) { remoteFileSize = (int)jsonAction["tag"]; } + if(jsonAction["tag"].GetType() == typeof(long)) { remoteFileSize = (long)jsonAction["tag"]; } + } + if((uploadRemotePath != path) || (uploadFileName != name)) { uploadCancel(); return; } - if (len == 0) { - // Send UPLOADDONE command - string cmd = "{\"action\":\"uploaddone\",\"reqid\":" + (uploadFileArrayPtr + 1000) + "}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } else { - // Send part of the file - // If starts with 0 or {, add a zero char at the start of the send, this will indicate that it's not a JSON command. - if ((buffer[1] == 123) || (buffer[1] == 0)) { wc.SendBinary(buffer, 0, len + 1); } else { wc.SendBinary(buffer, 1, len); } - } - } - - private delegate void closeTransferDialogHandler(); - - private void closeTransferDialog() - { - if (transferStatusForm == null) return; - if (this.InvokeRequired) { this.Invoke(new closeTransferDialogHandler(closeTransferDialog)); return; } - if (transferStatusForm.showingError == false) + // Hash the local file + string localHashHex = null; + try + { + string filePath = Path.Combine(localFolder.FullName, uploadFileName); + using(SHA384 SHA384 = SHA384Managed.Create()) { - // Everything was succesful, close the form - transferStatusForm.Close(); - transferStatusForm = null; - } else { - // Error are displayed, keep the form open - transferStatusForm.transferCompleted(); + uploadFileStream.Seek(0, SeekOrigin.Begin); + byte[] buf = new byte[65536]; + long ptr = 0; + int len = 1; + while(len != 0) + { + int l = buf.Length; + if(l > (remoteFileSize - ptr)) { l = (int)(remoteFileSize - ptr); } + if(l == 0) { len = 0; } else { len = uploadFileStream.Read(buf, 0, l); } + if(len > 0) { SHA384.TransformBlock(buf, 0, len, buf, 0); } + ptr += len; + } + SHA384.TransformFinalBlock(buf, 0, 0); + localHashHex = BitConverter.ToString(SHA384.Hash).Replace("-", string.Empty); + uploadFileStream.Seek(0, SeekOrigin.Begin); } - } + } + catch(Exception) { } - private void downloadButton_Click(object sender, EventArgs e) - { - // If a transfer is currently active, ignore this. - if (uploadActive || downloadActive || (transferStatusForm != null)) return; - - // If any files are going to be overwritten - int overWriteCount = 0; - foreach (ListViewItem l in rightListView.SelectedItems) + if((localHashHex != null) && (localHashHex.Equals(remoteHashHex))) + { + if(remoteFileSize == uploadFileStream.Length) { - if (l.ImageIndex == 2) - { - string filename = l.Text; - - foreach (ListViewItem l2 in leftListView.Items) - { - if (l2.ImageIndex == 2) - { - string filename2 = l2.Text; - if (node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } - if (filename.Equals(filename2)) { overWriteCount++; } - } - } - } - } - - skipExistingFiles = true; - if (overWriteCount > 0) - { - FileConfirmOverwriteForm f = new FileConfirmOverwriteForm(); - if (overWriteCount == 1) { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteOneFile), overWriteCount); } else { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteXfiles), overWriteCount); } - if (f.ShowDialog(this) != DialogResult.OK) return; - skipExistingFiles = f.skipExistingFiles; - } - - // Perform the download - downloadFileArrayPtr = 0; - downloadFileArray = new ArrayList(); - downloadFileSizeArray = new ArrayList(); - foreach (ListViewItem l in rightListView.SelectedItems) - { - if (l.ImageIndex == 2) - { - if (skipExistingFiles == false) - { - downloadFileArray.Add(l.Text); - downloadFileSizeArray.Add(int.Parse(l.SubItems[1].Text)); - } - else - { - bool overwrite = false; - string filename = l.Text; - foreach (ListViewItem l2 in leftListView.Items) - { - if (l2.ImageIndex == 2) - { - string filename2 = l2.Text; - if (node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } - if (filename.Equals(filename2)) { overwrite = true; } - } - } - if (overwrite == false) - { - downloadFileArray.Add(l.Text); - downloadFileSizeArray.Add(int.Parse(l.SubItems[1].Text)); - } - } - } - } - if (downloadFileArray.Count == 0) return; - downloadLocalPath = localFolder; - downloadRemotePath = remoteFolder; - downloadActive = true; - downloadStop = false; - - // Show transfer status dialog - transferStatusForm = new FileTransferStatusForm(this); - transferStatusForm.Show(this); - - downloadNextFile(); - } - - private void downloadNextFile() - { - if ((downloadFileArray == null) || (downloadFileArray.Count == 0)) return; - - string localFilePath; - localFilePath = Path.Combine(downloadLocalPath.FullName, (string)downloadFileArray[downloadFileArrayPtr]); - try { downloadFileStream = File.OpenWrite(localFilePath); } catch (Exception) { - // Download error, show it in the dialog - FileInfo f = new FileInfo(localFilePath); - if (transferStatusForm != null) { transferStatusForm.addErrorMessage(String.Format(Translate.T(Properties.Resources.UnableToWriteFileX), f.Name)); } - - // Unable to download the file, skip it. - if (downloadFileArray.Count > downloadFileArrayPtr + 1) - { - // Download the next file - downloadFileArrayPtr++; - downloadNextFile(); - } - else - { - // Done with all files - downloadActive = false; - downloadStop = false; - downloadFileArrayPtr = -1; - downloadFileArray = null; - downloadLocalPath = null; - downloadRemotePath = null; - closeTransferDialog(); - localRefresh(); - } - return; - } - downloadFileSize = (int)downloadFileSizeArray[downloadFileArrayPtr]; - downloadFilePtr = 0; - downloadFileStartTime = DateTime.Now; - - string r; - if (downloadRemotePath.EndsWith("/")) { r = downloadRemotePath + downloadFileArray[downloadFileArrayPtr]; } else { r = downloadRemotePath + "/" + downloadFileArray[downloadFileArrayPtr]; } - - // Send DOWNLOAD command - string cmd = "{\"action\":\"download\",\"sub\":\"start\",\"id\":" + (downloadFileArrayPtr + 1000) + ",\"path\":\"" + r + "\"}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); - } - - private void downloadGotBinaryData(byte[] data, int offset, int length) - { - if ((length < 4) || (downloadFileStream == null)) return; - if (length > 4) - { - // Save part to disk - downloadFileStream.Write(data, offset + 4, length - 4); - downloadFilePtr += (length - 4); - } - int controlBits = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, offset)); - if ((controlBits & 1) != 0) - { - if (downloadFileStream != null) { downloadFileStream.Close(); downloadFileStream = null; } - downloadFilePtr = 0; - downloadFileSize = 0; - - if (downloadFileArray.Count > downloadFileArrayPtr + 1) - { - // Download the next file - downloadFileArrayPtr++; - downloadNextFile(); - } - else - { - // Done with all files - downloadActive = false; - downloadStop = false; - downloadFileArrayPtr = -1; - downloadFileArray = null; - downloadLocalPath = null; - downloadRemotePath = null; - closeTransferDialog(); - localRefresh(); - } + // Files are the same length, skip the file. + // Check if another file needs to be uploaded + if(uploadFileArray.Count > (uploadFileArrayPtr + 1)) + { + // Upload the next file + uploadFileArrayPtr++; + uploadNextFile(); + } + else + { + // Done with all files + uploadActive = false; + uploadStop = false; + uploadFileArrayPtr = -1; + uploadFileArray = null; + uploadFileDuplicateArray = null; + uploadLocalPath = null; + uploadRemotePath = null; + uploadFilePtr = 0; + uploadFileStartPtr = 0; + uploadFileSize = 0; + uploadFileName = null; + closeTransferDialog(); + remoteRefresh(); + } } else { - // Send DOWNLOAD command - string cmd = "{\"action\":\"download\",\"sub\":\"ack\",\"id\":" + (downloadFileArrayPtr + 1000) + "}"; - byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); - wc.SendBinary(bincmd, 0, bincmd.Length); + // Files are not the same length, append the rest + uploadFileStream.Seek(remoteFileSize, SeekOrigin.Begin); + uploadFilePtr = uploadFileStartPtr = remoteFileSize; + + // Send UPLOAD command with append turned on + string cmd = "{\"action\":\"upload\",\"reqid\":" + (uploadFileArrayPtr + 1000) + ",\"path\":\"" + uploadRemotePath + "\",\"name\":\"" + name + "\",\"size\":" + uploadFileSize + ",\"append\":true}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); } - } - - public void downloadCancel() - { - if (downloadActive == false) return; - - // Send DOWNLOAD command - string cmd = "{\"action\":\"download\",\"sub\":\"stop\",\"id\":" + (downloadFileArrayPtr + 1000) + "}"; + } + else + { + // Send UPLOAD command + string cmd = "{\"action\":\"upload\",\"reqid\":" + (uploadFileArrayPtr + 1000) + ",\"path\":\"" + uploadRemotePath + "\",\"name\":\"" + name + "\",\"size\":" + uploadFileSize + "}"; byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); wc.SendBinary(bincmd, 0, bincmd.Length); - - // Done with all files - if (downloadFileStream != null) { downloadFileStream.Close(); downloadFileStream = null; } - downloadFilePtr = 0; - downloadFileSize = 0; - downloadActive = false; - downloadStop = false; - downloadFileArrayPtr = -1; - downloadFileArray = null; - downloadLocalPath = null; - downloadRemotePath = null; - closeTransferDialog(); - localRefresh(); + } } - - private void localNewFolderButton_Click(object sender, EventArgs e) + else if((action == "dialogmessage")) { - if (localFolder == null) return; - FilenamePromptForm f = new FilenamePromptForm(Translate.T(Properties.Resources.CreateFolder), ""); - if (f.ShowDialog(this) == DialogResult.OK) - { - Directory.CreateDirectory(Path.Combine(localFolder.FullName, f.filename)); - updateLocalFileView(); - } + // Dialog box message + string msg = null; + string file = null; + int progress = 0; + if(jsonAction.ContainsKey("msg") && (jsonAction["msg"] == null)) { msg = ""; } + else if(jsonAction.ContainsKey("msg") && (jsonAction["msg"].GetType() == typeof(string))) { msg = (string)jsonAction["msg"]; } + if(jsonAction.ContainsKey("file") && (jsonAction["file"].GetType() == typeof(string))) { file = (string)jsonAction["file"]; } + if(jsonAction.ContainsKey("progress") && (jsonAction["progress"].GetType() == typeof(System.Int32))) { progress = (int)jsonAction["progress"]; } + updateMsgForm(msg, file, progress); } - - private void localDeleteButton_Click(object sender, EventArgs e) + else if(reqid == 1) { - bool rec = false; - ArrayList filesArray = new ArrayList(); - foreach (ListViewItem l in leftListView.SelectedItems) { filesArray.Add(l.Text); if (l.ImageIndex == 1) { rec = true; } } - string[] files = (string[])filesArray.ToArray(typeof(string)); - string msg = string.Format(Translate.T(Properties.Resources.RemoveXItems), files.Length); - if (files.Length == 1) { msg = Translate.T(Properties.Resources.Remove1Item); } - FileDeletePromptForm f = new FileDeletePromptForm(msg, rec); - if (f.ShowDialog(this) == DialogResult.OK) - { - foreach (string file in filesArray) - { - try { - string fullpath = Path.Combine(localFolder.FullName, file); - FileAttributes attr = File.GetAttributes(fullpath); - if ((attr & FileAttributes.Directory) == FileAttributes.Directory) { Directory.Delete(fullpath, f.recursive); } else { File.Delete(fullpath); } - } catch (Exception) { } - } - updateLocalFileView(); - } + // Result of a LS command + if(jsonAction.ContainsKey("path")) { remoteFolder = (string)jsonAction["path"]; } + if(jsonAction.ContainsKey("dir")) { remoteFolderList = (ArrayList)jsonAction["dir"]; } + updateRemoteFileView(); } - - private void rightListView_DragEnter(object sender, DragEventArgs e) + } + else + { + if(downloadActive) { - if (uploadActive || downloadActive || (transferStatusForm != null)) return; - if ((node.agentid < 5) && ((remoteFolder == null) || (remoteFolder == ""))) { return; } - if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy; - } - - private void rightListView_DragDrop(object sender, DragEventArgs e) - { - if (uploadActive || downloadActive || (transferStatusForm != null)) return; - if ((node.agentid < 5) && ((remoteFolder == null) || (remoteFolder == ""))) { return; } - string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); - - // If any files are going to be overwritten - int overWriteCount = 0; - foreach (string file in files) - { - FileInfo f = new FileInfo(file); - string filename = f.Name; - foreach (ListViewItem l2 in rightListView.Items) - { - if (l2.ImageIndex == 2) - { - string filename2 = l2.Text; - if (node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } - if (filename.Equals(filename2)) { overWriteCount++; } - } - } - } - skipExistingFiles = true; - if (overWriteCount > 0) - { - FileConfirmOverwriteForm f = new FileConfirmOverwriteForm(); - if (overWriteCount == 1) { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteOneFile), overWriteCount); } else { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteXfiles), overWriteCount); } - if (f.ShowDialog(this) != DialogResult.OK) return; - skipExistingFiles = f.skipExistingFiles; - } - - // Perform the upload - uploadFileArrayPtr = 0; - uploadFileArray = new ArrayList(); - uploadFileDuplicateArray = new Hashtable(); - - foreach (string file in files) - { - bool overwrite = false; - bool overwriteNotLarger = false; - long remoteLength = 0; - string filename = Path.GetFileName(file); - foreach (ListViewItem l2 in rightListView.Items) - { - if (l2.ImageIndex == 2) - { - string filename2 = l2.Text; - if (node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } - if (filename.Equals(filename2)) { - overwrite = true; - if (skipExistingFiles == false) - { - long localLength = new FileInfo(file).Length; - remoteLength = long.Parse(l2.SubItems[1].Text); - if (localLength >= remoteLength) { overwriteNotLarger = true; } - } - break; - } - } - } - if ((skipExistingFiles == false) || (overwrite == false)) { - uploadFileArray.Add(file); - if (overwriteNotLarger) { uploadFileDuplicateArray.Add(file, remoteLength); } - } - } - - if (uploadFileArray.Count == 0) return; - uploadLocalPath = null; - uploadRemotePath = remoteFolder; - uploadActive = true; - uploadStop = false; - - // Show transfer status dialog - transferStatusForm = new FileTransferStatusForm(this); - transferStatusForm.Show(this); - - uploadNextFile(); - } - - private void leftListView_MouseMove(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) - { - ArrayList files = new ArrayList(); - foreach (ListViewItem l in leftListView.SelectedItems) { if (l.ImageIndex == 2) { files.Add(Path.Combine(localFolder.FullName, l.Text)); } } - if (files.Count > 0) - { - leftListView.DoDragDrop(new DataObject(DataFormats.FileDrop, (string[])files.ToArray(typeof(string))), DragDropEffects.Copy); - } - } - } - - private void rightListView_MouseMove(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) - { - ArrayList XdownloadFileArray = new ArrayList(); - ArrayList XdownloadFileSizeArray = new ArrayList(); - foreach (ListViewItem l in rightListView.SelectedItems) - { - if (l.ImageIndex == 2) - { - XdownloadFileArray.Add(l.Text); - XdownloadFileSizeArray.Add(int.Parse(l.SubItems[1].Text)); - } - } - if (XdownloadFileArray.Count > 0) - { - DataObject dataObj = new DataObject(); - dataObj.SetData("Type", "MeshCentralRouterRemoteFiles-" + rndString); - dataObj.SetData("RemoteFiles", XdownloadFileArray); - dataObj.SetData("RemoteSizes", XdownloadFileSizeArray); - dataObj.SetData("RemoteFolder", remoteFolder); - rightListView.DoDragDrop(dataObj, DragDropEffects.Copy); - } - } - } - - private void leftListView_DragEnter(object sender, DragEventArgs e) - { - if (uploadActive || downloadActive || (localFolder == null) || (transferStatusForm != null)) return; - if ((e.Data.GetDataPresent("Type") == true) && ((string)e.Data.GetData("Type") == ("MeshCentralRouterRemoteFiles-" + rndString))) { e.Effect = DragDropEffects.Copy; } - } - - private void leftListView_DragDrop(object sender, DragEventArgs e) - { - if (uploadActive || downloadActive || (transferStatusForm != null)) return; - if ((e.Data.GetDataPresent("Type") == false) || ((string)e.Data.GetData("Type") != ("MeshCentralRouterRemoteFiles-" + rndString))) return; - - ArrayList files = (ArrayList)e.Data.GetData("RemoteFiles"); - - // If any files are going to be overwritten - int overWriteCount = 0; - foreach (string file in files) - { - string filename = file; - foreach (ListViewItem l2 in leftListView.Items) - { - if (l2.ImageIndex == 2) - { - string filename2 = l2.Text; - if (node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } - if (filename.Equals(filename2)) { overWriteCount++; } - } - } - } - skipExistingFiles = true; - if (overWriteCount > 0) - { - FileConfirmOverwriteForm f = new FileConfirmOverwriteForm(); - if (overWriteCount == 1) { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteOneFile), overWriteCount); } else { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteXfiles), overWriteCount); } - if (f.ShowDialog(this) != DialogResult.OK) return; - skipExistingFiles = f.skipExistingFiles; - } - - // Perform downloads - downloadFileArrayPtr = 0; - downloadFileArray = (ArrayList)e.Data.GetData("RemoteFiles"); - downloadFileSizeArray = (ArrayList)e.Data.GetData("RemoteSizes"); - - if (skipExistingFiles == true) - { - ArrayList downloadFileArray2 = new ArrayList(); - ArrayList downloadFileSizeArray2 = new ArrayList(); - - for (int i = 0; i < downloadFileArray.Count; i++) - { - bool overwrite = false; - string filename = (string)downloadFileArray[i]; - foreach (ListViewItem l2 in leftListView.Items) - { - if (l2.ImageIndex == 2) - { - string filename2 = l2.Text; - if (node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } - if (filename.Equals(filename2)) { overwrite = true; } - } - } - if (overwrite == false) - { - downloadFileArray2.Add(downloadFileArray[i]); - downloadFileSizeArray2.Add(downloadFileSizeArray[i]); - } - } - - downloadFileArray = downloadFileArray2; - downloadFileSizeArray = downloadFileSizeArray2; - } - - if (downloadFileArray.Count == 0) return; - - downloadLocalPath = localFolder; - downloadRemotePath = (string)e.Data.GetData("RemoteFolder"); - downloadActive = true; - downloadStop = false; - - // Show transfer status dialog - transferStatusForm = new FileTransferStatusForm(this); - transferStatusForm.Show(this); - - downloadNextFile(); - } - private static string getRandomString(int length) - { - using (var rng = new RNGCryptoServiceProvider()) - { - var bytes = new byte[(((length * 6) + 7) / 8)]; - rng.GetBytes(bytes); - return Convert.ToBase64String(bytes); - } - } - - bool isPointVisibleOnAScreen(Point p) - { - foreach (Screen s in Screen.AllScreens) { if ((p.X < s.Bounds.Right) && (p.X > s.Bounds.Left) && (p.Y > s.Bounds.Top) && (p.Y < s.Bounds.Bottom)) return true; } - return false; - } - - private void localContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e) - { - if ((leftListView.SelectedItems.Count == 0) || (localFolder == null)) - { - deleteToolStripMenuItem1.Visible = toolStripMenuItem2.Visible = renameToolStripMenuItem1.Visible = false; - } - else if (leftListView.SelectedItems.Count == 1) - { - deleteToolStripMenuItem1.Visible = toolStripMenuItem2.Visible = renameToolStripMenuItem1.Visible = true; - } - else if (leftListView.SelectedItems.Count > 1) - { - renameToolStripMenuItem1.Visible = false; - deleteToolStripMenuItem1.Visible = toolStripMenuItem2.Visible = true; - } - } - - private void renameToolStripMenuItem1_Click(object sender, EventArgs e) - { - if ((leftListView.SelectedItems.Count != 1) || (localFolder == null)) return; - string oldname = leftListView.SelectedItems[0].Text; - FilenamePromptForm f = new FilenamePromptForm(Translate.T(Properties.Resources.Rename), oldname); - if (f.ShowDialog(this) == DialogResult.OK) - { - if (oldname == f.filename) return; - FileInfo fileinfo = new FileInfo(Path.Combine(localFolder.FullName, oldname)); - if (fileinfo.Exists == false) return; - try { fileinfo.MoveTo(Path.Combine(localFolder.FullName, f.filename)); } catch (Exception) { } - localRefresh(); - } + if(downloadStop) { downloadCancel(); return; } + downloadGotBinaryData(data, offset, length); } + } } + + public delegate void updateMsgFormHandler(string msg, string file, int progress); + + private void updateMsgForm(string msg, string file, int progress) + { + if(this.InvokeRequired) { this.Invoke(new updateMsgFormHandler(updateMsgForm), msg, file, progress); return; } + if((msg == null) || (msg == "")) + { + // Close the dialog box + if(msgForm != null) { msgForm.Close(); msgForm = null; remoteRefresh(); } + } + else + { + // Open or update the dialog box + if(msgForm == null) + { + msgForm = new FileDialogMsgForm(this); + msgForm.Show(this); + msgForm.UpdateStatus(msg, file, progress); + if(msgForm.StartPosition == FormStartPosition.CenterParent) + { + var x = Location.X + (Width - msgForm.Width) / 2; + var y = Location.Y + (Height - msgForm.Height) / 2; + msgForm.Location = new Point(Math.Max(x, 0), Math.Max(y, 0)); + } + } + else + { + msgForm.UpdateStatus(msg, file, progress); + } + } + } + + private delegate void remoteRefreshHandler(); + + private void remoteRefresh() + { + if(this.InvokeRequired) { this.Invoke(new remoteRefreshHandler(remoteRefresh)); return; } + updateTimer.Enabled = true; + } + + private delegate void localRefreshHandler(); + + private void localRefresh() + { + if(this.InvokeRequired) { this.Invoke(new localRefreshHandler(localRefresh)); return; } + updateLocalFileView(); + } + + private void MenuItemDisconnect_Click(object sender, EventArgs e) + { + if(wc != null) + { + // Disconnect + state = 0; + wc.Dispose(); + wc = null; + UpdateStatus(); + } + else + { + // Connect + MenuItemConnect_Click(null, null); + } + displayMessage(null); + } + + + public delegate void UpdateStatusHandler(); + + private void UpdateStatus() + { + if(this.IsDisposed) return; + if(this.InvokeRequired) { this.Invoke(new UpdateStatusHandler(UpdateStatus)); return; } + + //if (kvmControl == null) return; + switch(state) + { + case 0: // Disconnected + mainToolStripStatusLabel.Text = Translate.T(Properties.Resources.Disconnected); + connectButton.Text = Translate.T(Properties.Resources.Connect); + remoteRefreshButton.Enabled = false; + remoteUpButton.Enabled = false; + remoteRootButton.Enabled = false; + remoteNewFolderButton.Enabled = false; + remoteDeleteButton.Enabled = false; + remoteZipButton.Enabled = false; + remoteFolder = null; + break; + case 1: // Connecting + mainToolStripStatusLabel.Text = Translate.T(Properties.Resources.Connecting); + connectButton.Text = Translate.T(Properties.Resources.Disconnect); + break; + case 2: // Setup + mainToolStripStatusLabel.Text = Translate.T(Properties.Resources.Setup); + connectButton.Text = Translate.T(Properties.Resources.Disconnect); + break; + case 3: // Connected + string label = Translate.T(Properties.Resources.Connected); + if(sessionIsRecorded) { label += Translate.T(Properties.Resources.RecordedSession); } + if((userSessions != null) && (userSessions.Count > 1)) { label += string.Format(Translate.T(Properties.Resources.AddXUsers), userSessions.Count); } + label += "."; + mainToolStripStatusLabel.Text = label; + connectButton.Text = Translate.T(Properties.Resources.Disconnect); + break; + } + + rightListView.Enabled = (state == 3); + if(state != 3) { rightListView.Items.Clear(); } + } + + private void Main_FormClosing(object sender, FormClosingEventArgs e) + { + if(wc != null) + { + // Disconnect + state = 0; + wc.Dispose(); + wc = null; + UpdateStatus(); + } + node.fileViewer = null; + + // Clean up any downloads + if(downloadFileStream != null) { downloadFileStream.Close(); downloadFileStream = null; } + downloadFilePtr = 0; + downloadFileSize = 0; + downloadActive = false; + downloadStop = false; + downloadFileArrayPtr = -1; + downloadFileArray = null; + downloadLocalPath = null; + downloadRemotePath = null; + + // Clean up any uploads + uploadActive = false; + uploadStop = false; + uploadFileArrayPtr = -1; + uploadFileArray = null; + uploadFileDuplicateArray = null; + uploadLocalPath = null; + uploadRemotePath = null; + uploadFilePtr = 0; + uploadFileStartPtr = 0; + uploadFileSize = 0; + if(uploadFileStream != null) { uploadFileStream.Close(); uploadFileStream = null; } + + // Save window location + Settings.SetRegValue("filelocation", Location.X + "," + Location.Y + "," + Size.Width + "," + Size.Height); + } + + public delegate void displayMessageHandler(string msg); + public void displayMessage(string msg) + { + if(this.InvokeRequired) { this.Invoke(new displayMessageHandler(displayMessage), msg); return; } + if(msg == null) + { + consoleMessage.Visible = false; + consoleTimer.Enabled = false; + } + else + { + consoleMessage.Text = msg; + consoleMessage.Visible = true; + consoleTimer.Enabled = true; + } + } + private void consoleTimer_Tick(object sender, EventArgs e) + { + consoleMessage.Visible = false; + consoleTimer.Enabled = false; + } + + private void connectButton_Click(object sender, EventArgs e) + { + if(wc != null) + { + // Disconnect + state = 0; + wc.Dispose(); + wc = null; + UpdateStatus(); + } + else + { + // Connect + MenuItemConnect_Click(null, null); + } + displayMessage(null); + } + + private void leftListView_MouseDoubleClick(object sender, MouseEventArgs e) + { + ListViewItem item = leftListView.GetItemAt(e.X, e.Y); + if(item != null) + { + if(item.Tag.GetType() == typeof(DriveInfo)) + { + DirectoryInfo old = localFolder; + localFolder = ((DriveInfo)item.Tag).RootDirectory; + if(updateLocalFileView() == false) { localFolder = old; updateLocalFileView(); } + Settings.SetRegValue("LocalPath", (localFolder == null) ? "" : localFolder.FullName); + } + else if(item.Tag.GetType() == typeof(DirectoryInfo)) + { + DirectoryInfo old = localFolder; + localFolder = (DirectoryInfo)item.Tag; + if(updateLocalFileView() == false) { localFolder = old; updateLocalFileView(); } + Settings.SetRegValue("LocalPath", (localFolder == null) ? "" : localFolder.FullName); + } + } + } + + private void localUpButton_Click(object sender, EventArgs e) + { + localFolder = localFolder.Parent; + Settings.SetRegValue("LocalPath", (localFolder == null) ? "" : localFolder.FullName); + updateLocalFileView(); + } + + private void rightListView_MouseDoubleClick(object sender, MouseEventArgs e) + { + ListViewItem item = rightListView.GetItemAt(e.X, e.Y); + if(item != null) + { + string r = remoteFolder; + if((item.ImageIndex == 0) || (item.ImageIndex == 1)) + { + if((r == null) || (r == "")) + { + r = item.Text; + } + else + { + if(remoteFolder.EndsWith("/")) { r = remoteFolder + item.Text; } else { r = remoteFolder + "/" + item.Text; } + } + requestRemoteFolder(r); + } + } + } + + private void remoteUpButton_Click(object sender, EventArgs e) + { + string r = remoteFolder; + if(r.EndsWith("/")) { r = r.Substring(0, r.Length - 1); } + int i = r.LastIndexOf("/"); + if(i >= 0) { r = r.Substring(0, i + 1); } else { r = ""; } + requestRemoteFolder(r); + } + + private void leftRefreshButton_Click(object sender, EventArgs e) + { + updateLocalFileView(); + } + + private void rightRefreshButton_Click(object sender, EventArgs e) + { + requestRemoteFolder(remoteFolder); + } + + private void remoteNewFolderButton_Click(object sender, EventArgs e) + { + if(remoteFolder == null) return; + FilenamePromptForm f = new FilenamePromptForm(Translate.T(Properties.Resources.CreateFolder), ""); + if(f.ShowDialog(this) == DialogResult.OK) + { + string r; + if(remoteFolder.EndsWith("/")) { r = remoteFolder + f.filename; } else { r = remoteFolder + "/" + f.filename; } + requestCreateFolder(r); + remoteRefresh(); + } + } + + private void remoteZipButton_Click(object sender, EventArgs e) + { + if(remoteFolder == null) return; + FilenamePromptForm f = new FilenamePromptForm(Translate.T(Properties.Resources.ZipSelectedFiles), ""); + if(f.ShowDialog(this) == DialogResult.OK) + { + string r = f.filename; + if(!r.ToLower().EndsWith(".zip")) { r += ".zip"; } + ArrayList filesArray = new ArrayList(); + foreach(ListViewItem l in rightListView.SelectedItems) { filesArray.Add(l.Text); } + string[] files = (string[])filesArray.ToArray(typeof(string)); + requestCreateZipFileFolder(remoteFolder, r, files); + } + } + + private void localRootButton_Click(object sender, EventArgs e) + { + localFolder = null; + Settings.SetRegValue("LocalPath", ""); + updateLocalFileView(); + } + + private void remoteRootButton_Click(object sender, EventArgs e) + { + requestRemoteFolder(""); + } + + private void rightListView_SelectedIndexChanged(object sender, EventArgs e) + { + if(node.agentid < 5) + { + remoteDeleteButton.Enabled = remoteZipButton.Enabled = (!((remoteFolder == null) || (remoteFolder == ""))) && (rightListView.SelectedItems.Count > 0); + } + else + { + remoteDeleteButton.Enabled = remoteZipButton.Enabled = (rightListView.SelectedItems.Count > 0); + } + updateTransferButtons(); + } + + private void rightListView_Resize(object sender, EventArgs e) + { + if(rightListView.Columns[0].Width != (rightListView.Width - rightListView.Columns[1].Width - 22)) + { + rightListView.Columns[0].Width = rightListView.Width - rightListView.Columns[1].Width - 22; + } + } + + bool bRightCWChangedBusy = false; + private void rightListView_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e) + { + if(bRightCWChangedBusy) return; + bRightCWChangedBusy=true; + try + { + if(rightListView.Columns[0].Width != (rightListView.Width - rightListView.Columns[1].Width - 22)) + { + rightListView.Columns[0].Width = rightListView.Width - rightListView.Columns[1].Width - 22; + } + } + catch { } + bRightCWChangedBusy = false; + } + + private void leftListView_Resize(object sender, EventArgs e) + { + if(leftListView.Columns[0].Width != (leftListView.Width - leftListView.Columns[1].Width - 22)) + { + leftListView.Columns[0].Width = leftListView.Width - leftListView.Columns[1].Width - 22; + } + } + + bool bLeftCWChangedBusy = false; + private void leftListView_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e) + { + if(bLeftCWChangedBusy) return; + bLeftCWChangedBusy=true; + try + { + if(leftListView.Columns[0].Width != (leftListView.Width - leftListView.Columns[1].Width - 22)) + { + leftListView.Columns[0].Width = leftListView.Width - leftListView.Columns[1].Width - 22; + } + } + catch { } + bLeftCWChangedBusy = false; + } + + private void updateTimer_Tick(object sender, EventArgs e) + { + updateTimer.Enabled = false; + if(remoteFolder != null) { requestRemoteFolder(remoteFolder); } + } + + private void remoteDeleteButton_Click(object sender, EventArgs e) + { + bool rec = false; + ArrayList filesArray = new ArrayList(); + foreach(ListViewItem l in rightListView.SelectedItems) { filesArray.Add(l.Text); if(l.ImageIndex == 1) { rec = true; } } + string[] files = (string[])filesArray.ToArray(typeof(string)); + string msg = string.Format(Translate.T(Properties.Resources.RemoveXItems), files.Length); + if(files.Length == 1) { msg = Translate.T(Properties.Resources.Remove1Item); } + FileDeletePromptForm f = new FileDeletePromptForm(msg, rec); + if(f.ShowDialog(this) == DialogResult.OK) + { + requestDelete(remoteFolder, files, f.recursive); + remoteRefresh(); + } + } + + private void remoteContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e) + { + if((rightListView.SelectedItems.Count == 0) || ((node.agentid < 5) && ((remoteFolder == null) || (remoteFolder == "")))) + { + deleteToolStripMenuItem.Visible = toolStripMenuItem1.Visible = renameToolStripMenuItem.Visible = compressToolStripMenuItem.Visible = false; + } + else if(rightListView.SelectedItems.Count == 1) + { + deleteToolStripMenuItem.Visible = toolStripMenuItem1.Visible = renameToolStripMenuItem.Visible = compressToolStripMenuItem.Visible = true; + } + else if(rightListView.SelectedItems.Count > 1) + { + renameToolStripMenuItem.Visible = false; + deleteToolStripMenuItem.Visible = toolStripMenuItem1.Visible = compressToolStripMenuItem.Visible = true; + } + } + + private void renameToolStripMenuItem_Click(object sender, EventArgs e) + { + string oldname = rightListView.SelectedItems[0].Text; + if((rightListView.SelectedItems.Count != 1) || (remoteFolder == null)) return; + FilenamePromptForm f = new FilenamePromptForm(Translate.T(Properties.Resources.Rename), oldname); + if(f.ShowDialog(this) == DialogResult.OK) + { + if(oldname == f.filename) return; + //string r; + //if (remoteFolder.EndsWith("/")) { r = remoteFolder + f.filename; } else { r = remoteFolder + "/" + f.filename; } + requestRename(remoteFolder, oldname, f.filename); + remoteRefresh(); + } + } + + private delegate void updateTransferButtonsHandler(); + + private void updateTransferButtons() + { + if(this.InvokeRequired) { this.Invoke(new updateTransferButtonsHandler(updateTransferButtons)); return; } + if((wc == null) || (wc.State != webSocketClient.ConnectionStates.Connected)) + { + uploadButton.Enabled = false; + downloadButton.Enabled = false; + } + else + { + // Set upload button + bool uploadAllowed = true; + if(localFolder == null) { uploadAllowed = false; } + if(leftListView.SelectedItems.Count == 0) { uploadAllowed = false; } + foreach(ListViewItem l in leftListView.SelectedItems) { if(l.ImageIndex != 2) { uploadAllowed = false; } } + if((node.agentid < 5) && ((remoteFolder == null) || (remoteFolder == ""))) { uploadAllowed = false; } + uploadButton.Enabled = uploadAllowed; + + // Set download button + bool downloadAllowed = true; + if(localFolder == null) { downloadAllowed = false; } + if(rightListView.SelectedItems.Count == 0) { downloadAllowed = false; } + foreach(ListViewItem l in rightListView.SelectedItems) { if(l.ImageIndex != 1 && l.ImageIndex != 2) { downloadAllowed = false; } } // Flynn + if((node.agentid < 5) && ((remoteFolder == null) || (remoteFolder == ""))) { downloadAllowed = false; } + downloadButton.Enabled = downloadAllowed; + } + } + + private void leftListView_SelectedIndexChanged(object sender, EventArgs e) + { + updateTransferButtons(); + localDeleteButton.Enabled = ((localFolder != null) && (leftListView.SelectedItems.Count > 0)); + } + + private void uploadButton_Click(object sender, EventArgs e) + { + // If a transfer is currently active, ignore this. + if(uploadActive || downloadActive || (transferStatusForm != null)) return; + + // If any files are going to be overwritten + int overWriteCount = 0; + foreach(ListViewItem l in leftListView.SelectedItems) + { + if(l.ImageIndex == 2) + { + string filename = l.Text; + + foreach(ListViewItem l2 in rightListView.Items) + { + if(l2.ImageIndex == 2) + { + string filename2 = l2.Text; + if(node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } + if(filename.Equals(filename2)) { overWriteCount++; } + } + } + } + } + + skipExistingFiles = true; + if(overWriteCount > 0) + { + FileConfirmOverwriteForm f = new FileConfirmOverwriteForm(); + if(overWriteCount == 1) { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteOneFile), overWriteCount); } else { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteXfiles), overWriteCount); } + if(f.ShowDialog(this) != DialogResult.OK) return; + skipExistingFiles = f.skipExistingFiles; + } + + uploadFileArrayPtr = 0; + uploadFileArray = new ArrayList(); + uploadFileDuplicateArray = new Hashtable(); + + foreach(ListViewItem l in leftListView.SelectedItems) + { + if(l.ImageIndex == 2) + { + bool overwrite = false; + bool overwriteNotLarger = false; + long remoteLength = 0; + string filename = l.Text; + foreach(ListViewItem l2 in rightListView.Items) + { + if(l2.ImageIndex == 2) + { + string filename2 = l2.Text; + if(node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } + if(filename.Equals(filename2)) + { + overwrite = true; + if(skipExistingFiles == false) + { + long localLength = new FileInfo(Path.Combine(localFolder.FullName, l.Text)).Length; + remoteLength = long.Parse(l2.SubItems[1].Text); + if(localLength >= remoteLength) { overwriteNotLarger = true; } + } + break; + } + } + } + if((skipExistingFiles == false) || (overwrite == false)) + { + uploadFileArray.Add(l.Text); + if(overwriteNotLarger) { uploadFileDuplicateArray.Add(Path.Combine(localFolder.FullName, l.Text), remoteLength); } + } + } + } + + if(uploadFileArray.Count == 0) return; + uploadLocalPath = localFolder; + uploadRemotePath = remoteFolder; + uploadActive = true; + uploadStop = false; + + // Show transfer status dialog + transferStatusForm = new FileTransferStatusForm(this); + transferStatusForm.Show(this); + + uploadNextFile(); + } + + private void uploadNextFile() + { + if((uploadFileArray == null) || (uploadFileArray.Count == 0)) return; + + string localFilePath, localFileName; + if(uploadLocalPath != null) + { + localFilePath = Path.Combine(uploadLocalPath.FullName, (string)uploadFileArray[uploadFileArrayPtr]); + localFileName = (string)uploadFileArray[uploadFileArrayPtr]; + } + else + { + localFilePath = (string)uploadFileArray[uploadFileArrayPtr]; + localFileName = Path.GetFileName(localFilePath); + } + try { uploadFileStream = File.OpenRead(localFilePath); } + catch(Exception) + { + // Display the error + if(transferStatusForm != null) { transferStatusForm.addErrorMessage(String.Format(Translate.T(Properties.Resources.UnableToOpenFileX), localFileName)); } + + // Skip to the next file + // Check if another file needs to be uploaded + if(uploadFileArray.Count > (uploadFileArrayPtr + 1)) + { + // Upload the next file + uploadFileArrayPtr++; + uploadNextFile(); + } + else + { + // Done with all files + uploadActive = false; + uploadStop = false; + uploadFileArrayPtr = -1; + uploadFileArray = null; + uploadFileDuplicateArray = null; + uploadLocalPath = null; + uploadRemotePath = null; + uploadFilePtr = 0; + uploadFileStartPtr = 0; + uploadFileSize = 0; + uploadFileName = null; + closeTransferDialog(); + remoteRefresh(); + } + return; + } + uploadFileSize = new FileInfo(localFilePath).Length; + uploadFilePtr = 0; + uploadFileStartPtr = 0; + uploadFileStartTime = DateTime.Now; + uploadFileName = localFileName; + + // Check if the files already exist on the remote side + if(uploadFileDuplicateArray[localFilePath] != null) + { + // Send UPLOADHASH command + string cmd = "{\"action\":\"uploadhash\",\"reqid\":" + (uploadFileArrayPtr + 1000) + ",\"path\":\"" + uploadRemotePath + "\",\"name\":\"" + localFileName + "\",\"tag\":" + uploadFileDuplicateArray[localFilePath] + "}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + } + else + { + // Send UPLOAD command + string cmd = "{\"action\":\"upload\",\"reqid\":" + (uploadFileArrayPtr + 1000) + ",\"path\":\"" + uploadRemotePath + "\",\"name\":\"" + localFileName + "\",\"size\":" + uploadFileSize + "}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + } + } + + public void uploadCancel() + { + if(uploadActive == false) return; + + // Send UPLOADCANCEL command + string cmd = "{\"action\":\"uploadcancel\",\"reqid\":" + (uploadFileArrayPtr + 1000) + "}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + + // Clear state + uploadActive = false; + uploadStop = false; + uploadFileArrayPtr = -1; + uploadFileArray = null; + uploadFileDuplicateArray = null; + uploadLocalPath = null; + uploadRemotePath = null; + uploadFilePtr = 0; + uploadFileStartPtr = 0; + uploadFileSize = 0; + if(uploadFileStream != null) { uploadFileStream.Close(); uploadFileStream = null; } + closeTransferDialog(); + remoteRefresh(); + } + + private void uploadNextPart(bool dataPriming) + { + if(uploadActive == false) return; + byte[] buffer = new byte[16385]; + int len = uploadFileStream.Read(buffer, 1, buffer.Length - 1); + if(dataPriming && (len == 0)) return; + uploadFilePtr += len; + + if(len == 0) + { + // Send UPLOADDONE command + string cmd = "{\"action\":\"uploaddone\",\"reqid\":" + (uploadFileArrayPtr + 1000) + "}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + } + else + { + // Send part of the file + // If starts with 0 or {, add a zero char at the start of the send, this will indicate that it's not a JSON command. + if((buffer[1] == 123) || (buffer[1] == 0)) { wc.SendBinary(buffer, 0, len + 1); } else { wc.SendBinary(buffer, 1, len); } + } + } + + private delegate void closeTransferDialogHandler(); + + private void closeTransferDialog() + { + if(transferStatusForm == null) return; + if(this.InvokeRequired) { this.Invoke(new closeTransferDialogHandler(closeTransferDialog)); return; } + if(transferStatusForm.showingError == false) + { + // Everything was succesful, close the form + transferStatusForm.Close(); + transferStatusForm = null; + } + else + { + // Error are displayed, keep the form open + transferStatusForm.transferCompleted(); + } + + remoteFolder = strDownloadRel; // Zurücksetzen + remoteRefresh(); + } + + private void downloadButton_Click(object sender, EventArgs e) + { + downloadButton_ClickFlynn(sender, e); + return; + // If a transfer is currently active, ignore this. + if(uploadActive || downloadActive || (transferStatusForm != null)) return; + + // If any files are going to be overwritten + int overWriteCount = 0; + foreach(ListViewItem l in rightListView.SelectedItems) + { + if(l.ImageIndex == 2) + { + string filename = l.Text; + + foreach(ListViewItem l2 in leftListView.Items) + { + if(l2.ImageIndex == 2) + { + string filename2 = l2.Text; + if(node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } + if(filename.Equals(filename2)) { overWriteCount++; } + } + } + } + } + + skipExistingFiles = true; + if(overWriteCount > 0) + { + FileConfirmOverwriteForm f = new FileConfirmOverwriteForm(); + if(overWriteCount == 1) { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteOneFile), overWriteCount); } else { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteXfiles), overWriteCount); } + if(f.ShowDialog(this) != DialogResult.OK) return; + skipExistingFiles = f.skipExistingFiles; + } + + // Perform the download + downloadFileArrayPtr = 0; + downloadFileArray = new ArrayList(); + downloadFileSizeArray = new ArrayList(); + foreach(ListViewItem l in rightListView.SelectedItems) + { + if(l.ImageIndex == 2) + { + if(skipExistingFiles == false) + { + downloadFileArray.Add(l.Text); + downloadFileSizeArray.Add(int.Parse(l.SubItems[1].Text)); + } + else + { + bool overwrite = false; + string filename = l.Text; + foreach(ListViewItem l2 in leftListView.Items) + { + if(l2.ImageIndex == 2) + { + string filename2 = l2.Text; + if(node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } + if(filename.Equals(filename2)) { overwrite = true; } + } + } + if(overwrite == false) + { + downloadFileArray.Add(l.Text); + downloadFileSizeArray.Add(int.Parse(l.SubItems[1].Text)); + } + } + } + } + if(downloadFileArray.Count == 0) return; + downloadLocalPath = localFolder; + downloadRemotePath = remoteFolder; + downloadActive = true; + downloadStop = false; + + // Show transfer status dialog + transferStatusForm = new FileTransferStatusForm(this); + transferStatusForm.Show(this); + + downloadNextFile(); + } + + private void downloadButton_ClickFlynn(object sender, EventArgs e) + { + // If a transfer is currently active, ignore this. + if(uploadActive || downloadActive || (transferStatusForm != null)) return; + + strDownloadRel = remoteFolder; + + // Perform the download + downloadFileArrayPtr = 0; + downloadFileArray = new ArrayList(); + downloadFileSizeArray = new ArrayList(); + + bDontupdateRemoteFileView = true; + + foreach(ListViewItem l in rightListView.SelectedItems) + { + if(l.ImageIndex == 1) // Folder + { + RekursivelyCollectDownloadFiles(strDownloadRel+"/"+l.Text); + } + else if(l.ImageIndex == 2) // File + { + if(skipExistingFiles == false) + { + downloadFileArray.Add(strDownloadRel+"/"+l.Text); + downloadFileSizeArray.Add(int.Parse(l.SubItems[1].Text)); + } + else + { + bool overwrite = false; + string filename = l.Text; + foreach(ListViewItem l2 in leftListView.Items) + { + if(l2.ImageIndex == 2) + { + string filename2 = l2.Text; + if(node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } + if(filename.Equals(filename2)) { overwrite = true; } + } + } + if(overwrite == false) + { + downloadFileArray.Add(strDownloadRel+"/"+l.Text); + downloadFileSizeArray.Add(int.Parse(l.SubItems[1].Text)); + } + } + } + } + bDontupdateRemoteFileView = false; + + #region SKIP existing? + downloadLocalPath = localFolder; + // If any files are going to be overwritten + int overWriteCount = 0; + for(int i = 0; i < downloadFileArray.Count; i++) + { + string localFilePath; + String strDownloadFileString = (string)downloadFileArray[downloadFileArrayPtr]; + if(strDownloadRel.Length > 0) + { + strDownloadFileString = strDownloadFileString.Substring(strDownloadRel.Length); + if(strDownloadFileString.StartsWith("/")) strDownloadFileString = strDownloadFileString.Substring(1); + } + localFilePath = Path.Combine(downloadLocalPath.FullName, strDownloadFileString.Replace("/", "\\")); + + if(File.Exists(localFilePath) && new System.IO.FileInfo(localFilePath).Length.Equals(downloadFileSizeArray[i])) { overWriteCount++; } + } + + skipExistingFiles = true; + if(overWriteCount > 0) + { + FileConfirmOverwriteForm f = new FileConfirmOverwriteForm(); + if(overWriteCount == 1) { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteOneFile), overWriteCount); } else { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteXfiles), overWriteCount); } + if(f.ShowDialog(this) != DialogResult.OK) return; + skipExistingFiles = f.skipExistingFiles; + } + + if(skipExistingFiles) + { + for(int i = 0; i < downloadFileArray.Count; i++) + { + string localFilePath; + String strDownloadFileString = (string)downloadFileArray[downloadFileArrayPtr]; + if(strDownloadRel.Length > 0) + { + strDownloadFileString = strDownloadFileString.Substring(strDownloadRel.Length); + if(strDownloadFileString.StartsWith("/")) strDownloadFileString = strDownloadFileString.Substring(1); + } + localFilePath = Path.Combine(downloadLocalPath.FullName, strDownloadFileString.Replace("/", "\\")); + + if(File.Exists(localFilePath) && new System.IO.FileInfo(localFilePath).Length.Equals(downloadFileSizeArray[i])) + { + downloadFileArray.RemoveAt(i); + downloadFileSizeArray.RemoveAt(i); + i--; + } + } + } + + + + + + #endregion + + + + if(downloadFileArray.Count == 0) return; + downloadLocalPath = localFolder; + downloadRemotePath = remoteFolder; + downloadActive = true; + downloadStop = false; + + // Show transfer status dialog + transferStatusForm = new FileTransferStatusForm(this); + transferStatusForm.Show(this); + + downloadNextFile(); + } + + private void RekursivelyCollectDownloadFiles(String strFolder) + { + requestRemoteFolder(strFolder); + DateTime to = DateTime.Now.AddSeconds(5); + while(DateTime.Now < to && remoteFolder != strFolder) + Application.DoEvents(); + List FileList = new List(); + for(int i = 0; i < remoteFolderList.Count; i++) + { + Dictionary fileItem = (Dictionary)remoteFolderList[i]; + Fle file = new Fle(); + file.Size = -1; + file.Path = strFolder.Replace("//", "/"); + if(fileItem.ContainsKey("t")) { file.Icon = (int)fileItem["t"]; } + if(fileItem.ContainsKey("n")) { file.Name = (string)fileItem["n"]; } + if(fileItem.ContainsKey("d")) { file.Date = (string)fileItem["d"]; } + if(fileItem.ContainsKey("s")) + { + if(fileItem["s"].GetType() == typeof(System.Int32)) { file.Size = (int)fileItem["s"]; } + if(fileItem["s"].GetType() == typeof(System.Int64)) { file.Size = (long)fileItem["s"]; } + } + FileList.Add(file); // Folder + } + + for(int i = 0; i < FileList.Count; i++) + { + Fle file = FileList[i]; + if(file.Icon == 2) // Folder + { + RekursivelyCollectDownloadFiles(file.Path+"/"+file.Name); + } + else if(file.Icon == 3) // File + { + if(true) // Abfrage Skip + { + downloadFileArray.Add(file.Path+"/"+file.Name); + downloadFileSizeArray.Add(file.Size); + } + } + } + } + + String strDownloadRel = ""; + private void downloadNextFile() + { + if((downloadFileArray == null) || (downloadFileArray.Count == 0)) return; + + string localFilePath; + String strDownloadFileString = (string)downloadFileArray[downloadFileArrayPtr]; + if(strDownloadRel.Length > 0) + { + strDownloadFileString = strDownloadFileString.Substring(strDownloadRel.Length); + if(strDownloadFileString.StartsWith("/")) strDownloadFileString = strDownloadFileString.Substring(1); + } + localFilePath = Path.Combine(downloadLocalPath.FullName, strDownloadFileString.Replace("/", "\\")); + if(!Directory.Exists(Path.GetDirectoryName(localFilePath))) Directory.CreateDirectory(Path.GetDirectoryName(localFilePath)); + try { downloadFileStream = File.OpenWrite(localFilePath); } + catch(Exception) + { + // Download error, show it in the dialog + FileInfo f = new FileInfo(localFilePath); + if(transferStatusForm != null) { transferStatusForm.addErrorMessage(String.Format(Translate.T(Properties.Resources.UnableToWriteFileX), f.Name)); } + + // Unable to download the file, skip it. + if(downloadFileArray.Count > downloadFileArrayPtr + 1) + { + // Download the next file + downloadFileArrayPtr++; + downloadNextFile(); + } + else + { + // Done with all files + downloadActive = false; + downloadStop = false; + downloadFileArrayPtr = -1; + downloadFileArray = null; + downloadLocalPath = null; + downloadRemotePath = null; + closeTransferDialog(); + localRefresh(); + } + return; + } + + if(downloadFileSizeArray[downloadFileArrayPtr].GetType() == typeof(System.Int32)) { downloadFileSize = (int)downloadFileSizeArray[downloadFileArrayPtr]; } + if(downloadFileSizeArray[downloadFileArrayPtr].GetType() == typeof(System.Int64)) { downloadFileSize = (long)downloadFileSizeArray[downloadFileArrayPtr]; } + + downloadFilePtr = 0; + downloadFileStartTime = DateTime.Now; + + string r; + if(downloadRemotePath.EndsWith("/")) { r = downloadRemotePath + Path.GetFileName((String)downloadFileArray[downloadFileArrayPtr]); } else { r = downloadRemotePath + "/" + Path.GetFileName((String)downloadFileArray[downloadFileArrayPtr]); } + r=(String)downloadFileArray[downloadFileArrayPtr]; + // Send DOWNLOAD command + string cmd = "{\"action\":\"download\",\"sub\":\"start\",\"id\":" + (downloadFileArrayPtr + 1000) + ",\"path\":\"" + r + "\"}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + } + + private void downloadGotBinaryData(byte[] data, int offset, int length) + { + if((length < 4) || (downloadFileStream == null)) return; + if(length > 4) + { + // Save part to disk + downloadFileStream.Write(data, offset + 4, length - 4); + downloadFilePtr += (length - 4); + } + int controlBits = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, offset)); + if((controlBits & 1) != 0) + { + if(downloadFileStream != null) { downloadFileStream.Close(); downloadFileStream = null; } + downloadFilePtr = 0; + downloadFileSize = 0; + + if(downloadFileArray.Count > downloadFileArrayPtr + 1) + { + // Download the next file + downloadFileArrayPtr++; + downloadNextFile(); + } + else + { + // Done with all files + downloadActive = false; + downloadStop = false; + downloadFileArrayPtr = -1; + downloadFileArray = null; + downloadLocalPath = null; + downloadRemotePath = null; + closeTransferDialog(); + localRefresh(); + } + } + else + { + // Send DOWNLOAD command + string cmd = "{\"action\":\"download\",\"sub\":\"ack\",\"id\":" + (downloadFileArrayPtr + 1000) + "}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + } + } + + public void downloadCancel() + { + if(downloadActive == false) return; + + // Send DOWNLOAD command + string cmd = "{\"action\":\"download\",\"sub\":\"stop\",\"id\":" + (downloadFileArrayPtr + 1000) + "}"; + byte[] bincmd = UTF8Encoding.UTF8.GetBytes(cmd); + wc.SendBinary(bincmd, 0, bincmd.Length); + + // Done with all files + if(downloadFileStream != null) { downloadFileStream.Close(); downloadFileStream = null; } + downloadFilePtr = 0; + downloadFileSize = 0; + downloadActive = false; + downloadStop = false; + downloadFileArrayPtr = -1; + downloadFileArray = null; + downloadLocalPath = null; + downloadRemotePath = null; + closeTransferDialog(); + localRefresh(); + } + + private void localNewFolderButton_Click(object sender, EventArgs e) + { + if(localFolder == null) return; + FilenamePromptForm f = new FilenamePromptForm(Translate.T(Properties.Resources.CreateFolder), ""); + if(f.ShowDialog(this) == DialogResult.OK) + { + Directory.CreateDirectory(Path.Combine(localFolder.FullName, f.filename)); + updateLocalFileView(); + } + } + + private void localDeleteButton_Click(object sender, EventArgs e) + { + bool rec = false; + ArrayList filesArray = new ArrayList(); + foreach(ListViewItem l in leftListView.SelectedItems) { filesArray.Add(l.Text); if(l.ImageIndex == 1) { rec = true; } } + string[] files = (string[])filesArray.ToArray(typeof(string)); + string msg = string.Format(Translate.T(Properties.Resources.RemoveXItems), files.Length); + if(files.Length == 1) { msg = Translate.T(Properties.Resources.Remove1Item); } + FileDeletePromptForm f = new FileDeletePromptForm(msg, rec); + if(f.ShowDialog(this) == DialogResult.OK) + { + foreach(string file in filesArray) + { + try + { + string fullpath = Path.Combine(localFolder.FullName, file); + FileAttributes attr = File.GetAttributes(fullpath); + if((attr & FileAttributes.Directory) == FileAttributes.Directory) { Directory.Delete(fullpath, f.recursive); } else { File.Delete(fullpath); } + } + catch(Exception) { } + } + updateLocalFileView(); + } + } + + private void rightListView_DragEnter(object sender, DragEventArgs e) + { + if(uploadActive || downloadActive || (transferStatusForm != null)) return; + if((node.agentid < 5) && ((remoteFolder == null) || (remoteFolder == ""))) { return; } + if(e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy; + } + + private void rightListView_DragDrop(object sender, DragEventArgs e) + { + if(uploadActive || downloadActive || (transferStatusForm != null)) return; + if((node.agentid < 5) && ((remoteFolder == null) || (remoteFolder == ""))) { return; } + string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); + + // If any files are going to be overwritten + int overWriteCount = 0; + foreach(string file in files) + { + FileInfo f = new FileInfo(file); + string filename = f.Name; + foreach(ListViewItem l2 in rightListView.Items) + { + if(l2.ImageIndex == 2) + { + string filename2 = l2.Text; + if(node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } + if(filename.Equals(filename2)) { overWriteCount++; } + } + } + } + skipExistingFiles = true; + if(overWriteCount > 0) + { + FileConfirmOverwriteForm f = new FileConfirmOverwriteForm(); + if(overWriteCount == 1) { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteOneFile), overWriteCount); } else { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteXfiles), overWriteCount); } + if(f.ShowDialog(this) != DialogResult.OK) return; + skipExistingFiles = f.skipExistingFiles; + } + + // Perform the upload + uploadFileArrayPtr = 0; + uploadFileArray = new ArrayList(); + uploadFileDuplicateArray = new Hashtable(); + + foreach(string file in files) + { + bool overwrite = false; + bool overwriteNotLarger = false; + long remoteLength = 0; + string filename = Path.GetFileName(file); + foreach(ListViewItem l2 in rightListView.Items) + { + if(l2.ImageIndex == 2) + { + string filename2 = l2.Text; + if(node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } + if(filename.Equals(filename2)) + { + overwrite = true; + if(skipExistingFiles == false) + { + long localLength = new FileInfo(file).Length; + remoteLength = long.Parse(l2.SubItems[1].Text); + if(localLength >= remoteLength) { overwriteNotLarger = true; } + } + break; + } + } + } + if((skipExistingFiles == false) || (overwrite == false)) + { + uploadFileArray.Add(file); + if(overwriteNotLarger) { uploadFileDuplicateArray.Add(file, remoteLength); } + } + } + + if(uploadFileArray.Count == 0) return; + uploadLocalPath = null; + uploadRemotePath = remoteFolder; + uploadActive = true; + uploadStop = false; + + // Show transfer status dialog + transferStatusForm = new FileTransferStatusForm(this); + transferStatusForm.Show(this); + + uploadNextFile(); + } + + private void leftListView_MouseMove(object sender, MouseEventArgs e) + { + if(e.Button == MouseButtons.Left) + { + ArrayList files = new ArrayList(); + foreach(ListViewItem l in leftListView.SelectedItems) { if(l.ImageIndex == 2) { files.Add(Path.Combine(localFolder.FullName, l.Text)); } } + if(files.Count > 0) + { + leftListView.DoDragDrop(new DataObject(DataFormats.FileDrop, (string[])files.ToArray(typeof(string))), DragDropEffects.Copy); + } + } + } + + private void rightListView_MouseMove(object sender, MouseEventArgs e) + { + if(e.Button == MouseButtons.Left) + { + ArrayList XdownloadFileArray = new ArrayList(); + ArrayList XdownloadFileSizeArray = new ArrayList(); + foreach(ListViewItem l in rightListView.SelectedItems) + { + if(l.ImageIndex == 2) + { + XdownloadFileArray.Add(l.Text); + XdownloadFileSizeArray.Add(int.Parse(l.SubItems[1].Text)); + } + } + if(XdownloadFileArray.Count > 0) + { + DataObject dataObj = new DataObject(); + dataObj.SetData("Type", "MeshCentralRouterRemoteFiles-" + rndString); + dataObj.SetData("RemoteFiles", XdownloadFileArray); + dataObj.SetData("RemoteSizes", XdownloadFileSizeArray); + dataObj.SetData("RemoteFolder", remoteFolder); + rightListView.DoDragDrop(dataObj, DragDropEffects.Copy); + } + } + } + + private void leftListView_DragEnter(object sender, DragEventArgs e) + { + if(uploadActive || downloadActive || (localFolder == null) || (transferStatusForm != null)) return; + if((e.Data.GetDataPresent("Type") == true) && ((string)e.Data.GetData("Type") == ("MeshCentralRouterRemoteFiles-" + rndString))) { e.Effect = DragDropEffects.Copy; } + } + + private void leftListView_DragDrop(object sender, DragEventArgs e) + { + if(uploadActive || downloadActive || (transferStatusForm != null)) return; + if((e.Data.GetDataPresent("Type") == false) || ((string)e.Data.GetData("Type") != ("MeshCentralRouterRemoteFiles-" + rndString))) return; + + ArrayList files = (ArrayList)e.Data.GetData("RemoteFiles"); + + // If any files are going to be overwritten + int overWriteCount = 0; + foreach(string file in files) + { + string filename = file; + foreach(ListViewItem l2 in leftListView.Items) + { + if(l2.ImageIndex == 2) + { + string filename2 = l2.Text; + if(node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } + if(filename.Equals(filename2)) { overWriteCount++; } + } + } + } + skipExistingFiles = true; + if(overWriteCount > 0) + { + FileConfirmOverwriteForm f = new FileConfirmOverwriteForm(); + if(overWriteCount == 1) { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteOneFile), overWriteCount); } else { f.mainTextLabel = String.Format(Translate.T(Properties.Resources.OverwriteXfiles), overWriteCount); } + if(f.ShowDialog(this) != DialogResult.OK) return; + skipExistingFiles = f.skipExistingFiles; + } + + // Perform downloads + downloadFileArrayPtr = 0; + downloadFileArray = (ArrayList)e.Data.GetData("RemoteFiles"); + downloadFileSizeArray = (ArrayList)e.Data.GetData("RemoteSizes"); + + if(skipExistingFiles == true) + { + ArrayList downloadFileArray2 = new ArrayList(); + ArrayList downloadFileSizeArray2 = new ArrayList(); + + for(int i = 0; i < downloadFileArray.Count; i++) + { + bool overwrite = false; + string filename = (string)downloadFileArray[i]; + foreach(ListViewItem l2 in leftListView.Items) + { + if(l2.ImageIndex == 2) + { + string filename2 = l2.Text; + if(node.agentid < 5) { filename = filename.ToLower(); filename2 = filename2.ToLower(); } + if(filename.Equals(filename2)) { overwrite = true; } + } + } + if(overwrite == false) + { + downloadFileArray2.Add(downloadFileArray[i]); + downloadFileSizeArray2.Add(downloadFileSizeArray[i]); + } + } + + downloadFileArray = downloadFileArray2; + downloadFileSizeArray = downloadFileSizeArray2; + } + + if(downloadFileArray.Count == 0) return; + + downloadLocalPath = localFolder; + downloadRemotePath = (string)e.Data.GetData("RemoteFolder"); + downloadActive = true; + downloadStop = false; + + // Show transfer status dialog + transferStatusForm = new FileTransferStatusForm(this); + transferStatusForm.Show(this); + + downloadNextFile(); + } + private static string getRandomString(int length) + { + using(var rng = new RNGCryptoServiceProvider()) + { + var bytes = new byte[(((length * 6) + 7) / 8)]; + rng.GetBytes(bytes); + return Convert.ToBase64String(bytes); + } + } + + bool isPointVisibleOnAScreen(Point p) + { + foreach(Screen s in Screen.AllScreens) { if((p.X < s.Bounds.Right) && (p.X > s.Bounds.Left) && (p.Y > s.Bounds.Top) && (p.Y < s.Bounds.Bottom)) return true; } + return false; + } + + private void localContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e) + { + if((leftListView.SelectedItems.Count == 0) || (localFolder == null)) + { + deleteToolStripMenuItem1.Visible = toolStripMenuItem2.Visible = renameToolStripMenuItem1.Visible = false; + } + else if(leftListView.SelectedItems.Count == 1) + { + deleteToolStripMenuItem1.Visible = toolStripMenuItem2.Visible = renameToolStripMenuItem1.Visible = true; + } + else if(leftListView.SelectedItems.Count > 1) + { + renameToolStripMenuItem1.Visible = false; + deleteToolStripMenuItem1.Visible = toolStripMenuItem2.Visible = true; + } + } + + private void renameToolStripMenuItem1_Click(object sender, EventArgs e) + { + if((leftListView.SelectedItems.Count != 1) || (localFolder == null)) return; + string oldname = leftListView.SelectedItems[0].Text; + FilenamePromptForm f = new FilenamePromptForm(Translate.T(Properties.Resources.Rename), oldname); + if(f.ShowDialog(this) == DialogResult.OK) + { + if(oldname == f.filename) return; + FileInfo fileinfo = new FileInfo(Path.Combine(localFolder.FullName, oldname)); + if(fileinfo.Exists == false) return; + try { fileinfo.MoveTo(Path.Combine(localFolder.FullName, f.filename)); } catch(Exception) { } + localRefresh(); + } + } + } + + public class Fle + { + public String Path = ""; + public String Name = ""; + public String Date = ""; + public long Size = 0; + public int Icon = 0; + } } From d1091c5e0c14eb50b170742cd4a5baf74a940a1d Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 24 Feb 2022 14:21:14 -0800 Subject: [PATCH 14/20] Desktop Setting Improvements. --- KVMControl.cs | 1 + KVMSettingsForm.Designer.cs | 19 +++++++++---- KVMSettingsForm.cs | 30 ++++++++++++-------- KVMSettingsForm.resx | 56 ++++++++++++++++++++++++++++--------- KVMViewer.cs | 45 +++++++++++++++++++++++++++++ MainForm.cs | 6 ++++ 6 files changed, 128 insertions(+), 29 deletions(-) diff --git a/KVMControl.cs b/KVMControl.cs index e20d9d9..6efff18 100644 --- a/KVMControl.cs +++ b/KVMControl.cs @@ -40,6 +40,7 @@ namespace MeshCentralRouter private bool swamMouseButtons = false; private bool remoteKeyboardMap = false; private bool autoSendClipboard = false; + public bool AutoReconnect = false; private double scalefactor = 1; public List displays = new List(); public ushort currentDisp = 0; diff --git a/KVMSettingsForm.Designer.cs b/KVMSettingsForm.Designer.cs index 1189f0d..7c06c66 100644 --- a/KVMSettingsForm.Designer.cs +++ b/KVMSettingsForm.Designer.cs @@ -32,6 +32,7 @@ this.cancelButton = new System.Windows.Forms.Button(); this.okButton = new System.Windows.Forms.Button(); this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.autoSendClipboardCheckBox = new System.Windows.Forms.CheckBox(); this.remoteKeyboardMapCheckBox = new System.Windows.Forms.CheckBox(); this.swapMouseButtonsCheckBox = new System.Windows.Forms.CheckBox(); this.frameRateComboBox = new System.Windows.Forms.ComboBox(); @@ -42,7 +43,7 @@ this.label3 = new System.Windows.Forms.Label(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.label4 = new System.Windows.Forms.Label(); - this.autoSendClipboardCheckBox = new System.Windows.Forms.CheckBox(); + this.autoReconnectCheckBox = new System.Windows.Forms.CheckBox(); this.groupBox1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.SuspendLayout(); @@ -65,6 +66,7 @@ // groupBox1 // resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.autoReconnectCheckBox); this.groupBox1.Controls.Add(this.autoSendClipboardCheckBox); this.groupBox1.Controls.Add(this.remoteKeyboardMapCheckBox); this.groupBox1.Controls.Add(this.swapMouseButtonsCheckBox); @@ -77,6 +79,12 @@ this.groupBox1.Name = "groupBox1"; this.groupBox1.TabStop = false; // + // autoSendClipboardCheckBox + // + resources.ApplyResources(this.autoSendClipboardCheckBox, "autoSendClipboardCheckBox"); + this.autoSendClipboardCheckBox.Name = "autoSendClipboardCheckBox"; + this.autoSendClipboardCheckBox.UseVisualStyleBackColor = true; + // // remoteKeyboardMapCheckBox // resources.ApplyResources(this.remoteKeyboardMapCheckBox, "remoteKeyboardMapCheckBox"); @@ -137,11 +145,11 @@ resources.ApplyResources(this.label4, "label4"); this.label4.Name = "label4"; // - // autoSendClipboardCheckBox + // autoReconnectCheckBox // - resources.ApplyResources(this.autoSendClipboardCheckBox, "autoSendClipboardCheckBox"); - this.autoSendClipboardCheckBox.Name = "autoSendClipboardCheckBox"; - this.autoSendClipboardCheckBox.UseVisualStyleBackColor = true; + resources.ApplyResources(this.autoReconnectCheckBox, "autoReconnectCheckBox"); + this.autoReconnectCheckBox.Name = "autoReconnectCheckBox"; + this.autoReconnectCheckBox.UseVisualStyleBackColor = true; // // KVMSettingsForm // @@ -182,5 +190,6 @@ private System.Windows.Forms.CheckBox swapMouseButtonsCheckBox; private System.Windows.Forms.CheckBox remoteKeyboardMapCheckBox; private System.Windows.Forms.CheckBox autoSendClipboardCheckBox; + private System.Windows.Forms.CheckBox autoReconnectCheckBox; } } \ No newline at end of file diff --git a/KVMSettingsForm.cs b/KVMSettingsForm.cs index 033dccd..15871a4 100644 --- a/KVMSettingsForm.cs +++ b/KVMSettingsForm.cs @@ -25,6 +25,7 @@ namespace MeshCentralRouter { InitializeComponent(); Translate.TranslateControl(this); + qualityComboBox.Items.Add(new DropListItem(100, "100%")); qualityComboBox.Items.Add(new DropListItem(90, "90%")); qualityComboBox.Items.Add(new DropListItem(80, "80%")); qualityComboBox.Items.Add(new DropListItem(70, "70%")); @@ -76,17 +77,18 @@ namespace MeshCentralRouter get { return ((DropListItem)qualityComboBox.SelectedItem).value; } set { - if (value >= 90) { qualityComboBox.SelectedIndex = 0; return; } - if (value >= 80) { qualityComboBox.SelectedIndex = 1; return; } - if (value >= 70) { qualityComboBox.SelectedIndex = 2; return; } - if (value >= 60) { qualityComboBox.SelectedIndex = 3; return; } - if (value >= 50) { qualityComboBox.SelectedIndex = 4; return; } - if (value >= 40) { qualityComboBox.SelectedIndex = 5; return; } - if (value >= 30) { qualityComboBox.SelectedIndex = 6; return; } - if (value >= 20) { qualityComboBox.SelectedIndex = 7; return; } - if (value >= 10) { qualityComboBox.SelectedIndex = 8; return; } - if (value >= 5) { qualityComboBox.SelectedIndex = 9; return; } - qualityComboBox.SelectedIndex = 10; + if (value >= 100) { qualityComboBox.SelectedIndex = 0; return; } + if (value >= 90) { qualityComboBox.SelectedIndex = 1; return; } + if (value >= 80) { qualityComboBox.SelectedIndex = 2; return; } + if (value >= 70) { qualityComboBox.SelectedIndex = 3; return; } + if (value >= 60) { qualityComboBox.SelectedIndex = 4; return; } + if (value >= 50) { qualityComboBox.SelectedIndex = 5; return; } + if (value >= 40) { qualityComboBox.SelectedIndex = 6; return; } + if (value >= 30) { qualityComboBox.SelectedIndex = 7; return; } + if (value >= 20) { qualityComboBox.SelectedIndex = 8; return; } + if (value >= 10) { qualityComboBox.SelectedIndex = 9; return; } + if (value >= 5) { qualityComboBox.SelectedIndex = 10; return; } + qualityComboBox.SelectedIndex = 11; } } @@ -135,6 +137,12 @@ namespace MeshCentralRouter set { autoSendClipboardCheckBox.Checked = value; } } + public bool AutoReconnect + { + get { return autoReconnectCheckBox.Checked; } + set { autoReconnectCheckBox.Checked = value; } + } + private void okButton_Click(object sender, EventArgs e) { DialogResult = System.Windows.Forms.DialogResult.OK; diff --git a/KVMSettingsForm.resx b/KVMSettingsForm.resx index 11be2d7..f19b9d2 100644 --- a/KVMSettingsForm.resx +++ b/KVMSettingsForm.resx @@ -123,7 +123,7 @@ - 312, 254 + 312, 276 75, 23 @@ -151,7 +151,7 @@ Bottom, Right - 231, 254 + 231, 276 75, 23 @@ -177,6 +177,36 @@ Top, Bottom, Left, Right + + True + + + NoControl + + + 128, 174 + + + 144, 17 + + + 10 + + + Automatically Reconnect + + + autoReconnectCheckBox + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + True @@ -205,7 +235,7 @@ groupBox1 - 0 + 1 True @@ -235,7 +265,7 @@ groupBox1 - 1 + 2 True @@ -262,7 +292,7 @@ groupBox1 - 2 + 3 Top, Left, Right @@ -286,7 +316,7 @@ groupBox1 - 3 + 4 True @@ -313,7 +343,7 @@ groupBox1 - 4 + 5 Top, Left, Right @@ -337,7 +367,7 @@ groupBox1 - 5 + 6 True @@ -364,7 +394,7 @@ groupBox1 - 6 + 7 Top, Left, Right @@ -391,7 +421,7 @@ groupBox1 - 7 + 8 True @@ -418,13 +448,13 @@ groupBox1 - 8 + 9 12, 68 - 375, 180 + 375, 202 2 @@ -502,7 +532,7 @@ 6, 13 - 399, 289 + 399, 311 diff --git a/KVMViewer.cs b/KVMViewer.cs index 249f39a..2f5976f 100644 --- a/KVMViewer.cs +++ b/KVMViewer.cs @@ -43,6 +43,8 @@ namespace MeshCentralRouter public string lang = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; private bool splitMode = false; private KVMViewerExtra[] extraDisplays = null; + private System.Windows.Forms.Timer delayedConnectionTimer = null; + private bool localAutoReconnect = true; // Stats public long bytesIn = 0; @@ -84,7 +86,19 @@ namespace MeshCentralRouter mainToolTip.SetToolTip(clipInboundButton, Translate.T(Properties.Resources.PullClipboardFromRemoteDevice, lang)); mainToolTip.SetToolTip(zoomButton, Translate.T(Properties.Resources.ToggleZoomToFitMode, lang)); mainToolTip.SetToolTip(statsButton, Translate.T(Properties.Resources.DisplayConnectionStatistics, lang)); + + // Load remote desktop settings + int CompressionLevel = 60; + try { CompressionLevel = int.Parse(Settings.GetRegValue("kvmCompression", "60")); } catch (Exception) { } + int ScalingLevel = 1024; + try { ScalingLevel = int.Parse(Settings.GetRegValue("kvmScaling", "1024")); } catch (Exception) { } + int FrameRate = 100; + try { FrameRate = int.Parse(Settings.GetRegValue("kvmFrameRate", "100")); } catch (Exception) { } + kvmControl.SetCompressionParams(CompressionLevel, ScalingLevel, FrameRate); + kvmControl.SwamMouseButtons = Settings.GetRegValue("kvmSwamMouseButtons", "0").Equals("1"); + kvmControl.RemoteKeyboardMap = Settings.GetRegValue("kvmSwamMouseButtons", "0").Equals("1"); kvmControl.AutoSendClipboard = Settings.GetRegValue("kvmAutoClipboard", "0").Equals("1"); + kvmControl.AutoReconnect = Settings.GetRegValue("kvmAutoReconnect", "0").Equals("1"); } private void KvmControl_ScreenAreaUpdated(Bitmap desktop, Rectangle r) @@ -117,6 +131,25 @@ namespace MeshCentralRouter } } + public void TryAutoConnect() + { + if ((localAutoReconnect == false) || (kvmControl.AutoReconnect == false)) return; + if ((state == 0) && (wc == null) && (delayedConnectionTimer == null)) { + // Hold half a second before trying to connect + delayedConnectionTimer = new System.Windows.Forms.Timer(this.components); + delayedConnectionTimer.Tick += new EventHandler(updateTimerTick); + delayedConnectionTimer.Interval = 500; + delayedConnectionTimer.Enabled = true; + } + } + + private void updateTimerTick(object sender, EventArgs e) + { + delayedConnectionTimer.Dispose(); + delayedConnectionTimer = null; + if ((state == 0) && (wc == null)) { MenuItemConnect_Click(this, null); } + } + private void KvmControl_DesktopSizeChanged(object sender, EventArgs e) { kvmControl.Visible = true; @@ -318,6 +351,7 @@ namespace MeshCentralRouter wc.Dispose(); wc = null; UpdateStatus(); + localAutoReconnect = false; } else { @@ -325,6 +359,7 @@ namespace MeshCentralRouter if (sender != null) { consentFlags = 0; } MenuItemConnect_Click(null, null); kvmControl.AttachKeyboard(); + localAutoReconnect = true; } displayMessage(null); } @@ -434,11 +469,21 @@ namespace MeshCentralRouter form.SwamMouseButtons = kvmControl.SwamMouseButtons; form.RemoteKeyboardMap = kvmControl.RemoteKeyboardMap; form.AutoSendClipboard = kvmControl.AutoSendClipboard; + form.AutoReconnect = kvmControl.AutoReconnect; if (form.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) { kvmControl.SetCompressionParams(form.Compression, form.Scaling, form.FrameRate); kvmControl.SwamMouseButtons = form.SwamMouseButtons; kvmControl.RemoteKeyboardMap = form.RemoteKeyboardMap; + kvmControl.AutoReconnect = form.AutoReconnect; + + Settings.SetRegValue("kvmCompression", kvmControl.CompressionLevel.ToString()); + Settings.SetRegValue("kvmScaling", kvmControl.ScalingLevel.ToString()); + Settings.SetRegValue("kvmFrameRate", kvmControl.FrameRate.ToString()); + Settings.SetRegValue("kvmSwamMouseButtons", kvmControl.SwamMouseButtons ? "1" : "0"); + Settings.SetRegValue("kvmRemoteKeyboardMap", kvmControl.RemoteKeyboardMap ? "1" : "0"); + Settings.SetRegValue("kvmAutoReconnect", kvmControl.AutoReconnect ? "1" : "0"); + if (kvmControl.AutoSendClipboard != form.AutoSendClipboard) { kvmControl.AutoSendClipboard = form.AutoSendClipboard; diff --git a/MainForm.cs b/MainForm.cs index 60524d3..f2f66eb 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -647,6 +647,12 @@ namespace MeshCentralRouter // Setup any automatic mappings if ((fullRefresh == true) && (mappingsToSetup != null)) { setupMappings(); } + + // Reconnect any auto-reconnect nodes + foreach (NodeClass node in meshcentral.nodes.Values) + { + if (((node.conn & 1) != 0) && (node.desktopViewer != null)) { node.desktopViewer.TryAutoConnect(); } + } } private void updateDeviceList() From 95d1a442bedeba383c9221394df3ad406fafb4f0 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Wed, 2 Mar 2022 16:41:08 -0800 Subject: [PATCH 15/20] Improved multi-display selection. --- KVMViewer.Designer.cs | 30 +++-- KVMViewer.cs | 68 ++++++---- KVMViewer.resx | 142 +++++++++++++++----- MeshCentralRouter.csproj | 1 + Properties/Resources.Designer.cs | 10 ++ Properties/Resources.resx | 217 ++++++++++++++++--------------- Resources/icon-monitor1.png | Bin 0 -> 396 bytes Resources/icon-monitor1b.png | Bin 0 -> 339 bytes Resources/icon-monitor2.png | Bin 0 -> 461 bytes Resources/icon-monitor2b.png | Bin 0 -> 409 bytes Resources/monitor32.png | Bin 0 -> 848 bytes 11 files changed, 291 insertions(+), 177 deletions(-) create mode 100644 Resources/icon-monitor1.png create mode 100644 Resources/icon-monitor1b.png create mode 100644 Resources/icon-monitor2.png create mode 100644 Resources/icon-monitor2b.png create mode 100644 Resources/monitor32.png diff --git a/KVMViewer.Designer.cs b/KVMViewer.Designer.cs index c57a6e4..cee1679 100644 --- a/KVMViewer.Designer.cs +++ b/KVMViewer.Designer.cs @@ -51,11 +51,11 @@ namespace MeshCentralRouter this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.updateTimer = new System.Windows.Forms.Timer(this.components); this.topPanel = new System.Windows.Forms.Panel(); + this.extraButtonsPanel = new System.Windows.Forms.Panel(); this.splitButton = new System.Windows.Forms.Button(); this.clipOutboundButton = new System.Windows.Forms.Button(); this.clipInboundButton = new System.Windows.Forms.Button(); this.statsButton = new System.Windows.Forms.Button(); - this.displaySelectComboBox = new System.Windows.Forms.ComboBox(); this.settingsButton = new System.Windows.Forms.Button(); this.zoomButton = new System.Windows.Forms.Button(); this.cadButton = new System.Windows.Forms.Button(); @@ -68,6 +68,7 @@ namespace MeshCentralRouter this.consoleTimer = new System.Windows.Forms.Timer(this.components); this.mainToolTip = new System.Windows.Forms.ToolTip(this.components); this.resizeKvmControl = new MeshCentralRouter.KVMResizeControl(); + this.displaySelectorImageList = new System.Windows.Forms.ImageList(this.components); this.mainStatusStrip.SuspendLayout(); this.topPanel.SuspendLayout(); this.consentContextMenuStrip.SuspendLayout(); @@ -103,11 +104,11 @@ namespace MeshCentralRouter // topPanel // this.topPanel.BackColor = System.Drawing.SystemColors.Control; + this.topPanel.Controls.Add(this.extraButtonsPanel); this.topPanel.Controls.Add(this.splitButton); this.topPanel.Controls.Add(this.clipOutboundButton); this.topPanel.Controls.Add(this.clipInboundButton); this.topPanel.Controls.Add(this.statsButton); - this.topPanel.Controls.Add(this.displaySelectComboBox); this.topPanel.Controls.Add(this.settingsButton); this.topPanel.Controls.Add(this.zoomButton); this.topPanel.Controls.Add(this.cadButton); @@ -115,6 +116,11 @@ namespace MeshCentralRouter resources.ApplyResources(this.topPanel, "topPanel"); this.topPanel.Name = "topPanel"; // + // extraButtonsPanel + // + resources.ApplyResources(this.extraButtonsPanel, "extraButtonsPanel"); + this.extraButtonsPanel.Name = "extraButtonsPanel"; + // // splitButton // resources.ApplyResources(this.splitButton, "splitButton"); @@ -150,14 +156,6 @@ namespace MeshCentralRouter this.statsButton.UseVisualStyleBackColor = true; this.statsButton.Click += new System.EventHandler(this.statsButton_Click); // - // displaySelectComboBox - // - this.displaySelectComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - resources.ApplyResources(this.displaySelectComboBox, "displaySelectComboBox"); - this.displaySelectComboBox.Name = "displaySelectComboBox"; - this.displaySelectComboBox.TabStop = false; - this.displaySelectComboBox.SelectionChangeCommitted += new System.EventHandler(this.displaySelectComboBox_SelectionChangeCommitted); - // // settingsButton // resources.ApplyResources(this.settingsButton, "settingsButton"); @@ -243,6 +241,15 @@ namespace MeshCentralRouter this.resizeKvmControl.Enter += new System.EventHandler(this.resizeKvmControl_Enter); this.resizeKvmControl.Leave += new System.EventHandler(this.resizeKvmControl_Leave); // + // displaySelectorImageList + // + this.displaySelectorImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("displaySelectorImageList.ImageStream"))); + this.displaySelectorImageList.TransparentColor = System.Drawing.Color.Transparent; + this.displaySelectorImageList.Images.SetKeyName(0, "icon-monitor1.png"); + this.displaySelectorImageList.Images.SetKeyName(1, "icon-monitor1b.png"); + this.displaySelectorImageList.Images.SetKeyName(2, "icon-monitor2.png"); + this.displaySelectorImageList.Images.SetKeyName(3, "icon-monitor2b.png"); + // // KVMViewer // resources.ApplyResources(this, "$this"); @@ -278,7 +285,6 @@ namespace MeshCentralRouter private Button cadButton; private Button zoomButton; private Button settingsButton; - private ComboBox displaySelectComboBox; private Label consoleMessage; private Timer consoleTimer; private Button statsButton; @@ -290,6 +296,8 @@ namespace MeshCentralRouter private ToolStripMenuItem askConsentToolStripMenuItem; private ToolStripMenuItem privacyBarToolStripMenuItem; private Button splitButton; + private Panel extraButtonsPanel; + private ImageList displaySelectorImageList; } } diff --git a/KVMViewer.cs b/KVMViewer.cs index 2f5976f..920f39e 100644 --- a/KVMViewer.cs +++ b/KVMViewer.cs @@ -45,6 +45,7 @@ namespace MeshCentralRouter private KVMViewerExtra[] extraDisplays = null; private System.Windows.Forms.Timer delayedConnectionTimer = null; private bool localAutoReconnect = true; + private Dictionary displaySelectionButtons = new Dictionary(); // Stats public long bytesIn = 0; @@ -52,16 +53,6 @@ namespace MeshCentralRouter public long bytesOut = 0; public long bytesOutCompressed = 0; - public class displayTag - { - public ushort num; - public string name; - - public displayTag(ushort num, string name) { this.num = num; this.name = name; } - - public override string ToString() { return name; } - } - public KVMViewer(MainForm parent, MeshCentralServer server, NodeClass node) { this.parent = parent; @@ -376,7 +367,7 @@ namespace MeshCentralRouter { case 0: // Disconnected mainToolStripStatusLabel.Text = Translate.T(Properties.Resources.Disconnected, lang); - displaySelectComboBox.Visible = false; + extraButtonsPanel.Visible = false; kvmControl.Visible = false; kvmControl.screenWidth = 0; kvmControl.screenHeight = 0; @@ -384,13 +375,13 @@ namespace MeshCentralRouter break; case 1: // Connecting mainToolStripStatusLabel.Text = Translate.T(Properties.Resources.Connecting, lang); - displaySelectComboBox.Visible = false; + extraButtonsPanel.Visible = false; kvmControl.Visible = false; connectButton.Text = Translate.T(Properties.Resources.Disconnect, lang); break; case 2: // Setup mainToolStripStatusLabel.Text = "Setup..."; - displaySelectComboBox.Visible = false; + extraButtonsPanel.Visible = false; kvmControl.Visible = false; connectButton.Text = Translate.T(Properties.Resources.Disconnect, lang); break; @@ -515,35 +506,57 @@ namespace MeshCentralRouter resizeKvmControl.ZoomToFit = !resizeKvmControl.ZoomToFit; } + /// + /// + /// + /// + /// private void resizeKvmControl_DisplaysReceived(object sender, EventArgs e) { if (kvmControl == null || kvmControl.displays.Count == 0) return; if (kvmControl.displays.Count > 0) { - displaySelectComboBox.Visible = true; - displaySelectComboBox.Items.Clear(); + extraButtonsPanel.Visible = true; + extraButtonsPanel.Controls.Clear(); + displaySelectionButtons.Clear(); foreach (ushort displayNum in kvmControl.displays) { - displayTag t; if (displayNum == 0xFFFF) { - t = new displayTag(displayNum, Translate.T(Properties.Resources.AllDisplays, lang)); - displaySelectComboBox.Items.Add(t); + Button b = new Button(); + b.ImageList = displaySelectorImageList; + b.ImageIndex = (kvmControl.currentDisp == displayNum) ? 2 : 3; // All displayes + b.Width = 32; + b.Height = 32; + mainToolTip.SetToolTip(b, Translate.T(Properties.Resources.AllDisplays, lang)); + b.Click += new System.EventHandler(this.displaySelectComboBox_SelectionChangeCommitted); + b.Tag = displayNum; + b.Dock = DockStyle.Left; + extraButtonsPanel.Controls.Add(b); + displaySelectionButtons.Add(displayNum, b); } else { - t = new displayTag(displayNum, string.Format(Translate.T(Properties.Resources.DisplayX, lang), displayNum)); - displaySelectComboBox.Items.Add(t); + Button b = new Button(); + b.ImageList = displaySelectorImageList; + b.ImageIndex = (kvmControl.currentDisp == displayNum) ? 0 : 1; // One display grayed out + b.Width = 32; + b.Height = 32; + mainToolTip.SetToolTip(b, string.Format(Translate.T(Properties.Resources.DisplayX, lang), displayNum)); + b.Click += new System.EventHandler(this.displaySelectComboBox_SelectionChangeCommitted); + b.Tag = displayNum; + b.Dock = DockStyle.Left; + extraButtonsPanel.Controls.Add(b); + displaySelectionButtons.Add(displayNum, b); } - - if (kvmControl.currentDisp == displayNum) { displaySelectComboBox.SelectedItem = t; } } } else { - displaySelectComboBox.Visible = false; - displaySelectComboBox.Items.Clear(); + extraButtonsPanel.Visible = false; + extraButtonsPanel.Controls.Clear(); + displaySelectionButtons.Clear(); } // If there are many displays and all displays is selected, enable split/join button. @@ -553,7 +566,10 @@ namespace MeshCentralRouter private void displaySelectComboBox_SelectionChangeCommitted(object sender, EventArgs e) { if (splitMode) { splitButton_Click(this, null); } - if (kvmControl != null) { kvmControl.SendDisplay(((displayTag)displaySelectComboBox.SelectedItem).num); } + if (kvmControl != null) { + ushort displayNum = (ushort)((Button)sender).Tag; + kvmControl.SendDisplay(displayNum); + } } private void resizeKvmControl_TouchEnabledChanged(object sender, EventArgs e) @@ -738,5 +754,7 @@ namespace MeshCentralRouter } } } + + } } diff --git a/KVMViewer.resx b/KVMViewer.resx index 270e7a6..d23caf2 100644 --- a/KVMViewer.resx +++ b/KVMViewer.resx @@ -171,6 +171,30 @@ 154, 17 + + Top, Left, Right + + + 383, 4 + + + 658, 32 + + + 10 + + + extraButtonsPanel + + + System.Windows.Forms.Panel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + topPanel + + + 0 + Top, Right @@ -205,7 +229,7 @@ topPanel - 0 + 1 Top, Right @@ -238,7 +262,7 @@ topPanel - 1 + 2 Top, Right @@ -277,7 +301,7 @@ topPanel - 2 + 3 Top, Right @@ -310,36 +334,6 @@ topPanel - 3 - - - 16 - - - 384, 6 - - - 4, 4, 4, 4 - - - 169, 24 - - - 5 - - - False - - - displaySelectComboBox - - - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - topPanel - - 4 @@ -586,7 +580,7 @@ resizeKvmControl - MeshCentralRouter.KVMResizeControl, MeshCentralRouter, Version=1.8.8063.22517, Culture=neutral, PublicKeyToken=null + MeshCentralRouter.KVMResizeControl, MeshCentralRouter, Version=1.8.8096.29519, Culture=neutral, PublicKeyToken=null $this @@ -594,6 +588,80 @@ 2 + + 752, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADs + DgAAAk1TRnQBSQFMAgEBBAEAARABAAEQAQABEAEAARABAAT/AREBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABIAMAAQEBAAEQBgABEP8A/wD/AP8A/wD/AP8A/wAiAAH3AV4BpQEUAaUBFAGlARQBpQEUAaUBFAGl + ARQB9wFeEAAB9wFeAaUBFAGlARQBpQEUAaUBFAGlARQBpQEUAfcBXhAAAfcBXgGlARQBpQEUAaUBFAGl + ARQBpQEUAaUBFAH3AV4QAAH3AV4BpQEUAaUBFAGlARQBpQEUAaUBFAGlARQB9wFeEAAB3gF7ARgBYwFr + AS0BYwEQAYQBEAFrAS0BGAFjAd4BexAAAd4BewEYAWMBawEtAYQBEAGEARABawEtARgBYwHeAXsQAAHe + AXsBGAFjAWsBLQFjARABhAEQAWsBLQEYAWMB3gF7EAAB3gF7ARgBYwFrAS0BhAEQAYQBEAFrAS0BGAFj + Ad4BexQAAXsBbwFkARABZAEQAVoBaxgAAXsBbwFjAQwBYwEMAVoBaxgAAXsBbwFkARABZAEQAVoBaxgA + AXsBbwFjAQwBYwEMAVoBawwAAZwBcwH3AV4B9wFeAfcBXgH3AV4B9wFeAWsBLQFiARABYgEQAWoBLQH3 + AV4B9wFeAfcBXgH3AV4B9wFeAZwBcwGcAXMB9wFeAfcBXgH3AV4B9wFeAfcBXgFrAS0BYwEMAWMBDAFr + AS0B9wFeAfcBXgH3AV4B9wFeAfcBXgGcAXMBnAFzAfcBXgH3AV4B9wFeAfcBXgH3AV4BawEtAWIBEAFi + ARABagEtAfcBXgH3AV4B9wFeAfcBXgH3AV4BnAFzAZwBcwH3AV4B9wFeAfcBXgH3AV4B9wFeAWsBLQFj + AQwBYwEMAWsBLQH3AV4B9wFeAfcBXgH3AV4B9wFeAZwBcwErARkB2gEeAdoBHgHaAR4B2gEeAdoBHgHa + AR4B2wEeAdsBHgHbAR4BugEeAboBHgHaAR4BugEeAdoBHgFMARkBCAEhAVIBSgFSAUoBUgFKAVIBSgFS + AUoBUgFKAVIBSgFSAUoBUgFKAVIBSgFSAUoBUgFKAVIBSgFSAUoBKQElASsBGQHaAR4B2gEeAdoBHgHa + AR4B2gEeAdoBHgHbAR4B2wEeAdsBHgG6AR4BugEeAdoBHgG6AR4B2gEeAUwBGQEIASEBUgFKAVIBSgFS + AUoBUgFKAVIBSgFSAUoBUgFKAVIBSgFSAUoBUgFKAVIBSgFSAUoBUgFKAVIBSgEpASUBbAEZAT8BIwE/ + ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBbQEZASkBJQG1 + AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAUoBKQFs + ARkBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwFt + ARkBKQElAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1 + AVYBSgEpAWwBGQE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ + ASMBPwEjAW0BGQEpASUBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1 + AVYBtQFWAbUBVgFKASkBbAEZAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ + ASMBPwEjAT8BIwE/ASMBbQEZASkBJQG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1 + AVYBtQFWAbUBVgG1AVYBtQFWAUoBKQFsARkBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ + ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwFtARkBKQElAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1 + AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBSgEpAWwBGQH/ASYBfwEqAX8BKgF/ASoBfwEqAX8BKgH/ + ASYB/wEmAX8BKgF/ASoBfwEqAX8BKgF/ASoB/wEmAW0BGQEpASUBlAJSAUoBUgFKAVIBSgFSAUoBUgFK + AZQBUgGUAlIBSgFSAUoBUgFKAVIBSgFSAUoBlAFSAUoBKQFsARkBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ + ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwFtARkBKQElAbUBVgG1AVYBtQFWAbUBVgG1 + AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBSgEpAWwBGQF/ASoBfwE8AX8BPAF/ + ATwBfwE8AX8BPAF/ASoBfwEqAX8BPAF/ATwBfwE8AX8BPAF/ATwBfwEqAW0BGQEpASUBUgJKASkBSgEp + AUoBKQFKASkBSgEpAVIBSgFSAkoBKQFKASkBSgEpAUoBKQFKASkBUgJKASkBbAEZAT8BIwE/ASMBPwEj + AT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBbQEZASkBJQG1AVYBtQFW + AbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAUoBKQFsARkBfwEq + AX8BPAF/ATwBfwE8AX8BPAF/ATwBfwEqAX8BKgF/ATwBfwE8AX8BPAF/ATwBfwE8AX8BKgFtARkBKQEl + AVICSgEpAUoBKQFKASkBSgEpAUoBKQFSAUoBUgJKASkBSgEpAUoBKQFKASkBSgEpAVICSgEpAWwBGQE/ + ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAW0BGQEp + ASUBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgFK + ASkBbAEZAX8BKgF/ATwBfwE8AX8BPAF/ATwBfwE8AX8BKgF/ASoBfwE8AX8BPAF/ATwBfwE8AX8BPAF/ + ASoBbQEZASkBJQFSAkoBKQFKASkBSgEpAUoBKQFKASkBUgFKAVICSgEpAUoBKQFKASkBSgEpAUoBKQFS + AkoBKQFsARkBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEj + AT8BIwFtARkBKQElAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFW + AbUBVgG1AVYBSgEpAWwBGQF/ASoBfwE8AX8BPAF/ATwBfwE8AX8BPAF/ASoBfwEqAX8BPAF/ATwBfwE8 + AX8BPAF/ATwBfwEqAW0BGQEpASUBUgJKASkBSgEpAUoBKQFKASkBSgEpAVIBSgFSAkoBKQFKASkBSgEp + AUoBKQFKASkBUgJKASkBbAEZAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ + ASMBPwEjAT8BIwE/ASMBbQEZASkBJQG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1 + AVYBtQFWAbUBVgG1AVYBtQFWAUoBKQFsARkB/wEmAX8BKgF/ASoBfwEqAX8BKgF/ASoB/wEmAf8BJgF/ + ASoBfwEqAX8BKgF/ASoBfwEqAf8BJgFtARkBKQElAZQCUgFKAVIBSgFSAUoBUgFKAVIBSgGUAVIBlAJS + AUoBUgFKAVIBSgFSAUoBUgFKAZQBUgFKASkBbAEZAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ + ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBbQEZASkBJQG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1 + AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAUoBKQFsARkBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ + ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwFtARkBKQElAbUBVgG1AVYBtQFWAbUBVgG1 + AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBSgEpAUwBGQE/ASMBPwEjAT8BIwE/ + ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAW0BGQEpASUBtQFWAbUBVgG1 + AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgFKASkBTAEZAT8BIwE/ + ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBPwEjAT8BIwE/ASMBbQEZASkBJQG1 + AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAUoBKQHw + AT0B6AEYAegBGAHoARgB6AEYAegBGAHoARgB6AEYAegBGAHoARgB6AEYAegBGAHoARgB6AEYAegBGAHv + AT0B7wE9AecBHAHnARwB5wEcAecBHAHnARwB5wEcAecBHAHnARwB5wEcAecBHAHnARwB5wEcAecBHAHn + ARwB7wE9AfABPQHoARgB6AEYAegBGAHoARgB6AEYAegBGAHoARgB6AEYAegBGAHoARgB6AEYAegBGAHo + ARgB6AEYAe8BPQHvAT0B5wEcAecBHAHnARwB5wEcAecBHAHnARwB5wEcAecBHAHnARwB5wEcAecBHAHn + ARwB5wEcAecBHAHvAT0BQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEAAQEGAAEBFgAD/4EAAfABDwHw + AQ8B8AEPAfABDwHwAQ8B8AEPAfABDwHwAQ8B/AE/AfwBPwH8AT8B/AE/aAAL + + True @@ -1085,6 +1153,12 @@ System.Windows.Forms.ToolTip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + displaySelectorImageList + + + System.Windows.Forms.ImageList, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + KVMViewer diff --git a/MeshCentralRouter.csproj b/MeshCentralRouter.csproj index 341f63f..cf4c028 100644 --- a/MeshCentralRouter.csproj +++ b/MeshCentralRouter.csproj @@ -376,6 +376,7 @@ + diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index ab5d15a..42ad1d4 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -424,6 +424,16 @@ namespace MeshCentralRouter.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap icon_monitor1 { + get { + object obj = ResourceManager.GetObject("icon-monitor1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/Properties/Resources.resx b/Properties/Resources.resx index e1b095e..dd2d065 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -120,21 +120,18 @@ CIRA - - Toggle remote desktop connection - - - Unable to open file: {0} + + Change remote desktop settings - - ..\Resources\MeshCentral.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Gear20.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - Connect + + ..\Resources\icon-clipboard-in.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - {0} Bytes + + ZIP Selected Files Denied @@ -142,12 +139,6 @@ Invalid username or password - - {0} bytes/sec - - - Slow - Display connection statistics @@ -157,14 +148,14 @@ ..\Resources\50-Computer.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + Almost done + Email sent - - Port {0} to {1}:{2} - - - {0} minutes left + + Rename Failed to start remote terminal session @@ -175,8 +166,8 @@ ..\Resources\Empty-Banner.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - PuTTY SSH client + + Received invalid network data {0} Mbytes/sec @@ -184,8 +175,8 @@ ..\Resources\refresh16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - No tools allowed + + ..\Resources\delete16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a Send Ctrl-Alt-Del to remote device @@ -193,20 +184,23 @@ Fast - - {0} seconds left + + , Recorded Session Search - - Overwrite 1 file? + + Send token to registered email address? Don't ask for {0} days. - - Rename + + Stopped + + + ..\Resources\MeshCentral.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a Connecting... @@ -214,11 +208,14 @@ MeshCentral + + ..\Resources\folderzip.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + Failed to start remote desktop session - - Received invalid network data + + Offline Email verification required @@ -229,20 +226,20 @@ Unable to write file: {0} + + WinSCP client + {0} Kbytes/sec Changing language will close this tool. Are you sure? - - Invalid download. + + Connected - - Remove {0} items? - - - Change remote desktop settings + + Close Send token to registered phone number? @@ -256,17 +253,20 @@ Push local clipboard to remote device - - Unable to bind to local port + + {0} minutes left - - ..\Resources\icon-clipboard-in.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + Toggle remote desktop connection - - ..\Resources\MC2-Banner.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + Local - - Error uploading file: {0} + + Join + + + Relay Disconnected @@ -280,8 +280,8 @@ Medium - - Remote - {0} + + PuTTY SSH client Pull clipboard from remote device @@ -295,26 +295,23 @@ Port {0} to port {1} - - Very slow - Remove 1 item? - - , {0} connections. + + Overwrite 1 file? (Individual Devices) - - ..\Resources\xinstall.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + Split Create Folder - - ..\Resources\arrowright16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + {0} Bytes Updating... @@ -334,8 +331,8 @@ {0} hours left - - ..\Resources\icon-clipboard-out.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + Invalid download. Waiting for user to grant access... @@ -346,26 +343,29 @@ All Displays - - ..\Resources\HelpRelayMap.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + {0} seconds left - - MeshCentral Router + + ..\Resources\xinstall.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Disconnect AMT - - Local + + Port {0} to {1}:{2} - - Relay + + Error uploading file: {0} ..\Resources\icons01.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - Unable to connect + + Remove {0} items? Setup... @@ -376,14 +376,17 @@ ..\Resources\arrowleft16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - Close + + Unable to connect - - , {0} users + + Unable to bind to local port - - Disconnect + + No tools allowed + + + ..\Resources\arrowright16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a Languages @@ -391,14 +394,17 @@ Local - {0} - - ..\Resources\Gear20.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + {0} bytes/sec - - Offline + + ..\Resources\icon-clipboard-out.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - , Recorded Session + + Very slow + + + MeshCentral Router {0} Byte @@ -409,49 +415,46 @@ ..\Resources\folderup16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\delete16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + Unable to open file: {0} - - WinSCP client + + ..\Resources\MC2-Banner.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a , 1 connection. + + Connect + Two-factor Authentication Agent - - Connected + + , {0} connections. + + + Remote - {0} Error downloading file: {0} - - Almost done + + ..\Resources\HelpRelayMap.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a Remote - - Send token to registered email address? + + Slow - - Stopped + + , {0} users - - ..\Resources\folderzip.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ZIP Selected Files - - - Join - - - Split + + ..\Resources\icon-monitor1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a \ No newline at end of file diff --git a/Resources/icon-monitor1.png b/Resources/icon-monitor1.png new file mode 100644 index 0000000000000000000000000000000000000000..76380d010baf564fc447f6e8de81d94d9cde4e69 GIT binary patch literal 396 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1engQBO4V~B-+a!FyK_3wYz=coRpQ(R(6a^T#oFaRA&LsS@H+cE)|9}1?Oq@)UjXHjv|B&h^&b)Zp zrd{{{=ih%=`H=sz{esOBl0R5kh2r+ts`6hssi33t=fmma`rHjZ8xqg()Jyy`*krU} z}dgf3rHVL+Z!ouhEzyIxhcYgkTrZ+M&JZskE@YMhNBlzRr-`$6Q n^UK@qsr_DNAEGH>V8Fo8R2j{vBz_ghVqoxe^>bP0l+XkKiyxHe literal 0 HcmV?d00001 diff --git a/Resources/icon-monitor1b.png b/Resources/icon-monitor1b.png new file mode 100644 index 0000000000000000000000000000000000000000..8e7a6e6694c9075378ec787c8acb2384840c5073 GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBuf-vKbiP>*~f-gK>978PplS>K1oLs5|WY&V=ggz=nGHrHIpz+h>$q&;@!J{_ix{pKIO`~!R6ck z|MdoJj89s&*ZwYJa|;a(-9O*H{?KP84@F^N;pT=0heNZ?^Pf1@Bqly=2g<}X1wdSFBhu zanq(v3Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!T6?F-m4}VWDKBl4J5O+$s^mxN|FdsWrTEp9~Yy`xhpd% zicywUL|r6-Jin4xeOh7kl~%%qeqHJZ(4{i%MXjtYQJLD`1mp=IDV00000NkvXXu0mjf D+jGtF literal 0 HcmV?d00001 diff --git a/Resources/icon-monitor2b.png b/Resources/icon-monitor2b.png new file mode 100644 index 0000000000000000000000000000000000000000..7810b97f5e67a5d9a4197b45bb238617a01a75e1 GIT binary patch literal 409 zcmV;K0cQS*P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940WL{IK~y+TV{~zG zIs5(lcOwQe02>?IIYvJ}zyHzE(NH1M!1CqG8JHLu8KGR#0Z1fSmBQZ{N!2TT<3 zyZ}5SEgXiiHYe z0A?r+2hPsU8Zt66IV>zJMZjDt0CJ6}sHl;$va$dWzj*NA!5gSjFu*W?i;FA&+qZ9Z zfByUt;Nak3U}a@x0I`9FIRK;c!@GCy_Cu8d0Rsa7GQN?HJhIAu00000NkvXXu0mjf D8XToO literal 0 HcmV?d00001 diff --git a/Resources/monitor32.png b/Resources/monitor32.png new file mode 100644 index 0000000000000000000000000000000000000000..d11f8744d46d56a4dc43bf38880e0bd238175076 GIT binary patch literal 848 zcmWkrZA=>l0KJM1oop-p;(Fh`_Ih`vAN1>by}Qy+x|U!e44ovHw57l(PRaVm6=SAL zjQ%h~C`0$FWLv@*AT7pq&5XpwE!hmeH-F7e=ElS&k{HD$c>D3*%X{zNd!P5EjvhJ) z9RvX2P%;tgmz9-4yxJslt+LP}i=xnfGy<${B2Q%V@>uwdFaT7}z5YD&irlUB^$c|F z@9(GIIv(J?LBZGQ=R%@S^0||oAaa4sn}a8E85km{U=I`NrNb$vGs#B#h>WWz z2OEgnV?!aUjdM9n(FEQ7j?2PGE+@r$+_THxxm8bT#XYm;nXPzBRc>zGJ^hXJbQ8*Q5(KT+>zem+P)`YrQq$47Ba8`?r(!nf*GkVO7Vnzry z>LD7%%m_-s2(Hzk>Q+OWmIQT#PD7(`2Zd zW1(=sF9@8EGLSyECn!ph&R{eg;W?j1rA8nahYXX$)Co6YC* zj~@T_M`QcZ=Ej3xpKNXIZ0+pqJbd~)t^}1DLjm5 zYIa6F(_j8jBD}VMFDc=2U)4hX zRR6@&ZMfV3%atqFsUN)8yfp0-udQ7E{_;h&<*cG!pDIoji}k6!y<%~1d+EQ0MrdOL Y0P262td9Z3ro1GO>`KK}Bk5262jk%ly#N3J literal 0 HcmV?d00001 From bf668eae230ae6efde2a68269b6cad4c2176f3ad Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 12 May 2022 16:07:33 -0700 Subject: [PATCH 16/20] Added custom app support. --- AddPortMapForm.Designer.cs | 1 - AddPortMapForm.cs | 15 +- AddRelayMapForm.Designer.cs | 1 - AddRelayMapForm.cs | 15 +- CustomAppsAddForm.Designer.cs | 211 ++++ CustomAppsAddForm.cs | 70 ++ CustomAppsAddForm.resx | 1818 +++++++++++++++++++++++++++++++++ CustomAppsForm.Designer.cs | 248 +++++ CustomAppsForm.cs | 130 +++ CustomAppsForm.resx | 1818 +++++++++++++++++++++++++++++++++ CustomAppsRunForm.Designer.cs | 192 ++++ CustomAppsRunForm.cs | 58 ++ CustomAppsRunForm.resx | 1815 ++++++++++++++++++++++++++++++++ MainForm.Designer.cs | 22 +- MainForm.cs | 245 +++-- MainForm.resx | 548 ++++------ MapUserControl.cs | 33 +- MeshCentralRouter.csproj | 27 + Settings.cs | 49 + 19 files changed, 6885 insertions(+), 431 deletions(-) create mode 100644 CustomAppsAddForm.Designer.cs create mode 100644 CustomAppsAddForm.cs create mode 100644 CustomAppsAddForm.resx create mode 100644 CustomAppsForm.Designer.cs create mode 100644 CustomAppsForm.cs create mode 100644 CustomAppsForm.resx create mode 100644 CustomAppsRunForm.Designer.cs create mode 100644 CustomAppsRunForm.cs create mode 100644 CustomAppsRunForm.resx diff --git a/AddPortMapForm.Designer.cs b/AddPortMapForm.Designer.cs index e9f2b1c..adddb39 100644 --- a/AddPortMapForm.Designer.cs +++ b/AddPortMapForm.Designer.cs @@ -138,7 +138,6 @@ resources.GetString("appComboBox.Items4"), resources.GetString("appComboBox.Items5")}); this.appComboBox.Name = "appComboBox"; - this.appComboBox.Sorted = true; this.appComboBox.SelectedIndexChanged += new System.EventHandler(this.appComboBox_SelectedIndexChanged); // // label5 diff --git a/AddPortMapForm.cs b/AddPortMapForm.cs index 4205ea7..230a7cf 100644 --- a/AddPortMapForm.cs +++ b/AddPortMapForm.cs @@ -16,6 +16,7 @@ limitations under the License. using System; using System.Windows.Forms; +using System.Collections.Generic; namespace MeshCentralRouter { @@ -43,13 +44,25 @@ namespace MeshCentralRouter if (x == 3) { return 4; } // PuTTY if (x == 4) { return 3; } // RDP if (x == 5) { return 5; } // WinSCP - return x; + return 0; + } + public string getAppIdStr() + { + int x = (int)appComboBox.SelectedIndex; + if (x < 6) { return null; } // Custom or pre-defined + return apps[x - 6][1]; } public NodeClass getNode() { return (NodeClass)nodeComboBox.SelectedItem; } public void setNode(NodeClass node) { selectedNode = node; } + private List apps = null; + private void AddPortMapForm_Load(object sender, EventArgs e) { + // Add any custom applications + apps = Settings.GetApplications(); + if (apps != null) { foreach (String[] app in apps) { appComboBox.Items.Add(app[0]); } } + if (selectedNode == null) { // Fill the groups diff --git a/AddRelayMapForm.Designer.cs b/AddRelayMapForm.Designer.cs index fc328ef..10fb77a 100644 --- a/AddRelayMapForm.Designer.cs +++ b/AddRelayMapForm.Designer.cs @@ -140,7 +140,6 @@ resources.GetString("appComboBox.Items4"), resources.GetString("appComboBox.Items5")}); this.appComboBox.Name = "appComboBox"; - this.appComboBox.Sorted = true; this.appComboBox.SelectedIndexChanged += new System.EventHandler(this.appComboBox_SelectedIndexChanged); // // label5 diff --git a/AddRelayMapForm.cs b/AddRelayMapForm.cs index 0f02405..7c4e758 100644 --- a/AddRelayMapForm.cs +++ b/AddRelayMapForm.cs @@ -17,6 +17,7 @@ limitations under the License. using System; using System.Net; using System.Windows.Forms; +using System.Collections.Generic; namespace MeshCentralRouter { @@ -46,13 +47,25 @@ namespace MeshCentralRouter if (x == 3) { return 4; } // PuTTY if (x == 4) { return 3; } // RDP if (x == 5) { return 5; } // WinSCP - return x; + return 0; + } + public string getAppIdStr() + { + int x = (int)appComboBox.SelectedIndex; + if (x < 6) { return null; } // Custom or pre-defined + return apps[x - 6][1]; } public NodeClass getNode() { return (NodeClass)nodeComboBox.SelectedItem; } public void setNode(NodeClass node) { selectedNode = node; } + private List apps = null; + private void AddRelayMapForm_Load(object sender, EventArgs e) { + // Add any custom applications + apps = Settings.GetApplications(); + if (apps != null) { foreach (String[] app in apps) { appComboBox.Items.Add(app[0]); } } + if (selectedNode == null) { // Fill the groups diff --git a/CustomAppsAddForm.Designer.cs b/CustomAppsAddForm.Designer.cs new file mode 100644 index 0000000..19f68e9 --- /dev/null +++ b/CustomAppsAddForm.Designer.cs @@ -0,0 +1,211 @@ +namespace MeshCentralRouter +{ + partial class CustomAppsAddForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CustomAppsAddForm)); + this.okButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.nameTextBox = new System.Windows.Forms.TextBox(); + this.protocolTextBox = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.commandTextBox = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label4 = new System.Windows.Forms.Label(); + this.selectFileButton = new System.Windows.Forms.Button(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.ImeMode = System.Windows.Forms.ImeMode.NoControl; + this.okButton.Location = new System.Drawing.Point(244, 160); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 4; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.ImeMode = System.Windows.Forms.ImeMode.NoControl; + this.cancelButton.Location = new System.Drawing.Point(325, 160); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(75, 23); + this.cancelButton.TabIndex = 5; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 22); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(35, 13); + this.label1.TabIndex = 6; + this.label1.Text = "Name"; + // + // nameTextBox + // + this.nameTextBox.Location = new System.Drawing.Point(116, 19); + this.nameTextBox.Name = "nameTextBox"; + this.nameTextBox.Size = new System.Drawing.Size(266, 20); + this.nameTextBox.TabIndex = 7; + this.nameTextBox.TextChanged += new System.EventHandler(this.nameTextBox_TextChanged); + // + // protocolTextBox + // + this.protocolTextBox.Location = new System.Drawing.Point(116, 45); + this.protocolTextBox.Name = "protocolTextBox"; + this.protocolTextBox.Size = new System.Drawing.Size(266, 20); + this.protocolTextBox.TabIndex = 9; + this.protocolTextBox.TextChanged += new System.EventHandler(this.nameTextBox_TextChanged); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 48); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(46, 13); + this.label2.TabIndex = 8; + this.label2.Text = "Protocol"; + // + // commandTextBox + // + this.commandTextBox.Location = new System.Drawing.Point(116, 71); + this.commandTextBox.Name = "commandTextBox"; + this.commandTextBox.Size = new System.Drawing.Size(238, 20); + this.commandTextBox.TabIndex = 11; + this.commandTextBox.TextChanged += new System.EventHandler(this.nameTextBox_TextChanged); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 74); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(54, 13); + this.label3.TabIndex = 10; + this.label3.Text = "Command"; + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.selectFileButton); + this.groupBox1.Controls.Add(this.nameTextBox); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.commandTextBox); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.protocolTextBox); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Location = new System.Drawing.Point(12, 56); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(388, 98); + this.groupBox1.TabIndex = 12; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Application"; + // + // label4 + // + this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label4.Location = new System.Drawing.Point(12, 9); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(388, 44); + this.label4.TabIndex = 13; + this.label4.Text = "Enter a friendly name, protocol (like HTTP, RDP, VNC) and the command line and ar" + + "guments to run the application. In the command line, use %L for address and %P f" + + "or connection port."; + // + // selectFileButton + // + this.selectFileButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.selectFileButton.Location = new System.Drawing.Point(360, 71); + this.selectFileButton.Name = "selectFileButton"; + this.selectFileButton.Size = new System.Drawing.Size(21, 20); + this.selectFileButton.TabIndex = 12; + this.selectFileButton.Text = "..."; + this.selectFileButton.UseVisualStyleBackColor = true; + this.selectFileButton.Click += new System.EventHandler(this.selectFileButton_Click); + // + // openFileDialog + // + this.openFileDialog.DefaultExt = "exe"; + this.openFileDialog.Filter = "Executable|*.exe"; + this.openFileDialog.Title = "Select Application Executable"; + // + // CustomAppsAddForm + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(412, 195); + this.Controls.Add(this.label4); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.okButton); + this.Controls.Add(this.cancelButton); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CustomAppsAddForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Add Custom Application"; + this.Load += new System.EventHandler(this.CustomAppsAddForm_Load); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox nameTextBox; + private System.Windows.Forms.TextBox protocolTextBox; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox commandTextBox; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Button selectFileButton; + private System.Windows.Forms.OpenFileDialog openFileDialog; + } +} \ No newline at end of file diff --git a/CustomAppsAddForm.cs b/CustomAppsAddForm.cs new file mode 100644 index 0000000..07ca7cb --- /dev/null +++ b/CustomAppsAddForm.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace MeshCentralRouter +{ + public partial class CustomAppsAddForm : Form + { + public string appName + { + get { return nameTextBox.Text; } + set { nameTextBox.Text = value; updateInfo(); } + } + public string appProtocol + { + get { return protocolTextBox.Text; } + set { protocolTextBox.Text = value; updateInfo(); } + } + public string appCommand + { + get { return commandTextBox.Text; } + set { commandTextBox.Text = value; updateInfo(); } + } + + public CustomAppsAddForm() + { + InitializeComponent(); + } + + public void updateInfo() + { + okButton.Enabled = (nameTextBox.Text.Length > 0) && (protocolTextBox.Text.Length > 0) && (commandTextBox.Text.Length > 0) && (nameTextBox.Text.IndexOf(' ') == -1) && (protocolTextBox.Text.IndexOf(' ') == -1); + } + + private void CustomAppsAddForm_Load(object sender, EventArgs e) + { + updateInfo(); + nameTextBox.Focus(); + } + + private void nameTextBox_TextChanged(object sender, EventArgs e) + { + updateInfo(); + } + + private void okButton_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + } + + private void cancelButton_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + } + + private void selectFileButton_Click(object sender, EventArgs e) + { + if (openFileDialog.ShowDialog(this) == DialogResult.OK) + { + commandTextBox.Text = openFileDialog.FileName; + } + } + } +} diff --git a/CustomAppsAddForm.resx b/CustomAppsAddForm.resx new file mode 100644 index 0000000..7292dc4 --- /dev/null +++ b/CustomAppsAddForm.resx @@ -0,0 +1,1818 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + AAABAA0AMDAQAAEABABoBgAA1gAAACAgEAABAAQA6AIAAD4HAAAYGBAAAQAEAOgBAAAmCgAAEBAQAAEA + BAAoAQAADgwAADAwAAABAAgAqA4AADYNAAAgIAAAAQAIAKgIAADeGwAAGBgAAAEACADIBgAAhiQAABAQ + AAABAAgAaAUAAE4rAAAAAAAAAQAgAPgWAQC2MAAAMDAAAAEAIACoJQAArkcBACAgAAABACAAqBAAAFZt + AQAYGAAAAQAgAIgJAAD+fQEAEBAAAAEAIABoBAAAhocBACgAAAAwAAAAYAAAAAEABAAAAAAAgAQAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD/ + /wD/AAAA/wD/AP//AAD///8AAAAAAAAAAAAAAAAAAAAAAAczEwNwAAAAAAAAAAAAAAAId3cAAAAAAzc4 + N7gzAAAAAAAAAAAACHd3d4hwAABzeIt7c4tzcAAAAAAAAAh3d3d6p4j4cAN7iLeTOTiYcAAAAAAACHd3 + d3d4t3+Ih3OLeDODg4t7cAAAAAAAB3d3eHh4doj4+Ie3v4s5M4t7gAAAAAAAB3eHhnZ2d4iPiIOIeDl7 + c4iTAAAAAAAAB4d2VlZ3dYiI+Ie5v4t4O5t3gAAAAAAAB4ZXd3d3doj4iIOIiLczl4g7gAAAAAAAB4d3 + ZyV3d4iI+Ie7iIOLe4txAAAAAAAAB4dhdXd3doiIiIOIj7OXM3sbAAAAAAAAB3d3d2dndYiPiIOIuIuL + iJhzAAAAAAAAB4dlY3V3doiIiIi4e3e3k3M3AAAAAAAAB4d3d3d3d3iIiINzgTd7c4cAAAAAAAAAB4d3 + ZWdndoiIiIiDg4iAAIMAAAAAAAAAB3dDd3d3dYiIiIiDt4eAADsAAAAAAAAAB4d3dnV3doiIiIiDd4iA + AHMAAAAAAAAAB4d0NDZ3d3iIiIiDOIeAADkAAAAAAAAAB4Z3d3d3doiIiIeDeYiICDcAAAAAAAAAB4d3 + dldndXiHh4iDN4eIAzMAAAAAAAAAB4d0d3d3doiIiHh3M3iIA3kAAAAAAAAAB4d3d3d3d3h4eIeHMzN3 + MTAAAAAAAAAAB4d2FkNndniHh4h4c3ezE4AAAAAAAAAAB3d3d3d3dYeIeHh4d7lzdwAAAAAAAAAAB4h3 + Z3V3doh4eH54eHiIAAAAAAAAAAAAB3dnd4iIiHh4h4eHh4d4AAAAAAAAAAAAB4iIiIiIiHh3h4d4d3h4 + AAAAAAAAAAAAB/+IiIiIiHh4d3h3h3eIAAAAAAAAAAAAB/j4h4eIhoeHh4eHeHd4AAAAAAAAAAAAB4dn + R2dnd3d4d3d3d3h4AAAAAAAAAAAAB4iHd3d3Z3h3h4aHh3d4AAAAAAAAAAAAB4h3d3Z3dXh3d3h3d3d4 + AAAAAAAAAAAAB3d3d3d3doeHhod3d4Z4AAAAAAAAAAAAB/iId3d3dnd3eHd3d3d4AAAAAAAAAAAAB4h3 + dnR2dYd4d3d3d3d4AAAAAAAAAAAAB4eHd3d3d3d3d3d353d3AAAAAAAAAAAAB4+Ih3d3dnh3d4aHd3d4 + AAAAAAAAAAAAB4dnZ3d3d3d3hnd3d3doAAAAAAAAAAAAB4iIiIiIiHeHd3d3dnd3AAAAAAAAAAAAB/// + +IiIh3d3d3d3d3d3AAAAAAAAAAAAB/j4+PiIiHd3d3d2d3Z3AAAAAAAAAAAAB//4+I+Ijnh3d3d3d3d3 + AAAAAAAAAAAAB/j/j4iIh3d3d3Z3d2d3AAAAAAAAAAAAB/+Pj4+IiHd3d3d3Z3d3AAAAAAAAAAAAB/eH + d4iIh4d4aHd3d3d3AAAAAAAAAAAAB3ZmZCeIiGh3d2d3d3ZXAAAAAAAAAAAAB3h3d4eIiHd3d3d3d3d3 + AAAAAAAAAAAAAIiPiIiIh4iIiIAAAAAAAAAAAAAA/////4B/AAD//4P+AD8AAP/4AfAAHwAA/4AAYAAf + AAD+AAAAAB8AAP4AAAAAHwAA/gAAAAA/AAD+AAAAAB8AAP4AAAAAHwAA/gAAAAA/AAD+AAAAAD8AAP4A + AAAAPwAA/gAAAAA/AAD+AAAAAP8AAP4AAAAc/wAA/gAAABz/AAD+AAAAHP8AAP4AAAAc/wAA/gAAAAj/ + AAD+AAAACP8AAP4AAAAI/wAA/gAAAAH/AAD+AAAAAf8AAP4AAAAD/wAA/gAAAA//AAD+AAAAD/8AAP4A + AAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA// + AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP4A + AAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP8AAB///wAAKAAAACAA + AABAAAAAAQAEAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIAAAACAgACAAAAAgACAAICA + AACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP///wAAAAAAAAAAAAAzMzMzMzMwAAAAAAAA + AAAAuLe4t7m4kAAAAAAIh3eHAHubObMzMzAAAAh3d3o2/4C3uLiLe5swAAAIeHd4t4/4e3k7k5NzMAAA + CIh4d3b4j7e4uLizuDAAAAh3dnd3j4h7e5ezOTOQAAAIdnd3dviIt7i4uLe4MAAACIiHh4eIiDlzeTlz + eTAAAAh3d3Z2+IiIe3gAe3AAAAAId3d3dYiIiHg4ADeQAAAACIiHh4b4iIg4OAB7cAAAAAiHd2d3iIiI + e3gAe3AAAAAId3eHdoiHh3iHg7lwAAAACIiIeHeIiHhzi4e3AAAAAAh3Z2d2iHh4h3OXcAAAAAAIiIiI + hYh4h4eIAAAAAAAACP+PiIeHh3h3hwAAAAAAAAj/j4+GiHh3h3gAAAAAAAAI+PiIh4eHd3h4AAAAAAAA + CHd3d3aHd4d3dwAAAAAAAAiIiIh3h4d3d3gAAAAAAAAI+Ijnhod3d4Z3AAAAAAAACHd3d3eHeHZ3eAAA + AAAAAAiIiIeEh3d3d3cAAAAAAAAI+IiId4d3d3d3AAAAAAAACId2d4aHd3d3dwAAAAAAAAj4+PiGh3d2 + d2cAAAAAAAAI//+Ih3d3d3d3AAAAAAAACIh4j4aHd3d3dwAAAAAAAAh2QniHd3d3Z3cAAAAAAAAIiIiI + h4h4iIiAAAAAAP//wAH//8AB/4DAAfgAQAH4AAAB+AAAAfgAAAH4AAAB+AAAAfgAAMf4AADH+AAAx/gA + AMf4AAAH+AAAD/gAAB/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gA + AP/4AAD/+AAA//gAAP/4AAH/KAAAABgAAAAwAAAAAQAEAAAAAAAgAQAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP// + /wAAAAAAAAADMzMzMzAAAACHd4ALi4t7mzAAd3dyp/iDubOTczAAiHh3to/4uIuLOTAAiHd3d/iDk7M5 + NzAAiHeHd4iLi4t7OzAAiId3d/iDc3k3dTAAh3d4Z4iIe3ADtwAAiIh3eIiIeDAHlwAAiHfnd4iIODAH + twAAiIh4d4h4e4eLNwAAiGd3h4h4d4t5eAAAiPj4hoeHdzc4gAAAiP+Ih4eHh4AAAAAAiIiIh4d3eHAA + AAAAiId3d4eHd3AAAAAAiIiIdod3d3AAAAAAiHhod4d3d3AAAAAAiIiId3d3d3AAAAAAiId4d4d3Z3AA + AAAAj4+IhoZ3d3AAAAAAj/j4h3d3d3AAAAAAiGdoh4d3dnAAAAAAiIeIh4eIiIAAAAD/+AEA/BgBAMAA + AQDAAAEAwAABAMAAAQDAAAEAwABjAMAAYwDAAGMAwAADAMAAAwDAAAcAwAB/AMAAfwDAAH8AwAB/AMAA + fwDAAH8AwAB/AMAAfwDAAH8AwAB/AMAAfwAoAAAAEAAAACAAAAABAAQAAAAAAIAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A + /wD//wAA////AAB3d3MzMzMwAIeHiLi3uTAAiHhzt5M7MACIiIi4u3eQAIeHgzsXmzAAiIiIdwA3AACI + johzADcAAIiIh3e3NwAAh3Z3d3NwAACP/4+HAAAAAI+Pj/cAAAAAh3d3dwAAAACP+PiHAAAAAI//j4gA + AAAAiGYGiAAAAACIiIh4AAAAwAEAAMABAADAAQAAwAEAAMABAADAMwAAwDMAAMADAADABwAAwD8AAMA/ + AADAPwAAwD8AAMA/AADAPwAAwD8AACgAAAAwAAAAYAAAAAEACAAAAAAAAAkAAAAAAAAAAAAAAAEAAAAB + AAAAAAAAPj46AEA9PABBQT4ADDtRAA9BVQANRFwADUhgAABIagAYSWAAC1FvAB1UbwAHVnYAElt6ACZP + YgATYH8AM2J2AEhFQwBRTk0AV1NNAFVSUQBZVVIAXFhVAF5bWQBgWU8AZV5VAHRoRQBpYFUAZWFdAGtk + WwBxal8AZWNgAGllYgBuaWQAbWpoAHJsZwB6cWYAdXNrAHp0awB3eG8AeHhvAHVzcAB8dXAAe3tzAHx8 + egCFe2wAg3tzAIl/cQCCf3oAin95AH+AdgAO8U4ADexdAI2AbwCRh20AgIB3AI2BcwCDg3wAi4J7AJCE + cgCQhXsAk4l8AJmOfwAKX4EAE2KEAB9ohgASZ4kAFWmLABdukQAUcpUAG3KVABx3mgAcep4AIGeFACdu + jwAlcI4AJXOTACF3mgAkepsAKXyeADFzkAA8d5IAP3iQACR+oABId4wAW3WCACWAowArg6QAJoesAC6I + qgAyhKQAMYeoADOKqwA5jKwANI6yADqPsQAskroANJCzAD2StAA9mbsAXYqcAHiDhwBhhpcAZomYAHaU + nQB/kpwAToqiAFyNoQBLkKsAXZGmAEKUtQBBmLcASpi2AEGWuABEmrsAUZq3AHSWowBUoL8Ac6C1AH2n + uAB2qb4AZ/S4AEKdwQBKn8AARqHEAEyixABNqcoAUKXFAF2pxgBTqssAWK3OAE+u0ABYr9EAUrPXAFux + 0QBbtdgAWbncAGGqxwBgrswAca7FAHO0zQBgtdUAbbXRAGO41gBjutoAarzcAHK61QA98tUAc8DeAGbE + 5QBtwuIAccXlAHzG4AB2yOcAe8rmAHTK6QB6yukAhoWAAImGgQCLi4MAjo2JAJKLgwCajoQAkI6KAI+Q + hwCTkYYAnpOFAJOSjACblYsAnZiMAIWXmwCVlZEAmZaQAJqakwCTnJwAnp2YAKCThwCgmYQAoZaNAKWf + jwChnZcAo6GWAKqilACjo5wAqqOeALSsmwCNo6oAmqWmAI6wvgCZsbYAq6qkALGqowCwragAqbCtALOy + qwC5tasAqrW2ALW1sQC7tbEAt7ixALu7tACwvLoAvby7AMG1rwDBvLYAtsG/AMXEugDRzLkA1dC9AI6w + wACcvcsAtcfPAITO6gCP0+wAmtftAJrY7QCD1fQAkNv3AKjd8gCU4fwAoeL7ALfl9wC55fUAs+r9AMXF + wgDJxsAAzMvDAMTOygDNzMoA0M3FANTRwgDZ1cQA29jGANPTywDY1s0A29nMANLR0ADb29IA4N3PAOHe + 1QDf4NcA5OHUAOzo1ADk49oA6OnfAPLw3wDC6/sAzvH/AOfp4ADq7OIA7e/oAO/x5gDy8+oA6/v/APT2 + 8QD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdlELCQQFB2kAAAAAAAAAAAAAAAAA + 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 + TgBkYVsAaWJYAGpkWgBsZVsAa2RcAGxkXABrZmEAaWlnAG1qZgBxcWcAcnJoAHRxaQB1cm0AdnduAHhz + bwB6dG0Ad3hvAHt3cgB5eXEAfnhxAHx8cgB8eHUAfX11AIF7cwCDfHMAgXt1AIJ8dACEfnUAgX55AIR/ + eAAAzEYAE+5RAICAdgCBgnkAhoB5AIGBfgCGgn0AhYV9AImCeACIg34Ai4V+AI2FfQCIin4AkYd7AJCH + fQCQiX0AlYl+AJaMfwA+epsAAXimAEdzjwBTdo8ARXSSAE59lwBEe5sAVXeQAFJ6kgBWeJEAUXyXAFN9 + mABbfpgAF4y5AByRvgBWgJgAXYObAGKFmgBIiakAWZOuAGyQpwB7l6oAdZmuACzTuABV0pwAEJ3YACCV + wgAil8QAJJnGACmdygArn8wALKDNADCk0QAzp9QAM6vXADWq1gAzrNkAOa7aADSx3AA7sNwANLThAD+0 + 4ABOsNIAbbHJAEO45ABFuuUAR7znAEm+6QBrwt4AS8DrAEzB7ABRxfAAVsv1AF7T/QBtx+MAZMjmAGTI + 6ABzy+QAYNX/AGTV/wBo1v8AhYaBAIiGgACHiIEAiYmBAI2IgQCMjIMAjYmFAI2NhQCOj4oAkYqBAJGN + hQCYjoAAn4+FAJCPiACPkYoAm5GCAJyRggCbkYUAnZKEAJOTjACYlIwAnZmPAJeXkACZl5MAmpqTAJ6d + mgCglYYAopiJAKSajAClnI4AoZqSAKadkQChnpYAqZ+SAKCfmQCpoJIAqaGVAK6klwChoJoAoqOcAKWl + nQCqopgAraWZAK2omwCwp5oAta+bALGpnQCUn6IAl6KlAKWloQCrqqQArq6qALGqoQCwrKMAtq2hALCs + pQCyr6kAr7CoALiwpQCxsaoAtrGoALCwrgC1s60As7SvALW1rgC7tKgAvrisALW0sgC4t7AAubmyAL65 + sgC5ubQAvLy0ALy8uQDAuq8AwLqwAMS8sgDDvrcAxb60AMC/vADHw7cAzMaxAMHBuQDGwbkAwsG8AMTE + vQDJxLoAzcq9ANDLtwDExMEAyMfHAMjIwADNysEAysnGAM7LxADOzMQAzM3KANHOxgDQzskAztDGANXS + xgDb1cMA09HIANXRyADS0s4A09TMANfXzwDe28wA1dbSANjY0ADd2tEA29zSAN/c0QDY2tQA3d7WAN3d + 2QDi388A4t/RAOXi0wDo5dYA5ODZAOXm2wDi4dwA5uXcAOvn2QDr6dkA8e7eAOXl4ADn5+QA6erkAOrs + 5gDu7uQA9fLiAPj15QDw8eoA9vjxAPv58AD///cA///6AP///wAAAAAAAAAAAAAAAAAAAAAAAAA4ODg4 + ODg4ODg4ODg4AAAAAAAAAAAAAAAAAAAAAAAAAGhoZmRkZGxgVlZWYDgAAAAAAAAAAAAAx556NAT6KgAA + WFhTU1JRWkQ4ODhFOAAAAAAAAMGYMjI0gCUmCvv9mgBoaGhmZGRxYFZWVmA4AAAAAAAAwXqShYV/T04K + 9e/971hYVlVVU1xEODg4RTgAAAAAAAC+taKYj4WFNAj14uHWaGhqaGZmcWBWVlZgOAAAAAAAAMGSMBoW + EhotCvPh3sdYWFhXVlVeRDg4OEU4AAAAAAAAvg8WIS00f4AI793dvGhoa2poaHNgVlZWYDgAAAAAAADB + vrWekY6EhAjv09evODg8PDw4ODhAQDs4OAAAAAAAAMGokn0hISEtCufTz8+vmkFvQNMAADtbPQAAAAAA + AAAAxBoVITAyNIQI4s/Dx8/HQW9A0wAAO1s3AAAAAAAAAADTxL6omJGOhAjhw7y8u7xBb0DPAAA7WzcA + AAAAAAAAANOoiDAhISEhCuG8u7uvt0ZuR8cAAElfQwAAAAAAAAAA0xV1en2FhYUK3Luvr6+vSG1iTUxK + XVBLAAAAAAAAAADa0MG1opWPhQjWr6+tpqakQWdwZ2FQQQAAAAAAAAAAANN9FRYVFSF9CNOnpqWlpaWk + SEA6QEsAAAAAAAAAAAAA06zHxMrZ08oIz6aapaWUlJSWrwAAAAAAAAAAAAAAAADQ+fjx6OHZyg3DmqWU + lJSMjIymAAAAAAAAAAAAAAAAAN35+PHo6NjLDbyalIyMioqKiqYAAAAAAAAAAAAAAAAA0Pn48uvh2csN + vJSMioqHgoKBmgAAAAAAAAAAAAAAAADQjC4qMCoqNAi8jIqCgoKCeoKUAAAAAAAAAAAAAAAAANCvwa+o + opiRCLuKgoGCNDF6LIkAAAAAAAAAAAAAAAAA3eLaxMK1oJcKu4KCeiwxMSosigAAAAAAAAAAAAAAAADT + i4h6KTAwfQi3gnqCLDEqKieHAAAAAAAAAAAAAAAAANOspqisqJ6SCLd6MSwsKicnG4EAAAAAAAAAAAAA + AAAA2uzi2sTBqKANrzF6LCgbKhsbggAAAAAAAAAAAAAAAADQm3wuKjCIiQinMSwqKicbGxQsAAAAAAAA + AAAAAAAAANr05+fi2dnFBacxLigbGxsUFSwAAAAAAAAAAAAAAAAA2v//+vro2cUFpjEuKCgbGxkRLAAA + AAAAAAAAAAAAAADQ6KKirNnvzAWnMS4oKBsZFBEsAAAAAAAAAAAAAAAAAN0GAwIBDtrZCKYxMSgZGxQU + FCwAAAAAAAAAAAAAAAAA0cHBw723t7eNo6WlscPDz9bPAAAAAAAAAAAA///AAf//wAH/gMAB+ABAAfgA + AAH4AAAB+AAAAfgAAAH4AAAB+AAAx/gAAMf4AADH+AAAx/gAAAf4AAAP+AAAH/gAAP/4AAD/+AAA//gA + AP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAf8oAAAAGAAAADAA + AAABAAgAAAAAAEACAAAAAAAAAAAAAAABAAAAAQAAAAAAAGNfWABcclcAa2VeAFprYQBycmkAc3FtAHV1 + bQB5eG4Af3ltAHp6cQB6enQAfn51AINtYwCCemUAg3pvAIF7cgCFenAAg310AIR9dACBfngAhH94AA66 + LAAA/z4AgIB3AIGBeQCFgnkAhIR7AIWBfQCFhH0AiYF5AIiEewCNhXkAiIF8AImFfQCOh34AiIh+AI6I + fwCRh3oAlYt7AJCJfQAaYoMAGmiKABpxlgAadp0APnqbAAF4pgAaeKAAR3OPAEV0kgBOfZcARHubAFV3 + kABSepIAVniRAFF8lwBTfZgAW36YABqCqwAahK0AGoq1ABqLuAAajboAVoCYAFmAmABdg5sASImpAFmT + rgBgh6AAe5agAHWZrgAA1LIAQ8mLABqUwwAQndgAIpzKACSezAAqo9IALabVADOr1wAwqtgAM6zZADSx + 3AA0tOEAPbfkAE6w0gBtsckAQrzpAEW/7ABrw98ARsDtAEjC7wBNyPQAUMr2AG3H4wBkyOYAZMjoAHPL + 5ABn4v8AaOP/AI2HgACJiYEAjYiCAI6JhQCNjIUAkIqCAJGMhQCVjocAkY+IAJuQgQCRkYkAl5CIAJWR + jgCVlY0AmpOJAJyTiACclIkAnJaNAJiYjwCfmY8Am5eRAJiYkQCamZYAnJqWAJ2dlgCdnpgAnZycAKWP + hQCli48AoJaJAKGYiwChm48ApZuOAKadjwCgkZAAoZqQAKSbkACinZIApJ+ZAKqhlwChoJoApKObAKKi + ngClpZ4Ar6edAICbpQCjo6MApqagAKmnoQCqqaMArqmgAKqqpACtraYAra2qALGqoQC1raIAsq2lALCv + qwCvsKkAr7OtALizogCxsKgAtrCoALS0qwCzsqwAtbStALy2qwC4tK4Av7esALOxsAC2tbEAubmyAL26 + sgC+u7UAvr62ALm5uAC9vbkAxL6pAMS+rQDAurEAxL2zAMO+tADEv7UAwL+9AMbAtgDDw7sAxsK4AMfE + ugDDw7wAxMO9AMXFvADLxbsAysW8AMzHvQDPyrkAyci9AM3LvwDRzbwArcjVAMTGwgDKx8AAysjBAM3K + wgDJycQAy8zEAM7PyQDQzcAA0M3EANTPyADP0MoA09DHANPRyQDU1c0A2NTJAN/czgDT1dEA19XRANnZ + 0gDb29YA4N3PAObY0ADt2tMA5OHVAOvm0wDg4NoA5OPbAOfn3wDq6N0A5+bhAOno4ADs7OIA9vTjAP7+ + 7gD49fMA+fjzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAuLi4uLi4uLi4uAAAA + AAAAAKx1EQLHAABdXFxjWFBQPUsuAAAAdXV1CQ0WFwTp5Y5NS0xUSTo6KiwuAAAAs4p1g39IRwPh5eVa + WltiWE1QPUsuAAAAs5xpEREfEWbh2aw9PD1NOi8vKSwuAAAAwJZpd4mDbSXZ1KVaWltjWE1QPUsuAAAA + urOciSggDyDZzK4uMjIyLi41MjAuAAAAwJwfZGl1JiDXuse6N2A2AAAxTzMAAAAAuMCmkIltIGTNsKur + N2A1AAAxUC0AAAAAuqVkaWt1IB/LqqWlP19BAABCUzkAAAAAuLqlnIuDKB+6npaYP15WRkNSSkQAAAAA + uqZkIGSGgCCwl5eOkTdZYVVKN8YAAAAAs83Z2dzDnhyrjn19d5E1NjVExgAAAAAAs97o593DnyCqd313 + eXF9AAAAAAAAAAAAuNXc1MW6nxyYeXlxcXFxAAAAAAAAAAAAuKVxbGtrIByWeXFoaBxxAAAAAAAAAAAA + s9LSwKacbR+ScWhoHGhoAAAAAAAAAAAAwKx3eWZrZByOaB8dGwwkAAAAAAAAAAAAwMy3t7ObghF9aBsb + GwsfAAAAAAAAAAAAzMCdiniJdRl9HxsbCwsMAAAAAAAAAAAAz9jX1MPFoAt9HxsLCwcLAAAAAAAAAAAA + 0uTp5ePfsQt9HxkLCwcLAAAAAAAAAAAA1LEOAQfIxQt3HQsLBwUHAAAAAAAAAAAA1KyUkn2qrHeSkp6q + r7C6AAAAAAAAAP/4AQD8GAEAwAABAMAAAQDAAAEAwAABAMAAAQDAAGMAwABjAMAAYwDAAAMAwAADAMAA + BwDAAH8AwAB/AMAAfwDAAH8AwAB/AMAAfwDAAH8AwAB/AMAAfwDAAH8AwAB/ACgAAAAQAAAAIAAAAAEA + CAAAAAAAAAEAAAAAAAAAAAAAAAEAAAABAAAAAAAAMzMxAFxOJgB3cWoAeHJpAHhzbwB9dm4Ah31uAIJ7 + cgCFfnYAiH9yAIF/egCKgXYAjIN3AI+EdQCOhnwAlIl6AJqPfwAad58AAXimABZ9pAAaeKAATXCKAE5y + jABKdI8AX3aEAFh+lwAagqsAHoOoABqErQAai7gAGo26ADmdvQBuhZQARJKsAEmftgBQobcAGpTDACWf + zQAqo9IALabVADCq2AA9t+QAQrzpAEW/7ABGwO0ASMLvAE3I9ABQyvYAZ+L/AGjj/wCKhoEAlIyDAJ+W + hgCmnI0Aop6YAKqhkwCto5YAraSXAKqimACwp5kAsqiaALSqmwCzqpwAtqyeALSsogC4r6EAtrCmALqw + ogC8s6UAvbSmALqzqgC/tqgAu7WtALy3rwC/urMAwbepAMK5qwDEuqwAxr2vAMG8twDIvrAAwb24AMnB + sgDEwLsAxsO/ANPNuQDGw8AAyMbCAMrIxgDMysgA4NvKAOHcywDk384A6OXUAOrn2gDs6N0A7ergAO7s + 4ADw7eMA9fPpAPX16gD29OwA+PfuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + GJoAAAAwDUhjJCBnhf9Yr9H/YbnZ/2bE5f+x6Pv/YarH/zKJqv8tg6T/HHSV/xVpiv8KX4H/QJK0/16z + 0v84jq//UrPX/zFkfa4AAAA9AAAAOgAAACkAAAAXAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABzcW6BdWtiwouAef+Ngnz/i4B3/46Edv+Vi33/l4x9/5OJff9+dXD/Z/S4/z3y1f9rY1j/sK2o/93d + 1f/d3dX/5OPa/9PSy/9dXlzYBxsjikaWtv9wxub/XLLS/0ypyv+a1+3/XKrH/zSLrP9Albb/R5y9/0ec + vf9BmLf/c8De/3rL6v9Fm7z/Joes/xpOZaoAAAA8AAAANwAAACcAAAAbAAAADQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACEg3//fXRu44p/ef+ViYP/louC/5OIe/+Zjn//n5OE/56Thf+flon/nI6F/6CT + h/9pYFT/sa+q/9vc0//b29L/29rR/93d1f/n5tv/mKSl/DqRsv9Ppcb/WbDQ/3DE5P/O8f//bbXR/0CY + uf86j7H/LoSl/yR5m/8SZ4n/QZm6/1KoyP8vhab/Wrjc/z96kpYAAAAgAAAAIAAAABIAAAAJAAAABwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFhID/g3pzyZOIgv+dkYr/oZaN/56Vi/+Ignv/ZmJe/1xZ + V/9nZGH/fHZx/5KLgv9vZlv/srGr/9vb0f/Z2tH/2dnR/9jYz//Y2M//xM7K/ziOr/9swuH/ab7f/1y1 + 2P+o3fL/VKC//yd/oP8yh6n/NImq/zeMrv82i67/brzZ/3rK6f8pgKH/FXSX/2WmwmkAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjor/kIR7s4+Ff/94cW3/amZl/1ZT + VP9EQkL/T0tI/2tlXf9+dWr/i4Bw/5GFcv9oX1P/tLOt/9jZ0P/Y187/19bO/9fWzf/S0cr/nKam/0Wa + vf9Yrc7/WKzO/2m/3f/C7Pz/dLvV/0ujxP9TqMr/S6HC/z+Vtv8vhKX/Vq3N/2C11f9Blrj/QJ3C/z5+ + mIMAAAANAAAACgAAAAQAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjor/hn15tVJP + T/9dWVf/enJs/4J4a/+LgHH/joN0/5SMgP+PiYD/hoB6/42GgP9tZlz/tLKr/9XVzP/V1c3/1dPL/9XV + zP/R0cr/sLy6/zKKq/90yun/gdPy/4/T7P/D6vr/Up68/yR8nv8nfJ3/Inma/x1zlv8edJf/YK7M/2m5 + 2P8Vao3/MY6y/0mGoYcAAAAQAAAAHwAAABMAAAAJAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACQjon/kIR+u4R5dP+QhH7/iYB6/3BqZf9fXFn/WFRS/1tYVP9rZmH/eXNr/4uDeP9qYVf/s7Gs/9LT + y//T08v/0tLK/9HSyv/MzMT/lZ+e/1Cmxv9tw+L/YLna/1i63f+35ff/cbrV/0qiw/9Vqsv/VarL/1Gm + x/9Oo8T/esnm/3bI5/8/lbb/E3CU/3q51WQAAAAAAAAAAwAAAAcAAAAFAAAAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACPjor/loyDxHVva/9WUlD/SUVE/1ZRTv9yamT/iX9y/4uAcf+Og3T/j4R2/5KH + ef9pYFT/s7Gs/9HRyf/Q0Mn/0NDH/8/Pxv/MzcT/ucK//y6Jqv9wxub/hM7q/7nl9f/r+///XqjF/zGJ + q/8xh6j/KH2e/x91lv8hd5r/S6LE/1SrzP8XbpH/NJCz/6jh+mEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjor/koiCy3Zva/+HfXf/jIF4/5CHfv98dnH/ZGBd/19c + Wv9hXlz/c29q/4yEff9rY1j/s7Gr/87Oxv/Ozsb/zM3E/83NxP/Gxr//kZqb/z2Zu/+Q2/f/oeL7/5Th + /P+27f//fcvn/1Srzf9nu9r/bsPj/3XK6v9juNb/OIyr/0+kw/9Opcf/HHqe/4e/2GUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjon/nJCJz352cf9pZGP/W1hW/1RR + T/9dWVT/aGFb/3hwZv+Eemv/jYFv/4+CcP9nXlP/srGr/83MxP/Ly8P/ysrC/8nKwf/Hx8H/qrW2/2q+ + 3/+G1/f/c7TN/0+LpP9JmLf/XrfY/1WrzP9Zr8//U6jJ/0uixP8FWHn/W3WC/yZPYv8fd5n/PpW3/4i/ + 1mwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOjon/k42H1nNs + af9/dXH/hnpz/4uAcP+Pg3P/j4N0/5KKf/+QiYD/jIV//5SNhP9oYFT/srGr/8nJwf/KycH/x8fB/8bG + v//Fxr//tMC//zePsv87kLL/Flx6/32nuP8ASGr/MIms/z+Vtv9Kn8D/VKrL/zyStf8AV3n/tcfP/12R + pv8FWHkoAExvLG2kvAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACOjon/p5uS3ZGFf/+LgXz/d3Ft/2ZhXv9dWlj/WldU/19cWf9taWT/fXVv/4yDef9pYFb/s7Ks/8bG + v//Gxr//xcW+/8TEvP/Dw7r/wsK6/8LBuv+Zsbb/M4Wl/3zG4P8ydJD/jaOq/6mwrf+qqaX5X2BgVwAA + AAwPQ1tHca7F/z+QsP8AAAAGAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACPjor/npWP4mhkYf9RTUz/WVRR/2VeWf99dGj/iX5t/46Ccf+QhHP/kIRz/5GF + dP9oYFb/srGr/8PDvP/Cw7z/wsG5/8DBuf/AwLj/wMC3/76+t/+9vbf/Inia/1Otz/93k5v/nZyY/52c + mP+9vbX9uLm6bQAAAAEYUmxBRZa0/zKLr/8AAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOjon/pZyW6IyDfv+Ognz/kIR6/42DeP+AeHH/cmxo/29q + Zv9xbGj/eHNt/4yEfP9pYVf/sK+p/8DAt//AwLn/vr62/769tv+9vbX/vLy0/7q6s/+6urP/HXSW/zyW + t/91lp//t7ev/6+vqP+1s63/nZ2eagAAAAAeXHpANIOi/ymCpf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACNjIf/rqSe7YmBff9vamj/VFFQ/0A9 + PP9PTEn/XVlW/29oYP+Ad2v/iX5v/42Bcf9nX1P/sK+q/76+tv+9vbb/vLy0/7q6s/+5ubL/uLiy/7e4 + sf+3t7D/G3GT/yqEpf93l6H/tbWv/7OzrP+zs6z/vLm0dAAAAAAiYH09JXOS/yN9oP8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACNjIj/oJqX73hz + cP98dHD/gXdv/4l+b/+NgnP/jYJy/46DdP+Qhnr/kId9/5KJfP9oX1T/r62o/7q6tP+6urP/ubmy/7e3 + sf+2trD/tbWt/7W1r/+0s6z/EVx8/yqGp/9djqL/srKq/7Kyq/+xsan/p6ajgAAAAAAlZ4aEJXiY/xpx + lP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACMiof/vrKr8p2Tjf+Kgn7/d3Ft/2xoZP9jXlv/X1xZ/2djX/9vamX/eXRt/4yDev9oYFb/rKun/7e3 + sP+3trD/trWv/7W1rf+zs6z/srKq/7Kxq/+xsar/EFp5/yeAov8+ja7/rq+n/6+vp/+traX/paWgiAAA + AAAhaoz3JXyf/xlwk/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACKiYb/nZeT9mdjYP9oZGH/bWdj/3FqYf98c2f/g3lq/4Z8av+MgG//j4Jw/46B + b/9mXVL/q6qm/7O0rP+0tK3/s7Kr/7Gyq/+xsKn/r6+o/62vp/+trab/MHOS/xZkhP8viKr/X4ud/6uq + pP+qqqL/paSfjzB1mHoLUW//JXCO/yp8nv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACJiIX/u7Ku96Sak/+bjof/koV8/46Dd/+Lgnj/gHly/3l0 + bf98dXH/f3lz/4uDev9pYFb/qqql/7Kyqv+xsar/sLCo/7Cvp/+traf/rKyl/6uqpP+qqaT/g5id/wxX + d/8kc5L/KIKk/z94kP+Hl5n/Q3qT3BNgf/8NRFz/Gneb/yxykXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIiIT/v7mz95OOi/92cnD/X1xa/0VC + Qf9EQUD/VFBO/2FdWf9ybGf/hH1z/42Cdf9pYVf/qaml/6+vp/+vraf/rKym/6urpP+qqqP/qami/6io + oP+np5//p6eg/06JoP8ZdJX/NIut/zyQsP9LkKv/JIGk/w1Vcf8UYoL/NIam2zBykAUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACHh4T/k4+L+oN/ + fP+Gf3z/g3pz/4Z9b/+MgXL/jYFy/42Ccv+OgnL/joJz/4yAcP9lXVL/p6ai/6uspf+rq6T/qqqj/6mo + oP+op5//pqad/6Wlnv+lpZ3/o6Oc/6OjnP9biZv/MYWn/1ClxP9MmLb/H2iG/xVjhf8vfJ2nLnqcAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACGhYL/vbax/qykn/+QiYX/cm1q/2FdWf9lYF3/Y19d/2lmY/93c3D/hoJ+/5qUjP9xal//p6ai/6io + ov+oqaL/p6af/6amn/+kpJz/pKSc/6Kim/+goJr/oqCZ/5+emP+fnpj/n56Y/5+emP+cnJb/nJuYnQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACJiIX/hYF+/2lmY/9xb2n/gH95/46Mhf+joZn/uLar/8bEuP/OzMD/0M7A/9LR + w/+lpJn/pqWg/6amnv+mpp//pKSd/6SjnP+iopr/oJ+Z/5+fmf+dnZf/nJyU/5yclP+cm5P/m5uU/5ub + k/+ZmpP/mpmWpQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIh4T/29jH/9zYxf/U0cD/ysi4/8bEtf/Hxbb/x8S4/8bD + t//OzMD/zcu+/83Lvv+in5X/pqWf/6Ojm/+ko5v/oqKb/6Cgmf+enpj/nZ2W/5yclP+bm5P/mpuS/5qZ + kv+ZmJH/mZmR/5mZkf+Xl5D/mZmTqgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIh4P/8vDf/+fj0P/Z1sP/zsu7/8jF + t//Hxbb/zMq8/83Kvf/OzMD/y87B/9HPwv+joZb/oqCc/6Cgmf+gn5n/n5+Z/52dlv+cnJb/m5uU/5mZ + kf+ZmZH/mJiQ/5eXj/+XlpD/lpaP/5aWjv+Tk43/lpaRrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFhIH/8/Di/+zo + 1P/f28n/xsO2/7WzqP+jopn/m5qT/52blf+gn5j/pqSd/7azqf+Xk4j/oKCb/52dlv+enpf/nJyW/5ub + k/+ZmZH/mJiQ/5eXj/+Wlo//lJSN/5KTjP+Skov/kpKL/5OSjP+QkIn/k5OQsQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACEhID/xMG4/5mWjf92c3D/XVpZ/1FOTP9XUk//XllU/2plX/92cGj/hH1y/4uAc/9oYFf/n5+b/5yc + lP+bnJT/mpqT/5iXkP+Xlo//lpaO/5OTjP+Rkoz/kpKK/5CQiv+RkIn/kI+J/5CPif+NjYX/kpKPtQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACNjYr/t7Ot/7GtqP+vqaX/pp2U/5aLff+Og3L/j4Jw/4+Ccf+Qg3H/kYRy/4t/ + bP9lXVP/np6Z/5qZkv+amZL/mJeQ/5aUjv+UlI3/kpKL/5CQif+QkIn/jo6H/46Nhv+Ojob/jY2F/42N + hv+Li4P/kJCMuwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMjIj/zcrD/7m1sP+gnJn/j4qF/3x2cf9ybWj/b2ll/3Fs + Z/92cWz/gXp0/4uCd/9nX1b/nJuW/5iYkP+Yl5D/lpaO/5OSjP+Skov/kJCH/46Ph/+Ojob/jIyF/4uL + hP+Li4P/iouD/4qKgv+Hh4D/j46Lvo6NiwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKiob/mZaS/4eEgP+Gg4D/hYF9/4F8 + df98dWz/enNo/392a/+EfG//in9x/4uAcf9lXVP/nJuX/5aUjf+Wlo//k5OM/5CQiv+Qj4f/jo6G/4yM + hf+Li4P/iouD/4mJgf+Jh4D/iYmA/4eGf/+FhX3/jo2Kwo6MiwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKiof/29jQ/9DL + xP/Cvbb/s6yl/6qilP+ZjoD/j4V3/42Ddf+OhHf/j4V3/4uAcf9nX1T/m5qU/5SUjf+UlIz/kZGK/5CP + h/+Ojof/i4yE/4qKgv+JiYH/h4eA/4eHgP+Ghn//hYV+/4aFfv+Dg3r/jIyHxoyLiQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACKiYT/ycbA/62qpv+Sj4z/g4B9/3Jva/9oZWH/X1xa/2RgXf9vaWb/enVx/4uDef9nX1b/mpmT/5KS + jP+SkYv/kI+H/42Nhv+LjIT/ioqB/4mHgP+Hh4D/hoV//4WFfv+EhH3/g4N6/4ODfP+BgXj/i4uHzI2L + iQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACJiIT/p6Se/5+cmP+fm5f/oJyY/5mUjP+Si4D/i4F0/4Z8bP+HfW3/jYJy/4l9 + bP9lXlT/mJiS/5GQif+Pj4n/jo6G/4yMhP+LioL/iYeA/4aGf/+FhX7/hIR9/4ODev+Cgnr/goJ5/4KC + ef9/gHb/iYmE0YuKhwYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACHh4P/3tzV/9nWzf/QzMT/wr63/7CqoP+fl4v/kYl9/4d+ + cf+GfXD/in9x/4V5av9gWU//lpaP/4+Qh/+Oj4f/jIyE/4qLg/+JiYH/h4Z//4WFff+Dg3z/g4N6/4GB + ef+AgHf/gIF4/39/d/99fXT/h4aE1YuKiQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGhoH/sK2p/4aEgf90cnD/bWtp/2xq + aP9wbWr/dnRw/4J/eP+QjYX/m5eO/56Zi/9zb2X/k5OO/46Ohv+NjYX/iouD/4mJgf+Ghn//hIR9/4OE + fP+BgXn/gYF4/4B/dv9/f3b/fX51/319df96enP/hYWB2IqJhwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEhID/wcLA/8DB + vf/Hx8L/zMzE/87Nw//QzsD/0M29/9LNuv/Rzbn/0s65/9XPuv+dmY7/kpGM/42Nhf+MjIT/i4uD/4mH + gP+FhX7/g4N6/4KCev+AgHj/f393/35+dv99fXX/fX11/3p6c/95eXH/hYWB3YuKhwoAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACDgn7/9Pbw//L06//v8ub/6Onf/+Li2P/f3c//29jJ/9fSwP/W0L3/1c+8/9DLt/+cmIz/kZGM/42N + hP+LjIT/h4eB/4aGf/+FhX3/goJ6/4GBeP+AgHf/fn52/3x8dP98fHT/fHpz/3l6cv93eG//g4OA4YqJ + hwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACCgn7/8/Xt//L06//v8uf/6Org/+Tk2v/f3tH/29jK/9jTwv/W0L7/1c+8/9DL + tv+bl4v/kZCL/4uMhP+MjIT/iYmA/4aGf/+Dg3z/goJ6/4CAeP9/fnb/fX10/3x8dP96eXH/eXlx/3h4 + cP92dmz/goJ/5YmHhg0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCgX7/8/Tt//L07P/w8uj/6uzk/+Xl3f/g39X/3NrM/9rW + xf/X0sH/1c+9/9DKtv+al4v/kZCK/4uLhP+Li4P/h4eA/4aFfv+Dg3z/goJ6/39/d/9+fnb/fX11/3p8 + cv95eXD/eHhw/3h3b/90dGv/goJ+6YqHhg4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCgX3/8/Xt//L07P/y9Ov/7/Hn/+fp + 4P/i4tn/3dzP/9rXxv/X08L/1dC9/9DLtv+alor/kI+K/4yMhP+Ki4P/hoaA/4aFf/+Dg3r/gYF5/4B/ + d/9+fnb/fX11/3p6cv96eXH/eHhv/3Z2bf90dGr/goF+7IqHhhEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBgX3/8/bw//X3 + 8//t7+b/5eXb/+Pi1//m5Nr/5ePY/+Ddz//Z1sT/1tG//9DLt/+alon/kZGL/4uLg/+LjIT/h4eA/4aF + fv+Dg3r/goJ6/4CAeP9+fnb/fX10/3p8cv95eXH/eHhw/3d2b/91dGv/goF+74uJhxYAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACCgn7/7e/o/7Ssm/+imYL/oJmF/5eShv+YlIz/raqk/9DNxP/j4Nf/3tvN/9DMuf+bl4v/kJCL/4yM + hP+LjIP/iYmB/4aGf/+FhX3/g4N6/4CAd/9/f3f/fX10/3p6c/95enH/eHhx/3d3cP91dWz/goJ/8omH + hRsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACBgX7/kYdt/3RoRf9fW0v/SUdD/z4+Ov8+Pjr/QUE+/2NjYP+pqKX/4t7V/9nV + xv+dmY3/kI+K/4yMhP+Ki4P/iYmA/4aGfv+Dg3z/goJ5/4CAd/9+fXX/fX10/3l6cv94eHD/eHhv/3d2 + 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 + eP+SiX3/lox//5yRgv9qYlj/5OTg/9PUzP/T08n/vLy0/0vA6/9LwOv/Vsv1/1HF8P9Nwu3/Sr/q/2jW + //8/tOD/LKDN/yygzf8soM3/P7Tg/wF4pv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEvrT/wruw/7iw + pP+vppn/pp2P/6CVhv+ckYL/nJGC/2piWP/i4dz/zs/G/87Qxv+ysav/AXim/wF4pv9OfZf/Tn2X/059 + l/8BeKb/AXim/wF4pv9SepL/Tn2X/0dzj/8BeKb/AXim/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMW/ + tf+xq6L/oZuS/5CJgP+FfnX/g3xz/4J7c/+Jgnn/a2Ra/9/f2v/Ly8T/x8fA/8jIwf+3t6//np2a/1F8 + l/9kyOj/V3eQ/8/Ox/8AAAAAAAAAAEV1k/8zq9f/RHub/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAyMO5/3x4df94c2//gXt1/42FfP+Qh33/lox//5mPgf9pYlj/3NzY/8XGv//Cwrr/wsK6/8TE + vf/ExLz/U32Y/2XJ6P9WeJH/zMzE/wAAAAAAAAAARnSS/zOs2f8+epv/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADOysH/ycO4/764rP+1rKD/q6OV/6SajP+ek4T/nJGC/2liWP/Y2dT/wMC5/729 + tv+8vLT/urqz/7q6tP9TfZj/Zcno/1Z4kf/IyMD/AAAAAAAAAABGdJL/M6zZ/z56m/8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/Lwv+wrKP/mpSM/4uFfv+Efnb/fXdx/4J8dP+GgHn/a2Rb/9XW + 0v+8vLX/uLiy/7a2sP+2tq//tbSt/1aAmP9kyOb/XYOb/8XEvf8AAAAAAAAAAEiJqf80tOH/W36Y/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzsvE/3p3dP+Hg37/joiA/5ONhP+bkof/m5GE/5yR + gv9pYlj/0tLO/7i3sP+0tK3/srKq/7Gxqv+wsKn/YYSa/23H4/9tscn/dZmu/3uXqv9Zk67/NLHc/xCd + 2P9TfZjZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADSz8f/z8q//8a+tP+7tKj/sqmd/6mf + kv+imIn/m5GC/2liWf/Oz8r/s7Kr/6+wqP+traf/q6ul/6qqpP+XoqX/U32Y/2vD3/9zy+T/a8Ld/06w + 0v8Qndj/U32Y/3uXqmgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM7LxP+Oiob/dXNv/3Zz + bv91cWv/dnFs/4J+eP+RjYX/aWJZ/8vLx/+urqf/q6qj/6moof+np6D/pqae/6amnv+Un6L/ZIab/1Z4 + kv9Tdo//VHeR/1N9mNl7l6poAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz8zE/7Ov + qP/Hw7j/x8O3/83KvP/X1cf/0M7A/8jGuP9oYlj/x8fE/6qqov+npp7/paSc/6KjnP+ioZr/oJ+Z/6Cf + mf+fnpj/s7Kr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADSz8f/+PXl//Lv3//q6Nj/4t/R/9/czv/W1Mb/zcu9/2tkXP/Cwbz/paSd/6Oim/+gn5n/nZ6X/5qc + lP+bm5P/mpqT/5makv+urab/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANLPx//59ub/9PHi/+3q2//l4tP/39zO/9bUxv/Ny73/bGRc/769uf+goJn/np6X/5ub + lf+ampL/mJmQ/5eXkP+Wl4//lpaO/6moof8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA0s/H//n25v/28+P/8O3d/+jl1v/f3M7/1tTG/83Lvf9qZFv/vLy4/5yc + lf+amZL/l5eP/5aVjv+UlI3/kpKL/5KRiv+RkIj/paSc/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNysL/nJqU/4OBff+Fgn3/hoJ9/4eCff+Df3n/i4V+/2hi + Wf+8vbj/mpqR/5aVjv+UlIz/j5GK/4+PiP+OjYf/jo2G/4yMg/+gn5f/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/MxP+yr6r/vrmy/7ayqf+xqqH/raab/66l + mP+lnI7/aGJa/7q6tf+XlY//kpKL/5CQiP+Njob/jIyE/4qKg/+KioL/hoZ+/5ubk/8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0s/H/97a0v/W0cn/zce+/8S8 + sv+5sab/sKea/6edkP9qZFv/uLi0/5KSi/+Pj4f/jI2F/4qKgv+IiID/h4eA/4aFfv+Dg3v/mJeO/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNysL/mZeT/5SR + jv+MiIT/gn97/4iDfv+NiIH/kouD/2diW/+1tbL/kI+I/42Nhf+KioL/iIaA/4WFfv+EhHz/goJ6/4CB + dv+Tk4r/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/M + xP+yr6v/raqk/7Cspf+3saj/samf/6qimP+mnpL/ZmJa/7O0r/+NjYX/iouD/4iHgP+EhH3/g4N7/4GB + eP+AgXf/fX1z/5CPh/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA0s/H/+Tg2f/d2dD/1NDH/8vFu//Auq//t6+i/66kl/9rZmH/rq6q/4uLg/+Ih4D/hIR8/4CC + ev+AgHf/f352/319df95eXD/jYyE/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADSz8f/n5+f/46PjP+EhYL/gH97/4uIgP+Yk4r/nZmP/2ZkX/+srKb/ioqC/4aG + f/+Dg3v/gYF4/39+dv98fHT/e3tz/3V3bf+KiYH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAANLPx//n5+T/2dvU/93e1v/f3dL/2tbG/9vVw//MxrH/YWBb/6ur + pv+JiYH/hYV+/4KCe/9/f3f/fX11/3p7cv93d2//c3Np/4eGf/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0s/H//////////r/9vjw/+7u5P/i38//3NbC/8zH + sf9hX1r/q6um/4eIgf+Fg37/goJ5/39/d/99fXX/enpy/3l4cP9ycmj/h4Z+/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS0Mf/39zQ/7Wvm/+tqJv/s6+o/9XS + yP/r59n/0Mu3/2FgWf+rq6b/ioqC/4aEfv+Dg3n/gIB2/3x8c/94eXD/dXdv/3FxZ/+Hhn7/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANPQyP99cE7/U05D/0FA + Pf8+Pjz/aWln/9HOyv/c2Mj/ZGJc/6mrpf+Iin7/hYZ9/4CBeP97e3H/fHxy/3d4b/93d27/dHNp/4eG + fv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArquopq2q + o8Crqqm/r66sx6yrqtCpp6fYraup4rCtp+yXlZPtj46L34+QjdCNjYvBkJCNtKCgn6eVlJKdoJ+fk6Cf + noqXlpSEsK+vbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///AAf/hwAH+AEAB+AAAAfgA + AAH4AAAB+AAAAfgAAAH4AAAB+AAAx/gAAMf4AADH+AAAx/gAAAf4AAAH+AAAD/gAAP/4AAD/+AAA//gA + AP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP8oAAAAGAAAADAA + AAABACAAAAAAAGAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACclo0GZWJbTUVGRCwlJiUEAAAAAAF4pv8BeKb/AXim/wF4pv8BeKb/AXim/wF4pv8BeKb/AXim/wF4 + pv8AAAAAAAAAAAAAAAAAAAAAnJaNIJyWjUGclo1vnJaNqJyWjf+EeW/8XHJX/8HDv/EyMzJ5FxcYElDK + 9v9OyfX/Tcj0/2jj//9Fv+z/MKrY/zCq2P8ai7j/IpzK/wF4pv8AAAAAAAAAAAAAAACclo3/nJaN/5yW + jf9/eW3/g21j/w66LP8A/z7/Wmth//j18//p6OD/h4eBwiqj0v8ln83/JZ/N/z235P8alMP/GoKr/xqC + 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 + AADAPwAAwD8AAMA/AADAPwAA + + + \ No newline at end of file diff --git a/CustomAppsForm.Designer.cs b/CustomAppsForm.Designer.cs new file mode 100644 index 0000000..a270a76 --- /dev/null +++ b/CustomAppsForm.Designer.cs @@ -0,0 +1,248 @@ +namespace MeshCentralRouter +{ + partial class CustomAppsForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CustomAppsForm)); + this.cancelButton = new System.Windows.Forms.Button(); + this.okButton = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.removeButton = new System.Windows.Forms.Button(); + this.addButton = new System.Windows.Forms.Button(); + this.mainListView = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.appContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); + this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.runToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.addToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.groupBox1.SuspendLayout(); + this.appContextMenuStrip.SuspendLayout(); + this.SuspendLayout(); + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(320, 280); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(75, 23); + this.cancelButton.TabIndex = 0; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.Location = new System.Drawing.Point(239, 280); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 1; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(383, 48); + this.label1.TabIndex = 2; + this.label1.Text = "Setup custom applications that MeshCentral Router can open to use port mappings. " + + "These applications match a protocol and have a command line to open the applicat" + + "ion."; + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.removeButton); + this.groupBox1.Controls.Add(this.addButton); + this.groupBox1.Controls.Add(this.mainListView); + this.groupBox1.Location = new System.Drawing.Point(15, 60); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(380, 214); + this.groupBox1.TabIndex = 3; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Applications"; + // + // removeButton + // + this.removeButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.removeButton.Location = new System.Drawing.Point(299, 185); + this.removeButton.Name = "removeButton"; + this.removeButton.Size = new System.Drawing.Size(75, 23); + this.removeButton.TabIndex = 2; + this.removeButton.Text = "Remove"; + this.removeButton.UseVisualStyleBackColor = true; + this.removeButton.Click += new System.EventHandler(this.removeButton_Click); + // + // addButton + // + this.addButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.addButton.Location = new System.Drawing.Point(218, 185); + this.addButton.Name = "addButton"; + this.addButton.Size = new System.Drawing.Size(75, 23); + this.addButton.TabIndex = 1; + this.addButton.Text = "Add"; + this.addButton.UseVisualStyleBackColor = true; + this.addButton.Click += new System.EventHandler(this.addButton_Click); + // + // mainListView + // + this.mainListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.mainListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2, + this.columnHeader3}); + this.mainListView.ContextMenuStrip = this.appContextMenuStrip; + this.mainListView.FullRowSelect = true; + this.mainListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.mainListView.Location = new System.Drawing.Point(6, 19); + this.mainListView.Name = "mainListView"; + this.mainListView.Size = new System.Drawing.Size(368, 160); + this.mainListView.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.mainListView.TabIndex = 0; + this.mainListView.UseCompatibleStateImageBehavior = false; + this.mainListView.View = System.Windows.Forms.View.Details; + this.mainListView.SelectedIndexChanged += new System.EventHandler(this.mainListView_SelectedIndexChanged); + // + // columnHeader1 + // + this.columnHeader1.Text = "Name"; + // + // columnHeader2 + // + this.columnHeader2.Text = "Protocol"; + // + // columnHeader3 + // + this.columnHeader3.Text = "Command"; + this.columnHeader3.Width = 223; + // + // appContextMenuStrip + // + this.appContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.editToolStripMenuItem, + this.runToolStripMenuItem, + this.removeToolStripMenuItem, + this.toolStripMenuItem1, + this.addToolStripMenuItem}); + this.appContextMenuStrip.Name = "appContextMenuStrip"; + this.appContextMenuStrip.Size = new System.Drawing.Size(118, 98); + this.appContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.appContextMenuStrip_Opening); + // + // editToolStripMenuItem + // + this.editToolStripMenuItem.Name = "editToolStripMenuItem"; + this.editToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.editToolStripMenuItem.Text = "&Edit..."; + this.editToolStripMenuItem.Click += new System.EventHandler(this.editToolStripMenuItem_Click); + // + // runToolStripMenuItem + // + this.runToolStripMenuItem.Name = "runToolStripMenuItem"; + this.runToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.runToolStripMenuItem.Text = "R&un..."; + this.runToolStripMenuItem.Click += new System.EventHandler(this.runToolStripMenuItem_Click); + // + // removeToolStripMenuItem + // + this.removeToolStripMenuItem.Name = "removeToolStripMenuItem"; + this.removeToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.removeToolStripMenuItem.Text = "&Remove"; + this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeButton_Click); + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(114, 6); + // + // addToolStripMenuItem + // + this.addToolStripMenuItem.Name = "addToolStripMenuItem"; + this.addToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.addToolStripMenuItem.Text = "&Add..."; + this.addToolStripMenuItem.Click += new System.EventHandler(this.addButton_Click); + // + // CustomAppsForm + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(407, 315); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.label1); + this.Controls.Add(this.okButton); + this.Controls.Add(this.cancelButton); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CustomAppsForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Custom Applications"; + this.Load += new System.EventHandler(this.CustomAppsForm_Load); + this.groupBox1.ResumeLayout(false); + this.appContextMenuStrip.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button removeButton; + private System.Windows.Forms.Button addButton; + private System.Windows.Forms.ListView mainListView; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.ColumnHeader columnHeader3; + private System.Windows.Forms.ContextMenuStrip appContextMenuStrip; + private System.Windows.Forms.ToolStripMenuItem runToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem addToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; + } +} \ No newline at end of file diff --git a/CustomAppsForm.cs b/CustomAppsForm.cs new file mode 100644 index 0000000..ad08834 --- /dev/null +++ b/CustomAppsForm.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Diagnostics; + +namespace MeshCentralRouter +{ + public partial class CustomAppsForm : Form + { + List apps; + + public CustomAppsForm(List apps) + { + this.apps = apps; + InitializeComponent(); + } + + private void CustomAppsForm_Load(object sender, EventArgs e) + { + if (apps != null) { foreach (string[] app in apps) { mainListView.Items.Add(new ListViewItem(app)); } } + UpdateInfo(); + } + + public List getApplications() + { + List r = new List(); + foreach (ListViewItem l in mainListView.Items) + { + string[] x = new string[3]; + x[0] = l.SubItems[0].Text; + x[1] = l.SubItems[1].Text.ToLower(); + x[2] = l.SubItems[2].Text; + r.Add(x); + } + return r; + } + + private void addButton_Click(object sender, EventArgs e) + { + CustomAppsAddForm f = new CustomAppsAddForm(); + if (f.ShowDialog(this) == DialogResult.OK) + { + // Remove any matching protocol + List list = new List(); + foreach (ListViewItem l in mainListView.Items) { if (l.SubItems[1].Text.ToLower() == f.appProtocol.ToLower()) { list.Add(l); } } + foreach (ListViewItem l in list) { mainListView.Items.Remove(l); } + + // Add the new protocol + string[] x = new string[3]; + x[0] = f.appName; + x[1] = f.appProtocol.ToLower(); + x[2] = f.appCommand; + mainListView.Items.Add(new ListViewItem(x)); + } + } + + private void okButton_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + } + + private void cancelButton_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + } + + private void mainListView_SelectedIndexChanged(object sender, EventArgs e) + { + UpdateInfo(); + } + + private void UpdateInfo() + { + removeButton.Enabled = (mainListView.SelectedItems.Count > 0); + } + + private void removeButton_Click(object sender, EventArgs e) + { + if (mainListView.SelectedItems.Count == 0) return; + List list = new List(); + foreach (ListViewItem l in mainListView.SelectedItems) { list.Add(l); } + foreach (ListViewItem l in list) { mainListView.Items.Remove(l); } + } + + private void appContextMenuStrip_Opening(object sender, CancelEventArgs e) + { + runToolStripMenuItem.Visible = (mainListView.SelectedItems.Count == 1); + removeToolStripMenuItem.Visible = toolStripMenuItem1.Visible = (mainListView.SelectedItems.Count > 0); + } + + private void runToolStripMenuItem_Click(object sender, EventArgs e) + { + if (mainListView.SelectedItems.Count != 1) return; + ListViewItem i = mainListView.SelectedItems[0]; + CustomAppsRunForm f = new CustomAppsRunForm(i.SubItems[2].Text); + if (f.ShowDialog(this) == DialogResult.OK) { Process.Start(f.getFinalCommand()); } + } + + private void editToolStripMenuItem_Click(object sender, EventArgs e) + { + if (mainListView.SelectedItems.Count != 1) return; + ListViewItem i = mainListView.SelectedItems[0]; + CustomAppsAddForm f = new CustomAppsAddForm(); + f.appName = i.SubItems[0].Text; + f.appProtocol = i.SubItems[1].Text; + f.appCommand = i.SubItems[2].Text; + if (f.ShowDialog(this) == DialogResult.OK) + { + // Remove any matching protocol + List list = new List(); + foreach (ListViewItem l in mainListView.Items) { if (l.SubItems[1].Text.ToLower() == f.appProtocol.ToLower()) { list.Add(l); } } + foreach (ListViewItem l in list) { mainListView.Items.Remove(l); } + + // Add the new protocol + string[] x = new string[3]; + x[0] = f.appName; + x[1] = f.appProtocol.ToLower(); + x[2] = f.appCommand; + mainListView.Items.Add(new ListViewItem(x)); + } + + } + } +} diff --git a/CustomAppsForm.resx b/CustomAppsForm.resx new file mode 100644 index 0000000..a6c337a --- /dev/null +++ b/CustomAppsForm.resx @@ -0,0 +1,1818 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + AAABAA0AMDAQAAEABABoBgAA1gAAACAgEAABAAQA6AIAAD4HAAAYGBAAAQAEAOgBAAAmCgAAEBAQAAEA + BAAoAQAADgwAADAwAAABAAgAqA4AADYNAAAgIAAAAQAIAKgIAADeGwAAGBgAAAEACADIBgAAhiQAABAQ + AAABAAgAaAUAAE4rAAAAAAAAAQAgAPgWAQC2MAAAMDAAAAEAIACoJQAArkcBACAgAAABACAAqBAAAFZt + AQAYGAAAAQAgAIgJAAD+fQEAEBAAAAEAIABoBAAAhocBACgAAAAwAAAAYAAAAAEABAAAAAAAgAQAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD/ + /wD/AAAA/wD/AP//AAD///8AAAAAAAAAAAAAAAAAAAAAAAczEwNwAAAAAAAAAAAAAAAId3cAAAAAAzc4 + N7gzAAAAAAAAAAAACHd3d4hwAABzeIt7c4tzcAAAAAAAAAh3d3d6p4j4cAN7iLeTOTiYcAAAAAAACHd3 + d3d4t3+Ih3OLeDODg4t7cAAAAAAAB3d3eHh4doj4+Ie3v4s5M4t7gAAAAAAAB3eHhnZ2d4iPiIOIeDl7 + c4iTAAAAAAAAB4d2VlZ3dYiI+Ie5v4t4O5t3gAAAAAAAB4ZXd3d3doj4iIOIiLczl4g7gAAAAAAAB4d3 + ZyV3d4iI+Ie7iIOLe4txAAAAAAAAB4dhdXd3doiIiIOIj7OXM3sbAAAAAAAAB3d3d2dndYiPiIOIuIuL + iJhzAAAAAAAAB4dlY3V3doiIiIi4e3e3k3M3AAAAAAAAB4d3d3d3d3iIiINzgTd7c4cAAAAAAAAAB4d3 + ZWdndoiIiIiDg4iAAIMAAAAAAAAAB3dDd3d3dYiIiIiDt4eAADsAAAAAAAAAB4d3dnV3doiIiIiDd4iA + AHMAAAAAAAAAB4d0NDZ3d3iIiIiDOIeAADkAAAAAAAAAB4Z3d3d3doiIiIeDeYiICDcAAAAAAAAAB4d3 + dldndXiHh4iDN4eIAzMAAAAAAAAAB4d0d3d3doiIiHh3M3iIA3kAAAAAAAAAB4d3d3d3d3h4eIeHMzN3 + MTAAAAAAAAAAB4d2FkNndniHh4h4c3ezE4AAAAAAAAAAB3d3d3d3dYeIeHh4d7lzdwAAAAAAAAAAB4h3 + Z3V3doh4eH54eHiIAAAAAAAAAAAAB3dnd4iIiHh4h4eHh4d4AAAAAAAAAAAAB4iIiIiIiHh3h4d4d3h4 + AAAAAAAAAAAAB/+IiIiIiHh4d3h3h3eIAAAAAAAAAAAAB/j4h4eIhoeHh4eHeHd4AAAAAAAAAAAAB4dn + R2dnd3d4d3d3d3h4AAAAAAAAAAAAB4iHd3d3Z3h3h4aHh3d4AAAAAAAAAAAAB4h3d3Z3dXh3d3h3d3d4 + AAAAAAAAAAAAB3d3d3d3doeHhod3d4Z4AAAAAAAAAAAAB/iId3d3dnd3eHd3d3d4AAAAAAAAAAAAB4h3 + dnR2dYd4d3d3d3d4AAAAAAAAAAAAB4eHd3d3d3d3d3d353d3AAAAAAAAAAAAB4+Ih3d3dnh3d4aHd3d4 + AAAAAAAAAAAAB4dnZ3d3d3d3hnd3d3doAAAAAAAAAAAAB4iIiIiIiHeHd3d3dnd3AAAAAAAAAAAAB/// + +IiIh3d3d3d3d3d3AAAAAAAAAAAAB/j4+PiIiHd3d3d2d3Z3AAAAAAAAAAAAB//4+I+Ijnh3d3d3d3d3 + AAAAAAAAAAAAB/j/j4iIh3d3d3Z3d2d3AAAAAAAAAAAAB/+Pj4+IiHd3d3d3Z3d3AAAAAAAAAAAAB/eH + d4iIh4d4aHd3d3d3AAAAAAAAAAAAB3ZmZCeIiGh3d2d3d3ZXAAAAAAAAAAAAB3h3d4eIiHd3d3d3d3d3 + AAAAAAAAAAAAAIiPiIiIh4iIiIAAAAAAAAAAAAAA/////4B/AAD//4P+AD8AAP/4AfAAHwAA/4AAYAAf + AAD+AAAAAB8AAP4AAAAAHwAA/gAAAAA/AAD+AAAAAB8AAP4AAAAAHwAA/gAAAAA/AAD+AAAAAD8AAP4A + AAAAPwAA/gAAAAA/AAD+AAAAAP8AAP4AAAAc/wAA/gAAABz/AAD+AAAAHP8AAP4AAAAc/wAA/gAAAAj/ + AAD+AAAACP8AAP4AAAAI/wAA/gAAAAH/AAD+AAAAAf8AAP4AAAAD/wAA/gAAAA//AAD+AAAAD/8AAP4A + AAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA// + AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP4A + AAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP8AAB///wAAKAAAACAA + AABAAAAAAQAEAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIAAAACAgACAAAAAgACAAICA + AACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP///wAAAAAAAAAAAAAzMzMzMzMwAAAAAAAA + AAAAuLe4t7m4kAAAAAAIh3eHAHubObMzMzAAAAh3d3o2/4C3uLiLe5swAAAIeHd4t4/4e3k7k5NzMAAA + CIh4d3b4j7e4uLizuDAAAAh3dnd3j4h7e5ezOTOQAAAIdnd3dviIt7i4uLe4MAAACIiHh4eIiDlzeTlz + eTAAAAh3d3Z2+IiIe3gAe3AAAAAId3d3dYiIiHg4ADeQAAAACIiHh4b4iIg4OAB7cAAAAAiHd2d3iIiI + e3gAe3AAAAAId3eHdoiHh3iHg7lwAAAACIiIeHeIiHhzi4e3AAAAAAh3Z2d2iHh4h3OXcAAAAAAIiIiI + hYh4h4eIAAAAAAAACP+PiIeHh3h3hwAAAAAAAAj/j4+GiHh3h3gAAAAAAAAI+PiIh4eHd3h4AAAAAAAA + CHd3d3aHd4d3dwAAAAAAAAiIiIh3h4d3d3gAAAAAAAAI+Ijnhod3d4Z3AAAAAAAACHd3d3eHeHZ3eAAA + AAAAAAiIiIeEh3d3d3cAAAAAAAAI+IiId4d3d3d3AAAAAAAACId2d4aHd3d3dwAAAAAAAAj4+PiGh3d2 + d2cAAAAAAAAI//+Ih3d3d3d3AAAAAAAACIh4j4aHd3d3dwAAAAAAAAh2QniHd3d3Z3cAAAAAAAAIiIiI + h4h4iIiAAAAAAP//wAH//8AB/4DAAfgAQAH4AAAB+AAAAfgAAAH4AAAB+AAAAfgAAMf4AADH+AAAx/gA + AMf4AAAH+AAAD/gAAB/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gA + AP/4AAD/+AAA//gAAP/4AAH/KAAAABgAAAAwAAAAAQAEAAAAAAAgAQAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP// + /wAAAAAAAAADMzMzMzAAAACHd4ALi4t7mzAAd3dyp/iDubOTczAAiHh3to/4uIuLOTAAiHd3d/iDk7M5 + NzAAiHeHd4iLi4t7OzAAiId3d/iDc3k3dTAAh3d4Z4iIe3ADtwAAiIh3eIiIeDAHlwAAiHfnd4iIODAH + twAAiIh4d4h4e4eLNwAAiGd3h4h4d4t5eAAAiPj4hoeHdzc4gAAAiP+Ih4eHh4AAAAAAiIiIh4d3eHAA + AAAAiId3d4eHd3AAAAAAiIiIdod3d3AAAAAAiHhod4d3d3AAAAAAiIiId3d3d3AAAAAAiId4d4d3Z3AA + AAAAj4+IhoZ3d3AAAAAAj/j4h3d3d3AAAAAAiGdoh4d3dnAAAAAAiIeIh4eIiIAAAAD/+AEA/BgBAMAA + AQDAAAEAwAABAMAAAQDAAAEAwABjAMAAYwDAAGMAwAADAMAAAwDAAAcAwAB/AMAAfwDAAH8AwAB/AMAA + fwDAAH8AwAB/AMAAfwDAAH8AwAB/AMAAfwAoAAAAEAAAACAAAAABAAQAAAAAAIAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A + /wD//wAA////AAB3d3MzMzMwAIeHiLi3uTAAiHhzt5M7MACIiIi4u3eQAIeHgzsXmzAAiIiIdwA3AACI + johzADcAAIiIh3e3NwAAh3Z3d3NwAACP/4+HAAAAAI+Pj/cAAAAAh3d3dwAAAACP+PiHAAAAAI//j4gA + AAAAiGYGiAAAAACIiIh4AAAAwAEAAMABAADAAQAAwAEAAMABAADAMwAAwDMAAMADAADABwAAwD8AAMA/ + AADAPwAAwD8AAMA/AADAPwAAwD8AACgAAAAwAAAAYAAAAAEACAAAAAAAAAkAAAAAAAAAAAAAAAEAAAAB + AAAAAAAAPj46AEA9PABBQT4ADDtRAA9BVQANRFwADUhgAABIagAYSWAAC1FvAB1UbwAHVnYAElt6ACZP + YgATYH8AM2J2AEhFQwBRTk0AV1NNAFVSUQBZVVIAXFhVAF5bWQBgWU8AZV5VAHRoRQBpYFUAZWFdAGtk + WwBxal8AZWNgAGllYgBuaWQAbWpoAHJsZwB6cWYAdXNrAHp0awB3eG8AeHhvAHVzcAB8dXAAe3tzAHx8 + egCFe2wAg3tzAIl/cQCCf3oAin95AH+AdgAO8U4ADexdAI2AbwCRh20AgIB3AI2BcwCDg3wAi4J7AJCE + cgCQhXsAk4l8AJmOfwAKX4EAE2KEAB9ohgASZ4kAFWmLABdukQAUcpUAG3KVABx3mgAcep4AIGeFACdu + jwAlcI4AJXOTACF3mgAkepsAKXyeADFzkAA8d5IAP3iQACR+oABId4wAW3WCACWAowArg6QAJoesAC6I + qgAyhKQAMYeoADOKqwA5jKwANI6yADqPsQAskroANJCzAD2StAA9mbsAXYqcAHiDhwBhhpcAZomYAHaU + nQB/kpwAToqiAFyNoQBLkKsAXZGmAEKUtQBBmLcASpi2AEGWuABEmrsAUZq3AHSWowBUoL8Ac6C1AH2n + uAB2qb4AZ/S4AEKdwQBKn8AARqHEAEyixABNqcoAUKXFAF2pxgBTqssAWK3OAE+u0ABYr9EAUrPXAFux + 0QBbtdgAWbncAGGqxwBgrswAca7FAHO0zQBgtdUAbbXRAGO41gBjutoAarzcAHK61QA98tUAc8DeAGbE + 5QBtwuIAccXlAHzG4AB2yOcAe8rmAHTK6QB6yukAhoWAAImGgQCLi4MAjo2JAJKLgwCajoQAkI6KAI+Q + hwCTkYYAnpOFAJOSjACblYsAnZiMAIWXmwCVlZEAmZaQAJqakwCTnJwAnp2YAKCThwCgmYQAoZaNAKWf + jwChnZcAo6GWAKqilACjo5wAqqOeALSsmwCNo6oAmqWmAI6wvgCZsbYAq6qkALGqowCwragAqbCtALOy + qwC5tasAqrW2ALW1sQC7tbEAt7ixALu7tACwvLoAvby7AMG1rwDBvLYAtsG/AMXEugDRzLkA1dC9AI6w + wACcvcsAtcfPAITO6gCP0+wAmtftAJrY7QCD1fQAkNv3AKjd8gCU4fwAoeL7ALfl9wC55fUAs+r9AMXF + wgDJxsAAzMvDAMTOygDNzMoA0M3FANTRwgDZ1cQA29jGANPTywDY1s0A29nMANLR0ADb29IA4N3PAOHe + 1QDf4NcA5OHUAOzo1ADk49oA6OnfAPLw3wDC6/sAzvH/AOfp4ADq7OIA7e/oAO/x5gDy8+oA6/v/APT2 + 8QD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdlELCQQFB2kAAAAAAAAAAAAAAAAA + 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 + TgBkYVsAaWJYAGpkWgBsZVsAa2RcAGxkXABrZmEAaWlnAG1qZgBxcWcAcnJoAHRxaQB1cm0AdnduAHhz + bwB6dG0Ad3hvAHt3cgB5eXEAfnhxAHx8cgB8eHUAfX11AIF7cwCDfHMAgXt1AIJ8dACEfnUAgX55AIR/ + eAAAzEYAE+5RAICAdgCBgnkAhoB5AIGBfgCGgn0AhYV9AImCeACIg34Ai4V+AI2FfQCIin4AkYd7AJCH + fQCQiX0AlYl+AJaMfwA+epsAAXimAEdzjwBTdo8ARXSSAE59lwBEe5sAVXeQAFJ6kgBWeJEAUXyXAFN9 + mABbfpgAF4y5AByRvgBWgJgAXYObAGKFmgBIiakAWZOuAGyQpwB7l6oAdZmuACzTuABV0pwAEJ3YACCV + wgAil8QAJJnGACmdygArn8wALKDNADCk0QAzp9QAM6vXADWq1gAzrNkAOa7aADSx3AA7sNwANLThAD+0 + 4ABOsNIAbbHJAEO45ABFuuUAR7znAEm+6QBrwt4AS8DrAEzB7ABRxfAAVsv1AF7T/QBtx+MAZMjmAGTI + 6ABzy+QAYNX/AGTV/wBo1v8AhYaBAIiGgACHiIEAiYmBAI2IgQCMjIMAjYmFAI2NhQCOj4oAkYqBAJGN + hQCYjoAAn4+FAJCPiACPkYoAm5GCAJyRggCbkYUAnZKEAJOTjACYlIwAnZmPAJeXkACZl5MAmpqTAJ6d + mgCglYYAopiJAKSajAClnI4AoZqSAKadkQChnpYAqZ+SAKCfmQCpoJIAqaGVAK6klwChoJoAoqOcAKWl + nQCqopgAraWZAK2omwCwp5oAta+bALGpnQCUn6IAl6KlAKWloQCrqqQArq6qALGqoQCwrKMAtq2hALCs + pQCyr6kAr7CoALiwpQCxsaoAtrGoALCwrgC1s60As7SvALW1rgC7tKgAvrisALW0sgC4t7AAubmyAL65 + sgC5ubQAvLy0ALy8uQDAuq8AwLqwAMS8sgDDvrcAxb60AMC/vADHw7cAzMaxAMHBuQDGwbkAwsG8AMTE + vQDJxLoAzcq9ANDLtwDExMEAyMfHAMjIwADNysEAysnGAM7LxADOzMQAzM3KANHOxgDQzskAztDGANXS + xgDb1cMA09HIANXRyADS0s4A09TMANfXzwDe28wA1dbSANjY0ADd2tEA29zSAN/c0QDY2tQA3d7WAN3d + 2QDi388A4t/RAOXi0wDo5dYA5ODZAOXm2wDi4dwA5uXcAOvn2QDr6dkA8e7eAOXl4ADn5+QA6erkAOrs + 5gDu7uQA9fLiAPj15QDw8eoA9vjxAPv58AD///cA///6AP///wAAAAAAAAAAAAAAAAAAAAAAAAA4ODg4 + ODg4ODg4ODg4AAAAAAAAAAAAAAAAAAAAAAAAAGhoZmRkZGxgVlZWYDgAAAAAAAAAAAAAx556NAT6KgAA + WFhTU1JRWkQ4ODhFOAAAAAAAAMGYMjI0gCUmCvv9mgBoaGhmZGRxYFZWVmA4AAAAAAAAwXqShYV/T04K + 9e/971hYVlVVU1xEODg4RTgAAAAAAAC+taKYj4WFNAj14uHWaGhqaGZmcWBWVlZgOAAAAAAAAMGSMBoW + EhotCvPh3sdYWFhXVlVeRDg4OEU4AAAAAAAAvg8WIS00f4AI793dvGhoa2poaHNgVlZWYDgAAAAAAADB + vrWekY6EhAjv09evODg8PDw4ODhAQDs4OAAAAAAAAMGokn0hISEtCufTz8+vmkFvQNMAADtbPQAAAAAA + AAAAxBoVITAyNIQI4s/Dx8/HQW9A0wAAO1s3AAAAAAAAAADTxL6omJGOhAjhw7y8u7xBb0DPAAA7WzcA + AAAAAAAAANOoiDAhISEhCuG8u7uvt0ZuR8cAAElfQwAAAAAAAAAA0xV1en2FhYUK3Luvr6+vSG1iTUxK + XVBLAAAAAAAAAADa0MG1opWPhQjWr6+tpqakQWdwZ2FQQQAAAAAAAAAAANN9FRYVFSF9CNOnpqWlpaWk + SEA6QEsAAAAAAAAAAAAA06zHxMrZ08oIz6aapaWUlJSWrwAAAAAAAAAAAAAAAADQ+fjx6OHZyg3DmqWU + lJSMjIymAAAAAAAAAAAAAAAAAN35+PHo6NjLDbyalIyMioqKiqYAAAAAAAAAAAAAAAAA0Pn48uvh2csN + vJSMioqHgoKBmgAAAAAAAAAAAAAAAADQjC4qMCoqNAi8jIqCgoKCeoKUAAAAAAAAAAAAAAAAANCvwa+o + opiRCLuKgoGCNDF6LIkAAAAAAAAAAAAAAAAA3eLaxMK1oJcKu4KCeiwxMSosigAAAAAAAAAAAAAAAADT + i4h6KTAwfQi3gnqCLDEqKieHAAAAAAAAAAAAAAAAANOspqisqJ6SCLd6MSwsKicnG4EAAAAAAAAAAAAA + AAAA2uzi2sTBqKANrzF6LCgbKhsbggAAAAAAAAAAAAAAAADQm3wuKjCIiQinMSwqKicbGxQsAAAAAAAA + AAAAAAAAANr05+fi2dnFBacxLigbGxsUFSwAAAAAAAAAAAAAAAAA2v//+vro2cUFpjEuKCgbGxkRLAAA + AAAAAAAAAAAAAADQ6KKirNnvzAWnMS4oKBsZFBEsAAAAAAAAAAAAAAAAAN0GAwIBDtrZCKYxMSgZGxQU + FCwAAAAAAAAAAAAAAAAA0cHBw723t7eNo6WlscPDz9bPAAAAAAAAAAAA///AAf//wAH/gMAB+ABAAfgA + AAH4AAAB+AAAAfgAAAH4AAAB+AAAx/gAAMf4AADH+AAAx/gAAAf4AAAP+AAAH/gAAP/4AAD/+AAA//gA + AP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAf8oAAAAGAAAADAA + AAABAAgAAAAAAEACAAAAAAAAAAAAAAABAAAAAQAAAAAAAGNfWABcclcAa2VeAFprYQBycmkAc3FtAHV1 + bQB5eG4Af3ltAHp6cQB6enQAfn51AINtYwCCemUAg3pvAIF7cgCFenAAg310AIR9dACBfngAhH94AA66 + LAAA/z4AgIB3AIGBeQCFgnkAhIR7AIWBfQCFhH0AiYF5AIiEewCNhXkAiIF8AImFfQCOh34AiIh+AI6I + fwCRh3oAlYt7AJCJfQAaYoMAGmiKABpxlgAadp0APnqbAAF4pgAaeKAAR3OPAEV0kgBOfZcARHubAFV3 + kABSepIAVniRAFF8lwBTfZgAW36YABqCqwAahK0AGoq1ABqLuAAajboAVoCYAFmAmABdg5sASImpAFmT + rgBgh6AAe5agAHWZrgAA1LIAQ8mLABqUwwAQndgAIpzKACSezAAqo9IALabVADOr1wAwqtgAM6zZADSx + 3AA0tOEAPbfkAE6w0gBtsckAQrzpAEW/7ABrw98ARsDtAEjC7wBNyPQAUMr2AG3H4wBkyOYAZMjoAHPL + 5ABn4v8AaOP/AI2HgACJiYEAjYiCAI6JhQCNjIUAkIqCAJGMhQCVjocAkY+IAJuQgQCRkYkAl5CIAJWR + jgCVlY0AmpOJAJyTiACclIkAnJaNAJiYjwCfmY8Am5eRAJiYkQCamZYAnJqWAJ2dlgCdnpgAnZycAKWP + hQCli48AoJaJAKGYiwChm48ApZuOAKadjwCgkZAAoZqQAKSbkACinZIApJ+ZAKqhlwChoJoApKObAKKi + ngClpZ4Ar6edAICbpQCjo6MApqagAKmnoQCqqaMArqmgAKqqpACtraYAra2qALGqoQC1raIAsq2lALCv + qwCvsKkAr7OtALizogCxsKgAtrCoALS0qwCzsqwAtbStALy2qwC4tK4Av7esALOxsAC2tbEAubmyAL26 + sgC+u7UAvr62ALm5uAC9vbkAxL6pAMS+rQDAurEAxL2zAMO+tADEv7UAwL+9AMbAtgDDw7sAxsK4AMfE + ugDDw7wAxMO9AMXFvADLxbsAysW8AMzHvQDPyrkAyci9AM3LvwDRzbwArcjVAMTGwgDKx8AAysjBAM3K + wgDJycQAy8zEAM7PyQDQzcAA0M3EANTPyADP0MoA09DHANPRyQDU1c0A2NTJAN/czgDT1dEA19XRANnZ + 0gDb29YA4N3PAObY0ADt2tMA5OHVAOvm0wDg4NoA5OPbAOfn3wDq6N0A5+bhAOno4ADs7OIA9vTjAP7+ + 7gD49fMA+fjzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAuLi4uLi4uLi4uAAAA + AAAAAKx1EQLHAABdXFxjWFBQPUsuAAAAdXV1CQ0WFwTp5Y5NS0xUSTo6KiwuAAAAs4p1g39IRwPh5eVa + WltiWE1QPUsuAAAAs5xpEREfEWbh2aw9PD1NOi8vKSwuAAAAwJZpd4mDbSXZ1KVaWltjWE1QPUsuAAAA + urOciSggDyDZzK4uMjIyLi41MjAuAAAAwJwfZGl1JiDXuse6N2A2AAAxTzMAAAAAuMCmkIltIGTNsKur + N2A1AAAxUC0AAAAAuqVkaWt1IB/LqqWlP19BAABCUzkAAAAAuLqlnIuDKB+6npaYP15WRkNSSkQAAAAA + uqZkIGSGgCCwl5eOkTdZYVVKN8YAAAAAs83Z2dzDnhyrjn19d5E1NjVExgAAAAAAs97o593DnyCqd313 + eXF9AAAAAAAAAAAAuNXc1MW6nxyYeXlxcXFxAAAAAAAAAAAAuKVxbGtrIByWeXFoaBxxAAAAAAAAAAAA + s9LSwKacbR+ScWhoHGhoAAAAAAAAAAAAwKx3eWZrZByOaB8dGwwkAAAAAAAAAAAAwMy3t7ObghF9aBsb + GwsfAAAAAAAAAAAAzMCdiniJdRl9HxsbCwsMAAAAAAAAAAAAz9jX1MPFoAt9HxsLCwcLAAAAAAAAAAAA + 0uTp5ePfsQt9HxkLCwcLAAAAAAAAAAAA1LEOAQfIxQt3HQsLBwUHAAAAAAAAAAAA1KyUkn2qrHeSkp6q + r7C6AAAAAAAAAP/4AQD8GAEAwAABAMAAAQDAAAEAwAABAMAAAQDAAGMAwABjAMAAYwDAAAMAwAADAMAA + BwDAAH8AwAB/AMAAfwDAAH8AwAB/AMAAfwDAAH8AwAB/AMAAfwDAAH8AwAB/ACgAAAAQAAAAIAAAAAEA + CAAAAAAAAAEAAAAAAAAAAAAAAAEAAAABAAAAAAAAMzMxAFxOJgB3cWoAeHJpAHhzbwB9dm4Ah31uAIJ7 + cgCFfnYAiH9yAIF/egCKgXYAjIN3AI+EdQCOhnwAlIl6AJqPfwAad58AAXimABZ9pAAaeKAATXCKAE5y + jABKdI8AX3aEAFh+lwAagqsAHoOoABqErQAai7gAGo26ADmdvQBuhZQARJKsAEmftgBQobcAGpTDACWf + zQAqo9IALabVADCq2AA9t+QAQrzpAEW/7ABGwO0ASMLvAE3I9ABQyvYAZ+L/AGjj/wCKhoEAlIyDAJ+W + hgCmnI0Aop6YAKqhkwCto5YAraSXAKqimACwp5kAsqiaALSqmwCzqpwAtqyeALSsogC4r6EAtrCmALqw + ogC8s6UAvbSmALqzqgC/tqgAu7WtALy3rwC/urMAwbepAMK5qwDEuqwAxr2vAMG8twDIvrAAwb24AMnB + sgDEwLsAxsO/ANPNuQDGw8AAyMbCAMrIxgDMysgA4NvKAOHcywDk384A6OXUAOrn2gDs6N0A7ergAO7s + 4ADw7eMA9fPpAPX16gD29OwA+PfuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + GJoAAAAwDUhjJCBnhf9Yr9H/YbnZ/2bE5f+x6Pv/YarH/zKJqv8tg6T/HHSV/xVpiv8KX4H/QJK0/16z + 0v84jq//UrPX/zFkfa4AAAA9AAAAOgAAACkAAAAXAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABzcW6BdWtiwouAef+Ngnz/i4B3/46Edv+Vi33/l4x9/5OJff9+dXD/Z/S4/z3y1f9rY1j/sK2o/93d + 1f/d3dX/5OPa/9PSy/9dXlzYBxsjikaWtv9wxub/XLLS/0ypyv+a1+3/XKrH/zSLrP9Albb/R5y9/0ec + vf9BmLf/c8De/3rL6v9Fm7z/Joes/xpOZaoAAAA8AAAANwAAACcAAAAbAAAADQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACEg3//fXRu44p/ef+ViYP/louC/5OIe/+Zjn//n5OE/56Thf+flon/nI6F/6CT + h/9pYFT/sa+q/9vc0//b29L/29rR/93d1f/n5tv/mKSl/DqRsv9Ppcb/WbDQ/3DE5P/O8f//bbXR/0CY + uf86j7H/LoSl/yR5m/8SZ4n/QZm6/1KoyP8vhab/Wrjc/z96kpYAAAAgAAAAIAAAABIAAAAJAAAABwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFhID/g3pzyZOIgv+dkYr/oZaN/56Vi/+Ignv/ZmJe/1xZ + V/9nZGH/fHZx/5KLgv9vZlv/srGr/9vb0f/Z2tH/2dnR/9jYz//Y2M//xM7K/ziOr/9swuH/ab7f/1y1 + 2P+o3fL/VKC//yd/oP8yh6n/NImq/zeMrv82i67/brzZ/3rK6f8pgKH/FXSX/2WmwmkAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjor/kIR7s4+Ff/94cW3/amZl/1ZT + VP9EQkL/T0tI/2tlXf9+dWr/i4Bw/5GFcv9oX1P/tLOt/9jZ0P/Y187/19bO/9fWzf/S0cr/nKam/0Wa + vf9Yrc7/WKzO/2m/3f/C7Pz/dLvV/0ujxP9TqMr/S6HC/z+Vtv8vhKX/Vq3N/2C11f9Blrj/QJ3C/z5+ + mIMAAAANAAAACgAAAAQAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjor/hn15tVJP + T/9dWVf/enJs/4J4a/+LgHH/joN0/5SMgP+PiYD/hoB6/42GgP9tZlz/tLKr/9XVzP/V1c3/1dPL/9XV + zP/R0cr/sLy6/zKKq/90yun/gdPy/4/T7P/D6vr/Up68/yR8nv8nfJ3/Inma/x1zlv8edJf/YK7M/2m5 + 2P8Vao3/MY6y/0mGoYcAAAAQAAAAHwAAABMAAAAJAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACQjon/kIR+u4R5dP+QhH7/iYB6/3BqZf9fXFn/WFRS/1tYVP9rZmH/eXNr/4uDeP9qYVf/s7Gs/9LT + y//T08v/0tLK/9HSyv/MzMT/lZ+e/1Cmxv9tw+L/YLna/1i63f+35ff/cbrV/0qiw/9Vqsv/VarL/1Gm + x/9Oo8T/esnm/3bI5/8/lbb/E3CU/3q51WQAAAAAAAAAAwAAAAcAAAAFAAAAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACPjor/loyDxHVva/9WUlD/SUVE/1ZRTv9yamT/iX9y/4uAcf+Og3T/j4R2/5KH + ef9pYFT/s7Gs/9HRyf/Q0Mn/0NDH/8/Pxv/MzcT/ucK//y6Jqv9wxub/hM7q/7nl9f/r+///XqjF/zGJ + q/8xh6j/KH2e/x91lv8hd5r/S6LE/1SrzP8XbpH/NJCz/6jh+mEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjor/koiCy3Zva/+HfXf/jIF4/5CHfv98dnH/ZGBd/19c + Wv9hXlz/c29q/4yEff9rY1j/s7Gr/87Oxv/Ozsb/zM3E/83NxP/Gxr//kZqb/z2Zu/+Q2/f/oeL7/5Th + /P+27f//fcvn/1Srzf9nu9r/bsPj/3XK6v9juNb/OIyr/0+kw/9Opcf/HHqe/4e/2GUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjon/nJCJz352cf9pZGP/W1hW/1RR + T/9dWVT/aGFb/3hwZv+Eemv/jYFv/4+CcP9nXlP/srGr/83MxP/Ly8P/ysrC/8nKwf/Hx8H/qrW2/2q+ + 3/+G1/f/c7TN/0+LpP9JmLf/XrfY/1WrzP9Zr8//U6jJ/0uixP8FWHn/W3WC/yZPYv8fd5n/PpW3/4i/ + 1mwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOjon/k42H1nNs + af9/dXH/hnpz/4uAcP+Pg3P/j4N0/5KKf/+QiYD/jIV//5SNhP9oYFT/srGr/8nJwf/KycH/x8fB/8bG + v//Fxr//tMC//zePsv87kLL/Flx6/32nuP8ASGr/MIms/z+Vtv9Kn8D/VKrL/zyStf8AV3n/tcfP/12R + pv8FWHkoAExvLG2kvAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACOjon/p5uS3ZGFf/+LgXz/d3Ft/2ZhXv9dWlj/WldU/19cWf9taWT/fXVv/4yDef9pYFb/s7Ks/8bG + v//Gxr//xcW+/8TEvP/Dw7r/wsK6/8LBuv+Zsbb/M4Wl/3zG4P8ydJD/jaOq/6mwrf+qqaX5X2BgVwAA + AAwPQ1tHca7F/z+QsP8AAAAGAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACPjor/npWP4mhkYf9RTUz/WVRR/2VeWf99dGj/iX5t/46Ccf+QhHP/kIRz/5GF + dP9oYFb/srGr/8PDvP/Cw7z/wsG5/8DBuf/AwLj/wMC3/76+t/+9vbf/Inia/1Otz/93k5v/nZyY/52c + mP+9vbX9uLm6bQAAAAEYUmxBRZa0/zKLr/8AAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOjon/pZyW6IyDfv+Ognz/kIR6/42DeP+AeHH/cmxo/29q + Zv9xbGj/eHNt/4yEfP9pYVf/sK+p/8DAt//AwLn/vr62/769tv+9vbX/vLy0/7q6s/+6urP/HXSW/zyW + t/91lp//t7ev/6+vqP+1s63/nZ2eagAAAAAeXHpANIOi/ymCpf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACNjIf/rqSe7YmBff9vamj/VFFQ/0A9 + PP9PTEn/XVlW/29oYP+Ad2v/iX5v/42Bcf9nX1P/sK+q/76+tv+9vbb/vLy0/7q6s/+5ubL/uLiy/7e4 + sf+3t7D/G3GT/yqEpf93l6H/tbWv/7OzrP+zs6z/vLm0dAAAAAAiYH09JXOS/yN9oP8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACNjIj/oJqX73hz + cP98dHD/gXdv/4l+b/+NgnP/jYJy/46DdP+Qhnr/kId9/5KJfP9oX1T/r62o/7q6tP+6urP/ubmy/7e3 + sf+2trD/tbWt/7W1r/+0s6z/EVx8/yqGp/9djqL/srKq/7Kyq/+xsan/p6ajgAAAAAAlZ4aEJXiY/xpx + lP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACMiof/vrKr8p2Tjf+Kgn7/d3Ft/2xoZP9jXlv/X1xZ/2djX/9vamX/eXRt/4yDev9oYFb/rKun/7e3 + sP+3trD/trWv/7W1rf+zs6z/srKq/7Kxq/+xsar/EFp5/yeAov8+ja7/rq+n/6+vp/+traX/paWgiAAA + AAAhaoz3JXyf/xlwk/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACKiYb/nZeT9mdjYP9oZGH/bWdj/3FqYf98c2f/g3lq/4Z8av+MgG//j4Jw/46B + b/9mXVL/q6qm/7O0rP+0tK3/s7Kr/7Gyq/+xsKn/r6+o/62vp/+trab/MHOS/xZkhP8viKr/X4ud/6uq + pP+qqqL/paSfjzB1mHoLUW//JXCO/yp8nv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACJiIX/u7Ku96Sak/+bjof/koV8/46Dd/+Lgnj/gHly/3l0 + bf98dXH/f3lz/4uDev9pYFb/qqql/7Kyqv+xsar/sLCo/7Cvp/+traf/rKyl/6uqpP+qqaT/g5id/wxX + d/8kc5L/KIKk/z94kP+Hl5n/Q3qT3BNgf/8NRFz/Gneb/yxykXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIiIT/v7mz95OOi/92cnD/X1xa/0VC + Qf9EQUD/VFBO/2FdWf9ybGf/hH1z/42Cdf9pYVf/qaml/6+vp/+vraf/rKym/6urpP+qqqP/qami/6io + oP+np5//p6eg/06JoP8ZdJX/NIut/zyQsP9LkKv/JIGk/w1Vcf8UYoL/NIam2zBykAUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACHh4T/k4+L+oN/ + fP+Gf3z/g3pz/4Z9b/+MgXL/jYFy/42Ccv+OgnL/joJz/4yAcP9lXVL/p6ai/6uspf+rq6T/qqqj/6mo + oP+op5//pqad/6Wlnv+lpZ3/o6Oc/6OjnP9biZv/MYWn/1ClxP9MmLb/H2iG/xVjhf8vfJ2nLnqcAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACGhYL/vbax/qykn/+QiYX/cm1q/2FdWf9lYF3/Y19d/2lmY/93c3D/hoJ+/5qUjP9xal//p6ai/6io + ov+oqaL/p6af/6amn/+kpJz/pKSc/6Kim/+goJr/oqCZ/5+emP+fnpj/n56Y/5+emP+cnJb/nJuYnQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACJiIX/hYF+/2lmY/9xb2n/gH95/46Mhf+joZn/uLar/8bEuP/OzMD/0M7A/9LR + w/+lpJn/pqWg/6amnv+mpp//pKSd/6SjnP+iopr/oJ+Z/5+fmf+dnZf/nJyU/5yclP+cm5P/m5uU/5ub + k/+ZmpP/mpmWpQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIh4T/29jH/9zYxf/U0cD/ysi4/8bEtf/Hxbb/x8S4/8bD + t//OzMD/zcu+/83Lvv+in5X/pqWf/6Ojm/+ko5v/oqKb/6Cgmf+enpj/nZ2W/5yclP+bm5P/mpuS/5qZ + kv+ZmJH/mZmR/5mZkf+Xl5D/mZmTqgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIh4P/8vDf/+fj0P/Z1sP/zsu7/8jF + t//Hxbb/zMq8/83Kvf/OzMD/y87B/9HPwv+joZb/oqCc/6Cgmf+gn5n/n5+Z/52dlv+cnJb/m5uU/5mZ + kf+ZmZH/mJiQ/5eXj/+XlpD/lpaP/5aWjv+Tk43/lpaRrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFhIH/8/Di/+zo + 1P/f28n/xsO2/7WzqP+jopn/m5qT/52blf+gn5j/pqSd/7azqf+Xk4j/oKCb/52dlv+enpf/nJyW/5ub + k/+ZmZH/mJiQ/5eXj/+Wlo//lJSN/5KTjP+Skov/kpKL/5OSjP+QkIn/k5OQsQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACEhID/xMG4/5mWjf92c3D/XVpZ/1FOTP9XUk//XllU/2plX/92cGj/hH1y/4uAc/9oYFf/n5+b/5yc + lP+bnJT/mpqT/5iXkP+Xlo//lpaO/5OTjP+Rkoz/kpKK/5CQiv+RkIn/kI+J/5CPif+NjYX/kpKPtQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACNjYr/t7Ot/7GtqP+vqaX/pp2U/5aLff+Og3L/j4Jw/4+Ccf+Qg3H/kYRy/4t/ + bP9lXVP/np6Z/5qZkv+amZL/mJeQ/5aUjv+UlI3/kpKL/5CQif+QkIn/jo6H/46Nhv+Ojob/jY2F/42N + hv+Li4P/kJCMuwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMjIj/zcrD/7m1sP+gnJn/j4qF/3x2cf9ybWj/b2ll/3Fs + Z/92cWz/gXp0/4uCd/9nX1b/nJuW/5iYkP+Yl5D/lpaO/5OSjP+Skov/kJCH/46Ph/+Ojob/jIyF/4uL + hP+Li4P/iouD/4qKgv+Hh4D/j46Lvo6NiwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKiob/mZaS/4eEgP+Gg4D/hYF9/4F8 + df98dWz/enNo/392a/+EfG//in9x/4uAcf9lXVP/nJuX/5aUjf+Wlo//k5OM/5CQiv+Qj4f/jo6G/4yM + hf+Li4P/iouD/4mJgf+Jh4D/iYmA/4eGf/+FhX3/jo2Kwo6MiwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKiof/29jQ/9DL + xP/Cvbb/s6yl/6qilP+ZjoD/j4V3/42Ddf+OhHf/j4V3/4uAcf9nX1T/m5qU/5SUjf+UlIz/kZGK/5CP + h/+Ojof/i4yE/4qKgv+JiYH/h4eA/4eHgP+Ghn//hYV+/4aFfv+Dg3r/jIyHxoyLiQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACKiYT/ycbA/62qpv+Sj4z/g4B9/3Jva/9oZWH/X1xa/2RgXf9vaWb/enVx/4uDef9nX1b/mpmT/5KS + jP+SkYv/kI+H/42Nhv+LjIT/ioqB/4mHgP+Hh4D/hoV//4WFfv+EhH3/g4N6/4ODfP+BgXj/i4uHzI2L + iQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACJiIT/p6Se/5+cmP+fm5f/oJyY/5mUjP+Si4D/i4F0/4Z8bP+HfW3/jYJy/4l9 + bP9lXlT/mJiS/5GQif+Pj4n/jo6G/4yMhP+LioL/iYeA/4aGf/+FhX7/hIR9/4ODev+Cgnr/goJ5/4KC + ef9/gHb/iYmE0YuKhwYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACHh4P/3tzV/9nWzf/QzMT/wr63/7CqoP+fl4v/kYl9/4d+ + cf+GfXD/in9x/4V5av9gWU//lpaP/4+Qh/+Oj4f/jIyE/4qLg/+JiYH/h4Z//4WFff+Dg3z/g4N6/4GB + ef+AgHf/gIF4/39/d/99fXT/h4aE1YuKiQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGhoH/sK2p/4aEgf90cnD/bWtp/2xq + aP9wbWr/dnRw/4J/eP+QjYX/m5eO/56Zi/9zb2X/k5OO/46Ohv+NjYX/iouD/4mJgf+Ghn//hIR9/4OE + fP+BgXn/gYF4/4B/dv9/f3b/fX51/319df96enP/hYWB2IqJhwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEhID/wcLA/8DB + vf/Hx8L/zMzE/87Nw//QzsD/0M29/9LNuv/Rzbn/0s65/9XPuv+dmY7/kpGM/42Nhf+MjIT/i4uD/4mH + gP+FhX7/g4N6/4KCev+AgHj/f393/35+dv99fXX/fX11/3p6c/95eXH/hYWB3YuKhwoAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACDgn7/9Pbw//L06//v8ub/6Onf/+Li2P/f3c//29jJ/9fSwP/W0L3/1c+8/9DLt/+cmIz/kZGM/42N + hP+LjIT/h4eB/4aGf/+FhX3/goJ6/4GBeP+AgHf/fn52/3x8dP98fHT/fHpz/3l6cv93eG//g4OA4YqJ + hwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACCgn7/8/Xt//L06//v8uf/6Org/+Tk2v/f3tH/29jK/9jTwv/W0L7/1c+8/9DL + tv+bl4v/kZCL/4uMhP+MjIT/iYmA/4aGf/+Dg3z/goJ6/4CAeP9/fnb/fX10/3x8dP96eXH/eXlx/3h4 + cP92dmz/goJ/5YmHhg0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCgX7/8/Tt//L07P/w8uj/6uzk/+Xl3f/g39X/3NrM/9rW + xf/X0sH/1c+9/9DKtv+al4v/kZCK/4uLhP+Li4P/h4eA/4aFfv+Dg3z/goJ6/39/d/9+fnb/fX11/3p8 + cv95eXD/eHhw/3h3b/90dGv/goJ+6YqHhg4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCgX3/8/Xt//L07P/y9Ov/7/Hn/+fp + 4P/i4tn/3dzP/9rXxv/X08L/1dC9/9DLtv+alor/kI+K/4yMhP+Ki4P/hoaA/4aFf/+Dg3r/gYF5/4B/ + d/9+fnb/fX11/3p6cv96eXH/eHhv/3Z2bf90dGr/goF+7IqHhhEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBgX3/8/bw//X3 + 8//t7+b/5eXb/+Pi1//m5Nr/5ePY/+Ddz//Z1sT/1tG//9DLt/+alon/kZGL/4uLg/+LjIT/h4eA/4aF + fv+Dg3r/goJ6/4CAeP9+fnb/fX10/3p8cv95eXH/eHhw/3d2b/91dGv/goF+74uJhxYAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACCgn7/7e/o/7Ssm/+imYL/oJmF/5eShv+YlIz/raqk/9DNxP/j4Nf/3tvN/9DMuf+bl4v/kJCL/4yM + hP+LjIP/iYmB/4aGf/+FhX3/g4N6/4CAd/9/f3f/fX10/3p6c/95enH/eHhx/3d3cP91dWz/goJ/8omH + hRsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACBgX7/kYdt/3RoRf9fW0v/SUdD/z4+Ov8+Pjr/QUE+/2NjYP+pqKX/4t7V/9nV + xv+dmY3/kI+K/4yMhP+Ki4P/iYmA/4aGfv+Dg3z/goJ5/4CAd/9+fXX/fX10/3l6cv94eHD/eHhv/3d2 + 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 + eP+SiX3/lox//5yRgv9qYlj/5OTg/9PUzP/T08n/vLy0/0vA6/9LwOv/Vsv1/1HF8P9Nwu3/Sr/q/2jW + //8/tOD/LKDN/yygzf8soM3/P7Tg/wF4pv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEvrT/wruw/7iw + pP+vppn/pp2P/6CVhv+ckYL/nJGC/2piWP/i4dz/zs/G/87Qxv+ysav/AXim/wF4pv9OfZf/Tn2X/059 + l/8BeKb/AXim/wF4pv9SepL/Tn2X/0dzj/8BeKb/AXim/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMW/ + tf+xq6L/oZuS/5CJgP+FfnX/g3xz/4J7c/+Jgnn/a2Ra/9/f2v/Ly8T/x8fA/8jIwf+3t6//np2a/1F8 + l/9kyOj/V3eQ/8/Ox/8AAAAAAAAAAEV1k/8zq9f/RHub/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAyMO5/3x4df94c2//gXt1/42FfP+Qh33/lox//5mPgf9pYlj/3NzY/8XGv//Cwrr/wsK6/8TE + vf/ExLz/U32Y/2XJ6P9WeJH/zMzE/wAAAAAAAAAARnSS/zOs2f8+epv/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADOysH/ycO4/764rP+1rKD/q6OV/6SajP+ek4T/nJGC/2liWP/Y2dT/wMC5/729 + tv+8vLT/urqz/7q6tP9TfZj/Zcno/1Z4kf/IyMD/AAAAAAAAAABGdJL/M6zZ/z56m/8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/Lwv+wrKP/mpSM/4uFfv+Efnb/fXdx/4J8dP+GgHn/a2Rb/9XW + 0v+8vLX/uLiy/7a2sP+2tq//tbSt/1aAmP9kyOb/XYOb/8XEvf8AAAAAAAAAAEiJqf80tOH/W36Y/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzsvE/3p3dP+Hg37/joiA/5ONhP+bkof/m5GE/5yR + gv9pYlj/0tLO/7i3sP+0tK3/srKq/7Gxqv+wsKn/YYSa/23H4/9tscn/dZmu/3uXqv9Zk67/NLHc/xCd + 2P9TfZjZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADSz8f/z8q//8a+tP+7tKj/sqmd/6mf + kv+imIn/m5GC/2liWf/Oz8r/s7Kr/6+wqP+traf/q6ul/6qqpP+XoqX/U32Y/2vD3/9zy+T/a8Ld/06w + 0v8Qndj/U32Y/3uXqmgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM7LxP+Oiob/dXNv/3Zz + bv91cWv/dnFs/4J+eP+RjYX/aWJZ/8vLx/+urqf/q6qj/6moof+np6D/pqae/6amnv+Un6L/ZIab/1Z4 + kv9Tdo//VHeR/1N9mNl7l6poAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz8zE/7Ov + qP/Hw7j/x8O3/83KvP/X1cf/0M7A/8jGuP9oYlj/x8fE/6qqov+npp7/paSc/6KjnP+ioZr/oJ+Z/6Cf + mf+fnpj/s7Kr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADSz8f/+PXl//Lv3//q6Nj/4t/R/9/czv/W1Mb/zcu9/2tkXP/Cwbz/paSd/6Oim/+gn5n/nZ6X/5qc + lP+bm5P/mpqT/5makv+urab/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANLPx//59ub/9PHi/+3q2//l4tP/39zO/9bUxv/Ny73/bGRc/769uf+goJn/np6X/5ub + lf+ampL/mJmQ/5eXkP+Wl4//lpaO/6moof8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA0s/H//n25v/28+P/8O3d/+jl1v/f3M7/1tTG/83Lvf9qZFv/vLy4/5yc + lf+amZL/l5eP/5aVjv+UlI3/kpKL/5KRiv+RkIj/paSc/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNysL/nJqU/4OBff+Fgn3/hoJ9/4eCff+Df3n/i4V+/2hi + Wf+8vbj/mpqR/5aVjv+UlIz/j5GK/4+PiP+OjYf/jo2G/4yMg/+gn5f/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/MxP+yr6r/vrmy/7ayqf+xqqH/raab/66l + mP+lnI7/aGJa/7q6tf+XlY//kpKL/5CQiP+Njob/jIyE/4qKg/+KioL/hoZ+/5ubk/8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0s/H/97a0v/W0cn/zce+/8S8 + sv+5sab/sKea/6edkP9qZFv/uLi0/5KSi/+Pj4f/jI2F/4qKgv+IiID/h4eA/4aFfv+Dg3v/mJeO/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNysL/mZeT/5SR + jv+MiIT/gn97/4iDfv+NiIH/kouD/2diW/+1tbL/kI+I/42Nhf+KioL/iIaA/4WFfv+EhHz/goJ6/4CB + dv+Tk4r/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/M + xP+yr6v/raqk/7Cspf+3saj/samf/6qimP+mnpL/ZmJa/7O0r/+NjYX/iouD/4iHgP+EhH3/g4N7/4GB + eP+AgXf/fX1z/5CPh/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA0s/H/+Tg2f/d2dD/1NDH/8vFu//Auq//t6+i/66kl/9rZmH/rq6q/4uLg/+Ih4D/hIR8/4CC + ev+AgHf/f352/319df95eXD/jYyE/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADSz8f/n5+f/46PjP+EhYL/gH97/4uIgP+Yk4r/nZmP/2ZkX/+srKb/ioqC/4aG + f/+Dg3v/gYF4/39+dv98fHT/e3tz/3V3bf+KiYH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAANLPx//n5+T/2dvU/93e1v/f3dL/2tbG/9vVw//MxrH/YWBb/6ur + pv+JiYH/hYV+/4KCe/9/f3f/fX11/3p7cv93d2//c3Np/4eGf/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0s/H//////////r/9vjw/+7u5P/i38//3NbC/8zH + sf9hX1r/q6um/4eIgf+Fg37/goJ5/39/d/99fXX/enpy/3l4cP9ycmj/h4Z+/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS0Mf/39zQ/7Wvm/+tqJv/s6+o/9XS + yP/r59n/0Mu3/2FgWf+rq6b/ioqC/4aEfv+Dg3n/gIB2/3x8c/94eXD/dXdv/3FxZ/+Hhn7/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANPQyP99cE7/U05D/0FA + Pf8+Pjz/aWln/9HOyv/c2Mj/ZGJc/6mrpf+Iin7/hYZ9/4CBeP97e3H/fHxy/3d4b/93d27/dHNp/4eG + fv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArquopq2q + o8Crqqm/r66sx6yrqtCpp6fYraup4rCtp+yXlZPtj46L34+QjdCNjYvBkJCNtKCgn6eVlJKdoJ+fk6Cf + noqXlpSEsK+vbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///AAf/hwAH+AEAB+AAAAfgA + AAH4AAAB+AAAAfgAAAH4AAAB+AAAx/gAAMf4AADH+AAAx/gAAAf4AAAH+AAAD/gAAP/4AAD/+AAA//gA + AP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP8oAAAAGAAAADAA + AAABACAAAAAAAGAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACclo0GZWJbTUVGRCwlJiUEAAAAAAF4pv8BeKb/AXim/wF4pv8BeKb/AXim/wF4pv8BeKb/AXim/wF4 + pv8AAAAAAAAAAAAAAAAAAAAAnJaNIJyWjUGclo1vnJaNqJyWjf+EeW/8XHJX/8HDv/EyMzJ5FxcYElDK + 9v9OyfX/Tcj0/2jj//9Fv+z/MKrY/zCq2P8ai7j/IpzK/wF4pv8AAAAAAAAAAAAAAACclo3/nJaN/5yW + jf9/eW3/g21j/w66LP8A/z7/Wmth//j18//p6OD/h4eBwiqj0v8ln83/JZ/N/z235P8alMP/GoKr/xqC + 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 + AADAPwAAwD8AAMA/AADAPwAA + + + \ No newline at end of file diff --git a/CustomAppsRunForm.Designer.cs b/CustomAppsRunForm.Designer.cs new file mode 100644 index 0000000..5d4bd43 --- /dev/null +++ b/CustomAppsRunForm.Designer.cs @@ -0,0 +1,192 @@ +namespace MeshCentralRouter +{ + partial class CustomAppsRunForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CustomAppsRunForm)); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.portTextBox = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.addressTextBox = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.commandTextBox = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.okButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.portTextBox); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.addressTextBox); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.commandTextBox); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Location = new System.Drawing.Point(12, 49); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(382, 101); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Application Command Line"; + // + // portTextBox + // + this.portTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.portTextBox.Location = new System.Drawing.Point(116, 71); + this.portTextBox.Name = "portTextBox"; + this.portTextBox.Size = new System.Drawing.Size(260, 20); + this.portTextBox.TabIndex = 13; + this.portTextBox.Text = "1234"; + this.portTextBox.TextChanged += new System.EventHandler(this.portTextBox_TextChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(6, 74); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(26, 13); + this.label4.TabIndex = 12; + this.label4.Text = "Port"; + // + // addressTextBox + // + this.addressTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.addressTextBox.Location = new System.Drawing.Point(116, 45); + this.addressTextBox.Name = "addressTextBox"; + this.addressTextBox.Size = new System.Drawing.Size(260, 20); + this.addressTextBox.TabIndex = 11; + this.addressTextBox.Text = "127.0.0.1"; + this.addressTextBox.TextChanged += new System.EventHandler(this.addressTextBox_TextChanged); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 48); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(45, 13); + this.label3.TabIndex = 10; + this.label3.Text = "Address"; + // + // commandTextBox + // + this.commandTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.commandTextBox.Location = new System.Drawing.Point(116, 19); + this.commandTextBox.Name = "commandTextBox"; + this.commandTextBox.ReadOnly = true; + this.commandTextBox.Size = new System.Drawing.Size(260, 20); + this.commandTextBox.TabIndex = 9; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 22); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(54, 13); + this.label2.TabIndex = 8; + this.label2.Text = "Command"; + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.Location = new System.Drawing.Point(238, 156); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 3; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(319, 156); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(75, 23); + this.cancelButton.TabIndex = 2; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label1.Location = new System.Drawing.Point(12, 11); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(382, 35); + this.label1.TabIndex = 4; + this.label1.Text = "Test that the application runs correctly by specifying and address and port and c" + + "lick ok to run the application."; + // + // CustomAppsRunForm + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(406, 191); + this.Controls.Add(this.label1); + this.Controls.Add(this.okButton); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.groupBox1); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CustomAppsRunForm"; + this.Text = "Test Application"; + this.Load += new System.EventHandler(this.CustomAppsRunForm_Load); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox portTextBox; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox addressTextBox; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox commandTextBox; + private System.Windows.Forms.Label label2; + } +} \ No newline at end of file diff --git a/CustomAppsRunForm.cs b/CustomAppsRunForm.cs new file mode 100644 index 0000000..a3862a2 --- /dev/null +++ b/CustomAppsRunForm.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace MeshCentralRouter +{ + public partial class CustomAppsRunForm : Form + { + private string command = null; + + public CustomAppsRunForm(string command) + { + this.command = command; + InitializeComponent(); + } + + public string getFinalCommand() + { + return command.Replace("%L", addressTextBox.Text).Replace("%P", portTextBox.Text); + } + + public void UpdateInfo() + { + commandTextBox.Text = getFinalCommand(); + } + + private void addressTextBox_TextChanged(object sender, EventArgs e) + { + UpdateInfo(); + } + + private void portTextBox_TextChanged(object sender, EventArgs e) + { + UpdateInfo(); + } + + private void CustomAppsRunForm_Load(object sender, EventArgs e) + { + UpdateInfo(); + } + + private void okButton_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + } + + private void cancelButton_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + } + } +} diff --git a/CustomAppsRunForm.resx b/CustomAppsRunForm.resx new file mode 100644 index 0000000..b93e49a --- /dev/null +++ b/CustomAppsRunForm.resx @@ -0,0 +1,1815 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAA0AMDAQAAEABABoBgAA1gAAACAgEAABAAQA6AIAAD4HAAAYGBAAAQAEAOgBAAAmCgAAEBAQAAEA + BAAoAQAADgwAADAwAAABAAgAqA4AADYNAAAgIAAAAQAIAKgIAADeGwAAGBgAAAEACADIBgAAhiQAABAQ + AAABAAgAaAUAAE4rAAAAAAAAAQAgAPgWAQC2MAAAMDAAAAEAIACoJQAArkcBACAgAAABACAAqBAAAFZt + AQAYGAAAAQAgAIgJAAD+fQEAEBAAAAEAIABoBAAAhocBACgAAAAwAAAAYAAAAAEABAAAAAAAgAQAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD/ + /wD/AAAA/wD/AP//AAD///8AAAAAAAAAAAAAAAAAAAAAAAczEwNwAAAAAAAAAAAAAAAId3cAAAAAAzc4 + N7gzAAAAAAAAAAAACHd3d4hwAABzeIt7c4tzcAAAAAAAAAh3d3d6p4j4cAN7iLeTOTiYcAAAAAAACHd3 + d3d4t3+Ih3OLeDODg4t7cAAAAAAAB3d3eHh4doj4+Ie3v4s5M4t7gAAAAAAAB3eHhnZ2d4iPiIOIeDl7 + c4iTAAAAAAAAB4d2VlZ3dYiI+Ie5v4t4O5t3gAAAAAAAB4ZXd3d3doj4iIOIiLczl4g7gAAAAAAAB4d3 + ZyV3d4iI+Ie7iIOLe4txAAAAAAAAB4dhdXd3doiIiIOIj7OXM3sbAAAAAAAAB3d3d2dndYiPiIOIuIuL + iJhzAAAAAAAAB4dlY3V3doiIiIi4e3e3k3M3AAAAAAAAB4d3d3d3d3iIiINzgTd7c4cAAAAAAAAAB4d3 + ZWdndoiIiIiDg4iAAIMAAAAAAAAAB3dDd3d3dYiIiIiDt4eAADsAAAAAAAAAB4d3dnV3doiIiIiDd4iA + AHMAAAAAAAAAB4d0NDZ3d3iIiIiDOIeAADkAAAAAAAAAB4Z3d3d3doiIiIeDeYiICDcAAAAAAAAAB4d3 + dldndXiHh4iDN4eIAzMAAAAAAAAAB4d0d3d3doiIiHh3M3iIA3kAAAAAAAAAB4d3d3d3d3h4eIeHMzN3 + MTAAAAAAAAAAB4d2FkNndniHh4h4c3ezE4AAAAAAAAAAB3d3d3d3dYeIeHh4d7lzdwAAAAAAAAAAB4h3 + Z3V3doh4eH54eHiIAAAAAAAAAAAAB3dnd4iIiHh4h4eHh4d4AAAAAAAAAAAAB4iIiIiIiHh3h4d4d3h4 + AAAAAAAAAAAAB/+IiIiIiHh4d3h3h3eIAAAAAAAAAAAAB/j4h4eIhoeHh4eHeHd4AAAAAAAAAAAAB4dn + R2dnd3d4d3d3d3h4AAAAAAAAAAAAB4iHd3d3Z3h3h4aHh3d4AAAAAAAAAAAAB4h3d3Z3dXh3d3h3d3d4 + AAAAAAAAAAAAB3d3d3d3doeHhod3d4Z4AAAAAAAAAAAAB/iId3d3dnd3eHd3d3d4AAAAAAAAAAAAB4h3 + dnR2dYd4d3d3d3d4AAAAAAAAAAAAB4eHd3d3d3d3d3d353d3AAAAAAAAAAAAB4+Ih3d3dnh3d4aHd3d4 + AAAAAAAAAAAAB4dnZ3d3d3d3hnd3d3doAAAAAAAAAAAAB4iIiIiIiHeHd3d3dnd3AAAAAAAAAAAAB/// + +IiIh3d3d3d3d3d3AAAAAAAAAAAAB/j4+PiIiHd3d3d2d3Z3AAAAAAAAAAAAB//4+I+Ijnh3d3d3d3d3 + AAAAAAAAAAAAB/j/j4iIh3d3d3Z3d2d3AAAAAAAAAAAAB/+Pj4+IiHd3d3d3Z3d3AAAAAAAAAAAAB/eH + d4iIh4d4aHd3d3d3AAAAAAAAAAAAB3ZmZCeIiGh3d2d3d3ZXAAAAAAAAAAAAB3h3d4eIiHd3d3d3d3d3 + AAAAAAAAAAAAAIiPiIiIh4iIiIAAAAAAAAAAAAAA/////4B/AAD//4P+AD8AAP/4AfAAHwAA/4AAYAAf + AAD+AAAAAB8AAP4AAAAAHwAA/gAAAAA/AAD+AAAAAB8AAP4AAAAAHwAA/gAAAAA/AAD+AAAAAD8AAP4A + AAAAPwAA/gAAAAA/AAD+AAAAAP8AAP4AAAAc/wAA/gAAABz/AAD+AAAAHP8AAP4AAAAc/wAA/gAAAAj/ + AAD+AAAACP8AAP4AAAAI/wAA/gAAAAH/AAD+AAAAAf8AAP4AAAAD/wAA/gAAAA//AAD+AAAAD/8AAP4A + AAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA// + AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP4A + AAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP8AAB///wAAKAAAACAA + AABAAAAAAQAEAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIAAAACAgACAAAAAgACAAICA + AACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP///wAAAAAAAAAAAAAzMzMzMzMwAAAAAAAA + AAAAuLe4t7m4kAAAAAAIh3eHAHubObMzMzAAAAh3d3o2/4C3uLiLe5swAAAIeHd4t4/4e3k7k5NzMAAA + CIh4d3b4j7e4uLizuDAAAAh3dnd3j4h7e5ezOTOQAAAIdnd3dviIt7i4uLe4MAAACIiHh4eIiDlzeTlz + eTAAAAh3d3Z2+IiIe3gAe3AAAAAId3d3dYiIiHg4ADeQAAAACIiHh4b4iIg4OAB7cAAAAAiHd2d3iIiI + e3gAe3AAAAAId3eHdoiHh3iHg7lwAAAACIiIeHeIiHhzi4e3AAAAAAh3Z2d2iHh4h3OXcAAAAAAIiIiI + hYh4h4eIAAAAAAAACP+PiIeHh3h3hwAAAAAAAAj/j4+GiHh3h3gAAAAAAAAI+PiIh4eHd3h4AAAAAAAA + CHd3d3aHd4d3dwAAAAAAAAiIiIh3h4d3d3gAAAAAAAAI+Ijnhod3d4Z3AAAAAAAACHd3d3eHeHZ3eAAA + AAAAAAiIiIeEh3d3d3cAAAAAAAAI+IiId4d3d3d3AAAAAAAACId2d4aHd3d3dwAAAAAAAAj4+PiGh3d2 + d2cAAAAAAAAI//+Ih3d3d3d3AAAAAAAACIh4j4aHd3d3dwAAAAAAAAh2QniHd3d3Z3cAAAAAAAAIiIiI + h4h4iIiAAAAAAP//wAH//8AB/4DAAfgAQAH4AAAB+AAAAfgAAAH4AAAB+AAAAfgAAMf4AADH+AAAx/gA + AMf4AAAH+AAAD/gAAB/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gA + AP/4AAD/+AAA//gAAP/4AAH/KAAAABgAAAAwAAAAAQAEAAAAAAAgAQAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP// + /wAAAAAAAAADMzMzMzAAAACHd4ALi4t7mzAAd3dyp/iDubOTczAAiHh3to/4uIuLOTAAiHd3d/iDk7M5 + NzAAiHeHd4iLi4t7OzAAiId3d/iDc3k3dTAAh3d4Z4iIe3ADtwAAiIh3eIiIeDAHlwAAiHfnd4iIODAH + twAAiIh4d4h4e4eLNwAAiGd3h4h4d4t5eAAAiPj4hoeHdzc4gAAAiP+Ih4eHh4AAAAAAiIiIh4d3eHAA + AAAAiId3d4eHd3AAAAAAiIiIdod3d3AAAAAAiHhod4d3d3AAAAAAiIiId3d3d3AAAAAAiId4d4d3Z3AA + AAAAj4+IhoZ3d3AAAAAAj/j4h3d3d3AAAAAAiGdoh4d3dnAAAAAAiIeIh4eIiIAAAAD/+AEA/BgBAMAA + AQDAAAEAwAABAMAAAQDAAAEAwABjAMAAYwDAAGMAwAADAMAAAwDAAAcAwAB/AMAAfwDAAH8AwAB/AMAA + fwDAAH8AwAB/AMAAfwDAAH8AwAB/AMAAfwAoAAAAEAAAACAAAAABAAQAAAAAAIAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A + /wD//wAA////AAB3d3MzMzMwAIeHiLi3uTAAiHhzt5M7MACIiIi4u3eQAIeHgzsXmzAAiIiIdwA3AACI + johzADcAAIiIh3e3NwAAh3Z3d3NwAACP/4+HAAAAAI+Pj/cAAAAAh3d3dwAAAACP+PiHAAAAAI//j4gA + AAAAiGYGiAAAAACIiIh4AAAAwAEAAMABAADAAQAAwAEAAMABAADAMwAAwDMAAMADAADABwAAwD8AAMA/ + AADAPwAAwD8AAMA/AADAPwAAwD8AACgAAAAwAAAAYAAAAAEACAAAAAAAAAkAAAAAAAAAAAAAAAEAAAAB + AAAAAAAAPj46AEA9PABBQT4ADDtRAA9BVQANRFwADUhgAABIagAYSWAAC1FvAB1UbwAHVnYAElt6ACZP + YgATYH8AM2J2AEhFQwBRTk0AV1NNAFVSUQBZVVIAXFhVAF5bWQBgWU8AZV5VAHRoRQBpYFUAZWFdAGtk + WwBxal8AZWNgAGllYgBuaWQAbWpoAHJsZwB6cWYAdXNrAHp0awB3eG8AeHhvAHVzcAB8dXAAe3tzAHx8 + egCFe2wAg3tzAIl/cQCCf3oAin95AH+AdgAO8U4ADexdAI2AbwCRh20AgIB3AI2BcwCDg3wAi4J7AJCE + cgCQhXsAk4l8AJmOfwAKX4EAE2KEAB9ohgASZ4kAFWmLABdukQAUcpUAG3KVABx3mgAcep4AIGeFACdu + jwAlcI4AJXOTACF3mgAkepsAKXyeADFzkAA8d5IAP3iQACR+oABId4wAW3WCACWAowArg6QAJoesAC6I + qgAyhKQAMYeoADOKqwA5jKwANI6yADqPsQAskroANJCzAD2StAA9mbsAXYqcAHiDhwBhhpcAZomYAHaU + nQB/kpwAToqiAFyNoQBLkKsAXZGmAEKUtQBBmLcASpi2AEGWuABEmrsAUZq3AHSWowBUoL8Ac6C1AH2n + uAB2qb4AZ/S4AEKdwQBKn8AARqHEAEyixABNqcoAUKXFAF2pxgBTqssAWK3OAE+u0ABYr9EAUrPXAFux + 0QBbtdgAWbncAGGqxwBgrswAca7FAHO0zQBgtdUAbbXRAGO41gBjutoAarzcAHK61QA98tUAc8DeAGbE + 5QBtwuIAccXlAHzG4AB2yOcAe8rmAHTK6QB6yukAhoWAAImGgQCLi4MAjo2JAJKLgwCajoQAkI6KAI+Q + hwCTkYYAnpOFAJOSjACblYsAnZiMAIWXmwCVlZEAmZaQAJqakwCTnJwAnp2YAKCThwCgmYQAoZaNAKWf + jwChnZcAo6GWAKqilACjo5wAqqOeALSsmwCNo6oAmqWmAI6wvgCZsbYAq6qkALGqowCwragAqbCtALOy + qwC5tasAqrW2ALW1sQC7tbEAt7ixALu7tACwvLoAvby7AMG1rwDBvLYAtsG/AMXEugDRzLkA1dC9AI6w + wACcvcsAtcfPAITO6gCP0+wAmtftAJrY7QCD1fQAkNv3AKjd8gCU4fwAoeL7ALfl9wC55fUAs+r9AMXF + wgDJxsAAzMvDAMTOygDNzMoA0M3FANTRwgDZ1cQA29jGANPTywDY1s0A29nMANLR0ADb29IA4N3PAOHe + 1QDf4NcA5OHUAOzo1ADk49oA6OnfAPLw3wDC6/sAzvH/AOfp4ADq7OIA7e/oAO/x5gDy8+oA6/v/APT2 + 8QD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdlELCQQFB2kAAAAAAAAAAAAAAAAA + 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 + TgBkYVsAaWJYAGpkWgBsZVsAa2RcAGxkXABrZmEAaWlnAG1qZgBxcWcAcnJoAHRxaQB1cm0AdnduAHhz + bwB6dG0Ad3hvAHt3cgB5eXEAfnhxAHx8cgB8eHUAfX11AIF7cwCDfHMAgXt1AIJ8dACEfnUAgX55AIR/ + eAAAzEYAE+5RAICAdgCBgnkAhoB5AIGBfgCGgn0AhYV9AImCeACIg34Ai4V+AI2FfQCIin4AkYd7AJCH + fQCQiX0AlYl+AJaMfwA+epsAAXimAEdzjwBTdo8ARXSSAE59lwBEe5sAVXeQAFJ6kgBWeJEAUXyXAFN9 + mABbfpgAF4y5AByRvgBWgJgAXYObAGKFmgBIiakAWZOuAGyQpwB7l6oAdZmuACzTuABV0pwAEJ3YACCV + wgAil8QAJJnGACmdygArn8wALKDNADCk0QAzp9QAM6vXADWq1gAzrNkAOa7aADSx3AA7sNwANLThAD+0 + 4ABOsNIAbbHJAEO45ABFuuUAR7znAEm+6QBrwt4AS8DrAEzB7ABRxfAAVsv1AF7T/QBtx+MAZMjmAGTI + 6ABzy+QAYNX/AGTV/wBo1v8AhYaBAIiGgACHiIEAiYmBAI2IgQCMjIMAjYmFAI2NhQCOj4oAkYqBAJGN + hQCYjoAAn4+FAJCPiACPkYoAm5GCAJyRggCbkYUAnZKEAJOTjACYlIwAnZmPAJeXkACZl5MAmpqTAJ6d + mgCglYYAopiJAKSajAClnI4AoZqSAKadkQChnpYAqZ+SAKCfmQCpoJIAqaGVAK6klwChoJoAoqOcAKWl + nQCqopgAraWZAK2omwCwp5oAta+bALGpnQCUn6IAl6KlAKWloQCrqqQArq6qALGqoQCwrKMAtq2hALCs + pQCyr6kAr7CoALiwpQCxsaoAtrGoALCwrgC1s60As7SvALW1rgC7tKgAvrisALW0sgC4t7AAubmyAL65 + sgC5ubQAvLy0ALy8uQDAuq8AwLqwAMS8sgDDvrcAxb60AMC/vADHw7cAzMaxAMHBuQDGwbkAwsG8AMTE + vQDJxLoAzcq9ANDLtwDExMEAyMfHAMjIwADNysEAysnGAM7LxADOzMQAzM3KANHOxgDQzskAztDGANXS + xgDb1cMA09HIANXRyADS0s4A09TMANfXzwDe28wA1dbSANjY0ADd2tEA29zSAN/c0QDY2tQA3d7WAN3d + 2QDi388A4t/RAOXi0wDo5dYA5ODZAOXm2wDi4dwA5uXcAOvn2QDr6dkA8e7eAOXl4ADn5+QA6erkAOrs + 5gDu7uQA9fLiAPj15QDw8eoA9vjxAPv58AD///cA///6AP///wAAAAAAAAAAAAAAAAAAAAAAAAA4ODg4 + ODg4ODg4ODg4AAAAAAAAAAAAAAAAAAAAAAAAAGhoZmRkZGxgVlZWYDgAAAAAAAAAAAAAx556NAT6KgAA + WFhTU1JRWkQ4ODhFOAAAAAAAAMGYMjI0gCUmCvv9mgBoaGhmZGRxYFZWVmA4AAAAAAAAwXqShYV/T04K + 9e/971hYVlVVU1xEODg4RTgAAAAAAAC+taKYj4WFNAj14uHWaGhqaGZmcWBWVlZgOAAAAAAAAMGSMBoW + EhotCvPh3sdYWFhXVlVeRDg4OEU4AAAAAAAAvg8WIS00f4AI793dvGhoa2poaHNgVlZWYDgAAAAAAADB + vrWekY6EhAjv09evODg8PDw4ODhAQDs4OAAAAAAAAMGokn0hISEtCufTz8+vmkFvQNMAADtbPQAAAAAA + AAAAxBoVITAyNIQI4s/Dx8/HQW9A0wAAO1s3AAAAAAAAAADTxL6omJGOhAjhw7y8u7xBb0DPAAA7WzcA + AAAAAAAAANOoiDAhISEhCuG8u7uvt0ZuR8cAAElfQwAAAAAAAAAA0xV1en2FhYUK3Luvr6+vSG1iTUxK + XVBLAAAAAAAAAADa0MG1opWPhQjWr6+tpqakQWdwZ2FQQQAAAAAAAAAAANN9FRYVFSF9CNOnpqWlpaWk + SEA6QEsAAAAAAAAAAAAA06zHxMrZ08oIz6aapaWUlJSWrwAAAAAAAAAAAAAAAADQ+fjx6OHZyg3DmqWU + lJSMjIymAAAAAAAAAAAAAAAAAN35+PHo6NjLDbyalIyMioqKiqYAAAAAAAAAAAAAAAAA0Pn48uvh2csN + vJSMioqHgoKBmgAAAAAAAAAAAAAAAADQjC4qMCoqNAi8jIqCgoKCeoKUAAAAAAAAAAAAAAAAANCvwa+o + opiRCLuKgoGCNDF6LIkAAAAAAAAAAAAAAAAA3eLaxMK1oJcKu4KCeiwxMSosigAAAAAAAAAAAAAAAADT + i4h6KTAwfQi3gnqCLDEqKieHAAAAAAAAAAAAAAAAANOspqisqJ6SCLd6MSwsKicnG4EAAAAAAAAAAAAA + AAAA2uzi2sTBqKANrzF6LCgbKhsbggAAAAAAAAAAAAAAAADQm3wuKjCIiQinMSwqKicbGxQsAAAAAAAA + AAAAAAAAANr05+fi2dnFBacxLigbGxsUFSwAAAAAAAAAAAAAAAAA2v//+vro2cUFpjEuKCgbGxkRLAAA + AAAAAAAAAAAAAADQ6KKirNnvzAWnMS4oKBsZFBEsAAAAAAAAAAAAAAAAAN0GAwIBDtrZCKYxMSgZGxQU + FCwAAAAAAAAAAAAAAAAA0cHBw723t7eNo6WlscPDz9bPAAAAAAAAAAAA///AAf//wAH/gMAB+ABAAfgA + AAH4AAAB+AAAAfgAAAH4AAAB+AAAx/gAAMf4AADH+AAAx/gAAAf4AAAP+AAAH/gAAP/4AAD/+AAA//gA + AP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAf8oAAAAGAAAADAA + AAABAAgAAAAAAEACAAAAAAAAAAAAAAABAAAAAQAAAAAAAGNfWABcclcAa2VeAFprYQBycmkAc3FtAHV1 + bQB5eG4Af3ltAHp6cQB6enQAfn51AINtYwCCemUAg3pvAIF7cgCFenAAg310AIR9dACBfngAhH94AA66 + LAAA/z4AgIB3AIGBeQCFgnkAhIR7AIWBfQCFhH0AiYF5AIiEewCNhXkAiIF8AImFfQCOh34AiIh+AI6I + fwCRh3oAlYt7AJCJfQAaYoMAGmiKABpxlgAadp0APnqbAAF4pgAaeKAAR3OPAEV0kgBOfZcARHubAFV3 + kABSepIAVniRAFF8lwBTfZgAW36YABqCqwAahK0AGoq1ABqLuAAajboAVoCYAFmAmABdg5sASImpAFmT + rgBgh6AAe5agAHWZrgAA1LIAQ8mLABqUwwAQndgAIpzKACSezAAqo9IALabVADOr1wAwqtgAM6zZADSx + 3AA0tOEAPbfkAE6w0gBtsckAQrzpAEW/7ABrw98ARsDtAEjC7wBNyPQAUMr2AG3H4wBkyOYAZMjoAHPL + 5ABn4v8AaOP/AI2HgACJiYEAjYiCAI6JhQCNjIUAkIqCAJGMhQCVjocAkY+IAJuQgQCRkYkAl5CIAJWR + jgCVlY0AmpOJAJyTiACclIkAnJaNAJiYjwCfmY8Am5eRAJiYkQCamZYAnJqWAJ2dlgCdnpgAnZycAKWP + hQCli48AoJaJAKGYiwChm48ApZuOAKadjwCgkZAAoZqQAKSbkACinZIApJ+ZAKqhlwChoJoApKObAKKi + ngClpZ4Ar6edAICbpQCjo6MApqagAKmnoQCqqaMArqmgAKqqpACtraYAra2qALGqoQC1raIAsq2lALCv + qwCvsKkAr7OtALizogCxsKgAtrCoALS0qwCzsqwAtbStALy2qwC4tK4Av7esALOxsAC2tbEAubmyAL26 + sgC+u7UAvr62ALm5uAC9vbkAxL6pAMS+rQDAurEAxL2zAMO+tADEv7UAwL+9AMbAtgDDw7sAxsK4AMfE + ugDDw7wAxMO9AMXFvADLxbsAysW8AMzHvQDPyrkAyci9AM3LvwDRzbwArcjVAMTGwgDKx8AAysjBAM3K + wgDJycQAy8zEAM7PyQDQzcAA0M3EANTPyADP0MoA09DHANPRyQDU1c0A2NTJAN/czgDT1dEA19XRANnZ + 0gDb29YA4N3PAObY0ADt2tMA5OHVAOvm0wDg4NoA5OPbAOfn3wDq6N0A5+bhAOno4ADs7OIA9vTjAP7+ + 7gD49fMA+fjzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAuLi4uLi4uLi4uAAAA + AAAAAKx1EQLHAABdXFxjWFBQPUsuAAAAdXV1CQ0WFwTp5Y5NS0xUSTo6KiwuAAAAs4p1g39IRwPh5eVa + WltiWE1QPUsuAAAAs5xpEREfEWbh2aw9PD1NOi8vKSwuAAAAwJZpd4mDbSXZ1KVaWltjWE1QPUsuAAAA + urOciSggDyDZzK4uMjIyLi41MjAuAAAAwJwfZGl1JiDXuse6N2A2AAAxTzMAAAAAuMCmkIltIGTNsKur + N2A1AAAxUC0AAAAAuqVkaWt1IB/LqqWlP19BAABCUzkAAAAAuLqlnIuDKB+6npaYP15WRkNSSkQAAAAA + uqZkIGSGgCCwl5eOkTdZYVVKN8YAAAAAs83Z2dzDnhyrjn19d5E1NjVExgAAAAAAs97o593DnyCqd313 + eXF9AAAAAAAAAAAAuNXc1MW6nxyYeXlxcXFxAAAAAAAAAAAAuKVxbGtrIByWeXFoaBxxAAAAAAAAAAAA + s9LSwKacbR+ScWhoHGhoAAAAAAAAAAAAwKx3eWZrZByOaB8dGwwkAAAAAAAAAAAAwMy3t7ObghF9aBsb + GwsfAAAAAAAAAAAAzMCdiniJdRl9HxsbCwsMAAAAAAAAAAAAz9jX1MPFoAt9HxsLCwcLAAAAAAAAAAAA + 0uTp5ePfsQt9HxkLCwcLAAAAAAAAAAAA1LEOAQfIxQt3HQsLBwUHAAAAAAAAAAAA1KyUkn2qrHeSkp6q + r7C6AAAAAAAAAP/4AQD8GAEAwAABAMAAAQDAAAEAwAABAMAAAQDAAGMAwABjAMAAYwDAAAMAwAADAMAA + BwDAAH8AwAB/AMAAfwDAAH8AwAB/AMAAfwDAAH8AwAB/AMAAfwDAAH8AwAB/ACgAAAAQAAAAIAAAAAEA + CAAAAAAAAAEAAAAAAAAAAAAAAAEAAAABAAAAAAAAMzMxAFxOJgB3cWoAeHJpAHhzbwB9dm4Ah31uAIJ7 + cgCFfnYAiH9yAIF/egCKgXYAjIN3AI+EdQCOhnwAlIl6AJqPfwAad58AAXimABZ9pAAaeKAATXCKAE5y + jABKdI8AX3aEAFh+lwAagqsAHoOoABqErQAai7gAGo26ADmdvQBuhZQARJKsAEmftgBQobcAGpTDACWf + zQAqo9IALabVADCq2AA9t+QAQrzpAEW/7ABGwO0ASMLvAE3I9ABQyvYAZ+L/AGjj/wCKhoEAlIyDAJ+W + hgCmnI0Aop6YAKqhkwCto5YAraSXAKqimACwp5kAsqiaALSqmwCzqpwAtqyeALSsogC4r6EAtrCmALqw + ogC8s6UAvbSmALqzqgC/tqgAu7WtALy3rwC/urMAwbepAMK5qwDEuqwAxr2vAMG8twDIvrAAwb24AMnB + sgDEwLsAxsO/ANPNuQDGw8AAyMbCAMrIxgDMysgA4NvKAOHcywDk384A6OXUAOrn2gDs6N0A7ergAO7s + 4ADw7eMA9fPpAPX16gD29OwA+PfuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + GJoAAAAwDUhjJCBnhf9Yr9H/YbnZ/2bE5f+x6Pv/YarH/zKJqv8tg6T/HHSV/xVpiv8KX4H/QJK0/16z + 0v84jq//UrPX/zFkfa4AAAA9AAAAOgAAACkAAAAXAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABzcW6BdWtiwouAef+Ngnz/i4B3/46Edv+Vi33/l4x9/5OJff9+dXD/Z/S4/z3y1f9rY1j/sK2o/93d + 1f/d3dX/5OPa/9PSy/9dXlzYBxsjikaWtv9wxub/XLLS/0ypyv+a1+3/XKrH/zSLrP9Albb/R5y9/0ec + vf9BmLf/c8De/3rL6v9Fm7z/Joes/xpOZaoAAAA8AAAANwAAACcAAAAbAAAADQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACEg3//fXRu44p/ef+ViYP/louC/5OIe/+Zjn//n5OE/56Thf+flon/nI6F/6CT + h/9pYFT/sa+q/9vc0//b29L/29rR/93d1f/n5tv/mKSl/DqRsv9Ppcb/WbDQ/3DE5P/O8f//bbXR/0CY + uf86j7H/LoSl/yR5m/8SZ4n/QZm6/1KoyP8vhab/Wrjc/z96kpYAAAAgAAAAIAAAABIAAAAJAAAABwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFhID/g3pzyZOIgv+dkYr/oZaN/56Vi/+Ignv/ZmJe/1xZ + V/9nZGH/fHZx/5KLgv9vZlv/srGr/9vb0f/Z2tH/2dnR/9jYz//Y2M//xM7K/ziOr/9swuH/ab7f/1y1 + 2P+o3fL/VKC//yd/oP8yh6n/NImq/zeMrv82i67/brzZ/3rK6f8pgKH/FXSX/2WmwmkAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjor/kIR7s4+Ff/94cW3/amZl/1ZT + VP9EQkL/T0tI/2tlXf9+dWr/i4Bw/5GFcv9oX1P/tLOt/9jZ0P/Y187/19bO/9fWzf/S0cr/nKam/0Wa + vf9Yrc7/WKzO/2m/3f/C7Pz/dLvV/0ujxP9TqMr/S6HC/z+Vtv8vhKX/Vq3N/2C11f9Blrj/QJ3C/z5+ + mIMAAAANAAAACgAAAAQAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjor/hn15tVJP + T/9dWVf/enJs/4J4a/+LgHH/joN0/5SMgP+PiYD/hoB6/42GgP9tZlz/tLKr/9XVzP/V1c3/1dPL/9XV + zP/R0cr/sLy6/zKKq/90yun/gdPy/4/T7P/D6vr/Up68/yR8nv8nfJ3/Inma/x1zlv8edJf/YK7M/2m5 + 2P8Vao3/MY6y/0mGoYcAAAAQAAAAHwAAABMAAAAJAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACQjon/kIR+u4R5dP+QhH7/iYB6/3BqZf9fXFn/WFRS/1tYVP9rZmH/eXNr/4uDeP9qYVf/s7Gs/9LT + y//T08v/0tLK/9HSyv/MzMT/lZ+e/1Cmxv9tw+L/YLna/1i63f+35ff/cbrV/0qiw/9Vqsv/VarL/1Gm + x/9Oo8T/esnm/3bI5/8/lbb/E3CU/3q51WQAAAAAAAAAAwAAAAcAAAAFAAAAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACPjor/loyDxHVva/9WUlD/SUVE/1ZRTv9yamT/iX9y/4uAcf+Og3T/j4R2/5KH + ef9pYFT/s7Gs/9HRyf/Q0Mn/0NDH/8/Pxv/MzcT/ucK//y6Jqv9wxub/hM7q/7nl9f/r+///XqjF/zGJ + q/8xh6j/KH2e/x91lv8hd5r/S6LE/1SrzP8XbpH/NJCz/6jh+mEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjor/koiCy3Zva/+HfXf/jIF4/5CHfv98dnH/ZGBd/19c + Wv9hXlz/c29q/4yEff9rY1j/s7Gr/87Oxv/Ozsb/zM3E/83NxP/Gxr//kZqb/z2Zu/+Q2/f/oeL7/5Th + /P+27f//fcvn/1Srzf9nu9r/bsPj/3XK6v9juNb/OIyr/0+kw/9Opcf/HHqe/4e/2GUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPjon/nJCJz352cf9pZGP/W1hW/1RR + T/9dWVT/aGFb/3hwZv+Eemv/jYFv/4+CcP9nXlP/srGr/83MxP/Ly8P/ysrC/8nKwf/Hx8H/qrW2/2q+ + 3/+G1/f/c7TN/0+LpP9JmLf/XrfY/1WrzP9Zr8//U6jJ/0uixP8FWHn/W3WC/yZPYv8fd5n/PpW3/4i/ + 1mwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOjon/k42H1nNs + af9/dXH/hnpz/4uAcP+Pg3P/j4N0/5KKf/+QiYD/jIV//5SNhP9oYFT/srGr/8nJwf/KycH/x8fB/8bG + v//Fxr//tMC//zePsv87kLL/Flx6/32nuP8ASGr/MIms/z+Vtv9Kn8D/VKrL/zyStf8AV3n/tcfP/12R + pv8FWHkoAExvLG2kvAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACOjon/p5uS3ZGFf/+LgXz/d3Ft/2ZhXv9dWlj/WldU/19cWf9taWT/fXVv/4yDef9pYFb/s7Ks/8bG + v//Gxr//xcW+/8TEvP/Dw7r/wsK6/8LBuv+Zsbb/M4Wl/3zG4P8ydJD/jaOq/6mwrf+qqaX5X2BgVwAA + AAwPQ1tHca7F/z+QsP8AAAAGAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACPjor/npWP4mhkYf9RTUz/WVRR/2VeWf99dGj/iX5t/46Ccf+QhHP/kIRz/5GF + dP9oYFb/srGr/8PDvP/Cw7z/wsG5/8DBuf/AwLj/wMC3/76+t/+9vbf/Inia/1Otz/93k5v/nZyY/52c + mP+9vbX9uLm6bQAAAAEYUmxBRZa0/zKLr/8AAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOjon/pZyW6IyDfv+Ognz/kIR6/42DeP+AeHH/cmxo/29q + Zv9xbGj/eHNt/4yEfP9pYVf/sK+p/8DAt//AwLn/vr62/769tv+9vbX/vLy0/7q6s/+6urP/HXSW/zyW + t/91lp//t7ev/6+vqP+1s63/nZ2eagAAAAAeXHpANIOi/ymCpf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACNjIf/rqSe7YmBff9vamj/VFFQ/0A9 + PP9PTEn/XVlW/29oYP+Ad2v/iX5v/42Bcf9nX1P/sK+q/76+tv+9vbb/vLy0/7q6s/+5ubL/uLiy/7e4 + sf+3t7D/G3GT/yqEpf93l6H/tbWv/7OzrP+zs6z/vLm0dAAAAAAiYH09JXOS/yN9oP8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACNjIj/oJqX73hz + cP98dHD/gXdv/4l+b/+NgnP/jYJy/46DdP+Qhnr/kId9/5KJfP9oX1T/r62o/7q6tP+6urP/ubmy/7e3 + sf+2trD/tbWt/7W1r/+0s6z/EVx8/yqGp/9djqL/srKq/7Kyq/+xsan/p6ajgAAAAAAlZ4aEJXiY/xpx + lP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACMiof/vrKr8p2Tjf+Kgn7/d3Ft/2xoZP9jXlv/X1xZ/2djX/9vamX/eXRt/4yDev9oYFb/rKun/7e3 + sP+3trD/trWv/7W1rf+zs6z/srKq/7Kxq/+xsar/EFp5/yeAov8+ja7/rq+n/6+vp/+traX/paWgiAAA + AAAhaoz3JXyf/xlwk/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACKiYb/nZeT9mdjYP9oZGH/bWdj/3FqYf98c2f/g3lq/4Z8av+MgG//j4Jw/46B + b/9mXVL/q6qm/7O0rP+0tK3/s7Kr/7Gyq/+xsKn/r6+o/62vp/+trab/MHOS/xZkhP8viKr/X4ud/6uq + pP+qqqL/paSfjzB1mHoLUW//JXCO/yp8nv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACJiIX/u7Ku96Sak/+bjof/koV8/46Dd/+Lgnj/gHly/3l0 + bf98dXH/f3lz/4uDev9pYFb/qqql/7Kyqv+xsar/sLCo/7Cvp/+traf/rKyl/6uqpP+qqaT/g5id/wxX + d/8kc5L/KIKk/z94kP+Hl5n/Q3qT3BNgf/8NRFz/Gneb/yxykXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIiIT/v7mz95OOi/92cnD/X1xa/0VC + Qf9EQUD/VFBO/2FdWf9ybGf/hH1z/42Cdf9pYVf/qaml/6+vp/+vraf/rKym/6urpP+qqqP/qami/6io + oP+np5//p6eg/06JoP8ZdJX/NIut/zyQsP9LkKv/JIGk/w1Vcf8UYoL/NIam2zBykAUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACHh4T/k4+L+oN/ + fP+Gf3z/g3pz/4Z9b/+MgXL/jYFy/42Ccv+OgnL/joJz/4yAcP9lXVL/p6ai/6uspf+rq6T/qqqj/6mo + oP+op5//pqad/6Wlnv+lpZ3/o6Oc/6OjnP9biZv/MYWn/1ClxP9MmLb/H2iG/xVjhf8vfJ2nLnqcAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACGhYL/vbax/qykn/+QiYX/cm1q/2FdWf9lYF3/Y19d/2lmY/93c3D/hoJ+/5qUjP9xal//p6ai/6io + ov+oqaL/p6af/6amn/+kpJz/pKSc/6Kim/+goJr/oqCZ/5+emP+fnpj/n56Y/5+emP+cnJb/nJuYnQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACJiIX/hYF+/2lmY/9xb2n/gH95/46Mhf+joZn/uLar/8bEuP/OzMD/0M7A/9LR + w/+lpJn/pqWg/6amnv+mpp//pKSd/6SjnP+iopr/oJ+Z/5+fmf+dnZf/nJyU/5yclP+cm5P/m5uU/5ub + k/+ZmpP/mpmWpQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIh4T/29jH/9zYxf/U0cD/ysi4/8bEtf/Hxbb/x8S4/8bD + t//OzMD/zcu+/83Lvv+in5X/pqWf/6Ojm/+ko5v/oqKb/6Cgmf+enpj/nZ2W/5yclP+bm5P/mpuS/5qZ + kv+ZmJH/mZmR/5mZkf+Xl5D/mZmTqgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIh4P/8vDf/+fj0P/Z1sP/zsu7/8jF + t//Hxbb/zMq8/83Kvf/OzMD/y87B/9HPwv+joZb/oqCc/6Cgmf+gn5n/n5+Z/52dlv+cnJb/m5uU/5mZ + kf+ZmZH/mJiQ/5eXj/+XlpD/lpaP/5aWjv+Tk43/lpaRrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFhIH/8/Di/+zo + 1P/f28n/xsO2/7WzqP+jopn/m5qT/52blf+gn5j/pqSd/7azqf+Xk4j/oKCb/52dlv+enpf/nJyW/5ub + k/+ZmZH/mJiQ/5eXj/+Wlo//lJSN/5KTjP+Skov/kpKL/5OSjP+QkIn/k5OQsQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACEhID/xMG4/5mWjf92c3D/XVpZ/1FOTP9XUk//XllU/2plX/92cGj/hH1y/4uAc/9oYFf/n5+b/5yc + lP+bnJT/mpqT/5iXkP+Xlo//lpaO/5OTjP+Rkoz/kpKK/5CQiv+RkIn/kI+J/5CPif+NjYX/kpKPtQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACNjYr/t7Ot/7GtqP+vqaX/pp2U/5aLff+Og3L/j4Jw/4+Ccf+Qg3H/kYRy/4t/ + bP9lXVP/np6Z/5qZkv+amZL/mJeQ/5aUjv+UlI3/kpKL/5CQif+QkIn/jo6H/46Nhv+Ojob/jY2F/42N + hv+Li4P/kJCMuwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMjIj/zcrD/7m1sP+gnJn/j4qF/3x2cf9ybWj/b2ll/3Fs + Z/92cWz/gXp0/4uCd/9nX1b/nJuW/5iYkP+Yl5D/lpaO/5OSjP+Skov/kJCH/46Ph/+Ojob/jIyF/4uL + hP+Li4P/iouD/4qKgv+Hh4D/j46Lvo6NiwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKiob/mZaS/4eEgP+Gg4D/hYF9/4F8 + df98dWz/enNo/392a/+EfG//in9x/4uAcf9lXVP/nJuX/5aUjf+Wlo//k5OM/5CQiv+Qj4f/jo6G/4yM + hf+Li4P/iouD/4mJgf+Jh4D/iYmA/4eGf/+FhX3/jo2Kwo6MiwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKiof/29jQ/9DL + xP/Cvbb/s6yl/6qilP+ZjoD/j4V3/42Ddf+OhHf/j4V3/4uAcf9nX1T/m5qU/5SUjf+UlIz/kZGK/5CP + h/+Ojof/i4yE/4qKgv+JiYH/h4eA/4eHgP+Ghn//hYV+/4aFfv+Dg3r/jIyHxoyLiQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACKiYT/ycbA/62qpv+Sj4z/g4B9/3Jva/9oZWH/X1xa/2RgXf9vaWb/enVx/4uDef9nX1b/mpmT/5KS + jP+SkYv/kI+H/42Nhv+LjIT/ioqB/4mHgP+Hh4D/hoV//4WFfv+EhH3/g4N6/4ODfP+BgXj/i4uHzI2L + iQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACJiIT/p6Se/5+cmP+fm5f/oJyY/5mUjP+Si4D/i4F0/4Z8bP+HfW3/jYJy/4l9 + bP9lXlT/mJiS/5GQif+Pj4n/jo6G/4yMhP+LioL/iYeA/4aGf/+FhX7/hIR9/4ODev+Cgnr/goJ5/4KC + ef9/gHb/iYmE0YuKhwYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACHh4P/3tzV/9nWzf/QzMT/wr63/7CqoP+fl4v/kYl9/4d+ + cf+GfXD/in9x/4V5av9gWU//lpaP/4+Qh/+Oj4f/jIyE/4qLg/+JiYH/h4Z//4WFff+Dg3z/g4N6/4GB + ef+AgHf/gIF4/39/d/99fXT/h4aE1YuKiQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGhoH/sK2p/4aEgf90cnD/bWtp/2xq + aP9wbWr/dnRw/4J/eP+QjYX/m5eO/56Zi/9zb2X/k5OO/46Ohv+NjYX/iouD/4mJgf+Ghn//hIR9/4OE + fP+BgXn/gYF4/4B/dv9/f3b/fX51/319df96enP/hYWB2IqJhwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEhID/wcLA/8DB + vf/Hx8L/zMzE/87Nw//QzsD/0M29/9LNuv/Rzbn/0s65/9XPuv+dmY7/kpGM/42Nhf+MjIT/i4uD/4mH + gP+FhX7/g4N6/4KCev+AgHj/f393/35+dv99fXX/fX11/3p6c/95eXH/hYWB3YuKhwoAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACDgn7/9Pbw//L06//v8ub/6Onf/+Li2P/f3c//29jJ/9fSwP/W0L3/1c+8/9DLt/+cmIz/kZGM/42N + hP+LjIT/h4eB/4aGf/+FhX3/goJ6/4GBeP+AgHf/fn52/3x8dP98fHT/fHpz/3l6cv93eG//g4OA4YqJ + hwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACCgn7/8/Xt//L06//v8uf/6Org/+Tk2v/f3tH/29jK/9jTwv/W0L7/1c+8/9DL + tv+bl4v/kZCL/4uMhP+MjIT/iYmA/4aGf/+Dg3z/goJ6/4CAeP9/fnb/fX10/3x8dP96eXH/eXlx/3h4 + cP92dmz/goJ/5YmHhg0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCgX7/8/Tt//L07P/w8uj/6uzk/+Xl3f/g39X/3NrM/9rW + xf/X0sH/1c+9/9DKtv+al4v/kZCK/4uLhP+Li4P/h4eA/4aFfv+Dg3z/goJ6/39/d/9+fnb/fX11/3p8 + cv95eXD/eHhw/3h3b/90dGv/goJ+6YqHhg4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCgX3/8/Xt//L07P/y9Ov/7/Hn/+fp + 4P/i4tn/3dzP/9rXxv/X08L/1dC9/9DLtv+alor/kI+K/4yMhP+Ki4P/hoaA/4aFf/+Dg3r/gYF5/4B/ + d/9+fnb/fX11/3p6cv96eXH/eHhv/3Z2bf90dGr/goF+7IqHhhEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBgX3/8/bw//X3 + 8//t7+b/5eXb/+Pi1//m5Nr/5ePY/+Ddz//Z1sT/1tG//9DLt/+alon/kZGL/4uLg/+LjIT/h4eA/4aF + fv+Dg3r/goJ6/4CAeP9+fnb/fX10/3p8cv95eXH/eHhw/3d2b/91dGv/goF+74uJhxYAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACCgn7/7e/o/7Ssm/+imYL/oJmF/5eShv+YlIz/raqk/9DNxP/j4Nf/3tvN/9DMuf+bl4v/kJCL/4yM + hP+LjIP/iYmB/4aGf/+FhX3/g4N6/4CAd/9/f3f/fX10/3p6c/95enH/eHhx/3d3cP91dWz/goJ/8omH + hRsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACBgX7/kYdt/3RoRf9fW0v/SUdD/z4+Ov8+Pjr/QUE+/2NjYP+pqKX/4t7V/9nV + xv+dmY3/kI+K/4yMhP+Ki4P/iYmA/4aGfv+Dg3z/goJ5/4CAd/9+fXX/fX10/3l6cv94eHD/eHhv/3d2 + bP90dGr/gYF+9oqHhh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBgX3/oJmH/6Wfj/+PjYn/kI6M/4+Oiv+QkI3/kpGP/52c + mf+trKn/x8S8/8rGuv+jn5f/k5KM/4yMhP+Li4T/ioqB/4mJgf+Gh4D/hoZ//4ODff+Cg33/hYV//4WE + f/+EhH//hYWA/4eHgv+Hh4L9k5OR76yrqiEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysK5lrqyqjK+sqpGwrqyWsK6rnbOx + r6Swrqysrquqs6uqqLuqqKfEpqShzaOintOfnZzXkZCP0pSSkcWSkpG3kpKQqZGQj5yQj46SlpWUhqmp + qXqnpqVxlJKRaaempmCsq6tXpaSjTZqZl0ako6I8vr28L6qopwYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//5/4AfwAA//wB+AAPAAD/4ABgAAEAAP8AAAAAAAAA/gAAAAAA + AAD+AAAAAAAAAP4AAAAAHwAA/gAAAAAAAAD+AAAAAAAAAP4AAAAAEAAA/gAAAAAfAAD+AAAAAB8AAP4A + AAAAHwAA/gAAAAAfAAD+AAAAAD8AAP4AAAAAPwAA/gAAAAj/AAD+AAAACP8AAP4AAAAI/wAA/gAAAAj/ + AAD+AAAAAP8AAP4AAAAA/wAA/gAAAAD/AAD+AAAAAf8AAP4AAAAP/wAA/gAAAA//AAD+AAAAD/8AAP4A + AAAP/wAA/gAAAA//AAD+AAAAD/8AAP4AAAAP/wAA/gAAAAf/AAD+AAAAB/8AAP4AAAAH/wAA/gAAAAf/ + AAD+AAAAB/8AAP4AAAAH/wAA/gAAAAf/AAD+AAAAB/8AAP4AAAAH/wAA/gAAAAf/AAD+AAAAB/8AAP4A + AAAH/wAA/gAAAAf/AAD+AAAAB/8AAP4AAAAH/wAA/gAAAAf/AAD+AAAAB/8AACgAAAAgAAAAQAAAAAEA + IAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABeKb/AXim/wF4pv8BeKb/AXim/wF4 + pv8BeKb/AXim/wF4pv8BeKb/AXim/wF4pv8BeKb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAkYd7Bl9ZTTE/Ny5+JCQkZgAAAAAAAAAAAAAAAEvA6/9LwOv/Sb7p/0W6 + 5f9EueX/Q7jk/17T/f8/tOD/LKDN/yygzf8soM3/P7Tg/wF4pv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAJGHewyRh3tIkYd7hJGHe8CJhn/3kIp+/2NbUf/w8er/VFZTvQAAACIAAAAAM6fU/zOn + 1P8kmcb/JJnG/yKXxP8glcL/NarW/xeMuf8Deaf/A3mn/wN5p/8ckb7/AXim/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAJGHe4qRh3vJkYd7/5GHe/+QiX3/n4+F/wDMRv8T7lH/bGVb//b48v////f/n5+a+xAQ + EXpLwOv/S8Dr/03C7f9Ivej/R7zn/0a75v9g1f//P7Tg/yygzf8soM3/LKDN/z+04P8BeKb/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAwLqx/46Khv6imZP/nJGF/5uRgv+YjYD/VdKc/yzTuP9qYlj/6uzm/+bl + 3P/7+fD/5ebb/zOn1P8zp9T/K5/M/yqey/8onMn/JZrH/zmu2v8XjLn/A3mn/wN5p/8Deaf/HJG+/wF4 + pv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAurH/u7So/7GpnP+poJL/opiK/52Rgv+ckYL/lYl+/2pi + WP/p6uT/3NvS/9vc0v/Qz8n/S8Dr/0vA6/9SxvH/TMHs/0q/6v9Jvun/ZNX//z+04P8soM3/LKDN/yyg + zf8/tOD/AXim/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMC6sf+jnpX/jYZ+/395cf96dGz/dXBp/314 + cf+Ef3j/bGVb/+bm4f/Y2ND/19fP/8HBuf8zp9T/M6fU/zGl0v8wpNH/LKDN/yqey/87sNz/F4y5/wN5 + p/8Deaf/A3mn/xyRvv8BeKb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwLqx/21qZv96dW//gXtz/4qC + eP+SiX3/lox//5yRgv9qYlj/5OTg/9PUzP/T08n/vLy0/0vA6/9LwOv/Vsv1/1HF8P9Nwu3/Sr/q/2jW + //8/tOD/LKDN/yygzf8soM3/P7Tg/wF4pv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEvrT/wruw/7iw + pP+vppn/pp2P/6CVhv+ckYL/nJGC/2piWP/i4dz/zs/G/87Qxv+ysav/AXim/wF4pv9OfZf/Tn2X/059 + l/8BeKb/AXim/wF4pv9SepL/Tn2X/0dzj/8BeKb/AXim/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMW/ + tf+xq6L/oZuS/5CJgP+FfnX/g3xz/4J7c/+Jgnn/a2Ra/9/f2v/Ly8T/x8fA/8jIwf+3t6//np2a/1F8 + l/9kyOj/V3eQ/8/Ox/8AAAAAAAAAAEV1k/8zq9f/RHub/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAyMO5/3x4df94c2//gXt1/42FfP+Qh33/lox//5mPgf9pYlj/3NzY/8XGv//Cwrr/wsK6/8TE + vf/ExLz/U32Y/2XJ6P9WeJH/zMzE/wAAAAAAAAAARnSS/zOs2f8+epv/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADOysH/ycO4/764rP+1rKD/q6OV/6SajP+ek4T/nJGC/2liWP/Y2dT/wMC5/729 + tv+8vLT/urqz/7q6tP9TfZj/Zcno/1Z4kf/IyMD/AAAAAAAAAABGdJL/M6zZ/z56m/8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/Lwv+wrKP/mpSM/4uFfv+Efnb/fXdx/4J8dP+GgHn/a2Rb/9XW + 0v+8vLX/uLiy/7a2sP+2tq//tbSt/1aAmP9kyOb/XYOb/8XEvf8AAAAAAAAAAEiJqf80tOH/W36Y/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzsvE/3p3dP+Hg37/joiA/5ONhP+bkof/m5GE/5yR + gv9pYlj/0tLO/7i3sP+0tK3/srKq/7Gxqv+wsKn/YYSa/23H4/9tscn/dZmu/3uXqv9Zk67/NLHc/xCd + 2P9TfZjZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADSz8f/z8q//8a+tP+7tKj/sqmd/6mf + kv+imIn/m5GC/2liWf/Oz8r/s7Kr/6+wqP+traf/q6ul/6qqpP+XoqX/U32Y/2vD3/9zy+T/a8Ld/06w + 0v8Qndj/U32Y/3uXqmgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM7LxP+Oiob/dXNv/3Zz + bv91cWv/dnFs/4J+eP+RjYX/aWJZ/8vLx/+urqf/q6qj/6moof+np6D/pqae/6amnv+Un6L/ZIab/1Z4 + kv9Tdo//VHeR/1N9mNl7l6poAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz8zE/7Ov + qP/Hw7j/x8O3/83KvP/X1cf/0M7A/8jGuP9oYlj/x8fE/6qqov+npp7/paSc/6KjnP+ioZr/oJ+Z/6Cf + mf+fnpj/s7Kr/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADSz8f/+PXl//Lv3//q6Nj/4t/R/9/czv/W1Mb/zcu9/2tkXP/Cwbz/paSd/6Oim/+gn5n/nZ6X/5qc + lP+bm5P/mpqT/5makv+urab/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANLPx//59ub/9PHi/+3q2//l4tP/39zO/9bUxv/Ny73/bGRc/769uf+goJn/np6X/5ub + lf+ampL/mJmQ/5eXkP+Wl4//lpaO/6moof8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA0s/H//n25v/28+P/8O3d/+jl1v/f3M7/1tTG/83Lvf9qZFv/vLy4/5yc + lf+amZL/l5eP/5aVjv+UlI3/kpKL/5KRiv+RkIj/paSc/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNysL/nJqU/4OBff+Fgn3/hoJ9/4eCff+Df3n/i4V+/2hi + Wf+8vbj/mpqR/5aVjv+UlIz/j5GK/4+PiP+OjYf/jo2G/4yMg/+gn5f/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/MxP+yr6r/vrmy/7ayqf+xqqH/raab/66l + mP+lnI7/aGJa/7q6tf+XlY//kpKL/5CQiP+Njob/jIyE/4qKg/+KioL/hoZ+/5ubk/8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0s/H/97a0v/W0cn/zce+/8S8 + sv+5sab/sKea/6edkP9qZFv/uLi0/5KSi/+Pj4f/jI2F/4qKgv+IiID/h4eA/4aFfv+Dg3v/mJeO/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNysL/mZeT/5SR + jv+MiIT/gn97/4iDfv+NiIH/kouD/2diW/+1tbL/kI+I/42Nhf+KioL/iIaA/4WFfv+EhHz/goJ6/4CB + dv+Tk4r/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/M + xP+yr6v/raqk/7Cspf+3saj/samf/6qimP+mnpL/ZmJa/7O0r/+NjYX/iouD/4iHgP+EhH3/g4N7/4GB + eP+AgXf/fX1z/5CPh/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA0s/H/+Tg2f/d2dD/1NDH/8vFu//Auq//t6+i/66kl/9rZmH/rq6q/4uLg/+Ih4D/hIR8/4CC + ev+AgHf/f352/319df95eXD/jYyE/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADSz8f/n5+f/46PjP+EhYL/gH97/4uIgP+Yk4r/nZmP/2ZkX/+srKb/ioqC/4aG + f/+Dg3v/gYF4/39+dv98fHT/e3tz/3V3bf+KiYH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAANLPx//n5+T/2dvU/93e1v/f3dL/2tbG/9vVw//MxrH/YWBb/6ur + pv+JiYH/hYV+/4KCe/9/f3f/fX11/3p7cv93d2//c3Np/4eGf/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0s/H//////////r/9vjw/+7u5P/i38//3NbC/8zH + sf9hX1r/q6um/4eIgf+Fg37/goJ5/39/d/99fXX/enpy/3l4cP9ycmj/h4Z+/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS0Mf/39zQ/7Wvm/+tqJv/s6+o/9XS + yP/r59n/0Mu3/2FgWf+rq6b/ioqC/4aEfv+Dg3n/gIB2/3x8c/94eXD/dXdv/3FxZ/+Hhn7/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANPQyP99cE7/U05D/0FA + Pf8+Pjz/aWln/9HOyv/c2Mj/ZGJc/6mrpf+Iin7/hYZ9/4CBeP97e3H/fHxy/3d4b/93d27/dHNp/4eG + fv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArquopq2q + o8Crqqm/r66sx6yrqtCpp6fYraup4rCtp+yXlZPtj46L34+QjdCNjYvBkJCNtKCgn6eVlJKdoJ+fk6Cf + noqXlpSEsK+vbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///AAf/hwAH+AEAB+AAAAfgA + AAH4AAAB+AAAAfgAAAH4AAAB+AAAx/gAAMf4AADH+AAAx/gAAAf4AAAH+AAAD/gAAP/4AAD/+AAA//gA + AP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP8oAAAAGAAAADAA + AAABACAAAAAAAGAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACclo0GZWJbTUVGRCwlJiUEAAAAAAF4pv8BeKb/AXim/wF4pv8BeKb/AXim/wF4pv8BeKb/AXim/wF4 + pv8AAAAAAAAAAAAAAAAAAAAAnJaNIJyWjUGclo1vnJaNqJyWjf+EeW/8XHJX/8HDv/EyMzJ5FxcYElDK + 9v9OyfX/Tcj0/2jj//9Fv+z/MKrY/zCq2P8ai7j/IpzK/wF4pv8AAAAAAAAAAAAAAACclo3/nJaN/5yW + jf9/eW3/g21j/w66LP8A/z7/Wmth//j18//p6OD/h4eBwiqj0v8ln83/JZ/N/z235P8alMP/GoKr/xqC + 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 + AADAPwAAwD8AAMA/AADAPwAA + + + \ No newline at end of file diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index a4e9858..587630e 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -136,6 +136,8 @@ this.settingsToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.openMapFileDialog = new System.Windows.Forms.OpenFileDialog(); this.saveMapFileDialog = new System.Windows.Forms.SaveFileDialog(); + this.customAppsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.customAppsToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.panel5.SuspendLayout(); this.mainPanel.SuspendLayout(); this.mainTabControl.SuspendLayout(); @@ -515,7 +517,8 @@ this.sortByNameToolStripMenuItem, this.sortByGroupToolStripMenuItem, this.toolStripMenuItem4, - this.settingsToolStripMenuItem}); + this.settingsToolStripMenuItem, + this.customAppsToolStripMenuItem1}); this.mainContextMenuStrip.Name = "mainContextMenuStrip"; resources.ApplyResources(this.mainContextMenuStrip, "mainContextMenuStrip"); // @@ -928,7 +931,8 @@ this.openMappingsToolStripMenuItem, this.saveMappingsToolStripMenuItem, this.toolStripMenuItem5, - this.settingsToolStripMenuItem1}); + this.settingsToolStripMenuItem1, + this.customAppsToolStripMenuItem}); this.mappingsContextMenuStrip.Name = "mappingsContextMenuStrip"; resources.ApplyResources(this.mappingsContextMenuStrip, "mappingsContextMenuStrip"); // @@ -965,6 +969,18 @@ this.saveMapFileDialog.DefaultExt = "mcrouter"; resources.ApplyResources(this.saveMapFileDialog, "saveMapFileDialog"); // + // customAppsToolStripMenuItem + // + this.customAppsToolStripMenuItem.Name = "customAppsToolStripMenuItem"; + resources.ApplyResources(this.customAppsToolStripMenuItem, "customAppsToolStripMenuItem"); + this.customAppsToolStripMenuItem.Click += new System.EventHandler(this.customAppsToolStripMenuItem_Click); + // + // customAppsToolStripMenuItem1 + // + this.customAppsToolStripMenuItem1.Name = "customAppsToolStripMenuItem1"; + resources.ApplyResources(this.customAppsToolStripMenuItem1, "customAppsToolStripMenuItem1"); + this.customAppsToolStripMenuItem1.Click += new System.EventHandler(this.customAppsToolStripMenuItem_Click); + // // MainForm // resources.ApplyResources(this, "$this"); @@ -1121,6 +1137,8 @@ private System.Windows.Forms.ToolStripMenuItem askConsentToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem privacyBarToolStripMenuItem; private System.Windows.Forms.PictureBox pictureBox2; + private System.Windows.Forms.ToolStripMenuItem customAppsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem customAppsToolStripMenuItem1; } } diff --git a/MainForm.cs b/MainForm.cs index f2f66eb..3c7d9d0 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -123,7 +123,9 @@ namespace MeshCentralRouter try { installProcess = System.Diagnostics.Process.Start(startInfo); } catch (Exception) { return; } installTimer.Enabled = true; installButton.Visible = false; - } else { + } + else + { hookRouter(); installButton.Visible = !isRouterHooked(); } @@ -145,8 +147,6 @@ namespace MeshCentralRouter return principal.IsInRole(WindowsBuiltInRole.Administrator); } - public void DeleteSubKeyTree(RegistryKey key, string subkey) { if (key.OpenSubKey(subkey) == null) { return; } DeleteSubKeyTree(key, subkey); } - public class DeviceComparer : IComparer { public int Compare(Object a, Object b) @@ -177,7 +177,7 @@ namespace MeshCentralRouter { // Normal certificate check if (chain.Build(new X509Certificate2(certificate)) == true) { meshcentral.certHash = webSocketClient.GetMeshKeyHash(certificate); return true; } - if ((meshcentral.okCertHash != null) && ((meshcentral.okCertHash == certificate.GetCertHashString()) || (meshcentral.okCertHash == webSocketClient.GetMeshKeyHash(certificate)) || (meshcentral.okCertHash == webSocketClient.GetMeshCertHash(certificate)))) { meshcentral.certHash = webSocketClient.GetMeshKeyHash(certificate); return true; } + if ((meshcentral.okCertHash != null) && ((meshcentral.okCertHash == certificate.GetCertHashString()) || (meshcentral.okCertHash == webSocketClient.GetMeshKeyHash(certificate)) || (meshcentral.okCertHash == webSocketClient.GetMeshCertHash(certificate)))) { meshcentral.certHash = webSocketClient.GetMeshKeyHash(certificate); return true; } if ((meshcentral.okCertHash2 != null) && ((meshcentral.okCertHash2 == certificate.GetCertHashString()) || (meshcentral.okCertHash2 == webSocketClient.GetMeshKeyHash(certificate)) || (meshcentral.okCertHash2 == webSocketClient.GetMeshCertHash(certificate)))) { meshcentral.certHash = webSocketClient.GetMeshKeyHash(certificate); return true; } meshcentral.certHash = null; meshcentral.disconnectMsg = "cert"; @@ -214,10 +214,7 @@ namespace MeshCentralRouter versionLabel.Text = "v" + version.Major + "." + version.Minor + "." + version.Build; // Prevent edgecase where the hook priority can be on and the hook disabled causing havoc - if( !Settings.GetRegValue("Exp_KeyboardHook", false) ) - { - Settings.SetRegValue("Exp_KeyboardHookPriority", false); - } + if (!Settings.GetRegValue("Exp_KeyboardHook", false)) { Settings.SetRegValue("Exp_KeyboardHookPriority", false); } serverNameComboBox.Text = Settings.GetRegValue("ServerName", ""); userNameTextBox.Text = Settings.GetRegValue("UserName", ""); @@ -226,7 +223,8 @@ namespace MeshCentralRouter int argflags = 0; string update = null; string delete = null; - foreach (string arg in this.args) { + foreach (string arg in this.args) + { if (arg.ToLower() == "-oldstyle") { deviceListViewMode = false; } if (arg.ToLower() == "-install") { hookRouter(); forceExit = true; return; } if (arg.ToLower() == "-uninstall") { unHookRouter(); forceExit = true; return; } @@ -249,7 +247,8 @@ namespace MeshCentralRouter } autoLogin = (argflags == 7); - if (update != null) { + if (update != null) + { // New args ArrayList args2 = new ArrayList(); foreach (string a in args) { if (a.StartsWith("-update:") == false) { args2.Add(a); } } @@ -267,13 +266,15 @@ namespace MeshCentralRouter if (delete != null) { try { System.Threading.Thread.Sleep(1000); File.Delete(delete); } catch (Exception) { } } // Set automatic port map values - if (authLoginUrl != null) { + if (authLoginUrl != null) + { string autoNodeId = null; string autoRemoteIp = null; int autoRemotePort = 0; int autoLocalPort = 0; int autoProtocol = 0; int autoAppId = 0; + string autoAppIdStr = null; bool autoExit = false; try { @@ -282,13 +283,15 @@ namespace MeshCentralRouter autoRemoteIp = getValueFromQueryString(authLoginUrl.Query, "remoteip"); int.TryParse(getValueFromQueryString(authLoginUrl.Query, "remoteport"), out autoRemotePort); int.TryParse(getValueFromQueryString(authLoginUrl.Query, "protocol"), out autoProtocol); - int.TryParse(getValueFromQueryString(authLoginUrl.Query, "appid"), out autoAppId); autoExit = (getValueFromQueryString(authLoginUrl.Query, "autoexit") == "1"); string localPortStr = getValueFromQueryString(authLoginUrl.Query, "localport"); if (localPortStr != null) { autoLocalPort = int.Parse(localPortStr); } + autoAppIdStr = getValueFromQueryString(authLoginUrl.Query, "appid"); + int.TryParse(autoAppIdStr, out autoAppId); } catch (Exception) { } - if (((autoRemotePort != 0) && (autoProtocol != 0) && (autoNodeId != null)) || ((autoNodeId != null) && ((autoAppId == 6) || (autoAppId == 7)))) { + if (((autoRemotePort != 0) && (autoProtocol != 0) && (autoNodeId != null)) || ((autoNodeId != null) && ((autoAppId == 6) || (autoAppId == 7)))) + { Dictionary map = new Dictionary(); map.Add("nodeId", autoNodeId); if (autoRemoteIp != null) { map.Add("remoteIP", autoRemoteIp); } @@ -296,6 +299,7 @@ namespace MeshCentralRouter map.Add("localPort", autoLocalPort); map.Add("protocol", autoProtocol); map.Add("appId", autoAppId); + map.Add("appIdStr", autoAppIdStr); map.Add("autoExit", autoExit); map.Add("launch", 1); mappingsToSetup = new ArrayList(); @@ -375,10 +379,13 @@ namespace MeshCentralRouter // Load registry settings showGroupNamesToolStripMenuItem.Checked = (Settings.GetRegValue("Show Group Names", "1") == "1"); showOfflineDevicesToolStripMenuItem.Checked = (Settings.GetRegValue("Show Offline Devices", "1") == "1"); - if (Settings.GetRegValue("Device Sort", "Name") == "Name") { + if (Settings.GetRegValue("Device Sort", "Name") == "Name") + { sortByNameToolStripMenuItem.Checked = true; sortByGroupToolStripMenuItem.Checked = false; - } else { + } + else + { sortByNameToolStripMenuItem.Checked = false; sortByGroupToolStripMenuItem.Checked = true; } @@ -525,16 +532,21 @@ namespace MeshCentralRouter if ((twoFactorCookie != null) && (twoFactorCookie != "")) { twoFactorCookie = "cookie=" + twoFactorCookie; } else { twoFactorCookie = null; } Uri serverurl = null; - if (authLoginUrl != null) { - try { + if (authLoginUrl != null) + { + try + { meshcentral.okCertHash2 = getValueFromQueryString(authLoginUrl.Query, "t"); string loginkey = getValueFromQueryString(authLoginUrl.Query, "key"); string urlstring = "wss://" + authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.LocalPath + "?auth=" + getValueFromQueryString(authLoginUrl.Query, "c"); if (loginkey != null) { urlstring += ("&key=" + loginkey); } serverurl = new Uri(urlstring); - } catch (Exception) { } + } + catch (Exception) { } meshcentral.connect(serverurl, null, null, null); - } else { + } + else + { int keyIndex = serverNameComboBox.Text.IndexOf("?key="); if (keyIndex >= 0) { @@ -586,14 +598,17 @@ namespace MeshCentralRouter meshcentral.okCertHash = lastBadConnectCert.GetCertHashString(); Uri serverurl = null; - if (authLoginUrl != null) { + if (authLoginUrl != null) + { meshcentral.okCertHash2 = getValueFromQueryString(authLoginUrl.Query, "t"); string loginkey = getValueFromQueryString(authLoginUrl.Query, "key"); string urlstring = "wss://" + authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.LocalPath + "?auth=" + getValueFromQueryString(authLoginUrl.Query, "c"); if (loginkey != null) { urlstring += ("&key=" + loginkey); } serverurl = new Uri(urlstring); meshcentral.connect(serverurl, null, null, null); - } else { + } + else + { // Load two factor cookie if present string twoFactorCookie = Settings.GetRegValue("TwoFactorCookie", null); if ((twoFactorCookie != null) && (twoFactorCookie != "")) { twoFactorCookie = "cookie=" + twoFactorCookie; } else { twoFactorCookie = null; } @@ -676,16 +691,21 @@ namespace MeshCentralRouter device.SubItems.Add(node.getStateString()); device.Tag = node; node.listitem = device; - } else { + } + else + { device = node.listitem; device.SubItems[0].Text = node.name; device.SubItems[1].Text = node.getStateString(); } if ((node.meshid != null) && meshcentral.meshes.ContainsKey(node.meshid)) { node.mesh = (MeshClass)meshcentral.meshes[node.meshid]; } - if ((showGroupNamesToolStripMenuItem.Checked) && (node.mesh != null)) { + if ((showGroupNamesToolStripMenuItem.Checked) && (node.mesh != null)) + { device.SubItems[0].Text = node.mesh.name + " - " + node.name; - } else { + } + else + { device.SubItems[0].Text = node.name; } @@ -702,7 +722,9 @@ namespace MeshCentralRouter { // Normal search if (connVisible && ((search == "") || (device.SubItems[0].Text.ToLower().IndexOf(search) >= 0))) { controlsToAdd.Add(device); } - } else { + } + else + { // User search bool userSearchMatch = false; if (node.users != null) { foreach (string user in node.users) { if (user.ToLower().IndexOf(userSearch) >= 0) { userSearchMatch = true; } } } @@ -711,7 +733,8 @@ namespace MeshCentralRouter } // Add all controls at once to make it fast. - if (controlsToAdd.Count > 0) { + if (controlsToAdd.Count > 0) + { devicesListView.Items.AddRange((ListViewItem[])controlsToAdd.ToArray(typeof(ListViewItem))); } } @@ -832,31 +855,41 @@ namespace MeshCentralRouter if (meshcentral == null) return; if (this.InvokeRequired) { this.Invoke(new MeshCentralServer.onStateChangedHandler(Meshcentral_onStateChanged), state); return; } - if (state == 0) { - if (meshcentral.disconnectMsg == "tokenrequired") { + if (state == 0) + { + if (meshcentral.disconnectMsg == "tokenrequired") + { emailTokenButton.Visible = (meshcentral.disconnectEmail2FA == true) && (meshcentral.disconnectEmail2FASent == false); tokenEmailSentLabel.Visible = (meshcentral.disconnectEmail2FASent == true) || (meshcentral.disconnectSms2FASent == true); smsTokenButton.Visible = ((meshcentral.disconnectSms2FA == true) && (meshcentral.disconnectSms2FASent == false)); if (meshcentral.disconnectEmail2FASent) { tokenEmailSentLabel.Text = Translate.T(Properties.Resources.EmailSent); } if (meshcentral.disconnectSms2FASent) { tokenEmailSentLabel.Text = Translate.T(Properties.Resources.SmsSent); } - if ((meshcentral.disconnectEmail2FA == true) && (meshcentral.disconnectEmail2FASent == false)) { + if ((meshcentral.disconnectEmail2FA == true) && (meshcentral.disconnectEmail2FASent == false)) + { smsTokenButton.Left = emailTokenButton.Left + emailTokenButton.Width + 5; - } else { + } + else + { smsTokenButton.Left = emailTokenButton.Left; } tokenTextBox.Text = ""; - if (meshcentral.twoFactorCookieDays > 0) { + if (meshcentral.twoFactorCookieDays > 0) + { tokenRememberCheckBox.Visible = true; tokenRememberCheckBox.Text = string.Format(Translate.T(Properties.Resources.DontAskXDays), meshcentral.twoFactorCookieDays); - } else { + } + else + { tokenRememberCheckBox.Visible = false; } setPanel(2); tokenTextBox.Focus(); - } else { setPanel(1); } + } + else { setPanel(1); } - if ((meshcentral.disconnectMsg != null) && meshcentral.disconnectMsg.StartsWith("noauth")) { + if ((meshcentral.disconnectMsg != null) && meshcentral.disconnectMsg.StartsWith("noauth")) + { stateLabel.Text = Translate.T(Properties.Resources.InvalidUsernameOrPassword); stateLabel.Visible = true; stateClearTimer.Enabled = true; @@ -876,7 +909,8 @@ namespace MeshCentralRouter stateClearTimer.Enabled = true; serverNameComboBox.Focus(); } - else if (meshcentral.disconnectMsg == "cert") { + else if (meshcentral.disconnectMsg == "cert") + { lastBadConnectCert = meshcentral.disconnectCert; certDetailsTextBox.Text = "---Issuer---\r\n" + lastBadConnectCert.Issuer.Replace(", ", "\r\n") + "\r\n\r\n---Subject---\r\n" + lastBadConnectCert.Subject.Replace(", ", "\r\n"); setPanel(3); @@ -892,14 +926,16 @@ namespace MeshCentralRouter this.Text = title; // Clean up all mappings - foreach (Control c in mapPanel.Controls) { + foreach (Control c in mapPanel.Controls) + { if (c.GetType() == typeof(MapUserControl)) { ((MapUserControl)c).Dispose(); } } mapPanel.Controls.Clear(); noMapLabel.Visible = true; // Clean up all devices (old style) - foreach (Control c in devicesPanel.Controls) { + foreach (Control c in devicesPanel.Controls) + { if (c.GetType() == typeof(DeviceUserControl)) { ((DeviceUserControl)c).Dispose(); } } remoteAllDeviceControls(); @@ -910,7 +946,8 @@ namespace MeshCentralRouter noDevicesLabel.Visible = true; if ((meshcentral != null) && (meshcentral.nodes != null)) { - foreach (NodeClass n in meshcentral.nodes.Values) { + foreach (NodeClass n in meshcentral.nodes.Values) + { if (n.desktopViewer != null) { n.desktopViewer.Close(); } if (n.fileViewer != null) { n.fileViewer.Close(); } } @@ -925,7 +962,9 @@ namespace MeshCentralRouter meshcentral.onNodesChanged -= Meshcentral_onNodesChanged; meshcentral = null; authLoginUrl = null; - } else if (state == 1) { + } + else if (state == 1) + { stateLabel.Visible = false; //setPanel(1); nextButton1.Enabled = false; @@ -933,7 +972,9 @@ namespace MeshCentralRouter userNameTextBox.Enabled = false; passwordTextBox.Enabled = false; cookieRefreshTimer.Enabled = false; - } else if (state == 2) { + } + else if (state == 2) + { meshcentral.disconnectMsg = "connected"; stateLabel.Visible = false; setPanel(4); @@ -943,9 +984,12 @@ namespace MeshCentralRouter Settings.SetRegValue("ServerName", serverNameComboBox.Text); Settings.SetRegValue("UserName", userNameTextBox.Text); } - if (meshcentral.username != null) { + if (meshcentral.username != null) + { this.Text = title + " - " + meshcentral.username; - } else { + } + else + { this.Text = title + " - " + userNameTextBox.Text; } cookieRefreshTimer.Enabled = true; @@ -954,7 +998,8 @@ namespace MeshCentralRouter if (tokenRememberCheckBox.Checked) { meshcentral.sendCommand("{\"action\":\"twoFactorCookie\"}"); } // Setup single instance pipe server - if (authLoginUrl != null) { + if (authLoginUrl != null) + { string urlstring = "wss://" + authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.LocalPath; localPipeServer = new LocalPipeServer(Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(urlstring))); // + "" + meshcentral.certHash localPipeServer.onArgs += LocalPipeServer_onArgs; @@ -980,6 +1025,7 @@ namespace MeshCentralRouter int autoLocalPort = 0; int autoProtocol = 0; int autoAppId = 0; + string autoAppIdStr = null; bool autoExit = false; try { @@ -988,7 +1034,8 @@ namespace MeshCentralRouter autoRemoteIp = getValueFromQueryString(authLoginUrl2.Query, "remoteip"); int.TryParse(getValueFromQueryString(authLoginUrl2.Query, "remoteport"), out autoRemotePort); int.TryParse(getValueFromQueryString(authLoginUrl2.Query, "protocol"), out autoProtocol); - int.TryParse(getValueFromQueryString(authLoginUrl2.Query, "appid"), out autoAppId); + autoAppIdStr = getValueFromQueryString(authLoginUrl2.Query, "appid"); + int.TryParse(autoAppIdStr, out autoAppId); autoExit = (getValueFromQueryString(authLoginUrl2.Query, "autoexit") == "1"); string localPortStr = getValueFromQueryString(authLoginUrl.Query, "localport"); if (localPortStr != null) { autoLocalPort = int.Parse(localPortStr); } @@ -1003,6 +1050,7 @@ namespace MeshCentralRouter map.Add("localPort", autoLocalPort); map.Add("protocol", autoProtocol); map.Add("appId", autoAppId); + map.Add("appIdStr", autoAppIdStr); map.Add("autoExit", autoExit); map.Add("launch", 1); mappingsToSetup = new ArrayList(); @@ -1023,7 +1071,8 @@ namespace MeshCentralRouter if ((map.protocol == 2) && (map.mapper.totalConnectCounter == 0)) { // This is an unconnected UDP map, check if the target node is connected. - foreach (NodeClass n in meshcentral.nodes.Values) { + foreach (NodeClass n in meshcentral.nodes.Values) + { if ((map.node == n) && ((n.conn & 1) != 0)) { // Reconnect the UDP map @@ -1087,6 +1136,7 @@ namespace MeshCentralRouter map.localPort = (int)localPort; map.remotePort = (int)remotePort; map.appId = appId; + if (appId == 0) { map.appIdStr = x[3].ToLower(); } map.node = node; if (authLoginUrl != null) { map.host = authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.AbsolutePath.Replace("/control.ashx", ""); } else { map.host = serverNameComboBox.Text; } map.certhash = meshcentral.wshash; @@ -1148,6 +1198,7 @@ namespace MeshCentralRouter map.remoteIP = remoteIp.ToString(); map.remotePort = (int)remotePort; map.appId = appId; + if (appId == 0) { map.appIdStr = x[3].ToLower(); } map.node = node; if (authLoginUrl != null) { map.host = authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.AbsolutePath.Replace("/control.ashx", ""); } else { map.host = serverNameComboBox.Text; } map.certhash = meshcentral.wshash; @@ -1188,6 +1239,7 @@ namespace MeshCentralRouter map.localPort = form.getLocalPort(); map.remotePort = form.getRemotePort(); map.appId = form.getAppId(); + map.appIdStr = form.getAppIdStr(); map.node = form.getNode(); if (authLoginUrl != null) { map.host = authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.AbsolutePath.Replace("/control.ashx", ""); } else { map.host = serverNameComboBox.Text; } map.certhash = meshcentral.wshash; @@ -1221,12 +1273,15 @@ namespace MeshCentralRouter openWebSiteButton.Visible = false; Uri serverurl = null; - if (authLoginUrl != null) { + if (authLoginUrl != null) + { string loginkey = getValueFromQueryString(authLoginUrl.Query, "key"); string urlstring = "wss://" + authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.LocalPath + "?auth=" + getValueFromQueryString(authLoginUrl.Query, "c"); if (loginkey != null) { urlstring += ("&key=" + loginkey); } serverurl = new Uri(urlstring); - } else { + } + else + { int keyIndex = serverNameComboBox.Text.IndexOf("?key="); if (keyIndex >= 0) { @@ -1244,9 +1299,12 @@ namespace MeshCentralRouter meshcentral.debug = debug; meshcentral.tlsdump = tlsdump; meshcentral.ignoreCert = ignoreCert; - if (lastBadConnectCert != null) { + if (lastBadConnectCert != null) + { meshcentral.okCertHash = lastBadConnectCert.GetCertHashString(); - } else { + } + else + { string ignoreCert = Settings.GetRegValue("IgnoreCert", null); if (ignoreCert != null) { meshcentral.okCertHash = ignoreCert; } } @@ -1346,6 +1404,7 @@ namespace MeshCentralRouter map.remotePort = form.getRemotePort(); map.remoteIP = form.getRemoteIP(); map.appId = form.getAppId(); + map.appIdStr = form.getAppIdStr(); map.node = form.getNode(); if (authLoginUrl != null) { map.host = authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.AbsolutePath.Replace("/control.ashx", ""); } else { map.host = serverNameComboBox.Text; } map.certhash = meshcentral.wshash; @@ -1367,13 +1426,17 @@ namespace MeshCentralRouter private void openWebSiteButton_Click(object sender, EventArgs e) { cancelAutoClose(); - if (meshcentral.loginCookie != null) { + if (meshcentral.loginCookie != null) + { Uri serverurl = null; - if (authLoginUrl != null) { + if (authLoginUrl != null) + { string localPath = authLoginUrl.LocalPath; if (localPath.EndsWith("/control.ashx")) { localPath = localPath.Substring(0, localPath.Length - 12); } serverurl = new Uri("https://" + authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + localPath + "?login=" + meshcentral.loginCookie); - } else { + } + else + { serverurl = new Uri("https://" + serverNameComboBox.Text + "?login=" + meshcentral.loginCookie); } System.Diagnostics.Process.Start(serverurl.ToString()); @@ -1413,11 +1476,14 @@ namespace MeshCentralRouter if (f.ShowDialog(this) == DialogResult.OK) { inaddrany = f.BindAllInterfaces; - if (f.ShowSystemTray) { + if (f.ShowSystemTray) + { notifyIcon.Visible = true; this.ShowInTaskbar = false; this.MinimizeBox = false; - } else { + } + else + { notifyIcon.Visible = false; this.ShowInTaskbar = true; this.MinimizeBox = true; @@ -1427,10 +1493,13 @@ namespace MeshCentralRouter private void searchTextBox_TextChanged(object sender, EventArgs e) { - if (deviceListViewMode) { + if (deviceListViewMode) + { // Filter devices updateDeviceList(); - } else { + } + else + { // Filter devices int visibleDevices = 0; int deviceCount = 0; @@ -1464,9 +1533,12 @@ namespace MeshCentralRouter { cancelAutoClose(); searchTextBox.Visible = (devicesTabControl.SelectedIndex == 0); - if (devicesTabControl.SelectedIndex == 0) { + if (devicesTabControl.SelectedIndex == 0) + { menuLabel.ContextMenuStrip = mainContextMenuStrip; - } else { + } + else + { menuLabel.ContextMenuStrip = mappingsContextMenuStrip; } } @@ -1502,6 +1574,44 @@ namespace MeshCentralRouter map.localPort = 0; // Any map.remotePort = port; // HTTP map.appId = appId; // 0 = Custom, 1 = HTTP, 2 = HTTPS, 3 = RDP, 4 = PuTTY, 5 = WinSCP + map.appIdStr = null; + map.node = node; + if (authLoginUrl != null) { map.host = authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.AbsolutePath.Replace("/control.ashx", ""); } else { map.host = serverNameComboBox.Text; } + map.certhash = meshcentral.wshash; + map.parent = this; + map.Dock = DockStyle.Top; + map.Start(); + mapPanel.Controls.Add(map); + noMapLabel.Visible = false; + map.appButton_Click(this, null); + } + + public void QuickMap(int protocol, int port, string appIdStr, NodeClass node) + { + // See if we already have the right port mapping + foreach (Control c in mapPanel.Controls) + { + if (c.GetType() == typeof(MapUserControl)) + { + MapUserControl cc = (MapUserControl)c; + if ((cc.protocol == protocol) && (cc.remotePort == port) && (cc.appIdStr == appIdStr) && (cc.node == node)) + { + // Found a match + cc.appButton_Click(this, null); + return; + } + } + } + + // Add a new port map + MapUserControl map = new MapUserControl(); + map.xdebug = debug; + map.inaddrany = false; // Loopback only + map.protocol = protocol; // 1 = TCP, 2 = UDP + map.localPort = 0; // Any + map.remotePort = port; // HTTP + map.appId = 0; // 0 = Custom, 1 = HTTP, 2 = HTTPS, 3 = RDP, 4 = PuTTY, 5 = WinSCP + map.appIdStr = appIdStr; map.node = node; if (authLoginUrl != null) { map.host = authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.AbsolutePath.Replace("/control.ashx", ""); } else { map.host = serverNameComboBox.Text; } map.certhash = meshcentral.wshash; @@ -1535,7 +1645,7 @@ namespace MeshCentralRouter private void tokenTextBox_KeyUp(object sender, KeyEventArgs e) { - nextButton2.Enabled = (tokenTextBox.Text.Replace(" ","") != ""); + nextButton2.Enabled = (tokenTextBox.Text.Replace(" ", "") != ""); } private void tokenTextBox_TextChanged(object sender, EventArgs e) @@ -1566,7 +1676,7 @@ namespace MeshCentralRouter private void hideOfflineDevicesToolStripMenuItem_Click(object sender, EventArgs e) { showOfflineDevicesToolStripMenuItem.Checked = !showOfflineDevicesToolStripMenuItem.Checked; - Settings.SetRegValue("Show Offline Devices", showOfflineDevicesToolStripMenuItem.Checked?"1":"0"); + Settings.SetRegValue("Show Offline Devices", showOfflineDevicesToolStripMenuItem.Checked ? "1" : "0"); updateDeviceList(); } @@ -1626,7 +1736,8 @@ namespace MeshCentralRouter if (jsonAction["mappings"] != null) { ArrayList mappings = (ArrayList)jsonAction["mappings"]; - if (mappings.Count > 0) { + if (mappings.Count > 0) + { mappingsToSetup = mappings; if (mode == 2) { setupMappings(); } } @@ -1678,9 +1789,10 @@ namespace MeshCentralRouter if (x.ContainsKey("remoteIP")) { map.remoteIP = (string)x["remoteIP"]; } map.remotePort = (int)x["remotePort"]; map.appId = (int)x["appId"]; + if (x["appIdStr"] != null) { map.appIdStr = (string)x["appIdStr"]; } if (x.ContainsKey("autoExit")) { map.autoexit = (bool)x["autoExit"]; } map.node = node; - if (authLoginUrl != null) { map.host = authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.AbsolutePath.Replace("/control.ashx",""); } else { map.host = serverNameComboBox.Text; } + if (authLoginUrl != null) { map.host = authLoginUrl.Host + ":" + ((authLoginUrl.Port > 0) ? authLoginUrl.Port : 443) + authLoginUrl.AbsolutePath.Replace("/control.ashx", ""); } else { map.host = serverNameComboBox.Text; } map.certhash = meshcentral.wshash; map.parent = this; map.Dock = DockStyle.Top; @@ -1726,6 +1838,7 @@ namespace MeshCentralRouter text += " \"meshId\": \"" + mapCtrl.node.meshid + "\",\r\n"; text += " \"nodeId\": \"" + mapCtrl.node.nodeid + "\",\r\n"; text += " \"appId\": " + mapCtrl.appId + ",\r\n"; + if (mapCtrl.appIdStr != null) { text += " \"appIdStr\": \"" + mapCtrl.appIdStr + "\",\r\n"; } text += " \"protocol\": " + map.protocol + ",\r\n"; text += " \"localPort\": " + map.localport + ",\r\n"; if (map.remoteip != null) { text += " \"remoteIP\": \"" + map.remoteip + "\",\r\n"; } @@ -2003,6 +2116,14 @@ namespace MeshCentralRouter cancelAutoClose(); } + private void customAppsToolStripMenuItem_Click(object sender, EventArgs e) + { + CustomAppsForm f = new CustomAppsForm(Settings.GetApplications()); + if (f.ShowDialog(this) == DialogResult.OK) { + Settings.SetApplications(f.getApplications()); + } + } + /* private delegate void displayMessageHandler(string msg, int buttons, string extra, int progress); private void displayMessage(string msg, int buttons = 0, string extra = "", int progress = 0) diff --git a/MainForm.resx b/MainForm.resx index 8f90901..f067527 100644 --- a/MainForm.resx +++ b/MainForm.resx @@ -129,13 +129,10 @@ - 15, 354 - - - 4, 4, 4, 4 + 11, 286 - 127, 28 + 95, 23 @@ -172,13 +169,10 @@ NoControl - 321, 277 - - - 4, 0, 4, 0 + 241, 225 - 114, 17 + 88, 13 19 @@ -208,13 +202,10 @@ NoControl - 317, 217 - - - 4, 0, 4, 0 + 238, 176 - 69, 17 + 53, 13 18 @@ -241,13 +232,10 @@ NoControl - 317, 166 - - - 4, 0, 4, 0 + 238, 135 - 73, 17 + 55, 13 17 @@ -274,13 +262,10 @@ NoControl - 317, 113 - - - 4, 0, 4, 0 + 238, 92 - 50, 17 + 38, 13 16 @@ -304,16 +289,13 @@ Top, Left, Right - 321, 236 - - - 4, 4, 4, 4 + 241, 192 - 287, 22 + 214, 20 102 @@ -337,13 +319,10 @@ meshcentral.com - 321, 135 - - - 4, 4, 4, 4 + 241, 110 - 287, 24 + 214, 21 100 @@ -364,13 +343,10 @@ Top, Left, Right - 321, 186 - - - 4, 4, 4, 4 + 241, 151 - 287, 22 + 214, 20 101 @@ -394,13 +370,10 @@ NoControl - 235, 323 - - - 4, 0, 4, 0 + 174, 260 - 404, 16 + 303, 13 103 @@ -433,13 +406,10 @@ NoControl - 4, 323 - - - 4, 0, 4, 0 + 3, 260 - 47, 17 + 37, 13 11 @@ -466,13 +436,10 @@ NoControl - 498, 354 - - - 4, 4, 4, 4 + 372, 286 - 127, 28 + 95, 23 105 @@ -499,13 +466,10 @@ NoControl - 0, 343 - - - 4, 4, 4, 4 + 0, 277 - 640, 49 + 478, 40 StretchImage @@ -532,13 +496,10 @@ NoControl - 16, 11 - - - 4, 0, 4, 0 + 12, 9 - 608, 69 + 454, 56 6 @@ -565,13 +526,10 @@ NoControl - 20, 84 - - - 4, 4, 4, 4 + 15, 68 - 292, 212 + 217, 170 Zoom @@ -595,13 +553,10 @@ Fill - 4, 4 - - - 4, 4, 4, 4 + 3, 3 - 640, 392 + 478, 316 6 @@ -619,16 +574,13 @@ 0 - 4, 28 - - - 4, 4, 4, 4 + 4, 25 - 4, 4, 4, 4 + 3, 3, 3, 3 - 648, 400 + 484, 322 0 @@ -655,13 +607,10 @@ NoControl - 321, 272 - - - 4, 4, 4, 4 + 241, 221 - 170, 21 + 131, 17 204 @@ -688,13 +637,10 @@ NoControl - 321, 218 - - - 4, 4, 4, 4 + 241, 177 - 127, 28 + 95, 23 202 @@ -721,13 +667,10 @@ NoControl - 456, 218 - - - 4, 4, 4, 4 + 342, 177 - 127, 28 + 95, 23 203 @@ -757,13 +700,10 @@ NoControl - 317, 224 - - - 4, 0, 4, 0 + 238, 182 - 73, 17 + 55, 13 21 @@ -793,13 +733,10 @@ NoControl - 317, 166 - - - 4, 0, 4, 0 + 238, 135 - 48, 17 + 38, 13 19 @@ -823,13 +760,10 @@ Top, Left, Right - 321, 186 - - - 4, 4, 4, 4 + 241, 151 - 287, 22 + 214, 20 201 @@ -853,13 +787,10 @@ NoControl - 20, 84 - - - 4, 4, 4, 4 + 15, 68 - 272, 212 + 202, 170 Zoom @@ -886,13 +817,10 @@ NoControl - 363, 354 - - - 4, 4, 4, 4 + 270, 286 - 127, 28 + 95, 23 205 @@ -919,13 +847,10 @@ NoControl - 498, 354 - - - 4, 4, 4, 4 + 372, 286 - 127, 28 + 95, 23 206 @@ -952,13 +877,10 @@ NoControl - 0, 343 - - - 4, 4, 4, 4 + 0, 277 - 640, 49 + 478, 40 StretchImage @@ -985,13 +907,10 @@ NoControl - 16, 11 - - - 4, 0, 4, 0 + 12, 9 - 608, 69 + 454, 56 6 @@ -1015,13 +934,10 @@ Fill - 4, 4 - - - 4, 4, 4, 4 + 3, 3 - 640, 392 + 478, 316 7 @@ -1039,16 +955,13 @@ 0 - 4, 28 - - - 4, 4, 4, 4 + 4, 25 - 4, 4, 4, 4 + 3, 3, 3, 3 - 648, 400 + 484, 322 1 @@ -1075,13 +988,10 @@ True - 277, 318 - - - 4, 4, 4, 4 + 208, 256 - 190, 21 + 145, 17 302 @@ -1105,10 +1015,7 @@ Top, Bottom, Left, Right - 20, 101 - - - 4, 4, 4, 4 + 15, 82 True @@ -1117,7 +1024,7 @@ Vertical - 602, 202 + 450, 162 25 @@ -1141,13 +1048,10 @@ NoControl - 19, 313 - - - 4, 4, 4, 4 + 14, 251 - 251, 28 + 188, 23 301 @@ -1177,13 +1081,10 @@ NoControl - 11, 7 - - - 4, 0, 4, 0 + 8, 6 - 627, 27 + 468, 22 23 @@ -1213,13 +1114,10 @@ NoControl - 16, 42 - - - 4, 0, 4, 0 + 12, 34 - 608, 55 + 454, 45 22 @@ -1246,13 +1144,10 @@ NoControl - 371, 362 - - - 4, 4, 4, 4 + 276, 291 - 127, 28 + 95, 23 303 @@ -1279,13 +1174,10 @@ NoControl - 506, 362 - - - 4, 4, 4, 4 + 378, 291 - 127, 28 + 95, 23 304 @@ -1312,13 +1204,10 @@ NoControl - 0, 351 - - - 4, 4, 4, 4 + 0, 282 - 648, 49 + 484, 40 StretchImage @@ -1344,11 +1233,8 @@ 0, 0 - - 4, 4, 4, 4 - - 648, 400 + 484, 322 8 @@ -1366,13 +1252,10 @@ 0 - 4, 28 - - - 4, 4, 4, 4 + 4, 25 - 648, 400 + 484, 322 2 @@ -1402,43 +1285,49 @@ 613, 17 - 218, 26 + 185, 22 Show &Group Names - 218, 26 + 185, 22 Show &Offline Devices - 215, 6 + 182, 6 - 218, 26 + 185, 22 Sort by &Name - 218, 26 + 185, 22 Sort by G&roup - 215, 6 + 182, 6 - 218, 26 + 185, 22 S&ettings... + + 185, 22 + + + &Custom Apps... + - 219, 146 + 186, 170 mainContextMenuStrip @@ -1453,13 +1342,10 @@ NoControl - 608, 2 - - - 4, 0, 4, 0 + 454, 2 - 31, 31 + 25, 25 403 @@ -1483,13 +1369,10 @@ Top, Right - 411, 6 - - - 4, 4, 4, 4 + 306, 5 - 193, 22 + 146, 20 402 @@ -1522,13 +1405,10 @@ Bottom, Left - 5, 210 - - - 4, 4, 4, 4 + 4, 167 - 224, 43 + 168, 35 405 @@ -1570,82 +1450,82 @@ Segoe UI, 9pt, style=Bold - 198, 24 + 170, 22 Add &Map... - 198, 24 + 170, 22 Add &Relay Map... - 195, 6 + 167, 6 - 204, 26 + 171, 22 Ask Consent + Bar - 204, 26 + 171, 22 Ask Consent - 204, 26 + 171, 22 Privacy Bar - 198, 24 + 170, 22 Remote Desktop... - 198, 24 + 170, 22 Remote Files... - 198, 24 + 170, 22 HTTP - 198, 24 + 170, 22 HTTPS - 198, 24 + 170, 22 RDP - 198, 24 + 170, 22 SSH - 198, 24 + 170, 22 SCP - 199, 226 + 171, 208 devicesContextMenuStrip @@ -1661,7 +1541,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADg - HQAAAk1TRnQBSQFMAgEBEAEAAYABAAGAAQABEAEAARABAAT/ARkBAAj/AUIBTQE2BwABNgMAASgDAAFA + HQAAAk1TRnQBSQFMAgEBEAEAAYgBAAGIAQABEAEAARABAAT/ARkBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABUAMAAQEBAAEYBgABPP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AJYAA/0D+AP3A/sD/yEAA/0D+gP5 A/wD/xgAAfoB+wH6A/4qAAP9A/8tAAP7A88D1QPbA88D1AO+A9QYAAP8A90D4APjA90D4APUA+MSAAP8 AZEBjwF9AU4BaAEhAfQB9QH0JAAD/gPRA8YD+ioAAcYCxwHPAtAB2ALZA90DywPBA68DmgP3FQAD2APd @@ -1792,13 +1672,10 @@ - 13, 5 - - - 4, 4, 4, 4 + 10, 4 - 593, 258 + 446, 210 404 @@ -1828,13 +1705,10 @@ NoControl - 3, 108 - - - 4, 0, 4, 0 + 2, 88 - 530, 64 + 392, 52 5 @@ -1870,13 +1744,10 @@ NoControl - 3, 108 - - - 4, 0, 4, 0 + 2, 88 - 530, 64 + 392, 52 4 @@ -1902,11 +1773,8 @@ 0, 0 - - 4, 4, 4, 4 - - 628, 305 + 470, 248 50 @@ -1924,16 +1792,13 @@ 0 - 4, 28 - - - 4, 4, 4, 4 + 4, 25 - 4, 4, 4, 4 + 3, 3, 3, 3 - 632, 315 + 470, 250 0 @@ -1960,13 +1825,10 @@ NoControl - 5, 217 - - - 4, 4, 4, 4 + 4, 182 - 224, 43 + 168, 35 55 @@ -2005,13 +1867,10 @@ NoControl - 8, 97 - - - 4, 0, 4, 0 + 6, 79 - 595, 64 + 446, 52 4 @@ -2039,11 +1898,8 @@ Click "Add" to get started. 0, 0 - - 4, 4, 4, 4 - - 625, 264 + 472, 221 49 @@ -2067,13 +1923,10 @@ Click "Add" to get started. NoControl - 1, 271 - - - 4, 4, 4, 4 + 1, 226 - 27, 25 + 20, 20 54 @@ -2097,13 +1950,10 @@ Click "Add" to get started. NoControl - 317, 271 - - - 4, 4, 4, 4 + 240, 226 - 27, 25 + 20, 20 5 @@ -2130,13 +1980,10 @@ Click "Add" to get started. NoControl - 493, 268 - - - 4, 4, 4, 4 + 372, 223 - 133, 28 + 100, 23 50 @@ -2166,13 +2013,10 @@ Click "Add" to get started. NoControl - 352, 268 - - - 4, 4, 4, 4 + 266, 223 - 133, 28 + 100, 23 52 @@ -2193,16 +2037,13 @@ Click "Add" to get started. 5 - 4, 28 - - - 4, 4, 4, 4 + 4, 25 - 4, 4, 4, 4 + 3, 3, 3, 3 - 629, 311 + 472, 253 1 @@ -2223,13 +2064,10 @@ Click "Add" to get started. 1 - 4, 4 - - - 4, 4, 4, 4 + 3, 3 - 640, 347 + 478, 279 401 @@ -2253,13 +2091,10 @@ Click "Add" to get started. NoControl - 20, 362 - - - 4, 4, 4, 4 + 15, 291 - 145, 28 + 109, 23 406 @@ -2289,13 +2124,10 @@ Click "Add" to get started. NoControl - 371, 362 - - - 4, 4, 4, 4 + 276, 291 - 127, 28 + 95, 23 407 @@ -2322,13 +2154,10 @@ Click "Add" to get started. NoControl - 506, 362 - - - 4, 4, 4, 4 + 378, 291 - 127, 28 + 95, 23 408 @@ -2355,13 +2184,10 @@ Click "Add" to get started. NoControl - 0, 351 - - - 4, 4, 4, 4 + 0, 282 - 648, 49 + 484, 40 StretchImage @@ -2387,11 +2213,8 @@ Click "Add" to get started. 0, 0 - - 4, 4, 4, 4 - - 648, 400 + 484, 322 8 @@ -2409,13 +2232,10 @@ Click "Add" to get started. 0 - 4, 28 - - - 4, 4, 4, 4 + 4, 25 - 648, 400 + 484, 322 4 @@ -2445,7 +2265,7 @@ Click "Add" to get started. 0, 0, 0, 0 - 656, 432 + 492, 351 8 @@ -2469,13 +2289,10 @@ Click "Add" to get started. Fill - 0, 80 - - - 4, 4, 4, 4 + 0, 65 - 656, 432 + 492, 351 9 @@ -2501,11 +2318,8 @@ Click "Add" to get started. 0, 0 - - 4, 4, 4, 4 - - 656, 80 + 492, 65 Zoom @@ -2531,11 +2345,8 @@ Click "Add" to get started. 0, 0 - - 4, 4, 4, 4 - - 656, 512 + 492, 416 8 @@ -2565,22 +2376,22 @@ Click "Add" to get started. 418, 17 - 123, 24 + 112, 22 &Open... - 120, 6 + 109, 6 - 123, 24 + 112, 22 E&xit - 124, 58 + 113, 54 trayIconContextMenuStrip @@ -4292,28 +4103,34 @@ Click "Add" to get started. 905, 17 - 193, 24 + 168, 22 &Open Mappings... - 193, 24 + 168, 22 &Save Mappings... - 190, 6 + 165, 6 - 193, 24 + 168, 22 S&ettings... + + 168, 22 + + + &Custom Apps... + - 194, 82 + 169, 98 mappingsContextMenuStrip @@ -4343,10 +4160,10 @@ Click "Add" to get started. True - 8, 16 + 6, 13 - 656, 512 + 492, 416 @@ -6042,9 +5859,6 @@ Click "Add" to get started. AADAPwAAwD8AAMA/AADAPwAA - - 4, 4, 4, 4 - MeshCentral Router @@ -6264,6 +6078,18 @@ Click "Add" to get started. System.Windows.Forms.SaveFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + customAppsToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + customAppsToolStripMenuItem1 + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + MainForm diff --git a/MapUserControl.cs b/MapUserControl.cs index 3a78f6b..70bd89e 100644 --- a/MapUserControl.cs +++ b/MapUserControl.cs @@ -31,6 +31,7 @@ namespace MeshCentralRouter public string remoteIP = null; public int remotePort; public int appId; + public string appIdStr; public NodeClass node; public MainForm parent; public MeshMapper mapper; @@ -72,7 +73,7 @@ namespace MeshCentralRouter public void Start() { routingStatusLabel.Text = Translate.T(Properties.Resources.Starting); - appButton.Enabled = (appId != 0); + appButton.Enabled = (appId != 0) || (appIdStr != null); mapper = new MeshMapper(); mapper.xdebug = xdebug; mapper.inaddrany = inaddrany; @@ -110,7 +111,8 @@ namespace MeshCentralRouter if (protocol == 2) { statemsg = "UDP: " + statemsg; } else { - if (appId == 1) { statemsg = "HTTP: " + statemsg; } + if ((appId == 0) && (appIdStr != null)) { statemsg = appIdStr + ": " + statemsg; } + else if (appId == 1) { statemsg = "HTTP: " + statemsg; } else if (appId == 2) { statemsg = "HTTPS: " + statemsg; } else if (appId == 3) { statemsg = "RDP: " + statemsg; } else if (appId == 4) { statemsg = "PuTTY: " + statemsg; } @@ -125,6 +127,28 @@ namespace MeshCentralRouter bool shift = false; if (Control.ModifierKeys == Keys.Shift) { shift = true; } + if (appId == 0) + { + if (appIdStr == null) return; + string appCmd = null; + List apps = Settings.GetApplications(); + foreach (String[] app in apps) { if (app[1].ToLower() == appIdStr.ToLower()) { appCmd = app[2]; } } + appCmd = appCmd.Replace("%P", mapper.localport.ToString()).Replace("%L", "127.0.0.1"); + string appArgs = null; + int i = appCmd.IndexOf(' '); + if (i >= 0) { appArgs = appCmd.Substring(i + 1); appCmd = appCmd.Substring(0, i); } + if (appCmd != null) + { + // Launch the process + System.Diagnostics.Process proc = null; + try { proc = System.Diagnostics.Process.Start(appCmd, appArgs); } catch (System.ComponentModel.Win32Exception) { } + + // Setup auto-exit + if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; } + autoexit = false; + } + return; + } if (appId == 1) { System.Diagnostics.Process.Start("http://localhost:" + mapper.localport); } if (appId == 2) { System.Diagnostics.Process.Start("https://localhost:" + mapper.localport); } if (appId == 3) @@ -153,6 +177,7 @@ namespace MeshCentralRouter // Setup auto-exit if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; } + autoexit = false; } if (appId == 4) { @@ -179,6 +204,7 @@ namespace MeshCentralRouter // Setup auto-exit if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; } + autoexit = false; } else { @@ -209,6 +235,7 @@ namespace MeshCentralRouter // Setup auto-exit if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; } + autoexit = false; } } } @@ -226,6 +253,7 @@ namespace MeshCentralRouter // Setup auto-exit if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; } + autoexit = false; } else { @@ -246,6 +274,7 @@ namespace MeshCentralRouter // Setup auto-exit if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; } + autoexit = false; } } } diff --git a/MeshCentralRouter.csproj b/MeshCentralRouter.csproj index cf4c028..1f8c4d3 100644 --- a/MeshCentralRouter.csproj +++ b/MeshCentralRouter.csproj @@ -94,6 +94,24 @@ AddRelayMapForm.cs + + Form + + + CustomAppsAddForm.cs + + + Form + + + CustomAppsForm.cs + + + Form + + + CustomAppsRunForm.cs + Form @@ -274,6 +292,15 @@ AddRelayMapForm.cs + + CustomAppsAddForm.cs + + + CustomAppsForm.cs + + + CustomAppsRunForm.cs + FileConfirmOverwriteForm.cs diff --git a/Settings.cs b/Settings.cs index 27583fc..f21fa91 100644 --- a/Settings.cs +++ b/Settings.cs @@ -15,6 +15,7 @@ limitations under the License. */ using Microsoft.Win32; +using System.Collections.Generic; using System; namespace MeshCentralRouter @@ -53,5 +54,53 @@ namespace MeshCentralRouter { try { return bool.Parse(GetRegValue(name, value.ToString())); } catch (Exception) { return value; } } + + public static void SetApplications(List apps) + { + ClearApplications(); + using (RegistryKey key = Registry.CurrentUser.CreateSubKey(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router\Applications", true)) + { + foreach (string[] app in apps) + { + using (RegistryKey skey = key.CreateSubKey(app[0])) + { + skey.SetValue("Protocol", app[1]); + skey.SetValue("Command", app[2]); + } + } + } + } + + public static List GetApplications() + { + List apps = new List(); + using (RegistryKey key = Registry.CurrentUser.CreateSubKey(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router\Applications\", false)) + { + string[] keys = key.GetSubKeyNames(); + foreach (string k in keys) + { + using (RegistryKey key2 = Registry.CurrentUser.OpenSubKey(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router\Applications\" + k, false)) + { + string protocol = (string)key2.GetValue("Protocol"); + string command = (string)key2.GetValue("Command"); + String[] a = new string[3]; + a[0] = k; + a[1] = protocol; + a[2] = command; + apps.Add(a); + } + } + } + return apps; + } + + //public static void DeleteSubKeyTree(RegistryKey key, string subkey) { if (key.OpenSubKey(subkey) == null) { return; } DeleteSubKeyTree(key, subkey); } + + public static void ClearApplications() + { + RegistryKey key = Registry.CurrentUser.CreateSubKey(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router", true); + key.DeleteSubKeyTree("Applications"); + key.Close(); + } } } From 957bdb2648de77fd832804fa044fbaead1eab28c Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 12 May 2022 17:10:21 -0700 Subject: [PATCH 17/20] Added edit/run buttons on custom apps. --- CustomAppsForm.Designer.cs | 28 ++++++++++++++++++++++++++++ CustomAppsForm.cs | 1 + CustomAppsRunForm.Designer.cs | 1 + 3 files changed, 30 insertions(+) diff --git a/CustomAppsForm.Designer.cs b/CustomAppsForm.Designer.cs index a270a76..e124ecd 100644 --- a/CustomAppsForm.Designer.cs +++ b/CustomAppsForm.Designer.cs @@ -46,6 +46,8 @@ this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); this.addToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.editButton = new System.Windows.Forms.Button(); + this.runButton = new System.Windows.Forms.Button(); this.groupBox1.SuspendLayout(); this.appContextMenuStrip.SuspendLayout(); this.SuspendLayout(); @@ -90,6 +92,8 @@ this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.runButton); + this.groupBox1.Controls.Add(this.editButton); this.groupBox1.Controls.Add(this.removeButton); this.groupBox1.Controls.Add(this.addButton); this.groupBox1.Controls.Add(this.mainListView); @@ -201,6 +205,28 @@ this.addToolStripMenuItem.Text = "&Add..."; this.addToolStripMenuItem.Click += new System.EventHandler(this.addButton_Click); // + // editButton + // + this.editButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.editButton.Location = new System.Drawing.Point(137, 185); + this.editButton.Name = "editButton"; + this.editButton.Size = new System.Drawing.Size(75, 23); + this.editButton.TabIndex = 3; + this.editButton.Text = "Edit..."; + this.editButton.UseVisualStyleBackColor = true; + this.editButton.Click += new System.EventHandler(this.editToolStripMenuItem_Click); + // + // runButton + // + this.runButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.runButton.Location = new System.Drawing.Point(56, 185); + this.runButton.Name = "runButton"; + this.runButton.Size = new System.Drawing.Size(75, 23); + this.runButton.TabIndex = 4; + this.runButton.Text = "Run..."; + this.runButton.UseVisualStyleBackColor = true; + this.runButton.Click += new System.EventHandler(this.runToolStripMenuItem_Click); + // // CustomAppsForm // this.AcceptButton = this.okButton; @@ -244,5 +270,7 @@ private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; private System.Windows.Forms.ToolStripMenuItem addToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; + private System.Windows.Forms.Button editButton; + private System.Windows.Forms.Button runButton; } } \ No newline at end of file diff --git a/CustomAppsForm.cs b/CustomAppsForm.cs index ad08834..6403d6d 100644 --- a/CustomAppsForm.cs +++ b/CustomAppsForm.cs @@ -78,6 +78,7 @@ namespace MeshCentralRouter private void UpdateInfo() { removeButton.Enabled = (mainListView.SelectedItems.Count > 0); + runButton.Enabled = editButton.Enabled = (mainListView.SelectedItems.Count == 1); } private void removeButton_Click(object sender, EventArgs e) diff --git a/CustomAppsRunForm.Designer.cs b/CustomAppsRunForm.Designer.cs index 5d4bd43..0886598 100644 --- a/CustomAppsRunForm.Designer.cs +++ b/CustomAppsRunForm.Designer.cs @@ -168,6 +168,7 @@ this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "CustomAppsRunForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Test Application"; this.Load += new System.EventHandler(this.CustomAppsRunForm_Load); this.groupBox1.ResumeLayout(false); From f6c44b1d427a91711d10b0ff06c23da891dce283 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Fri, 13 May 2022 00:06:58 -0700 Subject: [PATCH 18/20] Fixed custom apps. --- CustomAppsAddForm.Designer.cs | 71 ++++++++++++++++++++----------- CustomAppsAddForm.cs | 15 +++---- CustomAppsForm.cs | 48 ++++++++++++--------- CustomAppsRunForm.Designer.cs | 80 ++++++++++++++++++++++++++++------- CustomAppsRunForm.cs | 11 +++-- MapUserControl.cs | 11 ++--- Settings.cs | 7 +-- 7 files changed, 162 insertions(+), 81 deletions(-) diff --git a/CustomAppsAddForm.Designer.cs b/CustomAppsAddForm.Designer.cs index 19f68e9..9159380 100644 --- a/CustomAppsAddForm.Designer.cs +++ b/CustomAppsAddForm.Designer.cs @@ -38,9 +38,11 @@ this.commandTextBox = new System.Windows.Forms.TextBox(); this.label3 = new System.Windows.Forms.Label(); this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.label4 = new System.Windows.Forms.Label(); this.selectFileButton = new System.Windows.Forms.Button(); + this.label4 = new System.Windows.Forms.Label(); this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.label5 = new System.Windows.Forms.Label(); + this.argsTextBox = new System.Windows.Forms.TextBox(); this.groupBox1.SuspendLayout(); this.SuspendLayout(); // @@ -48,7 +50,7 @@ // this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.okButton.ImeMode = System.Windows.Forms.ImeMode.NoControl; - this.okButton.Location = new System.Drawing.Point(244, 160); + this.okButton.Location = new System.Drawing.Point(244, 190); this.okButton.Name = "okButton"; this.okButton.Size = new System.Drawing.Size(75, 23); this.okButton.TabIndex = 4; @@ -61,7 +63,7 @@ this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.cancelButton.ImeMode = System.Windows.Forms.ImeMode.NoControl; - this.cancelButton.Location = new System.Drawing.Point(325, 160); + this.cancelButton.Location = new System.Drawing.Point(325, 190); this.cancelButton.Name = "cancelButton"; this.cancelButton.Size = new System.Drawing.Size(75, 23); this.cancelButton.TabIndex = 5; @@ -116,14 +118,17 @@ this.label3.AutoSize = true; this.label3.Location = new System.Drawing.Point(6, 74); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(54, 13); + this.label3.Size = new System.Drawing.Size(85, 13); this.label3.TabIndex = 10; - this.label3.Text = "Command"; + this.label3.Text = "Executable Path"; // // groupBox1 // - this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.argsTextBox); this.groupBox1.Controls.Add(this.selectFileButton); this.groupBox1.Controls.Add(this.nameTextBox); this.groupBox1.Controls.Add(this.label3); @@ -131,29 +136,16 @@ this.groupBox1.Controls.Add(this.label2); this.groupBox1.Controls.Add(this.protocolTextBox); this.groupBox1.Controls.Add(this.label1); - this.groupBox1.Location = new System.Drawing.Point(12, 56); + this.groupBox1.Location = new System.Drawing.Point(12, 57); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(388, 98); + this.groupBox1.Size = new System.Drawing.Size(388, 127); this.groupBox1.TabIndex = 12; this.groupBox1.TabStop = false; this.groupBox1.Text = "Application"; - // - // label4 - // - this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.label4.Location = new System.Drawing.Point(12, 9); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(388, 44); - this.label4.TabIndex = 13; - this.label4.Text = "Enter a friendly name, protocol (like HTTP, RDP, VNC) and the command line and ar" + - "guments to run the application. In the command line, use %L for address and %P f" + - "or connection port."; // // selectFileButton // - this.selectFileButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.selectFileButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.selectFileButton.Location = new System.Drawing.Point(360, 71); this.selectFileButton.Name = "selectFileButton"; this.selectFileButton.Size = new System.Drawing.Size(21, 20); @@ -161,20 +153,49 @@ this.selectFileButton.Text = "..."; this.selectFileButton.UseVisualStyleBackColor = true; this.selectFileButton.Click += new System.EventHandler(this.selectFileButton_Click); + // + // label4 + // + this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label4.Location = new System.Drawing.Point(12, 9); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(388, 45); + this.label4.TabIndex = 13; + this.label4.Text = "Enter a friendly name, protocol (like HTTP, RDP, VNC) and the command line and ar" + + "guments to run the application. In the arguments, use %L for address, %P for con" + + "nection port and %N for computer name."; // // openFileDialog // this.openFileDialog.DefaultExt = "exe"; - this.openFileDialog.Filter = "Executable|*.exe"; + this.openFileDialog.Filter = "Executable|*.exe|All Files|*.*"; this.openFileDialog.Title = "Select Application Executable"; // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(6, 100); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(57, 13); + this.label5.TabIndex = 13; + this.label5.Text = "Arguments"; + // + // argsTextBox + // + this.argsTextBox.Location = new System.Drawing.Point(116, 97); + this.argsTextBox.Name = "argsTextBox"; + this.argsTextBox.Size = new System.Drawing.Size(265, 20); + this.argsTextBox.TabIndex = 14; + this.argsTextBox.TextChanged += new System.EventHandler(this.nameTextBox_TextChanged); + // // CustomAppsAddForm // this.AcceptButton = this.okButton; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancelButton; - this.ClientSize = new System.Drawing.Size(412, 195); + this.ClientSize = new System.Drawing.Size(412, 225); this.Controls.Add(this.label4); this.Controls.Add(this.groupBox1); this.Controls.Add(this.okButton); @@ -207,5 +228,7 @@ private System.Windows.Forms.Label label4; private System.Windows.Forms.Button selectFileButton; private System.Windows.Forms.OpenFileDialog openFileDialog; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox argsTextBox; } } \ No newline at end of file diff --git a/CustomAppsAddForm.cs b/CustomAppsAddForm.cs index 07ca7cb..136fa48 100644 --- a/CustomAppsAddForm.cs +++ b/CustomAppsAddForm.cs @@ -1,11 +1,5 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.IO; using System.Windows.Forms; namespace MeshCentralRouter @@ -27,6 +21,11 @@ namespace MeshCentralRouter get { return commandTextBox.Text; } set { commandTextBox.Text = value; updateInfo(); } } + public string appArgs + { + get { return argsTextBox.Text; } + set { argsTextBox.Text = value; updateInfo(); } + } public CustomAppsAddForm() { @@ -35,7 +34,7 @@ namespace MeshCentralRouter public void updateInfo() { - okButton.Enabled = (nameTextBox.Text.Length > 0) && (protocolTextBox.Text.Length > 0) && (commandTextBox.Text.Length > 0) && (nameTextBox.Text.IndexOf(' ') == -1) && (protocolTextBox.Text.IndexOf(' ') == -1); + okButton.Enabled = (nameTextBox.Text.Length > 0) && (protocolTextBox.Text.Length > 0) && (commandTextBox.Text.Length > 0) && (nameTextBox.Text.IndexOf(' ') == -1) && (protocolTextBox.Text.IndexOf(' ') == -1) && (File.Exists(commandTextBox.Text)); } private void CustomAppsAddForm_Load(object sender, EventArgs e) diff --git a/CustomAppsForm.cs b/CustomAppsForm.cs index 6403d6d..11530dd 100644 --- a/CustomAppsForm.cs +++ b/CustomAppsForm.cs @@ -1,13 +1,8 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; using System.Diagnostics; +using System.Windows.Forms; +using System.ComponentModel; +using System.Collections.Generic; namespace MeshCentralRouter { @@ -23,7 +18,17 @@ namespace MeshCentralRouter private void CustomAppsForm_Load(object sender, EventArgs e) { - if (apps != null) { foreach (string[] app in apps) { mainListView.Items.Add(new ListViewItem(app)); } } + if (apps != null) { + foreach (string[] app in apps) { + string[] x = new string[5]; + x[0] = app[0]; + x[1] = app[1]; + x[2] = "\"" + app[2] + "\" " + app[3]; + x[3] = app[2]; + x[4] = app[3]; + mainListView.Items.Add(new ListViewItem(x)); + } + } UpdateInfo(); } @@ -32,10 +37,11 @@ namespace MeshCentralRouter List r = new List(); foreach (ListViewItem l in mainListView.Items) { - string[] x = new string[3]; + string[] x = new string[4]; x[0] = l.SubItems[0].Text; x[1] = l.SubItems[1].Text.ToLower(); - x[2] = l.SubItems[2].Text; + x[2] = l.SubItems[3].Text; + x[3] = l.SubItems[4].Text; r.Add(x); } return r; @@ -52,10 +58,12 @@ namespace MeshCentralRouter foreach (ListViewItem l in list) { mainListView.Items.Remove(l); } // Add the new protocol - string[] x = new string[3]; + string[] x = new string[5]; x[0] = f.appName; x[1] = f.appProtocol.ToLower(); - x[2] = f.appCommand; + x[2] = "\"" + f.appCommand + "\" " + f.appArgs; + x[3] = f.appCommand; + x[4] = f.appArgs; mainListView.Items.Add(new ListViewItem(x)); } } @@ -99,8 +107,8 @@ namespace MeshCentralRouter { if (mainListView.SelectedItems.Count != 1) return; ListViewItem i = mainListView.SelectedItems[0]; - CustomAppsRunForm f = new CustomAppsRunForm(i.SubItems[2].Text); - if (f.ShowDialog(this) == DialogResult.OK) { Process.Start(f.getFinalCommand()); } + CustomAppsRunForm f = new CustomAppsRunForm(i.SubItems[3].Text, i.SubItems[4].Text); + if (f.ShowDialog(this) == DialogResult.OK) { Process.Start(i.SubItems[3].Text, f.getFinalArgs()); } } private void editToolStripMenuItem_Click(object sender, EventArgs e) @@ -110,7 +118,8 @@ namespace MeshCentralRouter CustomAppsAddForm f = new CustomAppsAddForm(); f.appName = i.SubItems[0].Text; f.appProtocol = i.SubItems[1].Text; - f.appCommand = i.SubItems[2].Text; + f.appCommand = i.SubItems[3].Text; + f.appArgs = i.SubItems[4].Text; if (f.ShowDialog(this) == DialogResult.OK) { // Remove any matching protocol @@ -119,13 +128,14 @@ namespace MeshCentralRouter foreach (ListViewItem l in list) { mainListView.Items.Remove(l); } // Add the new protocol - string[] x = new string[3]; + string[] x = new string[5]; x[0] = f.appName; x[1] = f.appProtocol.ToLower(); - x[2] = f.appCommand; + x[2] = "\"" + f.appCommand + "\" " + f.appArgs; + x[3] = f.appCommand; + x[4] = f.appArgs; mainListView.Items.Add(new ListViewItem(x)); } - } } } diff --git a/CustomAppsRunForm.Designer.cs b/CustomAppsRunForm.Designer.cs index 0886598..3dc16e6 100644 --- a/CustomAppsRunForm.Designer.cs +++ b/CustomAppsRunForm.Designer.cs @@ -39,6 +39,10 @@ this.okButton = new System.Windows.Forms.Button(); this.cancelButton = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); + this.argsTextBox = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.nameTextBox = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); this.groupBox1.SuspendLayout(); this.SuspendLayout(); // @@ -47,6 +51,10 @@ this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.nameTextBox); + this.groupBox1.Controls.Add(this.label6); + this.groupBox1.Controls.Add(this.argsTextBox); + this.groupBox1.Controls.Add(this.label5); this.groupBox1.Controls.Add(this.portTextBox); this.groupBox1.Controls.Add(this.label4); this.groupBox1.Controls.Add(this.addressTextBox); @@ -55,16 +63,16 @@ this.groupBox1.Controls.Add(this.label2); this.groupBox1.Location = new System.Drawing.Point(12, 49); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(382, 101); + this.groupBox1.Size = new System.Drawing.Size(382, 155); this.groupBox1.TabIndex = 0; this.groupBox1.TabStop = false; - this.groupBox1.Text = "Application Command Line"; + this.groupBox1.Text = "Application Command"; // // portTextBox // this.portTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.portTextBox.Location = new System.Drawing.Point(116, 71); + this.portTextBox.Location = new System.Drawing.Point(116, 97); this.portTextBox.Name = "portTextBox"; this.portTextBox.Size = new System.Drawing.Size(260, 20); this.portTextBox.TabIndex = 13; @@ -74,17 +82,17 @@ // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(6, 74); + this.label4.Location = new System.Drawing.Point(6, 100); this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(26, 13); + this.label4.Size = new System.Drawing.Size(44, 13); this.label4.TabIndex = 12; - this.label4.Text = "Port"; + this.label4.Text = "Port %P"; // // addressTextBox // this.addressTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.addressTextBox.Location = new System.Drawing.Point(116, 45); + this.addressTextBox.Location = new System.Drawing.Point(116, 71); this.addressTextBox.Name = "addressTextBox"; this.addressTextBox.Size = new System.Drawing.Size(260, 20); this.addressTextBox.TabIndex = 11; @@ -94,11 +102,11 @@ // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(6, 48); + this.label3.Location = new System.Drawing.Point(6, 74); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(45, 13); + this.label3.Size = new System.Drawing.Size(62, 13); this.label3.TabIndex = 10; - this.label3.Text = "Address"; + this.label3.Text = "Address %L"; // // commandTextBox // @@ -122,7 +130,7 @@ // okButton // this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.okButton.Location = new System.Drawing.Point(238, 156); + this.okButton.Location = new System.Drawing.Point(238, 210); this.okButton.Name = "okButton"; this.okButton.Size = new System.Drawing.Size(75, 23); this.okButton.TabIndex = 3; @@ -134,7 +142,7 @@ // this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.cancelButton.Location = new System.Drawing.Point(319, 156); + this.cancelButton.Location = new System.Drawing.Point(319, 210); this.cancelButton.Name = "cancelButton"; this.cancelButton.Size = new System.Drawing.Size(75, 23); this.cancelButton.TabIndex = 2; @@ -150,8 +158,46 @@ this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(382, 35); this.label1.TabIndex = 4; - this.label1.Text = "Test that the application runs correctly by specifying and address and port and c" + - "lick ok to run the application."; + this.label1.Text = "Test that the application runs correctly by specifying and address, port and name" + + ". Then click ok to run the application."; + // + // argsTextBox + // + this.argsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.argsTextBox.Location = new System.Drawing.Point(116, 45); + this.argsTextBox.Name = "argsTextBox"; + this.argsTextBox.ReadOnly = true; + this.argsTextBox.Size = new System.Drawing.Size(260, 20); + this.argsTextBox.TabIndex = 15; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(6, 48); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(57, 13); + this.label5.TabIndex = 14; + this.label5.Text = "Arguments"; + // + // nameTextBox + // + this.nameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.nameTextBox.Location = new System.Drawing.Point(116, 123); + this.nameTextBox.Name = "nameTextBox"; + this.nameTextBox.Size = new System.Drawing.Size(260, 20); + this.nameTextBox.TabIndex = 17; + this.nameTextBox.Text = "MyComputer"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(6, 126); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(54, 13); + this.label6.TabIndex = 16; + this.label6.Text = "Name %N"; // // CustomAppsRunForm // @@ -159,7 +205,7 @@ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancelButton; - this.ClientSize = new System.Drawing.Size(406, 191); + this.ClientSize = new System.Drawing.Size(406, 245); this.Controls.Add(this.label1); this.Controls.Add(this.okButton); this.Controls.Add(this.cancelButton); @@ -189,5 +235,9 @@ private System.Windows.Forms.Label label3; private System.Windows.Forms.TextBox commandTextBox; private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox argsTextBox; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox nameTextBox; + private System.Windows.Forms.Label label6; } } \ No newline at end of file diff --git a/CustomAppsRunForm.cs b/CustomAppsRunForm.cs index a3862a2..647c572 100644 --- a/CustomAppsRunForm.cs +++ b/CustomAppsRunForm.cs @@ -13,21 +13,24 @@ namespace MeshCentralRouter public partial class CustomAppsRunForm : Form { private string command = null; + private string args = null; - public CustomAppsRunForm(string command) + public CustomAppsRunForm(string command, string args) { this.command = command; + this.args = args; InitializeComponent(); } - public string getFinalCommand() + public string getFinalArgs() { - return command.Replace("%L", addressTextBox.Text).Replace("%P", portTextBox.Text); + return args.Replace("%L", addressTextBox.Text).Replace("%P", portTextBox.Text).Replace("%N", nameTextBox.Text); } public void UpdateInfo() { - commandTextBox.Text = getFinalCommand(); + commandTextBox.Text = command; + argsTextBox.Text = getFinalArgs(); } private void addressTextBox_TextChanged(object sender, EventArgs e) diff --git a/MapUserControl.cs b/MapUserControl.cs index 70bd89e..a1c75be 100644 --- a/MapUserControl.cs +++ b/MapUserControl.cs @@ -131,18 +131,13 @@ namespace MeshCentralRouter { if (appIdStr == null) return; string appCmd = null; - List apps = Settings.GetApplications(); - foreach (String[] app in apps) { if (app[1].ToLower() == appIdStr.ToLower()) { appCmd = app[2]; } } - appCmd = appCmd.Replace("%P", mapper.localport.ToString()).Replace("%L", "127.0.0.1"); string appArgs = null; - int i = appCmd.IndexOf(' '); - if (i >= 0) { appArgs = appCmd.Substring(i + 1); appCmd = appCmd.Substring(0, i); } - if (appCmd != null) - { + List apps = Settings.GetApplications(); + foreach (String[] app in apps) { if (app[1].ToLower() == appIdStr.ToLower()) { appCmd = app[2]; if (app[3] != null) { appArgs = app[3].Replace("%P", mapper.localport.ToString()).Replace("%L", "127.0.0.1").Replace("%N", "xxx"); } } } + if (appCmd != null) { // Launch the process System.Diagnostics.Process proc = null; try { proc = System.Diagnostics.Process.Start(appCmd, appArgs); } catch (System.ComponentModel.Win32Exception) { } - // Setup auto-exit if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; } autoexit = false; diff --git a/Settings.cs b/Settings.cs index f21fa91..a19886d 100644 --- a/Settings.cs +++ b/Settings.cs @@ -66,6 +66,7 @@ namespace MeshCentralRouter { skey.SetValue("Protocol", app[1]); skey.SetValue("Command", app[2]); + skey.SetValue("Arguments", app[3]); } } } @@ -83,10 +84,12 @@ namespace MeshCentralRouter { string protocol = (string)key2.GetValue("Protocol"); string command = (string)key2.GetValue("Command"); - String[] a = new string[3]; + string args = (string)key2.GetValue("Arguments"); + String[] a = new string[4]; a[0] = k; a[1] = protocol; a[2] = command; + a[3] = args; apps.Add(a); } } @@ -94,8 +97,6 @@ namespace MeshCentralRouter return apps; } - //public static void DeleteSubKeyTree(RegistryKey key, string subkey) { if (key.OpenSubKey(subkey) == null) { return; } DeleteSubKeyTree(key, subkey); } - public static void ClearApplications() { RegistryKey key = Registry.CurrentUser.CreateSubKey(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router", true); From 40f8a7e663076091c3f4bdc2dec62bcd7eddefd7 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Mon, 16 May 2022 16:51:16 -0700 Subject: [PATCH 19/20] Added support for mapping name in URL. --- MainForm.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MainForm.cs b/MainForm.cs index 3c7d9d0..f8da223 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -29,6 +29,7 @@ using System.Security.Cryptography.X509Certificates; using Microsoft.Win32; using System.Drawing; using System.Text; +using System.Web; namespace MeshCentralRouter { @@ -268,6 +269,7 @@ namespace MeshCentralRouter // Set automatic port map values if (authLoginUrl != null) { + string autoName = null; string autoNodeId = null; string autoRemoteIp = null; int autoRemotePort = 0; @@ -279,6 +281,7 @@ namespace MeshCentralRouter try { // Automatic mappings + autoName = getValueFromQueryString(authLoginUrl.Query, "name"); autoNodeId = getValueFromQueryString(authLoginUrl.Query, "nodeid"); autoRemoteIp = getValueFromQueryString(authLoginUrl.Query, "remoteip"); int.TryParse(getValueFromQueryString(authLoginUrl.Query, "remoteport"), out autoRemotePort); @@ -293,6 +296,7 @@ namespace MeshCentralRouter if (((autoRemotePort != 0) && (autoProtocol != 0) && (autoNodeId != null)) || ((autoNodeId != null) && ((autoAppId == 6) || (autoAppId == 7)))) { Dictionary map = new Dictionary(); + if (autoName != null) { map.Add("name", HttpUtility.UrlDecode(autoName)); } map.Add("nodeId", autoNodeId); if (autoRemoteIp != null) { map.Add("remoteIP", autoRemoteIp); } map.Add("remotePort", autoRemotePort); From 84502d94230734e14ab3cffce38dd180041889bf Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Wed, 18 May 2022 13:36:21 -0700 Subject: [PATCH 20/20] Fixed mapping name when passing the URL thru a named pipe. --- MainForm.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MainForm.cs b/MainForm.cs index f8da223..99168cd 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -1023,6 +1023,7 @@ namespace MeshCentralRouter // Set automatic port map values if (authLoginUrl2 != null) { + string autoName = null; string autoNodeId = null; string autoRemoteIp = null; int autoRemotePort = 0; @@ -1034,6 +1035,7 @@ namespace MeshCentralRouter try { // Automatic mappings + autoName = getValueFromQueryString(authLoginUrl.Query, "name"); autoNodeId = getValueFromQueryString(authLoginUrl2.Query, "nodeid"); autoRemoteIp = getValueFromQueryString(authLoginUrl2.Query, "remoteip"); int.TryParse(getValueFromQueryString(authLoginUrl2.Query, "remoteport"), out autoRemotePort); @@ -1048,6 +1050,7 @@ namespace MeshCentralRouter if (((autoRemotePort != 0) && (autoProtocol != 0) && (autoNodeId != null)) || ((autoNodeId != null) && ((autoAppId == 6) || (autoAppId == 7)))) { Dictionary map = new Dictionary(); + if (autoName != null) { map.Add("name", HttpUtility.UrlDecode(autoName)); } map.Add("nodeId", autoNodeId); if (autoRemoteIp != null) { map.Add("remoteIP", autoRemoteIp); } map.Add("remotePort", autoRemotePort);