1
0
mirror of https://github.com/Ylianst/MeshCentralRouter synced 2026-01-15 22:43:13 +00:00

Moved source files and updated readme file.

This commit is contained in:
Ylian Saint-Hilaire
2022-05-20 12:24:53 -07:00
parent 48a001ed63
commit ad2a5078c9
111 changed files with 118 additions and 114 deletions

246
src/AddPortMapForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,246 @@
namespace MeshCentralRouter
{
partial class AddPortMapForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddPortMapForm));
this.cancelButton = new System.Windows.Forms.Button();
this.okButton = new System.Windows.Forms.Button();
this.localNumericUpDown = new System.Windows.Forms.NumericUpDown();
this.label1 = new System.Windows.Forms.Label();
this.nodeComboBox = new System.Windows.Forms.ComboBox();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.remoteNumericUpDown = new System.Windows.Forms.NumericUpDown();
this.label4 = new System.Windows.Forms.Label();
this.appComboBox = new System.Windows.Forms.ComboBox();
this.label5 = new System.Windows.Forms.Label();
this.groupComboBox = new System.Windows.Forms.ComboBox();
this.label6 = new System.Windows.Forms.Label();
this.tcpRadioButton = new System.Windows.Forms.RadioButton();
this.udpRadioButton = new System.Windows.Forms.RadioButton();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.label8 = new System.Windows.Forms.Label();
this.mainToolTip = new System.Windows.Forms.ToolTip(this.components);
((System.ComponentModel.ISupportInitialize)(this.localNumericUpDown)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.remoteNumericUpDown)).BeginInit();
this.SuspendLayout();
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// localNumericUpDown
//
resources.ApplyResources(this.localNumericUpDown, "localNumericUpDown");
this.localNumericUpDown.Maximum = new decimal(new int[] {
65535,
0,
0,
0});
this.localNumericUpDown.Name = "localNumericUpDown";
//
// label1
//
resources.ApplyResources(this.label1, "label1");
this.label1.Name = "label1";
//
// nodeComboBox
//
resources.ApplyResources(this.nodeComboBox, "nodeComboBox");
this.nodeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.nodeComboBox.FormattingEnabled = true;
this.nodeComboBox.Name = "nodeComboBox";
this.nodeComboBox.Sorted = true;
//
// label2
//
resources.ApplyResources(this.label2, "label2");
this.label2.Name = "label2";
//
// label3
//
resources.ApplyResources(this.label3, "label3");
this.label3.Name = "label3";
//
// remoteNumericUpDown
//
resources.ApplyResources(this.remoteNumericUpDown, "remoteNumericUpDown");
this.remoteNumericUpDown.Maximum = new decimal(new int[] {
65535,
0,
0,
0});
this.remoteNumericUpDown.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this.remoteNumericUpDown.Name = "remoteNumericUpDown";
this.remoteNumericUpDown.Value = new decimal(new int[] {
80,
0,
0,
0});
//
// label4
//
resources.ApplyResources(this.label4, "label4");
this.label4.Name = "label4";
//
// appComboBox
//
resources.ApplyResources(this.appComboBox, "appComboBox");
this.appComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.appComboBox.FormattingEnabled = true;
this.appComboBox.Items.AddRange(new object[] {
resources.GetString("appComboBox.Items"),
resources.GetString("appComboBox.Items1"),
resources.GetString("appComboBox.Items2"),
resources.GetString("appComboBox.Items3"),
resources.GetString("appComboBox.Items4"),
resources.GetString("appComboBox.Items5")});
this.appComboBox.Name = "appComboBox";
this.appComboBox.SelectedIndexChanged += new System.EventHandler(this.appComboBox_SelectedIndexChanged);
//
// label5
//
resources.ApplyResources(this.label5, "label5");
this.label5.Name = "label5";
//
// groupComboBox
//
resources.ApplyResources(this.groupComboBox, "groupComboBox");
this.groupComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.groupComboBox.FormattingEnabled = true;
this.groupComboBox.Name = "groupComboBox";
this.groupComboBox.Sorted = true;
this.groupComboBox.SelectedIndexChanged += new System.EventHandler(this.groupComboBox_SelectedIndexChanged);
//
// label6
//
resources.ApplyResources(this.label6, "label6");
this.label6.Name = "label6";
//
// tcpRadioButton
//
resources.ApplyResources(this.tcpRadioButton, "tcpRadioButton");
this.tcpRadioButton.Checked = true;
this.tcpRadioButton.Name = "tcpRadioButton";
this.tcpRadioButton.TabStop = true;
this.tcpRadioButton.UseVisualStyleBackColor = true;
this.tcpRadioButton.CheckedChanged += new System.EventHandler(this.tcpRadioButton_CheckedChanged);
//
// udpRadioButton
//
resources.ApplyResources(this.udpRadioButton, "udpRadioButton");
this.udpRadioButton.Name = "udpRadioButton";
this.udpRadioButton.UseVisualStyleBackColor = true;
this.udpRadioButton.CheckedChanged += new System.EventHandler(this.tcpRadioButton_CheckedChanged);
//
// nameTextBox
//
resources.ApplyResources(this.nameTextBox, "nameTextBox");
this.nameTextBox.Name = "nameTextBox";
this.mainToolTip.SetToolTip(this.nameTextBox, resources.GetString("nameTextBox.ToolTip"));
//
// label8
//
resources.ApplyResources(this.label8, "label8");
this.label8.Name = "label8";
this.mainToolTip.SetToolTip(this.label8, resources.GetString("label8.ToolTip"));
//
// AddPortMapForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.label8);
this.Controls.Add(this.udpRadioButton);
this.Controls.Add(this.tcpRadioButton);
this.Controls.Add(this.label6);
this.Controls.Add(this.label5);
this.Controls.Add(this.groupComboBox);
this.Controls.Add(this.label4);
this.Controls.Add(this.appComboBox);
this.Controls.Add(this.label3);
this.Controls.Add(this.remoteNumericUpDown);
this.Controls.Add(this.label2);
this.Controls.Add(this.nodeComboBox);
this.Controls.Add(this.label1);
this.Controls.Add(this.localNumericUpDown);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "AddPortMapForm";
this.Load += new System.EventHandler(this.AddPortMapForm_Load);
((System.ComponentModel.ISupportInitialize)(this.localNumericUpDown)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.remoteNumericUpDown)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.NumericUpDown localNumericUpDown;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox nodeComboBox;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.NumericUpDown remoteNumericUpDown;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.ComboBox appComboBox;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.ComboBox groupComboBox;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.RadioButton tcpRadioButton;
private System.Windows.Forms.RadioButton udpRadioButton;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.ToolTip mainToolTip;
}
}

173
src/AddPortMapForm.cs Normal file
View File

@@ -0,0 +1,173 @@
/*
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.Windows.Forms;
using System.Collections.Generic;
namespace MeshCentralRouter
{
public partial class AddPortMapForm : Form
{
private MeshCentralServer meshcentral;
private NodeClass selectedNode = null;
public AddPortMapForm(MeshCentralServer meshcentral)
{
this.meshcentral = meshcentral;
InitializeComponent();
Translate.TranslateControl(this);
}
public string getName() { return nameTextBox.Text; }
public int getProtocol() { return (int)(tcpRadioButton.Checked?1:2); }
public int getLocalPort() { return (int)localNumericUpDown.Value; }
public int getRemotePort() { return (int)remoteNumericUpDown.Value; }
public int getAppId() {
int x = (int)appComboBox.SelectedIndex;
if (x == 0) { return 0; } // Custom
if (x == 1) { return 1; } // HTTP
if (x == 2) { return 2; } // HTTPS
if (x == 3) { return 4; } // PuTTY
if (x == 4) { return 3; } // RDP
if (x == 5) { return 5; } // WinSCP
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<String[]> 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
groupComboBox.Items.Clear();
foreach (string meshid in meshcentral.meshes.Keys)
{
MeshClass mesh = meshcentral.meshes[meshid];
if ((mesh.type == 2) || (mesh.type == 3))
{
int nodeCount = 0;
foreach (string nodeid in meshcentral.nodes.Keys)
{
NodeClass node = meshcentral.nodes[nodeid];
if ((node.meshid == mesh.meshid) && (((node.conn & 1) != 0) || (node.mtype == 3))) { nodeCount++; }
}
if (nodeCount > 0) { groupComboBox.Items.Add(mesh); }
}
}
// If the user has indivitual device rights, add an extra device group
if (meshcentral.userRights != null)
{
bool indivitualDevices = false;
foreach (string id in meshcentral.userRights.Keys) { if (id.StartsWith("node/")) { indivitualDevices = true; } }
if (indivitualDevices)
{
MeshClass m = new MeshClass();
m.name = Translate.T(Properties.Resources.IndividualDevices);
groupComboBox.Items.Add(m);
}
}
// Set default selection
if (groupComboBox.Items.Count > 0) { groupComboBox.SelectedIndex = 0; }
appComboBox.SelectedIndex = 1;
fillNodesInDropDown();
} else {
if (selectedNode.mesh == null)
{
MeshClass m = new MeshClass();
m.name = Translate.T(Properties.Resources.IndividualDevices);
groupComboBox.Items.Add(m);
}
else
{
groupComboBox.Items.Add(selectedNode.mesh);
}
groupComboBox.SelectedIndex = 0;
groupComboBox.Enabled = false;
nodeComboBox.Items.Add(selectedNode);
nodeComboBox.SelectedIndex = 0;
nodeComboBox.Enabled = false;
appComboBox.SelectedIndex = 1;
}
nameTextBox.Focus();
}
private void fillNodesInDropDown()
{
if (selectedNode != null) return;
MeshClass mesh = (MeshClass)groupComboBox.SelectedItem;
// Fill the nodes dropdown
nodeComboBox.Items.Clear();
if (meshcentral.nodes != null)
{
foreach (string nodeid in meshcentral.nodes.Keys)
{
NodeClass node = meshcentral.nodes[nodeid];
if (((node.meshid == mesh.meshid) || ((mesh.meshid == null) && (meshcentral.userRights.ContainsKey(node.nodeid)))) && (((node.conn & 1) != 0) || (node.mtype == 3))) { nodeComboBox.Items.Add(node); }
}
}
if (nodeComboBox.Items.Count > 0) { nodeComboBox.SelectedIndex = 0; }
}
private void appComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (appComboBox.SelectedIndex == 1) { remoteNumericUpDown.Value = 80; } // HTTP
if (appComboBox.SelectedIndex == 2) { remoteNumericUpDown.Value = 443; } // HTTPS
if (appComboBox.SelectedIndex == 3) { remoteNumericUpDown.Value = 22; } // SSH
if (appComboBox.SelectedIndex == 4) { remoteNumericUpDown.Value = 3389; } // RDP
if (appComboBox.SelectedIndex == 5) { remoteNumericUpDown.Value = 22; } // SCP
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
private void okButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
private void groupComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
fillNodesInDropDown();
}
private void tcpRadioButton_CheckedChanged(object sender, EventArgs e)
{
appComboBox.Enabled = tcpRadioButton.Checked;
if (udpRadioButton.Checked) { appComboBox.SelectedIndex = 0; }
}
}
}

2324
src/AddPortMapForm.resx Normal file

File diff suppressed because it is too large Load Diff

262
src/AddRelayMapForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,262 @@
namespace MeshCentralRouter
{
partial class AddRelayMapForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddRelayMapForm));
this.cancelButton = new System.Windows.Forms.Button();
this.okButton = new System.Windows.Forms.Button();
this.localNumericUpDown = new System.Windows.Forms.NumericUpDown();
this.label1 = new System.Windows.Forms.Label();
this.nodeComboBox = new System.Windows.Forms.ComboBox();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.remoteNumericUpDown = new System.Windows.Forms.NumericUpDown();
this.label4 = new System.Windows.Forms.Label();
this.appComboBox = new System.Windows.Forms.ComboBox();
this.label5 = new System.Windows.Forms.Label();
this.remoteIpTextBox = new System.Windows.Forms.TextBox();
this.label6 = new System.Windows.Forms.Label();
this.groupComboBox = new System.Windows.Forms.ComboBox();
this.udpRadioButton = new System.Windows.Forms.RadioButton();
this.tcpRadioButton = new System.Windows.Forms.RadioButton();
this.label7 = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.label8 = new System.Windows.Forms.Label();
this.mainToolTip = new System.Windows.Forms.ToolTip(this.components);
((System.ComponentModel.ISupportInitialize)(this.localNumericUpDown)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.remoteNumericUpDown)).BeginInit();
this.SuspendLayout();
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// localNumericUpDown
//
resources.ApplyResources(this.localNumericUpDown, "localNumericUpDown");
this.localNumericUpDown.Maximum = new decimal(new int[] {
65535,
0,
0,
0});
this.localNumericUpDown.Name = "localNumericUpDown";
//
// label1
//
resources.ApplyResources(this.label1, "label1");
this.label1.Name = "label1";
//
// nodeComboBox
//
resources.ApplyResources(this.nodeComboBox, "nodeComboBox");
this.nodeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.nodeComboBox.FormattingEnabled = true;
this.nodeComboBox.Name = "nodeComboBox";
this.nodeComboBox.Sorted = true;
//
// label2
//
resources.ApplyResources(this.label2, "label2");
this.label2.Name = "label2";
//
// label3
//
resources.ApplyResources(this.label3, "label3");
this.label3.Name = "label3";
//
// remoteNumericUpDown
//
resources.ApplyResources(this.remoteNumericUpDown, "remoteNumericUpDown");
this.remoteNumericUpDown.Maximum = new decimal(new int[] {
65535,
0,
0,
0});
this.remoteNumericUpDown.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this.remoteNumericUpDown.Name = "remoteNumericUpDown";
this.remoteNumericUpDown.Value = new decimal(new int[] {
80,
0,
0,
0});
//
// label4
//
resources.ApplyResources(this.label4, "label4");
this.label4.Name = "label4";
//
// appComboBox
//
resources.ApplyResources(this.appComboBox, "appComboBox");
this.appComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.appComboBox.FormattingEnabled = true;
this.appComboBox.Items.AddRange(new object[] {
resources.GetString("appComboBox.Items"),
resources.GetString("appComboBox.Items1"),
resources.GetString("appComboBox.Items2"),
resources.GetString("appComboBox.Items3"),
resources.GetString("appComboBox.Items4"),
resources.GetString("appComboBox.Items5")});
this.appComboBox.Name = "appComboBox";
this.appComboBox.SelectedIndexChanged += new System.EventHandler(this.appComboBox_SelectedIndexChanged);
//
// label5
//
resources.ApplyResources(this.label5, "label5");
this.label5.Name = "label5";
//
// remoteIpTextBox
//
resources.ApplyResources(this.remoteIpTextBox, "remoteIpTextBox");
this.remoteIpTextBox.Name = "remoteIpTextBox";
this.remoteIpTextBox.TextChanged += new System.EventHandler(this.remoteIpTextBox_TextChanged);
//
// label6
//
resources.ApplyResources(this.label6, "label6");
this.label6.Name = "label6";
//
// groupComboBox
//
resources.ApplyResources(this.groupComboBox, "groupComboBox");
this.groupComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.groupComboBox.FormattingEnabled = true;
this.groupComboBox.Name = "groupComboBox";
this.groupComboBox.Sorted = true;
this.groupComboBox.SelectedIndexChanged += new System.EventHandler(this.groupComboBox_SelectedIndexChanged);
//
// udpRadioButton
//
resources.ApplyResources(this.udpRadioButton, "udpRadioButton");
this.udpRadioButton.Name = "udpRadioButton";
this.udpRadioButton.UseVisualStyleBackColor = true;
//
// tcpRadioButton
//
resources.ApplyResources(this.tcpRadioButton, "tcpRadioButton");
this.tcpRadioButton.Checked = true;
this.tcpRadioButton.Name = "tcpRadioButton";
this.tcpRadioButton.TabStop = true;
this.tcpRadioButton.UseVisualStyleBackColor = true;
this.tcpRadioButton.CheckedChanged += new System.EventHandler(this.tcpRadioButton_CheckedChanged);
//
// label7
//
resources.ApplyResources(this.label7, "label7");
this.label7.Name = "label7";
//
// nameTextBox
//
resources.ApplyResources(this.nameTextBox, "nameTextBox");
this.nameTextBox.Name = "nameTextBox";
this.mainToolTip.SetToolTip(this.nameTextBox, resources.GetString("nameTextBox.ToolTip"));
//
// label8
//
resources.ApplyResources(this.label8, "label8");
this.label8.Name = "label8";
this.mainToolTip.SetToolTip(this.label8, resources.GetString("label8.ToolTip"));
//
// AddRelayMapForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.label8);
this.Controls.Add(this.udpRadioButton);
this.Controls.Add(this.tcpRadioButton);
this.Controls.Add(this.label7);
this.Controls.Add(this.label6);
this.Controls.Add(this.groupComboBox);
this.Controls.Add(this.remoteIpTextBox);
this.Controls.Add(this.label5);
this.Controls.Add(this.label4);
this.Controls.Add(this.appComboBox);
this.Controls.Add(this.label3);
this.Controls.Add(this.remoteNumericUpDown);
this.Controls.Add(this.label2);
this.Controls.Add(this.nodeComboBox);
this.Controls.Add(this.label1);
this.Controls.Add(this.localNumericUpDown);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "AddRelayMapForm";
this.Load += new System.EventHandler(this.AddRelayMapForm_Load);
((System.ComponentModel.ISupportInitialize)(this.localNumericUpDown)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.remoteNumericUpDown)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.NumericUpDown localNumericUpDown;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox nodeComboBox;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.NumericUpDown remoteNumericUpDown;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.ComboBox appComboBox;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox remoteIpTextBox;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.ComboBox groupComboBox;
private System.Windows.Forms.RadioButton udpRadioButton;
private System.Windows.Forms.RadioButton tcpRadioButton;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.ToolTip mainToolTip;
}
}

187
src/AddRelayMapForm.cs Normal file
View File

@@ -0,0 +1,187 @@
/*
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.Net;
using System.Windows.Forms;
using System.Collections.Generic;
namespace MeshCentralRouter
{
public partial class AddRelayMapForm : Form
{
private MeshCentralServer meshcentral;
private NodeClass selectedNode = null;
public AddRelayMapForm(MeshCentralServer meshcentral)
{
this.meshcentral = meshcentral;
InitializeComponent();
Translate.TranslateControl(this);
updateInfo();
}
public string getName() { return nameTextBox.Text; }
public int getProtocol() { return (int)(tcpRadioButton.Checked ? 1 : 2); }
public int getLocalPort() { return (int)localNumericUpDown.Value; }
public int getRemotePort() { return (int)remoteNumericUpDown.Value; }
public string getRemoteIP() { return remoteIpTextBox.Text; }
public int getAppId() {
int x = (int)appComboBox.SelectedIndex;
if (x == 0) { return 0; } // Custom
if (x == 1) { return 1; } // HTTP
if (x == 2) { return 2; } // HTTPS
if (x == 3) { return 4; } // PuTTY
if (x == 4) { return 3; } // RDP
if (x == 5) { return 5; } // WinSCP
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<String[]> 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
groupComboBox.Items.Clear();
foreach (string meshid in meshcentral.meshes.Keys)
{
MeshClass mesh = meshcentral.meshes[meshid];
if (mesh.type == 2)
{
int nodeCount = 0;
foreach (string nodeid in meshcentral.nodes.Keys)
{
NodeClass node = meshcentral.nodes[nodeid];
if ((node.meshid == mesh.meshid) && ((node.conn & 1) != 0)) { nodeCount++; }
}
if (nodeCount > 0) { groupComboBox.Items.Add(mesh); }
}
}
// If the user has indivitual device rights, add an extra device group
if (meshcentral.userRights != null)
{
bool indivitualDevices = false;
foreach (string id in meshcentral.userRights.Keys) { if (id.StartsWith("node/")) { indivitualDevices = true; } }
if (indivitualDevices)
{
MeshClass m = new MeshClass();
m.name = Translate.T(Properties.Resources.IndividualDevices);
groupComboBox.Items.Add(m);
}
}
// Set default selection
if (groupComboBox.Items.Count > 0) { groupComboBox.SelectedIndex = 0; }
appComboBox.SelectedIndex = 1;
fillNodesInDropDown();
} else {
if (selectedNode.mesh == null)
{
MeshClass m = new MeshClass();
m.name = Translate.T(Properties.Resources.IndividualDevices);
groupComboBox.Items.Add(m);
}
else
{
groupComboBox.Items.Add(selectedNode.mesh);
}
groupComboBox.SelectedIndex = 0;
groupComboBox.Enabled = false;
nodeComboBox.Items.Add(selectedNode);
nodeComboBox.SelectedIndex = 0;
nodeComboBox.Enabled = false;
appComboBox.SelectedIndex = 1;
}
nameTextBox.Focus();
}
private void fillNodesInDropDown()
{
if (selectedNode != null) return;
MeshClass mesh = (MeshClass)groupComboBox.SelectedItem;
// Fill the nodes dropdown
nodeComboBox.Items.Clear();
if (meshcentral.nodes != null)
{
foreach (string nodeid in meshcentral.nodes.Keys)
{
NodeClass node = meshcentral.nodes[nodeid];
if (((node.meshid == mesh.meshid) || ((mesh.meshid == null) && (meshcentral.userRights.ContainsKey(node.nodeid)))) && ((node.conn & 1) != 0)) { nodeComboBox.Items.Add(node); }
}
}
if (nodeComboBox.Items.Count > 0) { nodeComboBox.SelectedIndex = 0; }
}
private void appComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (appComboBox.SelectedIndex == 1) { remoteNumericUpDown.Value = 80; } // HTTP
if (appComboBox.SelectedIndex == 2) { remoteNumericUpDown.Value = 443; } // HTTPS
if (appComboBox.SelectedIndex == 3) { remoteNumericUpDown.Value = 22; } // Putty
if (appComboBox.SelectedIndex == 4) { remoteNumericUpDown.Value = 3389; } // RDP
if (appComboBox.SelectedIndex == 5) { remoteNumericUpDown.Value = 22; } // WinSCP
}
private void updateInfo()
{
IPAddress ipaddress = null;
try { ipaddress = IPAddress.Parse(remoteIpTextBox.Text); } catch (Exception) { }
okButton.Enabled = (ipaddress != null);
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
private void okButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
private void remoteIpTextBox_TextChanged(object sender, EventArgs e)
{
updateInfo();
}
private void groupComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
fillNodesInDropDown();
}
private void tcpRadioButton_CheckedChanged(object sender, EventArgs e)
{
appComboBox.Enabled = tcpRadioButton.Checked;
if (udpRadioButton.Checked) { appComboBox.SelectedIndex = 0; }
}
}
}

2378
src/AddRelayMapForm.resx Normal file

File diff suppressed because it is too large Load Diff

164
src/AppLaunchForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,164 @@
namespace MeshCentralRouter
{
partial class AppLaunchForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AppLaunchForm));
this.cancelButton = new System.Windows.Forms.Button();
this.okButton = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.applicationComboBox = new System.Windows.Forms.ComboBox();
this.folderButton = new System.Windows.Forms.Button();
this.appNameLabel = new System.Windows.Forms.Label();
this.appLinkLabel = new System.Windows.Forms.LinkLabel();
this.appPathTextBox = new System.Windows.Forms.TextBox();
this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// groupBox1
//
resources.ApplyResources(this.groupBox1, "groupBox1");
this.groupBox1.Controls.Add(this.applicationComboBox);
this.groupBox1.Controls.Add(this.folderButton);
this.groupBox1.Controls.Add(this.appNameLabel);
this.groupBox1.Controls.Add(this.appLinkLabel);
this.groupBox1.Controls.Add(this.appPathTextBox);
this.groupBox1.Controls.Add(this.label3);
this.groupBox1.Controls.Add(this.label2);
this.groupBox1.Controls.Add(this.label1);
this.groupBox1.Name = "groupBox1";
this.groupBox1.TabStop = false;
//
// applicationComboBox
//
resources.ApplyResources(this.applicationComboBox, "applicationComboBox");
this.applicationComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.applicationComboBox.FormattingEnabled = true;
this.applicationComboBox.Name = "applicationComboBox";
this.applicationComboBox.SelectedIndexChanged += new System.EventHandler(this.applicationComboBox_SelectedIndexChanged);
//
// folderButton
//
resources.ApplyResources(this.folderButton, "folderButton");
this.folderButton.Image = global::MeshCentralRouter.Properties.Resources.Folder36;
this.folderButton.Name = "folderButton";
this.folderButton.UseVisualStyleBackColor = true;
this.folderButton.Click += new System.EventHandler(this.folderPictureBox_Click);
//
// appNameLabel
//
resources.ApplyResources(this.appNameLabel, "appNameLabel");
this.appNameLabel.Name = "appNameLabel";
//
// appLinkLabel
//
resources.ApplyResources(this.appLinkLabel, "appLinkLabel");
this.appLinkLabel.Name = "appLinkLabel";
this.appLinkLabel.TabStop = true;
this.appLinkLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.appLinkLabel_LinkClicked);
//
// appPathTextBox
//
resources.ApplyResources(this.appPathTextBox, "appPathTextBox");
this.appPathTextBox.Name = "appPathTextBox";
this.appPathTextBox.TextChanged += new System.EventHandler(this.appPathTextBox_TextChanged);
//
// label3
//
resources.ApplyResources(this.label3, "label3");
this.label3.Name = "label3";
//
// label2
//
resources.ApplyResources(this.label2, "label2");
this.label2.Name = "label2";
//
// label1
//
resources.ApplyResources(this.label1, "label1");
this.label1.Name = "label1";
//
// openFileDialog
//
this.openFileDialog.DefaultExt = "exe";
resources.ApplyResources(this.openFileDialog, "openFileDialog");
//
// AppLaunchForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "AppLaunchForm";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label appNameLabel;
private System.Windows.Forms.LinkLabel appLinkLabel;
private System.Windows.Forms.TextBox appPathTextBox;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.OpenFileDialog openFileDialog;
private System.Windows.Forms.Button folderButton;
private System.Windows.Forms.ComboBox applicationComboBox;
}
}

99
src/AppLaunchForm.cs Normal file
View File

@@ -0,0 +1,99 @@
/*
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.IO;
using System.Windows.Forms;
namespace MeshCentralRouter
{
public partial class AppLaunchForm : Form
{
public AppLaunchForm()
{
InitializeComponent();
Translate.TranslateControl(this);
UpdateInfo();
}
public class AppInfo
{
public AppInfo(string name, string link, string path, string tag) { this.name = name; this.link = link; this.path = path; this.tag = tag; }
public string name;
public string link;
public string path;
public string tag;
public override string ToString() { return name; }
}
public void SetAppName(string name) { appNameLabel.Text = name; }
public void SetAppLink(string link) { appLinkLabel.Text = link; }
public void SetAppPath(string path) { appPathTextBox.Text = path; }
public string GetAppPath() { return appPathTextBox.Text; }
public string GetAppTag() { return ((AppInfo)applicationComboBox.SelectedItem).tag; }
public void SetApps(AppInfo[] apps)
{
appNameLabel.Visible = false;
applicationComboBox.Visible = true;
foreach (AppInfo app in apps) { applicationComboBox.Items.Add(app); }
applicationComboBox.SelectedIndex = 0;
}
private void folderPictureBox_Click(object sender, EventArgs e)
{
openFileDialog.FileName = appPathTextBox.Text;
if (openFileDialog.ShowDialog(this) == DialogResult.OK)
{
appPathTextBox.Text = openFileDialog.FileName;
UpdateInfo();
}
}
private void appPathTextBox_TextChanged(object sender, EventArgs e)
{
UpdateInfo();
}
private void UpdateInfo()
{
okButton.Enabled = File.Exists(appPathTextBox.Text);
}
private void okButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
private void appLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
System.Diagnostics.Process.Start(appLinkLabel.Text);
}
private void applicationComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
appLinkLabel.Text = ((AppInfo)applicationComboBox.SelectedItem).link;
appPathTextBox.Text = ((AppInfo)applicationComboBox.SelectedItem).path;
}
}
}

2138
src/AppLaunchForm.resx Normal file

File diff suppressed because it is too large Load Diff

234
src/CustomAppsAddForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,234 @@
namespace MeshCentralRouter
{
partial class CustomAppsAddForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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.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();
//
// 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, 190);
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, 190);
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(85, 13);
this.label3.TabIndex = 10;
this.label3.Text = "Executable Path";
//
// 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.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);
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, 57);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(388, 127);
this.groupBox1.TabIndex = 12;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Application";
//
// selectFileButton
//
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);
this.selectFileButton.TabIndex = 12;
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|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, 225);
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;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox argsTextBox;
}
}

69
src/CustomAppsAddForm.cs Normal file
View File

@@ -0,0 +1,69 @@
using System;
using System.IO;
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 string appArgs
{
get { return argsTextBox.Text; }
set { argsTextBox.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) && (File.Exists(commandTextBox.Text));
}
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;
}
}
}
}

1818
src/CustomAppsAddForm.resx Normal file

File diff suppressed because it is too large Load Diff

276
src/CustomAppsForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,276 @@
namespace MeshCentralRouter
{
partial class CustomAppsForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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.editButton = new System.Windows.Forms.Button();
this.runButton = new System.Windows.Forms.Button();
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.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);
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);
//
// 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;
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;
private System.Windows.Forms.Button editButton;
private System.Windows.Forms.Button runButton;
}
}

141
src/CustomAppsForm.cs Normal file
View File

@@ -0,0 +1,141 @@
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
namespace MeshCentralRouter
{
public partial class CustomAppsForm : Form
{
List<string[]> apps;
public CustomAppsForm(List<string[]> apps)
{
this.apps = apps;
InitializeComponent();
}
private void CustomAppsForm_Load(object sender, EventArgs e)
{
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();
}
public List<string[]> getApplications()
{
List<string[]> r = new List<string[]>();
foreach (ListViewItem l in mainListView.Items)
{
string[] x = new string[4];
x[0] = l.SubItems[0].Text;
x[1] = l.SubItems[1].Text.ToLower();
x[2] = l.SubItems[3].Text;
x[3] = l.SubItems[4].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<ListViewItem> list = new List<ListViewItem>();
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[5];
x[0] = f.appName;
x[1] = f.appProtocol.ToLower();
x[2] = "\"" + f.appCommand + "\" " + f.appArgs;
x[3] = f.appCommand;
x[4] = f.appArgs;
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);
runButton.Enabled = editButton.Enabled = (mainListView.SelectedItems.Count == 1);
}
private void removeButton_Click(object sender, EventArgs e)
{
if (mainListView.SelectedItems.Count == 0) return;
List<ListViewItem> list = new List<ListViewItem>();
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[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)
{
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[3].Text;
f.appArgs = i.SubItems[4].Text;
if (f.ShowDialog(this) == DialogResult.OK)
{
// Remove any matching protocol
List<ListViewItem> list = new List<ListViewItem>();
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[5];
x[0] = f.appName;
x[1] = f.appProtocol.ToLower();
x[2] = "\"" + f.appCommand + "\" " + f.appArgs;
x[3] = f.appCommand;
x[4] = f.appArgs;
mainListView.Items.Add(new ListViewItem(x));
}
}
}
}

1818
src/CustomAppsForm.resx Normal file

File diff suppressed because it is too large Load Diff

243
src/CustomAppsRunForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,243 @@
namespace MeshCentralRouter
{
partial class CustomAppsRunForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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.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();
//
// 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.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);
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, 155);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
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, 97);
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, 100);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(44, 13);
this.label4.TabIndex = 12;
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, 71);
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, 74);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(62, 13);
this.label3.TabIndex = 10;
this.label3.Text = "Address %L";
//
// 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, 210);
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, 210);
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, 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
//
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, 245);
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.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
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;
private System.Windows.Forms.TextBox argsTextBox;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label label6;
}
}

61
src/CustomAppsRunForm.cs Normal file
View File

@@ -0,0 +1,61 @@
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;
private string args = null;
public CustomAppsRunForm(string command, string args)
{
this.command = command;
this.args = args;
InitializeComponent();
}
public string getFinalArgs()
{
return args.Replace("%L", addressTextBox.Text).Replace("%P", portTextBox.Text).Replace("%N", nameTextBox.Text);
}
public void UpdateInfo()
{
commandTextBox.Text = command;
argsTextBox.Text = getFinalArgs();
}
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;
}
}
}

1815
src/CustomAppsRunForm.resx Normal file

File diff suppressed because it is too large Load Diff

150
src/DeviceSettingsForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,150 @@
namespace MeshCentralRouter
{
partial class DeviceSettingsForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DeviceSettingsForm));
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.systemTrayCheckBox = new System.Windows.Forms.CheckBox();
this.doubleClickComboBox = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.okButton = new System.Windows.Forms.Button();
this.cancelButton = new System.Windows.Forms.Button();
this.exp_KeyboardHookCheckBox = new System.Windows.Forms.CheckBox();
this.exp_KeyboardHookPriorityCheckBox = new System.Windows.Forms.CheckBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
//
resources.ApplyResources(this.groupBox1, "groupBox1");
this.groupBox1.Controls.Add(this.systemTrayCheckBox);
this.groupBox1.Controls.Add(this.doubleClickComboBox);
this.groupBox1.Controls.Add(this.label1);
this.groupBox1.Name = "groupBox1";
this.groupBox1.TabStop = false;
//
// systemTrayCheckBox
//
resources.ApplyResources(this.systemTrayCheckBox, "systemTrayCheckBox");
this.systemTrayCheckBox.Name = "systemTrayCheckBox";
this.systemTrayCheckBox.UseVisualStyleBackColor = true;
//
// doubleClickComboBox
//
this.doubleClickComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.doubleClickComboBox.FormattingEnabled = true;
this.doubleClickComboBox.Items.AddRange(new object[] {
resources.GetString("doubleClickComboBox.Items"),
resources.GetString("doubleClickComboBox.Items1"),
resources.GetString("doubleClickComboBox.Items2"),
resources.GetString("doubleClickComboBox.Items3"),
resources.GetString("doubleClickComboBox.Items4"),
resources.GetString("doubleClickComboBox.Items5"),
resources.GetString("doubleClickComboBox.Items6"),
resources.GetString("doubleClickComboBox.Items7")});
resources.ApplyResources(this.doubleClickComboBox, "doubleClickComboBox");
this.doubleClickComboBox.Name = "doubleClickComboBox";
//
// label1
//
resources.ApplyResources(this.label1, "label1");
this.label1.Name = "label1";
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
//
// exp_KeyboardHookCheckBox
//
resources.ApplyResources(this.exp_KeyboardHookCheckBox, "exp_KeyboardHookCheckBox");
this.exp_KeyboardHookCheckBox.Name = "exp_KeyboardHookCheckBox";
this.exp_KeyboardHookCheckBox.UseVisualStyleBackColor = true;
this.exp_KeyboardHookCheckBox.CheckedChanged += new System.EventHandler(this.exp_KeyboardHookCheckBox_CheckedChanged);
//
// exp_KeyboardHookPriorityCheckBox
//
resources.ApplyResources(this.exp_KeyboardHookPriorityCheckBox, "exp_KeyboardHookPriorityCheckBox");
this.exp_KeyboardHookPriorityCheckBox.Name = "exp_KeyboardHookPriorityCheckBox";
this.exp_KeyboardHookPriorityCheckBox.UseVisualStyleBackColor = true;
//
// groupBox2
//
resources.ApplyResources(this.groupBox2, "groupBox2");
this.groupBox2.Controls.Add(this.exp_KeyboardHookPriorityCheckBox);
this.groupBox2.Controls.Add(this.exp_KeyboardHookCheckBox);
this.groupBox2.Name = "groupBox2";
this.groupBox2.TabStop = false;
//
// DeviceSettingsForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "DeviceSettingsForm";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.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.ComboBox doubleClickComboBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.CheckBox systemTrayCheckBox;
private System.Windows.Forms.CheckBox exp_KeyboardHookCheckBox;
private System.Windows.Forms.CheckBox exp_KeyboardHookPriorityCheckBox;
private System.Windows.Forms.GroupBox groupBox2;
}
}

81
src/DeviceSettingsForm.cs Normal file
View File

@@ -0,0 +1,81 @@
/*
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.Windows.Forms;
namespace MeshCentralRouter
{
public partial class DeviceSettingsForm : Form
{
public DeviceSettingsForm()
{
InitializeComponent();
Translate.TranslateControl(this);
doubleClickComboBox.SelectedIndex = 0;
}
public int deviceDoubleClickAction
{
get { return doubleClickComboBox.SelectedIndex; }
set { doubleClickComboBox.SelectedIndex = value; }
}
public bool ShowSystemTray
{
get { return systemTrayCheckBox.Checked; }
set { systemTrayCheckBox.Checked = value; }
}
public bool Exp_KeyboardHook
{
get { return exp_KeyboardHookCheckBox.Checked; }
set
{
exp_KeyboardHookCheckBox.Checked = value;
if (!value)
{
exp_KeyboardHookPriorityCheckBox.Checked = false;
exp_KeyboardHookPriorityCheckBox.Enabled = false;
}
}
}
public bool Exp_KeyboardHookPriority
{
get { return exp_KeyboardHookPriorityCheckBox.Checked; }
set { exp_KeyboardHookPriorityCheckBox.Checked = value; }
}
private void okButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
private void exp_KeyboardHookCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (exp_KeyboardHookCheckBox.Checked)
{
exp_KeyboardHookPriorityCheckBox.Enabled = true;
}
else
{
exp_KeyboardHookPriorityCheckBox.Checked = false;
exp_KeyboardHookPriorityCheckBox.Enabled = false;
}
}
}
}

2114
src/DeviceSettingsForm.resx Normal file

File diff suppressed because it is too large Load Diff

199
src/DeviceUserControl.Designer.cs generated Normal file
View File

@@ -0,0 +1,199 @@
namespace MeshCentralRouter
{
partial class DeviceUserControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DeviceUserControl));
this.devicePictureBox = new System.Windows.Forms.PictureBox();
this.deviceNameLabel = new System.Windows.Forms.Label();
this.deviceStatusLabel = new System.Windows.Forms.Label();
this.rdpButton = new System.Windows.Forms.Button();
this.rdpContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.setRDPPortToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.deviceImageList = new System.Windows.Forms.ImageList(this.components);
this.disabledDeviceImageList = new System.Windows.Forms.ImageList(this.components);
this.httpsButton = new System.Windows.Forms.Button();
this.altPortContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.httpButton = new System.Windows.Forms.Button();
this.scpButton = new System.Windows.Forms.Button();
this.sshButton = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.devicePictureBox)).BeginInit();
this.rdpContextMenuStrip.SuspendLayout();
this.altPortContextMenuStrip.SuspendLayout();
this.SuspendLayout();
//
// devicePictureBox
//
resources.ApplyResources(this.devicePictureBox, "devicePictureBox");
this.devicePictureBox.Name = "devicePictureBox";
this.devicePictureBox.TabStop = false;
//
// deviceNameLabel
//
resources.ApplyResources(this.deviceNameLabel, "deviceNameLabel");
this.deviceNameLabel.Name = "deviceNameLabel";
//
// deviceStatusLabel
//
resources.ApplyResources(this.deviceStatusLabel, "deviceStatusLabel");
this.deviceStatusLabel.Name = "deviceStatusLabel";
//
// rdpButton
//
resources.ApplyResources(this.rdpButton, "rdpButton");
this.rdpButton.ContextMenuStrip = this.rdpContextMenuStrip;
this.rdpButton.Name = "rdpButton";
this.rdpButton.UseVisualStyleBackColor = true;
this.rdpButton.Click += new System.EventHandler(this.rdpButton_Click);
//
// rdpContextMenuStrip
//
this.rdpContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.setRDPPortToolStripMenuItem});
this.rdpContextMenuStrip.Name = "rdpContextMenuStrip";
resources.ApplyResources(this.rdpContextMenuStrip, "rdpContextMenuStrip");
//
// setRDPPortToolStripMenuItem
//
this.setRDPPortToolStripMenuItem.Name = "setRDPPortToolStripMenuItem";
resources.ApplyResources(this.setRDPPortToolStripMenuItem, "setRDPPortToolStripMenuItem");
this.setRDPPortToolStripMenuItem.Click += new System.EventHandler(this.setRDPPortToolStripMenuItem_Click);
//
// deviceImageList
//
this.deviceImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("deviceImageList.ImageStream")));
this.deviceImageList.TransparentColor = System.Drawing.Color.Transparent;
this.deviceImageList.Images.SetKeyName(0, "icons01.png");
this.deviceImageList.Images.SetKeyName(1, "icons02.png");
this.deviceImageList.Images.SetKeyName(2, "icons03.png");
this.deviceImageList.Images.SetKeyName(3, "icons04.png");
this.deviceImageList.Images.SetKeyName(4, "icons05.png");
this.deviceImageList.Images.SetKeyName(5, "icons06.png");
this.deviceImageList.Images.SetKeyName(6, "icons07.png");
this.deviceImageList.Images.SetKeyName(7, "icons08.png");
//
// disabledDeviceImageList
//
this.disabledDeviceImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("disabledDeviceImageList.ImageStream")));
this.disabledDeviceImageList.TransparentColor = System.Drawing.Color.Transparent;
this.disabledDeviceImageList.Images.SetKeyName(0, "icons01t.png");
this.disabledDeviceImageList.Images.SetKeyName(1, "icons02t.png");
this.disabledDeviceImageList.Images.SetKeyName(2, "icons03t.png");
this.disabledDeviceImageList.Images.SetKeyName(3, "icons04t.png");
this.disabledDeviceImageList.Images.SetKeyName(4, "icons05t.png");
this.disabledDeviceImageList.Images.SetKeyName(5, "icons06t.png");
this.disabledDeviceImageList.Images.SetKeyName(6, "icons07t.png");
this.disabledDeviceImageList.Images.SetKeyName(7, "icons08t.png");
//
// httpsButton
//
resources.ApplyResources(this.httpsButton, "httpsButton");
this.httpsButton.ContextMenuStrip = this.altPortContextMenuStrip;
this.httpsButton.Name = "httpsButton";
this.httpsButton.UseVisualStyleBackColor = true;
this.httpsButton.Click += new System.EventHandler(this.httpsButton_Click);
//
// altPortContextMenuStrip
//
this.altPortContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripMenuItem1});
this.altPortContextMenuStrip.Name = "rdpContextMenuStrip";
resources.ApplyResources(this.altPortContextMenuStrip, "altPortContextMenuStrip");
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
resources.ApplyResources(this.toolStripMenuItem1, "toolStripMenuItem1");
this.toolStripMenuItem1.Click += new System.EventHandler(this.toolStripMenuItem1_Click);
//
// httpButton
//
resources.ApplyResources(this.httpButton, "httpButton");
this.httpButton.ContextMenuStrip = this.altPortContextMenuStrip;
this.httpButton.Name = "httpButton";
this.httpButton.UseVisualStyleBackColor = true;
this.httpButton.Click += new System.EventHandler(this.httpButton_Click);
//
// scpButton
//
resources.ApplyResources(this.scpButton, "scpButton");
this.scpButton.ContextMenuStrip = this.altPortContextMenuStrip;
this.scpButton.Name = "scpButton";
this.scpButton.UseVisualStyleBackColor = true;
this.scpButton.Click += new System.EventHandler(this.scpButton_Click);
//
// sshButton
//
resources.ApplyResources(this.sshButton, "sshButton");
this.sshButton.ContextMenuStrip = this.altPortContextMenuStrip;
this.sshButton.Name = "sshButton";
this.sshButton.UseVisualStyleBackColor = true;
this.sshButton.Click += new System.EventHandler(this.sshButton_Click);
//
// DeviceUserControl
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.ControlLight;
this.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.Controls.Add(this.scpButton);
this.Controls.Add(this.sshButton);
this.Controls.Add(this.httpButton);
this.Controls.Add(this.httpsButton);
this.Controls.Add(this.rdpButton);
this.Controls.Add(this.deviceStatusLabel);
this.Controls.Add(this.deviceNameLabel);
this.Controls.Add(this.devicePictureBox);
this.Name = "DeviceUserControl";
((System.ComponentModel.ISupportInitialize)(this.devicePictureBox)).EndInit();
this.rdpContextMenuStrip.ResumeLayout(false);
this.altPortContextMenuStrip.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.PictureBox devicePictureBox;
private System.Windows.Forms.Label deviceNameLabel;
private System.Windows.Forms.Label deviceStatusLabel;
private System.Windows.Forms.Button rdpButton;
private System.Windows.Forms.ImageList deviceImageList;
private System.Windows.Forms.ImageList disabledDeviceImageList;
private System.Windows.Forms.Button httpsButton;
private System.Windows.Forms.Button httpButton;
private System.Windows.Forms.Button scpButton;
private System.Windows.Forms.Button sshButton;
private System.Windows.Forms.ContextMenuStrip rdpContextMenuStrip;
private System.Windows.Forms.ToolStripMenuItem setRDPPortToolStripMenuItem;
private System.Windows.Forms.ContextMenuStrip altPortContextMenuStrip;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1;
}
}

150
src/DeviceUserControl.cs Normal file
View File

@@ -0,0 +1,150 @@
/*
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.Windows.Forms;
namespace MeshCentralRouter
{
public partial class DeviceUserControl : UserControl
{
public MeshClass mesh;
public NodeClass node;
public MainForm parent;
public bool present;
private bool xShowDeviceGroupName = true;
public bool showDeviceGroupName
{
get { return xShowDeviceGroupName; }
set { xShowDeviceGroupName = value; }
}
public DeviceUserControl()
{
InitializeComponent();
}
public void UpdateInfo()
{
if (parent.getShowGroupNames() && (mesh != null)) { deviceNameLabel.Text = mesh.name + ", " + node.name; } else { deviceNameLabel.Text = node.name; }
if ((node.icon > 0) && (node.icon <= disabledDeviceImageList.Images.Count))
{
if (node.conn == 0)
{
devicePictureBox.Image = disabledDeviceImageList.Images[node.icon - 1];
}
else
{
devicePictureBox.Image = deviceImageList.Images[node.icon - 1];
}
}
string status = "";
if ((node.conn & 1) != 0) { if (status.Length > 0) { status += ", "; } status += Translate.T(Properties.Resources.Agent); }
if ((node.conn & 2) != 0) { if (status.Length > 0) { status += ", "; } status += Translate.T(Properties.Resources.CIRA); }
if ((node.conn & 4) != 0) { if (status.Length > 0) { status += ", "; } status += Translate.T(Properties.Resources.AMT); }
if ((node.conn & 8) != 0) { if (status.Length > 0) { status += ", "; } status += Translate.T(Properties.Resources.Relay); }
if ((node.conn & 16) != 0) { if (status.Length > 0) { status += ", "; } status += Translate.T(Properties.Resources.MQTT); }
if (status == "") { status = Translate.T(Properties.Resources.Offline); }
deviceStatusLabel.Text = status;
if (node.agentid < 6) {
// Windows OS
sshButton.Visible = false;
scpButton.Visible = false;
rdpButton.Visible = true;
} else {
// Other OS
sshButton.Visible = true;
scpButton.Visible = true;
rdpButton.Visible = false;
}
// Compute rights on this device
ulong rights = node.rights; // Direct device rights
if (mesh != null) { rights |= mesh.rights; } // Device group rights
foreach (string i in node.links.Keys) { if (parent.meshcentral.userGroups.ContainsKey(i)) { rights |= node.links[i]; } } // Take a look at group rights
foreach (string i in parent.meshcentral.userRights.Keys) {
if ((i.StartsWith("ugrp/")) && (mesh.links.ContainsKey(i))) {
rights |= (ulong)mesh.links[i];
}
}
// Must have remote control rights
if ((rights & 8) != 0)
{
sshButton.Enabled = scpButton.Enabled = rdpButton.Enabled = httpsButton.Enabled = httpButton.Enabled = ((node.conn & 1) != 0);
}
else
{
sshButton.Enabled = scpButton.Enabled = rdpButton.Enabled = httpsButton.Enabled = httpButton.Enabled = false;
}
}
private void httpButton_Click(object sender, System.EventArgs e)
{
parent.QuickMap(1, 80, 1, node); // HTTP
}
private void httpsButton_Click(object sender, System.EventArgs e)
{
parent.QuickMap(1, 443, 2, node); // HTTPS
}
private void sshButton_Click(object sender, System.EventArgs e)
{
parent.QuickMap(1, 22, 4, node); // Putty
}
private void scpButton_Click(object sender, System.EventArgs e)
{
parent.QuickMap(1, 22, 5, node); // WinSCP
}
private void rdpButton_Click(object sender, System.EventArgs e)
{
int rdpport = 3389;
if (node.rdpport != 0) { rdpport = node.rdpport; }
parent.QuickMap(1, rdpport, 3, node); // RDP
}
private void setRDPPortToolStripMenuItem_Click(object sender, System.EventArgs e)
{
int rdpport = 3389;
if (node.rdpport != 0) { rdpport = node.rdpport; }
rdpPortForm form = new rdpPortForm();
form.rdpPort = node.rdpport;
if ((form.ShowDialog(this) == DialogResult.OK) && (rdpport != form.rdpPort))
{
parent.meshcentral.setRdpPort(node, form.rdpPort);
}
}
private void toolStripMenuItem1_Click(object sender, System.EventArgs e)
{
int port = 0, appid = 0;
if (altPortContextMenuStrip.SourceControl == httpButton) { appid = 1; port = 80; } // HTTP
if (altPortContextMenuStrip.SourceControl == httpsButton) { appid = 2; port = 443; } // HTTPS
if (altPortContextMenuStrip.SourceControl == scpButton) { appid = 5; port = 22; } // SCP
if (altPortContextMenuStrip.SourceControl == sshButton) { appid = 4; port = 22; } // SSH
if (appid == 0) return;
altPortForm form = new altPortForm();
form.altPort = port;
if ((form.ShowDialog(this) == DialogResult.OK)) { parent.QuickMap(1, form.altPort, appid, node); }
}
}
}

1868
src/DeviceUserControl.resx Normal file

File diff suppressed because it is too large Load Diff

128
src/FileConfirmOverwriteForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,128 @@
namespace MeshCentralRouter
{
partial class FileConfirmOverwriteForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.mainGroupBox = new System.Windows.Forms.GroupBox();
this.mainLabel = new System.Windows.Forms.Label();
this.okButton = new System.Windows.Forms.Button();
this.cancelButton = new System.Windows.Forms.Button();
this.skipCheckBox = new System.Windows.Forms.CheckBox();
this.mainGroupBox.SuspendLayout();
this.SuspendLayout();
//
// mainGroupBox
//
this.mainGroupBox.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.mainGroupBox.Controls.Add(this.skipCheckBox);
this.mainGroupBox.Controls.Add(this.mainLabel);
this.mainGroupBox.Location = new System.Drawing.Point(12, 12);
this.mainGroupBox.Name = "mainGroupBox";
this.mainGroupBox.Size = new System.Drawing.Size(315, 73);
this.mainGroupBox.TabIndex = 6;
this.mainGroupBox.TabStop = false;
this.mainGroupBox.Text = "Confirm Overwrite";
//
// mainLabel
//
this.mainLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.mainLabel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.mainLabel.Location = new System.Drawing.Point(14, 23);
this.mainLabel.Name = "mainLabel";
this.mainLabel.Size = new System.Drawing.Size(295, 22);
this.mainLabel.TabIndex = 1;
this.mainLabel.Text = "---";
//
// okButton
//
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.okButton.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.okButton.Location = new System.Drawing.Point(171, 91);
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(252, 91);
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);
//
// skipCheckBox
//
this.skipCheckBox.AutoSize = true;
this.skipCheckBox.Location = new System.Drawing.Point(17, 44);
this.skipCheckBox.Name = "skipCheckBox";
this.skipCheckBox.Size = new System.Drawing.Size(106, 17);
this.skipCheckBox.TabIndex = 2;
this.skipCheckBox.Text = "Skip existing files";
this.skipCheckBox.UseVisualStyleBackColor = true;
//
// FileConfirmOverwriteForm
//
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(339, 126);
this.Controls.Add(this.mainGroupBox);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Name = "FileConfirmOverwriteForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "File Operation";
this.mainGroupBox.ResumeLayout(false);
this.mainGroupBox.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox mainGroupBox;
private System.Windows.Forms.Label mainLabel;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.CheckBox skipCheckBox;
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Windows.Forms;
namespace MeshCentralRouter
{
public partial class FileConfirmOverwriteForm : Form
{
public FileConfirmOverwriteForm()
{
InitializeComponent();
skipCheckBox.Checked = (Settings.GetRegValue("skipExistingFiles", "0") == "1");
}
public string mainTextLabel { get { return mainLabel.Text; } set { mainLabel.Text = value; } }
public bool skipExistingFiles { get { return skipCheckBox.Checked; } set { skipCheckBox.Checked = value; } }
private void okButton_Click(object sender, EventArgs e)
{
Settings.SetRegValue("skipExistingFiles", skipCheckBox.Checked ? "1" : "0");
DialogResult = DialogResult.OK;
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

101
src/FileDeletePromptForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,101 @@
namespace MeshCentralRouter
{
partial class FileDeletePromptForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FileDeletePromptForm));
this.mainGroupBox = new System.Windows.Forms.GroupBox();
this.mainLabel = new System.Windows.Forms.Label();
this.recursiveCheckBox = new System.Windows.Forms.CheckBox();
this.okButton = new System.Windows.Forms.Button();
this.cancelButton = new System.Windows.Forms.Button();
this.mainGroupBox.SuspendLayout();
this.SuspendLayout();
//
// mainGroupBox
//
resources.ApplyResources(this.mainGroupBox, "mainGroupBox");
this.mainGroupBox.Controls.Add(this.mainLabel);
this.mainGroupBox.Controls.Add(this.recursiveCheckBox);
this.mainGroupBox.Name = "mainGroupBox";
this.mainGroupBox.TabStop = false;
//
// mainLabel
//
resources.ApplyResources(this.mainLabel, "mainLabel");
this.mainLabel.Name = "mainLabel";
//
// recursiveCheckBox
//
resources.ApplyResources(this.recursiveCheckBox, "recursiveCheckBox");
this.recursiveCheckBox.Name = "recursiveCheckBox";
this.recursiveCheckBox.UseVisualStyleBackColor = true;
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// FileDeletePromptForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.mainGroupBox);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FileDeletePromptForm";
this.mainGroupBox.ResumeLayout(false);
this.mainGroupBox.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox mainGroupBox;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Label mainLabel;
private System.Windows.Forms.CheckBox recursiveCheckBox;
}
}

View File

@@ -0,0 +1,48 @@
/*
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.Windows.Forms;
namespace MeshCentralRouter
{
public partial class FileDeletePromptForm : Form
{
public FileDeletePromptForm(string message, bool rec)
{
InitializeComponent();
Translate.TranslateControl(this);
mainLabel.Text = message;
if (rec == false)
{
recursiveCheckBox.Visible = false;
Height = 142;
}
}
public bool recursive { get { return recursiveCheckBox.Checked; } }
private void okButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}

File diff suppressed because it is too large Load Diff

124
src/FileDialogMsgForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,124 @@
namespace MeshCentralRouter
{
partial class FileDialogMsgForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FileDialogMsgForm));
this.mainGroupBox = new System.Windows.Forms.GroupBox();
this.mainLabel2 = new System.Windows.Forms.Label();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.mainLabel1 = new System.Windows.Forms.Label();
this.cancelButton = new System.Windows.Forms.Button();
this.mainGroupBox.SuspendLayout();
this.SuspendLayout();
//
// mainGroupBox
//
this.mainGroupBox.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.mainGroupBox.Controls.Add(this.mainLabel2);
this.mainGroupBox.Controls.Add(this.progressBar1);
this.mainGroupBox.Controls.Add(this.mainLabel1);
this.mainGroupBox.Location = new System.Drawing.Point(12, 12);
this.mainGroupBox.Name = "mainGroupBox";
this.mainGroupBox.Size = new System.Drawing.Size(345, 98);
this.mainGroupBox.TabIndex = 5;
this.mainGroupBox.TabStop = false;
this.mainGroupBox.Text = "Compression Progress";
//
// mainLabel2
//
this.mainLabel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.mainLabel2.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.mainLabel2.Location = new System.Drawing.Point(14, 43);
this.mainLabel2.Name = "mainLabel2";
this.mainLabel2.Size = new System.Drawing.Size(314, 13);
this.mainLabel2.TabIndex = 3;
this.mainLabel2.Text = "---";
//
// progressBar1
//
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressBar1.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.progressBar1.Location = new System.Drawing.Point(17, 65);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(311, 16);
this.progressBar1.TabIndex = 2;
//
// mainLabel1
//
this.mainLabel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.mainLabel1.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.mainLabel1.Location = new System.Drawing.Point(14, 23);
this.mainLabel1.Name = "mainLabel1";
this.mainLabel1.Size = new System.Drawing.Size(314, 13);
this.mainLabel1.TabIndex = 1;
this.mainLabel1.Text = "---";
//
// cancelButton
//
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.cancelButton.Location = new System.Drawing.Point(282, 116);
this.cancelButton.Name = "cancelButton";
this.cancelButton.Size = new System.Drawing.Size(75, 23);
this.cancelButton.TabIndex = 6;
this.cancelButton.Text = "Cancel";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// FileDialogMsgForm
//
this.AcceptButton = this.cancelButton;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(369, 151);
this.Controls.Add(this.cancelButton);
this.Controls.Add(this.mainGroupBox);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "FileDialogMsgForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "File Operation";
this.mainGroupBox.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox mainGroupBox;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label mainLabel1;
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Label mainLabel2;
}
}

36
src/FileDialogMsgForm.cs Normal file
View File

@@ -0,0 +1,36 @@
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 FileDialogMsgForm : Form
{
private FileViewer xparent = null;
public FileDialogMsgForm(FileViewer xparent)
{
this.xparent = xparent;
InitializeComponent();
Translate.TranslateControl(this);
}
public void UpdateStatus(string msg, string file, int progress)
{
if (msg != null) { mainLabel1.Text = msg; } else { mainLabel1.Text = ""; }
if (file != null) { mainLabel2.Text = file; } else { mainLabel2.Text = ""; }
if ((progress >= 0) && (progress <= 100)) { progressBar1.Value = progress; }
}
private void cancelButton_Click(object sender, EventArgs e)
{
xparent.requestCancel();
}
}
}

1815
src/FileDialogMsgForm.resx Normal file

File diff suppressed because it is too large Load Diff

136
src/FileTransferStatusForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,136 @@
namespace MeshCentralRouter
{
partial class FileTransferStatusForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FileTransferStatusForm));
this.cancelButton = new System.Windows.Forms.Button();
this.mainGroupBox = new System.Windows.Forms.GroupBox();
this.errorsTextBox = new System.Windows.Forms.TextBox();
this.mainLabel2 = new System.Windows.Forms.Label();
this.progressBar2 = new System.Windows.Forms.ProgressBar();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.mainLabel1 = new System.Windows.Forms.Label();
this.updateTimer = new System.Windows.Forms.Timer(this.components);
this.errorsGroupBox = new System.Windows.Forms.GroupBox();
this.mainGroupBox.SuspendLayout();
this.errorsGroupBox.SuspendLayout();
this.SuspendLayout();
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// mainGroupBox
//
resources.ApplyResources(this.mainGroupBox, "mainGroupBox");
this.mainGroupBox.Controls.Add(this.mainLabel2);
this.mainGroupBox.Controls.Add(this.progressBar2);
this.mainGroupBox.Controls.Add(this.progressBar1);
this.mainGroupBox.Controls.Add(this.mainLabel1);
this.mainGroupBox.Name = "mainGroupBox";
this.mainGroupBox.TabStop = false;
//
// errorsTextBox
//
resources.ApplyResources(this.errorsTextBox, "errorsTextBox");
this.errorsTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.errorsTextBox.Name = "errorsTextBox";
this.errorsTextBox.ReadOnly = true;
//
// mainLabel2
//
resources.ApplyResources(this.mainLabel2, "mainLabel2");
this.mainLabel2.Name = "mainLabel2";
//
// progressBar2
//
resources.ApplyResources(this.progressBar2, "progressBar2");
this.progressBar2.Name = "progressBar2";
//
// progressBar1
//
resources.ApplyResources(this.progressBar1, "progressBar1");
this.progressBar1.Name = "progressBar1";
//
// mainLabel1
//
resources.ApplyResources(this.mainLabel1, "mainLabel1");
this.mainLabel1.Name = "mainLabel1";
//
// updateTimer
//
this.updateTimer.Interval = 500;
this.updateTimer.Tick += new System.EventHandler(this.updateTimer_Tick);
//
// errorsGroupBox
//
this.errorsGroupBox.Controls.Add(this.errorsTextBox);
resources.ApplyResources(this.errorsGroupBox, "errorsGroupBox");
this.errorsGroupBox.Name = "errorsGroupBox";
this.errorsGroupBox.TabStop = false;
//
// FileTransferStatusForm
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.errorsGroupBox);
this.Controls.Add(this.mainGroupBox);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FileTransferStatusForm";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FileTransferStatusForm_FormClosing);
this.Load += new System.EventHandler(this.FileTransferStatusForm_Load);
this.mainGroupBox.ResumeLayout(false);
this.errorsGroupBox.ResumeLayout(false);
this.errorsGroupBox.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.GroupBox mainGroupBox;
private System.Windows.Forms.ProgressBar progressBar2;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label mainLabel1;
private System.Windows.Forms.Timer updateTimer;
private System.Windows.Forms.Label mainLabel2;
private System.Windows.Forms.TextBox errorsTextBox;
private System.Windows.Forms.GroupBox errorsGroupBox;
}
}

View File

@@ -0,0 +1,211 @@
/*
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;
namespace MeshCentralRouter
{
public partial class FileTransferStatusForm : Form
{
private FileViewer fileViewer;
private bool loaded = false;
public bool showingError = false;
private string errors = "";
private bool done = false;
private Point mainBoxLocation;
private Point errorBoxLocation;
public FileTransferStatusForm(FileViewer fileViewer)
{
this.fileViewer = fileViewer;
InitializeComponent();
Translate.TranslateControl(this);
updateInfo();
updateTimer.Enabled = true;
mainBoxLocation = mainGroupBox.Location;
errorBoxLocation = errorsGroupBox.Location;
}
private void updateTimer_Tick(object sender, EventArgs e)
{
updateInfo();
}
public delegate void updateErrorMessageshandler();
public void addErrorMessage(string msg)
{
lock (this)
{
errors += (msg + "\r\n");
showingError = true;
}
if (loaded == false) return;
if (this.InvokeRequired) { this.Invoke(new updateErrorMessageshandler(updateErrorMessages)); } else { updateErrorMessages(); }
}
public void updateErrorMessages()
{
showDialogParts(!done, showingError);
lock (this) { errorsTextBox.Text = errors; }
}
public void transferCompleted()
{
done = true;
showDialogParts(!done, showingError);
}
private void updateInfo()
{
if (fileViewer.uploadActive)
{
mainLabel1.Text = (string)fileViewer.uploadFileArray[fileViewer.uploadFileArrayPtr];
progressBar1.Maximum = (int)fileViewer.uploadFileSize;
int x = (int)fileViewer.uploadFilePtr;
if (x < 0) { x = 0; }
if (x > (int)fileViewer.uploadFileSize) { x = (int)fileViewer.uploadFileSize; }
progressBar1.Value = x;
// Compute bytes per second & estimated time left
double elapseTimeSeconds = DateTime.Now.Subtract(fileViewer.uploadFileStartTime).TotalMilliseconds / 1000;
if (elapseTimeSeconds < 5) { mainLabel2.Text = Translate.T(Properties.Resources.EstimatingDotDotDot); } else
{
double bytePerSecond = (x - fileViewer.uploadFileStartPtr) / elapseTimeSeconds;
double secondsLeft = Math.Round((fileViewer.uploadFileSize - x) / bytePerSecond);
mainLabel2.Text = bytePerSecondToString(bytePerSecond) + ", " + secondsLeftToString(secondsLeft);
}
progressBar2.Maximum = fileViewer.uploadFileArray.Count;
x = (int)fileViewer.uploadFileArrayPtr;
if (x < 0) { x = 0; }
if (x > (int)fileViewer.uploadFileArray.Count) { x = fileViewer.uploadFileArray.Count; }
progressBar2.Value = fileViewer.uploadFileArrayPtr;
}
else if (fileViewer.downloadActive)
{
mainLabel1.Text = (string)fileViewer.downloadFileArray[fileViewer.downloadFileArrayPtr];
progressBar1.Maximum = (int)fileViewer.downloadFileSize;
int x = (int)fileViewer.downloadFilePtr;
if (x < 0) { x = 0; }
if (x > (int)fileViewer.downloadFileSize) { x = (int)fileViewer.downloadFileSize; }
progressBar1.Value = x;
// Compute bytes per second & estimated time left
double elapseTimeSeconds = DateTime.Now.Subtract(fileViewer.downloadFileStartTime).TotalMilliseconds / 1000;
if (elapseTimeSeconds < 5) { mainLabel2.Text = Translate.T(Properties.Resources.EstimatingDotDotDot); } else
{
double bytePerSecond = x / elapseTimeSeconds;
double secondsLeft = Math.Round((fileViewer.downloadFileSize - x) / bytePerSecond);
mainLabel2.Text = bytePerSecondToString(bytePerSecond) + ", " + secondsLeftToString(secondsLeft);
}
progressBar2.Maximum = fileViewer.downloadFileArray.Count;
x = (int)fileViewer.downloadFileArrayPtr;
if (x < 0) { x = 0; }
if (x > (int)fileViewer.downloadFileArray.Count) { x = fileViewer.downloadFileArray.Count; }
progressBar2.Value = fileViewer.downloadFileArrayPtr;
}
else
{
done = true;
if (showingError == false) { Close(); } else { cancelButton.Text = Translate.T(Properties.Resources.Close); }
}
}
private string secondsLeftToString(double x)
{
if (x > 5400) return String.Format(Translate.T(Properties.Resources.xhoursleft), Math.Round(x / 60 / 60));
if (x > 90) return String.Format(Translate.T(Properties.Resources.xminutesleft), Math.Round(x / 60));
if (x > 1) return String.Format(Translate.T(Properties.Resources.xsecondsleft), Math.Round(x));
return Translate.T(Properties.Resources.Almostdone);
}
private string bytePerSecondToString(double x)
{
if (x > 1200000000) return String.Format(Translate.T(Properties.Resources.XGbytesPersec), Math.Round((x / 1024 / 1024 / 1024) * 10) / 10);
if (x > 1200000) return String.Format(Translate.T(Properties.Resources.XMbytesPersec), Math.Round((x / 1024 / 1024) * 10) / 10);
if (x > 1200) return String.Format(Translate.T(Properties.Resources.XKbytesPersec), Math.Round((x / 1024) * 10) / 10);
return String.Format(Translate.T(Properties.Resources.XbytesPersec), x);
}
private void FileTransferStatusForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (fileViewer.uploadActive) { fileViewer.uploadStop = true; }
if (fileViewer.downloadActive) { fileViewer.downloadStop = true; }
}
private void cancelButton_Click(object sender, EventArgs e)
{
if (done)
{
fileViewer.transferStatusForm = null;
Close();
}
else
{
// Cancel file transfer
if (fileViewer.uploadActive) { fileViewer.uploadCancel(); }
if (fileViewer.downloadActive) { fileViewer.downloadCancel(); }
}
}
private void FileTransferStatusForm_Load(object sender, EventArgs e)
{
CenterToParent();
lock (this) { errorsTextBox.Text = errors; }
loaded = true;
showDialogParts(!done, showingError);
}
private void showDialogParts(bool status, bool errors)
{
mainGroupBox.Visible = status;
errorsGroupBox.Visible = errors;
if (errors == false)
{
if (status == false)
{
// Show nothing
this.Height = 109;
}
else
{
// Show only status box
this.Height = mainGroupBox.Height + 99;
}
}
else
{
if (status == false)
{
// Show only error box
this.Height = errorsGroupBox.Height + 99;
errorsGroupBox.Location = mainBoxLocation;
}
else
{
// Show both status and error box
this.Height = mainGroupBox.Height + errorsGroupBox.Height + 109;
errorsGroupBox.Location = errorBoxLocation;
}
}
}
}
}

File diff suppressed because it is too large Load Diff

557
src/FileViewer.Designer.cs generated Normal file
View File

@@ -0,0 +1,557 @@
using System.Windows.Forms;
namespace MeshCentralRouter
{
partial class FileViewer
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FileViewer));
this.updateTimer = new System.Windows.Forms.Timer(this.components);
this.consoleTimer = new System.Windows.Forms.Timer(this.components);
this.mainToolTip = new System.Windows.Forms.ToolTip(this.components);
this.statsButton = new System.Windows.Forms.Button();
this.connectButton = new System.Windows.Forms.Button();
this.remoteRefreshButton = new System.Windows.Forms.Button();
this.remoteUpButton = new System.Windows.Forms.Button();
this.localRefreshButton = new System.Windows.Forms.Button();
this.localUpButton = new System.Windows.Forms.Button();
this.remoteNewFolderButton = new System.Windows.Forms.Button();
this.remoteRootButton = new System.Windows.Forms.Button();
this.localRootButton = new System.Windows.Forms.Button();
this.remoteDeleteButton = new System.Windows.Forms.Button();
this.downloadButton = new System.Windows.Forms.Button();
this.uploadButton = new System.Windows.Forms.Button();
this.localDeleteButton = new System.Windows.Forms.Button();
this.localNewFolderButton = new System.Windows.Forms.Button();
this.remoteZipButton = new System.Windows.Forms.Button();
this.topPanel = new System.Windows.Forms.Panel();
this.statusStrip = new System.Windows.Forms.StatusStrip();
this.mainToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.consoleMessage = new System.Windows.Forms.Label();
this.mainTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel();
this.panel1 = new System.Windows.Forms.Panel();
this.rightPanel = new System.Windows.Forms.Panel();
this.rightListView = new System.Windows.Forms.ListView();
this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.remoteContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.renameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.compressToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.deleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.refreshToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.fileIconImageList = new System.Windows.Forms.ImageList(this.components);
this.rightTopPanel = new System.Windows.Forms.Panel();
this.remoteLabel = new System.Windows.Forms.Label();
this.leftPanel = new System.Windows.Forms.Panel();
this.leftListView = 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.localContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.renameToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.deleteToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
this.refreshToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.leftTopPanel = new System.Windows.Forms.Panel();
this.localLabel = new System.Windows.Forms.Label();
this.topPanel.SuspendLayout();
this.statusStrip.SuspendLayout();
this.mainTableLayoutPanel.SuspendLayout();
this.panel1.SuspendLayout();
this.rightPanel.SuspendLayout();
this.remoteContextMenuStrip.SuspendLayout();
this.rightTopPanel.SuspendLayout();
this.leftPanel.SuspendLayout();
this.localContextMenuStrip.SuspendLayout();
this.leftTopPanel.SuspendLayout();
this.SuspendLayout();
//
// updateTimer
//
this.updateTimer.Tick += new System.EventHandler(this.updateTimer_Tick);
//
// consoleTimer
//
this.consoleTimer.Interval = 5000;
this.consoleTimer.Tick += new System.EventHandler(this.consoleTimer_Tick);
//
// statsButton
//
resources.ApplyResources(this.statsButton, "statsButton");
this.statsButton.Name = "statsButton";
this.statsButton.TabStop = false;
this.mainToolTip.SetToolTip(this.statsButton, resources.GetString("statsButton.ToolTip"));
this.statsButton.UseVisualStyleBackColor = true;
//
// connectButton
//
resources.ApplyResources(this.connectButton, "connectButton");
this.connectButton.Name = "connectButton";
this.connectButton.TabStop = false;
this.mainToolTip.SetToolTip(this.connectButton, resources.GetString("connectButton.ToolTip"));
this.connectButton.UseVisualStyleBackColor = true;
this.connectButton.Click += new System.EventHandler(this.connectButton_Click);
//
// remoteRefreshButton
//
resources.ApplyResources(this.remoteRefreshButton, "remoteRefreshButton");
this.remoteRefreshButton.Image = global::MeshCentralRouter.Properties.Resources.refresh16;
this.remoteRefreshButton.Name = "remoteRefreshButton";
this.mainToolTip.SetToolTip(this.remoteRefreshButton, resources.GetString("remoteRefreshButton.ToolTip"));
this.remoteRefreshButton.UseVisualStyleBackColor = true;
this.remoteRefreshButton.Click += new System.EventHandler(this.rightRefreshButton_Click);
//
// remoteUpButton
//
resources.ApplyResources(this.remoteUpButton, "remoteUpButton");
this.remoteUpButton.Image = global::MeshCentralRouter.Properties.Resources.folderup16;
this.remoteUpButton.Name = "remoteUpButton";
this.mainToolTip.SetToolTip(this.remoteUpButton, resources.GetString("remoteUpButton.ToolTip"));
this.remoteUpButton.UseVisualStyleBackColor = true;
this.remoteUpButton.Click += new System.EventHandler(this.remoteUpButton_Click);
//
// localRefreshButton
//
this.localRefreshButton.Image = global::MeshCentralRouter.Properties.Resources.refresh16;
resources.ApplyResources(this.localRefreshButton, "localRefreshButton");
this.localRefreshButton.Name = "localRefreshButton";
this.mainToolTip.SetToolTip(this.localRefreshButton, resources.GetString("localRefreshButton.ToolTip"));
this.localRefreshButton.UseVisualStyleBackColor = true;
this.localRefreshButton.Click += new System.EventHandler(this.leftRefreshButton_Click);
//
// localUpButton
//
resources.ApplyResources(this.localUpButton, "localUpButton");
this.localUpButton.Image = global::MeshCentralRouter.Properties.Resources.folderup16;
this.localUpButton.Name = "localUpButton";
this.mainToolTip.SetToolTip(this.localUpButton, resources.GetString("localUpButton.ToolTip"));
this.localUpButton.UseVisualStyleBackColor = true;
this.localUpButton.Click += new System.EventHandler(this.localUpButton_Click);
//
// remoteNewFolderButton
//
resources.ApplyResources(this.remoteNewFolderButton, "remoteNewFolderButton");
this.remoteNewFolderButton.Image = global::MeshCentralRouter.Properties.Resources.foldernew16;
this.remoteNewFolderButton.Name = "remoteNewFolderButton";
this.mainToolTip.SetToolTip(this.remoteNewFolderButton, resources.GetString("remoteNewFolderButton.ToolTip"));
this.remoteNewFolderButton.UseVisualStyleBackColor = true;
this.remoteNewFolderButton.Click += new System.EventHandler(this.remoteNewFolderButton_Click);
//
// remoteRootButton
//
resources.ApplyResources(this.remoteRootButton, "remoteRootButton");
this.remoteRootButton.Image = global::MeshCentralRouter.Properties.Resources.folderroot16;
this.remoteRootButton.Name = "remoteRootButton";
this.mainToolTip.SetToolTip(this.remoteRootButton, resources.GetString("remoteRootButton.ToolTip"));
this.remoteRootButton.UseVisualStyleBackColor = true;
this.remoteRootButton.Click += new System.EventHandler(this.remoteRootButton_Click);
//
// localRootButton
//
resources.ApplyResources(this.localRootButton, "localRootButton");
this.localRootButton.Image = global::MeshCentralRouter.Properties.Resources.folderroot16;
this.localRootButton.Name = "localRootButton";
this.mainToolTip.SetToolTip(this.localRootButton, resources.GetString("localRootButton.ToolTip"));
this.localRootButton.UseVisualStyleBackColor = true;
this.localRootButton.Click += new System.EventHandler(this.localRootButton_Click);
//
// remoteDeleteButton
//
resources.ApplyResources(this.remoteDeleteButton, "remoteDeleteButton");
this.remoteDeleteButton.Image = global::MeshCentralRouter.Properties.Resources.delete16;
this.remoteDeleteButton.Name = "remoteDeleteButton";
this.mainToolTip.SetToolTip(this.remoteDeleteButton, resources.GetString("remoteDeleteButton.ToolTip"));
this.remoteDeleteButton.UseVisualStyleBackColor = true;
this.remoteDeleteButton.Click += new System.EventHandler(this.remoteDeleteButton_Click);
//
// downloadButton
//
resources.ApplyResources(this.downloadButton, "downloadButton");
this.downloadButton.Image = global::MeshCentralRouter.Properties.Resources.arrowleft16;
this.downloadButton.Name = "downloadButton";
this.mainToolTip.SetToolTip(this.downloadButton, resources.GetString("downloadButton.ToolTip"));
this.downloadButton.UseVisualStyleBackColor = true;
this.downloadButton.Click += new System.EventHandler(this.downloadButton_Click);
//
// uploadButton
//
resources.ApplyResources(this.uploadButton, "uploadButton");
this.uploadButton.Image = global::MeshCentralRouter.Properties.Resources.arrowright16;
this.uploadButton.Name = "uploadButton";
this.mainToolTip.SetToolTip(this.uploadButton, resources.GetString("uploadButton.ToolTip"));
this.uploadButton.UseVisualStyleBackColor = true;
this.uploadButton.Click += new System.EventHandler(this.uploadButton_Click);
//
// localDeleteButton
//
resources.ApplyResources(this.localDeleteButton, "localDeleteButton");
this.localDeleteButton.Image = global::MeshCentralRouter.Properties.Resources.delete16;
this.localDeleteButton.Name = "localDeleteButton";
this.mainToolTip.SetToolTip(this.localDeleteButton, resources.GetString("localDeleteButton.ToolTip"));
this.localDeleteButton.UseVisualStyleBackColor = true;
this.localDeleteButton.Click += new System.EventHandler(this.localDeleteButton_Click);
//
// localNewFolderButton
//
resources.ApplyResources(this.localNewFolderButton, "localNewFolderButton");
this.localNewFolderButton.Image = global::MeshCentralRouter.Properties.Resources.foldernew16;
this.localNewFolderButton.Name = "localNewFolderButton";
this.mainToolTip.SetToolTip(this.localNewFolderButton, resources.GetString("localNewFolderButton.ToolTip"));
this.localNewFolderButton.UseVisualStyleBackColor = true;
this.localNewFolderButton.Click += new System.EventHandler(this.localNewFolderButton_Click);
//
// remoteZipButton
//
resources.ApplyResources(this.remoteZipButton, "remoteZipButton");
this.remoteZipButton.Image = global::MeshCentralRouter.Properties.Resources.folderzip;
this.remoteZipButton.Name = "remoteZipButton";
this.mainToolTip.SetToolTip(this.remoteZipButton, resources.GetString("remoteZipButton.ToolTip"));
this.remoteZipButton.UseVisualStyleBackColor = true;
this.remoteZipButton.Click += new System.EventHandler(this.remoteZipButton_Click);
//
// topPanel
//
this.topPanel.BackColor = System.Drawing.SystemColors.Control;
this.topPanel.Controls.Add(this.statsButton);
this.topPanel.Controls.Add(this.connectButton);
resources.ApplyResources(this.topPanel, "topPanel");
this.topPanel.Name = "topPanel";
//
// statusStrip
//
this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mainToolStripStatusLabel});
resources.ApplyResources(this.statusStrip, "statusStrip");
this.statusStrip.Name = "statusStrip";
//
// mainToolStripStatusLabel
//
this.mainToolStripStatusLabel.Name = "mainToolStripStatusLabel";
resources.ApplyResources(this.mainToolStripStatusLabel, "mainToolStripStatusLabel");
this.mainToolStripStatusLabel.Spring = true;
//
// consoleMessage
//
resources.ApplyResources(this.consoleMessage, "consoleMessage");
this.consoleMessage.ForeColor = System.Drawing.Color.Black;
this.consoleMessage.Name = "consoleMessage";
//
// mainTableLayoutPanel
//
resources.ApplyResources(this.mainTableLayoutPanel, "mainTableLayoutPanel");
this.mainTableLayoutPanel.Controls.Add(this.panel1, 0, 0);
this.mainTableLayoutPanel.Controls.Add(this.rightPanel, 1, 0);
this.mainTableLayoutPanel.Controls.Add(this.leftPanel, 0, 0);
this.mainTableLayoutPanel.Name = "mainTableLayoutPanel";
//
// panel1
//
this.panel1.Controls.Add(this.downloadButton);
this.panel1.Controls.Add(this.uploadButton);
resources.ApplyResources(this.panel1, "panel1");
this.panel1.Name = "panel1";
//
// rightPanel
//
this.rightPanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.rightPanel.Controls.Add(this.rightListView);
this.rightPanel.Controls.Add(this.rightTopPanel);
resources.ApplyResources(this.rightPanel, "rightPanel");
this.rightPanel.Name = "rightPanel";
//
// rightListView
//
this.rightListView.AllowDrop = true;
this.rightListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader3,
this.columnHeader4});
this.rightListView.ContextMenuStrip = this.remoteContextMenuStrip;
resources.ApplyResources(this.rightListView, "rightListView");
this.rightListView.FullRowSelect = true;
this.rightListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.rightListView.HideSelection = false;
this.rightListView.Name = "rightListView";
this.rightListView.SmallImageList = this.fileIconImageList;
this.rightListView.UseCompatibleStateImageBehavior = false;
this.rightListView.View = System.Windows.Forms.View.Details;
this.rightListView.ColumnWidthChanged += new System.Windows.Forms.ColumnWidthChangedEventHandler(this.rightListView_ColumnWidthChanged);
this.rightListView.SelectedIndexChanged += new System.EventHandler(this.rightListView_SelectedIndexChanged);
this.rightListView.DragDrop += new System.Windows.Forms.DragEventHandler(this.rightListView_DragDrop);
this.rightListView.DragEnter += new System.Windows.Forms.DragEventHandler(this.rightListView_DragEnter);
this.rightListView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.rightListView_MouseDoubleClick);
this.rightListView.MouseMove += new System.Windows.Forms.MouseEventHandler(this.rightListView_MouseMove);
this.rightListView.Resize += new System.EventHandler(this.rightListView_Resize);
//
// columnHeader3
//
resources.ApplyResources(this.columnHeader3, "columnHeader3");
//
// columnHeader4
//
resources.ApplyResources(this.columnHeader4, "columnHeader4");
//
// remoteContextMenuStrip
//
this.remoteContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.renameToolStripMenuItem,
this.compressToolStripMenuItem,
this.deleteToolStripMenuItem,
this.toolStripMenuItem1,
this.refreshToolStripMenuItem});
this.remoteContextMenuStrip.Name = "remoteContextMenuStrip";
resources.ApplyResources(this.remoteContextMenuStrip, "remoteContextMenuStrip");
this.remoteContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.remoteContextMenuStrip_Opening);
//
// renameToolStripMenuItem
//
this.renameToolStripMenuItem.Name = "renameToolStripMenuItem";
resources.ApplyResources(this.renameToolStripMenuItem, "renameToolStripMenuItem");
this.renameToolStripMenuItem.Click += new System.EventHandler(this.renameToolStripMenuItem_Click);
//
// compressToolStripMenuItem
//
this.compressToolStripMenuItem.Name = "compressToolStripMenuItem";
resources.ApplyResources(this.compressToolStripMenuItem, "compressToolStripMenuItem");
this.compressToolStripMenuItem.Click += new System.EventHandler(this.remoteZipButton_Click);
//
// deleteToolStripMenuItem
//
this.deleteToolStripMenuItem.Name = "deleteToolStripMenuItem";
resources.ApplyResources(this.deleteToolStripMenuItem, "deleteToolStripMenuItem");
this.deleteToolStripMenuItem.Click += new System.EventHandler(this.remoteDeleteButton_Click);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
resources.ApplyResources(this.toolStripMenuItem1, "toolStripMenuItem1");
//
// refreshToolStripMenuItem
//
this.refreshToolStripMenuItem.Name = "refreshToolStripMenuItem";
resources.ApplyResources(this.refreshToolStripMenuItem, "refreshToolStripMenuItem");
this.refreshToolStripMenuItem.Click += new System.EventHandler(this.rightRefreshButton_Click);
//
// fileIconImageList
//
this.fileIconImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("fileIconImageList.ImageStream")));
this.fileIconImageList.TransparentColor = System.Drawing.Color.Transparent;
this.fileIconImageList.Images.SetKeyName(0, "drive16.png");
this.fileIconImageList.Images.SetKeyName(1, "folder16.png");
this.fileIconImageList.Images.SetKeyName(2, "file16.png");
//
// rightTopPanel
//
this.rightTopPanel.Controls.Add(this.remoteZipButton);
this.rightTopPanel.Controls.Add(this.remoteDeleteButton);
this.rightTopPanel.Controls.Add(this.remoteRootButton);
this.rightTopPanel.Controls.Add(this.remoteNewFolderButton);
this.rightTopPanel.Controls.Add(this.remoteRefreshButton);
this.rightTopPanel.Controls.Add(this.remoteUpButton);
this.rightTopPanel.Controls.Add(this.remoteLabel);
resources.ApplyResources(this.rightTopPanel, "rightTopPanel");
this.rightTopPanel.Name = "rightTopPanel";
//
// remoteLabel
//
resources.ApplyResources(this.remoteLabel, "remoteLabel");
this.remoteLabel.Name = "remoteLabel";
//
// leftPanel
//
this.leftPanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.leftPanel.Controls.Add(this.consoleMessage);
this.leftPanel.Controls.Add(this.leftListView);
this.leftPanel.Controls.Add(this.leftTopPanel);
resources.ApplyResources(this.leftPanel, "leftPanel");
this.leftPanel.Name = "leftPanel";
//
// leftListView
//
this.leftListView.AllowDrop = true;
this.leftListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1,
this.columnHeader2});
this.leftListView.ContextMenuStrip = this.localContextMenuStrip;
resources.ApplyResources(this.leftListView, "leftListView");
this.leftListView.FullRowSelect = true;
this.leftListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.leftListView.HideSelection = false;
this.leftListView.Name = "leftListView";
this.leftListView.SmallImageList = this.fileIconImageList;
this.leftListView.UseCompatibleStateImageBehavior = false;
this.leftListView.View = System.Windows.Forms.View.Details;
this.leftListView.ColumnWidthChanged += new System.Windows.Forms.ColumnWidthChangedEventHandler(this.leftListView_ColumnWidthChanged);
this.leftListView.SelectedIndexChanged += new System.EventHandler(this.leftListView_SelectedIndexChanged);
this.leftListView.DragDrop += new System.Windows.Forms.DragEventHandler(this.leftListView_DragDrop);
this.leftListView.DragEnter += new System.Windows.Forms.DragEventHandler(this.leftListView_DragEnter);
this.leftListView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.leftListView_MouseDoubleClick);
this.leftListView.MouseMove += new System.Windows.Forms.MouseEventHandler(this.leftListView_MouseMove);
this.leftListView.Resize += new System.EventHandler(this.leftListView_Resize);
//
// columnHeader1
//
resources.ApplyResources(this.columnHeader1, "columnHeader1");
//
// columnHeader2
//
resources.ApplyResources(this.columnHeader2, "columnHeader2");
//
// localContextMenuStrip
//
this.localContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.renameToolStripMenuItem1,
this.deleteToolStripMenuItem1,
this.toolStripMenuItem2,
this.refreshToolStripMenuItem1});
this.localContextMenuStrip.Name = "localContextMenuStrip";
resources.ApplyResources(this.localContextMenuStrip, "localContextMenuStrip");
this.localContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.localContextMenuStrip_Opening);
//
// renameToolStripMenuItem1
//
this.renameToolStripMenuItem1.Name = "renameToolStripMenuItem1";
resources.ApplyResources(this.renameToolStripMenuItem1, "renameToolStripMenuItem1");
this.renameToolStripMenuItem1.Click += new System.EventHandler(this.renameToolStripMenuItem1_Click);
//
// deleteToolStripMenuItem1
//
this.deleteToolStripMenuItem1.Name = "deleteToolStripMenuItem1";
resources.ApplyResources(this.deleteToolStripMenuItem1, "deleteToolStripMenuItem1");
this.deleteToolStripMenuItem1.Click += new System.EventHandler(this.localDeleteButton_Click);
//
// toolStripMenuItem2
//
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
resources.ApplyResources(this.toolStripMenuItem2, "toolStripMenuItem2");
//
// refreshToolStripMenuItem1
//
this.refreshToolStripMenuItem1.Name = "refreshToolStripMenuItem1";
resources.ApplyResources(this.refreshToolStripMenuItem1, "refreshToolStripMenuItem1");
this.refreshToolStripMenuItem1.Click += new System.EventHandler(this.leftRefreshButton_Click);
//
// leftTopPanel
//
this.leftTopPanel.Controls.Add(this.localDeleteButton);
this.leftTopPanel.Controls.Add(this.localNewFolderButton);
this.leftTopPanel.Controls.Add(this.localRootButton);
this.leftTopPanel.Controls.Add(this.localRefreshButton);
this.leftTopPanel.Controls.Add(this.localUpButton);
this.leftTopPanel.Controls.Add(this.localLabel);
resources.ApplyResources(this.leftTopPanel, "leftTopPanel");
this.leftTopPanel.Name = "leftTopPanel";
//
// localLabel
//
resources.ApplyResources(this.localLabel, "localLabel");
this.localLabel.Name = "localLabel";
//
// FileViewer
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.Control;
this.Controls.Add(this.mainTableLayoutPanel);
this.Controls.Add(this.topPanel);
this.Controls.Add(this.statusStrip);
this.Name = "FileViewer";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Main_FormClosing);
this.Load += new System.EventHandler(this.MainForm_Load);
this.topPanel.ResumeLayout(false);
this.statusStrip.ResumeLayout(false);
this.statusStrip.PerformLayout();
this.mainTableLayoutPanel.ResumeLayout(false);
this.panel1.ResumeLayout(false);
this.rightPanel.ResumeLayout(false);
this.remoteContextMenuStrip.ResumeLayout(false);
this.rightTopPanel.ResumeLayout(false);
this.rightTopPanel.PerformLayout();
this.leftPanel.ResumeLayout(false);
this.leftPanel.PerformLayout();
this.localContextMenuStrip.ResumeLayout(false);
this.leftTopPanel.ResumeLayout(false);
this.leftTopPanel.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private Timer updateTimer;
private Timer consoleTimer;
private ToolTip mainToolTip;
private Panel topPanel;
private Button statsButton;
private Button connectButton;
private StatusStrip statusStrip;
private ToolStripStatusLabel mainToolStripStatusLabel;
private Label consoleMessage;
private TableLayoutPanel mainTableLayoutPanel;
private Panel panel1;
private Panel rightPanel;
private ListView rightListView;
private Panel leftPanel;
private ListView leftListView;
private Panel rightTopPanel;
private Label remoteLabel;
private Panel leftTopPanel;
private Label localLabel;
private ColumnHeader columnHeader3;
private ColumnHeader columnHeader4;
private ImageList fileIconImageList;
private ColumnHeader columnHeader1;
private ColumnHeader columnHeader2;
private Button remoteUpButton;
private Button localUpButton;
private Button localRefreshButton;
private Button remoteRefreshButton;
private Button remoteNewFolderButton;
private Button remoteRootButton;
private Button localRootButton;
private Button remoteDeleteButton;
private ContextMenuStrip remoteContextMenuStrip;
private ToolStripMenuItem renameToolStripMenuItem;
private ToolStripSeparator toolStripMenuItem1;
private ToolStripMenuItem refreshToolStripMenuItem;
private Button uploadButton;
private Button downloadButton;
private Button localDeleteButton;
private Button localNewFolderButton;
private ToolStripMenuItem deleteToolStripMenuItem;
private ContextMenuStrip localContextMenuStrip;
private ToolStripMenuItem renameToolStripMenuItem1;
private ToolStripMenuItem deleteToolStripMenuItem1;
private ToolStripSeparator toolStripMenuItem2;
private ToolStripMenuItem refreshToolStripMenuItem1;
private ToolStripMenuItem compressToolStripMenuItem;
private Button remoteZipButton;
}
}

2094
src/FileViewer.cs Normal file

File diff suppressed because it is too large Load Diff

1704
src/FileViewer.resx Normal file

File diff suppressed because it is too large Load Diff

101
src/FilenamePromptForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,101 @@
namespace MeshCentralRouter
{
partial class FilenamePromptForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FilenamePromptForm));
this.mainGroupBox = new System.Windows.Forms.GroupBox();
this.label1 = new System.Windows.Forms.Label();
this.mainTextBox = new System.Windows.Forms.TextBox();
this.cancelButton = new System.Windows.Forms.Button();
this.okButton = new System.Windows.Forms.Button();
this.mainGroupBox.SuspendLayout();
this.SuspendLayout();
//
// mainGroupBox
//
resources.ApplyResources(this.mainGroupBox, "mainGroupBox");
this.mainGroupBox.Controls.Add(this.label1);
this.mainGroupBox.Controls.Add(this.mainTextBox);
this.mainGroupBox.Name = "mainGroupBox";
this.mainGroupBox.TabStop = false;
//
// label1
//
resources.ApplyResources(this.label1, "label1");
this.label1.Name = "label1";
//
// mainTextBox
//
resources.ApplyResources(this.mainTextBox, "mainTextBox");
this.mainTextBox.Name = "mainTextBox";
this.mainTextBox.TextChanged += new System.EventHandler(this.mainTextBox_TextChanged);
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// FilenamePromptForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.Controls.Add(this.mainGroupBox);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FilenamePromptForm";
this.mainGroupBox.ResumeLayout(false);
this.mainGroupBox.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox mainGroupBox;
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox mainTextBox;
}
}

54
src/FilenamePromptForm.cs Normal file
View File

@@ -0,0 +1,54 @@
/*
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.Windows.Forms;
namespace MeshCentralRouter
{
public partial class FilenamePromptForm : Form
{
public string filename
{
get { return mainTextBox.Text; }
set { mainTextBox.Text = value; }
}
public FilenamePromptForm(string operation, string filename)
{
InitializeComponent();
Translate.TranslateControl(this);
mainGroupBox.Text = operation;
mainTextBox.Text = filename;
okButton.Enabled = (filename.Length > 0);
}
private void mainTextBox_TextChanged(object sender, EventArgs e)
{
okButton.Enabled = (mainTextBox.Text.Length > 0);
}
private void okButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}

1970
src/FilenamePromptForm.resx Normal file

File diff suppressed because it is too large Load Diff

102
src/InstallForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,102 @@
namespace MeshCentralRouter
{
partial class InstallForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InstallForm));
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.cancelButton = new System.Windows.Forms.Button();
this.okButton = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.label1 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Image = global::MeshCentralRouter.Properties.Resources.xinstall;
resources.ApplyResources(this.pictureBox1, "pictureBox1");
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.TabStop = false;
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// groupBox1
//
resources.ApplyResources(this.groupBox1, "groupBox1");
this.groupBox1.Controls.Add(this.label1);
this.groupBox1.Controls.Add(this.pictureBox1);
this.groupBox1.Name = "groupBox1";
this.groupBox1.TabStop = false;
//
// label1
//
resources.ApplyResources(this.label1, "label1");
this.label1.Name = "label1";
//
// InstallForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Name = "InstallForm";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label label1;
}
}

52
src/InstallForm.cs Normal file
View File

@@ -0,0 +1,52 @@
/*
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.IO;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
namespace MeshCentralRouter
{
public partial class InstallForm : Form
{
public InstallForm()
{
InitializeComponent();
Translate.TranslateControl(this);
// Load customizations
FileInfo selfExe = new FileInfo(Assembly.GetExecutingAssembly().Location);
try { pictureBox1.Image = (Bitmap)Image.FromFile(Path.Combine(selfExe.Directory.FullName, @"customization\install.png")); } catch (Exception) { }
try {
string[] lines = File.ReadAllLines(Path.Combine(selfExe.Directory.FullName, @"customization\customize.txt"));
if (lines[2] != "") { groupBox1.Text = lines[2]; }
if (lines[3] != "") { label1.Text = lines[3]; }
} catch (Exception) { }
}
private void okButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}

1967
src/InstallForm.resx Normal file

File diff suppressed because it is too large Load Diff

56
src/KVMControl.Designer.cs generated Normal file
View File

@@ -0,0 +1,56 @@
namespace MeshCentralRouter
{
partial class KVMControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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.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);
}
#endregion
//private System.Windows.Forms.Integration.ElementHost mainElementHost;
}
}

991
src/KVMControl.cs Normal file
View File

@@ -0,0 +1,991 @@
/*
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.IO;
using System.Net;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace MeshCentralRouter
{
public partial class KVMControl : UserControl
{
private bool remotepause = true;
public Bitmap desktop = null;
private Graphics desktopGraphics = null;
public uint screenWidth = 0;
public uint screenHeight = 0;
private Pen RedPen = new Pen(System.Drawing.Color.Red);
private Font DebugFont = new Font(FontFamily.GenericSansSerif, 14);
private int compressionlevel = 60; // 60% compression
private int scalinglevel = 1024; // 100% scale
private int frameRate = 100; // Medium frame rate
private bool swamMouseButtons = false;
private bool remoteKeyboardMap = false;
private bool autoSendClipboard = false;
public bool AutoReconnect = false;
private double scalefactor = 1;
public List<ushort> displays = new List<ushort>();
public ushort currentDisp = 0;
public bool MouseButtonLeft = false;
public bool MouseButtonMiddle = false;
public bool MouseButtonRight = false;
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;
//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,
Mouse = 2,
Picture = 3,
Copy = 4,
Compression = 5,
Refresh = 6,
Screen = 7,
Pause = 8,
TerminalText = 9,
CtrlAltDel = 10,
GetDisplays = 11,
SetDisplay = 12,
FrameRateTimer = 13,
InitTouch = 14,
Touch = 15,
Message = 16,
Jumbo = 27,
Disconnect = 59,
Alert = 65,
DisplayInfo = 82,
KeyUnicode = 85,
MouseCursor = 88
}
private enum KvmMouseButtonCommands
{
MOUSEEVENTF_LEFTDOWN = 0x0002,
MOUSEEVENTF_RIGHTDOWN = 0x0008,
MOUSEEVENTF_MIDDLEDOWN = 0x0020,
MOUSEEVENTF_LEFTUP = 0x0004,
MOUSEEVENTF_RIGHTUP = 0x0010,
MOUSEEVENTF_MIDDLEUP = 0x0040
}
[Category("Action")]
[Description("Fires when the remote desktop size changes.")]
public event EventHandler DesktopSizeChanged;
[Category("Action")]
[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,
Connecting,
Connected
}
public int CompressionLevel { get { return compressionlevel; } set { compressionlevel = value; SendCompressionLevel(); } }
public int ScalingLevel { get { return scalinglevel; } set { scalinglevel = value; SendCompressionLevel(); } }
public int FrameRate { get { return frameRate; } set { frameRate = value; SendCompressionLevel(); } }
public bool SwamMouseButtons { get { return swamMouseButtons; } set { swamMouseButtons = value; } }
public bool RemoteKeyboardMap { get { return remoteKeyboardMap; } set { remoteKeyboardMap = value; } }
public bool AutoSendClipboard { get { return autoSendClipboard; } set { autoSendClipboard = value; } }
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 { 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;
public int byterecv = 0;
public int tilecount = 0;
public int tilecopy = 0;
public bool debugmode = false;
public KVMControl()
{
InitializeComponent();
this.SetStyle(ControlStyles.Selectable, false);
this.SetStyle(ControlStyles.UserMouse, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.MouseWheel += new System.Windows.Forms.MouseEventHandler(KVMControl_MouseWheel);
if (Settings.GetRegValue("Exp_KeyboardHook", false))
{
ControlHook = new KVMControlHook();
KeyboardCallback = SendKey;
isHookWanted = true;
}
else
{
isHookWanted = false;
}
isHookPriority = Settings.GetRegValue("Exp_KeyboardHookPriority", false);
}
public void AttachKeyboard()
{
//Console.WriteLine(isHookWanted);
if (!keyboardIsAttached && isHookWanted)
{
ControlHook.AttachKeyboardHook(SendKey);
keyboardIsAttached = true;
}
}
public void DetacheKeyboard()
{
if (keyboardIsAttached)
{
ControlHook.DetachKeyboardHook();
keyboardIsAttached = false;
}
}
public int ProcessData(byte[] buffer, int off, int len)
{
//Console.Write("ProcessData " + off + ", " + len + "\r\n");
int jumboHeaderSize = 0;
if (len == 0) return 0;
if (len >= 4)
{
// Decode the command header
KvmCommands btype = (KvmCommands)((buffer[off] << 8) + buffer[off + 1]);
int blen = (buffer[off + 2] << 8) + buffer[off + 3];
if (len < blen) return 0;
// Handle JUMBO command
if ((btype == KvmCommands.Jumbo) && (blen == 8))
{
jumboHeaderSize = 8;
blen = (int)IPAddress.NetworkToHostOrder((int)BitConverter.ToUInt32(buffer, off + 4));
off += 8;
btype = (KvmCommands)((buffer[off] << 8) + buffer[off + 1]);
}
// Process the command
switch (btype)
{
case KvmCommands.Screen:
{
if (blen != 8) return blen;
uint w = (ushort)((buffer[off + 4] << 8) + buffer[off + 5]);
uint h = (ushort)((buffer[off + 6] << 8) + buffer[off + 7]);
if (screenWidth == w && screenHeight == h) break;
screenWidth = w;
screenHeight = h;
desktop = new Bitmap((int)screenWidth, (int)screenHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
desktopGraphics = Graphics.FromImage(desktop);
SendCompressionLevel();
Invoke(new SetSizeHandler(SetSize));
SendPause(false);
//SendMouse(2, KvmMouseButtonCommands.MOUSEEVENTF_LEFTUP);
//SendMouse(2, KvmMouseButtonCommands.MOUSEEVENTF_MIDDLEUP);
//SendMouse(2, KvmMouseButtonCommands.MOUSEEVENTF_RIGHTUP);
return blen + jumboHeaderSize;
}
case KvmCommands.Picture:
{
Image newtile;
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)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
if (desktop != null)
{
lock (desktop)
{
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));
}
}
// 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)
{
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;
}
case KvmCommands.Copy:
{
ushort sourcex = (ushort)((buffer[off + 4] << 8) + buffer[off + 5]);
ushort sourcey = (ushort)((buffer[off + 6] << 8) + buffer[off + 7]);
ushort targetx = (ushort)((buffer[off + 8] << 8) + buffer[off + 9]);
ushort targety = (ushort)((buffer[off + 10] << 8) + buffer[off + 11]);
ushort tilew = (ushort)((buffer[off + 12] << 8) + buffer[off + 13]);
ushort tileh = (ushort)((buffer[off + 14] << 8) + buffer[off + 15]);
Rectangle r1 = new Rectangle((int)sourcex, (int)sourcey, (int)tilew, (int)tileh);
Rectangle r2 = new Rectangle((int)targetx, (int)targety, (int)tilew, (int)tileh);
Rectangle r3 = new Rectangle((int)((double)targetx / (double)scalefactor) - 2, (int)((double)targety / (double)scalefactor) - 2, (int)((double)tilew / (double)scalefactor) + 4, (int)((double)tileh / (double)scalefactor) + 4);
// WinForm mode
if (desktop != null)
{
lock (desktop)
{
Bitmap bmp = new Bitmap(tilew, tileh);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(desktop, 0, 0, r1, GraphicsUnit.Pixel);
g.Dispose();
desktopGraphics.Flush();
desktopGraphics.DrawImage(bmp, r2, 0, 0, tilew, tileh, GraphicsUnit.Pixel);
if (debugmode) { desktopGraphics.DrawString("COPY", DebugFont, RedPen.Brush, new Point((int)targetx, (int)targety + 20)); }
}
tilecopy++;
}
return blen + jumboHeaderSize;
}
case KvmCommands.GetDisplays:
{
int i = 0;
ushort length = (ushort)((buffer[off + 4] << 8) + buffer[off + 5]);
displays.Clear();
if (length > 0) { for (i = 0; i < length; i++) { displays.Add((ushort)((buffer[off + 6 + i * 2] << 8) + buffer[off + 7 + i * 2])); } }
currentDisp = (ushort)((buffer[off + 6 + i * 2] << 8) + buffer[off + 7 + i * 2]);
if (DisplaysReceived != null) DisplaysReceived(this, null);
break;
}
case KvmCommands.SetDisplay:
{
currentDisp = (ushort)((buffer[off + 4] << 8) + buffer[off + 5]);
break;
}
case KvmCommands.MouseCursor:
{
if (blen != 5) return blen;
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!");
//Disconnect();
return 0;
}
}
return blen + jumboHeaderSize;
}
return 0;
}
private delegate void ChangeMouseCursorHandler(int cursorId);
private void ChangeMouseCursor(int cursorId)
{
if (this.InvokeRequired) { this.Invoke(new ChangeMouseCursorHandler(ChangeMouseCursor), cursorId); return; }
if (cursorId == 0) { this.Cursor = System.Windows.Forms.Cursors.Default; return; } // default
if (cursorId == 1) { this.Cursor = System.Windows.Forms.Cursors.AppStarting; return; } // progress
if (cursorId == 2) { this.Cursor = System.Windows.Forms.Cursors.Cross; return; } // crosshair
if (cursorId == 3) { this.Cursor = System.Windows.Forms.Cursors.Default; return; } // pointer
if (cursorId == 4) { this.Cursor = System.Windows.Forms.Cursors.Help; return; } // help
if (cursorId == 5) { this.Cursor = System.Windows.Forms.Cursors.IBeam; return; } // text
if (cursorId == 6) { this.Cursor = System.Windows.Forms.Cursors.No; return; } // no-drop
if (cursorId == 7) { this.Cursor = System.Windows.Forms.Cursors.Arrow; return; } // move
if (cursorId == 8) { this.Cursor = System.Windows.Forms.Cursors.SizeNESW; return; } // nesw-resize
if (cursorId == 9) { this.Cursor = System.Windows.Forms.Cursors.SizeNS; return; } // ns-resize
if (cursorId == 10) { this.Cursor = System.Windows.Forms.Cursors.SizeNWSE; return; } // nwse-resize
if (cursorId == 11) { this.Cursor = System.Windows.Forms.Cursors.SizeWE; return; } // w-resize
if (cursorId == 12) { this.Cursor = System.Windows.Forms.Cursors.Arrow; return; } // alias
if (cursorId == 13) { this.Cursor = System.Windows.Forms.Cursors.WaitCursor; return; } // wait
if (cursorId == 14) { this.Cursor = System.Windows.Forms.Cursors.Default; return; } // none
if (cursorId == 15) { this.Cursor = System.Windows.Forms.Cursors.No; return; } // not-allowed
if (cursorId == 16) { this.Cursor = System.Windows.Forms.Cursors.VSplit; return; } // col-resize
if (cursorId == 17) { this.Cursor = System.Windows.Forms.Cursors.HSplit; return; } // row-resize
if (cursorId == 18) { this.Cursor = System.Windows.Forms.Cursors.Default; return; } // copy
if (cursorId == 19) { this.Cursor = System.Windows.Forms.Cursors.SizeAll; return; } // zoom-in
if (cursorId == 20) { this.Cursor = System.Windows.Forms.Cursors.SizeAll; return; } // zoom-out
}
public void Repaint(Region region)
{
Invalidate(region);
}
public void Repaint(Rectangle rect)
{
Invalidate(rect);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Do not paint background.
}
private delegate void SetSizeHandler();
private void SetSize()
{
if (DesktopSizeChanged != null) { DesktopSizeChanged(this, null); }
}
private void KVMControl_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
if (desktop == null)
{
g.FillRectangle(new SolidBrush(Color.Black), e.ClipRectangle);
}
else
{
lock (desktop)
{
if (displayCrop == Rectangle.Empty) // No cropping
{
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
{
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);
}
}
}
}
}
public void SendKey(byte key, byte action)
{
//if (state != ConnectState.Connected) return;
BinaryWriter bw = GetBinaryWriter();
bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.Key));
bw.Write(IPAddress.HostToNetworkOrder((short)6));
bw.Write((byte)action);
bw.Write((byte)key);
Send(bw);
}
public void SendUnicodeKey(ushort key, byte action)
{
//if (state != ConnectState.Connected) return;
BinaryWriter bw = GetBinaryWriter();
bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.KeyUnicode));
bw.Write(IPAddress.HostToNetworkOrder((short)7));
bw.Write((byte)action);
bw.Write((byte)(key >> 8));
bw.Write((byte)(key & 0xFF));
Send(bw);
}
private void SendPress(KeyPressEventArgs e, byte action)
{
//if (state != ConnectState.Connected) return;
if (remoteKeyboardMap == true) return;
if (killNextKeyPress > 0)
{
long t = DateTime.Now.Ticks;
if ((t - killNextKeyPress) < 10) { killNextKeyPress = 0; return; }
}
ushort c = (ushort)e.KeyChar;
if (c < 32)
{
SendKey((byte)c, 0);
}
else
{
SendUnicodeKey(c, 0);
}
}
private void SendKey(KeyEventArgs e, byte action)
{
//if (state != ConnectState.Connected) return;
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))|| ((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;
}
private short LastX = 0;
private short LastY = 0;
private void SendMouse(MouseEventArgs e, byte action)
{
//if (state != ConnectState.Connected) return;
byte buttons = 0;
if (action == 1)
{
switch (e.Button)
{
case MouseButtons.Left:
if (swamMouseButtons)
{
buttons |= (byte)KvmMouseButtonCommands.MOUSEEVENTF_RIGHTDOWN;
}
else
{
buttons |= (byte)KvmMouseButtonCommands.MOUSEEVENTF_LEFTDOWN;
}
break;
case MouseButtons.Right:
if (swamMouseButtons)
{
buttons |= (byte)KvmMouseButtonCommands.MOUSEEVENTF_LEFTDOWN;
}
else
{
buttons |= (byte)KvmMouseButtonCommands.MOUSEEVENTF_RIGHTDOWN;
}
break;
case MouseButtons.Middle:
buttons |= (byte)KvmMouseButtonCommands.MOUSEEVENTF_MIDDLEDOWN;
break;
}
}
else if (action == 2)
{
switch (e.Button)
{
case MouseButtons.Left:
if (swamMouseButtons) { buttons |= (byte)KvmMouseButtonCommands.MOUSEEVENTF_RIGHTUP; } else { buttons |= (byte)KvmMouseButtonCommands.MOUSEEVENTF_LEFTUP; }
break;
case MouseButtons.Right:
if (swamMouseButtons) { buttons |= (byte)KvmMouseButtonCommands.MOUSEEVENTF_LEFTUP; } else { buttons |= (byte)KvmMouseButtonCommands.MOUSEEVENTF_RIGHTUP; }
break;
case MouseButtons.Middle:
buttons |= (byte)KvmMouseButtonCommands.MOUSEEVENTF_MIDDLEUP;
break;
}
}
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));
bw.Write(IPAddress.HostToNetworkOrder((short)(e.Delta == 0 ? 10 : 12)));
bw.Write((byte)action);
bw.Write((byte)buttons);
bw.Write(IPAddress.HostToNetworkOrder(LastX));
bw.Write(IPAddress.HostToNetworkOrder(LastY));
if (e.Delta != 0) { bw.Write(IPAddress.HostToNetworkOrder((short)e.Delta)); }
Send(bw);
}
public void SendMouseWheel(MouseEventArgs e, byte action)
{
//if (state != ConnectState.Connected) return;
BinaryWriter bw = GetBinaryWriter();
bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.Mouse));
bw.Write(IPAddress.HostToNetworkOrder((short)(e.Delta == 0 ? 10 : 12)));
bw.Write((short)0);
bw.Write(IPAddress.HostToNetworkOrder(LastX));
bw.Write(IPAddress.HostToNetworkOrder(LastY));
if (e.Delta != 0) { bw.Write(IPAddress.HostToNetworkOrder((short)e.Delta)); }
Send(bw);
}
private void SendMouse(byte action, KvmMouseButtonCommands buttons)
{
//if (state != ConnectState.Connected) return;
BinaryWriter bw = GetBinaryWriter();
bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.Mouse));
bw.Write(IPAddress.HostToNetworkOrder((short)10));
bw.Write((byte)action);
bw.Write((byte)buttons);
bw.Write((short)0);
bw.Write((short)0);
Send(bw);
}
public void SendCompressionLevel()
{
//if (state != ConnectState.Connected) return;
BinaryWriter bw = GetBinaryWriter();
bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.Compression));
bw.Write(IPAddress.HostToNetworkOrder((short)10));
bw.Write((byte)1); // Image Type (Reserved, 1 = JPEG)
bw.Write((byte)compressionlevel); // Compression Level
bw.Write(IPAddress.HostToNetworkOrder((short)scalinglevel)); // Scaling
bw.Write(IPAddress.HostToNetworkOrder((short)frameRate)); // Frame Rate
Send(bw);
}
public void SendRefresh()
{
//if (state != ConnectState.Connected) return;
BinaryWriter bw = GetBinaryWriter();
bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.Refresh));
bw.Write(IPAddress.HostToNetworkOrder((short)4));
Send(bw);
}
public void SendPause(bool paused)
{
//if (remotepauseactive == false || paused == remotepause) return;
//if (paused == remotepause) return;
remotepause = paused;
BinaryWriter bw = GetBinaryWriter();
bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.Pause));
bw.Write(IPAddress.HostToNetworkOrder((short)5));
bw.Write(paused ? (byte)1 : (byte)0);
Send(bw);
}
public void Send(byte[] buffer)
{
//if (state == ConnectState.Disconnected) return;
try
{
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) { }
}
public void Send(string str)
{
//if (state == ConnectState.Disconnected) return;
try
{
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) { }
}
public void Send(BinaryWriter bw)
{
//if (state == ConnectState.Disconnected) { RecycleBinaryWriter(bw); return; }
if ((parent != null) && (parent.wc != null))
{
try
{
parent.bytesOut += (int)((MemoryStream)bw.BaseStream).Length;
parent.bytesOutCompressed += parent.wc.SendBinary(((MemoryStream)bw.BaseStream).GetBuffer(), 0, (int)((MemoryStream)bw.BaseStream).Length);
bytesent += (int)((MemoryStream)bw.BaseStream).Length;
}
catch (Exception) { }
}
else if (parentEx != null)
{
parentEx.mainKvmControl.Send(bw);
}
RecycleBinaryWriter(bw);
}
private void KVMControl_MouseDown(object sender, MouseEventArgs e)
{
SendMouse(e, 1);
}
private void KVMControl_MouseUp(object sender, MouseEventArgs e)
{
SendMouse(e, 2);
}
long lastMouseMove = 0;
private void KVMControl_MouseMove(object sender, MouseEventArgs e)
{
long ct = DateTime.Now.Ticks;
if ((lastMouseMove + 30) < ct)
{
lastMouseMove = ct;
SendMouse(e, 0);
}
}
public void KVMControl_MouseWheel(object sender, MouseEventArgs e)
{
SendMouse(e, 0);
}
private void KVMControl_MouseEnter(object sender, EventArgs e)
{
this.Focus();
}
public void SendCtrlAltDel()
{
//if (state != ConnectState.Connected) return;
BinaryWriter bw = GetBinaryWriter();
bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.CtrlAltDel));
bw.Write(IPAddress.HostToNetworkOrder((short)4));
Send(bw);
}
public void GetDisplayNumbers()
{
//if (state != ConnectState.Connected) return;
BinaryWriter bw = GetBinaryWriter();
bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.GetDisplays));
bw.Write(IPAddress.HostToNetworkOrder((short)4));
Send(bw);
}
public void SendDisplay(int dispNo)
{
//if (state != ConnectState.Connected) return;
BinaryWriter bw = GetBinaryWriter();
bw.Write(IPAddress.HostToNetworkOrder((short)KvmCommands.SetDisplay));
bw.Write(IPAddress.HostToNetworkOrder((short)6));
bw.Write(IPAddress.HostToNetworkOrder((short)dispNo));
Send(bw);
}
public void SendCharmsKey()
{
SendKey(0x5B, 4); // Windows key down
SendKey(67, 1); // C down
SendKey(67, 2); // C up
SendKey(0x5B, 3); // Windows key up
}
// BinaryWriter Object Recycling System
private static Stack<BinaryWriter> BinaryWriteRecycleList = new Stack<BinaryWriter>();
public static BinaryWriter GetBinaryWriter() { lock (BinaryWriteRecycleList) { return (BinaryWriteRecycleList.Count == 0) ? new BinaryWriter(new MemoryStream(32000), Encoding.UTF8) : BinaryWriteRecycleList.Pop(); } }
public static void RecycleBinaryWriter(BinaryWriter obj) { lock (BinaryWriteRecycleList) { ((MemoryStream)obj.BaseStream).SetLength(0); BinaryWriteRecycleList.Push(obj); } }
// MemoryStream Object Recycling System
private static Stack<MemoryStream> MemoryStreamRecycleList = new Stack<MemoryStream>();
public static MemoryStream GetMemoryStream() { lock (MemoryStreamRecycleList) { return (MemoryStreamRecycleList.Count == 0) ? new MemoryStream(32000) : MemoryStreamRecycleList.Pop(); } }
public static void RecycleMemoryStream(MemoryStream obj) { lock (MemoryStreamRecycleList) { obj.SetLength(0); MemoryStreamRecycleList.Push(obj); } }
// StringBuilder Object Recycling System
private static Stack<StringBuilder> StringBuilderRecycleList = new Stack<StringBuilder>();
public static StringBuilder GetStringBuilder() { lock (StringBuilderRecycleList) { return (StringBuilderRecycleList.Count == 0) ? new StringBuilder(16000) : StringBuilderRecycleList.Pop(); } }
public static void RecycleStringBuilder(StringBuilder obj) { lock (StringBuilderRecycleList) { obj.Length = 0; StringBuilderRecycleList.Push(obj); } }
// byte[] Object Recycling System
private static Stack<byte[]> ByteArrayRecycleList = new Stack<byte[]>();
private static int ByteArrayRecycleListCount = 0;
public static byte[] GetByteArray() { lock (ByteArrayRecycleList) { if (ByteArrayRecycleList.Count == 0) ByteArrayRecycleListCount++; return (ByteArrayRecycleList.Count == 0) ? new byte[65535] : ByteArrayRecycleList.Pop(); } }
public static void RecycleByteArray(byte[] obj) { lock (ByteArrayRecycleList) { if (obj != null) ByteArrayRecycleList.Push(obj); } }
private void KVMControl_KeyDown(object sender, KeyEventArgs e)
{
if (!isHookPriority)
{
if ((e.KeyCode == Keys.LWin) || (e.KeyCode == Keys.RWin)) return; // Don't process the Windows key
SendKey(e, 0);
e.Handled = true;
}
}
private void KVMControl_KeyPress(object sender, KeyPressEventArgs e)
{
if (!isHookPriority)
{
SendPress(e, 0);
e.Handled = true;
}
}
private void KVMControl_KeyUp(object sender, KeyEventArgs e)
{
if (!isHookPriority)
{
SendKey(e, 1);
e.Handled = true;
}
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
const int WM_SYSKEYDOWN = 0x104;
// Tab keys
if (msg.Msg == WM_KEYDOWN && msg.WParam.ToInt32() == 9)
{
SendKey((byte)msg.WParam.ToInt32(), 0);
return true;
}
// Handle arrow keys
if (((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN)) && msg.WParam.ToInt32() >= 37 && msg.WParam.ToInt32() <= 40)
{
SendKey((byte)msg.WParam.ToInt32(), 0);
return true;
}
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;
}
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;
ProcessModule objCurrentModule = Process.GetCurrentProcess().MainModule;
objKeyboardProcess = new LowLevelKeyboardProc(captureKey);
ptrHook = SetWindowsHookEx(13, objKeyboardProcess, GetModuleHandle(objCurrentModule.ModuleName), 0);
}
//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;
}
}
}

120
src/KVMControl.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

105
src/KVMControlHook.cs Normal file
View File

@@ -0,0 +1,105 @@
/*
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.Runtime.InteropServices;
using System.Windows.Forms;
namespace MeshCentralRouter
{
public class KVMControlHook
{
public delegate void KVMCallback(byte keyCodes, byte lParam);
private KVMCallback _callback;
private KVMKeyboardHook.LowLevelKeyboardProc _proc;
private static IntPtr _hook = IntPtr.Zero;
protected static KVMControl _control;
internal KVMControlHook()
{
_proc = HookCallback;
}
internal void AttachKeyboardHook(KVMCallback callback)
{
try
{
_hook = KVMKeyboardHook.SetHook(_proc);
_callback = callback;
}
catch
{
DetachKeyboardHook();
throw new System.InvalidOperationException("Could not set hook.");
}
}
internal void DetachKeyboardHook()
{
_callback = null;
if (_hook != IntPtr.Zero)
KVMKeyboardHook.UnhookWindowsHookEx(_hook);
}
public IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
Keys key = (Keys)Marshal.ReadInt32(lParam);
if ((key == Keys.LWin) || (key == Keys.RWin)) {
bool alt = (Control.ModifierKeys & Keys.Alt) != 0;
bool control = (Control.ModifierKeys & Keys.Control) != 0;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;
byte bkey = (byte)key;
byte keyStatus = 255;
switch ((int)wParam)
{
case WM_KEYDOWN:
keyStatus = 0;
break;
case WM_KEYUP:
keyStatus = 1;
break;
case WM_SYSKEYDOWN:
//keyStatus = 0; // 4
break;
case WM_SYSKEYUP:
//keyStatus = 1; // 5
break;
default:
return KVMKeyboardHook.CallNextHookEx(_hook, nCode, wParam, lParam);
}
try
{
if ((_callback != null) && (keyStatus != 255))
{
_callback(bkey, keyStatus);
return (IntPtr)1;
}
}
catch { }
}
}
return KVMKeyboardHook.CallNextHookEx(_hook, nCode, wParam, lParam);
}
}
}

57
src/KVMKeyboardHook.cs Normal file
View File

@@ -0,0 +1,57 @@
/*
credit to https://github.com/shanselman/babysmash
Copyright (c) 2015 Scott Hanselman
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.Diagnostics;
using System.Runtime.InteropServices;
namespace MeshCentralRouter
{
internal class KVMKeyboardHook
{
#region Delegates
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
#endregion
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
public static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
}

132
src/KVMResizeControl.Designer.cs generated Normal file
View File

@@ -0,0 +1,132 @@
namespace MeshCentralRouter
{
partial class KVMResizeControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.rightScrollPanel = new System.Windows.Forms.Panel();
this.vScrollBar = new System.Windows.Forms.VScrollBar();
this.cornerBlockPanel = new System.Windows.Forms.Panel();
this.hScrollBar = new System.Windows.Forms.HScrollBar();
this.clientPanel = new System.Windows.Forms.Panel();
this.kvmControl = new MeshCentralRouter.KVMControl();
this.rightScrollPanel.SuspendLayout();
this.clientPanel.SuspendLayout();
this.SuspendLayout();
//
// rightScrollPanel
//
this.rightScrollPanel.Controls.Add(this.vScrollBar);
this.rightScrollPanel.Controls.Add(this.cornerBlockPanel);
this.rightScrollPanel.Dock = System.Windows.Forms.DockStyle.Right;
this.rightScrollPanel.Location = new System.Drawing.Point(1159, 0);
this.rightScrollPanel.Name = "rightScrollPanel";
this.rightScrollPanel.Size = new System.Drawing.Size(17, 789);
this.rightScrollPanel.TabIndex = 12;
//
// vScrollBar
//
this.vScrollBar.Dock = System.Windows.Forms.DockStyle.Fill;
this.vScrollBar.LargeChange = 100;
this.vScrollBar.Location = new System.Drawing.Point(0, 0);
this.vScrollBar.Name = "vScrollBar";
this.vScrollBar.Size = new System.Drawing.Size(17, 772);
this.vScrollBar.TabIndex = 10;
this.vScrollBar.ValueChanged += new System.EventHandler(this.vScrollBar_ValueChanged);
//
// cornerBlockPanel
//
this.cornerBlockPanel.BackColor = System.Drawing.SystemColors.Control;
this.cornerBlockPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
this.cornerBlockPanel.Location = new System.Drawing.Point(0, 772);
this.cornerBlockPanel.Name = "cornerBlockPanel";
this.cornerBlockPanel.Size = new System.Drawing.Size(17, 17);
this.cornerBlockPanel.TabIndex = 11;
this.cornerBlockPanel.Visible = false;
//
// hScrollBar
//
this.hScrollBar.Dock = System.Windows.Forms.DockStyle.Bottom;
this.hScrollBar.LargeChange = 100;
this.hScrollBar.Location = new System.Drawing.Point(0, 772);
this.hScrollBar.Name = "hScrollBar";
this.hScrollBar.Size = new System.Drawing.Size(1159, 17);
this.hScrollBar.TabIndex = 13;
this.hScrollBar.ValueChanged += new System.EventHandler(this.hScrollBar_ValueChanged);
//
// clientPanel
//
this.clientPanel.Controls.Add(this.kvmControl);
this.clientPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.clientPanel.Location = new System.Drawing.Point(0, 0);
this.clientPanel.Name = "clientPanel";
this.clientPanel.Size = new System.Drawing.Size(1159, 772);
this.clientPanel.TabIndex = 15;
//
// 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);
//
// KVMResizeControl
//
this.BackColor = System.Drawing.Color.Gray;
this.Controls.Add(this.clientPanel);
this.Controls.Add(this.hScrollBar);
this.Controls.Add(this.rightScrollPanel);
this.Name = "KVMResizeControl";
this.Size = new System.Drawing.Size(1176, 789);
this.Resize += new System.EventHandler(this.ResizeKVMControl_Resize);
this.rightScrollPanel.ResumeLayout(false);
this.clientPanel.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel rightScrollPanel;
private System.Windows.Forms.VScrollBar vScrollBar;
private System.Windows.Forms.Panel cornerBlockPanel;
private System.Windows.Forms.HScrollBar hScrollBar;
private KVMControl kvmControl;
private System.Windows.Forms.Panel clientPanel;
}
}

140
src/KVMResizeControl.cs Normal file
View File

@@ -0,0 +1,140 @@
/*
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.Windows.Forms;
using System.ComponentModel;
namespace MeshCentralRouter
{
public partial class KVMResizeControl : UserControl
{
private bool zoomtofit = false;
public KVMControl KVM { get { return kvmControl; } }
public bool ZoomToFit { get { return zoomtofit; } set { zoomtofit = value; CenterKvmControl(false); } }
[Category("Action")]
[Description("Fires when the connection state changes.")]
public event EventHandler StateChanged;
[Category("Action")]
[Description("Fires when the display list is received.")]
public event EventHandler DisplaysReceived;
public KVMResizeControl()
{
InitializeComponent();
vScrollBar.LargeChange = 100;
vScrollBar.SmallChange = 10;
hScrollBar.LargeChange = 100;
hScrollBar.SmallChange = 10;
//KVM.StateChanged += new EventHandler(KVM_StateChanged);
KVM.DisplaysReceived += new EventHandler(KVM_DisplaysReceived);
CenterKvmControl(false);
}
/*
void KVM_StateChanged(object sender, EventArgs e)
{
if (InvokeRequired) { Invoke(new EventHandler(KVM_StateChanged), sender, e); return; }
CenterKvmControl(false);
kvmControl.Visible = false;
//kvmControl.Visible = (kvmControl.State == KVMControl.ConnectState.Connected);
if (StateChanged != null) StateChanged(this, e);
}
*/
void KVM_DisplaysReceived(object sender, EventArgs e)
{
if (InvokeRequired) { Invoke(new EventHandler(KVM_DisplaysReceived), sender, e); return; }
if (DisplaysReceived != null) DisplaysReceived(this, e);
}
public void CenterKvmControl(bool forceRefresh)
{
int w = clientPanel.Width;
int h = clientPanel.Height;
int l = 0;
int t = 0;
bool invalidate = true;
if (zoomtofit == false)
{
if (kvmControl.Width != kvmControl.DesktopWidth || kvmControl.Height != kvmControl.DesktopHeight || kvmControl.ScaleFactor != 1)
{
kvmControl.Size = new System.Drawing.Size(kvmControl.DesktopWidth, kvmControl.DesktopHeight);
kvmControl.ScaleFactor = 1;
invalidate = true;
}
hScrollBar.Visible = (w < kvmControl.DesktopWidth);
rightScrollPanel.Visible = vScrollBar.Visible = (h < kvmControl.DesktopHeight);
cornerBlockPanel.Visible = (hScrollBar.Visible & vScrollBar.Visible);
}
else
{
hScrollBar.Visible = false;
rightScrollPanel.Visible = false;
double sfx = (double)kvmControl.DesktopWidth / (double)Width;
double sfy = (double)kvmControl.DesktopHeight / (double)Height;
double sf = Math.Max(sfx, sfy);
sf = Math.Max(1, sf);
if ((kvmControl.ScaleFactor != sf) || (forceRefresh))
{
kvmControl.Size = new System.Drawing.Size((int)((double)kvmControl.DesktopWidth / sf), (int)((double)kvmControl.DesktopHeight / sf));
kvmControl.ScaleFactor = sf;
invalidate = true;
}
}
if (w < kvmControl.Width) { hScrollBar.Maximum = (kvmControl.Width - w) + 100; } else { l = (w - kvmControl.Width) / 2; }
if (h < kvmControl.Height) { vScrollBar.Maximum = (kvmControl.Height - h) + 100; } else { t = (h - kvmControl.Height) / 2; }
if (vScrollBar.Visible) { kvmControl.Top = 0 - vScrollBar.Value; } else { kvmControl.Top = t; }
if (hScrollBar.Visible) { kvmControl.Left = 0 - hScrollBar.Value; } else { kvmControl.Left = l; }
if (invalidate) kvmControl.Invalidate();
}
private void kvmControl_Resize(object sender, EventArgs e)
{
CenterKvmControl(false);
}
private void ResizeKVMControl_Resize(object sender, EventArgs e)
{
CenterKvmControl(false);
}
private void vScrollBar_ValueChanged(object sender, EventArgs e)
{
kvmControl.Top = -vScrollBar.Value;
}
private void hScrollBar_ValueChanged(object sender, EventArgs e)
{
kvmControl.Left = -hScrollBar.Value;
}
private void kvmControl_DesktopSizeChanged(object sender, EventArgs e)
{
CenterKvmControl(true);
}
public void MouseWheelEx(object sender, MouseEventArgs e)
{
//if (KVMControl.WPF) kvmControl.SendMouseWheel(e, 0);
}
}
}

120
src/KVMResizeControl.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

195
src/KVMSettingsForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,195 @@
namespace MeshCentralRouter
{
partial class KVMSettingsForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(KVMSettingsForm));
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();
this.label2 = new System.Windows.Forms.Label();
this.scalingComboBox = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.qualityComboBox = new System.Windows.Forms.ComboBox();
this.label3 = new System.Windows.Forms.Label();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.label4 = new System.Windows.Forms.Label();
this.autoReconnectCheckBox = new System.Windows.Forms.CheckBox();
this.groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// 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);
this.groupBox1.Controls.Add(this.frameRateComboBox);
this.groupBox1.Controls.Add(this.label2);
this.groupBox1.Controls.Add(this.scalingComboBox);
this.groupBox1.Controls.Add(this.label1);
this.groupBox1.Controls.Add(this.qualityComboBox);
this.groupBox1.Controls.Add(this.label3);
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");
this.remoteKeyboardMapCheckBox.Name = "remoteKeyboardMapCheckBox";
this.remoteKeyboardMapCheckBox.UseVisualStyleBackColor = true;
//
// swapMouseButtonsCheckBox
//
resources.ApplyResources(this.swapMouseButtonsCheckBox, "swapMouseButtonsCheckBox");
this.swapMouseButtonsCheckBox.Name = "swapMouseButtonsCheckBox";
this.swapMouseButtonsCheckBox.UseVisualStyleBackColor = true;
//
// frameRateComboBox
//
resources.ApplyResources(this.frameRateComboBox, "frameRateComboBox");
this.frameRateComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.frameRateComboBox.FormattingEnabled = true;
this.frameRateComboBox.Name = "frameRateComboBox";
//
// label2
//
resources.ApplyResources(this.label2, "label2");
this.label2.Name = "label2";
//
// scalingComboBox
//
resources.ApplyResources(this.scalingComboBox, "scalingComboBox");
this.scalingComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.scalingComboBox.FormattingEnabled = true;
this.scalingComboBox.Name = "scalingComboBox";
//
// label1
//
resources.ApplyResources(this.label1, "label1");
this.label1.Name = "label1";
//
// qualityComboBox
//
resources.ApplyResources(this.qualityComboBox, "qualityComboBox");
this.qualityComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.qualityComboBox.FormattingEnabled = true;
this.qualityComboBox.Name = "qualityComboBox";
//
// label3
//
resources.ApplyResources(this.label3, "label3");
this.label3.Name = "label3";
//
// pictureBox1
//
resources.ApplyResources(this.pictureBox1, "pictureBox1");
this.pictureBox1.Image = global::MeshCentralRouter.Properties.Resources.Computer50;
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.TabStop = false;
//
// label4
//
resources.ApplyResources(this.label4, "label4");
this.label4.Name = "label4";
//
// autoReconnectCheckBox
//
resources.ApplyResources(this.autoReconnectCheckBox, "autoReconnectCheckBox");
this.autoReconnectCheckBox.Name = "autoReconnectCheckBox";
this.autoReconnectCheckBox.UseVisualStyleBackColor = true;
//
// KVMSettingsForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.label4);
this.Controls.Add(this.pictureBox1);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "KVMSettingsForm";
this.Load += new System.EventHandler(this.SettingsForm_Load);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.ComboBox frameRateComboBox;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.ComboBox scalingComboBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox qualityComboBox;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.CheckBox swapMouseButtonsCheckBox;
private System.Windows.Forms.CheckBox remoteKeyboardMapCheckBox;
private System.Windows.Forms.CheckBox autoSendClipboardCheckBox;
private System.Windows.Forms.CheckBox autoReconnectCheckBox;
}
}

156
src/KVMSettingsForm.cs Normal file
View File

@@ -0,0 +1,156 @@
/*
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.Windows.Forms;
namespace MeshCentralRouter
{
public partial class KVMSettingsForm : Form
{
public KVMSettingsForm(int features2)
{
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%"));
qualityComboBox.Items.Add(new DropListItem(60, "60%"));
qualityComboBox.Items.Add(new DropListItem(50, "50%"));
qualityComboBox.Items.Add(new DropListItem(40, "40%"));
qualityComboBox.Items.Add(new DropListItem(30, "30%"));
qualityComboBox.Items.Add(new DropListItem(20, "20%"));
qualityComboBox.Items.Add(new DropListItem(10, "10%"));
qualityComboBox.Items.Add(new DropListItem(5, "5%"));
qualityComboBox.Items.Add(new DropListItem(1, "1%"));
scalingComboBox.Items.Add(new DropListItem(1024, "100%"));
scalingComboBox.Items.Add(new DropListItem(896, "87.5%"));
scalingComboBox.Items.Add(new DropListItem(768, "75%"));
scalingComboBox.Items.Add(new DropListItem(640, "62.5%"));
scalingComboBox.Items.Add(new DropListItem(512, "50%"));
scalingComboBox.Items.Add(new DropListItem(384, "37.5%"));
scalingComboBox.Items.Add(new DropListItem(256, "25%"));
scalingComboBox.Items.Add(new DropListItem(128, "12.5%"));
frameRateComboBox.Items.Add(new DropListItem(50, Translate.T(Properties.Resources.Fast)));
frameRateComboBox.Items.Add(new DropListItem(100, Translate.T(Properties.Resources.Medium)));
frameRateComboBox.Items.Add(new DropListItem(400, Translate.T(Properties.Resources.Slow)));
frameRateComboBox.Items.Add(new DropListItem(1000, Translate.T(Properties.Resources.VerySlow)));
qualityComboBox.SelectedIndex = 4;
scalingComboBox.SelectedIndex = 0;
frameRateComboBox.SelectedIndex = 1;
if ((features2 & 0x1000) != 0) {
this.Height -= (autoSendClipboardCheckBox.Top - remoteKeyboardMapCheckBox.Top);
autoSendClipboardCheckBox.Visible = false;
}
}
private class DropListItem
{
public int value;
public string str;
public DropListItem(int value, string str) { this.value = value; this.str = str; }
public override string ToString() { return str; }
}
private void SettingsForm_Load(object sender, EventArgs e)
{
}
public int Compression
{
get { return ((DropListItem)qualityComboBox.SelectedItem).value; }
set
{
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;
}
}
public int Scaling
{
get { return ((DropListItem)scalingComboBox.SelectedItem).value; }
set
{
if (value >= 1024) { scalingComboBox.SelectedIndex = 0; return; }
if (value >= 896) { scalingComboBox.SelectedIndex = 1; return; }
if (value >= 768) { scalingComboBox.SelectedIndex = 2; return; }
if (value >= 640) { scalingComboBox.SelectedIndex = 3; return; }
if (value >= 512) { scalingComboBox.SelectedIndex = 4; return; }
if (value >= 384) { scalingComboBox.SelectedIndex = 5; return; }
if (value >= 256) { scalingComboBox.SelectedIndex = 6; return; }
scalingComboBox.SelectedIndex = 7;
}
}
public int FrameRate
{
get { return ((DropListItem)frameRateComboBox.SelectedItem).value; }
set
{
if (value <= 50) { frameRateComboBox.SelectedIndex = 0; return; }
if (value <= 100) { frameRateComboBox.SelectedIndex = 1; return; }
if (value <= 400) { frameRateComboBox.SelectedIndex = 2; return; }
frameRateComboBox.SelectedIndex = 3;
}
}
public bool SwamMouseButtons
{
get { return swapMouseButtonsCheckBox.Checked; }
set { swapMouseButtonsCheckBox.Checked = value; }
}
public bool RemoteKeyboardMap
{
get { return remoteKeyboardMapCheckBox.Checked; }
set { remoteKeyboardMapCheckBox.Checked = value; }
}
public bool AutoSendClipboard
{
get { return autoSendClipboardCheckBox.Checked; }
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;
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = System.Windows.Forms.DialogResult.Cancel;
}
}
}

974
src/KVMSettingsForm.resx Normal file
View File

@@ -0,0 +1,974 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="cancelButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Bottom, Right</value>
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="cancelButton.Location" type="System.Drawing.Point, System.Drawing">
<value>312, 276</value>
</data>
<data name="cancelButton.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
</data>
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="cancelButton.TabIndex" type="System.Int32, mscorlib">
<value>7</value>
</data>
<data name="cancelButton.Text" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="&gt;&gt;cancelButton.Name" xml:space="preserve">
<value>cancelButton</value>
</data>
<data name="&gt;&gt;cancelButton.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;cancelButton.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;cancelButton.ZOrder" xml:space="preserve">
<value>4</value>
</data>
<data name="okButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Bottom, Right</value>
</data>
<data name="okButton.Location" type="System.Drawing.Point, System.Drawing">
<value>231, 276</value>
</data>
<data name="okButton.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
</data>
<data name="okButton.TabIndex" type="System.Int32, mscorlib">
<value>6</value>
</data>
<data name="okButton.Text" xml:space="preserve">
<value>OK</value>
</data>
<data name="&gt;&gt;okButton.Name" xml:space="preserve">
<value>okButton</value>
</data>
<data name="&gt;&gt;okButton.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;okButton.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;okButton.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<data name="groupBox1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Bottom, Left, Right</value>
</data>
<data name="autoReconnectCheckBox.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="autoReconnectCheckBox.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="autoReconnectCheckBox.Location" type="System.Drawing.Point, System.Drawing">
<value>128, 174</value>
</data>
<data name="autoReconnectCheckBox.Size" type="System.Drawing.Size, System.Drawing">
<value>144, 17</value>
</data>
<data name="autoReconnectCheckBox.TabIndex" type="System.Int32, mscorlib">
<value>10</value>
</data>
<data name="autoReconnectCheckBox.Text" xml:space="preserve">
<value>Automatically Reconnect</value>
</data>
<data name="&gt;&gt;autoReconnectCheckBox.Name" xml:space="preserve">
<value>autoReconnectCheckBox</value>
</data>
<data name="&gt;&gt;autoReconnectCheckBox.Type" xml:space="preserve">
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;autoReconnectCheckBox.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;autoReconnectCheckBox.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="autoSendClipboardCheckBox.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="autoSendClipboardCheckBox.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="autoSendClipboardCheckBox.Location" type="System.Drawing.Point, System.Drawing">
<value>128, 151</value>
</data>
<data name="autoSendClipboardCheckBox.Size" type="System.Drawing.Size, System.Drawing">
<value>163, 17</value>
</data>
<data name="autoSendClipboardCheckBox.TabIndex" type="System.Int32, mscorlib">
<value>9</value>
</data>
<data name="autoSendClipboardCheckBox.Text" xml:space="preserve">
<value>Automatically Send Clipboard</value>
</data>
<data name="&gt;&gt;autoSendClipboardCheckBox.Name" xml:space="preserve">
<value>autoSendClipboardCheckBox</value>
</data>
<data name="&gt;&gt;autoSendClipboardCheckBox.Type" xml:space="preserve">
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;autoSendClipboardCheckBox.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;autoSendClipboardCheckBox.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="remoteKeyboardMapCheckBox.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="remoteKeyboardMapCheckBox.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="remoteKeyboardMapCheckBox.Location" type="System.Drawing.Point, System.Drawing">
<value>128, 128</value>
</data>
<data name="remoteKeyboardMapCheckBox.Size" type="System.Drawing.Size, System.Drawing">
<value>157, 17</value>
</data>
<data name="remoteKeyboardMapCheckBox.TabIndex" type="System.Int32, mscorlib">
<value>5</value>
</data>
<data name="remoteKeyboardMapCheckBox.Text" xml:space="preserve">
<value>Use Remote Keyboard Map</value>
</data>
<data name="&gt;&gt;remoteKeyboardMapCheckBox.Name" xml:space="preserve">
<value>remoteKeyboardMapCheckBox</value>
</data>
<data name="&gt;&gt;remoteKeyboardMapCheckBox.Type" xml:space="preserve">
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;remoteKeyboardMapCheckBox.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;remoteKeyboardMapCheckBox.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="swapMouseButtonsCheckBox.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="swapMouseButtonsCheckBox.Location" type="System.Drawing.Point, System.Drawing">
<value>128, 105</value>
</data>
<data name="swapMouseButtonsCheckBox.Size" type="System.Drawing.Size, System.Drawing">
<value>127, 17</value>
</data>
<data name="swapMouseButtonsCheckBox.TabIndex" type="System.Int32, mscorlib">
<value>4</value>
</data>
<data name="swapMouseButtonsCheckBox.Text" xml:space="preserve">
<value>Swap Mouse Buttons</value>
</data>
<data name="&gt;&gt;swapMouseButtonsCheckBox.Name" xml:space="preserve">
<value>swapMouseButtonsCheckBox</value>
</data>
<data name="&gt;&gt;swapMouseButtonsCheckBox.Type" xml:space="preserve">
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;swapMouseButtonsCheckBox.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;swapMouseButtonsCheckBox.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<data name="frameRateComboBox.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data>
<data name="frameRateComboBox.Location" type="System.Drawing.Point, System.Drawing">
<value>128, 75</value>
</data>
<data name="frameRateComboBox.Size" type="System.Drawing.Size, System.Drawing">
<value>238, 21</value>
</data>
<data name="frameRateComboBox.TabIndex" type="System.Int32, mscorlib">
<value>3</value>
</data>
<data name="&gt;&gt;frameRateComboBox.Name" xml:space="preserve">
<value>frameRateComboBox</value>
</data>
<data name="&gt;&gt;frameRateComboBox.Type" xml:space="preserve">
<value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;frameRateComboBox.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;frameRateComboBox.ZOrder" xml:space="preserve">
<value>4</value>
</data>
<data name="label2.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="label2.Location" type="System.Drawing.Point, System.Drawing">
<value>9, 78</value>
</data>
<data name="label2.Size" type="System.Drawing.Size, System.Drawing">
<value>57, 13</value>
</data>
<data name="label2.TabIndex" type="System.Int32, mscorlib">
<value>8</value>
</data>
<data name="label2.Text" xml:space="preserve">
<value>Frame rate</value>
</data>
<data name="&gt;&gt;label2.Name" xml:space="preserve">
<value>label2</value>
</data>
<data name="&gt;&gt;label2.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;label2.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;label2.ZOrder" xml:space="preserve">
<value>5</value>
</data>
<data name="scalingComboBox.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data>
<data name="scalingComboBox.Location" type="System.Drawing.Point, System.Drawing">
<value>128, 48</value>
</data>
<data name="scalingComboBox.Size" type="System.Drawing.Size, System.Drawing">
<value>238, 21</value>
</data>
<data name="scalingComboBox.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="&gt;&gt;scalingComboBox.Name" xml:space="preserve">
<value>scalingComboBox</value>
</data>
<data name="&gt;&gt;scalingComboBox.Type" xml:space="preserve">
<value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;scalingComboBox.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;scalingComboBox.ZOrder" xml:space="preserve">
<value>6</value>
</data>
<data name="label1.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="label1.Location" type="System.Drawing.Point, System.Drawing">
<value>9, 51</value>
</data>
<data name="label1.Size" type="System.Drawing.Size, System.Drawing">
<value>42, 13</value>
</data>
<data name="label1.TabIndex" type="System.Int32, mscorlib">
<value>6</value>
</data>
<data name="label1.Text" xml:space="preserve">
<value>Scaling</value>
</data>
<data name="&gt;&gt;label1.Name" xml:space="preserve">
<value>label1</value>
</data>
<data name="&gt;&gt;label1.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;label1.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;label1.ZOrder" xml:space="preserve">
<value>7</value>
</data>
<data name="qualityComboBox.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data>
<data name="qualityComboBox.ItemHeight" type="System.Int32, mscorlib">
<value>13</value>
</data>
<data name="qualityComboBox.Location" type="System.Drawing.Point, System.Drawing">
<value>128, 21</value>
</data>
<data name="qualityComboBox.Size" type="System.Drawing.Size, System.Drawing">
<value>238, 21</value>
</data>
<data name="qualityComboBox.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="&gt;&gt;qualityComboBox.Name" xml:space="preserve">
<value>qualityComboBox</value>
</data>
<data name="&gt;&gt;qualityComboBox.Type" xml:space="preserve">
<value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;qualityComboBox.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;qualityComboBox.ZOrder" xml:space="preserve">
<value>8</value>
</data>
<data name="label3.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="label3.Location" type="System.Drawing.Point, System.Drawing">
<value>9, 24</value>
</data>
<data name="label3.Size" type="System.Drawing.Size, System.Drawing">
<value>39, 13</value>
</data>
<data name="label3.TabIndex" type="System.Int32, mscorlib">
<value>4</value>
</data>
<data name="label3.Text" xml:space="preserve">
<value>Quality</value>
</data>
<data name="&gt;&gt;label3.Name" xml:space="preserve">
<value>label3</value>
</data>
<data name="&gt;&gt;label3.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;label3.Parent" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;label3.ZOrder" xml:space="preserve">
<value>9</value>
</data>
<data name="groupBox1.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 68</value>
</data>
<data name="groupBox1.Size" type="System.Drawing.Size, System.Drawing">
<value>375, 202</value>
</data>
<data name="groupBox1.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="groupBox1.Text" xml:space="preserve">
<value>Settings</value>
</data>
<data name="&gt;&gt;groupBox1.Name" xml:space="preserve">
<value>groupBox1</value>
</data>
<data name="&gt;&gt;groupBox1.Type" xml:space="preserve">
<value>System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;groupBox1.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;groupBox1.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="pictureBox1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
</data>
<data name="pictureBox1.Location" type="System.Drawing.Point, System.Drawing">
<value>337, 12</value>
</data>
<data name="pictureBox1.Size" type="System.Drawing.Size, System.Drawing">
<value>50, 50</value>
</data>
<data name="pictureBox1.TabIndex" type="System.Int32, mscorlib">
<value>3</value>
</data>
<data name="&gt;&gt;pictureBox1.Name" xml:space="preserve">
<value>pictureBox1</value>
</data>
<data name="&gt;&gt;pictureBox1.Type" xml:space="preserve">
<value>System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;pictureBox1.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;pictureBox1.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="label4.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data>
<data name="label4.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 12</value>
</data>
<data name="label4.Size" type="System.Drawing.Size, System.Drawing">
<value>319, 50</value>
</data>
<data name="label4.TabIndex" type="System.Int32, mscorlib">
<value>4</value>
</data>
<data name="label4.Text" xml:space="preserve">
<value>Remote desktop quality, scaling and frame rate settings. These can be adjusted depending on the quality of the network connection.</value>
</data>
<data name="&gt;&gt;label4.Name" xml:space="preserve">
<value>label4</value>
</data>
<data name="&gt;&gt;label4.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;label4.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;label4.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>6, 13</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>399, 311</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
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
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=
</value>
</data>
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
<value>CenterParent</value>
</data>
<data name="$this.Text" xml:space="preserve">
<value>Remote Desktop Settings</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>KVMSettingsForm</value>
</data>
<data name="&gt;&gt;$this.Type" xml:space="preserve">
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

187
src/KVMStats.Designer.cs generated Normal file
View File

@@ -0,0 +1,187 @@
namespace MeshCentralRouter
{
partial class KVMStats
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(KVMStats));
this.okButton = new System.Windows.Forms.Button();
this.label12 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.label2 = new System.Windows.Forms.Label();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.kvmCompInBytesLabel = new System.Windows.Forms.Label();
this.kvmCompOutBytesLabel = new System.Windows.Forms.Label();
this.kvmOutBytesLabel = new System.Windows.Forms.Label();
this.kvmInBytesLabel = new System.Windows.Forms.Label();
this.outRatioLabel = new System.Windows.Forms.Label();
this.inRatioLabel = new System.Windows.Forms.Label();
this.label10 = new System.Windows.Forms.Label();
this.label11 = new System.Windows.Forms.Label();
this.refreshTimer = new System.Windows.Forms.Timer(this.components);
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// label12
//
resources.ApplyResources(this.label12, "label12");
this.label12.Name = "label12";
//
// groupBox1
//
resources.ApplyResources(this.groupBox1, "groupBox1");
this.groupBox1.Controls.Add(this.outRatioLabel);
this.groupBox1.Controls.Add(this.inRatioLabel);
this.groupBox1.Controls.Add(this.label10);
this.groupBox1.Controls.Add(this.label11);
this.groupBox1.Controls.Add(this.kvmCompOutBytesLabel);
this.groupBox1.Controls.Add(this.kvmCompInBytesLabel);
this.groupBox1.Controls.Add(this.label2);
this.groupBox1.Controls.Add(this.label12);
this.groupBox1.Name = "groupBox1";
this.groupBox1.TabStop = false;
//
// label2
//
resources.ApplyResources(this.label2, "label2");
this.label2.Name = "label2";
//
// groupBox2
//
resources.ApplyResources(this.groupBox2, "groupBox2");
this.groupBox2.Controls.Add(this.kvmOutBytesLabel);
this.groupBox2.Controls.Add(this.label3);
this.groupBox2.Controls.Add(this.kvmInBytesLabel);
this.groupBox2.Controls.Add(this.label4);
this.groupBox2.Name = "groupBox2";
this.groupBox2.TabStop = false;
//
// label3
//
resources.ApplyResources(this.label3, "label3");
this.label3.Name = "label3";
//
// label4
//
resources.ApplyResources(this.label4, "label4");
this.label4.Name = "label4";
//
// kvmCompInBytesLabel
//
resources.ApplyResources(this.kvmCompInBytesLabel, "kvmCompInBytesLabel");
this.kvmCompInBytesLabel.Name = "kvmCompInBytesLabel";
//
// kvmCompOutBytesLabel
//
resources.ApplyResources(this.kvmCompOutBytesLabel, "kvmCompOutBytesLabel");
this.kvmCompOutBytesLabel.Name = "kvmCompOutBytesLabel";
//
// kvmOutBytesLabel
//
resources.ApplyResources(this.kvmOutBytesLabel, "kvmOutBytesLabel");
this.kvmOutBytesLabel.Name = "kvmOutBytesLabel";
//
// kvmInBytesLabel
//
resources.ApplyResources(this.kvmInBytesLabel, "kvmInBytesLabel");
this.kvmInBytesLabel.Name = "kvmInBytesLabel";
//
// outRatioLabel
//
resources.ApplyResources(this.outRatioLabel, "outRatioLabel");
this.outRatioLabel.Name = "outRatioLabel";
//
// inRatioLabel
//
resources.ApplyResources(this.inRatioLabel, "inRatioLabel");
this.inRatioLabel.Name = "inRatioLabel";
//
// label10
//
resources.ApplyResources(this.label10, "label10");
this.label10.Name = "label10";
//
// label11
//
resources.ApplyResources(this.label11, "label11");
this.label11.Name = "label11";
//
// refreshTimer
//
this.refreshTimer.Interval = 500;
this.refreshTimer.Tick += new System.EventHandler(this.refreshTimer_Tick);
//
// KVMStats
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.okButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "KVMStats";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.KVMStats_FormClosing);
this.Load += new System.EventHandler(this.KVMStats_Load);
this.groupBox1.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.Label label12;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label outRatioLabel;
private System.Windows.Forms.Label inRatioLabel;
private System.Windows.Forms.Label label10;
private System.Windows.Forms.Label label11;
private System.Windows.Forms.Label kvmCompOutBytesLabel;
private System.Windows.Forms.Label kvmCompInBytesLabel;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.Label kvmOutBytesLabel;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label kvmInBytesLabel;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Timer refreshTimer;
}
}

68
src/KVMStats.cs Normal file
View File

@@ -0,0 +1,68 @@
/*
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.Windows.Forms;
namespace MeshCentralRouter
{
public partial class KVMStats : Form
{
public KVMViewer viewer;
public KVMStats(KVMViewer viewer)
{
this.viewer = viewer;
InitializeComponent();
Translate.TranslateControl(this);
}
private void refreshTimer_Tick(object sender, EventArgs e)
{
kvmInBytesLabel.Text = string.Format(((viewer.bytesIn == 1)? Translate.T(Properties.Resources.OneByte): Translate.T(Properties.Resources.XBytes)), viewer.bytesIn);
kvmOutBytesLabel.Text = string.Format(((viewer.bytesOut == 1) ? Translate.T(Properties.Resources.OneByte) : Translate.T(Properties.Resources.XBytes)), viewer.bytesOut);
kvmCompInBytesLabel.Text = string.Format(((viewer.bytesInCompressed == 1) ? Translate.T(Properties.Resources.OneByte) : Translate.T(Properties.Resources.XBytes)), viewer.bytesInCompressed);
kvmCompOutBytesLabel.Text = string.Format(((viewer.bytesOutCompressed == 1) ? Translate.T(Properties.Resources.OneByte) : Translate.T(Properties.Resources.XBytes)), viewer.bytesOutCompressed);
if (viewer.bytesIn == 0) {
inRatioLabel.Text = "0%";
} else {
inRatioLabel.Text = (100 - ((viewer.bytesInCompressed * 100) / viewer.bytesIn)) + "%";
}
if (viewer.bytesOut == 0) {
outRatioLabel.Text = "0%";
} else {
outRatioLabel.Text = (100 - ((viewer.bytesOutCompressed * 100) / viewer.bytesOut)) + "%";
}
}
private void KVMStats_FormClosing(object sender, FormClosingEventArgs e)
{
refreshTimer.Enabled = false;
}
private void KVMStats_Load(object sender, EventArgs e)
{
refreshTimer.Enabled = true;
refreshTimer_Tick(this, null);
Text = viewer.Text;
}
private void okButton_Click(object sender, EventArgs e)
{
viewer.closeKvmStats();
}
}
}

2309
src/KVMStats.resx Normal file

File diff suppressed because it is too large Load Diff

303
src/KVMViewer.Designer.cs generated Normal file
View File

@@ -0,0 +1,303 @@
using System.Windows.Forms;
namespace MeshCentralRouter
{
public class BlankPanel : System.Windows.Forms.Panel
{
public BlankPanel()
{
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Do not paint background.
}
}
partial class KVMViewer
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(KVMViewer));
this.mainStatusStrip = new System.Windows.Forms.StatusStrip();
this.mainToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
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.settingsButton = new System.Windows.Forms.Button();
this.zoomButton = new System.Windows.Forms.Button();
this.cadButton = new System.Windows.Forms.Button();
this.connectButton = new System.Windows.Forms.Button();
this.consentContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.askConsentBarToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.askConsentToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.privacyBarToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.consoleMessage = new System.Windows.Forms.Label();
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();
this.SuspendLayout();
//
// 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});
resources.ApplyResources(this.mainStatusStrip, "mainStatusStrip");
this.mainStatusStrip.Name = "mainStatusStrip";
//
// mainToolStripStatusLabel
//
this.mainToolStripStatusLabel.Name = "mainToolStripStatusLabel";
resources.ApplyResources(this.mainToolStripStatusLabel, "mainToolStripStatusLabel");
this.mainToolStripStatusLabel.Spring = true;
//
// toolStripStatusLabel1
//
this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
resources.ApplyResources(this.toolStripStatusLabel1, "toolStripStatusLabel1");
//
// updateTimer
//
this.updateTimer.Enabled = true;
this.updateTimer.Interval = 1000;
this.updateTimer.Tick += new System.EventHandler(this.updateTimer_Tick);
//
// 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.settingsButton);
this.topPanel.Controls.Add(this.zoomButton);
this.topPanel.Controls.Add(this.cadButton);
this.topPanel.Controls.Add(this.connectButton);
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");
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");
this.clipOutboundButton.Image = global::MeshCentralRouter.Properties.Resources.iconClipboardOut;
this.clipOutboundButton.Name = "clipOutboundButton";
this.clipOutboundButton.TabStop = false;
this.clipOutboundButton.UseVisualStyleBackColor = true;
this.clipOutboundButton.Click += new System.EventHandler(this.clipOutboundButton_Click);
//
// clipInboundButton
//
resources.ApplyResources(this.clipInboundButton, "clipInboundButton");
this.clipInboundButton.Image = global::MeshCentralRouter.Properties.Resources.iconClipboardIn;
this.clipInboundButton.Name = "clipInboundButton";
this.clipInboundButton.TabStop = false;
this.mainToolTip.SetToolTip(this.clipInboundButton, resources.GetString("clipInboundButton.ToolTip"));
this.clipInboundButton.UseVisualStyleBackColor = true;
this.clipInboundButton.Click += new System.EventHandler(this.clipInboundButton_Click);
//
// statsButton
//
resources.ApplyResources(this.statsButton, "statsButton");
this.statsButton.Name = "statsButton";
this.statsButton.TabStop = false;
this.statsButton.UseVisualStyleBackColor = true;
this.statsButton.Click += new System.EventHandler(this.statsButton_Click);
//
// settingsButton
//
resources.ApplyResources(this.settingsButton, "settingsButton");
this.settingsButton.Name = "settingsButton";
this.settingsButton.TabStop = false;
this.settingsButton.UseVisualStyleBackColor = true;
this.settingsButton.Click += new System.EventHandler(this.settingsToolStripMenuItem_Click);
//
// zoomButton
//
resources.ApplyResources(this.zoomButton, "zoomButton");
this.zoomButton.Image = global::MeshCentralRouter.Properties.Resources.ZoomToFit;
this.zoomButton.Name = "zoomButton";
this.zoomButton.TabStop = false;
this.zoomButton.UseVisualStyleBackColor = true;
this.zoomButton.Click += new System.EventHandler(this.zoomButton_Click);
//
// cadButton
//
resources.ApplyResources(this.cadButton, "cadButton");
this.cadButton.Name = "cadButton";
this.cadButton.TabStop = false;
this.cadButton.UseVisualStyleBackColor = true;
this.cadButton.Click += new System.EventHandler(this.sendCtrlAltDelToolStripMenuItem_Click);
//
// connectButton
//
this.connectButton.ContextMenuStrip = this.consentContextMenuStrip;
resources.ApplyResources(this.connectButton, "connectButton");
this.connectButton.Name = "connectButton";
this.connectButton.TabStop = false;
this.connectButton.UseVisualStyleBackColor = true;
this.connectButton.Click += new System.EventHandler(this.MenuItemDisconnect_Click);
//
// consentContextMenuStrip
//
this.consentContextMenuStrip.ImageScalingSize = new System.Drawing.Size(20, 20);
this.consentContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.askConsentBarToolStripMenuItem,
this.askConsentToolStripMenuItem,
this.privacyBarToolStripMenuItem});
this.consentContextMenuStrip.Name = "consentContextMenuStrip";
resources.ApplyResources(this.consentContextMenuStrip, "consentContextMenuStrip");
this.consentContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.consentContextMenuStrip_Opening);
//
// askConsentBarToolStripMenuItem
//
this.askConsentBarToolStripMenuItem.Name = "askConsentBarToolStripMenuItem";
resources.ApplyResources(this.askConsentBarToolStripMenuItem, "askConsentBarToolStripMenuItem");
this.askConsentBarToolStripMenuItem.Click += new System.EventHandler(this.askConsentBarToolStripMenuItem_Click);
//
// askConsentToolStripMenuItem
//
this.askConsentToolStripMenuItem.Name = "askConsentToolStripMenuItem";
resources.ApplyResources(this.askConsentToolStripMenuItem, "askConsentToolStripMenuItem");
this.askConsentToolStripMenuItem.Click += new System.EventHandler(this.askConsentToolStripMenuItem_Click);
//
// privacyBarToolStripMenuItem
//
this.privacyBarToolStripMenuItem.Name = "privacyBarToolStripMenuItem";
resources.ApplyResources(this.privacyBarToolStripMenuItem, "privacyBarToolStripMenuItem");
this.privacyBarToolStripMenuItem.Click += new System.EventHandler(this.privacyBarToolStripMenuItem_Click);
//
// consoleMessage
//
resources.ApplyResources(this.consoleMessage, "consoleMessage");
this.consoleMessage.ForeColor = System.Drawing.Color.Black;
this.consoleMessage.Name = "consoleMessage";
//
// consoleTimer
//
this.consoleTimer.Interval = 5000;
this.consoleTimer.Tick += new System.EventHandler(this.consoleTimer_Tick);
//
// resizeKvmControl
//
this.resizeKvmControl.BackColor = System.Drawing.Color.Gray;
resources.ApplyResources(this.resizeKvmControl, "resizeKvmControl");
this.resizeKvmControl.Name = "resizeKvmControl";
this.resizeKvmControl.ZoomToFit = false;
this.resizeKvmControl.StateChanged += new System.EventHandler(this.kvmControl_StateChanged);
this.resizeKvmControl.DisplaysReceived += new System.EventHandler(this.resizeKvmControl_DisplaysReceived);
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");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Gray;
this.Controls.Add(this.consoleMessage);
this.Controls.Add(this.resizeKvmControl);
this.Controls.Add(this.topPanel);
this.Controls.Add(this.mainStatusStrip);
this.Name = "KVMViewer";
this.Activated += new System.EventHandler(this.KVMViewer_Activated);
this.Deactivate += new System.EventHandler(this.KVMViewer_Deactivate);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Main_FormClosing);
this.Load += new System.EventHandler(this.MainForm_Load);
this.Resize += new System.EventHandler(this.MainForm_Resize);
this.mainStatusStrip.ResumeLayout(false);
this.mainStatusStrip.PerformLayout();
this.topPanel.ResumeLayout(false);
this.consentContextMenuStrip.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private StatusStrip mainStatusStrip;
private ToolStripStatusLabel mainToolStripStatusLabel;
private Timer updateTimer;
private KVMResizeControl resizeKvmControl;
private ToolStripStatusLabel toolStripStatusLabel1;
private Panel topPanel;
private Button connectButton;
private Button cadButton;
private Button zoomButton;
private Button settingsButton;
private Label consoleMessage;
private Timer consoleTimer;
private Button statsButton;
private Button clipInboundButton;
private Button clipOutboundButton;
private ToolTip mainToolTip;
private ContextMenuStrip consentContextMenuStrip;
private ToolStripMenuItem askConsentBarToolStripMenuItem;
private ToolStripMenuItem askConsentToolStripMenuItem;
private ToolStripMenuItem privacyBarToolStripMenuItem;
private Button splitButton;
private Panel extraButtonsPanel;
private ImageList displaySelectorImageList;
}
}

760
src/KVMViewer.cs Normal file
View File

@@ -0,0 +1,760 @@
/*
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.Collections.Generic;
using System.Security.Cryptography;
using System.Web.Script.Serialization;
using System.Threading;
namespace MeshCentralRouter
{
public partial class KVMViewer : Form
{
private MainForm parent = null;
private KVMControl kvmControl = null;
private KVMStats kvmStats = null;
private MeshCentralServer server = null;
private NodeClass node = null;
private int state = 0;
private RandomNumberGenerator rand = RandomNumberGenerator.Create();
private string randomIdHex = null;
private bool sessionIsRecorded = false;
public int consentFlags = 0;
public webSocketClient wc = null;
public Dictionary<string, int> userSessions = null;
private string lastClipboardSent = null;
private DateTime lastClipboardTime = DateTime.MinValue;
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;
private Dictionary<int, Button> displaySelectionButtons = new Dictionary<int, Button>();
// Stats
public long bytesIn = 0;
public long bytesInCompressed = 0;
public long bytesOut = 0;
public long bytesOutCompressed = 0;
public KVMViewer(MainForm parent, MeshCentralServer server, NodeClass node)
{
this.parent = parent;
InitializeComponent();
Translate.TranslateControl(this);
this.Text += " - " + node.name;
this.node = node;
this.server = server;
kvmControl = resizeKvmControl.KVM;
kvmControl.parent = this;
kvmControl.DesktopSizeChanged += KvmControl_DesktopSizeChanged;
kvmControl.ScreenAreaUpdated += KvmControl_ScreenAreaUpdated;
resizeKvmControl.ZoomToFit = true;
UpdateStatus();
this.MouseWheel += MainForm_MouseWheel;
parent.ClipboardChanged += Parent_ClipboardChanged;
mainToolTip.SetToolTip(connectButton, Translate.T(Properties.Resources.ToggleRemoteDesktopConnection, lang));
mainToolTip.SetToolTip(cadButton, Translate.T(Properties.Resources.SendCtrlAltDelToRemoteDevice, lang));
mainToolTip.SetToolTip(settingsButton, Translate.T(Properties.Resources.ChangeRemoteDesktopSettings, lang));
mainToolTip.SetToolTip(clipOutboundButton, Translate.T(Properties.Resources.PushLocaClipboardToRemoteDevice, lang));
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)
{
if (extraDisplays == null) return;
foreach (KVMViewerExtra x in extraDisplays) {
if (x != null) { x.UpdateScreenArea(desktop, r); }
}
}
private void Parent_ClipboardChanged()
{
if (state != 3) return;
if (kvmControl.AutoSendClipboard) { SendClipboard(); }
}
private delegate void SendClipboardHandler();
private void SendClipboard()
{
if (this.InvokeRequired) { this.Invoke(new SendClipboardHandler(SendClipboard)); return; }
string textData = (string)Clipboard.GetData(DataFormats.Text);
if (textData != null)
{
if ((DateTime.Now.Subtract(lastClipboardTime).TotalSeconds < 20) && (lastClipboardSent != null) && (lastClipboardSent.Equals(textData))) return; // Don't resend clipboard if same and sent in last 20 seconds. This avoids clipboard loop.
string textData2 = textData.Replace("\\", "\\\\").Replace("\"", "\\\"");
server.sendCommand("{\"action\":\"msg\",\"type\":\"setclip\",\"nodeid\":\"" + node.nodeid + "\",\"data\":\"" + textData2 + "\"}");
lastClipboardTime = DateTime.Now;
lastClipboardSent = textData;
}
}
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;
}
private void Server_onStateChanged(int state)
{
UpdateStatus();
}
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);
topPanel.Visible = true;
// Restore Window Location
string locationStr = Settings.GetRegValue("kvmlocation", "");
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) { }
}
}
}
public void OnScreenChanged()
{
resizeKvmControl.CenterKvmControl(true);
}
private void MenuItemExit_Click(object sender, EventArgs e)
{
node.desktopViewer = null;
closeKvmStats();
Close();
}
public void MenuItemConnect_Click(object sender, EventArgs e)
{
if (wc != 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=2&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;
kvmControl.DetacheKeyboard();
break;
}
case webSocketClient.ConnectionStates.Connecting:
{
state = 1;
displayMessage(null);
break;
}
case webSocketClient.ConnectionStates.Connected:
{
// Reset stats
bytesIn = 0;
bytesInCompressed = 0;
bytesOut = 0;
bytesOutCompressed = 0;
state = 2;
string u = "*" + server.wsurl.AbsolutePath.Replace("control.ashx", "meshrelay.ashx") + "?p=2&nodeid=" + node.nodeid + "&id=" + randomIdHex + "&rauth=" + server.rauthCookie;
server.sendCommand("{ \"action\": \"msg\", \"type\": \"tunnel\", \"nodeid\": \"" + node.nodeid + "\", \"value\": \"" + u.ToString() + "\", \"usage\": 2 }");
displayMessage(null);
break;
}
}
UpdateStatus();
}
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;
// Send any connection options here
if (consentFlags != 0) { kvmControl.Send("{ \"type\": \"options\", \"consent\": " + consentFlags + " }"); }
// Send remote desktop protocol (2)
kvmControl.Send("2");
kvmControl.SendCompressionLevel();
kvmControl.SendPause(false);
kvmControl.SendRefresh();
UpdateStatus();
displayMessage(null);
// Send clipboard
if (kvmControl.AutoSendClipboard) { SendClipboard(); }
return;
}
if (state != 3) return;
// Parse the received JSON
Dictionary<string, object> jsonAction = new Dictionary<string, object>();
jsonAction = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(data);
if ((jsonAction == null) || (jsonAction.ContainsKey("type") == false) || (jsonAction["type"].GetType() != typeof(string))) return;
string action = jsonAction["type"].ToString();
switch (action)
{
case "metadata":
{
if ((jsonAction.ContainsKey("users") == false) || (jsonAction["users"] == null)) return;
Dictionary<string, object> usersex = (Dictionary<string, object>)jsonAction["users"];
userSessions = new Dictionary<string, int>();
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, lang); }
if (msgid == 2) { msg = Translate.T(Properties.Resources.Denied, lang); }
if (msgid == 3) { msg = Translate.T(Properties.Resources.FailedToStartRemoteDesktopSession, lang); }
if (msgid == 4) { msg = Translate.T(Properties.Resources.Timeout, lang); }
if (msgid == 5) { msg = Translate.T(Properties.Resources.ReceivedInvalidNetworkData, lang); }
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;
kvmControl.ProcessData(data, offset, length);
}
private void MenuItemDisconnect_Click(object sender, EventArgs e)
{
if (wc != null)
{
// Disconnect
if (splitMode) { splitButton_Click(this, null); }
splitButton.Visible = false;
state = 0;
wc.Dispose();
wc = null;
UpdateStatus();
localAutoReconnect = false;
}
else
{
// Connect
if (sender != null) { consentFlags = 0; }
MenuItemConnect_Click(null, null);
kvmControl.AttachKeyboard();
localAutoReconnect = true;
}
displayMessage(null);
}
public delegate void UpdateStatusHandler();
private void UpdateStatus()
{
if (this.InvokeRequired) { try { this.Invoke(new UpdateStatusHandler(UpdateStatus)); } catch (Exception) { } return; }
//if (kvmControl == null) return;
switch (state)
{
case 0: // Disconnected
mainToolStripStatusLabel.Text = Translate.T(Properties.Resources.Disconnected, lang);
extraButtonsPanel.Visible = false;
kvmControl.Visible = false;
kvmControl.screenWidth = 0;
kvmControl.screenHeight = 0;
connectButton.Text = Translate.T(Properties.Resources.Connect, lang);
break;
case 1: // Connecting
mainToolStripStatusLabel.Text = Translate.T(Properties.Resources.Connecting, lang);
extraButtonsPanel.Visible = false;
kvmControl.Visible = false;
connectButton.Text = Translate.T(Properties.Resources.Disconnect, lang);
break;
case 2: // Setup
mainToolStripStatusLabel.Text = "Setup...";
extraButtonsPanel.Visible = false;
kvmControl.Visible = false;
connectButton.Text = Translate.T(Properties.Resources.Disconnect, lang);
break;
case 3: // Connected
string label = Translate.T(Properties.Resources.Connected, lang);
if (sessionIsRecorded) { label += Translate.T(Properties.Resources.RecordedSession, lang); }
if ((userSessions != null) && (userSessions.Count > 1)) { label += string.Format(Translate.T(Properties.Resources.AddXUsers, lang), userSessions.Count); }
label += ".";
mainToolStripStatusLabel.Text = label;
connectButton.Text = Translate.T(Properties.Resources.Disconnect, lang);
kvmControl.SendCompressionLevel();
break;
}
cadButton.Enabled = (state == 3);
if ((kvmControl.AutoSendClipboard) && ((server.features2 & 0x1000) == 0)) // 0x1000 Clipboard Set
{
clipInboundButton.Visible = false;
clipOutboundButton.Visible = false;
}
else
{
clipInboundButton.Visible = ((server.features2 & 0x0800) == 0); // 0x0800 Clipboard Get
clipOutboundButton.Visible = ((server.features2 & 0x1000) == 0); // 0x1000 Clipboard Set
}
clipInboundButton.Enabled = (state == 3);
clipOutboundButton.Enabled = (state == 3);
}
private void updateTimer_Tick(object sender, EventArgs e)
{
UpdateStatus();
}
private void Main_FormClosing(object sender, FormClosingEventArgs e)
{
if (wc != null)
{
// Disconnect
state = 0;
wc.Dispose();
wc = null;
UpdateStatus();
}
node.desktopViewer = null;
closeKvmStats();
// 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)
{
//MenuItemConnect.Enabled = (kvmControl.State == KVMControl.ConnectState.Disconnected);
//MenuItemDisconnect.Enabled = (kvmControl.State != KVMControl.ConnectState.Disconnected);
//serverConnectToolStripMenuItem.Enabled = (server == null && kvmControl.State == KVMControl.ConnectState.Disconnected);
//serviceDisconnectToolStripMenuItem.Enabled = (server != null && server.CurrentState != MeshSwarmServer.State.Disconnected);
}
private void kvmControl_StateChanged(object sender, EventArgs e)
{
UpdateStatus();
}
private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (kvmControl == null) return;
using (KVMSettingsForm form = new KVMSettingsForm(server.features2))
{
form.Compression = kvmControl.CompressionLevel;
form.Scaling = kvmControl.ScalingLevel;
form.FrameRate = kvmControl.FrameRate;
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;
Settings.SetRegValue("kvmAutoClipboard", kvmControl.AutoSendClipboard ? "1" : "0");
if (kvmControl.AutoSendClipboard == true) { Parent_ClipboardChanged(); }
}
UpdateStatus();
}
}
}
private void MainForm_Resize(object sender, EventArgs e)
{
if (kvmControl != null) kvmControl.SendPause(WindowState == FormWindowState.Minimized);
}
private void sendCtrlAltDelToolStripMenuItem_Click(object sender, EventArgs e)
{
if (kvmControl != null) kvmControl.SendCtrlAltDel();
}
private void debugButton_Click(object sender, EventArgs e)
{
if (kvmControl != null) kvmControl.debugmode = !kvmControl.debugmode;
}
private void zoomButton_Click(object sender, EventArgs e)
{
resizeKvmControl.ZoomToFit = !resizeKvmControl.ZoomToFit;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void resizeKvmControl_DisplaysReceived(object sender, EventArgs e)
{
if (kvmControl == null || kvmControl.displays.Count == 0) return;
if (kvmControl.displays.Count > 0)
{
extraButtonsPanel.Visible = true;
extraButtonsPanel.Controls.Clear();
displaySelectionButtons.Clear();
foreach (ushort displayNum in kvmControl.displays)
{
if (displayNum == 0xFFFF)
{
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
{
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);
}
}
}
else
{
extraButtonsPanel.Visible = false;
extraButtonsPanel.Controls.Clear();
displaySelectionButtons.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 (splitMode) { splitButton_Click(this, null); }
if (kvmControl != null) {
ushort displayNum = (ushort)((Button)sender).Tag;
kvmControl.SendDisplay(displayNum);
}
}
private void resizeKvmControl_TouchEnabledChanged(object sender, EventArgs e)
{
UpdateStatus();
}
private void commandsToolStripMenuItem_CheckStateChanged(object sender, EventArgs e)
{
//if (server == null) return;
//if (commandsToolStripMenuItem.Checked) server.ShowCommandViewer(); else server.HideCommandViewer();
}
private void emulateTouchToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
{
//kvmControl.emulateTouch = emulateTouchToolStripMenuItem.Checked;
}
private void packetsToolStripMenuItem_CheckStateChanged(object sender, EventArgs e)
{
//kvmControl.ShowPackets(packetsToolStripMenuItem.Checked);
}
private void kVMCommandsToolStripMenuItem_Click(object sender, EventArgs e)
{
//kvmControl.ShowCommands(kVMCommandsToolStripMenuItem.Checked);
}
private void winButton_Click(object sender, EventArgs e)
{
//kvmControl.SendWindowsKey();
}
private void charmButton_Click(object sender, EventArgs e)
{
//kvmControl.SendCharmsKey();
}
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 statsButton_Click(object sender, EventArgs e)
{
if (kvmStats == null)
{
kvmStats = new KVMStats(this);
kvmStats.Show(this);
}
else
{
kvmStats.Focus();
}
}
public void closeKvmStats()
{
if (kvmStats == null) return;
kvmStats.Close();
kvmStats = null;
}
private void clipInboundButton_Click(object sender, EventArgs e)
{
//string textData = "abc";
//Clipboard.SetData(DataFormats.Text, (Object)textData);
server.sendCommand("{\"action\":\"msg\",\"type\":\"getclip\",\"nodeid\":\"" + node.nodeid + "\"}");
}
private void clipOutboundButton_Click(object sender, EventArgs e)
{
SendClipboard();
}
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 askConsentBarToolStripMenuItem_Click(object sender, EventArgs e)
{
consentFlags = 0x0008 + 0x0040; // Consent Prompt + Privacy bar
MenuItemDisconnect_Click(null, null);
}
private void askConsentToolStripMenuItem_Click(object sender, EventArgs e)
{
consentFlags = 0x0008; // Consent Prompt
MenuItemDisconnect_Click(null, null);
}
private void privacyBarToolStripMenuItem_Click(object sender, EventArgs e)
{
consentFlags = 0x0040; // Privacy bar
MenuItemDisconnect_Click(null, null);
}
private void consentContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
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);
}
}
}
}
}

1168
src/KVMViewer.resx Normal file

File diff suppressed because it is too large Load Diff

65
src/KVMViewerExtra.Designer.cs generated Normal file
View File

@@ -0,0 +1,65 @@
using System.Windows.Forms;
namespace MeshCentralRouter
{
partial class KVMViewerExtra
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

125
src/KVMViewerExtra.cs Normal file
View File

@@ -0,0 +1,125 @@
/*
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.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)
{
//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();
}
}
}

599
src/KVMViewerExtra.resx Normal file
View File

@@ -0,0 +1,599 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="resizeKvmControl.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="resizeKvmControl.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 0</value>
</data>
<data name="resizeKvmControl.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 4, 4, 4</value>
</data>
<data name="resizeKvmControl.Size" type="System.Drawing.Size, System.Drawing">
<value>826, 522</value>
</data>
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="resizeKvmControl.TabIndex" type="System.Int32, mscorlib">
<value>10</value>
</data>
<data name="&gt;&gt;resizeKvmControl.Name" xml:space="preserve">
<value>resizeKvmControl</value>
</data>
<data name="&gt;&gt;resizeKvmControl.Type" xml:space="preserve">
<value>MeshCentralRouter.KVMResizeControl, MeshCentralRouter, Version=1.8.8062.29471, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;resizeKvmControl.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;resizeKvmControl.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>8, 16</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>826, 522</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
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
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=
</value>
</data>
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>3, 2, 3, 2</value>
</data>
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
<value>CenterScreen</value>
</data>
<data name="$this.Text" xml:space="preserve">
<value>Remote Desktop</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>KVMViewerExtra</value>
</data>
<data name="&gt;&gt;$this.Type" xml:space="preserve">
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

393
src/ListViewExtended.cs Normal file
View File

@@ -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);
/// <summary>
/// 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.
/// </summary>
/// <param name="hWnd">
/// [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.
/// </param>
/// <param name="uMsg">[in] Specifies the message to be sent.</param>
/// <param name="wParam">[in] Specifies additional message-specific information.</param>
/// <param name="lParam">[in] Type of LVGROUP, Specifies additional message-specific information.</param>
/// <returns>
/// 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.
/// </returns>
[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);
}
}
/// <summary>
/// LVGROUP StructureUsed to set and retrieve groups.
/// </summary>
/// <example>
/// 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
/// </example>
/// <remarks>
/// 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
/// </remarks>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode), Description("LVGROUP StructureUsed to set and retrieve groups.")]
public struct LVGROUP
{
/// <summary>
/// Size of this structure, in bytes.
/// </summary>
[Description("Size of this structure, in bytes.")]
public int CbSize;
/// <summary>
/// Mask that specifies which members of the structure are valid input. One or more of the following values:LVGF_NONENo other items are valid.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// ID of the group.
/// </summary>
[Description("ID of the group.")]
public int IGroupId;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// Windows Vista. Index of the title image in the control imagelist.
/// </summary>
[Description("Windows Vista. Index of the title image in the control imagelist.")]
public int ITitleImage;
/// <summary>
/// Windows Vista. Index of the extended image in the control imagelist.
/// </summary>
[Description("Windows Vista. Index of the extended image in the control imagelist.")]
public int IExtendedImage;
/// <summary>
/// Windows Vista. Read-only.
/// </summary>
[Description("Windows Vista. Read-only.")]
public int IFirstItem;
/// <summary>
/// Windows Vista. Read-only in non-owner data mode.
/// </summary>
[Description("Windows Vista. Read-only in non-owner data mode.")]
public IntPtr CItems;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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.
/// </summary>
[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
{
/// <summary>
/// Groups are expanded, the group name is displayed, and all items in the group are displayed.
/// </summary>
Normal = 0,
/// <summary>
/// The group is collapsed.
/// </summary>
Collapsed = 1,
/// <summary>
/// The group is hidden.
/// </summary>
Hidden = 2,
/// <summary>
/// Version 6.00 and Windows Vista. The group does not display a header.
/// </summary>
NoHeader = 4,
/// <summary>
/// Version 6.00 and Windows Vista. The group can be collapsed.
/// </summary>
Collapsible = 8,
/// <summary>
/// Version 6.00 and Windows Vista. The group has keyboard focus.
/// </summary>
Focused = 16,
/// <summary>
/// Version 6.00 and Windows Vista. The group is selected.
/// </summary>
Selected = 32,
/// <summary>
/// Version 6.00 and Windows Vista. The group displays only a portion of its items.
/// </summary>
SubSeted = 64,
/// <summary>
/// Version 6.00 and Windows Vista. The subset link of the group has keyboard focus.
/// </summary>
SubSetLinkFocused = 128,
}
}

102
src/LocalPipe.cs Normal file
View File

@@ -0,0 +1,102 @@
/*
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.Collections.Generic;
using System.IO.Pipes;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
namespace MeshCentralRouter
{
public class LocalPipeServer
{
private String name;
private byte[] buffer = new byte[4096];
private NamedPipeServerStream pipeServer;
public delegate void onArgsHandler(string args);
public event onArgsHandler onArgs;
public LocalPipeServer(string name)
{
this.name = name;
pipeServer = new NamedPipeServerStream(name, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
pipeServer.BeginWaitForConnection(new AsyncCallback(processConnection), null);
}
public void Dispose()
{
try { pipeServer.Close(); } catch (Exception) { }
pipeServer = null;
}
private void processConnection(IAsyncResult ar)
{
try { pipeServer.EndWaitForConnection(ar); } catch (Exception) { }
try { pipeServer.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(processRead), null); } catch (Exception) { }
}
private void processRead(IAsyncResult ar)
{
int len = 0;
try { len = pipeServer.EndRead(ar); } catch (Exception) { }
if (len > 0)
{
string args = UTF8Encoding.UTF8.GetString(buffer, 0, len);
pipeServer.Close();
onArgs(args);
pipeServer = new NamedPipeServerStream(name, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
pipeServer.BeginWaitForConnection(new AsyncCallback(processConnection), null);
}
}
}
public class LocalPipeClient
{
private byte[] buffer = new byte[4096];
private NamedPipeClientStream pipeClient;
public LocalPipeClient(string name)
{
pipeClient = new NamedPipeClientStream(".", name, PipeDirection.InOut, PipeOptions.Asynchronous, TokenImpersonationLevel.None);
}
public bool TrySendingArguments(string args)
{
try
{
byte[] buf = UTF8Encoding.UTF8.GetBytes(args);
pipeClient.Connect(10);
pipeClient.BeginWrite(buf, 0, buf.Length, new AsyncCallback(processWrite), null);
}
catch (Exception) { return false; }
return true;
}
private void processWrite(IAsyncResult ar)
{
try { pipeClient.EndWrite(ar); } catch (Exception) { }
pipeClient.Close();
}
}
}

1154
src/MainForm.Designer.cs generated Normal file

File diff suppressed because it is too large Load Diff

2203
src/MainForm.cs Normal file

File diff suppressed because it is too large Load Diff

6138
src/MainForm.resx Normal file

File diff suppressed because it is too large Load Diff

139
src/MapUserControl.Designer.cs generated Normal file
View File

@@ -0,0 +1,139 @@
namespace MeshCentralRouter
{
partial class MapUserControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MapUserControl));
this.devicePictureBox = new System.Windows.Forms.PictureBox();
this.deviceNameLabel = new System.Windows.Forms.Label();
this.routingStatusLabel = new System.Windows.Forms.Label();
this.appButton = new System.Windows.Forms.Button();
this.closeButton = new System.Windows.Forms.Button();
this.deviceImageList = new System.Windows.Forms.ImageList(this.components);
this.mainContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.statsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.autoExitTimer = new System.Windows.Forms.Timer(this.components);
((System.ComponentModel.ISupportInitialize)(this.devicePictureBox)).BeginInit();
this.mainContextMenuStrip.SuspendLayout();
this.SuspendLayout();
//
// devicePictureBox
//
this.devicePictureBox.Image = global::MeshCentralRouter.Properties.Resources.icons01;
resources.ApplyResources(this.devicePictureBox, "devicePictureBox");
this.devicePictureBox.Name = "devicePictureBox";
this.devicePictureBox.TabStop = false;
//
// deviceNameLabel
//
resources.ApplyResources(this.deviceNameLabel, "deviceNameLabel");
this.deviceNameLabel.Name = "deviceNameLabel";
//
// routingStatusLabel
//
resources.ApplyResources(this.routingStatusLabel, "routingStatusLabel");
this.routingStatusLabel.Name = "routingStatusLabel";
//
// appButton
//
resources.ApplyResources(this.appButton, "appButton");
this.appButton.Name = "appButton";
this.appButton.UseVisualStyleBackColor = true;
this.appButton.Click += new System.EventHandler(this.appButton_Click);
//
// closeButton
//
resources.ApplyResources(this.closeButton, "closeButton");
this.closeButton.Name = "closeButton";
this.closeButton.UseVisualStyleBackColor = true;
this.closeButton.Click += new System.EventHandler(this.closeButton_Click);
//
// deviceImageList
//
this.deviceImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("deviceImageList.ImageStream")));
this.deviceImageList.TransparentColor = System.Drawing.Color.Transparent;
this.deviceImageList.Images.SetKeyName(0, "icons01.png");
this.deviceImageList.Images.SetKeyName(1, "icons02.png");
this.deviceImageList.Images.SetKeyName(2, "icons03.png");
this.deviceImageList.Images.SetKeyName(3, "icons04.png");
this.deviceImageList.Images.SetKeyName(4, "icons05.png");
this.deviceImageList.Images.SetKeyName(5, "icons06.png");
this.deviceImageList.Images.SetKeyName(6, "icons07.png");
this.deviceImageList.Images.SetKeyName(7, "icons08.png");
//
// mainContextMenuStrip
//
this.mainContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.statsToolStripMenuItem});
this.mainContextMenuStrip.Name = "mainContextMenuStrip";
resources.ApplyResources(this.mainContextMenuStrip, "mainContextMenuStrip");
//
// statsToolStripMenuItem
//
this.statsToolStripMenuItem.Name = "statsToolStripMenuItem";
resources.ApplyResources(this.statsToolStripMenuItem, "statsToolStripMenuItem");
this.statsToolStripMenuItem.Click += new System.EventHandler(this.statsToolStripMenuItem_Click);
//
// autoExitTimer
//
this.autoExitTimer.Interval = 1000;
this.autoExitTimer.Tick += new System.EventHandler(this.autoExitTimer_Tick);
//
// MapUserControl
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.ControlLight;
this.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.ContextMenuStrip = this.mainContextMenuStrip;
this.Controls.Add(this.closeButton);
this.Controls.Add(this.appButton);
this.Controls.Add(this.routingStatusLabel);
this.Controls.Add(this.deviceNameLabel);
this.Controls.Add(this.devicePictureBox);
this.Name = "MapUserControl";
((System.ComponentModel.ISupportInitialize)(this.devicePictureBox)).EndInit();
this.mainContextMenuStrip.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.PictureBox devicePictureBox;
private System.Windows.Forms.Label deviceNameLabel;
private System.Windows.Forms.Label routingStatusLabel;
private System.Windows.Forms.Button appButton;
private System.Windows.Forms.Button closeButton;
private System.Windows.Forms.ImageList deviceImageList;
private System.Windows.Forms.ContextMenuStrip mainContextMenuStrip;
private System.Windows.Forms.ToolStripMenuItem statsToolStripMenuItem;
private System.Windows.Forms.Timer autoExitTimer;
}
}

309
src/MapUserControl.cs Normal file
View File

@@ -0,0 +1,309 @@
/*
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.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using Microsoft.Win32;
namespace MeshCentralRouter
{
public partial class MapUserControl : UserControl
{
public string name;
public int protocol;
public int localPort;
public string remoteIP = null;
public int remotePort;
public int appId;
public string appIdStr;
public NodeClass node;
public MainForm parent;
public MeshMapper mapper;
public string host;
//public string authCookie;
public string certhash;
public bool xdebug = false;
public bool inaddrany = false;
public MappingStats stats = null;
public bool autoexit = false;
public static void saveToRegistry(string name, string value)
{
try { Registry.SetValue(@"HKEY_CURRENT_USER\SOFTWARE\OpenSource\MeshRouter", name, value); } catch (Exception) { }
}
public static string loadFromRegistry(string name)
{
try { return Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\OpenSource\MeshRouter", name, "").ToString(); } catch (Exception) { return ""; }
}
public MapUserControl()
{
InitializeComponent();
}
public void UpdateInfo()
{
if ((name != null) && (name != ""))
{
deviceNameLabel.Text = node.name + ": " + this.name;
}
else
{
deviceNameLabel.Text = node.name;
}
devicePictureBox.Image = deviceImageList.Images[node.icon - 1];
}
public void Start()
{
routingStatusLabel.Text = Translate.T(Properties.Resources.Starting);
appButton.Enabled = (appId != 0) || (appIdStr != null);
mapper = new MeshMapper();
mapper.xdebug = xdebug;
mapper.inaddrany = inaddrany;
mapper.certhash = certhash;
mapper.onStateMsgChanged += Mapper_onStateMsgChanged;
string serverurl;
int keyIndex = host.IndexOf("?key=");
if (keyIndex >= 0) {
serverurl = "wss://" + host.Substring(0, keyIndex) + "/" + ((node.mtype == 3)?"local":"mesh") + "relay.ashx?nodeid=" + node.nodeid + "&key=" + host.Substring(keyIndex + 5);
} else {
serverurl = "wss://" + host + "/" + ((node.mtype == 3) ? "local" : "mesh") + "relay.ashx?nodeid=" + node.nodeid;
}
if (protocol == 1) {
serverurl += ("&tcpport=" + remotePort);
if (remoteIP != null) { serverurl += "&tcpaddr=" + remoteIP; }
} else if (protocol == 2) {
serverurl += ("&udpport=" + remotePort);
if (remoteIP != null) { serverurl += "&udpaddr=" + remoteIP; }
}
mapper.start(parent.meshcentral, protocol, localPort, serverurl, remotePort, remoteIP);
UpdateInfo();
}
public void Stop()
{
routingStatusLabel.Text = Translate.T(Properties.Resources.Stopped);
appButton.Enabled = false;
if (mapper != null) { mapper.onStateMsgChanged -= Mapper_onStateMsgChanged; mapper.stop(); mapper = null; }
if (stats != null) { stats.Close(); stats = null; }
}
private void Mapper_onStateMsgChanged(string statemsg)
{
if (this.InvokeRequired) { this.Invoke(new MeshMapper.onStateMsgChangedHandler(Mapper_onStateMsgChanged), statemsg); return; }
if (protocol == 2) {
statemsg = "UDP: " + statemsg;
} else {
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; }
else if (appId == 5) { statemsg = "WinSCP: " + statemsg; }
else { statemsg = "TCP: " + statemsg; }
}
routingStatusLabel.Text = statemsg;
}
public void appButton_Click(object sender, EventArgs e)
{
bool shift = false;
if (Control.ModifierKeys == Keys.Shift) { shift = true; }
if (appId == 0)
{
if (appIdStr == null) return;
string appCmd = null;
string appArgs = null;
List<String[]> 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;
}
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)
{
System.Diagnostics.Process proc = null;
string cmd = System.Environment.GetFolderPath(System.Environment.SpecialFolder.System) + "\\mstsc.exe";
string tfile = Path.Combine(Path.GetTempPath(), "MeshRdpFile.rdp");
string[] f = null;
try { if (File.Exists(tfile)) f = File.ReadAllLines(tfile); } catch (Exception) { }
if (f != null)
{
List<string> f2 = new List<string>();
foreach (string fx in f) { if (!fx.StartsWith("full address")) f2.Add(fx); }
f2.Add(string.Format("full address:s:127.0.0.1:{0}", mapper.localport));
File.WriteAllLines(tfile, f2.ToArray());
}
else
{
File.WriteAllText(tfile, string.Format("full address:s:127.0.0.1:{0}", mapper.localport));
}
string args = "/edit:\"" + tfile + "\"";
// Launch the process
try { proc = System.Diagnostics.Process.Start(cmd, args); }
catch (System.ComponentModel.Win32Exception) { }
// Setup auto-exit
if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; }
autoexit = false;
}
if (appId == 4)
{
string appTag = null;
string appPath = null;
string puttyPath = loadFromRegistry("PuttyPath");
string openSshPath = loadFromRegistry("OpenSshPath");
if (File.Exists(puttyPath)) { appTag = "PuttyPath"; appPath = puttyPath; }
if (File.Exists(openSshPath)) { appTag = "OpenSshPath"; appPath = openSshPath; }
if ((shift == false) && (appPath != null))
{
// Launch the process
System.Diagnostics.Process proc = null;
string args = null;
if (appTag == "OpenSshPath") {
SshUsernameForm f2 = new SshUsernameForm();
if (f2.ShowDialog(this) != DialogResult.OK) return;
args = "127.0.0.1 -l " + f2.Username + " -p " + mapper.localport;
}
if (appTag == "PuttyPath") { args = "-ssh 127.0.0.1 -P " + mapper.localport; }
try { proc = System.Diagnostics.Process.Start(appPath, args); }
catch (System.ComponentModel.Win32Exception) { }
// Setup auto-exit
if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; }
autoexit = false;
}
else
{
using (AppLaunchForm f = new AppLaunchForm())
{
System.Diagnostics.Process proc = null;
AppLaunchForm.AppInfo[] apps = new AppLaunchForm.AppInfo[2];
apps[0] = new AppLaunchForm.AppInfo(Translate.T(Properties.Resources.OpenSSHAppName), "https://www.openssh.com/", (parent.nativeSshPath != null) ? parent.nativeSshPath.FullName : "", "OpenSshPath");
apps[1] = new AppLaunchForm.AppInfo(Translate.T(Properties.Resources.PuttyAppName), "http://www.chiark.greenend.org.uk/~sgtatham/putty/", puttyPath, "PuttyPath");
f.SetApps(apps);
if (f.ShowDialog(this) == DialogResult.OK)
{
appTag = f.GetAppTag();
appPath = f.GetAppPath();
saveToRegistry(appTag, f.GetAppPath());
string args = null;
if (appTag == "OpenSshPath") {
SshUsernameForm f2 = new SshUsernameForm();
if (f2.ShowDialog(this) != DialogResult.OK) return;
args = "127.0.0.1 -l " + f2.Username + " -p " + mapper.localport; saveToRegistry("PuttyPath", "");
}
if (appTag == "PuttyPath") { args = "-ssh 127.0.0.1 -P " + mapper.localport; saveToRegistry("OpenSshPath", ""); }
if (args == null) return;
// Launch the process
try { proc = System.Diagnostics.Process.Start(appPath, args); } catch (Win32Exception) { }
// Setup auto-exit
if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; }
autoexit = false;
}
}
}
}
if (appId == 5)
{
string winScpPath = loadFromRegistry("WinSCPPath");
if ((shift == false) && (File.Exists(winScpPath)))
{
// Launch the process
System.Diagnostics.Process proc = null;
string args = "scp://127.0.0.1:" + mapper.localport;
try { proc = System.Diagnostics.Process.Start(winScpPath, args); }
catch (System.ComponentModel.Win32Exception) { }
// Setup auto-exit
if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; }
autoexit = false;
}
else
{
using (AppLaunchForm f = new AppLaunchForm())
{
System.Diagnostics.Process proc = null;
f.SetAppName(Translate.T(Properties.Resources.WinscpAppName));
f.SetAppLink("http://winscp.net/");
f.SetAppPath(winScpPath);
if (f.ShowDialog(this) == DialogResult.OK)
{
saveToRegistry("WinSCPPath", f.GetAppPath());
string args = "scp://127.0.0.1:" + mapper.localport;
// Launch the process
try { proc = System.Diagnostics.Process.Start(f.GetAppPath(), args); }
catch (System.ComponentModel.Win32Exception) { }
// Setup auto-exit
if ((autoexit == true) && (parent.autoExitProc == null)) { parent.autoExitProc = proc; parent.SetAutoClose(); autoExitTimer.Enabled = true; }
autoexit = false;
}
}
}
}
}
private void closeButton_Click(object sender, EventArgs e)
{
if (stats != null) { stats.Close(); stats = null; }
if (mapper != null) { mapper.stop(); mapper = null; }
parent.removeMap(this);
}
private void statsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (stats == null) {
stats = new MappingStats(this);
stats.Show(this);
} else {
stats.Focus();
}
}
public void closeStats()
{
if (stats == null) return;
stats.Close();
stats = null;
}
private void autoExitTimer_Tick(object sender, EventArgs e)
{
if (parent.autoExitProc == null) return;
if (parent.autoExitProc.HasExited == true) { Application.Exit(); }
}
}
}

983
src/MapUserControl.resx Normal file
View File

@@ -0,0 +1,983 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="devicePictureBox.Location" type="System.Drawing.Point, System.Drawing">
<value>5, 0</value>
</data>
<data name="devicePictureBox.Size" type="System.Drawing.Size, System.Drawing">
<value>50, 50</value>
</data>
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="devicePictureBox.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="&gt;&gt;devicePictureBox.Name" xml:space="preserve">
<value>devicePictureBox</value>
</data>
<data name="&gt;&gt;devicePictureBox.Type" xml:space="preserve">
<value>System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;devicePictureBox.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;devicePictureBox.ZOrder" xml:space="preserve">
<value>5</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="deviceNameLabel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data>
<data name="deviceNameLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Microsoft Sans Serif, 8.25pt, style=Bold</value>
</data>
<data name="deviceNameLabel.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="deviceNameLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>60, 10</value>
</data>
<data name="deviceNameLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>275, 15</value>
</data>
<data name="deviceNameLabel.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="deviceNameLabel.Text" xml:space="preserve">
<value>ComputerName</value>
</data>
<data name="&gt;&gt;deviceNameLabel.Name" xml:space="preserve">
<value>deviceNameLabel</value>
</data>
<data name="&gt;&gt;deviceNameLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;deviceNameLabel.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;deviceNameLabel.ZOrder" xml:space="preserve">
<value>4</value>
</data>
<data name="routingStatusLabel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data>
<data name="routingStatusLabel.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="routingStatusLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>60, 30</value>
</data>
<data name="routingStatusLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>275, 15</value>
</data>
<data name="routingStatusLabel.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="routingStatusLabel.Text" xml:space="preserve">
<value>Routing Status</value>
</data>
<data name="&gt;&gt;routingStatusLabel.Name" xml:space="preserve">
<value>routingStatusLabel</value>
</data>
<data name="&gt;&gt;routingStatusLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;routingStatusLabel.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;routingStatusLabel.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<data name="appButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
</data>
<data name="appButton.Location" type="System.Drawing.Point, System.Drawing">
<value>341, 3</value>
</data>
<data name="appButton.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
</data>
<data name="appButton.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="appButton.Text" xml:space="preserve">
<value>Open...</value>
</data>
<data name="&gt;&gt;appButton.Name" xml:space="preserve">
<value>appButton</value>
</data>
<data name="&gt;&gt;appButton.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;appButton.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;appButton.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="closeButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
</data>
<data name="closeButton.Location" type="System.Drawing.Point, System.Drawing">
<value>341, 27</value>
</data>
<data name="closeButton.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
</data>
<data name="closeButton.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="closeButton.Text" xml:space="preserve">
<value>Remove</value>
</data>
<data name="&gt;&gt;closeButton.Name" xml:space="preserve">
<value>closeButton</value>
</data>
<data name="&gt;&gt;closeButton.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;closeButton.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;closeButton.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<metadata name="deviceImageList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<data name="deviceImageList.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAy
mgAAAk1TRnQBSQFMAgEBCAEAAXABAAFwAQABMgEAATIBAAT/AREBAAj/AUIBTQE2BwABNgMAASgDAAHI
AwABlgMAAQEBAAEQBQABYAHq/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A
/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A
/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A
/wD/AAkAAf8BfwH/AX8B/wF/Af8BfwH/AX8B/wF//wB7AAH/AX8B3gF7AZwBcwFaAWsBGAFjARgBYwEY
AWMB9wFeAfcBXgH3AV4B9wFeARgBYwE5AWcBnAFzAf8BfwH/AX//AG0AAf8BfwGcAXMBOQFnATkBZwGc
AXMBewFvAXsBbwF7AW8BewFvAVoBawE5AWcBOQFnAVoBawFaAWsBWgFrARgBYwHWAVoB9wFeAZwBcwH/
AX/6AAH/AX8B/wF/aAABvQF3ATkBZwFaAWsBOQFnAVoBawFaAWsBewFvAXsBbwF7AW8BewFvAVoBawFa
AWsBOQFnAXsBbwF7AW8BOQFnAfcBXgHWAVoBGAFjAfcBXgH3AV4B3gF7+AABOAFfAbMBRgHeAXtkAAGc
AXMBOQFnARgBYwE5AWcBOQFnAVoBawFaAWsBewFvAXsBbwF7AW8BewFvAVoBawE5AWcBOQFnAXsBbwF7
AW8BGAFjAfcBXgEYAWMBGAFjAbUBVgG1AVYB1gFaAXsBbwH/AX/yAAF6AWsBiQERAYkBDQHtASUBmwFv
Af8Bf14AAd4BewEYAWMBGAFjATgBZwE5AWcBWQFrAVoBawFaAWsBewFvAXsBbwF7AW8BewFvAVoBawE5
AWcBOQFnAXsBbwFaAWsB9wFeARgBYwEYAWMB1gFaAbUBVgG1AVYBlAFSAbUBVgGcAXPwAAF7AW8B8AE5
ATABMgGqARkBiQENAakBEQHVAU4B/wF/XAABewFvAfcBXgEYAWMBOQFnATkBZwFaAWsBWgFrAXsBbwF7
AW8BewFvAXsBbwF7AW8BWgFrATkBZwE5AWcBWgFrARgBYwEYAWMBGAFjAdYBWgHWAVoBtQFWAZQBUgFz
AU4BlAFSATkBZ+4AAb0BdwEQAT4BdAFOAZQBTgFzAUoBqQEVAakBEQGJAQ0BDgEqAZwBcwH/AX9YAAFa
AWsBGAFjATkBZwFZAWsBWgFrAVoBawF6AW8BewFvAXsBbwF7AW8BewFvAXoBbwFaAWsBOQFnARgBYwEY
AWMB9wFeAfcBXgHWAVoBtQFWAZQBUgFzAU4BUgFKAVIBSgGUAVIBOQFnPgAB3gF7Ab0BdwG9AXcBvQF3
Ad4Be6QAAd4BewFRAUYBlQFSAfgBWgGUAUoBqwEZAYkBEQGqARUBiQERAc0BLQGqARUB9gFWAf8Bf1YA
AXsBbwEYAWMBWgFrAXoBbwF6AW8BWQFrATkBZwE5AWcBOQFnAXsBbwFaAWsBWgFrATkBZwEYAWMB9wFe
AfcBXgHWAVoBtQFWAZQBUgFzAU4BUgFKAVIBSgFSAUoBcwFOAZQBUgGcAXM0AAHeAXsBvQF3Ab0BdwGc
AXMBWgFrATkBZwEYAWMBGAFjAfcBXgEYAWMBewFvAb0Bd1oAAd4BewHeAXsBvQF3Ad4BezwAAf8BfwEO
AS4BigEVAYwBKQEyAUYB7AEhAYkBDQGJAQ0BpAEMAecBHAHNATUBigEVAYkBDQEvAS4BvQFzAf8Bf1IA
Ad4BewHWAVoBGAFjAfcBXgH3AV4B9wFeAfcBXgEYAWMB1gFaATkBZwFaAWsBOQFnARgBYwH3AV4B1gFa
AbUBVgGUAlIBSgExAUYB7wE9ATEBRgFSAUoBcwFOAZQBUgHWAVoB/wF/Ad4BewH/AX8oAAHeAXsBvQF3
AZwBcwF7AW8BOQFnARgBYwHWAVoBlAFSAZQBUgG1AVYBlAFSAZQBUgGUAVIBEAFCAXMBTgEYAWMBnAFz
Ad4Be0oAAd4BewG9AXcBewFvAXsBbwFaAWsBWgFrAVoBawFaAWsBewFvATkBZwFaAWsBvQF3NgAB/wF/
AVABOgGJAQ0BqgERAYkBEQGKARUBiQENAYkBEQGkAQgBpQEUAUoBJQGLAS0BaAERAQ0BJgHMAR0BygEV
ARcBWwH/AX9GAAH/AX8B3gF7AZwBcwFaAWsB9wFeAbUBWgG1AVoBtQFWAbUBVgHWAVoB9wFeAdYBWgH3
AV4B9wFeAfcBXgF6AW8B9wFeAbUBVgGTAlIBSgEQAUIBzgE5AYwBMQGMATEB7wE9ARABQgExAUYBcwFO
AbUBVgH3AV4BGAFjARgBYwE5AWcB/wF/HgAB3gF7Ab0BdwGcAXMBewFvATkBZwH3AV4BtQFWAZQBUgGU
AVIBcgFOAXMBTgGUAVIBtQFWAfQBVgGzAVIBcwFOAXMBTgGUAVIBzgE5ARABQgG1AVYBWgFrAb0Bdz4A
Ad4BewGcAXMBOQFnAdUBVgFSAUoB7wE9AYwCMQFGAVoBawFaAWsBWgFrAVoBawF7AW8BvQF3AZwBcwEY
AWMB9wFeARgBYwGcAXMwAAH/AX8BswFKAYkBDQGrARkBywEdAaoBFQGJAQ0BqQERAYkBFQHFARABCAEh
AcYBGAFrAS0BBgERAQgBIQFIAREB7QEhAaoBFQFQATYBvQF3OgAB/wF/Af8BfwG9AXcBWgFrAfcBXgGU
AlIBTgExAUoBUgFKAXMBTgGUAVIBlAFWAbUBVgHXAVYBtwFOAZcBQgF3AToBGAFjAfcBXgHWAloBawEY
AWMBUgFKARABQgHOATkBrQE1Aa0BNQHvAT0BMQFGAXMBTgG1AVYB9wFeAfcBXgH3AV4B9wFeAfcBXgH3
AV4B1gFaAb0BdxgAAd4BewG9AXcBewFvATkBZwH3AV4BtQFWAZQBUgFzAU4BlAFSAbUBVgG2AVYB9wFe
AfgBXgH4AV4B+AFeAfcBXgEsAToBYQEIAaUBFAFzAU4BlAFSAXMBTgHvAT0BzgE5AXMBTgEYAWMBnAFz
Ad4BezQAAZwBcwH3AV4BUgFKAc4BOQFrAS0BKQElAQgBIQHnARwBxgEYAYQBEAHvAT0BOQFnARgBYwH3
AV4B9wFeAfcBXgF8AW8BewFvAfYBXgH3AV4B9gFeAbUBVgH3AV4BnAFzKgAB/wF/AfYBVgGJAQ0BiQEN
AasBGQGqARUBzAEdAe0BKQGqARUBiQENAe0BLQH4AWIB7wE9AWMBDAGDAQwBhAEQAaUBFAGsAS0BqgEZ
AakBHQGrARkBOAFfAf8Bfy4AAf8BfwG9AXcBewFvARgBYwG1AVYBcwJSAUoBMQFGATEBRgExAUYBUgFK
AXMBTgGVAUoBlgFGAXcBPgF4ATYBNwEqAfYBIQH2ASEB9QEhAfUBIQH5AVIBGAFjAbUBVgEYAWcBGAFj
AfcBXgFzAU4BUgFKAXMBTgG1AVYBtQFWAbUBVgG1AVYBtQFaAdYBWgHWAVoB9wFeAfcBXgH3AV4B9wFe
AdYBWgE5AWcQAAHeAXsBvQF3AZwBcwFaAWsBGAFjAdYBWgGUAVIBkwFSAXMBTgG1AVYB1gFaARkBYwFa
AWsBWwFrAVsBawFbAWsBOgFnARgBYwH4AV4BlQFWAUcBLgFAAQABIgEEATIBRgFSAUoBcwFOAVIBSgEx
AUYBzgE5ARABQgHWAloBawG9AXcsAAGcAW8B1gFaARABQgFrAS0BCAEhAecBHAHGARgBxgEYASkBIQGl
ARQB5wEYAQoBIgEhAQQBawEtAZQBUgExAUYBMQFGATEBRgExAUYB1gFaAbUBVgEwAUYBcwFOAbUBVgHW
AVoB1QFaAZQBUgH3AV4BvQF3JgABOQFjAYkBDQGJAQ0BiQENAYkBDQGJAQ0BzAEhAYkBEQGJAQ0BiQIN
ASYBtQFWAZQBUgGUAVIBhQEUAYQBEAGEARABJwENAYkBIQGJARkBigEdAaoBEQFxAToB3gF3JAAB3QJ7
AXMBGAFnAbUBVgFzAU4BcwFSAXMBUgFzAVIBcwFOAXMBTgGUAVIBdQFGAXYBQgF3AToBVwEyATcBKgEX
ASIBFwEiARgBIgEXASIBFwEiARcBIgEWASIBFgEiAfYBIQH4AVYBGAFjAbUBVgE5AWcBGAFjAfcBYgH3
AV4BlAFSAXMBTgGUAVIBtQFWAbUBVgG1AVYB1gFaAfcBXgH4AV4BmAFOATkBQgG5AVIBGAFjAfcBXgH3
AV4OAAHeAnsBbwEYAWMB1gFaAbUBVgGUAVIBtQFWAdYBWgE5AWcBfAFvAZ0BcwG+AXcBngFzAZ0BcwF8
AW8BWwFrAToBZwE5AWcBGQFjAfgBYgGVAVIB7AFCAUABBAEhAQQBMQFGAVIBSgFSAUoBEAFCAVIBSgFS
AUoB7wE9Ac4BOQFzAU4BGAFjAZwBcwHeAXsiAAGcAXMB1gFaAe8BPQFJASkB5wEcAcYBGAGlARQBhAEQ
ASgBHQGpAR0BIgEIAesBJQHDAQwBQgEEAeYBEAIAAQgBJQFSAUoBMQFGATEBRgExAUYBMQFGARgBYwG1
AVYBzgE5Ae8BPQEQAUIBcwFOAdYBWgH3AV4BtQFWAZQBUgE5AWciAAF7AW8BiQERAYkBDQGJAQ0BiQEN
AYkBDQGJAQ0BaQEVAWMBCAGkAQgBiQENAYkCDQEmATABMgFJARkBhQEUAYQBEAEGAREBTwE6AaoBGQFo
AQ0B5gEQAYoBGQGJARUBywEZAVkBZwH/AX8gAAFSAU4BMQFKAVABQgEvAUIBcwFOAbUBUgG2AU4BlwFC
AXcBOgFYATIBFwEiARcBJgEXASYBOAEmATgBJgE4ASYBOAEmATgBJgE4ASIBOAEiARcBJgEXASYBFwEi
ARcBIgEWASIB2QFKATkBZwGUAVYBOAFnARcBYwHWAVoB1gFaAdYBXgG1AVYBtQFWAdcBWgF3AUoB9wE5
AZgBLQEXARUBdQEEAVUBAAFVAQAB1wE1ARgBYwEYAWMB1gFaAf8BfwwAAXsBbwH3AV4B1gFaAdYBWgH3
AV4BOgFnAXwBbwG+AXcBvwF3Ab4BdwG+AXcBngFzAZ0BcwGdAXMBfAFvAVsBawFbAWsBOgFnARkBYwEZ
AWMBlAFSAe8BRgEHAR0BhAEQAVIBSgGUAVIBlAFSATEBRgExAUYBMQFGAVIBSgExAUYBzgE5ARABQgG1
AVYBWgFrAb0BdxoAAb0BdwF7AW8BGAFjAUoBKQGlARQBhAEQAcYBFAGlARABIQEEASEBBAIAAaQBDAEG
ARUKAAEBAQABKgElAVIBSgFSAUoBUgFKAVIBSgFzAU4BWgFrAZQBUgHNATkB7wE9ARABQgHvAUEBMQFG
AZQBUgG1AVYB1gFaAXMBTgHWAVoBvQF3HAABvQFzAaoBEQGJAQ0BiQENAYkBDQGJAQ0BiQENAYoBHQGE
AQgBZAEMAWQBDAFoAQ0BiQENAYkBDQGJAQ0BiAENAUgBDQEGAREBRAE1AQcBXgGpAR0BiQEVAYsBJQGq
ARUBaAERAWoBHQHNAS0BEAFCAd4Bex4AAZQBVgGVAUoBdgE+AXcBOgE3AS4BFgEmAfYBIQEWASIBFwEi
ARgBIgE4ASIBOAEmATgBJgE4ASYBOAEmATgBJgE4ASYBOAEmATgBJgE4ASIBOAEiATgBJgEYASYBGAEm
ARcBJgG4AUYBOQFnAZQBUgE4AWcBGAFjAfcBXgG3AVYBVwFKATgBQgF4ASUBlQEIAVUBAAFUAQABVAEA
AVQBAAFUAQABVAEAAVQBAAGXASkBGAFjARgBYwGUAVIB/wF/CgAB3gF7AfcBXgHWAVoBOQFnAVsBawF8
AW8BnQFzAZ0BcwGeAXMBvgF3Ab4BdwG+AXcBvgF3AZ0BcwGdAXMBfAFvAVwBawFbAWsBOgFnARkBYwEZ
AWMBtQFWAS0BOgGMATEB8AE9AVIBSgEYAWMB9wFeAbUBVgFzAU4BMQFGATEBRgFSAUoBUgFKARABQgHO
ATkBcwFOARgBYwGcAXMB3gF7FAABewFvATkBZwFaAWsBlAFSAYQBEAEmARUBQQEEAYkBHQFmARUKAAEi
AQQBZAEMAacBEAEKARkBKwEdAU0BIQGvATEB1gFaAfcBXgEYAWMBGAFjATkBZwF7AW8B9wFeAVIBSgEQ
AUIB7wE9ARABQgEwAUYBEAFCAe8BPQG1AVYBFwFjAZQBUgGUAVIBWgFrGAAB3gF7AasBGQGJAQ0BRwEV
AUcBKQGJAQ0BiQENAYoBGQGlAQwBZAEMAUIBCAEGAQ0BiAENAYgBDQGIAQ0BygElAeoBPQHrATUBiQER
AYUBNQGmATEBiQERAYkBEQEnAREBiQERAWgBEQFKASEBlAFOATIBRgEpASEBOQFnAf8BfxoAARgBYwF3
AToB9QEhAfUBIQH1ASEB9gEhARYBIgEWASIBFwEiARgBIgE4ASIBOAEiATgBJgE4ASYBOAEmATgBJgE4
ASYBOAEmATgBJgE4ASYBOAEmATgBJgE4ASYBOAEmATgBJgGZAToBOQFnAbUBVgH4AV4BuQFSATcBQgHW
ATUBlgEtAVYBJQE2ASEB1QEQAXQBBAF0AQQBdAEEAXQBBAF0AQQBdAEEAXUBBAFXASEBGAFjATkBZwGU
AVIB3gF7CgABnAFzAdYBWgE5AWcBWwFrAVsBawF8AW8BfAFvAZ0BcwGdAXMBvgF3Ab4BdwG+AXcBvgF3
AZ4BcwGdAXMBfAFvAXwBbwFbAWsBOgFnARkBYwEZAWMB9wFeAbIBTgGUAVIBcwFOAXMBTgG8AXcBWgFr
ATkBZwH3AV4BlAJSAUoBMQFGATEBRgFzAU4BMQFGAe8BPQEQAUIB1gJaAWsBvQF3EAABewFvAfcBXgE5
AWcBOQFnAe8BPQFkAQgB6wElAUABBAYAASIBBAGFAQwB6QEYASwBIQFuASUBjwEtAa8BMQHPATEB8AE5
ATEBQgF0AU4BOQFnATkBZwEYAWMBGAFjAfgBXgH3AV4BGAFjATkBZwEYAWMB1gFaAVIBSgEQAUIBMQFG
Ae8BPQEQAUIBUgFKAbUBVgHWAVoBcwFOARgBYwHeAXsSAAH/AXsB7AElAYkBDQGJAQ0BaAENAWgBDQGJ
AQ0BigEdAaUBDAFkAQwBQgEIAeUBCAGIAQ0BiAENAYgBDQGJAQ0BCwFSAWEBGAFnAT0BygEhAWgBDQFo
AQ0BBwEVAUkBGQFoARUBagEhAYsBJQGUAU4BdAFKAe4BRQHvAUEBKQElAVIBSgHeAXsYAAFaAWsBlwFC
AfUBIQH1ASEB9QEhAfYBIQEWASIBFgEiARcBIgEXASIBGAEiATgBIgE4ASIBOAEiATgBIgE4ASYBOAEm
ATgBJgE4ASYBOAEmATgBJgE4ASYBOAEmATgBJgE4ASYBeAE2AVoBawHWAVoBtwFWAZkBUgE3AUIB1gE1
AZYBLQF1ASUBNQEhARUBGQG1AQwBlQEEAXUBBAF1AQQBlQEEAZUBBAGVAQQB9wEUATkBZwE5AWcBlAFS
Ab0BdwoAAXsBbwHWAVoBOgFnAToBawFbAWsBewFvAXwBbwGdAXMBnQFzAb4BdwG+AXcBvgF3Ab4BdwGe
AXMBnQFzAZ0BbwF8AW8BfAFvAVsBawFbAWsBGQFjAdYBWgGUAVIBcwFOAXMBTgFaAWsBvQF3AZwBcwF7
AW8BWgFrARgBYwHWAVoBlAJSAUoBMQFGAVIBSgFSAUoBEAFCAe8BPQFzAU4BGAFjAZwBcw4AATkBZwFz
AU4BcwFOAXMBTgGtATUGAAFDAQgBpwEQASsBHQFuASUBjwEtAdABNQERAT4BUgFGAZQBUgHWAVoBGAFj
ATkBZwE5AWcBOQFnARgBYwEYAWMBGAFjARgBYwEYAWMB9wFeAfcBXgH3AV4B9wFeARgBYwE5AWcB9wFe
AZQBUgEPAUIBMQFGARABQgEQAUIBtQFWAdYBWgGUAVIB9wFeAb0Bdw4AAf8BfwEvATIBiQENAYkBEQHu
AS0BqgEVAYgBDQGKARkBpQEMAWMBDAFCAQgBxQEIAYgBDQGIAQ0BiAENAYgBDQGIAQ0B6wE1AckBQQHr
AT0BiAENAWgBDQFoAQ0BigEZAWkBFQFJARkBzQExAVMBSgF0AU4BSQE1AQUBMQEFATUBrAFBAe8BOQHO
ATkBmwFvAf8BfxQAAXsBbwG4AUYB9QEhAfUBIQH2ASEBFgEiARYBIgEWASIBFwEiARcBIgEYASIBGAEi
ARgBIgE4ASIBOAEiATgBJgE4ASYBOAEmATkBJgE5ASYBWQEmAVkBJgFaASYBWgEmAVoBJgFZASoBWgFr
AfcBXgG3AVYBmQFSAVcBRgH2ATkBtgExAXYBKQFVASEBNgEdAfYBGAG1AQwBlQEIAZUBCAGVAQgBlgEI
AZYBCAHWAQwBGQFjATkBZwG1AVYBnAFzCgABOQFnAfcBXgE6AWcBOgFnAVsBawFbAWsBfAFvAZ0BcwGd
AXMBngFzAb4BdwG+AXcBvgF3Ab4BdwG+AXcBnQFzAVsBawEYAWMBtQFWAVIBSgExAUYBUgFKAbUBVgH3
AV4BOQFnATkBZwE5AWcBewFvAb0BdwGcAXMBewFvAVoBawEYAWMBtQFWAXMBTgFSAUoBUgFKAXMBTgFS
AUoB7wE9ARABQgHWAVoBewFvAd4BewoAAdYBWgHvAT0BMQFGAXMBTgHvAT0BYwEIAcgBFAEsASEBjwEp
Aa8BMQHwATkBUgFGAbUBVgEYAWMBWgFrAVsBawFbAWsBWgFrAVoBawFaAWcBOQFnATkBZwE5AWcBOQFn
ATkBZwEYAWMBGAFjARgBYwEYAV8B9wFeAfcBXgH3AV4B9wFeAfcBXgE5AWcBFwFjAZQBUgExAUYBEAFC
ARABQgGUAVIB1gFaAZQBUgH3AV4BvQF3CgAB/wF/AXEBPgGJAQ0BiAENAaoBFQGJAREBzAEhAYkBEQGl
AQwBYwEMAUIBCAHEAQgBaAENAWgBDQGJAREBaAENAWgBDQFoAQ0BaAENAWgBDQFoAQ0BaAENAaoBGQFo
AQ0BigEZAasBIQGrAR0BzwE1AZUBUgGKAT0BBQExAQUBNQEFATEBBQExAWkBOQFSAUYBDgEqAdQBTgH+
AXsSAAG9AXcB2AFSAfUBIQH2ASEBFgEiARYBIgEWASYBFgEiARYBIgEXASIBFwEiARcBIgEYASIBFwEm
ARcBJgE4ASYBWQEmAVoBJgFaASYBWgEmAVoBJgFbASIBWwEiAVwBIgFcASIBWQEqAVoBZwH3AV4BtgFW
AbkBUgFYAUYB9wE5AdYBMQGWASkBVgElATYBIQEWAR0B9gEUAbYBDAG2AQgBtgEMAbYBDAG2AQwBtgEI
AfkBXgE5AWcBtQFWAXsBbwoAATgBZwH4AV4BOgFnAToBZwFaAWsBWwFrAXwBbwGdAXMBvgF3Ab8BdwG+
AXcBnQFzAVsBawEYAWMBtQFSAXMBTgFzAU4BcwFOAbUBVgHWAVoBGAFjATkBZwE5AWcBGAFjAfcBXgH3
AV4BGAFjARgBYwE5AWcBewFvAb0BdwGcAXMBewFvATkBZwH3AV4BtQFWAXMBTgFSAUoBUgFKAXMBTgEx
AUYB7wE9AZQBUgE5AWcBvQF3CAAB9wFeATEBRgExAUYBcwFOAbUBVgESAT4BrwEtAfABOQFzAU4B9wFe
AVoBawF7AW8BewFvAXsBawFbAWsBWwFrAVoBawFaAWsBWgFrAVoBawFaAWsBWgFrAToBZwE5AWcBOQFn
ATkBZwEYAWMBGAFjARgBYwH4AV4B9wFeAfcBXgH3AV4B9wFeAdYBWgH3AV4BOQFnAfcBXgFzAU4BEAFC
Ae8BQQFSAUoB1gFeAbUBVgH3AV4BvQF3BgAB/wF/AdQBTgGIAQ0BiQENAaoBFQGrARkBqgEVAYkBDQHE
AQgBQwEIAUMBCAGkAQgBaAENAWgBDQFoAQ0BigEVAYkBDQGJAQ0BaAENAWgBDQFoAQ0BaAENAYoBFQFo
ARkBaAENAWgBDQGJAREBigEZASgBGQHvATkBqwE9AQUBNQEFATUB5AEwAQUBMQHOATkBEAE2AQYBDQFj
AQgBqwElAZwBcwH/AX8OAAHeAXsB+AFaAfUBIQEWASYBFgEmARYBJgEWASYBFgEiARYBIgEWASIBFwEi
ARcBIgEXASIBFwEiARcBJgE4ASYBWgEmAVsBIgFbASIBXAEiAVwBIgF9ASIBfQEiAX0BIgF+ASIBWgEi
AVsBYwEYAWMBlQFSAbkBVgFYAUoBFwE+AdcBNQGWAS0BdgEpAVYBIQE2AR0BFgEZAdYBEAHWAQwB1gEM
AdYBDAHWAQwBtgEIAbkBVgE5AWcB1gFaATkBZwoAARgBYwH3AV4BWwFrAVoBawFbAWsBWwFrAVoBawEZ
AWMB9wFeAbUBVgGUAVIBcwFOAXMBTgG1AVYB9wFeATkBZwFaAW8BewFvAVoBawFaAWsBOQFnARgBZwEY
AWMBGAFjAfcBXgH3AV4BFwFjAfcBXgH3AV4BGAFjATkBZwGcAXMBvQF3AZwBcwFaAWsBOQFnAfcBXgGU
AlIBSgFSAUoBcwFOAVIBSgEQAUIB1gJaAWsBvQF3BgABGAFjAXMBTgH3AV4BWgFrAXsBbwFaAWsBGAFj
AVoBawF8AW8BfAFvAXsBbwF7AW8BewFvAXsBbwF7AW8BewFvAXsBbwF7AWsBWwFrAVsBawFaAWsBWgFr
AVoBawE6AWcBOQFnATkBZwE5AWcBGAFjARgBYwEYAWMBGAFjARgBYwH3AV4B1gFaAdcBWgHWAVoB1gFa
ARgBYwE5AWcBtQFWAVIBSgHvAT0BUgFKAbUBVgHWAVoBOQFnAd4BewQAARcBWwGIAQ0BiQERAYkBDQGJ
ARUBqgEZAWgBDQFoAQ0BhAEIAUMBCAGkAQgBaAENAWgBDQGIAQ0BqgEVAaoBGQGrAR0BiQEVAWgBDQFo
AQ0BaAENAYoBFQEIASEBSQEdAYoBFQFoAQ0BaAENAWgBDQFIAQ0B5gEQAa0BMQEQAUYBRwE5AUgBOQEx
AUIB7wExAeYBFAFCAQQBYwEMAcUBFAGJAREB9QFSAf8BfwwAAf8BfwH3AV4BFgEiARYBIgEXASIBFwEi
ARYBIgH1ASEB9QEhAfYBIQEWASIBFgEiARcBIgEXASIBFwEmATkBJgFcASIBfAEiAX0BIgF9ASIBfgEi
AX4BIgF+ASIBngEiAZ4BIgFcASIBOgFfATkBZwGVAVIB2gFWAXgBSgE3AUIB9wE5AbcBMQGXASkBdwEl
AVcBIQE3ARkB9wEUAdcBEAHXARAB1wEQAdcBEAG3AQwBeQFKATkBZwH3AV4B9wFeCgABWgFrAVIBSgHW
AVoBtQFWAbUBVgG1AVYBlAFSAZQBUgHWAVoBGAFjAVkBawGbAXMBvQF3AbwBdwGcAXMBewFvAVoBawFa
AWsBWgFrAVsBawF7AWsBfAFvAXwBbwF8AWsBWwFnATkBYwEYAV8B+AFeAfcBXgHXAVoB1wFeAfcBXgE5
AWcBnAFzAZwBcwF7AW8BWgFrARgBYwHWAVoBlAFSAXMBTgGUAVIBlAFSAdYBWgF7AW8BvQF3BgABvQF3
AZwBcwF7AW8BWgFrAVsBawF7AW8BfAFvAXwBbwF8AW8BfAFvAXwBbwF8AW8BfAFvAXwBbwF8AW8BfAFv
AXsBbwF7AW8BewFvAVsBawFbAWsBWgFrAVoBawFaAWsBWgFrAToBZwE6AWcBGQFjAfcBXgHWAVoBtQFW
AXMBTgFSAUoBlAFSAdYBWgHWAVoB1gFaAdYBWgH3AV4BOQFnARgBYwFzAU4B7wE9ATEBRgHWAVoB9wFe
AXsBbwIAAVoBZwHlAQwBpAEIAUcBEQGIARkBaAEdAWcBGQFoAQ0BaAENAaUBDAGlAQgBaAENAWgBDQFo
AQ0BaAENAWgBDQFoAQ0BigEVAWgBDQFoAQ0BaAENAYoBFQEIAR0BKwEpASoBJQHoARwBaQEZAWkBEQFo
AQ0BaAENAWgBDQEnAQ0BigEZAc4BMQEQAT4BrAEpAaUBDAEiAQQBQgEIAWMBDAEnAREBaQEVAYoBFQEO
ASoBnAFzAf8BfwgAAf8BfwH3AV4BVwEyARcBJgEXASYBFwEmAfYBIQH1ASEB9QEhAfUBIQEWASIBFgEi
ARYBJgEWASYBFwEmAVsBIgF9ASIBfgEiAX4BIgF+ASIBngEiAZ4BIgGfASIBnwEmAb8BJgF9ASIBGwFT
AVoBawGUAVIB2QFWAXkBTgE4AUIBFwE6AdcBMQGXAS0BdwEpAXcBJQE3AR0BFwEZAfcBFAH3ARQB9wEU
AfcBFAHXARABWQFCATkBZwEYAWMBtQFWCgAB3gF7AVoBawE5AWsBewFvAZwBcwGcAXMBvQF7Ad4BfwHe
AX8B3gF7Ad4BewG9AXcBnAFzAVoBawE5AWcBOgFnAVsBawF8AWsBnAFvAZ0BbwGdAXMBnQFzAZ0BcwGc
AW8BewFrAVoBZwE6AWMBGQFjAfgBXgHXAVoBtgFWAZQBUgGUAU4BtQFWATkBZwGcAXMBnAFzAXsBbwFa
AWsBGAFjAbUBVgGUAVIB1gFaAfcBXgG9AXcB3gF7CgABvQF3AZwBcwF8AW8BfAFvAZwBcwGcAXMBnAFz
AZwBcwGcAXMBnAFzAZwBcwGcAXMBnAFvAXwBbwF8AW8BfAFvAXwBbwF7AW8BewFvAXsBbwFaAWsBGAFj
AfcBXgHWAVoBcwFOAXQBTgGUAVIBdAFOAXMBTgGUAVIBlAJSAUoBcwFOAZQBUgHWAVoB1gFaAdYBWgHW
AVoBGAFjATkBZwG1AVYBEAFCAVIBSgH3AV4BewFvAgABDwE2AaQBFAHGARwBhAEMAcUBEAFHARUBaAEV
AWcBHQFHARUBaAENAUcBDQFQATYBzAEdAWgBDQFoAQ0BaAENAWgBDQFoAQ0BaAENAWgBDQGKARUB5wEY
AcgBHAHHARwBxwEcAaYBGAGlARQBBwEZAYoBFQFoAQ0BigEVAYoBFQFoAQ0BaAENAWoBHQGEAQwBIgEE
AUIBCAFjAQwB5gEQAUkBFQEqASUBcwFGAc0BKQGrASkBFwFbAf8BfwgAARgBZwF4ATYBFwEiATgBJgE3
ASYB9QEhAfQBIQH1ASEB9QEhAfUBIQEWASIBFgEiARYBJgE4ASYBfAEiAZ4BIgGeASIBngEiAZ8BIgGf
ASYBvwEmAb8BJgG/ASoBvwEqAb4BJgH6AU4BewFvAZQBUgHZAVoBmQFOAVgBRgEYAT4B1wE1AbcBLQGX
ASkBdwElAVcBIQE3ARkBFwEVARcBFQEXARUBGAEVAfcBEAEZAToBWgFrATkBZwGUAVIB/wF/DAAB3gF7
Ad0BewG9AXcBewFvAXsBbwHeAXsB3gF7Ad4BewG9AXsBnAFzATkBZwFaAWcBfAFvAZ0BcwG9AXcBvQF3
AZwBcwGcAXMBewFzAXsBbwF7AW8BWgFrAVoBawFaAWsBWgFrAVoBawE5AWcBOQFnATkBZwEYAWMB1gFa
AXQBTgEyAUYBlAFSAVoBawGcAXMBnAFzAXsBbwE5AWcBGAFjAfcBXgE5AWcSAAHeAXsBvQF3AZ0BcwGd
AXMBnQFzAZ0BcwGdAXMBnQFzAZwBcwGcAXMBnAFzAZwBcwGcAXMBewFrATkBZwEYAWMB1gFaAbUBVgG2
AVoBlQFSAZQBUgG1AVYBtQFWAZQBUgGUAVIBtQFWAXMBTgFzAU4BlAFSAZQBUgFzAU4BlAFSAZQBUgG1
AVYB1gFaAdYBWgHWAVoB9wFeATkBZwHWAVoBcwFOAVoBawG9AXcCAAH/AX8BzQE9AWkBMQHGARwBpQEU
AYMBDAHlARABRwEVAWgBGQFoAREBhAEQAecBHAHNAS0BDgEqAWgBDQFoAQ0BaAENAWgBDQFoAQ0BigEV
AcYBFAGEARABZAEQAWQBEAFjARABYwEMAUMBDAGlAQwBaAENAYoBGQGJARUBaAENAWgBDQFJARkBYwEI
ASIBBAFCAQgBYwEMAcUBEAEpARkBKgElASoBJQERAT4BtgFSAZQBSgGrAR0BLwEyAb0BdwYAAVoBawG4
AUIBFwEmATgBJgEWASYB9QEhAfUBIQH0ASEB9QEhAfUBIQEWASIBFgEiARcBIgE5ASYBngEiAZ8BJgG/
ASYBvwEmAb8BJgG/ASoBvwEqAb8BKgHfAS4B3wEuAb8BKgHbAUIBewFvAZQBVgHYAVYBmQFOAVgBSgE4
AUIB9wE5AbcBMQGXAS0BlwEpAXgBJQE4AR0BGAEZARgBGQEYARkBGAEZARgBFQG5AS0BWgFrATkBZwFz
AU4B3gF7EAAB3gF7Ab0BewG9AXcBvQF3Ad0BewHeAXsB3gF7Ab0BdwG9AXcB/wF/Af8BfwHeAXsB3gF7
Ad4BewG9AXcBvQF3Ab0BdwGcAXMBnAFzAZwBcwF7AW8BewFvAXsBbwFaAWsBWgFrAVoBawFaAWsBWQFr
AVkBawE5AWcB9wFeAXMBTgHWAVoBOQFnAXsBbwGcAXMBnAFzAXsBbwE5AWcBWgFrFgAB3gF7Ab4BdwG9
AXMBnQFzAZ0BcwGdAXMBnQFzAZwBcwGcAXMB+AFeAZQBUgHWAVoBtQFWAZQBUgHXAV4B9wFeAbUBVgG2
AVYB9wFeAZQBUgFzAU4B1gFaAbUBVgFzAU4BtQFWAbUBVgFzAU4BcwFOAbUBVgGUAlIBSgFzAU4BcwFO
AZQBUgG1AVYB1gFaAdYBWgEYAWMBOQFnAd4BewQAAf8BfwFZAWsBkwFWAc0BPQEnASUBxgEcAYQBFAGE
AQwBBgENAWgBDQFrASkBpQEYAcYBGAFoAQ0BaAENAWgBDQFoAQ0BaAENAWgBDQFoAQ0BBgENAWMBDAFD
AQwBQwEMAUMBDAFDAQwBpQEMAWkBGQFoAQ0BaAERAScBFQEnASUBJwEJAUIBBAEhAQQBIQEEAWMBDAHF
ARABSQEdASoBJQEqASUBKgElAa4BMQG2AVIBtgFSAbYBUgEQATIBigEVATkBYwQAAXsBbwHZAU4BFgEm
ATgBJgH1ASEB9QEhAfUBIQH0ASEB9QEhAfUBIQEWASIBFgEmARcBJgFbASYBvwEmAb8BKgG/ASoBvwEq
Ab8BKgHfAS4B3wEuAd8BMgH/ATYB/wE2Af8BMgG6AToBewFvAbUBVgG4AVYBuQFSAXkBSgE4AUIB+AE5
AdcBNQG3ATEBmAEtAXgBKQFYASEBOAEdATgBHQE4AR0BOAEdARgBGQF5ASUBWgFrAVoBawFzAU4BvQF3
FgAB3gF7Ab0BdwG9AXcBvQF3Ad4BewH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwHeAXsB3gF7Ad4BewHe
AXcBvQF3Ab0BdwG9AXcBnAFzAZwBcwF7AXMBewFvAXsBbwF7AW8BWgFrAVoBawFaAWsBWgFrARgBYwEY
AWMBGAFjARgBYwE5AWcBewFvAb0BdwF7AW8BnAFzHAAB3gF7Ab0BdwGdAXMBnQFzAZ0BcwGcAXMBWwFr
AVoBawHXAVoBtQFWAdYBWgG1AVYBtQFWAdYBWgG1AVYBlAFSAdYBWgG1AVYBlAFSAZQBUgG1AVYBcwFO
AXMBTgGUAVIBcwFOAVIBSgFzAU4BcwFOATEBRgFSAUoBcwFOAXMBTgHWAVoB1gFaARgBYwG9AXcIAAH/
AX8BvQF3ATgBZwFxAU4BiwE1AQcBJQHGARwBhAEQAaQBCAFHAREBiQEZAScBDQFmATEBTwFGAWgBDQFo
AQ0BaAENAWgBDQFoAQ0BaAENAYoBGQHFAQwBYwEMAUMBDAGlAQwBaAERAWgBEQFoAREBaAENAWkBFQFH
AQ0B5QEIASEBBAEhAQQBYwEMAcUBEAFKAR0BKgElASoBJQEqASUBKgElAa4BMQF0AUoBtgFSAbYBUgG2
AVIBcwFGAZwBbwQAAZwBcwH6AVIBFgEiATcBJgH1ASEB9QEhAfUBIQH1ASEB9QEhAfUBIQH2ASEBFgEi
ARcBJgF8ASYB3wEuAd8BLgHfAS4B3wEyAd8BMgHfATYB/wE2Af8BOgH/AToBHwE/Af8BPgGbATIBfAFz
AdYBWgG3AVYBugFSAZkBTgFYAUYBGAE+AdgBNQHYATEBuAEtAZgBKQF4ASUBWAEhATgBHQE4AR0BOAEd
ATgBHQE4AR0BWgFrAVoBawGUAVIBnAFzHAAB3gF7Ab0BdwG9AXcBvQF7Ad4BewH/AX8B/wF/Af8BfwH/
AX8B/wF/Af8BfwH/AX8B3gF7Ad4BewHeAXsB3gF7Ab0BdwG9AXcBnAFzAZwBcwGcAXMBewFvAXsBbwFa
AWsBWgFrATkBZwE5AWcBGAFjARgBYwH3AWIBGAFjATkBZwF7AW8kAAHeAXcBvQF3AZ0BcwGdAXMBnAFz
AVoBawFbAWsBOQFnAdYBWgG1AVYBtQFWAdYBWgGUAVIBlQFSAdYBWgGUAlIBSgFzAU4BcwFOATEBSgFS
AUoBcwFOAVIBSgFzAU4BtQFWAdYBWgH3AWIBWgFrAXsBbwGcAXMBvQF3Ad4BewwAAf8BfwH/AX8BnAFz
AfYBYgEwAUoBaQExAQcBIQHFARgBhAEQAcQBCAFHAREBhAFJAaUBQQFJASUBqwEdAWgBDQFoAQ0BaAEN
AasBIQHMATkBqwE5AScBDQHlAQwBqgEpAWgBEQFoAREBaAEhAYkBKQGJAR0BigElAQYBDQEhAQQBgwEI
ASYBDQFIAREBKgElASoBJQEqASUBKgEhAUsBJQFTAUYBVAFKAXQBSgGVAU4BlQFSAbYBUgH4AV4EAAG9
AXcBOQFjAfYBIQH2ASEB1QEdAfQBIQH1ASEB9QEhAfUBIQH1ASEB9QEhARYBIgE4ASYBngEmAd8BNgH/
ATYB/wE2Af8BOgH/AToB/wE6Af8BPgEfAT8BHwFDAR8BQwEfAUMBnAEyAZwBcwEYAWMBtgFWAboBVgGZ
AU4BWAFGARgBPgH4ATkB2AE1AbgBMQG4AS0BmAEpAVgBIQFYASEBWQEhAVkBIQFYASEBGAEVAToBZwFa
AWsBtQFWAVoBayIAAd4BewG9AXcBvQF3Ab0BdwHeAXsB3gF7Ad4BfwHeAXsBvQF3Ab0BewG9AXcBnAFz
AZwBcwG9AXcBvQF3AZwBcwGcAXMBmwFzAXsBbwFaAWsBOQFnATkBZwE5AWcBOQFnATkBZwFaAWsBewFv
AZwBcwHeAXssAAHeAXcBvQF3AZ0BcwGcAXMBewFvAXwBbwE5AWcBtQFWAbYBVgG2AVYBcwFOATEBRgFz
AU4BcwFOAVIBSgGUAVIB1gFaARgBYwE5AWcBewFvAZwBcwG9AXceAAH/AX8B3gF7AXoBbwH1AV4BLwFG
AUkBLQHmARwBpQEYAYQBDAHkARQBRwERAScBDQGKATEBzAExAWgBDQFoAQ0BigEdAawBPQFoAQ0BSAEN
AWkBFQFIAQ0BaAERAUcBHQFoAR0BaAEZAYoBGQGKAR0BaQEdAeUBCAFIAQ0BSAENAUgBDQEqASUBKgEl
AUsBJQGuATEBVAFGAVQBSgFUAUoBVAFKAXQBSgF0AUoBtgFSAbYBUgHfAXsCAAHeAXsBOgFnARYBJgHV
AR0B1QEdAdUBHQH1ASEB9QEhAfQBIQH1ASEB9QEhARYBIgE5ASYB3wEyAf8BOgH/AT4BHwE/AR8BPwEf
AT8BHwFDAR8BQwEeAUcBHgFHAR0BSwEdAUsBnAEuAZ0BcwE5AWcBlQFSAdoBVgGZAVIBWAFKATgBQgH4
ATkB2AE1AdgBMQG4ATEBmAEpAXkBJQF5ASUBeQEhAXkBJQFZASEBGAEZARsBYwFaAWsB1gFaATkBZygA
Ad4BewG9AXcBvAF3Ab0BdwGcAXcB9gFeAe8BPQGtATUBzgE5ATEBRgE5AWcBnAFzAZsBcwF7AW8BegFv
AVoBawF7AW8BewFzAZwBcwG9AXcB3gF7PAAB3gF7Ab0BdwF7AW8BWgFrAVoBZwH3AV4BlAFSAdYBWgEY
AWMBOQFnAXsBbwG9AXcB3gF7Ad4BeywAAf8BfwHeAXsBWQFrAbQBWgHtAT0BKAEpAeYBHAGlARQBpAEM
AWgBDQGqASEBaAENAUcBEQFHASEBiAEVAWgBDQFIAQkBSAEJAWkBGQFoAREBZwEdAWgBGQFIARkBaAEN
AWoBJQErASkBagElAYkBFQFpAR0BaQEVAUcBDQEqASEBKgEhAY0BLQFUAUoBVAFKAVQBSgFUAUoBVAFK
AVQBSgFUAUoBdAFKAbYBUgGcAW8CAAH/AX8BOQFnATYBKgHVAR0B1QEdAdUBHQH1ASEB9QEhAfQBIQH1
ASEB9QEhARYBIgFbASYB/wE6AR8BQwEfAUMBHwFDAR8BQwEfAUMBHgFHAR4BRwEdAUsBHQFPARwBUwEc
AVMBvAE2AZ0BawFaAWsBlQFSAboBVgGZAVIBWAFKATgBQgEYAToB+AE1AdgBNQHYATEBuQEtAZkBKQF5
ASUBeQElAXkBJQF5ASUBOAEZAfsCWgFrAfcBXgHWAVouAAHeAXsBvQF3Ab0BdwF7AW8BewFvAZwBcwGc
AXMBnAFzAb0BdwG9AXcB3gF7Ad4Be04AAd4BewG9AXcBnAFzAd4Bez4AAf8BfwG9AXcBOAFnAXIBUgGr
ATUBJwElAUgBGQFIAQ0BSAENAWgBEQFGAR0B5AFNAWIBNQFoARUBaAEVAUcBCQFoARUBRwEdAWcBHQFo
ARUBaAENAUkBIQGmARgBpgEYAaYBFAHGARgBaAEVAUcBCQFHAQkBSgEdAa4BMQFUAUoBVAFKAVQBSgFU
AUoBVAFKAVQBSgFUAUoBVAFKAVQBSgF0AUoB+AFeBAABOQFnAVcBNgHUAR0B1QEdAdUBHQHVAR0B9QEh
AfUBIQH1ASEB9QEhARYBJgGdASoBHwFDAR4BRwEeAUcBHgFHAR8BRwEeAUMBHgFDAR4BQwH+AT4B3QE6
AbwBNgGcATIBegEqAX0BZwGcAXMBlAFSAboBUgGZAU4BWQFKATgBQgEYAT4B+AE5AfgBNQHZATUBuQEx
AZkBKQGZASkBmQEpAZkBKQGZASUBWAEdAboBUgF7AW8BGAFjAbUBVgH/AX/cAAH/AX8BnAF3ARcBYwFQ
AUoB1QFSAWgBGQGHARkB5QE1AYIBYgFAAWYBQQE1AcEBRQFkASUBiQEZAUcBHQFHAR0BaAEVAUcBCQFH
AQ0BpAEMAUMBDAFDAQwBQwEMAcUBDAFIAREBRwEJAQcBEQFLASUBMgFCAVQBSgFUAUoBVAFKAVQBSgFU
AUoBVAFKAVQBSgFUAUoBVAFKAVQBSgFbAWsEAAFaAWsBmAE6AdUBHQHVAR0B1QEdAfUBHQH1ASEB9QEh
AfUBIQH1ASEBFgEmAZ0BKgH/AToB3gE2Ab0BMgGcAS4BewEqAZsBLgGbATYBugFCAdsBRgEaAVcBXAFf
AZwBbwG9AXMBvQF3AZwBbwHYAVoB2gFWAZkBTgFZAUoBOQFCARgBPgH4ATkB+AE1AfkBNQHZATEBuQEt
AZkBKQGZASkBmQEpAZkBKQF4ASEBegFGAXsBbwE5AWcBcwFOAf8Bf+AAAd4BewF6AW8B/wF/Ad4BewHR
AVoB4AF+AYABbgGAAW4BgAFFAWABPQGBAUEBZwElAWgBFQFoARkBRwEJAWkBFQFoARUBRwEJAeYBDAFj
AQwB5wEUAUkBGQFHAQkB5wEQASoBIQEqASUBbAEpAZUBTgF0AUoBVAFKAVQBSgFUAUoBVAFKAVQBSgFU
AUoBdAFKAb0BcwYAAXsBbwG4AUoB1QEdAdUBHQHVAR0B9QEdAfUBIQH1ASEB9QElATcBKgFXATYBmQE6
AbkBSgH6AU4BGgFbATsBYwFbAWsBWgFrAToBZwE6AWcBOgFnATsBYwEbAV8B+wFaAdsBVgHbAVYBvAFS
AdwBWgEcAWMB/AFeAZoBTgFZAUYBOQE+ARkBOgH5ATkB+QE1AdkBNQG5ATEBuQEtAbkBKQG5AS0BuQEt
AXkBJQEaAToBewFvAVoBawFSAUoB3gF76AAB/wF/AcYBbgGgAXYBRAF/AcMBbgGAAUkBYAFFAYcBIQFo
AREBSAENAWgBEQFpARkBRwEJAYkBGQFHAQ0BJwEJAUgBEQFpARkB5wEUASoBIQEqASEBSwElAXQBSgHX
AVYBlQFOAfABOQFUAUoBVAFKAVQBSgFUAUoBlQFSAd4BewgAAZwBcwHZAVIBNwEuAXcBNgGYAT4BuAFK
AdkBTgH4AVoBGQFfATkBZwE5AWcBOQFnARkBXwH6AV4B+gFaAfoBWgHaAVoB2wFWAdsBVgHbAVYBuwFS
AbsBUgG7AVIBmwFOAZsBTgF7AUoBWwFGAXsBSgG7AVIBuwFSAdsBVgG7AVIBegFKATkBQgEZAToB+QE5
AfkBNQHZATEBuQEtAbkBLQG5AS0BuQEtAZkBKQHZATEBmwFzAXsBbwFSAUoBvQF36AABnAF3AcMBdgFE
AX8BqAF/AagBfwFmAX8BogFuAaUBMQGMAR0BcAEdAY8BGQFJAQ0BaAERAWkBGQFHAQkBaAERAUgBEQEH
ASUBKgEhASoBIQEqASUBKgElAfABOQG2AVIBlQFOAZQBTgF0AU4BVAFKAVQBSgH3AVoB/wF/CgAB3gF7
ARgBYwH4AV4BGQFjAToBZwFbAWsBewFvAXwBbwGdAXMBvQF3AXwBbwF8AW8B2gFWAbsBUgGbAU4BmwFO
AZoBTgF6AUoBegFKAXoBRgFaAUYBWgFGAVsBQgE7AUIBOwE+ARsBOgEbAToBWwFGAZsBTgF7AUoBegFK
AVoBRgF6AUYBegFGAToBQgEZAT4B+QE5AdkBNQHZATEBuQEtAbkBLQG5AS0BuQEpAbkBKQGcAXMBnAJz
AU4BnAFz5gABewFzAe8BSQFEAX8BqQF/AakBfwGHAX8BRQF/AakBfwErAT4BbwEZAZEBHQH1ASkBkQEd
AW0BFQFoAREBJQEhAW8BXgFHAQ0BSQEdASoBJQEqASUBKgEhAegBHAFTAUoBtgFSAbYBUgF0AUoBtgFS
AfcBXgGcAW8B/wF/DgAB/wF/Af8BfwHeAXsBvgF3AZ0BcwGdAXMBnQFzAZ0BcwGdAXMBfAFvAXsBbwGZ
AU4BWgFCATkBQgE5AUIBGQE+ARkBPgEZAToB+QE5AfkBNQH6ATUB2gE1AdoBMQHaATEBugEtAdoBMQE6
AUIBWgFGAVoBRgFaAUYBOgFCAToBQgE6AT4BGgE+ARoBPgEZAToB+QE1AdkBMQHZATEB2QExAdkBMQG5
AS0BmQElAZwBcwGcAXMBlAFSAVoBa+QAAb0BdwHPAUUBtgFeASoBSgEGAUYBaQF3AYcBfwGqAX8BVwFn
AZIBHQGRAR0B9QElAfUBKQEXAS4B9gEpAZABHQFlATkB5gFZAYgBQQEmAS0BKgElASoBIQFsASkBdAFK
AdcBVgG2AVYB1wFWATIBRgFSAUYBtQFSGgAB/wF/Af8BfwH/AX8B3gF7Ab4BdwF8AW8BOwFnAXkBSgH4
ATUB2AE1AbgBMQG4ATEBuAEtAZgBLQGYAS0BmAEpAZkBKQF5ASUBeQElAXkBIQFZASEBmgElARoBPgE6
AUIBOgE+ARoBPgEaAToBGQE6AfkBOQH5ATkB+QE1AfkBNQHZATUB2QExAdkBMQHZATEB2QExAbkBMQF4
ASUBfAFvAb0BdwHWAVoBGAFj5AABvQF7AbYBXgFsATUBhAEUAfABPQG7AXcBsAF7Ad0BewG4AUoBswEh
ARYBLgEWASoBFwEuAdQBIQE4AS4BFgEqAWkBHQGqASkByQFBAUcBNQEJAR0BjQEtAREBPgG2AVIB1wFW
AdcBVgHXAVYB1wFWAbUBUgFTAUYB/wF/IgAB3gF7ARkBYwEWAT4BNgEdAVcBIQFXASEBVwElAVcBIQFY
ASEBOAEdATgBHQEYARkBGAEVAfgBFAH4ARAB+QEQATkBHQHZATUB+QE1AfkBNQH5ATUB2QE1AdkBNQHZ
ATUB2QExAdkBMQHZATEB2QExAdkBMQHZATEB2QExAdkBMQHZATEBeAElATwBZwG9AXcB9wFeAfcBXuQA
Af8BfwG1AVYBhAEUAfABPQHeAXsCAAH/AX8CAAHZAU4BOAEuAVgBMgFZATIBWQEyARYBKgEWASoB9QEp
AUgBEQFIARkBqwEpAXEBPgFLASkBtgFSAdcBVgHXAVYB1wFWAdcBVgG2AVYBMgFCAbYBUgHXAVYB/wF/
IgAB/wF/ATkBZwEUAT4BUwEAAVMBAAF0AQABdQEEAZUBCAG2AQgBtwEMAdcBDAG3AQgBlwEIAZcBBAGY
AQQBmAEEATkBGQHZATEB2QExAdkBMQHZATEB2QExAdkBMQHZATEB2QExAdkBMQHZATEBuQExAbkBLQG5
AS0BuQEtAZkBKQGZASUBWAEdAfsBWgHeAXsBGAFjAZQBUuYAAf8BfwG9AXcB3gF7CAAB+QFSATcBLgE4
ATIBWQE2AVkBMgFYATIBmQFCAe4BKQEnAQkBJwEJARcBWwH/AX8B3gF7ARkBXwHXAVYB1wFWAdcBVgGV
AlIBRgHOATUBawEpAVoBayYAARgBZwF1AU4BUwEAAVMBAAFUAQABVAEAAVUBAAFVAQABVQEAAVYBAAFW
AQABdwEAAXcBAAF4AQABmAEAATkBHQG5ATEBuQExAbkBLQG5AS0BuQEtAZkBKQGZASUBeQElAXgBIQFY
AR0BWAEdAVgBGQFYAR0BeAEhAZgBJQHYATEBGQE6ATsBYwHeAXsBWgFrAXMBTvQAAb4BdwFYAToBmQFC
AZkBQgFYATIBGwFXAf8BfwH/AX8BWQFjAXoBZwYAAf8BfwGcAXMB1wFWATIBRgEyAUIBUwFKAbYBUgF7
AWsB/wF/JgABOQFrAbYBVgFSAQABUwEAAVQBAAFUAQABVQEAAVUBAAFVAQABVgEAAVYBAAFXAQABdwEA
AXgBAAGYAQQBGQEVAVgBIQFYAR0BOAEZATgBGQE4ARkBOAEZAXcBIQG4AS0BGAE6AVkBRgG5AU4B+gFa
AToBZwF7AW8BvAF3Ab0BdwHeAXsB3gF7Ad4BewGcAXMBnAFz9gAB/wF/Af8BfwH/AX8BvgF3FAAB/wF/
AVoBawHwATkBzgE5Ab0BdyoAAVoBawH3AV4BkgEIAVMBAAFUAQABVAEAAVUBAAFVAQABVQEAAVYBAAF2
AQABdwEAAXcBAAGXAQQB1gEQAXcBJQH4ATUBWAFCAZkBTgHaAVoBGQFjAVoBawF7AW8BewFvAXsBbwF7
AW8BewFvAZwBcwGcAXMBvQF3Ab0BdwG9AXcB3gF7Ad4BewH/AX8B/wF//wAZAAH/AX8B/wF/LAABnAFz
AfcBYgHSARABUwEAAVMBAAFzAQQBtAEMARQBGQF1ASUB1QE1ATYBQgGXAU4B2AFaARkBYwE5AWcBWgFr
AVoBawFaAWsBWgFrAXsBbwF7AW8BnAFzAZwBcwG9AXcB3gF7Af8BfwH/AX8B/wF//wBZAAGcAXMB9wFe
ATQBRgFUAUoBtgFWAfgBXgEYAWMBGAFjARgBYwEYAWMBOQFnAVoBawF7AW8BnAFzAb0BdwG9AXcB3gF7
Af8BfwH/AX8B/wF//wBpAAHeAXsBGAFjARgBYwE5AWcBewFvAZwBcwG9AXcB3gF7Ad4BewH/AX//AH0A
Af8BfwH/AX8B/wF//wD/AP8A/wD/APMAAd4BewHeAXsBvQF3AXsBbwFaAWsBOQFnATkBZwFaAWsBvQF3
/wB1AAHeAXsBvQF3AXwBbwE6AWsBGAFjAfcBXgHWAVoBtQFWAXQBTgFTAUoBtgFWAbYBWgF0AU4BMgFG
AfcBXgF7AW8BnAFzAd4Be/8AZwAB3gF7AVoBawEYAWMB1gFaAbUBVgGVAVIBdAFOAVMBSgEyAUYBMgFC
AREBQgHwAT0B0AE5AVMBSgF0AU4BtQFWAZQBUgHvAT0BlAFSARgBYwFaAWsBnAFzrgAB3gF7AZwBcwFa
AWsBWgFrAVoBawFaAWsBWgFrAZwBcwHeAXtSAAHeAnsBbwH3AV4B9wFeAZwBc0YAATkBZwG1AVYBdAFO
ATIBRgERAUIBEQFCAREBQgERAUIBMgFGATIBRgFTAUYBUwFKATIBRgEyAUYBdAFOAXQBUgGVAVIBtgFW
AXMBTgHwAT0BtQFWAfcBXgEYAWMBewFvAd4Be0gAAd4BewG9AXcB3gF7VgABvQF3AVoBawFaAWsBOQFn
AVoBawFaAWsBWgFrAVoBawE5AWcBOQFnARgBYwH3AV4BGAFjAVoBawHeAXtGAAG9AXcBOQFnAZUBUgEy
AUYBMwFGAdgBWgGWAVIBzwE5AZQBUgG9AXc+AAHeAXsB1gFaAXQBUgGVAVIBdAFOATIBRgEyAUYBUwFK
AXQBTgF0AU4BdAFOAXQBTgGUAU4BlAFOAVMBSgFTAUoBtgFWAdcBWgG2AVYBtgFWAbUBVgERAUYBMgFG
ARgBYwEYAWMBOQFnAXsBbwHeAXs+AAHeAnsBbwH3AVoBUwFKARABPgGtATUBbAEtAZQBUlAAAb0BdwE5
AWcBGAFjATkBZwFaAWsBewFvAXsBbwF7AW8BewFvAVoBawE5AWcBWgFrAXsBbwE5AWcB1gFaAdYBWgHW
AVoBOQFnAd4BewHeAXsBvQF3AZwBcwG9AXcB3gF7MgABnAFzAfgBXgF0AU4BMgFGAVMBSgGWAVIBGgFj
AX0BawF9AWcBfQFnAfgBVgHPATkBzgI5AWc8AAH3AV4BtgFWAdcBWgHWAVoB1gFaAbUBVgG1AVYBtQFW
AXQBTgFTAUoBUgFKAVIBSgGUAVIBlQFSAVMBSgFTAUoBEgFCAZYBTgG2AVoBtgFWAbYBVgF0AU4B7wE9
AfcBXgE5AWcBOQFnAVoBawF7AW8B3gF7NgABnAFzARgBYwGUAU4BEAFCAe8BPQHvAT0BEAFCAe8BPQGM
ATEBSgEpAQgBIQHOATkBewFvSgABvQF3ARgBYwEYAWMBGAFjATkBZwFaAWsBWgFrAXsBbwF7AW8BewFv
AVoBawE5AWcBewFvAXsBbwH3AV4B9wFeARgBYwHWAVoBlAFSAdYBWgEYAWMBGAFjARgBYwE5AWcBewFv
Ab0BdwHeAXsmAAHeAnsBbwHWAVoBdAFOATIBRgGVAVIB+AFeAXwBbwG+AXMBvgFzAZ0BbwF9AWcBXAFj
AVwBXwFcAV8BXAFfAXUBSgGNATEBcwFOAd4BezYAAVoBawHWAVoBGQFjAfcBXgH4AV4BGQFnARgBYwH3
AV4BlAFSAVMBSgGUAVIBlAFSAbUBVgG1AVYBlQFSAXQBTgF0AU4BUwFKATIBRgG2AVYBtgFWAbYBVgG1
AVYBzwE5AbYBVgFaAWsBWgFrAVoBawF7AW8BnAFzAd4BeywAAb0BdwE5AWcBtQFWATEBQgHvAT0B7wE9
ARABQgExAUYB7wE9AYwBMQEIASEBxgEYAcYBGAHGARgBCAEhAQgBIQFKASkB1gFaSAABGAFjAfcBXgH3
AV4BGAFjATkBZwFaAWsBWgFrAXsBbwF7AW8BewFvAVoBawE5AWcBewFvATkBZwH3AV4BGAFjAdYBWgG1
AVYBlAFSAXMBTgGUAVIBlAFSAdYBWgH3AV4BOQFnAXsBbwGcAXMBvQF3HgABvQF3ATkBZwG1AVYBdAFO
AXQBTgHXAVoBGQFjAb0BdwH/AX8B/wF7Ad4BdwG+AXMBnQFvAX0BawF8AWcBXAFjAVwBXwE7AVsBOwFb
AVwBWwH6AVYB8QE9Ae8BPQE5AWcyAAHeAXsB9wFeATkBZwE5AWcBtQFWARIBPgG2AVIBWgFrATkBZwEY
AWMBOQFnAToBZwFaAWsBnAFzARgBYwGVAVIBlAFSAZYBUgHWAVoBtQFWAbYBVgG2AVYBtgFaAdYBWgHw
AT0BUwFKAXsBbwFaAWsBewFvAXsBbwGcAXMBnQFzAd4BeyQAAVoBawHWAVYBUgFGAe8BPQHvAT0BEAE+
ATEBRgEQAUIBrQE1ASkBJQHGARgBpQEUAcYBGAEpASUBawEtAc4BOQGUAVIBMQFGAQgBIQEpASUBCAEh
ARABQgG9AXcmAAG9AXcBewFvAb0BdwG9AXcBvQF3Ab0BdwG9AXcB3gF7DAAB3gF7AdYBWgHWAVoB9wFe
ARgBYwEYAWMBOQFnAVoBawF7AW8BewFvAVoBawE5AWcBGAFjATkBZwEYAWMBGAFjAdYBWgG1AVYBlAFS
AXMBTgFzAU4BlAFSAbUBVgHWAVoB9wFeARgBYwFaAWsBewFvAZwBcwHeAXsUAAHeAnsBbwH4AV4BtQFW
AXQBTgG2AVYBGAFjAXsBbwGdAXMBvQF3AXsBbwG9AXcB/wF/Ad8BdwG+AXMBngFvAZ0BbwF9AWsBfQFn
AXwBYwFdAWMBXAFfATsBWwH5AVIB2AFOAXQBSgGMATEBCAEhAZQBUjAAAZwBcwH3AV4BWgFrAVoBawEY
AWMBtQFWAfcBXgF7AW8BewFvAVoBawGcAXMBvQF3Ab0BdwFaAWsB9wFeAfcBXgF0AVIBEgE+AVQBSgHX
AV4BtgFaAbYBVgHWAVoB1wFaAREBQgExAUYBewFvAXsBbwGcAXMBnAFzAZwBcwG9AXcBvQF3Ad4BeyAA
AVoBawHOATkB7wE9ATEBRgEQAUIBzgE5AUoBKQHnARwBpQEUAcYBGAEIASEBawEtAe8BPQFSAUoBcwFO
AdYBWgEYAWMB9wFeATkBZwFSAkoBKQEIASEBCAEhAWsBLQEYAWMiAAH3AV4B7wE9Ac4BOQEQAUIBcwFO
AbUBVgFSAUoBMQFGAbUBVgE5AWcBnAFzAd4BewYAAd4BewHWAVoB1gFaAfcBXgH3AV4BGAFjARgBYwE5
AWcBWgFrAVoBawFaAWsBOQFnARgBYwH3AV4B9wFeAdYBWgG1AVYBcwFOAVIBSgFSAUoBcwFOAZQBUgHW
AVoB9wFeARgBYwE5AWcBWgFrAXsBbwGcAXMBvQF3DgABvQF3AVoBawHWAVoBtQFWAZQBUgHXAVoBOgFn
AZ0BcwG9AXcBvQF3AVoBawEYAWMBtQFWATEBRgEQAUIB9wFaAb4BdwHeAXcBvgFzAb4BbwGeAW8BfQFn
AToBXwG3AVIBMgE+AY4BLQFLASUBKgElAecBHAHoARwBCQEhAcYBGAGtATUBewFvLAABWgFrARgBYwFa
AWsBWgFrAVoBawEYAWMBUwFKAXUBSgF7AW8BmwFzAVoBawFaAWsBWgFrAVoBZwE6AWcBGQFjAdcBWgGU
AVIBlQFSAdcBWgHWAVoB1gFaAdcBWgHXAV4BUgFKAe8BPQF7AW8BnAFzAZwBcwG9AXcBvQF3Ab0BdwG9
AXcB3gF7Ad4Bex4AATkBZwFSAUoBrQE1AecBHAGlARQBpQEUAecBHAFKASkBzgE5AVIBSgG1AVYBGAFj
AVoBawGcAXMB9wFeARgBYwE5AWcB9wFeAf8BfwGcAXMBtQFWAYwBMQEIASEBKQElASkBIQFzAU4eAAGc
AXMBEAFCAVMBSgEQAUIBzgE5Ae8BPQGMATEBKQElAYwBMQFzAU4BlAFSAZQBUgEYAWMBewFvAb0BdwQA
ATkBZwG1AVYB1gFaAfcBXgH3AV4B9wFeARgBYwEYAWMBOQFnARgBYwH3AV4B9wFeAdYBWgGUAlIBSgEQ
AUIBEAFCAVIBSgFSAUoBcwFOAdYBWgEYAWMBOQFnATkBZwFaAWsBewFvAZwBcwG9AXcKAAGcAXMBOQFn
AdYBWgG1AVYBtgFWARkBYwFbAWsBvQFzAb4BdwGcAXMBOQFnAdYBWgGUAlIBSgEQAUIBzgE5Aa0BNQGM
ATEBawEtATEBRgF8AW8BnQFvAfgBWgFTAUoBrgE1ASsBJQHIARgBpwEUAYcBEAGHARABpwEUAegBHAHo
ARwBxwEYAegBHAGlARQB5wEcAdYBWioAAVoBawE5AWcBOQFnATkBZwE5AWcBOQFnAbUBVgF0AU4BOQFn
AXsBbwGdAXMBnQF3AZwBcwF7AW8BWgFrARkBZwEYAWMB+AFeAfcBXgH3AV4B+AFeARgBYwH4AWIB9wFe
AXQBUgHOATkBewFvAZwBcwG9AXcBvQF3Ab0BdwHeAXsB3gF7Ad4BewHeAXsgAAFaAWsBSgIpASUBrQE1
ATEBRgG1AVYBGAFjAVoBawF7AW8BnAFzAZwBcwGcAXMBnAFzAfcBXgH3AV4BOQFnARgBYwH/AX8B/wF/
Ad4BewEYAWMB7wE9ASkBJQEpASUBCAEhAbUBVhwAAVoBawFSAUoBlQFSATEBRgHvAT0BMQFGAVIBSgEx
AUYB7wE9Ae8BPQFzAU4BtQFWAZQBUgG1AVYB9wFeAXsBbwG9AXcB3gF7ARgBYwG1AVYB1gFaAdYBWgHW
AVoB1gFaAdYBWgG1AVYBtQFWAXMBTgFSAUoBEAFCAc4BOQGMATEBrQE1ARABQgFSAUoB1gFaAfcBXgEY
AWMBOQFnATkBZwF7AW8BnAFzAb0BdwHeAXsKAAE5AWcBtQFWAfgBXgE5AWMBfAFvAXwBbwGdAXMBnQFz
Ab0BdwHeAXsBvgF3ARgBYwExAUYBzgE5Ac4BOQHOATkBzgE5Ae8BPQEwAUIBEAFCARABQgHPATkBbAEt
AegBHAHIARgBpwEUAcgBFAGnARAByAEUAacBFAGnARABhgEQAacBEAHpARwB6AEcAccBGAHnARgBpQEU
AWMBDAExAUYB3gF7JAAB3gF7ATkBZwE5AWcBOQFnATkBZwE5AWcBWgFnATkBZwE5AWcBWgFrAVoBawF7
AW8BewFvAXsBbwF7AW8BewFvAXsBbwFaAWsBWgFrAVoBawFaAWsBOQFrARgBYwH3AV4B+AFeAZUBVgGt
ATUBewFvAb0BdwG9AXcBvQF3Ad4BewHeAXsB3gF7Ad4BewHeAXsgAAE5AWcBcwFOAdYBWgF7AW8BnAFz
AZwBcwGcAXMBnAFzAZwBcwGcAXMBnAFzAZwBcwGcAXMB9wFeARgBYwE5AWcBGAFjAf8BfwHeAXsB3gF7
Af8BfwF7AW8BUgJKASkBawExAbUBUgFaAWsBvQF3GAABOQFnAVMBSgH4AV4BcwFOAe8BPQEQAUIBMQFG
AXMBTgGUAVIBcwFOATEBRgExAUYBcwFOAZQBUgG1AVYBtQFWATkBZwF7AW8BWgFrAdYBWgGUAVIBlAFS
AXMBTgFzAU4BcwFOAVIBSgEQAT4B7wE9Ae8BPQHOATkB7wE9AVIBSgG1AVYB1gFaAdYBWgH3AV4B9wFe
AfcBXgH3AV4B1gJaAWsOAAG+AXcBOgFnAVsBawFbAWsBWwFrAVsBawF8AW8BnAFzAZ0BcwG9AXcBvgF3
Ad4BewH/AX8BvQF3AbYBVgExAUYBMQFGATEBRgEQAUIBjQExASoBJQEJASEByAEYAegBGAHIARgB6AEY
AacBFAHIARQBpwEUAcgBFAGnARQBqAEUAacBFAGnARQBhwEQAcgBGAEJASEBxwEYAccBGAGFARABpQEU
AXMBTgGcAXMiAAHeAXsBGAFjARgBYwEYAWMBGAFjATkBZwE5AWcBWgFrAVsBbwF7AW8BewFvAZsBcwGc
AXMBnAF3AZsBcwF6AW8BWQFnARgBYwG2AVYBMwFGAfIBOQGRAS0BLwEdAbIBMQE5AWcBtgFWAc4BOQGc
AXMB3gF7Ad4BewHeAXsB3gF7KAABWgFrAZwBcwF7AW8BvQF3Ab0BdwGcAXMBnAFzAb0BdwGcAXMBnAFz
AZwBcwGcAXMBnAFzARgBXwEYAWMBWgFrARgBYwHeAXsB3gF7Ab0BdwG9AXcBvQF3AZwBcwG1AVYBMQFG
ATkBZwFaAWsBWgFrAZwBcxYAARgBYwGUAVIBGgFjAXQBTgEPAUIBEAFCARABQgExAUYBUgFKAZQBUgHW
AVoBtQFWAVIBSgHOATkBlAFSAbUBVgHWAVoB1gFaAdYBWgHWAVoB1gFaAdYBWgHWAVoBtQFWAXMBTgEx
AUYBMQFKATEBSgFzAU4BlAFSAbUBVgHWAVoB1QFaAdUBWgH2AV4BFwFjAfgBXgEZAWMBGAFjAdYBWgEY
AWMQAAF8AW8BOgFnAToBZwFbAWsBWwFrAXwBbwGcAXMBnQFzAb4BdwG+AXcBnQFzAVoBawHWAVoBUgFK
Aa4BNQFLASkBCQEhAegBHAEJASEB6AEcAegBHAHIARgBCQEdAegBGAHpARgByAEUAckBGAHIARQBpwEU
AacBEAGGARABpwEUAacBFAHIARgB6QEcAUwBIQEJAR0BpgEUAcYBGAGtATUBUgFKAbUBVgGcAXMgAAG9
AXcB9wFeARgBYwE5AWcBOQFnAVoBawF7AW8BewFzAXoBbwFZAWsBOQFnARgBXwG2AVIBVQFGARQBPgGy
AS0BUQEhAe8BFAHPAQwBrgEIAY4BBAGOAQQBjwEAAXMBJQE5AWcB1gFaAc4BOQG+AXcwAAFaAWsBvQF3
AXsBbwG9AXcBvQF3Ab0BdwG9AXcBvQF3Ab0BdwGcAXMBnAFzAZwBcwGcAXMBGAFjARgBYwFaAWsBGAFj
Ad4BewG9AXcBvQF3AZwBcwGcAXMBewFvAXsBbwFSAUoBOQFnAXsBbwF7AW8BewFvAZwBcxQAARgBYwG2
AVYBOwFnAXQBTgEQAUIBMQFGATEBRgExAUYBMQFGATEBRgFzAU4BtQFWAfcBXgG1AVYBcwFOAZQBUgHW
AVoB1gFaAfcBXgH3AV4B1gFaAdYBWgG1AVoBlAJSAU4BUgFKAVIBSgExAUoBMQFKAZIBUgG0AVoBtgFa
AbcBVgF4AUoBGQE+AbkBLQEYARkB9wEUAfgBXgH2AV4BGAFjEgAB3gF7AXwBbwFbAWsBWwFrAXwBbwF7
AW8BOQFnAdYBWgFSAUoB7wE9AWsBLQFKASkBCQEhASoBJQEJASEBCQEhAegBHAEJASEB6AEcAekBHAHo
ARgB6QEcAekBGAHIARgByAEUAcgBFAHIARgByAEYAQoBIQEqASUBbAEtAWwBLQFLASkBbwEhAW8BFQEK
ARkBawEtAVIBSgH3AV4BOQFnATkBZwFaAWsBvQF3HgABvQF3AfcBXgEYAWMBOQFnARgBXwG2AVYBdgFK
AVYBRgEVAToBswEtAXIBIQEzARkBEgEVAfIBEAHyARAB8gEQAdEBDAGwAQgBsAEIAa8BCAGvAQgBrwEI
Aa8BBAFzASUBOQFnAfcBXgHvAT0B3gF7MAABWgFrAb0BdwF7AW8BvQF3Ab0BdwG9AXcBvQF3Ab0BdwG9
AXcBvQF3AZwBcwGcAXMBvQF3ARgBYwEYAWMBWgFrARgBYwG9AXcBvQF3AZwBcwF7AW8BewFvAVoBawFa
AWsBUgFKATkBZwGcAXMBnAFzAZwBcwGcAXMBvQF3Ad4BexAAARgBYwG3AVYBXAFrAXQBTgEQAUIBMQFG
AVIBSgFSAUoBUgFKAVIBSgFSAUoBcwFOAZQBUgHWAVoB1gFaAZQBUgG1AVYB1gFaAbUBVgGUAVIBcwFO
AVIBSgExAUoBMAFKAVEBTgFRAU4BMgFKAVMBSgEUAUIBtgExAZgBKQEXARkBtgEIAXYBBAFVAQABNAEA
AVQBAAGUAQgB2AFaARcBYwH3AV4WAAHeAXsBnAFzAfgBXgEyAUYBrQE1AUoCKQElAUsBKQEqASUBKgEp
AQkBIQEJASUBCQEhASoBJQEJASEBCQEhAekBHAHpARwB6QEcAegBGAHpARwBCQEdAUsBKQFLASkBrgE1
Aa0BNQGNATEBjAExAWwBLQFKAikBJQFLASkBzwE9AbUBVgE5AWcBWgFrAVoBawH3AV4BWgFrAd4BeyAA
AZwBcwEXAWMBuAFSAbUBKQGWASUBlgEhAXYBHQFVARkBNQEZATUBGQE0ARUBFAEVARMBFQETARUBMwEZ
ARIBFQHxARAB0AEMAdABCAGwAQgBsAEIAbABCAGvAQQBcwElATkBZwH3AV4BzwE5Ad4BezAAAVoBawG9
AXcBewFvAd4BewG9AXcBvQF3Ab0BdwG9AXcBvQF3Ab0BdwG9AXcBvQF3Ab0BdwEYAWMBGAFjAVoBawH3
AV4BvQF3AZwBcwF7AW8BewFvAVoBawE5AWcBOQFnAVIBSgFaAWsBvQF3Ab0BdwG9AXcBvQF3Ad4BewHe
AXsB3gF7DgABGAFjAbcBVgFcAWsBdAFOATEBRgFSAUoBcwFOAXMBTgFzAU4BcwFOAXMBTgFzAU4BUgFO
AVIBSgFSAUoBUgFOAXMBTgFzAVIBkwFSAZMBVgGTAVIBcwFOATIBRgHzATkBtAExAVQBJQHUARABlAEI
AXQBBAFUAQABVAEAAXQBBAF0AQQBdQEEAZUBCAGVAQgBlgEIAbYBDAG4AVYBOAFnAdYBWgHeAXsYAAGc
AXMB1wFaATIBRgGuATUBbAEtASoCKQElASoBJQEqASUBKgElAQkBIQHoARwBCQEhAQkBIQEKASEBKgEl
AWwBLQGNATEBrgE1Aa0BNQGNATEBjAExAUsBKQFKASkBKgElASkBJQEpASUBbAEtAe8BPQFSAUoBUgFK
ARABQgGtATUBSgEpAecBIAHGARwBawEtAb0BdyAAAXsBcwEYAWcBmQFOAZkBIQGYASUBmAEhAXcBIQF2
AR0BVgEdAVUBGQE0ARkBNAEVARMBFQEzARkBMwEZARIBFQESARUB0QEMAdABDAHQAQwB0AEMAdABDAGw
AQgBcwElATkBZwEYAWMB7wE9Ad4BezAAAVoBawG9AXcBewFvAd4BewG9AXcBvQF3Ab0BdwG9AXcBvQF3
Ab0BdwG9AXcBvQF3Ab0BdwEYAWMBGAFjAVoBawH3AV4BnAFzAXsBbwFaAWsBWgFrATkBZwEYAWMBGAFj
AVIBSgF7AW8B3gF7Ad4BewHeAXsB3gF7Ad4BexIAAfgBXgG3AVYBXAFrAXQBTgFRAUoBcwFOAXMBTgGU
AVIBlAFSAZQCUgFKATEBRgExAUYBbwFGAVEBTgFyAU4BlAFSAZUBUgETAUIBkwExAVQBKQGxARABUgEE
AVIBAAESAQABEgEAATIBAAEyAQABdAEEAbUBDAG1AQwBtgEMAbYBDAG2AQwBtgEMAdcBDAHXAQwB1wEM
AXgBTgE4AWcBtQFWAb0BdxwAAb0BdwH4AV4BMwFGAc8BOQFrAS0BKQElAQkBIQEJASEBSwEpASoBJQFr
ASkBjQExAa4BNQGuATUBrgE1AYwBMQFLAikBJQHoARwBxgEYAaUBFAHGARgB5wEcAQgBIQEpASUBSQIp
ASUB5wEcAeYBHAHmASABCAElAWwBLQGPASkBEwE6AbUBVgFbAWsgAAF7AW8BFwFjAZkBTgGYASEBuAEl
AZgBJQGXASEBdgEhAXYBHQFVAR0BVQEZATQBGQE0ARUBVAEZATMBGQESARUBEgEVAfEBEAHRAQwB0QEM
AdABDAHQAQwBsAEIAXMBJQE5AWcBGAFjAe8BOQHdAXcwAAFaAWsBvQF3AXsBbwHeAXsB3gF7Ab0BdwG9
AXcBvQF3Ab0BdwG9AXcBvQF3Ab0BdwG9AXcBGAFjARgBYwFaAWsB9wFeAXsBbwFaAWsBOQFnATkBZwEY
AWMBGAFjAfcBXgExAUYBnAFzHAAB9wFeAbYBVgE7AWcBUwFKAVIBSgGUAVIBlAFSAZQBUgG1AVYBtQFW
AXMBTgEyAUoBMgFGAfIBOQGSATEBEQEdAbEBEAFxAQgBMAEAARABAAEQAQABEAEAATEBAAExAQABMgEA
ATIBAAFTAQABVAEAAbUBDAHWARAB1gEQAfcBEAH3ARAB+AEUAfgBFAH4ARQBGQEVAdkBEAE5AUIBWQFr
AbUBVgGcAXMgAAG+AXcBGQFjAVMBSgGuATUBjQExAa4BNQGNATEBbAEtAWwBLQFsAS0BbQEtAY0BMQFs
AS0BKQElAcYBGAHGARgBxgEYAecBHAEIASEBCAEhAQgBIQEHASUBKAElASkBJQFsAS0BsAExAZIBKQG2
ASUBuQEhAXoBEQE7AQUBugEdAVsBawGcAW8gAAFaAWsB9wFiAZkBSgGZASUBuAElAZgBJQGXASEBdwEh
AXYBHQFWAR0BVQEZATQBGQE0ARkBVAEdATQBGQETARUBMwEZAfIBEAHxAQwB8QEMAfEBDAHRAQwB0QEI
AXMBJQE5AWcBOQFnAe8BPQG9AXcwAAFaAWsBvQF3AXsBbwHeAXsB3gF7Ad4BewG9AXcBvQF3Ab0BdwG9
AXcBvQF3Ab0BdwG9AXcBGAFjARgBYwFaAWsB9wFeAXsBbwE5AWcBOQFnARgBYwH3AV4B9wFeAfcBXgEx
AUYBnAFzHAAB9wFeAZUBUgEaAWMBUwFKAXMBTgG1AVYBtQFWAbUBVgG1AVYB1gFaAZMBUgEzAUYBcAEI
ATABAAEQAQABEAEAARABAAEQAQABEAEAATABAAEwAQABMQEAATEBAAEyAQABMwEAAVMBAAFUAQABdQEE
AfYBFAEXARkBGAEZARgBGQE5ARkBOQEZATkBGQE6AR0BOgEdARoBFQEZAToBWQFrAbUBVgF7AW8kAAHe
AXsBOgFnAdcBWgG2AVYBlQFSAZUBUgG2AVYBtQFWAXQBTgHwAT0BjAExAUoCKQElASkBJQFJASkBagEt
AWoBLQFrAS0BrwExAbMBKQGWASUBmAEdAXoBEQE6AQkBGgEBAdkBAAH5AQABGQEBAfkBAAE5AQkBGQFf
AVsBayAAAVoBawH2AV4BeQFKAbkBJQG5ASUBmAElAZgBJQF3ASEBdgEhAXYBHQFVAR0BVQEZAVUBGQF1
AR0BNAEZATMBFQEzARkBEgEVAfIBEAHxARAB8QEQAfEBEAHRAQwBlAElATkBZwE5AWcB7wE9Ab0BdzAA
AVoBawG9AXcBewFvAd4BewHeAXsB3gF7Ad4BewHeAXsBvQF3Ab0BdwG9AXcBvQF3Ab0BdwEYAWMBGAFj
AVoBawH3AV4BWgFrARgBYwEYAWMB9wFeAfcBXgHWAVoB1gFaATEBRgG9AXccAAH3AV4BdAFOARkBYwFT
AUoBlAFSAbUBVgG1AVYB1gFaAdYBWgH3AV4BtQFWAVMBSgFQAQQBMAEAAXEBCAFRAQQBUAEEAVABBAEw
AQABMAEAATEBAAExAQABMgEAAVMBAAFTAQABVAEAAVQBAAGWAQQBOAEdAVkBIQFZASEBWgEhAXoBIQF6
ASEBewEhAXsBIQF7ASUBWwEdAfoBNQFZAWsB1gJaAWsuAAGcAXMB9wFeATEBRgGsATUBagEtAWoBLQGL
ATEBrQE1Ac8BNQGxAS0BtAEpAZcBIQFYARUBOQEJARoBBQH5AQAB+QEAAfkBAAH4AQAB+AEAAfgBAAEZ
AQEBOQEFATkBBQE5AQkB2QFWAVoBayAAATkBZwHWAV4BeQFGAbkBJQG5ASkBuAElAZgBJQGXASEBdwEh
AXYBHQFWAR0BVQEdAVUBHQF1ASEBNAEZATQBGQFUAR0BEwEVARIBEQHyARAB8gEQAfIBEAHyAQwBlAEl
ARgBYwFZAWsB7wE9Ab0BdzAAAVoBawG9AXcBewFvAd4BewHeAXsB3gF7Ad4BewHeAXsB3gF7Ad4BewG9
AXcBvQF3Ad4BewEYAWMBGAFjAVoBawH3AV4BOQFnAfcBXgH3AV4B1gFaAdYBWgG1AVYB1gFaATEBRgG9
AXccAAH3AV4BcwFOAfgBXgFTAUoBtQFWAdYBWgHWAVoB1gFaAdYBWgH3AV4B1gFaAbUBVgGwARABcQEI
AZIBDAFxAQgBcQEIAVEBCAFRAQQBMQEAATEBAAEyAQABUwEAAVQBAAFUAQABVQEAAVUBAAG3AQwBeQEl
AZoBKQGaASkBmwEpAZsBKQGbASkBvAEpAbwBKQG8ASkBnAElAfsBNQFaAWsB1gFaARgBYyoAARgBYwEx
AUYBrAE1AYsBMQGMATEBzwE5AdEBNQG0AS0BtgEpAXcBHQEYAQ0BGAEJAfgBBAHYAQAB+AEEAfgBBAH4
AQQBGQEJARkBCQEZAQUBGQEFAfgBBAH5AQQBGQEFAToBCQE6AQkBOgEJAZkBSgFaAWsB3gF7HgABOQFn
AdUBWgF5AUYBugElAbkBKQG5ASUBuAElAZgBJQGXASEBdwEhAXYBHQFWAR0BdgEhAXYBIQFUARkBNAEZ
AVUBHQE0ARkBEwEVARMBFQETARUBEwEVAfIBEAGUASUBGAFjAVoBawHwAT0BvQF3MAABWgFrAb0BdwF8
AW8B/wF/Ad4BewHeAXsB3gF7Ad4BewHeAXsB3gF7Ad4BewHeAXsB3gF7ARgBYwEYAWMBWgFrAfcBXgE5
AWcB9wFeAdYBWgHWAVoBtQFWAbUBVgG1AVYBMQFGAb0BdxwAAfcBXgFTAUoB1wFaAVIBSgG1AVYB1gFa
AdYBWgHWAVoB9wFeAfcBXgH3AV4B1QFaARIBIQFxAQgBsgEQAbIBEAGSAQwBkgEMAXIBCAExAQABMgEA
AVMBAAFUAQABVAEAAVUBAAFVAQABVgEAAfgBEAG7AS0B2wEtAdsBLQHcAS0B3AExAdwBMQHcATEB/QEx
Af0BMQHdATEB/AE1AVoBawH3AV4B9wFeKAAB3gF7ATEBRgHRATUB1AExAbUBKQF2AR0BFwERAfcBDAHX
AQQBtgEAAdYBBAHWAQQB9wEIAfcBCAEXAQ0BGAENARgBDQE5AQ0BWQERAVkBEQFZAREBOQENATkBDQE5
AQ0BWgENAToBDQE6AQ0BGgEFAVkBPgFaAWsB3gF7HgABGAFnAdUBWgFZAUIBugEpAdoBKQG5ASkBuQEl
AZgBJQGYASEBlwEhAXYBIQF2ASEBlgElAXYBIQFVARkBVQEdAXUBIQFUARkBMwEVARMBFQETARUBEwEV
ARMBEQGUASkB9wFeAVoBawHwAT0BvQF3MAABWgFrAb0BdwGcAW8B/wF/Ad4BewHeAXsB3gF7Ad4BewHe
AXsB3gF7Ad4BewHeAXsB3gF7ARgBYwEYAWMBWgFrAfcBXgEYAWMB1gFaAdYBWgG1AVYBtQFWAbUBVgG1
AVYBMQFGAb0BdxwAAfcBXgEyAUYBtgFWAVIBSgHWAVoB1gFaAdYBWgH3AV4B9wFeAfcBXgH3AV4B9gFe
AXMBLQFyAQgB0wEYAdMBFAGyARQBswEQAXIBBAEyAQABMgEAAVMBAAFUAQABVQEAAVUBAAFWAQABVwEA
ATkBGQH7ATUB/AE1AfwBNQEcATYBHQE2AR0BOgEdAToBHQE6AT4BOgEeAToB/QE1AToBZwEYAWMB1gFa
KgABOwFnARcBEQG2AQQBtQEAAbUBBAG1AQQBtQEEAdUBCAHVAQgB9gEMAfcBDAEXAQ0BFwENARgBEQEY
AREBOAERATkBEQFZARUBegEZAXoBGQFZARUBWgEVAVoBFQFaARUBWgEVAVoBFQE7AQ0B+QEtATkBZwG9
AXceAAEYAWMBtAFWAVkBQgHaASkB2gEpAbkBKQG5ASkBuAElAZgBJQGXASEBdwEhAZcBJQG3ASUBlgEh
AVUBHQF1AR0BdgEhAVUBHQE0ARkBNAEZATQBGQE0ARkBFAEVAZUBKQHWAVoBWQFrAe8BPQG9AXcwAAFa
AWsBvQFzAZwBcwH/AX8B/wF/Ad4BewHeAXsB3gF7Ad4BewHeAXsB3gF7Ad4BewHeAXsBGQFjARgBYwFa
AWsB9wFeAfcBXgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgExAUYBvQF3HAAB9wFeATIBRgG2AVYBUgFK
AdYBWgH3AV4B9wFeAfcBXgH3AV4B9wFeAfcBXgH3AWIBkwExAZIBDAEUAR0B8wEYAfMBGAHTARQBUgEA
ATIBAAFTAQABVAEAAVUBAAFVAQABVgEAAVcBAAF4AQABewElATwBPgE9AT4BPQE+AT0BPgE9AT4BXgE+
AV4BPgFeAUIBXgFCAV4BQgEeATYBGgFjATkBZwG1AVYqAAF7AW8CFQG1AQQB9QEMAfUBDAH1AQwB1QEM
AdUBDAHVAQgB1gEIAfYBDAH3AQwB9wEMARcBDQEYAQ0B+AEMARgBEQF5ARkBmgEdAXoBHQF6AR0BegEZ
AZsBHQGbAR0BmwEZAZsBGQF7ARUBugEhATkBYwF8AW8eAAEYAWMBlAFWAVkBQgHbASkB2gEpAdoBKQHZ
ASkBuQEpAbgBJQGYASUBlwElAbgBJQG3ASkBlwEhAXYBHQF2ASEBlgElAXUBHQFVARkBVQEZAVUBGQE0
ARkBNAEVAZUBKQG1AVYBWgFrAe8BPQG9AXMwAAFaAWsBvQFzAZwBcwH/AX8B/wF/Af8BfwH/AX8B3gF7
Ad4BewHeAXsB3gF7Ad4BewHeAXsBOQFjARgBYwFaAWsB1gFaAfcBXgG1AVYBtQFWAbUBVgG1AVYBtQFW
AbUBVgExAUYBvQF3HAAB9wFeATABQgFxAUYBMgFGAdYBWgH3AV4B9wFeAfcBXgH3AV4BGAFjARgBYwEX
AWMB0wE5AZIBEAE0ASEBNAEhATQBIQGzARABMgEAATMBAAFUAQABVQEAAVUBAAFWAQABVwEAAXgBAAGZ
AQQB3AEtAX0BRgFdAUYBfQFGAX4BRgF+AUYBfgFGAX4BRgF/AUYBnwFGAZ8BSgE/AT4B+wJaAWsBtQFW
Ad4BeygAAbwBdwGWASUB1gEIARYBEQEWAREBFgERARYBEQH2ARAB9gEMAfYBDAH2AQwB9wEMAfcBDAH4
AQwB+AEMAfgBDAE5ARUBmgEhAbsBJQG7ASEBuwEhAbsBIQG7ASUBvAEhAbwBIQG8ASEBvAEdAbsBIQEZ
AV8BWgFrHgABFwFjAZQBUgFZAT4B2wEtAfoBLQHaAS0B2gEpAbkBKQG5ASUBuAElAbgBJQG4ASkBuAEp
AZcBIQF2ASEBlwElAZcBJQF2ASEBVQEdAVUBHQFVAR0BVQEdAVUBGQG1ASkBtQFWAVoBawHvAT0BnQFz
MAABWgFrAb0BdwGcAXMB/wF/Af8BfwH/AX8B/wF/Af8BfwHeAXsB3gF7Ad4BewHeAXsB3gF7ATkBZwEY
AWMBWgFrAdYBWgH3AV4BtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBMQFGAb0BdxwAARgBYwFnASEBqAEl
ATEBRgH3AV4B9wFeAfcBXgH3AV4BGAFjARgBYwE5AWcBGAFjAVQBSgGyARABVQElAVUBJQFVASUBcwEI
ATIBAAFTAQABVAEAAVUBAAFWAQABVwEAAXcBAAF4AQABugEIAT0BOgGeAUoBngFKAZ4BSgGeAUoBnwFO
Ab8BTgG/AU4BvwFOAb8BTgG/AU4BfwFCAdwBVgF6AW8BtQFWAb0BdygAAd4BfwEXAToB9gEMATYBFQE2
ARUBNgEVATYBFQEWARUB9gEQAfYBEAEXAREBFwERARgBEQEYAREBGAERARkBEQFaARkB2wElAdsBKQHb
ASkB2wEpAdwBKQH8ASkB/AEpAdwBKQHcASUB3AElAbsBIQHZAVYBWgFrHgAB9wFeAZQBUgFZAT4B/AEt
AfsBLQH6AS0B2gEtAdoBKQHZASkBuQEpAdkBKQHZAS0BuAEpAZcBIQGXASEBlwElAbcBKQF3ASEBdgEd
AXYBHQF2AR0BdgEdAVYBHQG2ASkBlAFSAVoBawHwAT0BvQFzMAABWgFrAb0BdwGcAXMB/wF/Af8BfwH/
AX8B/wF/Af8BfwH/AX8B/wF/Ad4BewHeAXsB/wF/ATkBZwEYAWMBWgFrAdYBWgH3AV4BtQFWAbUBVgG1
AVYBtQFWAbUBVgG1AVYBMQFGAb0BdxwAATkBZwHoARwBKwElATEBRgH3AV4B9wFeAfcBXgEYAWMBGAFj
ARgBYwE5AWcBGAFjAdYBWgHSARQBdQEpAZYBLQE1AR0BMgEAATMBAAFUAQABVQEAAVUBAAFWAQABdwEA
AXgBAAF5AQAB+wEQAX0BRgG+AVIBvgFSAb4BUgHfAVIB3wFSAd8BUgHfAVIB3wFSAd8BVgH/AVYBnwFK
AdwBVgF6AW8BtQFWAXsBbygAAf8BfwF4AUoBFgERAVcBGQFXAR0BVwEdAVcBHQE3ARUBFgERARcBEQEX
ARUBGAEVATgBFQE4ARUBOQEVATkBFQF6AR0B+wEtARwBMgH8AS0B/AEtARwBMgEcATIBHAEyARwBLgEd
AS4BHQEuAdwBJQGZAU4BWgFrHgAB9wFeAZQBUgE5AT4B/AEtAfsBLQH7AS0B2gEtAdoBKQHaASkB2QEp
AfkBLQH5AS0BuQEpAZgBJQGYASUBuAEpAbgBKQGXASEBdwEhAXYBIQF2ASEBdgEhAXYBHQG2ASkBlAFS
AVkBawEQAT4BnAFzMAABWgFrAb0BcwGcAXMB/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwH/
AX8B/wF/ATkBZwH4AV4BWgFrAdYBWgH3AV4BtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBMQFGAb0BdxwA
ATkBZwEIASEBawEtARABQgEYAWMB9wFeAfcBXgEYAWMBGAFjATkBZwE5AWcBOAFnAfgBYgHyARwBdgEt
AbcBMQHUARABMgEAAVMBAAFUAQABVQEAAVYBAAF3AQABeQEAAXoBAAF7AQABXQEdAd8BUgH/AVYB/wFW
Af8BVgH/AVYBHwFXAR8BWwEfAVsBHwFbAR8BWwE/AVsB/wFSAf0BVgF7AXMB1gJaAWsqAAHYAVYBNgEZ
AXcBHQF3ASEBdwEhAXcBIQE3ARkBFwEVATcBFQE4ARUBOAEVATgBFQE5ARUBOQEVAVoBGQG7ASUBHAE2
ATwBNgE8ATYBPAE2AV0BOgFdAToBPQE2AT0BNgE9ATYBPQEyAf0BKQF6AUYBOAFnAd4BexwAAfcBXgGU
AVIBWgFCATwBNgEcATYB+wExAfsBLQH6AS0B2gEtAfoBLQH6ATEB+gEtAdkBKQG4ASUBuAElAdkBKQHY
ASkBmAElAZcBIQGXASEBdwEhAZcBIQF3ASEB1gEtAZQBUgFZAWsBEAFCAZ0BczAAAVoBawGcAXMBnAFz
Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwE5AWcB9wFeAVoBawHWAVoB9wFe
AbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWATEBRgG9AXccAAGcAXMBrQE1Ae8BPQH2AV4BewFvATkBZwEY
AWMBGAFjARgBYwE5AWcBOQFnATkBZwEYAWMBMgEhAZYBLQGWAS0BcwEEATMBAAFVAQABVgEAAXcBAAF4
AQABegEAAXsBAAGcAQABnQEAAd4BLQEfAVsBHwFfAR8BWwEfAV8BPwFfAT8BXwE/AV8BPwFfAT8FXwE/
AVcB/QFSAXsBcwHWAVoBGAFjKgABOgFjAVYBHQF4ASEBmAElAZgBJQF4ASEBNwEZATcBGQE4ARkBOAEZ
AVgBGQFZARkBWQEZAVoBGQF6AR0B2wEtAVwBPgFcAT4BXQE+AX0BPgF9AT4BfQE+AV0BOgFdAToBXQE6
AV0BOgE9ATIBewE+AfgBXgG9AXccAAHWAVoBlAFSAXoBQgFdAToBXAE6ATwBOgE8ATYBGwE2ARsBMgEb
ATYBGwE2AfoBMQHZASkBuQEpAdkBKQHZAS0B2QEtAbgBJQGYASUBmAElAbgBJQG4ASUBuAElAdcBMQGU
AU4BOQFrAREBQgGcAXMwAAFaAWsBnAFzAZwBcwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/
Af8BfwH/AX8BOQFnAfcBXgFaAWsB1gFaAfcBXgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgExAUYBvQF3
HgAB3gF7Ad4BewIAAd0BewG9AXcBnAF3AXsBcwF6AW8BWgFrATkBZwE5AWcBOAFnAXMBLQGWAS0BNgEh
ATMBAAFUAQABVQEAAVcBAAF4AQABeQEAAXoBAAGbAQABnAEAAb0BAAFfAT4BPwFjAT8BYwE/AWMBXwFj
AV8BYwFfAWMBXwFjAV8BYwFfAWMBfwFnAX8BZwFfAWMB3QFSAXwBbwH3AV4B9wFeKgABewFvAZYBJQGY
ASUB2AEtAbgBLQF4ASEBNwEZATgBGQFYARkBWAEdAVkBHQFZAR0BegEdAXoBHQF7ASEBHAE2AX0BQgF9
AUIBfQFCAZ0BRgGdAUYBnQFCAZ0BQgF+AUIBfgE+AX0BPgF+AToBWwE6ARgBYwF8AW8cAAHWAVoBtQFW
AXsBQgFdAT4BXQE+AVwBPgFcAToBPAE6AVwBPgFcAT4BWwE+ATsBNgEaATIB+gExARoBMgEaATYBGgE2
AfkBLQHZAS0B2QEtAdkBLQHZAS0B2QEpAfcBMQGUAVIBOQFrATEBQgGcAXMwAAFaAWsBnAFzAZwBcwH/
AX8B/wF/Af8BfwHeAXsBWwFrAb4BdwH/AX8B/wF/Af8BfwH/AX8BOQFnAfcBXgFaAWsB1gFaAfcBXgG1
AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgExAUYBvQF3KgAB3gF7Ad0BewG9AXcBnAFzAXsBbwFZAWsB1AE1
AVYBJQG0ARABMwEAAVUBAAFWAQABdwEAAXgBAAF5AQABegEAAZsBAAGdAQAB/gEIAb8BTgF/AWcBXwFn
AV8BZwF/AWcBfwFnAX8BZwF/AWcBfwFnAX8BawF/AWsBnwFrAX8BZwH+AVIBfAFvATgBZwH3AV4qAAG8
AXcB1gExAZgBKQH5ATEB2QEtAVcBIQFYAR0BWAEdAVgBHQF5AR0BeQEdAXoBHQF7ASEBewEdAbwBJQFd
AT4BnQFKAb4BSgG+AUoBvgFKAb4BSgG+AUYBvgFGAb4BRgG+AUYBvgFCAZ4BQgFcAToBGQFfAVoBaxwA
AdYBWgG1AVYBewFGAV0BPgFdAT4BXQE+AVwBPgFcAT4BfAFCAXwBQgFcAT4BOwE6ARsBNgEbATYBOwE6
ATsBOgEaATYB+gExAfoBLQH6AS0B+QEtAdkBLQHaAS0B+AE1AZQBUgE5AWsBMQFGAZwBczAAAVoBawGd
AXMBnAFzAf8BfwH/AX8B3gF7AS8BOgFpAS4BsAFGAd4BewH/AX8B/wF/Ad4BewEYAWMBGAFjAVoBawHW
AVoB9wFeAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWATEBRgG9AXcyAAHeAXsBegFvARUBQgHUARQBUwEA
AVQBAAFVAQABVgEAAXcBAAF4AQABegEAAZsBAAGcAQABfQEAAV4BGQEfAV8BfwFrAX8BawF/AWsBfwFr
AX8BawGfAWsBnwFrAZ8BawGfAW8BnwFvAZ8BbwGfAW8BHwFXAXwBbwFaAWsBtQFWKgAB3QF7ATcBQgG4
ASkBGQE2AbgBKQFXAR0BWAEdAXkBIQF5ASEBegEhAZoBIQGbASEBnAEhAZwBIQHdASkBngFGAd4BTgHe
AU4B3gFSAd4BTgHeAU4B3gFOAd4BSgHeAUoB3gFKAd4BSgG+AUYBfQE6AfkBVgE5AWccAAHWAVoB1gFa
AXsBRgF+AUIBfQFCAX0BQgF9AUIBfQFCAX0BRgF9AUIBXAE+ATwBOgE7AToBOwE6ATsBOgE7AToBGwE2
ARoBMgH6ATEB+gExAfoBMQH6ATEB+gEtAfgBNQGVAVIBOQFnATEBRgGcAXMwAAFaAWsBvQF3AZwBcwH/
AX8B/wF/ATkBZwEJASYBkAFXAQ4BTwHWAVYBfAFvAVoBawE5AWcBOQFnATkBZwFaAWsB1gFaAfcBXgG1
AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgExAUYBvQF3NAABmwFzAXYBTgFSAQABMwEAAVQBAAFVAQABVwEA
AXgBAAF5AQABegEAAZsBAAGcAQABnQEAAb8BKQF/AWsBnwFvAZ8BbwGfAW8BnwFvAZ8BbwGfAW8BnwFv
AZ8BbwG/AW8BvwFzAb8BcwG/AXMBPwFfAXwBawGcAXMBlAFSAd4BeygAAf4BfwF3AUoBuAEtARoBNgGY
ASkBeAEhAXkBIQF5ASEBmgEhAZoBIQGbASUBvAElAbwBJQG9ASUBHQEyAb4BTgH+AVYB/gFWAf4BVgH+
AVIB3gFOAd4BUgH+AVIB/gFOAd4BTgHeAU4B3gFKAZ0BPgHZAVIBOQFnGgAB3gF7AdUBWgHWAVoBnAFG
AX4BQgGdAUYBnQFGAZ0BRgGdAUoBnQFKAZ0BRgF8AUIBXAE+AVwBOgFcAT4BXAE+AVwBPgE7AToBGwE2
ARsBMgEbATIBGgEyAfoBMQH7ATEBGAE2AbUBVgE5AWcBMQFGAZwBczAAAVoBawHeAXsBvQF3AZwBcwGc
AXMBGQFnAU4BOgFyAVsBrAE+AfcBXgFaAWsBWgFrAVoBawFaAWsBWgFrAXsBbwHWAVoB9wFeAbUBVgG1
AVYBtQFWAbUBVgG1AVYBtQFWAVIBSgG9AXc0AAGbAXMBtwFWAVIBAAEzAQABVAEAAVUBAAF3AQABeAEA
AXkBAAF6AQABmwEAAZ0BAAGeAQABXwE+AZ8BcwGfAXMBnwFvAb8BcwG/AXMBvwFzAb8BcwG/AXMBvwFz
Ab8BcwG/AXMBvwFzAb8BbwE/AVsBXQFnAb0BdwGUAVIBvQF3KgABuAFWAdgBLQH5ATEBmAElAXgBIQGZ
ASUBmgElAZoBJQG7ASUBuwEpAbwBKQG8ASUBvQElAV4BOgH+AVYBHgFbAR4BWwEeAVcB/gFWAf4BUgH+
AVIB/gFSAf4BUgH+AVIB/gFSAf4BTgG+AUYB2gFOARcBYwHeAXsYAAHeAXsBtQFWAfcBXgGcAUoBngFG
AZ0BRgG+AUoBvgFKAb4BTgG+AUoBnQFKAX0BQgF8AUIBXAE+AXwBPgF8AUIBXAE+ATwBOgEbATYBGwE2
ARsBNgEbATYBGwEyARsBMgEYAToBtQFWATkBZwFSAUYBnAFzMAABWgFrAd4BewHeAXsB3gF7Ad4BewHe
AXsBOQFnAXEBQgHVAVYBnAFzAXsBbwF7AW8BewFvAXsBbwF7AW8BewFvAdYBWgH3AV4BtQFWAbUBVgG1
AVYBtQFWAbUBVgG1AVYBUgFKAb0BdzQAAZwBcwH3AV4BkgEIATMBAAFVAQABVgEAAXcBAAF4AQABeQEA
AXsBAAGcAQABnQEAAd4BBAHfAVIBvwF3Ab8BcwG/AXMBnwFvAZ8BbwF/AWsBfwFnAV8BYwE/AV8BPwFb
AR4BVwH+AVYB/QFWAdwBTgFcAWcB3gF/AZQBUgGcAXMqAAEZAWMB1wExAbkBLQF4ASUBmQElAZkBJQGa
ASUBuwEpAbsBKQHcAS0B3AEpAd0BKQHdAS0BngFGAT8BXwE+AV8BPgFfAR4BWwEeAVsBHgFXAR4BVwEe
AVcBHgFXAR4BVwEeAVcB/gFSAd4BSgG7AUoB9wFeAb0BdxgAAd4BewGUAVYB+AFeAb0BSgGeAUYBvgFK
Ad4BTgHeAVIB3gFSAd4BTgG9AUoBnQFGAZ0BRgF9AUIBfQFCAX0BQgFcAT4BPAE6ATwBOgE8ATYBPAE2
ARwBNgEcATYBHAE2ARkBOgG1AVYBOQFnAVIBSgGcAXMwAAF7AW8B3gF7Af8BfwH/AX8B3gF7Ad4BewHe
AXsBvgF7Ab4BewGcAXMBewFvAXsBbwF7AW8BewFvAXsBbwGcAXMBtQFWARgBYwG1AVYBtQFWAbUBVgG1
AVYBtQFWAbUBVgFSAUoBvQF3NAABvQF3ARgBYwHSARQBNAEAAVUBAAFWAQABdwEAAXgBAAF6AQABewEA
AXwBAAF9AQAB3wEEAZ8BRgEfAVsB/wFWAd8BTgG+AUoBvAFKAbsBTgHbAVIB+wFWAfsBVgEaAV8BOgFn
AXsBawGcAXMBvQF3Ad4BewIAAVoBawHeAXsqAAF7AW8B1wExAZgBJQGYASUBmQElAboBKQG6ASkB2wEt
AdwBLQHcAS0B3QEtAd0BLQEeATYB3wFSAV8BZwFfAWMBPgFjAT4BXwE+AV8BPgFbAR4BWwEeAVsBHgFb
AR4BWwEeAVcBHgFXAf4BUgG7AUYB9wFeAZwBcxgAAd4BewGUAVYBGAFfAb0BTgG+AUoB3gFOAf4BUgH+
AVYB/gFWAd4BUgHeAU4BvQFKAZ0BSgGdAUYBnQFGAZ0BRgF9AUIBXAE6ATwBOgE8AToBPAE2ATwBNgE8
ATYBPAE2ARkBOgG1AVYBOQFnAVIBSgGcAXMwAAF7AW8BvQF3Ab0BdwG9AXcBvQF3AZwBcwGcAXMBnAFz
Ab0BdwG9AXcBvQF3Ad4BewHeAXsB3gF7Af8BfwH/AX8B1gFaAfcBXgEYAWMB9wFeAdYBWgG1AVYBtQFW
AbUBVgFSAUoBvQF3NAAB3gF7ATgBZwEzASEBFAEAATUBAAE2AQABVgEAAXcBAAGYAQQBuAEIARkBFQFa
AR0BugEtAXoBRgG5AVIB2QFaARoBXwEaAWMBOgFnAVoBawF7AW8BnAF3AbwBdwG9AXcB3gF7Ad4BezYA
AZwBcwH2ATUBeAElAZkBKQG5ASkBugEpAdsBLQHbATEB/AExAfwBMQH9ATEB/QExAV4BPgEfAV8BfwFr
AV8BZwFeAWMBXgFjAV4BYwE+AV8BPgFfAT4BWwEeAVsBHgFXAf4BVgH9AVIB3QFKAXsBPgH4AloBaxgA
Ab0BdwG0AVYB+AFeAd0BTgHeAU4B/gFWAf4BVgEeAVsB/gFWAf4BVgHeAVIB3gFOAb4BTgG+AUoBvQFK
AZ0BRgF9AUIBXQE+AV0BOgE8AToBPAE6ATwBOgE8AToBPQE2ATkBOgHWAVoBOQFnAVIBSgGcAXMwAAGc
AXMB3gF7Ad4BewHeAXsB3gF7Ad4BewH/AX8B/wF/Af8BfwHeAXsB3gF7Ab0BdwG9AXcBnAFzAXsBbwGc
AW8BWgFrAdYBWgG1AVYBtQFWAdYBWgH3AWIB9wFeAfcBXgFSAUoBvQF3NgABOQFnAdMBOQHxARgBdAEp
AbUBMQH1ATkBNAFGAZUBUgH3AV4BOAFnAVkBawF5AW8BegFzAZwBcwG8AXcBvQF3Ab0BdwHeAXtEAAHd
AXsBNgFCAZgBJQGZASkBuQEpAdoBLQHbATEB+wExAfwBMQH9ATEBHQE2AR4BNgF/AUYBXwFjAX8BawF/
AWcBXwFnAT8BXwE+AVsBHgFXAf0BUgHcAVIBuwFOAboBTgHaAVIB2QFWAdgBVgH4AVoBOQFjARgBYxgA
Ab0BdwG0AVYB+AFeAd0BUgH+AVIB/gFWAR4BWwEeAVsBHgFbAf4BVgH+AVYB3gFSAd4BUgHeAU4BvgFK
AZ0BRgF9AUIBXQE+AV0BPgFdAToBXQE6AV0BOgE9AToBPQE6ATkBOgG2AVYBGAFjAVIBSgGcAXMwAAG9
AXcBvQF3Ad4BewHeAXsB3gF7Ab0BdwGcAXMBnAFzAXsBbwFaAWcBGAFjAfcBXgHXAVoB1gFaAbYBVgHW
AVYB1wFaAfgBXgEYAWMB9wFeAdYBVgGUAVIBcwFOAZQCUgFKAb0BdzYAATkBZwH3AV4B9gFiATgBawF6
AW8BmwFzAZwBcwG8AXcBvQF7Ad4Be1QAAf4BfwF2AUoBmAEpAbkBKQHaAS0B2gExAfsBMQH8ATUBHAE2
AR0BNgEeATYBHgE2AZ4BRgE+AV8BPgFfARwBWwH7AVYB+wFaAfsBWgH6AVoB+QFeAToBZwFaAWsBWgFr
AVoBbwGbAXMBvAF3AbwBdwGcAXMB3gF7GAABvQF3AbUBVgH4AV4B3QFSAf4BVgEeAVsBHgFbAR4BWwEe
AVsBHgFbAR4BVwH+AVYB/gFSAd4BUgG+AU4BngFGAX0BQgF9AT4BXQE+AV0BPgFeAToBXgE6AT0BOgE+
ATYBGQE6AbUBVgEYAWMBUgFKAZwBczAAAd4BewGcAXMBnAFzAXwBbwF7AW8BewFvATkBZwH3AV4BtQFW
AbUBUgGUAVIBlAFSAZQBUgGUAVIBlQFSAZUBUgG1AVIBtQFWAdYBVgH3AVoBGAFjARgBYwH3AV4BlAFS
AdYBWgHeAXs2AAHeAXsB3gF7ZgABtwFSAbgBKQG5AS0B2gEtAdoBMQH7ATUBGwE6ARsBOgE7AT4BewFG
AbsBTgH7AVoBGgFjAVsBZwF7AWsBewFvAXsBbwGcAXMBvQF3Ab0BewHdAXsB3gF7JgABvQF3AbUBVgH4
AVoB/gFSAf4BVgEeAVsBHwFfAT8BXwE/AV8BHwFfAR8BWwH+AVYB/gFSAd4BTgG9AU4BnQFGAXwBQgFc
AUIBWwE+AToBPgE4AToBOAE+AVgBQgE3AUIBNAFCAZQBUgH3AWIBUgFKAZwBczgAAd4BewG9AXcBfAFv
AVoBZwH3AV4BtgFWAbUBVgG1AVYBtgFWAdYBWgHWAVoB1wFaAfcBXgE5AWMBOQFnAVoBawF7AW8BnAFz
Ab0BdwHeAXukAAH4AV4B1gE1ARcBPgFYAUYBmQFOAdkBVgEaAWMBWwFrAXsBbwGcAXMBvQF3Ad0BewHd
AXsB3gF7Ad4BezQAAb0BdwG1AVYB+QFaAf4BUgH9AVYB3AFWAdsBUgHbAVYB2gFWAdoBVgHZAVIBuAFS
AZcBTgF2AU4BdQFKAXQBSgF0AU4BdAFOAZQBUgGUAVIBlAFSAZMBUgGTAVIBkwFSAZQBUgGUAVIB9wFe
AVIBSgGcAXNCAAHeAXsBnAFzAXsBbwGcAXMBvQF3Ad4Be7YAAZwBcwFaAWsBnAFzAb0BdwHeAXsB/gF/
Af4Bf0QAAZwBdwG1AVYBdAFOAXQBTgF0AU4BcwFOAVMBSgFSAUoBUgFKAVIBSgFSAUoBUgFKAXIBTgGT
AVIBlAFSAZQBUgG0AVYBtQFWAbUBVgHWAVoB1gFaAdYBWgHWAVoB1gFaAdYBWgGUAVIB1gFaAe8BPQG9
AXf/AFcAAb0BdwG1AVYBUgFKAVIBSgFSAUoBUgFKAXMBTgFzAU4BlAFSAZQBUgGUAVIBlAFSAbUBVgG1
AVYBtQFWAbUBVgHWAVYB1gFaAdYBWgHWAVoB1gFaAfcBXgH3AV4B9wFeAfcBWgG1AVYB8AE9AfABPf8A
WQABvQF3AfcBXgHWAVoBtQFWAZQBUgGUAVIBlAFSAbUBUgGVAVIBlAFSAdYBVgGUAU4B7wE9Ae8BPQGU
AVIBGAFjAfcBWgHWAVoB9wFaAfcBWgH3AV4B+AFeAfgBWgHXAVoB1wFWAdcBWgG2AVYBnQFz/wBbAAF7
AWsBWwFnAVsBZwE6AWMBOQFjARkBYwEZAWMBGQFjARgBXwF7AWsBlAFOAYwBMQHOATkBMgFGAVoBZwEZ
AV8B+AFeAfgBXgH4AVoB1wFaARkBXwEZAWMBWgFnAZwBcwHeAXv/AGEAAb0BdwF8AW8BewFrAVsBawFb
AWsBWgFnAToBZwE6AWMBGgFjARkBXwH4AVoB+AFeARkBYwE6AWcBWgFnAVsBawF8AW8BvQF3Ad4BewHe
AXv/AHUAAd4BewHeAXsB3gF7Ad4Be/8A/wAuAAFCAU0BPgcAAT4DAAEoAwAByAMAAZYDAAEBAQABAQUA
AWgBEBYAA///AP8A/wD/AP8AfgAZ/wMAGf8DABb/AcAC/wMAFf8B+AEAAQcB/wMAFf8B4AEAAQEB/wMA
Dv8B8wb/AcACAAH/AwAO/wHxBv8BgAIAAT8DAA7/AeABfwX/AwABPwMADv8BwAE/Bf8DAAE/AwAO/wGA
AQ8F/wMAAT8DAAP/AYMK/wEAAQcF/wMAAT8DAAL/AfABAAX/AfgBfwL/Af4BAAEBBf8DAAEPAwAC/wIA
AT8D/wH+AQABHwL/AfwCAAT/AeADAAEHAwAB/wHwAgABHwP/AcABAAEHAv8B+AIAAX8C/wH8BAABBwMA
Af8BgAIAAQcC/wH+AgABAQL/AfACAAEfAv8BwAQAAQcDAAH4AwABAwL/AfADAAF/Af8B8AIAAQ8B/wH8
BQABBwMAAfAEAAL/AYADAAE/Af8B4AIAAQMB/wH8BQABAwMAAfAEAAF/AfwEAAEPAf8BwAIAAQEB/wH8
BQABAwMAAeAEAAEfAfgEAAEHAf8BgAMAAX8B/AUAAQMDAAHgBAABDwHwBAABAQH/BAABPwH8BQABAwMA
AeAEAAEHAfAFAAH+BAABDwH8BQABAwMAAeAEAAEBAfAFAAF8BAABBwH8BQABAwMAAeAFAAHwBQABOAQA
AQEB/AUAAQMDAAHgBQABcAUAARgFAAH8BQABAwMAAeAFAAFwBQABEAUAATwFAAEDAwAB4AUAAXwFAAEQ
BQABHgUAAQEDAAH4BAABAQH/BQABEAUAAQ4FAAEBAwAB/gQAAQEB/wHABAABMAUAAQYFAAEBAwAB/wHA
AwABAQH/AfgEAAF4BQABBgUAAQEDAAH/AfgDAAEDAv8EAAH8BQABBgUAAQEDAAL/AwABBwL/AeACAAF/
Af8FAAECBQABAQMAAv8B4AIAA/8B/AEAAQ8C/wHABAABAgUAAQEDAAL/AfwBAAE/BP8BhwP/AfAEAAED
CQAN/wH8BAABAwkADv8EAAEHCQAO/wHwAwABDwkADv8B8AMAAR8JAA7/AeADAAE/AYAIAA7/AcADAAH/
AfgIAA7/AcADAAF/Af8BwAcADv8BwQFAAgABfwH/AcAHAA7/AeMBwAIAAv8B4AcAD/8BwAEOAQAC/wHg
BwAP/wHhAf8BgwL/AeADAAEBAwAR/wHnAv8B4AIAAQEB/wMAFP8B4AEAAQEC/wMAFP8B4AEHA/8DABT/
AeME/wMAGf8DABn/AwAZ/wMAD/8B+AEDCP8DAA//AgABPwf/AwAO/wH4AgABHwf/AwAD/wHAAR8E/wHw
AX8D/wHwAgABBwT/AY8C/wMAAv8B/gEAAQME/wGAAR8D/wHAAgABAwP/AfgBBwL/AwAC/wH4AgABBwL/
AfwBAAEPA/8BwAIAAQED/wHAAQEC/wMAAv8B8AIAAQEC/wHAAQABAwP/AYADAAL/AfwCAAL/AwAC/wHw
AwAB/wH+AgABAQP/BAABfwH/AeACAAE/Af8DAAH4AQcB4AMAAX8B4AMAA/8EAAE/Af8BwAIAAR8B/wMA
AfABAAHgAwABfwQAAT8C/wQAAR8B/wHAAgABDwH/AwAB4AEAATADAAH4BAABHwL/BAABHwH/AeACAAEH
Af8DAAHgBAABAQHwBAABBwH/Af4EAAEfAf8B4AIAAQEB/wMAAeAEAAEPAeAEAAEDAf8B/gMAAQEC/wHg
AwAB/wMAAeAEAAEPAfAEAAEBAf8B/gMAAR8C/wHgAwABfwMAAeAEAAEPAfgFAAH/Af4DAAEfAv8B4AMA
AR8DAAHgBAABDwH+BAABAQH/Af4DAAEfAv8B4AMAAQ8DAAHgBAABBwH/AYADAAEBAf8B/gMAAR8C/wHg
AwABPwMAAeAEAAEHAf8B4AMAAQEB/wH+AwABHwL/AeACAAEHAf8DAAHgBAABBwH/AfgDAAEBAf8B/gMA
AR8C/wHgAgABBwH/AwAB4AQAAQcB/wH+AwABAQH/Af4DAAEfAv8B4AIAAQcB/wMAAeAEAAEHAv8B8AIA
AQEB/wH+AwABHwL/AeACAAEHAf8DAAHgBAABBwL/AcADAAH/Af4DAAEfAv8B4AIAAQcB/wMAAeAEAAEH
Av8BgAMAAf8B/gMAAR8C/wHgAgABBwH/AwAB4AQAAQcC/wHAAwAB/wH+AwABHwL/AeACAAEHAf8DAAHg
BAABBwL/AcADAAH/Af4DAAEfAv8B4AIAAQcB/wMAAeAEAAEDAv8BwAMAAf8B/gMAAR8C/wHgAgABBwH/
AwAB4AQAAQMC/wHAAwAB/wH+AwABHwL/AeACAAEHAf8DAAHgBAABAwL/AcADAAH/Af4DAAEfAv8B4AIA
AQcB/wMAAeAEAAEDAv8B4AMAAX8B/gMAAR8C/wHgAgABBwH/AwAB4AQAAQMC/wHgAwABfwH+AwABHwL/
AeACAAEHAf8DAAHyBAABAwL/AeADAAF/Af4DAAEfAv8B4AIAAQcB/wMAAf8BwAMAAQMC/wHgAwABfwH+
AwABHwL/AeACAAEHAf8DAAH/AfwDAAEDAv8B4AMAAX8B/gMAAR8C/wHgAgABBwH/AwAB/wH+AwABAQL/
AeADAAF/AfwDAAEfAv8B4AIAAQcB/wMAAf8B/gMAAQEC/wHwAwABPwH8AwABHwL/AeACAAEHAf8DAAH/
Af4DAAEBAv8B8AMAAT8B/AMAAR8C/wHgAgABBwH/AwAB/wH+AwABCQL/AfADAAE/AfwDAAEfAv8B4AIA
AQcB/wMAAf8B/gMAAX8C/wHwAwABPwH8AwABHwL/AeACAAEHAf8DAAL/AgABPwP/AfADAAE/AfwDAAEf
Av8B4AIAAQcB/wMAAv8BAAE/BP8B8AMAAT8B/AMAAR8C/wHgAgABBwH/AwAC/wE/Bf8B+AIAAR8B/wH8
AwABHwL/Af4CAAEfAf8DAAj/AfgBAAEPAv8B/AMAAR8D/wHwAT8C/wMACP8B+AEPA/8B/AMAAR8H/wMA
Df8B/AMAAT8H/wMADf8B/AMAAT8H/wMADf8B/gMACP8DAA7/AgABDwj/AwAO/wH8AT8J/wMAGf8DAAs=
</value>
</data>
<metadata name="mainContextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>156, 17</value>
</metadata>
<data name="statsToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>108, 22</value>
</data>
<data name="statsToolStripMenuItem.Text" xml:space="preserve">
<value>Stats...</value>
</data>
<data name="mainContextMenuStrip.Size" type="System.Drawing.Size, System.Drawing">
<value>109, 26</value>
</data>
<data name="&gt;&gt;mainContextMenuStrip.Name" xml:space="preserve">
<value>mainContextMenuStrip</value>
</data>
<data name="&gt;&gt;mainContextMenuStrip.Type" xml:space="preserve">
<value>System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<metadata name="autoExitTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>334, 17</value>
</metadata>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>6, 13</value>
</data>
<data name="$this.Size" type="System.Drawing.Size, System.Drawing">
<value>419, 55</value>
</data>
<data name="&gt;&gt;deviceImageList.Name" xml:space="preserve">
<value>deviceImageList</value>
</data>
<data name="&gt;&gt;deviceImageList.Type" xml:space="preserve">
<value>System.Windows.Forms.ImageList, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;statsToolStripMenuItem.Name" xml:space="preserve">
<value>statsToolStripMenuItem</value>
</data>
<data name="&gt;&gt;statsToolStripMenuItem.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;autoExitTimer.Name" xml:space="preserve">
<value>autoExitTimer</value>
</data>
<data name="&gt;&gt;autoExitTimer.Type" xml:space="preserve">
<value>System.Windows.Forms.Timer, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>MapUserControl</value>
</data>
<data name="&gt;&gt;$this.Type" xml:space="preserve">
<value>System.Windows.Forms.UserControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

61
src/MappingHelpForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,61 @@
namespace MeshCentralRouter
{
partial class MappingHelpForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MappingHelpForm));
this.helpPictureBox = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.helpPictureBox)).BeginInit();
this.SuspendLayout();
//
// helpPictureBox
//
resources.ApplyResources(this.helpPictureBox, "helpPictureBox");
this.helpPictureBox.Image = global::MeshCentralRouter.Properties.Resources.HelpRelayMap;
this.helpPictureBox.Name = "helpPictureBox";
this.helpPictureBox.TabStop = false;
//
// MappingHelpForm
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.helpPictureBox);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "MappingHelpForm";
((System.ComponentModel.ISupportInitialize)(this.helpPictureBox)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.PictureBox helpPictureBox;
}
}

37
src/MappingHelpForm.cs Normal file
View File

@@ -0,0 +1,37 @@
/*
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.IO;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
namespace MeshCentralRouter
{
public partial class MappingHelpForm : Form
{
public MappingHelpForm()
{
InitializeComponent();
Translate.TranslateControl(this);
// Load customizations
FileInfo selfExe = new FileInfo(Assembly.GetExecutingAssembly().Location);
try { helpPictureBox.Image = (Bitmap)Image.FromFile(Path.Combine(selfExe.Directory.FullName, @"customization\help.png")); } catch (Exception) { }
}
}
}

1859
src/MappingHelpForm.resx Normal file

File diff suppressed because it is too large Load Diff

187
src/MappingStats.Designer.cs generated Normal file
View File

@@ -0,0 +1,187 @@
namespace MeshCentralRouter
{
partial class MappingStats
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MappingStats));
this.okButton = new System.Windows.Forms.Button();
this.label12 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.outRatioLabel = new System.Windows.Forms.Label();
this.inRatioLabel = new System.Windows.Forms.Label();
this.label10 = new System.Windows.Forms.Label();
this.label11 = new System.Windows.Forms.Label();
this.kvmCompOutBytesLabel = new System.Windows.Forms.Label();
this.kvmCompInBytesLabel = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.kvmOutBytesLabel = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.kvmInBytesLabel = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.refreshTimer = new System.Windows.Forms.Timer(this.components);
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// label12
//
resources.ApplyResources(this.label12, "label12");
this.label12.Name = "label12";
//
// groupBox1
//
resources.ApplyResources(this.groupBox1, "groupBox1");
this.groupBox1.Controls.Add(this.outRatioLabel);
this.groupBox1.Controls.Add(this.inRatioLabel);
this.groupBox1.Controls.Add(this.label10);
this.groupBox1.Controls.Add(this.label11);
this.groupBox1.Controls.Add(this.kvmCompOutBytesLabel);
this.groupBox1.Controls.Add(this.kvmCompInBytesLabel);
this.groupBox1.Controls.Add(this.label2);
this.groupBox1.Controls.Add(this.label12);
this.groupBox1.Name = "groupBox1";
this.groupBox1.TabStop = false;
//
// outRatioLabel
//
resources.ApplyResources(this.outRatioLabel, "outRatioLabel");
this.outRatioLabel.Name = "outRatioLabel";
//
// inRatioLabel
//
resources.ApplyResources(this.inRatioLabel, "inRatioLabel");
this.inRatioLabel.Name = "inRatioLabel";
//
// label10
//
resources.ApplyResources(this.label10, "label10");
this.label10.Name = "label10";
//
// label11
//
resources.ApplyResources(this.label11, "label11");
this.label11.Name = "label11";
//
// kvmCompOutBytesLabel
//
resources.ApplyResources(this.kvmCompOutBytesLabel, "kvmCompOutBytesLabel");
this.kvmCompOutBytesLabel.Name = "kvmCompOutBytesLabel";
//
// kvmCompInBytesLabel
//
resources.ApplyResources(this.kvmCompInBytesLabel, "kvmCompInBytesLabel");
this.kvmCompInBytesLabel.Name = "kvmCompInBytesLabel";
//
// label2
//
resources.ApplyResources(this.label2, "label2");
this.label2.Name = "label2";
//
// groupBox2
//
resources.ApplyResources(this.groupBox2, "groupBox2");
this.groupBox2.Controls.Add(this.kvmOutBytesLabel);
this.groupBox2.Controls.Add(this.label3);
this.groupBox2.Controls.Add(this.kvmInBytesLabel);
this.groupBox2.Controls.Add(this.label4);
this.groupBox2.Name = "groupBox2";
this.groupBox2.TabStop = false;
//
// kvmOutBytesLabel
//
resources.ApplyResources(this.kvmOutBytesLabel, "kvmOutBytesLabel");
this.kvmOutBytesLabel.Name = "kvmOutBytesLabel";
//
// label3
//
resources.ApplyResources(this.label3, "label3");
this.label3.Name = "label3";
//
// kvmInBytesLabel
//
resources.ApplyResources(this.kvmInBytesLabel, "kvmInBytesLabel");
this.kvmInBytesLabel.Name = "kvmInBytesLabel";
//
// label4
//
resources.ApplyResources(this.label4, "label4");
this.label4.Name = "label4";
//
// refreshTimer
//
this.refreshTimer.Interval = 500;
this.refreshTimer.Tick += new System.EventHandler(this.refreshTimer_Tick);
//
// MappingStats
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.okButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "MappingStats";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.KVMStats_FormClosing);
this.Load += new System.EventHandler(this.KVMStats_Load);
this.groupBox1.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.Label label12;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label outRatioLabel;
private System.Windows.Forms.Label inRatioLabel;
private System.Windows.Forms.Label label10;
private System.Windows.Forms.Label label11;
private System.Windows.Forms.Label kvmCompOutBytesLabel;
private System.Windows.Forms.Label kvmCompInBytesLabel;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.Label kvmOutBytesLabel;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label kvmInBytesLabel;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Timer refreshTimer;
}
}

68
src/MappingStats.cs Normal file
View File

@@ -0,0 +1,68 @@
/*
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.Windows.Forms;
namespace MeshCentralRouter
{
public partial class MappingStats : Form
{
public MapUserControl mapControl;
public MappingStats(MapUserControl mapControl)
{
this.mapControl = mapControl;
InitializeComponent();
Translate.TranslateControl(this);
}
private void refreshTimer_Tick(object sender, EventArgs e)
{
kvmInBytesLabel.Text = string.Format(((mapControl.mapper.bytesToClient == 1) ? Translate.T(Properties.Resources.OneByte) : Translate.T(Properties.Resources.XBytes)), mapControl.mapper.bytesToClient);
kvmOutBytesLabel.Text = string.Format(((mapControl.mapper.bytesToServer == 1) ? Translate.T(Properties.Resources.OneByte) : Translate.T(Properties.Resources.XBytes)), mapControl.mapper.bytesToServer);
kvmCompInBytesLabel.Text = string.Format(((mapControl.mapper.bytesToClientCompressed == 1) ? Translate.T(Properties.Resources.OneByte) : Translate.T(Properties.Resources.XBytes)), mapControl.mapper.bytesToClientCompressed);
kvmCompOutBytesLabel.Text = string.Format(((mapControl.mapper.bytesToServerCompressed == 1) ? Translate.T(Properties.Resources.OneByte) : Translate.T(Properties.Resources.XBytes)), mapControl.mapper.bytesToServerCompressed);
if (mapControl.mapper.bytesToClient == 0) {
inRatioLabel.Text = "0%";
} else {
inRatioLabel.Text = (100 - ((mapControl.mapper.bytesToClientCompressed * 100) / mapControl.mapper.bytesToClient)) + "%";
}
if (mapControl.mapper.bytesToServer == 0) {
outRatioLabel.Text = "0%";
} else {
outRatioLabel.Text = (100 - ((mapControl.mapper.bytesToServerCompressed * 100) / mapControl.mapper.bytesToServer)) + "%";
}
}
private void KVMStats_FormClosing(object sender, FormClosingEventArgs e)
{
refreshTimer.Enabled = false;
}
private void KVMStats_Load(object sender, EventArgs e)
{
refreshTimer.Enabled = true;
refreshTimer_Tick(this, null);
Text += " - " + mapControl.node.name;
}
private void okButton_Click(object sender, EventArgs e)
{
mapControl.closeStats();
}
}
}

2438
src/MappingStats.resx Normal file

File diff suppressed because it is too large Load Diff

773
src/MeshCentralServer.cs Normal file
View File

@@ -0,0 +1,773 @@
/*
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.IO;
using System.Web;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Deployment.Application;
using System.Collections.Specialized;
using System.Web.Script.Serialization;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Win32;
namespace MeshCentralRouter
{
public class MeshCentralServer
{
public Uri wsurl = null;
private string user = null;
private string pass = null;
private string token = null;
private webSocketClient wc = null;
//private System.Timers.Timer procTimer = new System.Timers.Timer(5000);
private int constate = 0;
public Dictionary<string, NodeClass> nodes = null;
public Dictionary<string, MeshClass> meshes = null;
public string disconnectCause = null;
public string disconnectMsg = null;
public bool disconnectEmail2FA = false;
public bool disconnectEmail2FASent = false;
public bool disconnectSms2FA = false;
public bool disconnectSms2FASent = false;
public X509Certificate2 disconnectCert;
public string authCookie = null;
public string rauthCookie = null;
public string loginCookie = null;
public string wshash = null;
public string certHash = null;
public string okCertHash = null;
public string okCertHash2 = null;
public bool debug = false;
public bool tlsdump = false;
public bool ignoreCert = false;
public string userid = null;
public string username = null;
public int twoFactorCookieDays = 0;
public Dictionary<string, ulong> userRights = null;
public Dictionary<string, string> userGroups = null;
private JavaScriptSerializer JSON = new JavaScriptSerializer();
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;
const MESHRIGHT_MANAGEUSERS = 2;
const MESHRIGHT_MANAGECOMPUTERS = 4;
const MESHRIGHT_REMOTECONTROL = 8;
const MESHRIGHT_AGENTCONSOLE = 16;
const MESHRIGHT_SERVERFILES = 32;
const MESHRIGHT_WAKEDEVICE = 64;
const MESHRIGHT_SETNOTES = 128;
const MESHRIGHT_REMOTEVIEWONLY = 256;
const MESHRIGHT_NOTERMINAL = 512;
const MESHRIGHT_NOFILES = 1024;
const MESHRIGHT_NOAMT = 2048;
const MESHRIGHT_DESKLIMITEDINPUT = 4096;
const MESHRIGHT_LIMITEVENTS = 8192;
const MESHRIGHT_CHATNOTIFY = 16384;
const MESHRIGHT_UNINSTALL = 32768;
*/
public static void saveToRegistry(string name, string value)
{
try { Registry.SetValue(@"HKEY_CURRENT_USER\SOFTWARE\OpenSource\MeshRouter", name, value); } catch (Exception) { }
}
public static string loadFromRegistry(string name)
{
try { return Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\OpenSource\MeshRouter", name, "").ToString(); } catch (Exception) { return ""; }
}
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;
}
}
// Parse the URL query parameters and returns a collection
public static NameValueCollection GetQueryStringParameters()
{
NameValueCollection nameValueTable = new NameValueCollection();
if (ApplicationDeployment.IsNetworkDeployed)
{
string queryString = ApplicationDeployment.CurrentDeployment.ActivationUri.Query;
nameValueTable = HttpUtility.ParseQueryString(queryString);
}
return (nameValueTable);
}
// Starts the routing server, called when the start button is pressed
public void connect(Uri wsurl, string user, string pass, string token)
{
JSON.MaxJsonLength = 217483647;
this.user = user;
this.pass = pass;
this.token = token;
this.wsurl = wsurl;
// Setup extra headers if needed
Dictionary<string, string> extraHeaders = new Dictionary<string, string>();
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.TLSCertCheck = webSocketClient.TLSCertificateCheck.Verify;
wc.Start(wsurl, okCertHash, okCertHash2);
if (debug || tlsdump) { try { File.AppendAllText("debug.log", "Connect-" + wsurl + "\r\n"); } catch (Exception) { } }
wc.debug = debug;
wc.tlsdump = tlsdump;
wc.TLSCertCheck = (ignoreCert) ? webSocketClient.TLSCertificateCheck.Ignore : webSocketClient.TLSCertificateCheck.Verify;
}
public void disconnect()
{
if (wc != null)
{
wc.Dispose();
wc = null;
if (debug || tlsdump) { try { File.AppendAllText("debug.log", "Disconnect\r\n"); } catch (Exception) { } }
}
}
public void sendCommand(string cmd)
{
if (wc != null)
{
if (debug) { try { File.AppendAllText("debug.log", "sendCommand: " + cmd + "\r\n"); } catch (Exception) { } }
wc.SendString(cmd);
}
}
public void refreshCookies()
{
if (wc != null) {
if (debug) { try { File.AppendAllText("debug.log", "RefreshCookies\r\n"); } catch (Exception) { } }
wc.SendString("{\"action\":\"authcookie\"}");
wc.SendString("{\"action\":\"logincookie\"}");
}
}
public void setRdpPort(NodeClass node, int port)
{
if (wc != null)
{
if (debug) { try { File.AppendAllText("debug.log", "SetRdpPort\r\n"); } catch (Exception) { } }
wc.SendString("{\"action\":\"changedevice\",\"nodeid\":\"" + node.nodeid + "\",\"rdpport\":" + port + "}");
}
}
public void processServerData(webSocketClient sender, string data, int orglen)
{
if (debug) { try { File.AppendAllText("debug.log", "ServerData-" + data + "\r\n"); } catch (Exception) { } }
// Parse the received JSON
Dictionary<string, object> jsonAction = new Dictionary<string, object>();
try
{
jsonAction = JSON.Deserialize<Dictionary<string, object>>(data);
} catch (Exception ex) {
if (debug) {
try {
File.AppendAllText("debug.log", "processServerData JSON Deserialize error: \r\n" + ex.ToString());
File.AppendAllText("debug.log", "Invalid data (" + data.Length + "): \r\n" + data);
} catch (Exception) { }
}
return;
}
if (jsonAction == null || jsonAction["action"].GetType() != typeof(string)) return;
try
{
string action = jsonAction["action"].ToString();
switch (action)
{
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<string, object> serverinfo = (Dictionary<string, object>)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)
{
certHash = webSocketClient.GetMeshCertHash(new X509Certificate2(sender.RemoteCertificate));
}
break;
}
case "logincookie":
{
loginCookie = jsonAction["cookie"].ToString();
if (onLoginTokenChanged != null) { onLoginTokenChanged(); }
break;
}
case "userinfo":
{
Dictionary<string, object> userinfo = (Dictionary<string, object>)jsonAction["userinfo"];
userid = (string)userinfo["_id"];
if (userinfo.ContainsKey("name")) { username = (string)userinfo["name"]; }
userRights = new Dictionary<string, ulong>();
if (userinfo.ContainsKey("links"))
{
Dictionary<string, object> userLinks = (Dictionary<string, object>)userinfo["links"];
foreach (string i in userLinks.Keys)
{
Dictionary<string, object> userLinksEx = (Dictionary<string, object>)userLinks[i];
if (userLinksEx.ContainsKey("rights"))
{
userRights[i] = ulong.Parse(userLinksEx["rights"].ToString());
}
}
}
break;
}
case "usergroups":
{
userGroups = new Dictionary<string, string>();
if (jsonAction.ContainsKey("ugroups"))
{
Dictionary<string, object> usergroups = (Dictionary<string, object>)jsonAction["ugroups"];
if (usergroups != null)
{
foreach (string i in usergroups.Keys)
{
Dictionary<string, object> usergroupsEx = (Dictionary<string, object>)usergroups[i];
if (usergroupsEx.ContainsKey("name"))
{
userGroups.Add(i, usergroupsEx["name"].ToString());
}
}
if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(false);
}
}
break;
}
case "event":
{
Dictionary<string, object> ev = (Dictionary<string, object>)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<string, object> links = ((Dictionary<string, object>)ev["links"]);
if (links.ContainsKey(userid))
{
Dictionary<string, object> urights = ((Dictionary<string, object>)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<string, ulong> newlinks = new Dictionary<string, ulong>();
foreach (string j in links.Keys)
{
Dictionary<string, object> urights = ((Dictionary<string, object>)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<string, object> node = (Dictionary<string, object>)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<string, object>)node["agent"])["id"];
if (((Dictionary<string, object>)node["agent"]).ContainsKey("caps")) { n.agentcaps = (int)((Dictionary<string, object>)node["agent"])["caps"]; } else { n.agentcaps = 0; }
}
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<string, object> links = ((Dictionary<string, object>)node["links"]);
if (links.ContainsKey(userid))
{
Dictionary<string, object> linksEx = ((Dictionary<string, object>)links[userid]);
if (linksEx.ContainsKey("rights")) { nodeRights = (ulong)(int)linksEx["rights"]; }
}
n.links = new Dictionary<string, ulong>();
foreach (string j in links.Keys)
{
Dictionary<string, object> linksEx = ((Dictionary<string, object>)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<string, MeshClass>();
ArrayList meshList = (ArrayList)jsonAction["meshes"];
for (int i = 0; i < meshList.Count; i++)
{
Dictionary<string, object> mesh = (Dictionary<string, object>)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<string, ulong>();
Dictionary<string, object> links = ((Dictionary<string, object>)mesh["links"]);
if (links.ContainsKey(userid))
{
Dictionary<string, object> urights = ((Dictionary<string, object>)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<string, object> urights = ((Dictionary<string, object>)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<string, NodeClass>(); }
Dictionary<string, NodeClass> nodes2 = new Dictionary<string, NodeClass>();
lock (nodes)
{
Dictionary<string, object> groups = (Dictionary<string, object>)jsonAction["nodes"];
foreach (string meshid in groups.Keys)
{
ArrayList nodesinMesh = (ArrayList)groups[meshid];
for (int i = 0; i < nodesinMesh.Count; i++)
{
Dictionary<string, object> node = (Dictionary<string, object>)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<string, object>)node["agent"])["id"];
if (((Dictionary<string, object>)node["agent"]).ContainsKey("caps")) { n.agentcaps = (int)((Dictionary<string, object>)node["agent"])["caps"]; } else { n.agentcaps = 0; }
}
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<string, ulong>();
if (node.ContainsKey("links"))
{
Dictionary<string, object> links = ((Dictionary<string, object>)node["links"]);
if (links.ContainsKey(userid))
{
Dictionary<string, object> linksEx = ((Dictionary<string, object>)links[userid]);
if (linksEx.ContainsKey("rights")) { n.rights = (ulong)(int)linksEx["rights"]; }
}
foreach (string j in links.Keys)
{
Dictionary<string, object> linksEx = ((Dictionary<string, object>)links[j]);
if (linksEx.ContainsKey("rights"))
{
n.links.Add(j, ulong.Parse(linksEx["rights"].ToString()));
}
}
}
nodes2[n.nodeid] = n;
}
else
{
NodeClass n = new NodeClass();
n.nodeid = nodeid;
if (node.ContainsKey("agent"))
{
n.agentid = (int)((Dictionary<string, object>)node["agent"])["id"];
if (((Dictionary<string, object>)node["agent"]).ContainsKey("caps")) { n.agentcaps = (int)((Dictionary<string, object>)node["agent"])["caps"]; } else { n.agentcaps = 0; }
}
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<string, object>))
{
Dictionary<string, object> users = (Dictionary<string, object>)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;
}
}
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<string, ulong>();
if (node.ContainsKey("links"))
{
Dictionary<string, object> links = ((Dictionary<string, object>)node["links"]);
if (links.ContainsKey(userid))
{
Dictionary<string, object> linksEx = ((Dictionary<string, object>)links[userid]);
if (linksEx.ContainsKey("rights")) { n.rights = (ulong)(int)linksEx["rights"]; }
}
foreach (string j in links.Keys)
{
Dictionary<string, object> linksEx = ((Dictionary<string, object>)links[j]);
if (linksEx.ContainsKey("rights"))
{
n.links.Add(j, ulong.Parse(linksEx["rights"].ToString()));
}
}
}
nodes2[n.nodeid] = n;
}
}
}
}
nodes = nodes2;
if ((onNodesChanged != null) && (nodes != null)) onNodesChanged(true);
break;
}
case "msg":
{
if (jsonAction.ContainsKey("type"))
{
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;
}
case "twoFactorCookie":
{
if (jsonAction.ContainsKey("cookie"))
{
string cookie = (string)jsonAction["cookie"];
if (onTwoFactorCookie != null) { onTwoFactorCookie(cookie); }
}
break;
}
case "meshToolInfo":
{
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();
// 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(); }
// 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;
}
default:
{
break;
}
}
} catch (Exception ex)
{
if (debug) { try { File.AppendAllText("debug.log", ex.ToString() + "\r\n"); } catch (Exception) { } }
}
}
private static string getValueFromQueryString(string query, string name)
{
if ((query == null) || (name == null)) return null;
int i = query.IndexOf("?" + name + "=");
if (i == -1) { i = query.IndexOf("&" + name + "="); }
if (i == -1) return null;
string r = query.Substring(i + name.Length + 2);
i = r.IndexOf("&");
if (i >= 0) { r = r.Substring(0, i); }
return r;
}
public delegate void onStateChangedHandler(int state);
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();
public event onLoginTokenChangedHandler onLoginTokenChanged;
public delegate void onClipboardDataHandler(string nodeid, string data);
public event onClipboardDataHandler onClipboardData;
public delegate void twoFactorCookieHandler(string cookie);
public event twoFactorCookieHandler onTwoFactorCookie;
public delegate void toolUpdateHandler(string url, string hash, int size, string serverhash);
public event toolUpdateHandler onToolUpdate;
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);
}
}
}

352
src/MeshDiscovery.cs Normal file
View File

@@ -0,0 +1,352 @@
/*
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.IO;
using System.Net;
using System.Text;
using System.Security;
using System.Security.Cryptography;
using System.Net.Sockets;
using System.Collections;
using System.Net.NetworkInformation;
namespace MeshCentralRouter
{
/// <summary>
/// This class is used to perform mesh node discovery on the local network. It is used to listen of node advertizements and to multicast a "PING" to find mesh
/// nodes on the network. This class works with both IPv4 and IPv6 and must work regardless of the number of network interfaces on this computer.
/// This class also monitors local adapter changes and events them. This is useful to immidiately remove nodes that are not long accessible.
/// </summary>
public sealed class MeshDiscovery
{
private static IPAddress MulticastV4Addr = IPAddress.Parse("239.255.255.235");
private static IPAddress MulticastV6Addr = IPAddress.Parse("FF02:0:0:0:0:0:0:FE");
private static byte[] PingPacket = UTF8Encoding.UTF8.GetBytes("MeshServerScan");
public delegate void NotifyHandler(MeshDiscovery sender, IPEndPoint source, IPEndPoint local, string agentCertHash, string url, string name, string info);
public event NotifyHandler OnNotify;
public delegate void InterfaceChangedHandler(MeshDiscovery sender, bool added, IPAddress localaddress);
public event InterfaceChangedHandler OnInterfaceChanged;
private Hashtable sessions = new Hashtable();
private Hashtable xsessions = new Hashtable();
private ArrayList localinterfaces = new ArrayList();
private IPEndPoint MulticastV4EndPoint;
private IPEndPoint MulticastV6EndPoint;
private UdpClient GeneralSessionV4 = null; // Used for other things like node messages, etc.
private UdpClient GeneralSessionV6 = null; // Used for other things like node messages, etc.
private const int SIO_UDP_CONNRESET = -1744830452;
private byte[] inValue = new byte[] { 0, 0, 0, 0 }; // == false
private byte[] outValue = new byte[] { 0, 0, 0, 0 }; // initialize to 0
public MeshDiscovery()
{
MulticastV4EndPoint = new IPEndPoint(MulticastV4Addr, 16989);
MulticastV6EndPoint = new IPEndPoint(MulticastV6Addr, 16989);
SetupSessions();
NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(AddressChangedSink);
GeneralSessionV4 = new UdpClient(new IPEndPoint(IPAddress.Any, 0));
GeneralSessionV4.Client.IOControl(SIO_UDP_CONNRESET, inValue, outValue);
GeneralSessionV4.BeginReceive(new AsyncCallback(OnReceiveSink), GeneralSessionV4);
try
{
GeneralSessionV6 = new UdpClient(new IPEndPoint(IPAddress.IPv6Any, 0));
GeneralSessionV6.Client.IOControl(SIO_UDP_CONNRESET, inValue, outValue);
GeneralSessionV6.BeginReceive(new AsyncCallback(OnReceiveSink), GeneralSessionV6);
}
catch (SocketException) { GeneralSessionV6 = null; } // This section will fail on Windows XP because it does not support IPv6
}
public void Dispose()
{
NetworkChange.NetworkAddressChanged -= new NetworkAddressChangedEventHandler(AddressChangedSink);
CloseSessions();
GeneralSessionV4.Close();
GeneralSessionV4 = null;
if (GeneralSessionV6 != null)
{
GeneralSessionV6.Close();
GeneralSessionV6 = null;
}
}
/// <summary>
/// Called then the list of local network adapters has changed.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AddressChangedSink(object sender, EventArgs e)
{
//DebugEventViewerForm.LogEvent(this, DebugEventViewerForm.EventType.Warning, "Network interface change detected.");
SetupSessions();
}
/// <summary>
/// Creates all of the UDP client sessions for each local IP address. This method should be called when the list of local network adapters changes on the
/// local computer.
/// </summary>
private void SetupSessions()
{
NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
if (adapters == null) CloseSessions();
ArrayList tif = new ArrayList(sessions.Keys);
foreach (NetworkInterface adapter in adapters)
{
// We first filter out the local adapters that are not interesting
if (adapter.SupportsMulticast == false) continue;
if (adapter.OperationalStatus != OperationalStatus.Up) continue;
if (adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback) continue;
// Out of each remaining adapter, we look at their IP addresses and create a UDP client for each one.
foreach (System.Net.NetworkInformation.UnicastIPAddressInformation uif in adapter.GetIPProperties().UnicastAddresses)
{
IPAddress addr = uif.Address;
if (addr.AddressFamily == AddressFamily.InterNetwork || addr.ScopeId != 0)
{
tif.Remove(addr);
if (sessions.ContainsKey(addr) == false)
{
// Event this new interface
if (OnInterfaceChanged != null) OnInterfaceChanged(this, true, addr);
// If this local address is IPv4, setup an IPv4 UDP client.
if (addr.AddressFamily == AddressFamily.InterNetwork)
{
UdpClient session = new UdpClient(AddressFamily.InterNetwork);
session.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
session.ExclusiveAddressUse = false;
session.Client.Bind(new IPEndPoint(addr, 0));
session.EnableBroadcast = true;
session.JoinMulticastGroup(MulticastV4Addr, addr);
session.Client.IOControl(SIO_UDP_CONNRESET, inValue, outValue);
session.BeginReceive(new AsyncCallback(OnReceiveSink), session);
sessions[addr] = session;
session = new UdpClient(AddressFamily.InterNetwork);
session.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
session.ExclusiveAddressUse = false;
session.Client.Bind(new IPEndPoint(addr, 16990));
session.EnableBroadcast = true;
session.JoinMulticastGroup(MulticastV4Addr, addr);
session.Client.IOControl(SIO_UDP_CONNRESET, inValue, outValue);
session.BeginReceive(new AsyncCallback(OnReceiveSink), session);
xsessions[addr] = session;
}
// If this local address is IPv6, setup an IPv6 UDP client.
if (addr.AddressFamily == AddressFamily.InterNetworkV6)
{
UdpClient session = new UdpClient(AddressFamily.InterNetworkV6);
session.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
session.ExclusiveAddressUse = false;
session.Client.Bind(new IPEndPoint(addr, 0));
session.EnableBroadcast = true;
session.JoinMulticastGroup((int)addr.ScopeId, MulticastV6Addr);
session.Client.IOControl(SIO_UDP_CONNRESET, inValue, outValue);
session.BeginReceive(new AsyncCallback(OnReceiveSink), session);
sessions[addr] = session;
session = new UdpClient(AddressFamily.InterNetworkV6);
session.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
session.ExclusiveAddressUse = false;
session.Client.Bind(new IPEndPoint(addr, 16990));
session.EnableBroadcast = true;
session.JoinMulticastGroup((int)addr.ScopeId, MulticastV6Addr);
session.Client.IOControl(SIO_UDP_CONNRESET, inValue, outValue);
session.BeginReceive(new AsyncCallback(OnReceiveSink), session);
xsessions[addr] = session;
}
}
}
}
}
// Remove old sessions
if (tif.Count > 0)
{
foreach (IPAddress a in tif)
{
UdpClient c = (UdpClient)sessions[a];
c.Close();
sessions.Remove(a);
if (OnInterfaceChanged != null) OnInterfaceChanged(this, false, a);
}
}
}
/// <summary>
/// Closes all of the UDP client sessions.
/// </summary>
private void CloseSessions()
{
ArrayList l = new ArrayList(sessions.Values);
foreach (UdpClient session in l)
{
IPAddress a = ((IPEndPoint)session.Client.LocalEndPoint).Address;
session.Close();
sessions.Remove(a);
if (OnInterfaceChanged != null) OnInterfaceChanged(this, false, a);
}
sessions.Clear();
l = new ArrayList(xsessions.Values);
foreach (UdpClient session in l)
{
IPAddress a = ((IPEndPoint)session.Client.LocalEndPoint).Address;
session.Close();
sessions.Remove(a);
if (OnInterfaceChanged != null) OnInterfaceChanged(this, false, a);
}
xsessions.Clear();
}
/// <summary>
/// Called by the UDP clients when data is received or when the client is closed.
/// </summary>
/// <param name="result">AsyncResult parameter</param>
private void OnReceiveSink(IAsyncResult result)
{
byte[] buffer;
IPEndPoint ep = null;
UdpClient session = (UdpClient)result.AsyncState;
try
{
buffer = session.EndReceive(result, ref ep);
try
{
// We received some data, decode it
string[] values = UTF8Encoding.UTF8.GetString(buffer).Split('|');
if ((values.Length >= 3) && (values[0] == "MeshCentral2"))
{
Uri url = new Uri(values[2].Replace("%s", ep.Address.ToString()).Replace("wss://", "https://").Replace("ws://", "http://").Replace("/agent.ashx", "/"));
string agentCertHash = values[1];
string serverName = null;
string serverInfo = null;
if (values.Length >= 4) { serverName = values[3]; }
if (values.Length >= 5) { serverInfo = values[4]; }
OnNotify(this, ep, (IPEndPoint)(session.Client.LocalEndPoint), agentCertHash, url.ToString(), serverName, serverInfo);
// Send a targeted scan to this server to get more information
if (values.Length == 3) { session.Send(PingPacket, PingPacket.Length, ep); session.Send(PingPacket, PingPacket.Length, ep); }
}
}
catch (Exception) { }
session.BeginReceive(new AsyncCallback(OnReceiveSink), session);
}
catch (Exception)
{
// If the client is disposed, it will throw another exception.
try
{
if (session != null && session.Client != null)
{
IPAddress a = ((IPEndPoint)session.Client.LocalEndPoint).Address;
sessions.Remove(a);
if (OnInterfaceChanged != null) OnInterfaceChanged(this, false, a);
}
}
catch (Exception) { }
}
}
/*
internal void SendBlockRequest(TargetTrak tt, string[] requests)
{
// PB_SYNCREQUEST
MemoryStream mem = new MemoryStream();
mem.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)12)), 0, 2); // Write PB_SYNCREQUEST
mem.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)(4 + (32 * requests.Length)))), 0, 2); // Write length of header + (32 * requests)
foreach (string s in requests)
{
byte[] buf = MeshUtils.HexToBytes(s);
mem.Write(buf, 0, buf.Length);
}
byte[] packet = MeshDiscovery.util_cipher(tt.UdpSessionKey, 0, MeshUtils.HexToBytes(tt.Node.NodeIdHex), mem.ToArray(), true, tt.ConsoleId);
GeneralUnicast(packet, new IPEndPoint(tt.Target, 16990));
}
*/
/// <summary>
/// This method sends out a multicast "PING" on all local adapters in both IPv4 and IPv6.
/// </summary>
public void MulticastPing()
{
//DebugEventViewerForm.LogEvent(this, DebugEventViewerForm.EventType.Information, "Performing full multicast ping.");
foreach (UdpClient session in sessions.Values) MulticastPing(session);
}
/// <summary>
/// Performs a multicast ping on a single UDP session.
/// </summary>
/// <param name="session">The UDP client on which to perform the multicast</param>
private void MulticastPing(UdpClient session)
{
try
{
IPAddress address = ((IPEndPoint)session.Client.LocalEndPoint).Address;
if (session.Client.AddressFamily == AddressFamily.InterNetwork)
{
session.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, address.GetAddressBytes());
session.Send(PingPacket, PingPacket.Length, MulticastV4EndPoint);
}
else if (session.Client.AddressFamily == AddressFamily.InterNetworkV6 && address.ScopeId != 0)
{
session.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastInterface, BitConverter.GetBytes((int)address.ScopeId));
session.Send(PingPacket, PingPacket.Length, MulticastV6EndPoint);
}
}
catch (SocketException) { }
}
/// <summary>
/// This method is used to send out unicast UDP packets.
/// </summary>
/// <param name="buffer">The buffer to send out as unicast</param>
/// <param name="local">The local IP address to use</param>
/// <param name="remote">The remote IP address that this packet will be sent to</param>
public void UnicastData(byte[] buffer, IPAddress local, IPEndPoint remote)
{
UdpClient session = (UdpClient)sessions[local];
if (session == null) return;
try
{
session.Send(buffer, buffer.Length, remote);
}
catch (SocketException) { }
}
public void GeneralUnicast(byte[] buffer, IPEndPoint remote)
{
try
{
if (remote.AddressFamily == AddressFamily.InterNetwork && GeneralSessionV4 != null) GeneralSessionV4.Send(buffer, buffer.Length, remote);
if (remote.AddressFamily == AddressFamily.InterNetworkV6 && GeneralSessionV6 != null) GeneralSessionV6.Send(buffer, buffer.Length, remote);
}
catch (SocketException) { }
}
}
}

419
src/MeshMapper.cs Normal file
View File

@@ -0,0 +1,419 @@
/*
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.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Web.Script.Serialization;
namespace MeshCentralRouter
{
public class MeshMapper
{
public MeshCentralServer parent = null;
public int state = 0;
public string url = null;
public int protocol = 1; // 1 = TCP, 2 = UDP
public int localport = 0;
public int remoteport = 0;
public string remoteip = null;
public string certhash = null;
public int connectCounter = 0;
public int totalConnectCounter = 0;
public bool exit = false;
public bool xdebug = false;
public bool inaddrany = false;
private TcpListener listener = null;
private JavaScriptSerializer JSON = new JavaScriptSerializer();
// Stats
public long bytesToServer = 0;
public long bytesToClient = 0;
public long bytesToServerCompressed = 0;
public long bytesToClientCompressed = 0;
public delegate void onStateMsgChangedHandler(string statemsg);
public event onStateMsgChangedHandler onStateMsgChanged;
// 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)
{
this.parent = parent;
this.protocol = protocol;
this.remoteport = remotePort;
this.remoteip = remoteIP;
this.url = url;
//wshash = serverHashTextBox.Text;
Debug(string.Format("MeshMapper-Start: Protcol={0}, LocalPort={1}, Url={2}, RemotePort={3}, RemoteIP={4}", protocol, localPort, url, remotePort, remoteIP));
if (protocol == 1)
{
// Start the TCP listener
try
{
if (listener != null) return;
listener = new TcpListener(inaddrany ? IPAddress.Any : IPAddress.Loopback, localPort);
try { listener.Start(); } catch (Exception) { listener = null; }
if (listener != null)
{
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptTcpClientSink), null);
localport = ((IPEndPoint)listener.LocalEndpoint).Port;
state = 1;
UpdateInfo();
}
else
{
state = -1;
UpdateInfo();
}
}
catch (Exception ex) {
Debug(ex.ToString());
stop();
}
} else if (protocol == 2) {
// Start websocket connection
try
{
IPEndPoint udpEndPoint = new IPEndPoint(inaddrany ? IPAddress.Any : IPAddress.Loopback, localPort);
UdpClient client = new UdpClient(udpEndPoint);
localport = ((IPEndPoint)client.Client.LocalEndPoint).Port;
state = 1;
UpdateInfo();
ConnectWS(client, ++connectCounter);
}
catch (Exception ex) {
Debug(ex.ToString());
stop();
}
}
}
public void Debug(string msg) { if (xdebug) { try { File.AppendAllText("debug.log", "Debug-MeshMapper-" + msg + "\r\n"); } catch (Exception) { } } }
private void UpdateInfo() {
string msg = "";
if (state == -1) { msg = Translate.T(Properties.Resources.UnableToBindToLocalPort); }
else if (state == 0) { msg = Translate.T(Properties.Resources.Stopped2); }
else if (state == 1) {
if (remoteip == null)
{
msg = string.Format(Translate.T(Properties.Resources.PortXtoPortY), localport, remoteport);
} else {
msg = string.Format(Translate.T(Properties.Resources.PortXtoIPPortY), localport, remoteip, remoteport);
}
if (totalConnectCounter == 1) { msg += Translate.T(Properties.Resources.OneConnection); }
if (totalConnectCounter > 1) { msg += string.Format(Translate.T(Properties.Resources.ManyConnections), totalConnectCounter); }
}
if (onStateMsgChanged != null) { onStateMsgChanged(msg); }
}
public void stop()
{
Debug("stopButton_Click()");
exit = true;
if (listener != null) {
listener.Stop();
listener = null;
}
localport = 0;
state = 0;
UpdateInfo();
}
private void ShutdownClients(TcpClient c1, UdpClient c2, webSocketClient c3, int counter)
{
Debug("#" + counter + ": ShutdownWebClients()");
if (c1 != null)
{
try
{
if (c1.Client.Connected)
{
try { c1.Client.Disconnect(false); } catch (Exception) { }
try { c1.Client.Close(); } catch (Exception) { }
try { c1.Close(); } catch (Exception) { }
}
}
catch (Exception) { }
}
if (c2 != null)
{
try { c2.Close(); } catch (Exception) { }
}
try { c3.Dispose(); } catch (Exception) { }
}
private void AcceptTcpClientSink(IAsyncResult ar)
{
TcpClient client = null;
try
{
client = listener.EndAcceptTcpClient(ar);
}
catch (Exception) { exit = true; }
if (client != null)
{
// Connect using websocket
ConnectWS(client, ++connectCounter);
}
try
{
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptTcpClientSink), null);
}
catch (Exception) { exit = true; }
}
private void ConnectWS(TcpClient client, int counter)
{
webSocketClient wc = new webSocketClient();
Uri wsurl = new Uri(url + "&auth=" + Uri.EscapeDataString(parent.authCookie));
Debug("#" + counter + ": Connecting web socket to: " + wsurl.ToString());
wc.debug = xdebug;
wc.tag = client;
wc.id = counter;
wc.tunneling = false;
wc.onStateChanged += Wc_onStateChanged;
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)
{
webSocketClient wc = new webSocketClient();
Uri wsurl = new Uri(url + "&auth=" + Uri.EscapeDataString(parent.authCookie));
Debug("#" + counter + ": Connecting web socket to: " + wsurl.ToString());
wc.debug = xdebug;
wc.tag = client;
wc.id = counter;
wc.tunneling = false;
wc.onStateChanged += Wc_onStateChanged;
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)
{
if (sender.tag.GetType() == typeof(TcpClient))
{
// This is a TCP client, if it's not reading now, start reading
if (sender.tag2 == null) return;
object[] args = sender.tag2;
sender.tag2 = null;
MeshMapper mm = (MeshMapper)args[0];
webSocketClient wc = (webSocketClient)args[1];
TcpClient client = (TcpClient)args[2];
byte[] buf = (byte[])args[3];
try { client.GetStream().BeginRead(buf, 0, buf.Length, new AsyncCallback(ClientEndReadWS), new object[] { mm, wc, client, buf }); } catch (Exception) { }
}
if ((sender.tag.GetType() == typeof(UdpClient)) && (sender.endpoint != null))
{
// This is a UDP socket, do nothing since it's always reading
}
}
private void Wc_onStateChanged(webSocketClient sender, webSocketClient.ConnectionStates state)
{
Debug("#" + sender.id + ": Websocket mapping, connected to server.");
switch (state)
{
case webSocketClient.ConnectionStates.Disconnected:
{
if (sender.tag.GetType() == typeof(TcpClient)) {
ShutdownClients((TcpClient)sender.tag, null, sender, sender.id);
} else if (sender.tag.GetType() == typeof(UdpClient)) {
ShutdownClients(null, (UdpClient)sender.tag, sender, sender.id);
}
break;
}
}
}
private void Wc_onStringData(webSocketClient sender, string data, int orglen)
{
bytesToClient += data.Length;
bytesToClientCompressed += orglen;
if ((sender.tunneling == false) && ((data == "c") || (data == "cr")))
{
Debug("#" + sender.id + ": Websocket got server 'c' confirmation.");
// Server confirmed connection, start reading the TCP stream
//Console.Write("WS-Relay Connect\r\n");
if (sender.tag == null) return;
if (sender.tag.GetType() == typeof(TcpClient))
{
TcpClient client = (TcpClient)sender.tag;
if (client != null)
{
byte[] buf1 = new byte[65000];
try { client.GetStream().BeginRead(buf1, 0, buf1.Length, new AsyncCallback(ClientEndReadWS), new object[] { this, sender, client, buf1 }); } catch (Exception) { }
sender.tunneling = true;
}
}
if (sender.tag.GetType() == typeof(UdpClient))
{
UdpClient uclient = (UdpClient)sender.tag;
try { uclient.BeginReceive(new AsyncCallback(UClientEndReadWS), new object[] { this, sender, uclient }); } catch (Exception) { }
sender.tunneling = true;
}
}
else if (sender.tunneling == true)
{
Debug("#" + sender.id + ": Websocket got text frame: " + data);
// Parse the received JSON
Dictionary<string, object> jsonAction = new Dictionary<string, object>();
try { jsonAction = JSON.Deserialize<Dictionary<string, object>>(data); } catch (Exception) { }
if ((jsonAction == null) || (jsonAction["ctrlChannel"].GetType() != typeof(string)) || ((string)jsonAction["ctrlChannel"] != "102938")) return;
string actiontype = jsonAction["type"].ToString();
switch (actiontype)
{
case "ping":
{
// We can't respond to a ping with a pong in this case since it will be relayed and corrupt the data channel.
break;
}
case "pong":
{
// NOP
break;
}
}
}
}
private void Wc_onBinaryData(webSocketClient sender, byte[] data, int offset, int length, int orglen)
{
bytesToClient += length;
bytesToClientCompressed += orglen;
Debug("#" + sender.id + ": Websocket binary data: " + length);
if ((sender.tunneling == false) || (sender.tag == null)) return;
if (sender.tag.GetType() == typeof(TcpClient))
{
// Write: WS --> TCP
TcpClient client = (TcpClient)sender.tag;
if (client != null) {
sender.Pause(); // Pause reading from the websocket until the data is sent on the TCP client
try { client.GetStream().BeginWrite(data, offset, length, new AsyncCallback(ClientEndWrite), sender); } catch (Exception) { }
}
}
if ((sender.tag.GetType() == typeof(UdpClient)) && (sender.endpoint != null))
{
// Write: WS --> UDP
UdpClient uclient = (UdpClient)sender.tag;
if (offset == 0)
{
try { uclient.Send(data, length, sender.endpoint); } catch (Exception) { }
}
else
{
byte[] data2 = new byte[length];
Array.Copy(data, offset, data2, 0, length);
try { uclient.Send(data2, length, sender.endpoint); } catch (Exception) { }
}
}
}
private void ClientEndWrite(IAsyncResult ar)
{
// TCP Client finished sending data, read more from the websocket
((webSocketClient)ar.AsyncState).Resume();
}
// Read from the local client
private void ClientEndReadWS(IAsyncResult ar)
{
// Fetch the state
object[] args = (object[])ar.AsyncState;
MeshMapper mm = (MeshMapper)args[0];
webSocketClient wc = (webSocketClient)args[1];
TcpClient client = (TcpClient)args[2];
byte[] buf = (byte[])args[3];
int counter = wc.id;
int len = 0;
try
{
// Read the data
if (client != null && client.Connected == true) { len = client.GetStream().EndRead(ar); }
}
catch (Exception) { ShutdownClients(client, null, wc, counter); return; }
//Debug("#" + counter + ": ClientEndRead(" + len + ") - Local Read");
if (len > 0)
{
// Forward the data & read again
try
{
mm.bytesToServer += len;
wc.tag2 = args; // When the websocket SendOK is triggered, read more data from the TCP client.
mm.bytesToServerCompressed += wc.SendBinary(buf, 0, len);
}
catch (Exception)
{
ShutdownClients(client, null, wc, counter);
return;
}
}
else
{
Debug("#" + counter + ": ClientEndRead(" + len + ") - Disconnect");
ShutdownClients(client, null, wc, counter);
return;
}
}
private void UClientEndReadWS(IAsyncResult ar)
{
// Fetch the state
object[] args = (object[])ar.AsyncState;
MeshMapper mm = (MeshMapper)args[0];
webSocketClient wc = (webSocketClient)args[1];
UdpClient uclient = (UdpClient)args[2];
int counter = wc.id;
byte[] buf = null;
try
{
// Read the data
if (uclient != null) { buf = uclient.EndReceive(ar, ref wc.endpoint); }
}
catch (Exception) { ShutdownClients(null, uclient, wc, counter); return; }
if (buf != null) {
mm.bytesToServer += buf.Length;
mm.bytesToServerCompressed += wc.SendBinary(buf, 0, buf.Length); // TODO: Do Async
try { uclient.BeginReceive(new AsyncCallback(UClientEndReadWS), new object[] { mm, wc, uclient }); } catch (Exception) { }
}
}
}
}

BIN
src/MeshServer.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

69
src/NodeClass.cs Normal file
View File

@@ -0,0 +1,69 @@
/*
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.Windows.Forms;
using System.Collections.Generic;
namespace MeshCentralRouter
{
public class NodeClass
{
public string name;
public int icon;
public string nodeid;
public string meshid;
public int agentid;
public int agentcaps;
public int conn;
public int rdpport;
public ulong rights;
public int mtype;
public MeshClass mesh;
public ListViewItem listitem;
public DeviceUserControl control;
public KVMViewer desktopViewer;
public FileViewer fileViewer;
public Dictionary<string, ulong> links;
public string[] users;
public override string ToString() { return name; }
public string getStateString()
{
string status = "";
if (mtype == 3) return Translate.T(Properties.Resources.Local);
if ((conn & 1) != 0) { if (status.Length > 0) { status += ", "; } status += Translate.T(Properties.Resources.Agent); }
if ((conn & 2) != 0) { if (status.Length > 0) { status += ", "; } status += Translate.T(Properties.Resources.CIRA); }
if ((conn & 4) != 0) { if (status.Length > 0) { status += ", "; } status += Translate.T(Properties.Resources.AMT); }
if ((conn & 8) != 0) { if (status.Length > 0) { status += ", "; } status += Translate.T(Properties.Resources.Relay); }
if ((conn & 16) != 0) { if (status.Length > 0) { status += ", "; } status += Translate.T(Properties.Resources.MQTT); }
if (status == "") { status = Translate.T(Properties.Resources.Offline); }
return status;
}
}
public class MeshClass
{
public string name;
public string meshid;
public string desc;
public int type;
public ulong rights;
public Dictionary<string, ulong> links;
public override string ToString() { return name; }
}
}

248
src/ProxySettings.Designer.cs generated Normal file
View File

@@ -0,0 +1,248 @@
namespace MeshCentralRouter
{
partial class ProxySettings
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProxySettings));
this.okButton = new System.Windows.Forms.Button();
this.hostTextBox = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.usernameTextBox = new System.Windows.Forms.TextBox();
this.label4 = new System.Windows.Forms.Label();
this.passwordTextBox = new System.Windows.Forms.TextBox();
this.label5 = new System.Windows.Forms.Label();
this.manualProxyCheckBox = new System.Windows.Forms.CheckBox();
this.cancelButton = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.label2 = new System.Windows.Forms.Label();
this.authComboBox = new System.Windows.Forms.ComboBox();
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.Location = new System.Drawing.Point(164, 203);
this.okButton.Margin = new System.Windows.Forms.Padding(2);
this.okButton.Name = "okButton";
this.okButton.Size = new System.Drawing.Size(95, 23);
this.okButton.TabIndex = 1;
this.okButton.Text = "OK";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// hostTextBox
//
this.hostTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.hostTextBox.Location = new System.Drawing.Point(145, 39);
this.hostTextBox.Margin = new System.Windows.Forms.Padding(2);
this.hostTextBox.Name = "hostTextBox";
this.hostTextBox.Size = new System.Drawing.Size(192, 20);
this.hostTextBox.TabIndex = 2;
this.hostTextBox.TextChanged += new System.EventHandler(this.manualProxyCheckBox_CheckedChanged);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(6, 42);
this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(106, 13);
this.label1.TabIndex = 3;
this.label1.Text = "Proxy Hostname:Port";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(5, 93);
this.label3.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(55, 13);
this.label3.TabIndex = 7;
this.label3.Text = "Username";
//
// usernameTextBox
//
this.usernameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.usernameTextBox.Location = new System.Drawing.Point(145, 90);
this.usernameTextBox.Margin = new System.Windows.Forms.Padding(2);
this.usernameTextBox.Name = "usernameTextBox";
this.usernameTextBox.Size = new System.Drawing.Size(192, 20);
this.usernameTextBox.TabIndex = 6;
this.usernameTextBox.TextChanged += new System.EventHandler(this.manualProxyCheckBox_CheckedChanged);
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(6, 117);
this.label4.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(53, 13);
this.label4.TabIndex = 9;
this.label4.Text = "Password";
//
// passwordTextBox
//
this.passwordTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.passwordTextBox.Location = new System.Drawing.Point(145, 114);
this.passwordTextBox.Margin = new System.Windows.Forms.Padding(2);
this.passwordTextBox.Name = "passwordTextBox";
this.passwordTextBox.PasswordChar = '*';
this.passwordTextBox.Size = new System.Drawing.Size(192, 20);
this.passwordTextBox.TabIndex = 8;
this.passwordTextBox.TextChanged += new System.EventHandler(this.manualProxyCheckBox_CheckedChanged);
//
// label5
//
this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label5.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.label5.Location = new System.Drawing.Point(12, 7);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(346, 44);
this.label5.TabIndex = 10;
this.label5.Text = "By default, the system\'s proxy is used. You can override this by manually configu" +
"ring your own proxy settings here.\r\n";
this.label5.UseMnemonic = false;
//
// manualProxyCheckBox
//
this.manualProxyCheckBox.AutoSize = true;
this.manualProxyCheckBox.Location = new System.Drawing.Point(145, 18);
this.manualProxyCheckBox.Margin = new System.Windows.Forms.Padding(2);
this.manualProxyCheckBox.Name = "manualProxyCheckBox";
this.manualProxyCheckBox.Size = new System.Drawing.Size(131, 17);
this.manualProxyCheckBox.TabIndex = 11;
this.manualProxyCheckBox.Text = "Manual Proxy Settings";
this.manualProxyCheckBox.UseVisualStyleBackColor = true;
this.manualProxyCheckBox.CheckedChanged += new System.EventHandler(this.manualProxyCheckBox_CheckedChanged);
//
// 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(263, 203);
this.cancelButton.Margin = new System.Windows.Forms.Padding(2);
this.cancelButton.Name = "cancelButton";
this.cancelButton.Size = new System.Drawing.Size(95, 23);
this.cancelButton.TabIndex = 12;
this.cancelButton.Text = "Cancel";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// 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.label2);
this.groupBox1.Controls.Add(this.authComboBox);
this.groupBox1.Controls.Add(this.hostTextBox);
this.groupBox1.Controls.Add(this.usernameTextBox);
this.groupBox1.Controls.Add(this.manualProxyCheckBox);
this.groupBox1.Controls.Add(this.passwordTextBox);
this.groupBox1.Controls.Add(this.label4);
this.groupBox1.Controls.Add(this.label1);
this.groupBox1.Controls.Add(this.label3);
this.groupBox1.Location = new System.Drawing.Point(12, 54);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(342, 144);
this.groupBox1.TabIndex = 13;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Proxy Settings";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(6, 67);
this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(104, 13);
this.label2.TabIndex = 13;
this.label2.Text = "Proxy Authentication";
//
// authComboBox
//
this.authComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.authComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.authComboBox.FormattingEnabled = true;
this.authComboBox.Items.AddRange(new object[] {
"None",
"Basic Authentication"});
this.authComboBox.Location = new System.Drawing.Point(145, 64);
this.authComboBox.Name = "authComboBox";
this.authComboBox.Size = new System.Drawing.Size(192, 21);
this.authComboBox.TabIndex = 12;
this.authComboBox.SelectedIndexChanged += new System.EventHandler(this.manualProxyCheckBox_CheckedChanged);
//
// ProxySettings
//
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(369, 237);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.cancelButton);
this.Controls.Add(this.label5);
this.Controls.Add(this.okButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Margin = new System.Windows.Forms.Padding(2);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "ProxySettings";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Proxy Settings";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.TextBox hostTextBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox usernameTextBox;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox passwordTextBox;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.CheckBox manualProxyCheckBox;
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.ComboBox authComboBox;
}
}

75
src/ProxySettings.cs Normal file
View File

@@ -0,0 +1,75 @@
using System;
using System.Windows.Forms;
namespace MeshCentralRouter
{
public partial class ProxySettings : Form
{
public ProxySettings()
{
InitializeComponent();
manualProxyCheckBox.Checked = Settings.GetRegValue("ManualProxy", false);
string host = Settings.GetRegValue("ProxyHost", "");
if (host != "") { host += ":" + Settings.GetRegValue("ProxyPort", 443); }
hostTextBox.Text = host;
authComboBox.SelectedIndex = Settings.GetRegValue("ProxyAuth", 0);
usernameTextBox.Text = Settings.GetRegValue("ProxyUsername", "");
passwordTextBox.Text = Settings.GetRegValue("ProxyPassword", "");
UpdateInfo();
}
private void UpdateInfo()
{
hostTextBox.Enabled = manualProxyCheckBox.Checked;
usernameTextBox.Enabled = passwordTextBox.Enabled = (manualProxyCheckBox.Checked && (authComboBox.SelectedIndex == 1));
bool ok = true;
if (manualProxyCheckBox.Checked == true)
{
string portStr = "";
string hostStr = hostTextBox.Text;
int i = hostStr.IndexOf(':');
if (i >= 0) { portStr = hostStr.Substring(i + 1); hostStr = hostStr.Substring(0, i); }
int port = 0;
int.TryParse(portStr, out port);
if ((hostStr.Length == 0) || (port < 1) || (port > 65535)) { ok = false; }
}
okButton.Enabled = ok;
}
private void manualProxyCheckBox_CheckedChanged(object sender, EventArgs e)
{
UpdateInfo();
}
private void okButton_Click(object sender, EventArgs e)
{
Settings.SetRegValue("ManualProxy", manualProxyCheckBox.Checked);
if (manualProxyCheckBox.Checked == true) {
string hostStr = hostTextBox.Text;
string portStr = "";
int i = hostStr.IndexOf(':');
if (i >= 0) { portStr = hostStr.Substring(i + 1); hostStr = hostStr.Substring(0, i); }
int port = 0;
int.TryParse(portStr, out port);
Settings.SetRegValue("ProxyHost", hostStr);
Settings.SetRegValue("ProxyPort", port);
Settings.SetRegValue("ProxyAuth", authComboBox.SelectedIndex);
Settings.SetRegValue("ProxyUsername", (authComboBox.SelectedIndex == 1) ? usernameTextBox.Text : "");
Settings.SetRegValue("ProxyPassword", (authComboBox.SelectedIndex == 1) ? passwordTextBox.Text : "");
} else {
Settings.SetRegValue("ProxyHost", "");
Settings.SetRegValue("ProxyPort", "");
Settings.SetRegValue("ProxyAuth", 0);
Settings.SetRegValue("ProxyUsername", "");
Settings.SetRegValue("ProxyPassword", "");
}
DialogResult = DialogResult.OK;
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}

1815
src/ProxySettings.resx Normal file

File diff suppressed because it is too large Load Diff

110
src/ServerUserControl.Designer.cs generated Normal file
View File

@@ -0,0 +1,110 @@
namespace MeshCentralRouter
{
partial class ServerUserControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServerUserControl));
this.serverInfoLabel = new System.Windows.Forms.Label();
this.serverNameLabel = new System.Windows.Forms.Label();
this.serverPictureBox = new System.Windows.Forms.PictureBox();
this.serverContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.infoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.backTimer = new System.Windows.Forms.Timer(this.components);
((System.ComponentModel.ISupportInitialize)(this.serverPictureBox)).BeginInit();
this.serverContextMenuStrip.SuspendLayout();
this.SuspendLayout();
//
// serverInfoLabel
//
resources.ApplyResources(this.serverInfoLabel, "serverInfoLabel");
this.serverInfoLabel.Name = "serverInfoLabel";
this.serverInfoLabel.Click += new System.EventHandler(this.serverButton_Click);
//
// serverNameLabel
//
resources.ApplyResources(this.serverNameLabel, "serverNameLabel");
this.serverNameLabel.Name = "serverNameLabel";
this.serverNameLabel.Click += new System.EventHandler(this.serverButton_Click);
//
// serverPictureBox
//
this.serverPictureBox.Image = global::MeshCentralRouter.Properties.Resources.MeshCentral;
resources.ApplyResources(this.serverPictureBox, "serverPictureBox");
this.serverPictureBox.Name = "serverPictureBox";
this.serverPictureBox.TabStop = false;
this.serverPictureBox.Click += new System.EventHandler(this.serverButton_Click);
//
// serverContextMenuStrip
//
this.serverContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.infoToolStripMenuItem});
this.serverContextMenuStrip.Name = "serverContextMenuStrip";
resources.ApplyResources(this.serverContextMenuStrip, "serverContextMenuStrip");
//
// infoToolStripMenuItem
//
this.infoToolStripMenuItem.Name = "infoToolStripMenuItem";
resources.ApplyResources(this.infoToolStripMenuItem, "infoToolStripMenuItem");
this.infoToolStripMenuItem.Click += new System.EventHandler(this.infoToolStripMenuItem_Click);
//
// backTimer
//
this.backTimer.Interval = 2000;
this.backTimer.Tick += new System.EventHandler(this.backTime_Tick);
//
// ServerUserControl
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.ContextMenuStrip = this.serverContextMenuStrip;
this.Controls.Add(this.serverInfoLabel);
this.Controls.Add(this.serverNameLabel);
this.Controls.Add(this.serverPictureBox);
this.Cursor = System.Windows.Forms.Cursors.Hand;
this.Name = "ServerUserControl";
this.Load += new System.EventHandler(this.ServerUserControl_Load);
this.Click += new System.EventHandler(this.serverButton_Click);
((System.ComponentModel.ISupportInitialize)(this.serverPictureBox)).EndInit();
this.serverContextMenuStrip.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Label serverInfoLabel;
private System.Windows.Forms.Label serverNameLabel;
private System.Windows.Forms.PictureBox serverPictureBox;
private System.Windows.Forms.ContextMenuStrip serverContextMenuStrip;
private System.Windows.Forms.ToolStripMenuItem infoToolStripMenuItem;
private System.Windows.Forms.Timer backTimer;
}
}

98
src/ServerUserControl.cs Normal file
View File

@@ -0,0 +1,98 @@
/*
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;
namespace MeshCentralRouter
{
public partial class ServerUserControl : UserControl
{
private MainForm parent;
public string key;
public string name;
public string info;
public string url;
public DateTime lastUpdate;
private Color xbackColor;
public ServerUserControl(MainForm parent, string key, string name, string info, string url)
{
this.parent = parent;
this.key = key;
this.name = name;
this.info = info;
this.url = url;
this.lastUpdate = DateTime.Now;
InitializeComponent();
}
private void ServerUserControl_Load(object sender, EventArgs e)
{
serverNameLabel.Text = this.name;
serverInfoLabel.Text = this.info;
xbackColor = BackColor;
BackColor = Color.Wheat;
backTimer.Enabled = true;
}
public bool Update(string name, string info, string url)
{
this.lastUpdate = DateTime.Now;
// Fix the name
if (name == null) { name = this.name; }
if (name == null) { name = Translate.T(Properties.Resources.MeshCentralTitle); }
// Don't replace a IPv4 address with a IPv6 one, or remove information
if ((this.url.IndexOf("://[") == -1) && (url.IndexOf("://[") >= 0)) return false;
if ((this.info != null) && (info == null)) return false;
// If any changes need to be made, make them now
if ((this.name != name) || (this.info != info) || (this.url != url))
{
this.name = name;
this.info = info;
this.url = url;
serverNameLabel.Text = this.name;
if (this.info != null) { serverInfoLabel.Text = this.info; } else { serverInfoLabel.Text = url; }
BackColor = Color.Wheat;
backTimer.Enabled = true;
return true;
}
return false;
}
private void serverButton_Click(object sender, EventArgs e)
{
//MouseEventArgs me = (MouseEventArgs)e;
//if (me.Button == MouseButtons.Left) { parent.serverClick(this); }
}
private void infoToolStripMenuItem_Click(object sender, EventArgs e)
{
//ServerInfoForm form = new ServerInfoForm(name, url, info, key);
//form.ShowDialog(this);
}
private void backTime_Tick(object sender, EventArgs e)
{
BackColor = xbackColor;
backTimer.Enabled = false;
}
}
}

255
src/ServerUserControl.resx Normal file
View File

@@ -0,0 +1,255 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="serverInfoLabel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="serverInfoLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Arial, 9pt</value>
</data>
<data name="serverInfoLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>65, 30</value>
</data>
<data name="serverInfoLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>420, 18</value>
</data>
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="serverInfoLabel.TabIndex" type="System.Int32, mscorlib">
<value>11</value>
</data>
<data name="serverInfoLabel.Text" xml:space="preserve">
<value>Server information</value>
</data>
<data name="&gt;&gt;serverInfoLabel.Name" xml:space="preserve">
<value>serverInfoLabel</value>
</data>
<data name="&gt;&gt;serverInfoLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;serverInfoLabel.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;serverInfoLabel.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="serverNameLabel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
</data>
<data name="serverNameLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Arial, 11.25pt, style=Bold</value>
</data>
<data name="serverNameLabel.Location" type="System.Drawing.Point, System.Drawing">
<value>65, 10</value>
</data>
<data name="serverNameLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>420, 18</value>
</data>
<data name="serverNameLabel.TabIndex" type="System.Int32, mscorlib">
<value>10</value>
</data>
<data name="serverNameLabel.Text" xml:space="preserve">
<value>ServerName</value>
</data>
<data name="&gt;&gt;serverNameLabel.Name" xml:space="preserve">
<value>serverNameLabel</value>
</data>
<data name="&gt;&gt;serverNameLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;serverNameLabel.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;serverNameLabel.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="serverPictureBox.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 0</value>
</data>
<data name="serverPictureBox.Size" type="System.Drawing.Size, System.Drawing">
<value>59, 59</value>
</data>
<data name="serverPictureBox.SizeMode" type="System.Windows.Forms.PictureBoxSizeMode, System.Windows.Forms">
<value>StretchImage</value>
</data>
<data name="serverPictureBox.TabIndex" type="System.Int32, mscorlib">
<value>9</value>
</data>
<data name="&gt;&gt;serverPictureBox.Name" xml:space="preserve">
<value>serverPictureBox</value>
</data>
<data name="&gt;&gt;serverPictureBox.Type" xml:space="preserve">
<value>System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;serverPictureBox.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;serverPictureBox.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<metadata name="serverContextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<data name="infoToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>104, 22</value>
</data>
<data name="infoToolStripMenuItem.Text" xml:space="preserve">
<value>&amp;Info...</value>
</data>
<data name="serverContextMenuStrip.Size" type="System.Drawing.Size, System.Drawing">
<value>105, 26</value>
</data>
<data name="&gt;&gt;serverContextMenuStrip.Name" xml:space="preserve">
<value>serverContextMenuStrip</value>
</data>
<data name="&gt;&gt;serverContextMenuStrip.Type" xml:space="preserve">
<value>System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<metadata name="backTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>200, 17</value>
</metadata>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>6, 13</value>
</data>
<data name="$this.Size" type="System.Drawing.Size, System.Drawing">
<value>479, 51</value>
</data>
<data name="&gt;&gt;infoToolStripMenuItem.Name" xml:space="preserve">
<value>infoToolStripMenuItem</value>
</data>
<data name="&gt;&gt;infoToolStripMenuItem.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;backTimer.Name" xml:space="preserve">
<value>backTimer</value>
</data>
<data name="&gt;&gt;backTimer.Type" xml:space="preserve">
<value>System.Windows.Forms.Timer, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>ServerUserControl</value>
</data>
<data name="&gt;&gt;$this.Type" xml:space="preserve">
<value>System.Windows.Forms.UserControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

116
src/Settings.cs Normal file
View File

@@ -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 Microsoft.Win32;
using System.Collections.Generic;
using System;
namespace MeshCentralRouter
{
public static class Settings
{
public static void SetRegValue(string name, string value)
{
try { Registry.SetValue(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router", name, value); } catch (Exception) { }
}
public static void SetRegValue(string name, bool value)
{
try { Registry.SetValue(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router", name, value.ToString()); } catch (Exception) { }
}
public static void SetRegValue(string name, int value)
{
try { Registry.SetValue(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router", name, value.ToString()); } catch (Exception) { }
}
/// <summary>
/// This function querys the registry. If the key is found it returns the value as a string
/// </summary>
/// <param name="name">Keyname</param>
/// <param name="value">Return on fail</param>
/// <returns></returns>
public static string GetRegValue(string name, string 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; }
}
/// <summary>
/// This function querys the registry. If the key is found it returns the value as a boolean
/// </summary>
/// <param name="name">Keyname</param>
/// <param name="value">Return on fail</param>
/// <returns></returns>
public static bool GetRegValue(string name, bool value)
{
try { return bool.Parse(GetRegValue(name, value.ToString())); } catch (Exception) { return value; }
}
public static int GetRegValue(string name, int value)
{
try { return int.Parse(GetRegValue(name, value.ToString())); } catch (Exception) { return value; }
}
public static void SetApplications(List<string[]> 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]);
skey.SetValue("Arguments", app[3]);
}
}
}
}
public static List<string[]> GetApplications()
{
List<string[]> apps = new List<string[]>();
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 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);
}
}
}
return apps;
}
public static void ClearApplications()
{
RegistryKey key = Registry.CurrentUser.CreateSubKey(@"HKEY_CURRENT_USER\SOFTWARE\Open Source\MeshCentral Router", true);
key.DeleteSubKeyTree("Applications");
key.Close();
}
}
}

102
src/SettingsForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,102 @@
namespace MeshCentralRouter
{
partial class SettingsForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SettingsForm));
this.cancelButton = new System.Windows.Forms.Button();
this.okButton = new System.Windows.Forms.Button();
this.allInterfacesCheckBox = new System.Windows.Forms.CheckBox();
this.systemTrayCheckBox = new System.Windows.Forms.CheckBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// allInterfacesCheckBox
//
resources.ApplyResources(this.allInterfacesCheckBox, "allInterfacesCheckBox");
this.allInterfacesCheckBox.Name = "allInterfacesCheckBox";
this.allInterfacesCheckBox.UseVisualStyleBackColor = true;
//
// systemTrayCheckBox
//
resources.ApplyResources(this.systemTrayCheckBox, "systemTrayCheckBox");
this.systemTrayCheckBox.Name = "systemTrayCheckBox";
this.systemTrayCheckBox.UseVisualStyleBackColor = true;
//
// groupBox1
//
resources.ApplyResources(this.groupBox1, "groupBox1");
this.groupBox1.Controls.Add(this.systemTrayCheckBox);
this.groupBox1.Controls.Add(this.allInterfacesCheckBox);
this.groupBox1.Name = "groupBox1";
this.groupBox1.TabStop = false;
//
// SettingsForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SettingsForm";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.CheckBox allInterfacesCheckBox;
private System.Windows.Forms.CheckBox systemTrayCheckBox;
private System.Windows.Forms.GroupBox groupBox1;
}
}

52
src/SettingsForm.cs Normal file
View File

@@ -0,0 +1,52 @@
/*
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.Windows.Forms;
namespace MeshCentralRouter
{
public partial class SettingsForm : Form
{
public SettingsForm()
{
InitializeComponent();
Translate.TranslateControl(this);
}
public bool BindAllInterfaces
{
get { return allInterfacesCheckBox.Checked; }
set { allInterfacesCheckBox.Checked = value; }
}
public bool ShowSystemTray
{
get { return systemTrayCheckBox.Checked; }
set { systemTrayCheckBox.Checked = value; }
}
private void okButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}

1979
src/SettingsForm.resx Normal file

File diff suppressed because it is too large Load Diff

102
src/SshUsernameForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,102 @@
namespace MeshCentralRouter
{
partial class SshUsernameForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SshUsernameForm));
this.cancelButton = new System.Windows.Forms.Button();
this.okButton = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.label2 = new System.Windows.Forms.Label();
this.usernameTextBox = new System.Windows.Forms.TextBox();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// groupBox1
//
resources.ApplyResources(this.groupBox1, "groupBox1");
this.groupBox1.Controls.Add(this.usernameTextBox);
this.groupBox1.Controls.Add(this.label2);
this.groupBox1.Name = "groupBox1";
this.groupBox1.TabStop = false;
//
// label2
//
resources.ApplyResources(this.label2, "label2");
this.label2.Name = "label2";
//
// usernameTextBox
//
resources.ApplyResources(this.usernameTextBox, "usernameTextBox");
this.usernameTextBox.Name = "usernameTextBox";
this.usernameTextBox.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
//
// SshUsernameForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SshUsernameForm";
this.Load += new System.EventHandler(this.SshUsernameForm_Load);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox usernameTextBox;
}
}

62
src/SshUsernameForm.cs Normal file
View File

@@ -0,0 +1,62 @@
/*
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.Windows.Forms;
namespace MeshCentralRouter
{
public partial class SshUsernameForm : Form
{
public SshUsernameForm()
{
InitializeComponent();
Translate.TranslateControl(this);
}
public string Username
{
get { return usernameTextBox.Text; }
set { usernameTextBox.Text = value; updateInfo(); }
}
private void okButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
public void updateInfo()
{
okButton.Enabled = (usernameTextBox.Text.Length > 0) && (usernameTextBox.Text.IndexOf(" ") == -1);
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
updateInfo();
}
private void SshUsernameForm_Load(object sender, EventArgs e)
{
updateInfo();
usernameTextBox.Focus();
}
}
}

1970
src/SshUsernameForm.resx Normal file

File diff suppressed because it is too large Load Diff

4965
src/Translate.cs Normal file

File diff suppressed because it is too large Load Diff

110
src/UpdateForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,110 @@
namespace MeshCentralRouter
{
partial class UpdateForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UpdateForm));
this.cancelButton = new System.Windows.Forms.Button();
this.okButton = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.updateProgressBar = new System.Windows.Forms.ProgressBar();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.mainLabel = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// cancelButton
//
resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Name = "cancelButton";
this.cancelButton.UseVisualStyleBackColor = true;
//
// okButton
//
resources.ApplyResources(this.okButton, "okButton");
this.okButton.Name = "okButton";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// groupBox1
//
resources.ApplyResources(this.groupBox1, "groupBox1");
this.groupBox1.Controls.Add(this.updateProgressBar);
this.groupBox1.Controls.Add(this.pictureBox1);
this.groupBox1.Controls.Add(this.mainLabel);
this.groupBox1.Name = "groupBox1";
this.groupBox1.TabStop = false;
//
// updateProgressBar
//
resources.ApplyResources(this.updateProgressBar, "updateProgressBar");
this.updateProgressBar.Name = "updateProgressBar";
//
// pictureBox1
//
resources.ApplyResources(this.pictureBox1, "pictureBox1");
this.pictureBox1.Image = global::MeshCentralRouter.Properties.Resources.MeshCentral;
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.TabStop = false;
//
// mainLabel
//
resources.ApplyResources(this.mainLabel, "mainLabel");
this.mainLabel.Name = "mainLabel";
//
// UpdateForm
//
this.AcceptButton = this.okButton;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelButton;
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.okButton);
this.Controls.Add(this.cancelButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "UpdateForm";
this.groupBox1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label mainLabel;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.ProgressBar updateProgressBar;
}
}

169
src/UpdateForm.cs Normal file
View File

@@ -0,0 +1,169 @@
/*
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.IO;
using System.Net;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.Net.Security;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace MeshCentralRouter
{
public partial class UpdateForm : Form
{
private string url = null;
private string hash = null;
private int size = 0;
private string[] args = null;
private string serverTlsCertHash = null;
public UpdateForm(string url, string hash, int size, string[] args, string serverhash)
{
InitializeComponent();
Translate.TranslateControl(this);
this.url = url;
this.hash = hash;
this.size = size;
this.args = args;
this.serverTlsCertHash = serverhash;
try
{
FileInfo selfExe = new FileInfo(Assembly.GetExecutingAssembly().Location);
string[] lines = File.ReadAllLines(Path.Combine(selfExe.Directory.FullName, @"customization\customize.txt"));
if (lines[4] != "") { this.Text = lines[4]; }
if (lines[5] != "") { mainLabel.Text = lines[5]; }
}
catch (Exception) { }
}
private void okButton_Click(object sender, EventArgs e)
{
DownloadUpdate();
}
private void Client_DownloadProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e)
{
updateProgressBar.Value = e.ProgressPercentage;
}
private void DownloadUpdate()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
Uri x = webRequest.RequestUri;
webRequest.Method = "GET";
webRequest.Timeout = 10000;
webRequest.BeginGetResponse(new AsyncCallback(DownloadUpdateRespone), webRequest);
webRequest.ServerCertificateValidationCallback += RemoteCertificateValidationCallback;
updateProgressBar.Visible = true;
}
public bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
// Check MeshCentral server's TLS certificate. This is our first security layer.
if ((serverTlsCertHash != null) && (serverTlsCertHash != certificate.GetCertHashString().ToLower()) && (serverTlsCertHash != GetMeshKeyHash(certificate).ToLower()) && (serverTlsCertHash != GetMeshCertHash(certificate).ToLower())) return false;
return true;
}
public delegate void updateProgressHandler(int ptr, int total);
public void updateProgress(int ptr, int total)
{
if (this.InvokeRequired) { this.Invoke(new updateProgressHandler(updateProgress), ptr, total); return; }
updateProgressBar.Visible = true;
updateProgressBar.Maximum = total;
if (ptr <= total) { updateProgressBar.Value = ptr; } else { updateProgressBar.Value = total; }
}
public delegate void updateMessageHandler(string msg, int buttons);
public void updateMessage(string msg, int buttons)
{
if (this.InvokeRequired) { this.Invoke(new updateMessageHandler(updateMessage), msg, buttons); return; }
mainLabel.Text = msg;
okButton.Enabled = ((buttons & 1) != 0);
cancelButton.Enabled = ((buttons & 2) != 0);
updateProgressBar.Visible = ((buttons & 4) != 0);
}
private void DownloadUpdateRespone(IAsyncResult asyncResult)
{
long received = 0;
HttpWebRequest webRequest = (HttpWebRequest)asyncResult.AsyncState;
try
{
// Hash our own executable
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult))
{
byte[] buffer = new byte[4096];
FileStream fileStream = File.OpenWrite(System.Reflection.Assembly.GetEntryAssembly().Location + ".update.exe");
using (Stream input = webResponse.GetResponseStream())
{
int size = input.Read(buffer, 0, buffer.Length);
while (size > 0)
{
fileStream.Write(buffer, 0, size);
received += size;
updateProgress((int)received, (int)size);
size = input.Read(buffer, 0, buffer.Length);
}
}
fileStream.Flush();
fileStream.Close();
// Hash the resulting file
byte[] downloadHash;
using (var sha384 = SHA384Managed.Create()) { using (var stream = File.OpenRead(System.Reflection.Assembly.GetEntryAssembly().Location + ".update.exe")) { downloadHash = sha384.ComputeHash(stream); } }
string downloadHashHex = BitConverter.ToString(downloadHash).Replace("-", string.Empty).ToLower();
if (downloadHashHex != hash) {
updateMessage(Translate.T(Properties.Resources.InvalidDownload), 2);
File.Delete(System.Reflection.Assembly.GetEntryAssembly().Location + ".update.exe");
} else {
updateMessage(Translate.T(Properties.Resources.Updating), 0);
Process.Start(System.Reflection.Assembly.GetEntryAssembly().Location + ".update.exe", "-update:" + System.Reflection.Assembly.GetEntryAssembly().Location + " " + string.Join(" ", args));
Application.Exit();
}
}
}
catch (Exception ex) { updateMessage("Error: " + ex.ToString(), 2); }
}
// 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();
}
}
}

Some files were not shown because too many files have changed in this diff Show More