Compare commits

..

109 Commits

Author SHA1 Message Date
David Sparer
7445e917d6 fixed an incomplete merge 2018-10-25 10:26:28 -05:00
David Sparer
7a54b98ea2 Merge branch 'develop' into remove_statics
# Conflicts:
#	mRemoteV1/UI/Controls/MultiSshToolStrip.cs
#	mRemoteV1/UI/Forms/frmMain.cs
#	mRemoteV1/UI/Panels/PanelAdder.cs
#	mRemoteV1/UI/Window/ConnectionTreeWindow.cs
2018-10-25 10:02:32 -05:00
David Sparer
f56b8f8e42 Merge branch 'master' into develop
# Conflicts:
#	CHANGELOG.TXT
#	CREDITS.TXT
#	mRemoteV1/Properties/AssemblyInfo.cs
2018-10-20 09:48:50 -05:00
David Sparer
8ab221e5a8 Merge branch 'release/v1.76' 2018-10-18 17:29:11 -05:00
David Sparer
6b280b5aa4 Merge pull request #1145 from st-schuler/reconnect-patch
Fixing "Reconnect to previously opened sessions on startup"
2018-10-17 16:46:39 -05:00
st-schuler
e6713520c7 Fixing "Reconnect to previously opened sessions on startup" 2018-10-17 20:01:51 +02:00
David Sparer
4f75b0343e Merge pull request #1120 from Fyers/develop
Improved German translations
2018-10-10 08:22:34 -05:00
David Sparer
097ebccdcd Merge pull request #1129 from pablomh/patch-1
Update Language.es.resx
2018-10-10 06:48:49 -05:00
pablomh
954e1de4da Update Language.es.resx
Misc fixes.
2018-10-10 09:22:31 +02:00
Fyers
63dc79699d Merge pull request #2 from Fyers/merge
Merge
2018-10-08 23:31:54 +02:00
Fyers
63f342bbdb resolved conflicts 2018-10-08 23:31:01 +02:00
Fyers
7c9b90ed7d Merge remote-tracking branch 'upstream/develop' into merge 2018-10-08 23:21:31 +02:00
David Sparer
00e45b60ad Merge branch 'master' into develop
# Conflicts:
#	CHANGELOG.TXT
#	mRemoteV1/Properties/AssemblyInfo.cs
#	mRemoteV1/Resources/Language/Language.resx
2018-10-08 15:23:25 -05:00
David Sparer
d1a7a37909 Merge branch 'release/v1.76' 2018-10-07 18:42:03 -05:00
David Sparer
fbd0407863 added redirect clipboard to xml schema for v2.7 confcons 2018-10-03 21:05:12 -05:00
David Sparer
7bab1b4297 created a confcons v2.7 serializer 2018-10-03 21:00:23 -05:00
David Sparer
cfce9e9887 Merge pull request #951 from CrAbelleira/develop
Clipboard sharing setting implementation for RDP protocol
2018-10-03 20:51:19 -05:00
Fyers
9df2a96027 improved german translations 2018-10-01 19:26:26 +02:00
Cristian Abelleira Olañeta
d967c719f5 Added "RedirectClipboard" to ConnectionSerializers/Xml and MiscSerializers 2018-10-01 00:52:31 +02:00
Cristian Abelleira Olañeta
726491feee Completed BuildExpectedConnectionInfoPropertyList 2018-09-24 18:19:33 +02:00
Cristian Abelleira
36a94e1399 Merge branch 'develop' into develop 2018-09-24 11:39:32 +02:00
David Sparer
d9e65719d3 Merge branch 'release/v1.76' into develop
# Conflicts:
#	CHANGELOG.TXT
2018-09-22 17:40:42 -05:00
David Sparer
ee63292e55 Merge branch 'update-asset-labels' into develop 2018-08-26 12:49:18 -05:00
David Sparer
9fbcde3ca0 simplify labels 2018-08-26 12:46:17 -05:00
David Sparer
9e48c8e359 changed labels to be more enduser appropriate 2018-08-26 12:21:59 -05:00
David Sparer
da07f50e49 Merge branch 'label-github-assets' into develop 2018-08-25 18:27:39 -05:00
David Sparer
cc872cd2b4 fixed powershell script 2018-08-25 17:03:28 -05:00
David Sparer
a3fa1e541c modified build to label assets 2018-08-25 17:02:54 -05:00
David Sparer
b579e823bd updated credits 2018-08-25 11:42:11 -05:00
David Sparer
fc5b1ec85e adjusted a few english strings that were added in #928 2018-08-25 11:39:25 -05:00
David Sparer
e0c2037831 set assembly version to 1.77.0 2018-08-25 11:38:40 -05:00
David Sparer
9f44d6b75b added changelog items for v1.77 updates 2018-08-25 10:56:30 -05:00
David Sparer
b6f2fff42b Merge branch 'release/v1.76' into develop 2018-08-25 10:46:10 -05:00
David Sparer
067ac8fb56 Merge branch 'areytsman-Advanced_closing_tabs' into develop 2018-08-25 09:51:09 -05:00
David Sparer
4428089146 Merge branch 'Advanced_closing_tabs' of https://github.com/areytsman/mRemoteNG into areytsman-Advanced_closing_tabs
# Conflicts:
#	mRemoteV1/Resources/Language/Language.resx
#	mRemoteV1/Resources/Language/Language.ru.resx
2018-08-25 09:24:58 -05:00
David Sparer
4dea0d03ed Merge branch 'develop' into remove_statics
# Conflicts:
#	mRemoteNGTests/IntegrationTests/XmlSerializationLifeCycleTests.cs
#	mRemoteV1/App/Windows.cs
#	mRemoteV1/Config/Settings/SettingsLoader.cs
#	mRemoteV1/Messages/WriterDecorators/MessageFocusDecorator.cs
#	mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs
#	mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs
#	mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs
#	mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs
#	mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs
#	mRemoteV1/UI/Forms/frmChoosePanel.cs
#	mRemoteV1/UI/Forms/frmMain.cs
#	mRemoteV1/UI/Window/ConfigWindow.cs
#	mRemoteV1/UI/Window/ConnectionTreeWindow.cs
#	mRemoteV1/UI/Window/ErrorAndInfoWindow.cs
2018-08-24 18:14:54 -05:00
David Sparer
44ce674166 Merge branch 'release/v1.76' into develop 2018-08-24 17:20:56 -05:00
David Sparer
3fad827b9f Merge branch 'release/v1.76' into develop
# Conflicts:
#	Tools/zip_portable_files.ps1
#	mRemoteV1/Config/Putty/PuttySessionsRegistryProvider.cs
2018-08-22 10:39:09 -05:00
David Sparer
8bd571c78d added a wrapper around the windows registry api so we can better unit test classes that use the registry 2018-08-22 09:41:32 -05:00
David Sparer
38ff8340e4 Merge pull request #1016 from wwj402/develop
Chinese simplified language update for latest commit 05c96da
2018-08-19 12:01:31 -05:00
David Sparer
f759ea4bc2 Merge pull request #1072 from sli-pro/develop
Update the Russian language
2018-08-19 11:54:19 -05:00
sli-pro
011d0cad8c Update the Russian language
- Update the Russian language (Language.ru.resx)

- Update Language.resx
2018-08-11 18:34:11 +03:00
David Sparer
7526bb430f Merge pull request #1057 from Toomix/patch-1
Fixing NullReferenceException when renaming node
2018-08-01 06:45:42 -05:00
Toomix
7dbef77687 Fixing NullReferenceExcepction in renaming Node
When I have no selected node and I press F2 key, NullReferenceException appears in method RenameSelectedNode(). I added not null condition, it is working now. Debugged in VS2017.
2018-08-01 08:50:55 +02:00
Sean Kaim
a259ab9541 fix typo 2018-07-27 14:16:14 -04:00
Sean Kaim
08569276eb Revert "fixing changelog item"
This reverts commit edc4be2d44.
2018-07-27 14:11:43 -04:00
David Sparer
edc4be2d44 fixing changelog item 2018-07-27 07:49:00 -05:00
Sean Kaim
64422c60bb update changelog 2018-07-25 14:08:05 -04:00
Sean Kaim
a8b082ed4b fix test failures 2018-07-25 13:46:54 -04:00
Sean Kaim
5a5ade0d60 fix build failure 2018-07-25 13:10:39 -04:00
Sean Kaim
7e24e2dcfb fixes #971
Remove the "machineNode" XML node so that settings are portable to all systems
2018-07-25 13:02:30 -04:00
Sean Kaim
930579d983 PortableSettingsProvider code clean up 2018-07-25 12:35:53 -04:00
David Sparer
e05eb0807e fixed a few missed merge items 2018-07-23 15:19:29 -05:00
David Sparer
1aca1b7ae8 Merge branch 'develop' into remove_statics
# Conflicts:
#	mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializerTests.cs
#	mRemoteNGTests/mRemoteNGTests.csproj
#	mRemoteV1/App/Runtime.cs
#	mRemoteV1/Config/Connections/XmlConnectionsLoader.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs
#	mRemoteV1/Connection/ConnectionsService.cs
#	mRemoteV1/UI/Forms/frmMain.cs
#	mRemoteV1/UI/Menu/MainFileMenu.cs
#	mRemoteV1/UI/Window/ConfigWindow.cs
#	mRemoteV1/UI/Window/ConnectionTreeWindow.cs
#	mRemoteV1/UI/Window/PortScanWindow.cs
2018-07-23 15:06:15 -05:00
David Sparer
82847f07b2 Merge branch 'release/v1.76' into develop 2018-07-23 13:22:39 -05:00
Sean Kaim
a7280da30c Solution config was building wrong projects 2018-07-07 14:10:18 -04:00
Sean Kaim
ac2920820d the post publish job in the appveyor.yaml in ps1 form 2018-07-03 17:04:11 -04:00
Sean Kaim
fcecc4b31e post build zip artifact test 2018-07-03 14:24:12 -04:00
Sean Kaim
4abef50ca0 appveyor post build tests 2018-07-03 13:38:22 -04:00
Sean Kaim
5e16445b08 testing post build appveyor script 2018-07-03 13:11:10 -04:00
Sean Kaim
be593b8185 don't run post build zip in appveyor 2018-07-03 13:10:52 -04:00
Sean Kaim
ca27cb9981 Trim ConfigurationName 2018-07-03 12:34:20 -04:00
Sean Kaim
5b64e629c9 zip portable directly via powershell
Trying to fix appveyor artifact build
2018-07-03 11:59:02 -04:00
Sean Kaim
18640826b6 latest 7-zip 2018-07-03 11:48:26 -04:00
Sean Kaim
e4d3239831 appveyor build installer 2018-07-02 17:34:08 -04:00
Sean Kaim
e834eadbe1 appveyor artifacts test 2018-07-02 17:03:23 -04:00
Sean Kaim
0ec8f66972 Revert "test appveyor artifacts"
This reverts commit 458c462f49.
2018-07-02 15:31:17 -04:00
Sean Kaim
28b49aab70 fix quotes 2018-07-02 15:29:27 -04:00
Sean Kaim
458c462f49 test appveyor artifacts 2018-07-02 15:29:05 -04:00
Sean Kaim
6f6e2a1254 code clean up (convert to expression body) 2018-07-02 15:12:01 -04:00
Sean Kaim
f46a3d69e1 minor code clean up 2018-07-02 14:57:10 -04:00
Sean Kaim
fa787ed082 minor code clean up 2018-07-02 14:34:22 -04:00
wwj402
b5b748f993 Chinese simplified language update for latest commit 05c96da 2018-07-02 11:02:48 +08:00
David Sparer
75c866f7c1 remove unnecessary frmmain singleton property 2018-05-24 17:49:03 -05:00
David Sparer
c3ae438e9c fix failing test 2018-05-24 17:48:44 -05:00
David Sparer
314c989dae created IConnectionService interface and replaced usage with concrete type 2018-05-24 17:25:04 -05:00
David Sparer
8c350429b7 massive refactor of the rest of the frmmain statics 2018-05-22 21:31:22 -05:00
David Sparer
b21f2ffe65 removed some more default frmmain uses 2018-05-20 20:18:58 -05:00
David Sparer
66b307bff9 rdp protocol now no longer uses static frmmain ref 2018-05-20 20:06:22 -05:00
David Sparer
c43ef052c6 removed some frmmain static instance refs 2018-05-20 19:57:25 -05:00
David Sparer
d0a011d8ff Merge branch 'develop' into remove_statics 2018-05-20 11:08:29 -05:00
David Sparer
05c96da98f Merge branch 'release/v1.76' into develop 2018-05-20 11:08:14 -05:00
David Sparer
de9b78c5fb fix test 2018-05-20 09:51:35 -05:00
David Sparer
991505b043 fixed bug where connection properties weren't being passed to external tools 2018-05-20 09:42:31 -05:00
David Sparer
729166fc30 Merge branch 'develop' into remove_statics
# Conflicts:
#	mRemoteV1/UI/Forms/frmMain.Designer.cs
#	mRemoteV1/UI/Forms/frmMain.cs
#	mRemoteV1/UI/Menu/ViewMenu.cs
2018-05-20 09:29:55 -05:00
David Sparer
ea53fc190b Merge branch 'release/v1.76' into develop 2018-05-20 09:08:41 -05:00
Sean Kaim
662b5bde31 code clean up 2018-05-16 22:58:12 -04:00
Sean Kaim
388a4ed75b minor code clean up
* No need to kick off the registry provider here (it's done already in PuttySessionsManager#StartWatcher())

* if (Directory.Exists(sessionsFolderPath)) thows an exception even though it should have just fallen through... but if (!Directory.Exists(sessionsFolderPath)) doesn't throw and logs a message with a graceful return????

IDK... I had a Uri.IsWellFormedUriString test in there to avoid the exception, but it seems unnecessary...
2018-05-16 21:55:24 -04:00
Cristian Abelleira Olañeta
5311b522b7 Added InheritRedirectClipboard to CsvSerializer 2018-04-18 18:07:52 +02:00
Cristian Abelleira Olañeta
ea682e218d Fixed multiple errors in implementation 2018-04-15 20:13:28 +02:00
Cristian Abelleira Olañeta
aa5f7ef2a8 Implemented clipboard sharing setting for RDP protocol 2018-04-15 10:41:39 +02:00
Aleksei Reytsman
2c62218fd6 Add context menu items to close other and other to the right tabs 2018-03-28 18:21:47 +03:00
David Sparer
3fbad29017 removed a reference to static FrmMain 2018-03-12 21:43:01 -05:00
David Sparer
7a4b232695 updated a few more classes to not rely on Runtime 2018-03-04 12:23:19 -06:00
David Sparer
ba94e10cfa modified a few more classes to reduce reliance on Runtime 2018-03-04 12:04:32 -06:00
David Sparer
5093035f68 changed more classes to not rely on Runtime for the connections service 2018-03-04 11:52:58 -06:00
David Sparer
8159165968 modified some classes to request ConnectionsService as a ctor arg 2018-03-04 11:34:48 -06:00
David Sparer
5903481c87 made the Import class non static 2018-03-03 17:53:00 -06:00
David Sparer
e7afe5ea93 made some references to the connection service non static 2018-03-03 17:34:45 -06:00
David Sparer
f00dad3c96 moved several methods from Runtime to the connections service 2018-03-03 17:20:04 -06:00
David Sparer
db99a32c1d moved encryption key variable to the connections service where it makes more sense 2018-03-03 17:14:02 -06:00
David Sparer
c04bb44da3 fixed a composition bug and created a few tests 2018-03-03 13:25:42 -06:00
David Sparer
ba11746e6f removed ExternalToolsService var from Runtime 2018-03-03 12:47:37 -06:00
David Sparer
ced33027b8 made Shutdown and SettingsSaver non-static 2018-03-03 12:05:38 -06:00
David Sparer
0febc13ec7 removed use of the credential catalog Runtime var 2018-03-03 11:02:36 -06:00
David Sparer
05e62ff76f made Export class non static 2018-03-03 10:48:02 -06:00
David Sparer
107067cead removed unnecessary var in Runtime 2018-03-03 10:47:47 -06:00
David Sparer
13f51629af completed first round of fixes 2018-03-02 13:40:24 -06:00
David Sparer
8dc3303e0f first wave of changes 2018-03-02 06:38:55 -06:00
147 changed files with 4657 additions and 2454 deletions

View File

@@ -1,16 +1,10 @@
1.76.12 (2018-11-08):
1.77.0 (2018-xx-xx):
Features/Enhancements:
----------------------
#1180: Allow saving certain connection properties locally when using database
Fixes:
------
#1181: Connections sometimes dont immediately load when switching to sql feature
#1173: Fixed memory leak when loading connections multiple times
#1168: Autohide Connection and Config tab won't open when ssh connection active
#1134: Fixed issue where opening a connection opens same connection on other clients when using database feature
#449: Encrypt passwords saved to database
#1072: Russian translation improvements
#1016: Chinese (simplified) translation improvements
#928: Add context menu items to 'Close all but this' and 'Close all tabs to the right'
1.76.11 (2018-10-18):

View File

@@ -25,6 +25,7 @@ github.com/sirLoaf
github.com/Fyers
Vladimir Semenov (github.com/sli-pro)
Stephan (github.com/st-schuler)
Aleksey Reytsman (github.com/areytsman)
Past Contributors
@@ -63,6 +64,7 @@ Stefan (github.com/polluks)
github.com/emazv72
Vladimir Semenov (github.com/sli-pro)
Marco Sousa (github.com/marcomsousa)
github.com/wwj402
Included Source Code

View File

@@ -0,0 +1,17 @@
using System.Windows.Forms;
using NUnit.Framework;
// Dont put this in a namespace. Leaving it by itself tells NUnit
// to run it on assembly load
[SetUpFixture]
public class AssemblyTestSetup
{
[OneTimeSetUp]
public void AssemblySetup()
{
// ensure window options set before any test window created
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
}
}

View File

@@ -1,12 +1,16 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Security;
using mRemoteNG.Tree;
using mRemoteNGTests.Properties;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
@@ -18,7 +22,10 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
public void Setup(string confCons, string password)
{
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(() => password.ConvertToSecureString());
var connectionsService = new ConnectionsService(PuttySessionsManager.Instance,
new Import(Substitute.For<IWin32Window>()),
Substitute.For<IWin32Window>());
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(connectionsService, Substitute.For<IWin32Window>(), () => password.ConvertToSecureString());
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize(confCons);
}

View File

@@ -1,9 +1,8 @@
using System.Data;
using System.Security;
using mRemoteNG.Config.Serializers.MsSql;
using System.Linq;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Connection;
using mRemoteNG.Security;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tree;
using mRemoteNGTests.TestHelpers;
using NSubstitute;
@@ -14,37 +13,30 @@ namespace mRemoteNGTests.Config.Serializers
public class DataTableDeserializerTests
{
private DataTableDeserializer _deserializer;
private ICryptographyProvider _cryptographyProvider;
[SetUp]
public void Setup()
{
_cryptographyProvider = new LegacyRijndaelCryptographyProvider();
}
[Test]
public void WeCanDeserializeATree()
{
var model = CreateConnectionTreeModel();
var dataTable = CreateDataTable(model.RootNodes[0]);
_deserializer = new DataTableDeserializer(_cryptographyProvider, new SecureString());
_deserializer = new DataTableDeserializer(Substitute.For<IConnectionsService>());
var output = _deserializer.Deserialize(dataTable);
Assert.That(output.GetRecursiveChildList().Count, Is.EqualTo(model.GetRecursiveChildList().Count));
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(model.GetRecursiveChildList().Count()));
}
[Test]
public void WeCanDeserializeASingleEntry()
{
var dataTable = CreateDataTable(new ConnectionInfo());
_deserializer = new DataTableDeserializer(_cryptographyProvider, new SecureString());
_deserializer = new DataTableDeserializer(Substitute.For<IConnectionsService>());
var output = _deserializer.Deserialize(dataTable);
Assert.That(output.GetRecursiveChildList().Count, Is.EqualTo(1));
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(1));
}
private DataTable CreateDataTable(ConnectionInfo tableContent)
{
var serializer = new DataTableSerializer(new SaveFilter(), _cryptographyProvider, new SecureString());
var serializer = new DataTableSerializer(new SaveFilter());
return serializer.Serialize(tableContent);
}

View File

@@ -1,15 +1,11 @@
using System.Linq;
using System.Security;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.MsSql;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Security;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNGTests.TestHelpers;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Config.Serializers
@@ -23,10 +19,7 @@ namespace mRemoteNGTests.Config.Serializers
public void Setup()
{
_saveFilter = new SaveFilter();
_dataTableSerializer = new DataTableSerializer(
_saveFilter,
new LegacyRijndaelCryptographyProvider(),
new SecureString());
_dataTableSerializer = new DataTableSerializer(_saveFilter);
}
[Test]

View File

@@ -5,6 +5,7 @@ using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.SSH;
using mRemoteNG.Container;
using mRemoteNG.Tree.Root;
using NSubstitute;
using NUnit.Framework;
@@ -13,11 +14,13 @@ namespace mRemoteNGTests.Connection
public class ConnectionInfoTests
{
private ConnectionInfo _connectionInfo;
private IConnectionsService _connectionsService;
private const string TestDomain = "somedomain";
[SetUp]
public void Setup()
{
_connectionsService = Substitute.For<IConnectionsService>();
_connectionInfo = new ConnectionInfo();
}
@@ -79,7 +82,7 @@ namespace mRemoteNGTests.Connection
{
var eventWasCalled = false;
_connectionInfo.PropertyChanged += (sender, args) => eventWasCalled = true;
_connectionInfo.OpenConnections.Add(new ProtocolSSH2());
_connectionInfo.OpenConnections.Add(new ProtocolSSH2(_connectionsService));
Assert.That(eventWasCalled);
}
@@ -88,7 +91,7 @@ namespace mRemoteNGTests.Connection
{
var nameOfModifiedProperty = "";
_connectionInfo.PropertyChanged += (sender, args) => nameOfModifiedProperty = args.PropertyName;
_connectionInfo.OpenConnections.Add(new ProtocolSSH2());
_connectionInfo.OpenConnections.Add(new ProtocolSSH2(_connectionsService));
Assert.That(nameOfModifiedProperty, Is.EqualTo("OpenConnections"));
}

View File

@@ -1,31 +1,50 @@
using System.Collections.ObjectModel;
using System;
using System.Security;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.App.Update;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Settings;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Tools;
using mRemoteNG.Tools.CustomCollections;
using mRemoteNG.UI.Controls;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Window;
using NSubstitute;
using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNGTests.Connection.Protocol
{
public class IntegratedProgramTests
{
private readonly ExternalTool _extTool = new ExternalTool
{
DisplayName = "notepad",
FileName = @"%windir%\system32\notepad.exe",
Arguments = "",
TryIntegrate = true
};
public class IntegratedProgramTests
{
private ExternalToolsService _externalToolsService;
private IConnectionInitiator _connectionInitiator;
[Test]
[OneTimeSetUp]
public void OneTimeSetUp()
{
_connectionInitiator = Substitute.For<IConnectionInitiator>();
var extTool = new ExternalTool(_connectionInitiator, Substitute.For<IConnectionsService>())
{
DisplayName = "notepad",
FileName = @"%windir%\system32\notepad.exe",
Arguments = "",
TryIntegrate = true
};
_externalToolsService = new ExternalToolsService();
_externalToolsService.ExternalTools.Add(extTool);
}
[Test]
[Apartment(ApartmentState.STA)]
public void CanStartExternalApp()
{
SetExternalToolList(_extTool);
var sut = new IntegratedProgram();
var sut = new IntegratedProgram(_externalToolsService, Substitute.For<IConnectionsService>());
sut.InterfaceControl = BuildInterfaceControl("notepad", sut);
sut.Initialize();
var appStarted = sut.Connect();
@@ -34,23 +53,42 @@ namespace mRemoteNGTests.Connection.Protocol
}
[Test]
[Apartment(ApartmentState.STA)]
public void ConnectingToExternalAppThatDoesntExistDoesNothing()
{
SetExternalToolList(_extTool);
var sut = new IntegratedProgram();
var sut = new IntegratedProgram(_externalToolsService, Substitute.For<IConnectionsService>());
sut.InterfaceControl = BuildInterfaceControl("doesntExist", sut);
var appInitialized = sut.Initialize();
Assert.That(appInitialized, Is.False);
}
private void SetExternalToolList(ExternalTool externalTool)
{
Runtime.ExternalToolsService.ExternalTools = new FullyObservableCollection<ExternalTool> {externalTool};
}
private InterfaceControl BuildInterfaceControl(string extAppName, ProtocolBase sut)
{
var connectionWindow = new ConnectionWindow(new DockContent());
var frmMain = new FrmMain();
var import = new Import(Substitute.For<IWin32Window>());
var connectionsService = new ConnectionsService(PuttySessionsManager.Instance, import, frmMain);
var configWindow = new ConfigWindow(new DockContent(), connectionsService);
var sshTransferWindow = new SSHTransferWindow();
var connectionTreeWindow = new ConnectionTreeWindow(new DockContent(), _connectionInitiator, connectionsService);
Func<SecureString> encryptionKeySelectionFunc = () => connectionsService.EncryptionKey;
var connectionTree = connectionTreeWindow.ConnectionTree;
var export = new Export(new CredentialRepositoryList(), connectionsService, frmMain);
var connectionTreeContextMenu = new ConnectionContextMenu(connectionTree, _connectionInitiator, sshTransferWindow, export, _externalToolsService, import, connectionsService);
connectionTreeWindow.ConnectionTreeContextMenu = connectionTreeContextMenu;
var errorAndInfoWindow = new ErrorAndInfoWindow(new DockContent(), new DockPanel(), connectionTreeWindow);
var screenshotManagerWindow = new ScreenshotManagerWindow(new DockContent(), new DockPanel());
var shutdown = new Shutdown(new SettingsSaver(new ExternalToolsService()), new ConnectionsService(PuttySessionsManager.Instance, import, frmMain), frmMain);
var appUpdater = new AppUpdater(encryptionKeySelectionFunc);
Func<UpdateWindow> updateWindowBuilder = () => new UpdateWindow(new DockContent(), shutdown, appUpdater);
Func<NotificationAreaIcon> notificationAreaIconBuilder = () => new NotificationAreaIcon(frmMain, _connectionInitiator, shutdown, connectionsService);
Func<ExternalToolsWindow> externalToolsWindowBuilder = () => new ExternalToolsWindow(_connectionInitiator, _externalToolsService, () => connectionTree.SelectedNode, frmMain, connectionsService);
Func<PortScanWindow> portScanWindowBuilder = () => new PortScanWindow(connectionTreeWindow, import);
Func<ActiveDirectoryImportWindow> activeDirectoryImportWindowBuilder = () => new ActiveDirectoryImportWindow(() => connectionTreeWindow.SelectedNode, import, connectionsService);
var databaseConnectorFactory = new DatabaseConnectorFactory(encryptionKeySelectionFunc);
var windows = new Windows(_connectionInitiator, connectionTreeWindow, configWindow, errorAndInfoWindow, screenshotManagerWindow,
sshTransferWindow, updateWindowBuilder, notificationAreaIconBuilder, externalToolsWindowBuilder,
connectionsService, portScanWindowBuilder, activeDirectoryImportWindowBuilder, appUpdater, databaseConnectorFactory, frmMain);
var connectionWindow = new ConnectionWindow(new DockContent(), _connectionInitiator, windows, _externalToolsService, frmMain);
var connectionInfo = new ConnectionInfo {ExtApp = extAppName};
return new InterfaceControl(connectionWindow, sut, connectionInfo);
}

View File

@@ -1,9 +1,12 @@
using System.Collections;
using System.Collections.Specialized;
using mRemoteNG.Config.Putty;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.SSH;
using mRemoteNG.Connection.Protocol.Telnet;
using mRemoteNG.Connection.Protocol.VNC;
using NSubstitute;
using NUnit.Framework;
@@ -20,9 +23,10 @@ namespace mRemoteNGTests.Connection.Protocol
[SetUp]
public void Setup()
{
var connectionService = Substitute.For<IConnectionsService>();
_protocolList = new ProtocolList();
_protocol1 = new ProtocolTelnet();
_protocol2 = new ProtocolSSH2();
_protocol1 = new ProtocolTelnet(connectionService);
_protocol2 = new ProtocolSSH2(connectionService);
_protocol3 = new ProtocolVNC();
}

View File

@@ -1,7 +1,8 @@
using System;
using System.Linq;
using System.Xml.Linq;
using mRemoteNG.Config.Serializers;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Container;
@@ -9,6 +10,7 @@ using mRemoteNG.Security;
using mRemoteNG.Security.Factories;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using NSubstitute;
using NUnit.Framework;
@@ -31,7 +33,8 @@ namespace mRemoteNGTests.IntegrationTests
_originalModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
new SaveFilter());
_serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer);
_deserializer = new XmlConnectionsDeserializer();
var mockWindow = Substitute.For<IWin32Window>();
_deserializer = new XmlConnectionsDeserializer(new ConnectionsService(PuttySessionsManager.Instance, new Import(mockWindow), mockWindow), mockWindow);
}
[TearDown]
@@ -139,4 +142,4 @@ namespace mRemoteNGTests.IntegrationTests
return connectionTreeModel;
}
}
}
}

View File

@@ -40,7 +40,8 @@
public TType RedirectKeys { get; set; }
public TType RedirectDiskDrives { get; set; }
public TType RedirectPrinters { get; set; }
public TType RedirectPorts { get; set; }
public TType RedirectClipboard { get; set; }
public TType RedirectPorts { get; set; }
public TType RedirectSmartCards { get; set; }
public TType RedirectSound { get; set; }
public TType SoundQuality { get; set; }

View File

@@ -2,6 +2,7 @@
using System.Collections;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
using NSubstitute;
using NUnit.Framework;
@@ -34,7 +35,7 @@ namespace mRemoteNGTests.Tools
MacAddress = TestString,
UserField = TestString
};
_argumentParser = new ExternalToolArgumentParser(connectionInfo);
_argumentParser = new ExternalToolArgumentParser(connectionInfo, Substitute.For<IConnectionsService>());
}
[OneTimeTearDown]
@@ -52,7 +53,7 @@ namespace mRemoteNGTests.Tools
[Test]
public void NullConnectionInfoResultsInEmptyVariables()
{
var parser = new ExternalToolArgumentParser(null);
var parser = new ExternalToolArgumentParser(null, Substitute.For<IConnectionsService>());
var parsedText = parser.ParseArguments("test %USERNAME% test");
Assert.That(parsedText, Is.EqualTo("test test"));
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Linq;
using mRemoteNG.Tools.WindowsRegistry;
using NUnit.Framework;
namespace mRemoteNGTests.Tools.Registry
{
public class WindowsRegistryTests
{
private WindowsRegistry _registry;
[SetUp]
public void Setup()
{
_registry = new WindowsRegistry();
}
[Test]
public void CanGetSubkeyNames()
{
var subKeyNames = _registry.GetSubKeyNames(RegistryHive.CurrentUser, "Software");
Assert.That(subKeyNames, Does.Contain("Microsoft"));
}
[Test]
public void GetSubkeyNamesThrowsIfGivenNullKeyPath()
{
Assert.Throws<ArgumentNullException>(() => _registry.GetSubKeyNames(RegistryHive.CurrentUser, null));
}
[Test]
public void CanGetKeyValue()
{
var keyValue = _registry.GetKeyValue(RegistryHive.ClassesRoot, @".dll\PersistentHandler", "");
Assert.That(keyValue.FirstOrDefault(), Is.EqualTo("{098f2470-bae0-11cd-b579-08002b30bfeb}"));
}
[Test]
public void GetKeyValueThrowsIfGivenNullKeyPath()
{
Assert.Throws<ArgumentNullException>(() => _registry.GetKeyValue(RegistryHive.CurrentUser, null, ""));
}
[Test]
public void GetKeyValueThrowsIfGivenNullPropertyName()
{
Assert.Throws<ArgumentNullException>(() => _registry.GetKeyValue(RegistryHive.CurrentUser, "", null));
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
using mRemoteNG.UI.Controls;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.UI.Controls
{
public class ExternalToolsToolStripTests
{
private ExternalToolsToolStrip _externalToolsToolStrip;
[SetUp]
public void Setup()
{
_externalToolsToolStrip = new ExternalToolsToolStrip();
}
[TearDown]
public void Teardown()
{
_externalToolsToolStrip.Dispose();
}
[Test]
public void SettingExternalToolsServiceToNullThrowsException()
{
Assert.Throws<ArgumentNullException>(() => _externalToolsToolStrip.ExternalToolsService = null);
}
[Test]
public void AddExternalToolsToToolBarCreatesControlsForAllExternalTools()
{
var externaltoolsService = new ExternalToolsService();
externaltoolsService.ExternalTools.Add(BuildExternalTool());
externaltoolsService.ExternalTools.Add(BuildExternalTool());
_externalToolsToolStrip.ExternalToolsService = externaltoolsService;
_externalToolsToolStrip.AddExternalToolsToToolBar();
Assert.That(_externalToolsToolStrip.Items.Count, Is.EqualTo(2));
}
private ExternalTool BuildExternalTool()
{
return new ExternalTool(Substitute.For<IConnectionInitiator>(), Substitute.For<IConnectionsService>());
}
}
}

View File

@@ -6,7 +6,6 @@ namespace mRemoteNGTests.UI.Controls
{
public TextBoxExtensionsTestForm()
{
Application.EnableVisualStyles();
InitializeComponent();
}
}

View File

@@ -30,7 +30,8 @@ namespace mRemoteNGTests.UI.Controls
{
const string text = "Type Here";
var textBox = new TextBoxTester(_textBoxExtensionsTestForm.textBox1.Name);
Assert.That(textBox.Properties.SetCueBannerText(text), Is.True);
var textWasSet = textBox.Properties.SetCueBannerText(text);
Assert.That(textWasSet, Is.True);
}
[Test]

View File

@@ -0,0 +1,16 @@
using System.Threading;
using mRemoteNG.UI.Forms;
using NUnit.Framework;
namespace mRemoteNGTests.UI.Forms
{
public class FrmMainTests
{
[Test]
[Apartment(ApartmentState.STA)]
public void CanCreateFrmMain()
{
var frmMain = new FrmMain();
}
}
}

View File

@@ -1,9 +1,24 @@
using NUnit.Framework;
using System;
using System.Security;
using System.Windows.Forms;
using System.Xml.Linq;
using mRemoteNG.App;
using mRemoteNG.App.Update;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Config.Settings;
using mRemoteNG.Connection;
using mRemoteNG.Security;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.UI.Forms
{
public class OptionsFormSetupAndTeardown
public class OptionsFormSetupAndTeardown
{
protected frmOptions _optionsForm;
@@ -15,7 +30,16 @@ namespace mRemoteNGTests.UI.Forms
[SetUp]
public void Setup()
{
_optionsForm = new frmOptions();
var frmMain = new FrmMain();
var connectionInitiator = Substitute.For<IConnectionInitiator>();
var import = new Import(Substitute.For<IWin32Window>());
var shutdown = new Shutdown(new SettingsSaver(new ExternalToolsService()), new ConnectionsService(PuttySessionsManager.Instance, import, frmMain), frmMain);
var connectionsService = new ConnectionsService(PuttySessionsManager.Instance, import, frmMain);
Func<NotificationAreaIcon> notificationIconBuilder = () => new NotificationAreaIcon(frmMain, connectionInitiator, shutdown, connectionsService);
Func<SecureString> encryptionKeySelectionFunc = () => connectionsService.EncryptionKey;
var databaseConnectorFactory = new DatabaseConnectorFactory(encryptionKeySelectionFunc);
var appUpdater = new AppUpdater(encryptionKeySelectionFunc);
_optionsForm = new frmOptions(connectionInitiator, type => {}, notificationIconBuilder, connectionsService, appUpdater, databaseConnectorFactory, frmMain);
_optionsForm.Show();
}

View File

@@ -8,7 +8,9 @@ using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Container;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Window;
using NSubstitute;
using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
{
@@ -19,7 +21,7 @@ namespace mRemoteNGTests.UI.Window.ConfigWindowTests
[SetUp]
public void Setup()
{
_configWindow = new ConfigWindow
_configWindow = new ConfigWindow(new DockContent(), Substitute.For<IConnectionsService>())
{
PropertiesVisible = true
};
@@ -149,6 +151,7 @@ namespace mRemoteNGTests.UI.Window.ConfigWindowTests
nameof(ConnectionInfo.RedirectKeys),
nameof(ConnectionInfo.RedirectDiskDrives),
nameof(ConnectionInfo.RedirectPrinters),
nameof(ConnectionInfo.RedirectClipboard),
nameof(ConnectionInfo.RedirectPorts),
nameof(ConnectionInfo.RedirectSmartCards),
nameof(ConnectionInfo.RedirectSound),

View File

@@ -2,7 +2,9 @@
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.UI.Window;
using NSubstitute;
using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
{
@@ -20,7 +22,7 @@ namespace mRemoteNGTests.UI.Window.ConfigWindowTests
ConnectionInfo = ConfigWindowGeneralTests.ConstructConnectionInfo(Protocol, TestAgainstContainerInfo);
ExpectedPropertyList = ConfigWindowGeneralTests.BuildExpectedConnectionInfoPropertyList(Protocol, TestAgainstContainerInfo);
ConfigWindow = new ConfigWindow
ConfigWindow = new ConfigWindow(new DockContent(), Substitute.For<IConnectionsService>())
{
PropertiesVisible = true,
};

View File

@@ -1,19 +1,38 @@
using System.Threading;
using System.Security;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Security;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using mRemoteNG.UI.Controls;
using mRemoteNG.UI.Window;
using NSubstitute;
using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNGTests.UI.Window
{
public class ConnectionTreeWindowTests
public class ConnectionTreeWindowTests
{
private ConnectionTreeWindow _connectionTreeWindow;
[SetUp]
public void Setup()
{
_connectionTreeWindow = new ConnectionTreeWindow(new DockContent());
var connectionInitiator = Substitute.For<IConnectionInitiator>();
var connectionTree = new ConnectionTree();
var sshTransferWindow = new SSHTransferWindow();
var externalToolsService = new ExternalToolsService();
var import = new Import(Substitute.For<IWin32Window>());
var connectionsService = new ConnectionsService(PuttySessionsManager.Instance, import, connectionTree);
var export = new Export(new CredentialRepositoryList(), connectionsService, connectionTree);
var connectionContextMenu = new ConnectionContextMenu(connectionTree, connectionInitiator, sshTransferWindow, export, externalToolsService, import, connectionsService);
_connectionTreeWindow = new ConnectionTreeWindow(new DockContent(), connectionInitiator, connectionsService) {ConnectionTreeContextMenu = connectionContextMenu};
}
[TearDown]

View File

@@ -109,6 +109,7 @@
</Choose>
<ItemGroup>
<Compile Include="App\UpdaterTests.cs" />
<Compile Include="AssemblyTestSetup.cs" />
<Compile Include="BinaryFileTests.cs" />
<Compile Include="Config\Connections\Multiuser\ConnectionsUpdateAvailableEventArgsTests.cs" />
<Compile Include="Config\DataProviders\FileBackupCreatorTests.cs" />
@@ -178,6 +179,7 @@
<Compile Include="Tools\ExternalToolsArgumentParserTests.cs" />
<Compile Include="Tools\FullyObservableCollectionTests.cs" />
<Compile Include="Tools\OptionalTests.cs" />
<Compile Include="Tools\Registry\WindowsRegistryTests.cs" />
<Compile Include="Tree\ClickHandlers\TreeNodeCompositeClickHandlerTests.cs" />
<Compile Include="Tree\ConnectionTreeDragAndDropHandlerTests.cs" />
<Compile Include="Tree\ConnectionTreeModelTests.cs" />
@@ -207,6 +209,7 @@
<Compile Include="Tree\RootNodeInfoTests.cs" />
<Compile Include="Tree\ClickHandlers\SwitchToConnectionClickHandlerTests.cs" />
<Compile Include="Tree\SelectedConnectionDeletionConfirmerTests.cs" />
<Compile Include="UI\Controls\ExternalToolsToolStripTests.cs" />
<Compile Include="UI\Controls\ConnectionTreeTests.cs" />
<Compile Include="UI\Controls\PageSequenceTests.cs" />
<Compile Include="UI\Controls\SecureTextBoxTestForm.cs">
@@ -229,6 +232,7 @@
<DependentUpon>TextBoxExtensionsTestForm.cs</DependentUpon>
</Compile>
<Compile Include="UI\Controls\TextBoxExtensionsTests.cs" />
<Compile Include="UI\Forms\FrmMainTests.cs" />
<Compile Include="UI\Forms\OptionsFormSetupAndTeardown.cs" />
<Compile Include="UI\Forms\PasswordFormTests.cs" />
<Compile Include="UI\WindowListTests.cs" />

View File

@@ -6,25 +6,35 @@ using System;
using System.Diagnostics;
using System.Windows.Forms;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
namespace mRemoteNG.App
{
public static class CompatibilityChecker
public class CompatibilityChecker
{
public static void CheckCompatibility(MessageCollector messageCollector)
private readonly MessageCollector _messageCollector;
private readonly IWin32Window _dialogWindowParent;
public CompatibilityChecker(MessageCollector messageCollector, IWin32Window dialogWindowParent)
{
CheckFipsPolicy(messageCollector);
CheckLenovoAutoScrollUtility(messageCollector);
_messageCollector = messageCollector.ThrowIfNull(nameof(messageCollector));
_dialogWindowParent = dialogWindowParent.ThrowIfNull(nameof(dialogWindowParent));
}
private static void CheckFipsPolicy(MessageCollector messageCollector)
public void CheckCompatibility()
{
messageCollector.AddMessage(MessageClass.InformationMsg, "Checking FIPS Policy...", true);
CheckFipsPolicy();
CheckLenovoAutoScrollUtility();
}
private void CheckFipsPolicy()
{
_messageCollector.AddMessage(MessageClass.InformationMsg, "Checking FIPS Policy...", true);
if (!FipsPolicyEnabledForServer2003() && !FipsPolicyEnabledForServer2008AndNewer()) return;
var errorText = string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName,
GeneralAppInfo.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
messageCollector.AddMessage(MessageClass.ErrorMsg, errorText, true);
MessageBox.Show(FrmMain.Default, errorText);
_messageCollector.AddMessage(MessageClass.ErrorMsg, errorText, true);
MessageBox.Show(_dialogWindowParent, errorText);
Environment.Exit(1);
}
@@ -46,9 +56,9 @@ namespace mRemoteNG.App
return (int)fipsPolicy != 0;
}
private static void CheckLenovoAutoScrollUtility(MessageCollector messageCollector)
private void CheckLenovoAutoScrollUtility()
{
messageCollector.AddMessage(MessageClass.InformationMsg, "Checking Lenovo AutoScroll Utility...", true);
_messageCollector.AddMessage(MessageClass.InformationMsg, "Checking Lenovo AutoScroll Utility...", true);
if (!Settings.Default.CompatibilityWarnLenovoAutoScrollUtility)
return;
@@ -60,7 +70,7 @@ namespace mRemoteNG.App
}
catch (InvalidOperationException ex)
{
messageCollector.AddExceptionMessage("Error in CheckLenovoAutoScrollUtility", ex);
_messageCollector.AddExceptionMessage("Error in CheckLenovoAutoScrollUtility", ex);
}
if (proccesses.Length <= 0) return;

View File

@@ -8,8 +8,10 @@ using mRemoteNG.Config.Serializers.Csv;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Credential;
using mRemoteNG.Security;
using mRemoteNG.Security.Factories;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Forms;
@@ -17,9 +19,20 @@ using mRemoteNG.UI.Forms;
namespace mRemoteNG.App
{
public static class Export
public class Export
{
public static void ExportToFile(ConnectionInfo selectedNode, ConnectionTreeModel connectionTreeModel)
private readonly IConnectionsService _connectionsService;
private readonly ICredentialRepositoryList _credentialRepositoryList;
private readonly IWin32Window _dialogWindowParent;
public Export(ICredentialRepositoryList credentialRepositoryList, IConnectionsService connectionsService, IWin32Window dialogWindowParent)
{
_credentialRepositoryList = credentialRepositoryList.ThrowIfNull(nameof(credentialRepositoryList));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
_dialogWindowParent = dialogWindowParent.ThrowIfNull(nameof(dialogWindowParent));
}
public void ExportToFile(ConnectionInfo selectedNode, ConnectionTreeModel connectionTreeModel)
{
try
{
@@ -36,7 +49,7 @@ namespace mRemoteNG.App
exportForm.SelectedConnection = selectedNode;
}
if (exportForm.ShowDialog(FrmMain.Default) != DialogResult.OK)
if (exportForm.ShowDialog(_dialogWindowParent) != DialogResult.OK)
return;
ConnectionInfo exportTarget;
@@ -69,7 +82,7 @@ namespace mRemoteNG.App
}
}
private static void SaveExportFile(string fileName, SaveFormat saveFormat, SaveFilter saveFilter, ConnectionInfo exportTarget)
private void SaveExportFile(string fileName, SaveFormat saveFormat, SaveFilter saveFilter, ConnectionInfo exportTarget)
{
try
{
@@ -79,14 +92,14 @@ namespace mRemoteNG.App
case SaveFormat.mRXML:
var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build();
var rootNode = exportTarget.GetRootParent() as RootNodeInfo;
var connectionNodeSerializer = new XmlConnectionNodeSerializer26(
var connectionNodeSerializer = new XmlConnectionNodeSerializer27(
cryptographyProvider,
rootNode?.PasswordString.ConvertToSecureString() ?? new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString(),
saveFilter);
serializer = new XmlConnectionsSerializer(cryptographyProvider, connectionNodeSerializer);
break;
case SaveFormat.mRCSV:
serializer = new CsvConnectionsSerializerMremotengFormat(saveFilter, Runtime.CredentialProviderCatalog);
serializer = new CsvConnectionsSerializerMremotengFormat(saveFilter, _credentialRepositoryList);
break;
default:
throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null);
@@ -101,7 +114,7 @@ namespace mRemoteNG.App
}
finally
{
Runtime.ConnectionsService.RemoteConnectionsSyncronizer?.Enable();
_connectionsService.RemoteConnectionsSyncronizer?.Enable();
}
}
}

View File

@@ -3,15 +3,26 @@ using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using mRemoteNG.Config.Import;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using mRemoteNG.Tools;
namespace mRemoteNG.App
{
public static class Import
public class Import
{
public static void ImportFromFile(ContainerInfo importDestinationContainer)
private readonly IWin32Window _dialogWindowParent;
public Import(IWin32Window dialogWindowParent)
{
_dialogWindowParent = dialogWindowParent.ThrowIfNull(nameof(dialogWindowParent));
}
// TODO - this is only a property to break up a circular dependency. move this to ctor when able
public IConnectionsService ConnectionsService { get; set; }
public void ImportFromFile(ContainerInfo importDestinationContainer)
{
try
{
@@ -50,7 +61,7 @@ namespace mRemoteNG.App
}
}
Runtime.ConnectionsService.SaveConnectionsAsync();
ConnectionsService.SaveConnectionsAsync();
}
}
catch (Exception ex)
@@ -59,12 +70,12 @@ namespace mRemoteNG.App
}
}
public static void ImportFromActiveDirectory(string ldapPath, ContainerInfo importDestinationContainer, bool importSubOu)
public void ImportFromActiveDirectory(string ldapPath, ContainerInfo importDestinationContainer, bool importSubOu)
{
try
{
ActiveDirectoryImporter.Import(ldapPath, importDestinationContainer, importSubOu);
Runtime.ConnectionsService.SaveConnectionsAsync();
ConnectionsService.SaveConnectionsAsync();
}
catch (Exception ex)
{
@@ -72,13 +83,13 @@ namespace mRemoteNG.App
}
}
public static void ImportFromPortScan(IEnumerable<ScanHost> hosts, ProtocolType protocol, ContainerInfo importDestinationContainer)
public void ImportFromPortScan(IEnumerable<ScanHost> hosts, ProtocolType protocol, ContainerInfo importDestinationContainer)
{
try
{
var importer = new PortScanImporter(protocol);
importer.Import(hosts, importDestinationContainer);
Runtime.ConnectionsService.SaveConnectionsAsync();
ConnectionsService.SaveConnectionsAsync();
}
catch (Exception ex)
{
@@ -86,14 +97,14 @@ namespace mRemoteNG.App
}
}
private static IConnectionImporter<string> BuildConnectionImporterFromFileExtension(string fileName)
private IConnectionImporter<string> BuildConnectionImporterFromFileExtension(string fileName)
{
// TODO: Use the file contents to determine the file type instead of trusting the extension
var extension = Path.GetExtension(fileName) ?? "";
switch (extension.ToLowerInvariant())
{
case ".xml":
return new MRemoteNGXmlImporter();
return new MRemoteNGXmlImporter(ConnectionsService, _dialogWindowParent);
case ".csv":
return new MRemoteNGCsvImporter();
case ".rdp":

View File

@@ -2,15 +2,14 @@
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using mRemoteNG.Connection;
namespace mRemoteNG.App.Info
{
public static class SettingsFileInfo
{
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location);
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
public static string SettingsPath => Runtime.IsPortableEdition ? ExePath : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName;
public static string SettingsPath { get; } = Runtime.IsPortableEdition ? ExePath : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName;
public static string LayoutFileName { get; } = "pnlLayout.xml";
public static string ExtAppsFilesName { get; } = "extApps.xml";
public static string ThemesFileName { get; } = "Themes.xml";

View File

@@ -1,18 +1,24 @@
using System.IO;
using mRemoteNG.Config.Connections;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
using System.IO;
namespace mRemoteNG.App.Initialization
{
public class CredsAndConsSetup
{
public void LoadCredsAndCons()
public class CredsAndConsSetup
{
private readonly IConnectionsService _connectionsService;
public CredsAndConsSetup(IConnectionsService connectionsService)
{
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
public void LoadCredsAndCons()
{
new SaveConnectionsOnEdit(Runtime.ConnectionsService);
if (Settings.Default.FirstStart && !Settings.Default.LoadConsFromCustomLocation && !File.Exists(_connectionsService.GetStartupConnectionFileName()))
_connectionsService.NewConnectionsFile(_connectionsService.GetStartupConnectionFileName());
if (Settings.Default.FirstStart && !Settings.Default.LoadConsFromCustomLocation && !File.Exists(Runtime.ConnectionsService.GetStartupConnectionFileName()))
Runtime.ConnectionsService.NewConnectionsFile(Runtime.ConnectionsService.GetStartupConnectionFileName());
Runtime.LoadConnections();
_connectionsService.LoadConnections();
}
}
}

View File

@@ -3,10 +3,13 @@ using System.Linq;
using mRemoteNG.Messages;
using mRemoteNG.Messages.MessageWriters;
using mRemoteNG.Messages.WriterDecorators;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Window;
namespace mRemoteNG.App.Initialization
{
public class MessageCollectorSetup
public class MessageCollectorSetup
{
public static void SetupMessageCollector(MessageCollector messageCollector, IList<IMessageWriter> messageWriterList)
{
@@ -19,13 +22,13 @@ namespace mRemoteNG.App.Initialization
};
}
public static void BuildMessageWritersFromSettings(IList<IMessageWriter> messageWriterList)
public static void BuildMessageWritersFromSettings(IList<IMessageWriter> messageWriterList, FrmMain frmMain, ErrorAndInfoWindow errorAndInfoWindow)
{
#if DEBUG
messageWriterList.Add(BuildDebugConsoleWriter());
#endif
messageWriterList.Add(BuildTextLogMessageWriter());
messageWriterList.Add(BuildNotificationPanelMessageWriter());
messageWriterList.Add(BuildNotificationPanelMessageWriter(frmMain, errorAndInfoWindow));
messageWriterList.Add(BuildPopupMessageWriter());
}
@@ -42,16 +45,17 @@ namespace mRemoteNG.App.Initialization
);
}
private static IMessageWriter BuildNotificationPanelMessageWriter()
private static IMessageWriter BuildNotificationPanelMessageWriter(FrmMain frmMain, ErrorAndInfoWindow errorAndInfoWindow)
{
return new OnlyLogMessageFilter(
errorAndInfoWindow.ThrowIfNull(nameof(errorAndInfoWindow));
return new OnlyLogMessageFilter(
new MessageTypeFilterDecorator(
new NotificationPanelMessageFilteringOptions(),
new MessageFocusDecorator(
Windows.ErrorsForm,
frmMain,
errorAndInfoWindow,
new NotificationPanelSwitchOnMessageFilteringOptions(),
new NotificationPanelMessageWriter(Windows.ErrorsForm)
new NotificationPanelMessageWriter(errorAndInfoWindow)
)
)
);

View File

@@ -26,7 +26,8 @@ namespace mRemoteNG.App
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(FrmMain.Default);
var frmMain = new FrmMain();
Application.Run(frmMain);
}
public static void CloseSingletonInstanceMutex()

View File

@@ -1,24 +1,11 @@
using mRemoteNG.App.Info;
using mRemoteNG.Config.Putty;
using mRemoteNG.Connection;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Messages;
using mRemoteNG.Security;
using mRemoteNG.Tools;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.TaskDialog;
using System;
using System.IO;
using System.Security;
using System.Threading;
using System.Windows.Forms;
namespace mRemoteNG.App
{
public static class Runtime
public class Runtime
{
public static bool IsPortableEdition
{
@@ -32,158 +19,7 @@ namespace mRemoteNG.App
}
}
public static WindowList WindowList { get; set; }
public static MessageCollector MessageCollector { get; } = new MessageCollector();
public static NotificationAreaIcon NotificationAreaIcon { get; set; }
public static ExternalToolsService ExternalToolsService { get; } = new ExternalToolsService();
public static SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
public static ICredentialRepositoryList CredentialProviderCatalog { get; } = new CredentialRepositoryList();
public static ConnectionsService ConnectionsService { get; } = new ConnectionsService(PuttySessionsManager.Instance);
#region Connections Loading/Saving
public static void LoadConnectionsAsync()
{
var t = new Thread(LoadConnectionsBGd);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private static void LoadConnectionsBGd()
{
LoadConnections();
}
/// <summary>
///
/// </summary>
/// <param name="withDialog">
/// Should we show the file selection dialog to allow the user to select
/// a connection file
/// </param>
public static void LoadConnections(bool withDialog = false)
{
var connectionFileName = "";
try
{
// disable sql update checking while we are loading updates
ConnectionsService.RemoteConnectionsSyncronizer?.Disable();
if (withDialog)
{
var loadDialog = DialogFactory.BuildLoadConnectionsDialog();
if (loadDialog.ShowDialog() != DialogResult.OK)
return;
connectionFileName = loadDialog.FileName;
Settings.Default.UseSQLServer = false;
Settings.Default.Save();
}
else if (!Settings.Default.UseSQLServer)
{
connectionFileName = ConnectionsService.GetStartupConnectionFileName();
}
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
if (Settings.Default.UseSQLServer)
{
ConnectionsService.LastSqlUpdate = DateTime.Now;
}
// re-enable sql update checking after updates are loaded
ConnectionsService.RemoteConnectionsSyncronizer?.Enable();
}
catch (Exception ex)
{
if (Settings.Default.UseSQLServer)
{
MessageCollector.AddExceptionMessage(Language.strLoadFromSqlFailed, ex);
var commandButtons = string.Join("|", Language.strCommandTryAgain, Language.strCommandOpenConnectionFile, string.Format(Language.strCommandExitProgram, Application.ProductName));
CTaskDialog.ShowCommandBox(Application.ProductName, Language.strLoadFromSqlFailed, Language.strLoadFromSqlFailedContent, MiscTools.GetExceptionMessageRecursive(ex), "", "", commandButtons, false, ESysIcons.Error, ESysIcons.Error);
switch (CTaskDialog.CommandButtonResult)
{
case 0:
LoadConnections(withDialog);
return;
case 1:
Settings.Default.UseSQLServer = false;
LoadConnections(true);
return;
default:
Application.Exit();
return;
}
}
if (ex is FileNotFoundException && !withDialog)
{
MessageCollector.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName), ex, MessageClass.InformationMsg);
string[] commandButtons =
{
Language.ConfigurationCreateNew,
Language.ConfigurationCustomPath,
Language.ConfigurationImportFile,
Language.strMenuExit
};
var answered = false;
while (!answered)
{
try
{
CTaskDialog.ShowTaskDialogBox(
GeneralAppInfo.ProductName,
Language.ConnectionFileNotFound,
"", "", "", "", "",
string.Join(" | ", commandButtons),
ETaskDialogButtons.None,
ESysIcons.Question,
ESysIcons.Question);
switch (CTaskDialog.CommandButtonResult)
{
case 0:
ConnectionsService.NewConnectionsFile(connectionFileName);
answered = true;
break;
case 1:
LoadConnections(true);
answered = true;
break;
case 2:
ConnectionsService.NewConnectionsFile(connectionFileName);
Import.ImportFromFile(ConnectionsService.ConnectionTreeModel.RootNodes[0]);
answered = true;
break;
case 3:
Application.Exit();
answered = true;
break;
}
}
catch (Exception exc)
{
MessageCollector.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName), exc, MessageClass.InformationMsg);
}
}
return;
}
MessageCollector.AddExceptionStackTrace(string.Format(Language.strConnectionsFileCouldNotBeLoaded, connectionFileName), ex);
if (connectionFileName != ConnectionsService.GetStartupConnectionFileName())
{
LoadConnections(withDialog);
}
else
{
MessageBox.Show(FrmMain.Default,
string.Format(Language.strErrorStartupConnectionFileLoad, Environment.NewLine, Application.ProductName, ConnectionsService.GetStartupConnectionFileName(), MiscTools.GetExceptionMessageRecursive(ex)),
@"Could not load startup file.", MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.Exit();
}
}
}
#endregion
}
}

View File

@@ -1,31 +1,38 @@
using System.Windows.Forms;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.App
{
public static class Screens
public class Screens
{
public static void SendFormToScreen(Screen screen)
private readonly FrmMain _frmMain;
public Screens(FrmMain frmMain)
{
_frmMain = frmMain.ThrowIfNull(nameof(frmMain));
}
public void SendFormToScreen(Screen screen)
{
var frmMain = FrmMain.Default;
var wasMax = false;
if (frmMain.WindowState == FormWindowState.Maximized)
if (_frmMain.WindowState == FormWindowState.Maximized)
{
wasMax = true;
frmMain.WindowState = FormWindowState.Normal;
_frmMain.WindowState = FormWindowState.Normal;
}
frmMain.Location = screen.Bounds.Location;
_frmMain.Location = screen.Bounds.Location;
if (wasMax)
{
frmMain.WindowState = FormWindowState.Maximized;
_frmMain.WindowState = FormWindowState.Maximized;
}
}
public static void SendPanelToScreen(DockContent panel, Screen screen)
public void SendPanelToScreen(DockContent panel, Screen screen)
{
panel.DockState = DockState.Float;
if (panel.ParentForm == null) return;

View File

@@ -3,29 +3,41 @@ using System;
using System.Diagnostics;
using System.Windows.Forms;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Settings;
using mRemoteNG.Connection;
using mRemoteNG.UI.Controls;
using mRemoteNG.UI.Forms;
// ReSharper disable ArrangeAccessorOwnerBody
namespace mRemoteNG.App
{
public static class Shutdown
public class Shutdown
{
private readonly SettingsSaver _settingsSaver;
private readonly IConnectionsService _connectionsService;
private readonly FrmMain _frmMain;
private static string _updateFilePath;
public Shutdown(SettingsSaver settingsSaver, IConnectionsService connectionsService, FrmMain frmMain)
{
_settingsSaver = settingsSaver.ThrowIfNull(nameof(settingsSaver));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
_frmMain = frmMain.ThrowIfNull(nameof(frmMain));
}
private static bool UpdatePending
{
get { return !string.IsNullOrEmpty(_updateFilePath); }
}
public static void Quit(string updateFilePath = null)
public void Quit(string updateFilePath = null)
{
_updateFilePath = updateFilePath;
FrmMain.Default.Close();
_frmMain.Close();
ProgramRoot.CloseSingletonInstanceMutex();
}
public static void Cleanup(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, MultiSshToolStrip multiSshToolStrip, FrmMain frmMain)
public void Cleanup(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, MultiSshToolStrip multiSshToolStrip, FrmMain frmMain)
{
try
{
@@ -41,34 +53,34 @@ namespace mRemoteNG.App
}
}
private static void StopPuttySessionWatcher()
private void StopPuttySessionWatcher()
{
PuttySessionsManager.Instance.StopWatcher();
}
private static void DisposeNotificationAreaIcon()
private void DisposeNotificationAreaIcon()
{
if (Runtime.NotificationAreaIcon != null && Runtime.NotificationAreaIcon.Disposed == false)
Runtime.NotificationAreaIcon.Dispose();
}
private static void SaveConnections()
private void SaveConnections()
{
if (Settings.Default.SaveConsOnExit)
Runtime.ConnectionsService.SaveConnections();
_connectionsService.SaveConnections();
}
private static void SaveSettings(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, MultiSshToolStrip multiSshToolStrip, FrmMain frmMain)
private void SaveSettings(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, MultiSshToolStrip multiSshToolStrip, FrmMain frmMain)
{
Config.Settings.SettingsSaver.SaveSettings(quickConnectToolStrip, externalToolsToolStrip, multiSshToolStrip, frmMain);
_settingsSaver.SaveSettings(quickConnectToolStrip, externalToolsToolStrip, multiSshToolStrip, frmMain);
}
private static void UnregisterBrowsers()
private void UnregisterBrowsers()
{
IeBrowserEmulation.Unregister();
}
public static void StartUpdate()
public void StartUpdate()
{
try
{
@@ -80,7 +92,7 @@ namespace mRemoteNG.App
}
}
private static void RunUpdateFile()
private void RunUpdateFile()
{
if (UpdatePending)
Process.Start(_updateFilePath);

View File

@@ -7,6 +7,7 @@ using mRemoteNG.App.Initialization;
using mRemoteNG.App.Update;
using mRemoteNG.Config.Connections;
using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Connection;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
@@ -17,30 +18,34 @@ using mRemoteNG.UI.Forms;
namespace mRemoteNG.App
{
public class Startup
public class Startup
{
private AppUpdater _appUpdate;
private readonly AppUpdater _appUpdate;
private readonly ConnectionIconLoader _connectionIconLoader;
private readonly FrmMain _frmMain = FrmMain.Default;
private readonly FrmMain _frmMain;
private readonly Windows _windows;
private readonly IConnectionsService _connectionsService;
private readonly DatabaseConnectorFactory _databaseConnectorFactory;
private readonly CompatibilityChecker _compatibilityChecker;
public static Startup Instance { get; } = new Startup();
private Startup()
public Startup(FrmMain frmMain, Windows windows, IConnectionsService connectionsService,
AppUpdater appUpdate, DatabaseConnectorFactory databaseConnectorFactory, CompatibilityChecker compatibilityChecker)
{
_appUpdate = new AppUpdater();
_frmMain = frmMain.ThrowIfNull(nameof(frmMain));
_windows = windows.ThrowIfNull(nameof(windows));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
_appUpdate = appUpdate.ThrowIfNull(nameof(appUpdate));
_databaseConnectorFactory = databaseConnectorFactory.ThrowIfNull(nameof(databaseConnectorFactory));
_compatibilityChecker = compatibilityChecker.ThrowIfNull(nameof(compatibilityChecker));
_connectionIconLoader = new ConnectionIconLoader(GeneralAppInfo.HomePath + "\\Icons\\");
}
static Startup()
{
}
public void InitializeProgram(MessageCollector messageCollector)
{
Debug.Print("---------------------------" + Environment.NewLine + "[START] - " + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture));
var startupLogger = new StartupDataLogger(messageCollector);
startupLogger.LogStartupData();
CompatibilityChecker.CheckCompatibility(messageCollector);
_compatibilityChecker.CheckCompatibility();
ParseCommandLineArgs(messageCollector);
IeBrowserEmulation.Register();
_connectionIconLoader.GetConnectionIcons();
@@ -59,17 +64,14 @@ namespace mRemoteNG.App
messageCollector.AddMessage(MessageClass.DebugMsg, "Determining if we need a database syncronizer");
if (!Settings.Default.UseSQLServer) return;
messageCollector.AddMessage(MessageClass.DebugMsg, "Creating database syncronizer");
Runtime.ConnectionsService.RemoteConnectionsSyncronizer = new RemoteConnectionsSyncronizer(new SqlConnectionsUpdateChecker());
Runtime.ConnectionsService.RemoteConnectionsSyncronizer.Enable();
var sqlConnectionsUpdateChecker = new SqlConnectionsUpdateChecker(_connectionsService, _databaseConnectorFactory);
_connectionsService.RemoteConnectionsSyncronizer = new RemoteConnectionsSyncronizer(sqlConnectionsUpdateChecker, _connectionsService);
_connectionsService.RemoteConnectionsSyncronizer.Enable();
}
public void CheckForUpdate()
{
if (_appUpdate == null)
{
_appUpdate = new AppUpdater();
}
else if (_appUpdate.IsGetUpdateInfoRunning)
if (_appUpdate.IsGetUpdateInfoRunning)
{
return;
}
@@ -107,7 +109,7 @@ namespace mRemoteNG.App
if (_appUpdate.IsUpdateAvailable())
{
Windows.Show(WindowType.Update);
_windows.Show(WindowType.Update);
}
}
catch (Exception ex)

View File

@@ -4,6 +4,7 @@ using System.Net;
using System.ComponentModel;
using System.Threading;
using System.Reflection;
using System.Security;
using mRemoteNG.App.Info;
using mRemoteNG.Security.SymmetricEncryption;
using System.Security.Cryptography;
@@ -22,6 +23,7 @@ namespace mRemoteNG.App.Update
private WebProxy _webProxy;
private Thread _getUpdateInfoThread;
private Thread _getChangeLogThread;
private readonly Func<SecureString> _encryptionKeyRetrievalFunc;
#region Public Properties
@@ -48,8 +50,9 @@ namespace mRemoteNG.App.Update
#region Public Methods
public AppUpdater()
public AppUpdater(Func<SecureString> encryptionKeyRetrievalFunc)
{
_encryptionKeyRetrievalFunc = encryptionKeyRetrievalFunc;
SetProxySettings();
}
@@ -61,7 +64,7 @@ namespace mRemoteNG.App.Update
var useAuthentication = Settings.Default.UpdateProxyUseAuthentication;
var username = Settings.Default.UpdateProxyAuthUser;
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
var password = cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, Runtime.EncryptionKey);
var password = cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, _encryptionKeyRetrievalFunc());
SetProxySettings(shouldWeUseProxy, proxyAddress, port, useAuthentication, username, password);
}

View File

@@ -1,94 +1,134 @@
using System;
using mRemoteNG.App.Update;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Connection;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.UI;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Window;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.App
{
public static class Windows
public class Windows
{
private static AboutWindow _aboutForm;
private static ActiveDirectoryImportWindow _adimportForm;
private static HelpWindow _helpForm;
private static ExternalToolsWindow _externalappsForm;
private static PortScanWindow _portscanForm;
private static UltraVNCWindow _ultravncscForm;
private static ComponentsCheckWindow _componentscheckForm;
private static ConnectionTreeWindow _treeForm;
private readonly IConnectionInitiator _connectionInitiator;
private AboutWindow _aboutForm;
private ActiveDirectoryImportWindow _adimportForm;
private HelpWindow _helpForm;
private ExternalToolsWindow _externalappsForm;
private PortScanWindow _portscanForm;
private UltraVNCWindow _ultravncscForm;
private ComponentsCheckWindow _componentscheckForm;
private UpdateWindow _updateForm;
private readonly Func<UpdateWindow> _updateWindowBuilder;
private readonly Func<NotificationAreaIcon> _notificationAreaIconBuilder;
private readonly Func<ExternalToolsWindow> _externalToolsWindowBuilder;
private readonly Func<PortScanWindow> _portScanWindowBuilder;
private readonly Func<ActiveDirectoryImportWindow> _activeDirectoryImportWindowBuilder;
private readonly IConnectionsService _connectionsService;
private readonly AppUpdater _appUpdater;
private readonly DatabaseConnectorFactory _databaseConnectorFactory;
private readonly FrmMain _frmMain;
internal static ConnectionTreeWindow TreeForm
internal ConnectionTreeWindow TreeForm { get; }
internal ConfigWindow ConfigForm { get; }
internal ErrorAndInfoWindow ErrorsForm { get; }
internal ScreenshotManagerWindow ScreenshotForm { get; }
internal SSHTransferWindow SshtransferForm { get; private set; }
public Windows(
IConnectionInitiator connectionInitiator,
ConnectionTreeWindow treeForm,
ConfigWindow configForm,
ErrorAndInfoWindow errorAndInfoWindow,
ScreenshotManagerWindow screenshotForm,
SSHTransferWindow sshtransferForm,
Func<UpdateWindow> updateWindowBuilder,
Func<NotificationAreaIcon> notificationAreaIconBuilder,
Func<ExternalToolsWindow> externalToolsWindowBuilder,
IConnectionsService connectionsService,
Func<PortScanWindow> portScanWindowBuilder,
Func<ActiveDirectoryImportWindow> activeDirectoryImportWindowBuilder,
AppUpdater appUpdater,
DatabaseConnectorFactory databaseConnectorFactory,
FrmMain frmMain)
{
get => _treeForm ?? (_treeForm = new ConnectionTreeWindow());
set => _treeForm = value;
_connectionInitiator = connectionInitiator.ThrowIfNull(nameof(connectionInitiator));
TreeForm = treeForm.ThrowIfNull(nameof(treeForm));
ConfigForm = configForm.ThrowIfNull(nameof(configForm));
ErrorsForm = errorAndInfoWindow.ThrowIfNull(nameof(errorAndInfoWindow));
ScreenshotForm = screenshotForm.ThrowIfNull(nameof(screenshotForm));
SshtransferForm = sshtransferForm.ThrowIfNull(nameof(sshtransferForm));
_updateWindowBuilder = updateWindowBuilder;
_notificationAreaIconBuilder = notificationAreaIconBuilder;
_externalToolsWindowBuilder = externalToolsWindowBuilder;
_portScanWindowBuilder = portScanWindowBuilder;
_activeDirectoryImportWindowBuilder = activeDirectoryImportWindowBuilder;
_frmMain = frmMain;
_databaseConnectorFactory = databaseConnectorFactory.ThrowIfNull(nameof(databaseConnectorFactory));
_appUpdater = appUpdater.ThrowIfNull(nameof(appUpdater));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
internal static ConfigWindow ConfigForm { get; set; } = new ConfigWindow();
internal static ErrorAndInfoWindow ErrorsForm { get; set; } = new ErrorAndInfoWindow();
internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow();
private static UpdateWindow UpdateForm { get; set; } = new UpdateWindow();
internal static SSHTransferWindow SshtransferForm { get; private set; } = new SSHTransferWindow();
public static void Show(WindowType windowType)
public void Show(WindowType windowType)
{
try
{
var dockPanel = FrmMain.Default.pnlDock;
// ReSharper disable once SwitchStatementMissingSomeCases
switch (windowType)
{
case WindowType.About:
if (_aboutForm == null || _aboutForm.IsDisposed)
_aboutForm = new AboutWindow();
_aboutForm.Show(dockPanel);
_aboutForm.Show(_frmMain.pnlDock);
break;
case WindowType.ActiveDirectoryImport:
if (_adimportForm == null || _adimportForm.IsDisposed)
_adimportForm = new ActiveDirectoryImportWindow();
_adimportForm.Show(dockPanel);
_adimportForm = _activeDirectoryImportWindowBuilder();
_adimportForm.Show(_frmMain.pnlDock);
break;
case WindowType.Options:
using (var optionsForm = new frmOptions())
using (var optionsForm = new frmOptions(_connectionInitiator, Show, _notificationAreaIconBuilder, _connectionsService, _appUpdater, _databaseConnectorFactory, _frmMain))
{
optionsForm.ShowDialog(dockPanel);
optionsForm.ShowDialog(_frmMain);
}
break;
case WindowType.SSHTransfer:
if (SshtransferForm == null || SshtransferForm.IsDisposed)
SshtransferForm = new SSHTransferWindow();
SshtransferForm.Show(dockPanel);
SshtransferForm = new SSHTransferWindow(_frmMain);
SshtransferForm.Show(_frmMain.pnlDock);
break;
case WindowType.Update:
if (UpdateForm == null || UpdateForm.IsDisposed)
UpdateForm = new UpdateWindow();
UpdateForm.Show(dockPanel);
if (_updateForm == null || _updateForm.IsDisposed)
_updateForm = _updateWindowBuilder();
_updateForm.Show(_frmMain.pnlDock);
break;
case WindowType.Help:
if (_helpForm == null || _helpForm.IsDisposed)
_helpForm = new HelpWindow();
_helpForm.Show(dockPanel);
_helpForm.Show(_frmMain.pnlDock);
break;
case WindowType.ExternalApps:
if (_externalappsForm == null || _externalappsForm.IsDisposed)
_externalappsForm = new ExternalToolsWindow();
_externalappsForm.Show(dockPanel);
_externalappsForm = _externalToolsWindowBuilder();
_externalappsForm.Show(_frmMain.pnlDock);
break;
case WindowType.PortScan:
_portscanForm = new PortScanWindow();
_portscanForm.Show(dockPanel);
_portscanForm = _portScanWindowBuilder();
_portscanForm.Show(_frmMain.pnlDock);
break;
case WindowType.UltraVNCSC:
if (_ultravncscForm == null || _ultravncscForm.IsDisposed)
_ultravncscForm = new UltraVNCWindow();
_ultravncscForm.Show(dockPanel);
_ultravncscForm = new UltraVNCWindow(Show);
_ultravncscForm.Show(_frmMain.pnlDock);
break;
case WindowType.ComponentsCheck:
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Showing ComponentsCheck window", true);
if (_componentscheckForm == null || _componentscheckForm.IsDisposed)
_componentscheckForm = new ComponentsCheckWindow();
_componentscheckForm.Show(dockPanel);
_componentscheckForm.Show(_frmMain.pnlDock);
break;
}
}
@@ -98,4 +138,4 @@ namespace mRemoteNG.App
}
}
}
}
}

View File

@@ -1,9 +1,8 @@
using System;
using mRemoteNG.App;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.Csv;
using mRemoteNG.Credential;
using mRemoteNG.Security;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
namespace mRemoteNG.Config.Connections
@@ -12,21 +11,18 @@ namespace mRemoteNG.Config.Connections
{
private readonly string _connectionFileName;
private readonly SaveFilter _saveFilter;
private readonly ICredentialRepositoryList _credentialRepositoryList;
public CsvConnectionsSaver(string connectionFileName, SaveFilter saveFilter)
public CsvConnectionsSaver(string connectionFileName, SaveFilter saveFilter, ICredentialRepositoryList credentialRepositoryList)
{
if (string.IsNullOrEmpty(connectionFileName))
throw new ArgumentException($"Argument '{nameof(connectionFileName)}' cannot be null or empty");
if (saveFilter == null)
throw new ArgumentNullException(nameof(saveFilter));
_connectionFileName = connectionFileName;
_saveFilter = saveFilter;
_connectionFileName = connectionFileName.ThrowIfNullOrEmpty(nameof(connectionFileName));
_saveFilter = saveFilter.ThrowIfNull(nameof(saveFilter));
_credentialRepositoryList = credentialRepositoryList.ThrowIfNull(nameof(credentialRepositoryList));
}
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
public void Save(ConnectionTreeModel connectionTreeModel)
{
var csvConnectionsSerializer = new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialProviderCatalog);
var csvConnectionsSerializer = new CsvConnectionsSerializerMremotengFormat(_saveFilter, _credentialRepositoryList);
var dataProvider = new FileDataProvider(_connectionFileName);
var csvContent = csvConnectionsSerializer.Serialize(connectionTreeModel);
dataProvider.Save(csvContent);

View File

@@ -1,9 +0,0 @@
using mRemoteNG.Tree;
namespace mRemoteNG.Config.Connections
{
public interface IConnectionsLoader
{
ConnectionTreeModel Load();
}
}

View File

@@ -1,6 +1,7 @@
using mRemoteNG.App;
using System;
using System;
using System.Timers;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
// ReSharper disable ArrangeAccessorOwnerBody
@@ -10,15 +11,17 @@ namespace mRemoteNG.Config.Connections.Multiuser
{
private readonly Timer _updateTimer;
private readonly IConnectionsUpdateChecker _updateChecker;
private readonly IConnectionsService _connectionsService;
public double TimerIntervalInMilliseconds
{
get { return _updateTimer.Interval; }
}
public RemoteConnectionsSyncronizer(IConnectionsUpdateChecker updateChecker)
public RemoteConnectionsSyncronizer(IConnectionsUpdateChecker updateChecker, IConnectionsService connectionsService)
{
_updateChecker = updateChecker;
_updateChecker = updateChecker.ThrowIfNull(nameof(updateChecker));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
_updateTimer = new Timer(3000);
SetEventListeners();
}
@@ -34,7 +37,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
private void Load(object sender, ConnectionsUpdateAvailableEventArgs args)
{
Runtime.ConnectionsService.LoadConnections(true, false, "");
_connectionsService.LoadConnections(true, false, "");
args.Handled = true;
}

View File

@@ -1,11 +1,13 @@
using mRemoteNG.App;
using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Messages;
using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
namespace mRemoteNG.Config.Connections
{
@@ -13,14 +15,17 @@ namespace mRemoteNG.Config.Connections
{
private readonly SqlDatabaseConnector _sqlConnector;
private readonly SqlCommand _sqlQuery;
private DateTime LastUpdateTime => Runtime.ConnectionsService.LastSqlUpdate;
private readonly IConnectionsService _connectionsService;
private DateTime _lastUpdateTime;
private DateTime _lastDatabaseUpdateTime;
public SqlConnectionsUpdateChecker()
public SqlConnectionsUpdateChecker(IConnectionsService connectionsService, DatabaseConnectorFactory databaseConnectorFactory)
{
_sqlConnector = DatabaseConnectorFactory.SqlDatabaseConnectorFromSettings();
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
databaseConnectorFactory.ThrowIfNull(nameof(databaseConnectorFactory));
_sqlConnector = databaseConnectorFactory.SqlDatabaseConnectorFromSettings();
_sqlQuery = new SqlCommand("SELECT * FROM tblUpdate", _sqlConnector.SqlConnection);
_lastUpdateTime = default(DateTime);
_lastDatabaseUpdateTime = default(DateTime);
}
@@ -57,14 +62,14 @@ namespace mRemoteNG.Config.Connections
private bool DatabaseIsMoreUpToDateThanUs()
{
var lastUpdateInDb = GetLastUpdateTimeFromDbResponse();
var amTheLastoneUpdated = CheckIfIAmTheLastOneUpdated(lastUpdateInDb);
return (lastUpdateInDb > LastUpdateTime && !amTheLastoneUpdated);
var IAmTheLastoneUpdated = CheckIfIAmTheLastOneUpdated(lastUpdateInDb);
return (lastUpdateInDb > _lastUpdateTime && !IAmTheLastoneUpdated);
}
private bool CheckIfIAmTheLastOneUpdated(DateTime lastUpdateInDb)
{
DateTime lastSqlUpdateWithoutMilliseconds = new DateTime(LastUpdateTime.Ticks - (LastUpdateTime.Ticks % TimeSpan.TicksPerSecond), LastUpdateTime.Kind);
return lastUpdateInDb == lastSqlUpdateWithoutMilliseconds;
DateTime LastSqlUpdateWithoutMilliseconds = new DateTime(_connectionsService.LastSqlUpdate.Ticks - (_connectionsService.LastSqlUpdate.Ticks % TimeSpan.TicksPerSecond), _connectionsService.LastSqlUpdate.Kind);
return lastUpdateInDb == LastSqlUpdateWithoutMilliseconds;
}
private DateTime GetLastUpdateTimeFromDbResponse()
@@ -103,9 +108,10 @@ namespace mRemoteNG.Config.Connections
public event ConnectionsUpdateAvailableEventHandler ConnectionsUpdateAvailable;
private void RaiseConnectionsUpdateAvailableEvent()
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Remote connection update is available");
var args = new ConnectionsUpdateAvailableEventArgs(_sqlConnector, _lastDatabaseUpdateTime);
ConnectionsUpdateAvailable?.Invoke(this, args);
if(args.Handled)
_lastUpdateTime = _lastDatabaseUpdateTime;
}
public void Dispose()

View File

@@ -1,16 +1,17 @@
using System;
using mRemoteNG.Connection;
using System;
using System.Collections.Specialized;
using System.ComponentModel;
using mRemoteNG.Connection;
using mRemoteNG.UI.Forms;
namespace mRemoteNG.Config.Connections
{
public class SaveConnectionsOnEdit
{
private readonly ConnectionsService _connectionsService;
private readonly IConnectionsService _connectionsService;
public SaveConnectionsOnEdit(ConnectionsService connectionsService)
public bool Enabled { get; set; } = true;
public SaveConnectionsOnEdit(IConnectionsService connectionsService)
{
if (connectionsService == null)
throw new ArgumentNullException(nameof(connectionsService));
@@ -33,7 +34,7 @@ namespace mRemoteNG.Config.Connections
private void ConnectionTreeModelOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
SaveConnectionOnEdit(propertyChangedEventArgs.PropertyName);
SaveConnectionOnEdit();
}
private void ConnectionTreeModelOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
@@ -41,14 +42,15 @@ namespace mRemoteNG.Config.Connections
SaveConnectionOnEdit();
}
private void SaveConnectionOnEdit(string propertyName = "")
private void SaveConnectionOnEdit()
{
if (!mRemoteNG.Settings.Default.SaveConnectionsAfterEveryEdit)
return;
if (FrmMain.Default.IsClosing)
if (!Enabled)
return;
_connectionsService.SaveConnectionsAsync(propertyName);
_connectionsService.SaveConnectionsAsync();
}
}
}

View File

@@ -1,89 +1,33 @@
using System;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.MsSql;
using mRemoteNG.Config.Serializers.Versioning;
using mRemoteNG.Container;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using mRemoteNG.Security;
using mRemoteNG.Security.Authentication;
using mRemoteNG.Security.SymmetricEncryption;
namespace mRemoteNG.Config.Connections
{
public class SqlConnectionsLoader : IConnectionsLoader
public class SqlConnectionsLoader
{
private readonly IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> _localConnectionPropertiesDeserializer;
private readonly IDataProvider<string> _dataProvider;
private readonly DatabaseConnectorFactory _databaseConnectorFactory;
private readonly IConnectionsService _connectionsService;
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; } =
() => MiscTools.PasswordDialog("", false);
public SqlConnectionsLoader(
IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> localConnectionPropertiesDeserializer,
IDataProvider<string> dataProvider)
public SqlConnectionsLoader(DatabaseConnectorFactory databaseConnectorFactory, IConnectionsService connectionsService)
{
_localConnectionPropertiesDeserializer = localConnectionPropertiesDeserializer.ThrowIfNull(nameof(localConnectionPropertiesDeserializer));
_dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
_databaseConnectorFactory = databaseConnectorFactory.ThrowIfNull(nameof(databaseConnectorFactory));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
public ConnectionTreeModel Load()
{
var connector = DatabaseConnectorFactory.SqlDatabaseConnectorFromSettings();
var connector = _databaseConnectorFactory.SqlDatabaseConnectorFromSettings();
var dataProvider = new SqlDataProvider(connector);
var metaDataRetriever = new SqlDatabaseMetaDataRetriever();
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(connector);
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
var metaData = metaDataRetriever.GetDatabaseMetaData(connector);
var decryptionKey = GetDecryptionKey(metaData);
if (!decryptionKey.Any())
throw new Exception("Could not load SQL connections");
databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion);
databaseVersionVerifier.VerifyDatabaseVersion();
var dataTable = dataProvider.Load();
var deserializer = new DataTableDeserializer(cryptoProvider, decryptionKey.First());
var connectionTree = deserializer.Deserialize(dataTable);
ApplyLocalConnectionProperties(connectionTree.RootNodes.First(i => i is RootNodeInfo));
return connectionTree;
}
private Optional<SecureString> GetDecryptionKey(SqlConnectionListMetaData metaData)
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
var cipherText = metaData.Protected;
var authenticator = new PasswordAuthenticator(cryptographyProvider, cipherText, AuthenticationRequestor);
var authenticated = authenticator.Authenticate(new RootNodeInfo(RootNodeType.Connection).DefaultPassword.ConvertToSecureString());
if (authenticated)
return authenticator.LastAuthenticatedPassword;
return Optional<SecureString>.Empty;
}
private void ApplyLocalConnectionProperties(ContainerInfo rootNode)
{
var localPropertiesXml = _dataProvider.Load();
var localConnectionProperties = _localConnectionPropertiesDeserializer.Deserialize(localPropertiesXml);
rootNode
.GetRecursiveChildList()
.Join(localConnectionProperties,
con => con.ConstantID,
locals => locals.ConnectionId,
(con, locals) => new {Connection = con, LocalProperties = locals})
.ForEach(x =>
{
x.Connection.PleaseConnect = x.LocalProperties.Connected;
if (x.Connection is ContainerInfo container)
container.IsExpanded = x.LocalProperties.Expanded;
});
var deserializer = new DataTableDeserializer(_connectionsService);
return deserializer.Deserialize(dataTable);
}
}
}

View File

@@ -1,10 +1,14 @@
using mRemoteNG.App;
using System;
using System.Data.SqlClient;
using System.Globalization;
using System.Linq;
using mRemoteNG.App;
using mRemoteNG.App.Info;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.MsSql;
using mRemoteNG.Config.Serializers.Versioning;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Messages;
using mRemoteNG.Security;
@@ -12,101 +16,48 @@ using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Globalization;
using System.Linq;
using System.Security;
using mRemoteNG.Connection;
namespace mRemoteNG.Config.Connections
{
public class SqlConnectionsSaver : ISaver<ConnectionTreeModel>
{
private SecureString _password = Runtime.EncryptionKey;
private readonly IConnectionsService _connectionsService;
private readonly SaveFilter _saveFilter;
private readonly ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> _localPropertiesSerializer;
private readonly IDataProvider<string> _dataProvider;
private readonly DatabaseConnectorFactory _databaseConnectorFactory;
public SqlConnectionsSaver(
SaveFilter saveFilter,
ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> localPropertieSerializer,
IDataProvider<string> localPropertiesDataProvider)
public SqlConnectionsSaver(SaveFilter saveFilter, IConnectionsService connectionsService, DatabaseConnectorFactory databaseConnectorFactory)
{
if (saveFilter == null)
throw new ArgumentNullException(nameof(saveFilter));
_saveFilter = saveFilter;
_localPropertiesSerializer = localPropertieSerializer.ThrowIfNull(nameof(localPropertieSerializer));
_dataProvider = localPropertiesDataProvider.ThrowIfNull(nameof(localPropertiesDataProvider));
_saveFilter = saveFilter.ThrowIfNull(nameof(saveFilter));
_databaseConnectorFactory = databaseConnectorFactory.ThrowIfNull(nameof(databaseConnectorFactory));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
public void Save(ConnectionTreeModel connectionTreeModel)
{
var rootTreeNode = connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
UpdateLocalConnectionProperties(rootTreeNode);
if (PropertyIsLocalOnly(propertyNameTrigger))
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
$"Property {propertyNameTrigger} is local only. Not saving to database.");
return;
}
if (SqlUserIsReadOnly())
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Trying to save connection tree but the SQL read only checkbox is checked, aborting!");
return;
}
using (var sqlConnector = DatabaseConnectorFactory.SqlDatabaseConnectorFromSettings())
using (var sqlConnector = _databaseConnectorFactory.SqlDatabaseConnectorFromSettings())
{
sqlConnector.Connect();
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(sqlConnector);
var metaDataRetriever = new SqlDatabaseMetaDataRetriever();
var metaData = metaDataRetriever.GetDatabaseMetaData(sqlConnector);
if (!databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion))
if (!databaseVersionVerifier.VerifyDatabaseVersion())
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strErrorConnectionListSaveFailed);
return;
}
var rootTreeNode = connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
UpdateRootNodeTable(rootTreeNode, sqlConnector);
UpdateConnectionsTable(rootTreeNode, sqlConnector);
UpdateUpdatesTable(sqlConnector);
}
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Saved connections to database");
}
/// <summary>
/// Determines if a given property name should be only saved
/// locally.
/// </summary>
/// <param name="property">
/// The name of the property that triggered the save event
/// </param>
/// <returns></returns>
private bool PropertyIsLocalOnly(string property)
{
return property == nameof(ConnectionInfo.OpenConnections) ||
property == nameof(ContainerInfo.IsExpanded);
}
private void UpdateLocalConnectionProperties(ContainerInfo rootNode)
{
var a = rootNode.GetRecursiveChildList().Select(info => new LocalConnectionPropertiesModel
{
ConnectionId = info.ConstantID,
Connected = info.OpenConnections.Count > 0,
Expanded = info is ContainerInfo c && c.IsExpanded
});
var serializedProperties = _localPropertiesSerializer.Serialize(a);
_dataProvider.Save(serializedProperties);
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Saved local connection properties");
}
private void UpdateRootNodeTable(RootNodeInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
@@ -117,17 +68,17 @@ namespace mRemoteNG.Config.Connections
{
if (rootTreeNode.Password)
{
_password = rootTreeNode.PasswordString.ConvertToSecureString();
strProtected = cryptographyProvider.Encrypt("ThisIsProtected", _password);
_connectionsService.EncryptionKey = rootTreeNode.PasswordString.ConvertToSecureString();
strProtected = cryptographyProvider.Encrypt("ThisIsProtected", _connectionsService.EncryptionKey);
}
else
{
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", _password);
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", _connectionsService.EncryptionKey);
}
}
else
{
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", _password);
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", _connectionsService.EncryptionKey);
}
var sqlQuery = new SqlCommand("DELETE FROM tblRoot", sqlDatabaseConnector.SqlConnection);
@@ -149,15 +100,13 @@ namespace mRemoteNG.Config.Connections
}
}
private void UpdateConnectionsTable(RootNodeInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
private void UpdateConnectionsTable(ContainerInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
{
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
var serializer = new DataTableSerializer(_saveFilter, cryptoProvider, rootTreeNode.PasswordString.ConvertToSecureString());
var dataTable = serializer.Serialize(rootTreeNode);
var dataProvider = new SqlDataProvider(sqlDatabaseConnector);
var sqlQuery = new SqlCommand("DELETE FROM tblCons", sqlDatabaseConnector.SqlConnection);
sqlQuery.ExecuteNonQuery();
var serializer = new DataTableSerializer(_saveFilter);
var dataTable = serializer.Serialize(rootTreeNode);
var dataProvider = new SqlDataProvider(sqlDatabaseConnector);
dataProvider.Save(dataTable);
}

View File

@@ -1,40 +1,37 @@
using mRemoteNG.Config.DataProviders;
using System.Security;
using System.Windows.Forms;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using System;
using System.IO;
using System.Security;
namespace mRemoteNG.Config.Connections
{
public class XmlConnectionsLoader : IConnectionsLoader
{
public class XmlConnectionsLoader
{
private readonly IConnectionsService _connectionsService;
private readonly string _connectionFilePath;
private readonly IWin32Window _dialogWindowParent;
public XmlConnectionsLoader(string connectionFilePath)
public XmlConnectionsLoader(string connectionFilePath, IConnectionsService connectionsService, IWin32Window dialogWindowParent)
{
if (string.IsNullOrEmpty(connectionFilePath))
throw new ArgumentException($"{nameof(connectionFilePath)} cannot be null or empty");
if (!File.Exists(connectionFilePath))
throw new FileNotFoundException($"{connectionFilePath} does not exist");
_connectionFilePath = connectionFilePath;
_dialogWindowParent = dialogWindowParent;
_connectionFilePath = connectionFilePath.ThrowIfNullOrEmpty(nameof(connectionFilePath));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
public ConnectionTreeModel Load()
{
var dataProvider = new FileDataProvider(_connectionFilePath);
var xmlString = dataProvider.Load();
var deserializer = new XmlConnectionsDeserializer(PromptForPassword);
var deserializer = new XmlConnectionsDeserializer(_connectionsService, _dialogWindowParent, PromptForPassword);
return deserializer.Deserialize(xmlString);
}
private Optional<SecureString> PromptForPassword()
{
var password = MiscTools.PasswordDialog("", false);
return password;
return MiscTools.PasswordDialog("", false);
}
}
}

View File

@@ -27,12 +27,12 @@ namespace mRemoteNG.Config.Connections
_saveFilter = saveFilter;
}
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
public void Save(ConnectionTreeModel connectionTreeModel)
{
try
{
var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build();
var connectionNodeSerializer = new XmlConnectionNodeSerializer26(
var connectionNodeSerializer = new XmlConnectionNodeSerializer27(
cryptographyProvider,
connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
_saveFilter);

View File

@@ -18,7 +18,7 @@ namespace mRemoteNG.Config
_dataProvider = dataProvider;
}
public void Save(IEnumerable<ICredentialRepository> repositories, string propertyNameTrigger = "")
public void Save(IEnumerable<ICredentialRepository> repositories)
{
var serializer = new CredentialRepositoryListSerializer();
var data = serializer.Serialize(repositories);

View File

@@ -1,17 +1,26 @@
using mRemoteNG.App;
using System;
using System.Security;
using mRemoteNG.App;
using mRemoteNG.Security.SymmetricEncryption;
namespace mRemoteNG.Config.DatabaseConnectors
{
public class DatabaseConnectorFactory
{
public static SqlDatabaseConnector SqlDatabaseConnectorFromSettings()
private readonly Func<SecureString> _decryptionKeyRetrievalFun;
public DatabaseConnectorFactory(Func<SecureString> decryptionKeyRetrievalFun)
{
_decryptionKeyRetrievalFun = decryptionKeyRetrievalFun;
}
public SqlDatabaseConnector SqlDatabaseConnectorFromSettings()
{
var sqlHost = mRemoteNG.Settings.Default.SQLHost;
var sqlCatalog = mRemoteNG.Settings.Default.SQLDatabaseName;
var sqlUsername = mRemoteNG.Settings.Default.SQLUser;
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
var sqlPassword = cryptographyProvider.Decrypt(mRemoteNG.Settings.Default.SQLPass, Runtime.EncryptionKey);
var sqlPassword = cryptographyProvider.Decrypt(mRemoteNG.Settings.Default.SQLPass, _decryptionKeyRetrievalFun());
return new SqlDatabaseConnector(sqlHost, sqlCatalog, sqlUsername, sqlPassword);
}
}

View File

@@ -2,6 +2,6 @@
{
public interface ISaver<in T>
{
void Save(T model, string propertyNameTrigger = "");
void Save(T model);
}
}

View File

@@ -1,11 +1,13 @@
using System.IO;
using System.Linq;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
namespace mRemoteNG.Config.Import
@@ -13,6 +15,15 @@ namespace mRemoteNG.Config.Import
// ReSharper disable once InconsistentNaming
public class MRemoteNGXmlImporter : IConnectionImporter<string>
{
private readonly IConnectionsService _connectionsService;
private readonly IWin32Window _dialogWindowParent;
public MRemoteNGXmlImporter(IConnectionsService connectionsService, IWin32Window dialogWindowParent)
{
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
_dialogWindowParent = dialogWindowParent.ThrowIfNull(nameof(dialogWindowParent));
}
public void Import(string fileName, ContainerInfo destinationContainer)
{
if (fileName == null)
@@ -26,7 +37,7 @@ namespace mRemoteNG.Config.Import
var dataProvider = new FileDataProvider(fileName);
var xmlString = dataProvider.Load();
var xmlConnectionsDeserializer = new XmlConnectionsDeserializer();
var xmlConnectionsDeserializer = new XmlConnectionsDeserializer(_connectionsService, _dialogWindowParent);
var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString, true);
var rootImportContainer = new ContainerInfo { Name = Path.GetFileNameWithoutExtension(fileName) };

View File

@@ -234,6 +234,12 @@ namespace mRemoteNG.Config.Serializers.Csv
if (bool.TryParse(connectionCsv[headers.IndexOf("RedirectPrinters")], out value))
connectionRecord.RedirectPrinters = value;
}
if (headers.Contains("RedirectClipboard"))
{
bool value;
if (bool.TryParse(connectionCsv[headers.IndexOf("RedirectClipboard")], out value))
connectionRecord.RedirectClipboard = value;
}
if (headers.Contains("RedirectSmartCards"))
{
@@ -453,6 +459,13 @@ namespace mRemoteNG.Config.Serializers.Csv
connectionRecord.Inheritance.RedirectPrinters = value;
}
if (headers.Contains("InheritRedirectClipboard"))
{
bool value;
if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRedirectClipboard")], out value))
connectionRecord.Inheritance.RedirectClipboard = value;
}
if (headers.Contains("InheritRedirectSmartCards"))
{
bool value;

View File

@@ -52,9 +52,9 @@ namespace mRemoteNG.Config.Serializers.Csv
sb.Append("Password;");
if (_saveFilter.SaveDomain)
sb.Append("Domain;");
sb.Append("Hostname;Protocol;PuttySession;Port;ConnectToConsole;UseCredSsp;RenderingEngine;ICAEncryptionStrength;RDPAuthenticationLevel;LoadBalanceInfo;Colors;Resolution;AutomaticResize;DisplayWallpaper;DisplayThemes;EnableFontSmoothing;EnableDesktopComposition;CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectSmartCards;RedirectSound;RedirectKeys;PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;VNCProxyPort;VNCProxyUsername;VNCProxyPassword;VNCColors;VNCSmartSizeMode;VNCViewOnly;RDGatewayUsageMethod;RDGatewayHostname;RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;");
sb.Append("Hostname;Protocol;PuttySession;Port;ConnectToConsole;UseCredSsp;RenderingEngine;ICAEncryptionStrength;RDPAuthenticationLevel;LoadBalanceInfo;Colors;Resolution;AutomaticResize;DisplayWallpaper;DisplayThemes;EnableFontSmoothing;EnableDesktopComposition;CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectClipboard;RedirectSmartCards;RedirectSound;RedirectKeys;PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;VNCProxyPort;VNCProxyUsername;VNCProxyPassword;VNCColors;VNCSmartSizeMode;VNCViewOnly;RDGatewayUsageMethod;RDGatewayHostname;RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;");
if (_saveFilter.SaveInheritance)
sb.Append("InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;InheritEnableFontSmoothing;InheritEnableDesktopComposition;InheritDomain;InheritIcon;InheritPanel;InheritPassword;InheritPort;InheritProtocol;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;InheritRedirectSmartCards;InheritRedirectSound;InheritResolution;InheritAutomaticResize;InheritUseConsoleSession;InheritUseCredSsp;InheritRenderingEngine;InheritUsername;InheritICAEncryptionStrength;InheritRDPAuthenticationLevel;InheritLoadBalanceInfo;InheritPreExtApp;InheritPostExtApp;InheritMacAddress;InheritUserField;InheritExtApp;InheritVNCCompression;InheritVNCEncoding;InheritVNCAuthMode;InheritVNCProxyType;InheritVNCProxyIP;InheritVNCProxyPort;InheritVNCProxyUsername;InheritVNCProxyPassword;InheritVNCColors;InheritVNCSmartSizeMode;InheritVNCViewOnly;InheritRDGatewayUsageMethod;InheritRDGatewayHostname;InheritRDGatewayUseConnectionCredentials;InheritRDGatewayUsername;InheritRDGatewayPassword;InheritRDGatewayDomain;InheritRDPAlertIdleTimeout;InheritRDPMinutesToIdleTimeout;InheritSoundQuality");
sb.Append("InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;InheritEnableFontSmoothing;InheritEnableDesktopComposition;InheritDomain;InheritIcon;InheritPanel;InheritPassword;InheritPort;InheritProtocol;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;InheritRedirectClipboard;InheritRedirectSmartCards;InheritRedirectSound;InheritResolution;InheritAutomaticResize;InheritUseConsoleSession;InheritUseCredSsp;InheritRenderingEngine;InheritUsername;InheritICAEncryptionStrength;InheritRDPAuthenticationLevel;InheritLoadBalanceInfo;InheritPreExtApp;InheritPostExtApp;InheritMacAddress;InheritUserField;InheritExtApp;InheritVNCCompression;InheritVNCEncoding;InheritVNCAuthMode;InheritVNCProxyType;InheritVNCProxyIP;InheritVNCProxyPort;InheritVNCProxyUsername;InheritVNCProxyPassword;InheritVNCColors;InheritVNCSmartSizeMode;InheritVNCViewOnly;InheritRDGatewayUsageMethod;InheritRDGatewayHostname;InheritRDGatewayUseConnectionCredentials;InheritRDGatewayUsername;InheritRDGatewayPassword;InheritRDGatewayDomain;InheritRDPAlertIdleTimeout;InheritRDPMinutesToIdleTimeout;InheritSoundQuality");
}
private void SerializeNodesRecursive(ConnectionInfo node, StringBuilder sb)
@@ -116,6 +116,7 @@ namespace mRemoteNG.Config.Serializers.Csv
.Append(FormatForCsv(con.RedirectDiskDrives))
.Append(FormatForCsv(con.RedirectPorts))
.Append(FormatForCsv(con.RedirectPrinters))
.Append(FormatForCsv(con.RedirectClipboard))
.Append(FormatForCsv(con.RedirectSmartCards))
.Append(FormatForCsv(con.RedirectSound))
.Append(FormatForCsv(con.RedirectKeys))
@@ -164,6 +165,7 @@ namespace mRemoteNG.Config.Serializers.Csv
.Append(FormatForCsv(con.Inheritance.RedirectKeys))
.Append(FormatForCsv(con.Inheritance.RedirectPorts))
.Append(FormatForCsv(con.Inheritance.RedirectPrinters))
.Append(FormatForCsv(con.Inheritance.RedirectClipboard))
.Append(FormatForCsv(con.Inheritance.RedirectSmartCards))
.Append(FormatForCsv(con.Inheritance.RedirectSound))
.Append(FormatForCsv(con.Inheritance.Resolution))

View File

@@ -1,20 +0,0 @@
namespace mRemoteNG.Config.Serializers.MsSql
{
public class LocalConnectionPropertiesModel
{
/// <summary>
/// The unique Id of this tree node
/// </summary>
public string ConnectionId { get; set; }
/// <summary>
/// Indicates whether this connection is connected
/// </summary>
public bool Connected { get; set; }
/// <summary>
/// Indicates whether this container is expanded in the tree
/// </summary>
public bool Expanded { get; set; }
}
}

View File

@@ -1,60 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace mRemoteNG.Config.Serializers.MsSql
{
public class LocalConnectionPropertiesXmlSerializer :
ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string>,
IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>>
{
public string Serialize(IEnumerable<LocalConnectionPropertiesModel> models)
{
var localConnections = models
.Select(m => new XElement("Node",
new XAttribute("ConnectionId", m.ConnectionId),
new XAttribute("Connected", m.Connected),
new XAttribute("Expanded", m.Expanded)));
var root = new XElement("LocalConnections", localConnections);
var xdoc = new XDocument(new XDeclaration("1.0", "utf-8", null), root);
return WriteXmlToString(xdoc);
}
public IEnumerable<LocalConnectionPropertiesModel> Deserialize(string serializedData)
{
if (string.IsNullOrWhiteSpace(serializedData))
return Enumerable.Empty<LocalConnectionPropertiesModel>();
var xdoc = XDocument.Parse(serializedData);
return xdoc
.Descendants("Node")
.Where(e => e.Attribute("ConnectionId") != null)
.Select(e => new LocalConnectionPropertiesModel
{
ConnectionId = e.Attribute("ConnectionId")?.Value,
Connected = bool.Parse(e.Attribute("Connected")?.Value ?? "False"),
Expanded = bool.Parse(e.Attribute("Expanded")?.Value ?? "False")
});
}
private static string WriteXmlToString(XNode xmlDocument)
{
string xmlString;
var xmlWriterSettings = new XmlWriterSettings { Indent = true, IndentChars = " ", Encoding = Encoding.UTF8 };
var memoryStream = new MemoryStream();
using (var xmlTextWriter = XmlWriter.Create(memoryStream, xmlWriterSettings))
{
xmlDocument.WriteTo(xmlTextWriter);
xmlTextWriter.Flush();
var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true);
memoryStream.Seek(0, SeekOrigin.Begin);
xmlString = streamReader.ReadToEnd();
}
return xmlString;
}
}
}

View File

@@ -1,13 +0,0 @@
using System;
using System.Security;
namespace mRemoteNG.Config.Serializers.MsSql
{
public class SqlConnectionListMetaData
{
public string Name { get; set; }
public string Protected { get; set; }
public bool Export { get; set; }
public Version ConfVersion { get; set; }
}
}

View File

@@ -210,7 +210,7 @@ namespace mRemoteNG.Config.Serializers.Xml
element.Add(new XAttribute("InheritRedirectDiskDrives", falseString));
element.Add(new XAttribute("InheritRedirectKeys", falseString));
element.Add(new XAttribute("InheritRedirectPorts", falseString));
element.Add(new XAttribute("InheritRedirectPrinters", falseString));
element.Add(new XAttribute("InheritRedirectPrinters", falseString));
element.Add(new XAttribute("InheritRedirectSmartCards", falseString));
element.Add(new XAttribute("InheritRedirectSound", falseString));
element.Add(new XAttribute("InheritSoundQuality", falseString));

View File

@@ -0,0 +1,256 @@
using System;
using System.Security;
using System.Xml.Linq;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Security;
namespace mRemoteNG.Config.Serializers.Xml
{
// ReSharper disable once InconsistentNaming
public class XmlConnectionNodeSerializer27 : ISerializer<ConnectionInfo,XElement>
{
private readonly ICryptographyProvider _cryptographyProvider;
private readonly SecureString _encryptionKey;
private readonly SaveFilter _saveFilter;
public XmlConnectionNodeSerializer27(ICryptographyProvider cryptographyProvider, SecureString encryptionKey, SaveFilter saveFilter)
{
if (cryptographyProvider == null)
throw new ArgumentNullException(nameof(cryptographyProvider));
if (encryptionKey == null)
throw new ArgumentNullException(nameof(encryptionKey));
if (saveFilter == null)
throw new ArgumentNullException(nameof(saveFilter));
_cryptographyProvider = cryptographyProvider;
_encryptionKey = encryptionKey;
_saveFilter = saveFilter;
}
public XElement Serialize(ConnectionInfo connectionInfo)
{
var element = new XElement(XName.Get("Node", ""));
SetElementAttributes(element, connectionInfo);
SetInheritanceAttributes(element, connectionInfo);
return element;
}
private void SetElementAttributes(XContainer element, ConnectionInfo connectionInfo)
{
var nodeAsContainer = connectionInfo as ContainerInfo;
element.Add(new XAttribute("Name", connectionInfo.Name));
element.Add(new XAttribute("Type", connectionInfo.GetTreeNodeType().ToString()));
if (nodeAsContainer != null)
element.Add(new XAttribute("Expanded", nodeAsContainer.IsExpanded.ToString().ToLowerInvariant()));
element.Add(new XAttribute("Descr", connectionInfo.Description));
element.Add(new XAttribute("Icon", connectionInfo.Icon));
element.Add(new XAttribute("Panel", connectionInfo.Panel));
element.Add(new XAttribute("Id", connectionInfo.ConstantID));
element.Add(_saveFilter.SaveUsername
? new XAttribute("Username", connectionInfo.Username)
: new XAttribute("Username", ""));
element.Add(_saveFilter.SaveDomain
? new XAttribute("Domain", connectionInfo.Domain)
: new XAttribute("Domain", ""));
if (_saveFilter.SavePassword && !connectionInfo.Inheritance.Password)
element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey)));
else
element.Add(new XAttribute("Password", ""));
element.Add(new XAttribute("Hostname", connectionInfo.Hostname));
element.Add(new XAttribute("Protocol", connectionInfo.Protocol));
element.Add(new XAttribute("PuttySession", connectionInfo.PuttySession));
element.Add(new XAttribute("Port", connectionInfo.Port));
element.Add(new XAttribute("ConnectToConsole", connectionInfo.UseConsoleSession.ToString().ToLowerInvariant()));
element.Add(new XAttribute("UseCredSsp", connectionInfo.UseCredSsp.ToString().ToLowerInvariant()));
element.Add(new XAttribute("RenderingEngine", connectionInfo.RenderingEngine));
element.Add(new XAttribute("ICAEncryptionStrength", connectionInfo.ICAEncryptionStrength));
element.Add(new XAttribute("RDPAuthenticationLevel", connectionInfo.RDPAuthenticationLevel));
element.Add(new XAttribute("RDPMinutesToIdleTimeout", connectionInfo.RDPMinutesToIdleTimeout));
element.Add(new XAttribute("RDPAlertIdleTimeout", connectionInfo.RDPAlertIdleTimeout.ToString().ToLowerInvariant()));
element.Add(new XAttribute("LoadBalanceInfo", connectionInfo.LoadBalanceInfo));
element.Add(new XAttribute("Colors", connectionInfo.Colors));
element.Add(new XAttribute("Resolution", connectionInfo.Resolution));
element.Add(new XAttribute("AutomaticResize", connectionInfo.AutomaticResize.ToString().ToLowerInvariant()));
element.Add(new XAttribute("DisplayWallpaper", connectionInfo.DisplayWallpaper.ToString().ToLowerInvariant()));
element.Add(new XAttribute("DisplayThemes", connectionInfo.DisplayThemes.ToString().ToLowerInvariant()));
element.Add(new XAttribute("EnableFontSmoothing", connectionInfo.EnableFontSmoothing.ToString().ToLowerInvariant()));
element.Add(new XAttribute("EnableDesktopComposition", connectionInfo.EnableDesktopComposition.ToString().ToLowerInvariant()));
element.Add(new XAttribute("CacheBitmaps", connectionInfo.CacheBitmaps.ToString().ToLowerInvariant()));
element.Add(new XAttribute("RedirectDiskDrives", connectionInfo.RedirectDiskDrives.ToString().ToLowerInvariant()));
element.Add(new XAttribute("RedirectPorts", connectionInfo.RedirectPorts.ToString().ToLowerInvariant()));
element.Add(new XAttribute("RedirectPrinters", connectionInfo.RedirectPrinters.ToString().ToLowerInvariant()));
element.Add(new XAttribute("RedirectClipboard", connectionInfo.RedirectClipboard.ToString().ToLowerInvariant()));
element.Add(new XAttribute("RedirectSmartCards", connectionInfo.RedirectSmartCards.ToString().ToLowerInvariant()));
element.Add(new XAttribute("RedirectSound", connectionInfo.RedirectSound.ToString()));
element.Add(new XAttribute("SoundQuality", connectionInfo.SoundQuality.ToString()));
element.Add(new XAttribute("RedirectKeys", connectionInfo.RedirectKeys.ToString().ToLowerInvariant()));
element.Add(new XAttribute("Connected", (connectionInfo.OpenConnections.Count > 0).ToString().ToLowerInvariant()));
element.Add(new XAttribute("PreExtApp", connectionInfo.PreExtApp));
element.Add(new XAttribute("PostExtApp", connectionInfo.PostExtApp));
element.Add(new XAttribute("MacAddress", connectionInfo.MacAddress));
element.Add(new XAttribute("UserField", connectionInfo.UserField));
element.Add(new XAttribute("ExtApp", connectionInfo.ExtApp));
element.Add(new XAttribute("VNCCompression", connectionInfo.VNCCompression));
element.Add(new XAttribute("VNCEncoding", connectionInfo.VNCEncoding));
element.Add(new XAttribute("VNCAuthMode", connectionInfo.VNCAuthMode));
element.Add(new XAttribute("VNCProxyType", connectionInfo.VNCProxyType));
element.Add(new XAttribute("VNCProxyIP", connectionInfo.VNCProxyIP));
element.Add(new XAttribute("VNCProxyPort", connectionInfo.VNCProxyPort));
element.Add(_saveFilter.SaveUsername
? new XAttribute("VNCProxyUsername", connectionInfo.VNCProxyUsername)
: new XAttribute("VNCProxyUsername", ""));
element.Add(_saveFilter.SavePassword
? new XAttribute("VNCProxyPassword",
_cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey))
: new XAttribute("VNCProxyPassword", ""));
element.Add(new XAttribute("VNCColors", connectionInfo.VNCColors));
element.Add(new XAttribute("VNCSmartSizeMode", connectionInfo.VNCSmartSizeMode));
element.Add(new XAttribute("VNCViewOnly", connectionInfo.VNCViewOnly.ToString().ToLowerInvariant()));
element.Add(new XAttribute("RDGatewayUsageMethod", connectionInfo.RDGatewayUsageMethod));
element.Add(new XAttribute("RDGatewayHostname", connectionInfo.RDGatewayHostname));
element.Add(new XAttribute("RDGatewayUseConnectionCredentials", connectionInfo.RDGatewayUseConnectionCredentials));
element.Add(_saveFilter.SaveUsername
? new XAttribute("RDGatewayUsername", connectionInfo.RDGatewayUsername)
: new XAttribute("RDGatewayUsername", ""));
element.Add(_saveFilter.SavePassword
? new XAttribute("RDGatewayPassword",
_cryptographyProvider.Encrypt(connectionInfo.RDGatewayPassword, _encryptionKey))
: new XAttribute("RDGatewayPassword", ""));
element.Add(_saveFilter.SaveDomain
? new XAttribute("RDGatewayDomain", connectionInfo.RDGatewayDomain)
: new XAttribute("RDGatewayDomain", ""));
}
private void SetInheritanceAttributes(XContainer element, IInheritable connectionInfo)
{
if (_saveFilter.SaveInheritance)
{
element.Add(new XAttribute("InheritCacheBitmaps", connectionInfo.Inheritance.CacheBitmaps.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritColors", connectionInfo.Inheritance.Colors.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritDescription", connectionInfo.Inheritance.Description.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritDisplayThemes", connectionInfo.Inheritance.DisplayThemes.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritDisplayWallpaper", connectionInfo.Inheritance.DisplayWallpaper.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritEnableFontSmoothing", connectionInfo.Inheritance.EnableFontSmoothing.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritEnableDesktopComposition", connectionInfo.Inheritance.EnableDesktopComposition.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritDomain", connectionInfo.Inheritance.Domain.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritIcon", connectionInfo.Inheritance.Icon.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritPanel", connectionInfo.Inheritance.Panel.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritPassword", connectionInfo.Inheritance.Password.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritPort", connectionInfo.Inheritance.Port.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritProtocol", connectionInfo.Inheritance.Protocol.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritPuttySession", connectionInfo.Inheritance.PuttySession.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRedirectDiskDrives", connectionInfo.Inheritance.RedirectDiskDrives.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRedirectKeys", connectionInfo.Inheritance.RedirectKeys.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRedirectPorts", connectionInfo.Inheritance.RedirectPorts.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRedirectPrinters", connectionInfo.Inheritance.RedirectPrinters.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRedirectClipboard", connectionInfo.Inheritance.RedirectClipboard.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRedirectSmartCards", connectionInfo.Inheritance.RedirectSmartCards.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRedirectSound", connectionInfo.Inheritance.RedirectSound.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritSoundQuality", connectionInfo.Inheritance.SoundQuality.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritResolution", connectionInfo.Inheritance.Resolution.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritAutomaticResize", connectionInfo.Inheritance.AutomaticResize.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritUseConsoleSession", connectionInfo.Inheritance.UseConsoleSession.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritUseCredSsp", connectionInfo.Inheritance.UseCredSsp.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRenderingEngine", connectionInfo.Inheritance.RenderingEngine.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritUsername", connectionInfo.Inheritance.Username.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritICAEncryptionStrength", connectionInfo.Inheritance.ICAEncryptionStrength.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRDPAuthenticationLevel", connectionInfo.Inheritance.RDPAuthenticationLevel.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", connectionInfo.Inheritance.RDPMinutesToIdleTimeout.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRDPAlertIdleTimeout", connectionInfo.Inheritance.RDPAlertIdleTimeout.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritLoadBalanceInfo", connectionInfo.Inheritance.LoadBalanceInfo.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritPreExtApp", connectionInfo.Inheritance.PreExtApp.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritPostExtApp", connectionInfo.Inheritance.PostExtApp.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritMacAddress", connectionInfo.Inheritance.MacAddress.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritUserField", connectionInfo.Inheritance.UserField.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritExtApp", connectionInfo.Inheritance.ExtApp.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCCompression", connectionInfo.Inheritance.VNCCompression.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCEncoding", connectionInfo.Inheritance.VNCEncoding.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCAuthMode", connectionInfo.Inheritance.VNCAuthMode.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCProxyType", connectionInfo.Inheritance.VNCProxyType.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCProxyIP", connectionInfo.Inheritance.VNCProxyIP.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCProxyPort", connectionInfo.Inheritance.VNCProxyPort.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCProxyUsername", connectionInfo.Inheritance.VNCProxyUsername.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCProxyPassword", connectionInfo.Inheritance.VNCProxyPassword.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCColors", connectionInfo.Inheritance.VNCColors.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCSmartSizeMode", connectionInfo.Inheritance.VNCSmartSizeMode.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritVNCViewOnly", connectionInfo.Inheritance.VNCViewOnly.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRDGatewayUsageMethod", connectionInfo.Inheritance.RDGatewayUsageMethod.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRDGatewayHostname", connectionInfo.Inheritance.RDGatewayHostname.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", connectionInfo.Inheritance.RDGatewayUseConnectionCredentials.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRDGatewayUsername", connectionInfo.Inheritance.RDGatewayUsername.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRDGatewayPassword", connectionInfo.Inheritance.RDGatewayPassword.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRDGatewayDomain", connectionInfo.Inheritance.RDGatewayDomain.ToString().ToLowerInvariant()));
}
else
{
var falseString = false.ToString().ToLowerInvariant();
element.Add(new XAttribute("InheritCacheBitmaps", falseString));
element.Add(new XAttribute("InheritColors", falseString));
element.Add(new XAttribute("InheritDescription", falseString));
element.Add(new XAttribute("InheritDisplayThemes", falseString));
element.Add(new XAttribute("InheritDisplayWallpaper", falseString));
element.Add(new XAttribute("InheritEnableFontSmoothing", falseString));
element.Add(new XAttribute("InheritEnableDesktopComposition", falseString));
element.Add(new XAttribute("InheritDomain", falseString));
element.Add(new XAttribute("InheritIcon", falseString));
element.Add(new XAttribute("InheritPanel", falseString));
element.Add(new XAttribute("InheritPassword", falseString));
element.Add(new XAttribute("InheritPort", falseString));
element.Add(new XAttribute("InheritProtocol", falseString));
element.Add(new XAttribute("InheritPuttySession", falseString));
element.Add(new XAttribute("InheritRedirectDiskDrives", falseString));
element.Add(new XAttribute("InheritRedirectKeys", falseString));
element.Add(new XAttribute("InheritRedirectPorts", falseString));
element.Add(new XAttribute("InheritRedirectPrinters", falseString));
element.Add(new XAttribute("InheritRedirectClipboard", falseString));
element.Add(new XAttribute("InheritRedirectSmartCards", falseString));
element.Add(new XAttribute("InheritRedirectSound", falseString));
element.Add(new XAttribute("InheritSoundQuality", falseString));
element.Add(new XAttribute("InheritResolution", falseString));
element.Add(new XAttribute("InheritAutomaticResize", falseString));
element.Add(new XAttribute("InheritUseConsoleSession", falseString));
element.Add(new XAttribute("InheritUseCredSsp", falseString));
element.Add(new XAttribute("InheritRenderingEngine", falseString));
element.Add(new XAttribute("InheritUsername", falseString));
element.Add(new XAttribute("InheritICAEncryptionStrength", falseString));
element.Add(new XAttribute("InheritRDPAuthenticationLevel", falseString));
element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", falseString));
element.Add(new XAttribute("InheritRDPAlertIdleTimeout", falseString));
element.Add(new XAttribute("InheritLoadBalanceInfo", falseString));
element.Add(new XAttribute("InheritPreExtApp", falseString));
element.Add(new XAttribute("InheritPostExtApp", falseString));
element.Add(new XAttribute("InheritMacAddress", falseString));
element.Add(new XAttribute("InheritUserField", falseString));
element.Add(new XAttribute("InheritExtApp", falseString));
element.Add(new XAttribute("InheritVNCCompression", falseString));
element.Add(new XAttribute("InheritVNCEncoding", falseString));
element.Add(new XAttribute("InheritVNCAuthMode", falseString));
element.Add(new XAttribute("InheritVNCProxyType", falseString));
element.Add(new XAttribute("InheritVNCProxyIP", falseString));
element.Add(new XAttribute("InheritVNCProxyPort", falseString));
element.Add(new XAttribute("InheritVNCProxyUsername", falseString));
element.Add(new XAttribute("InheritVNCProxyPassword", falseString));
element.Add(new XAttribute("InheritVNCColors", falseString));
element.Add(new XAttribute("InheritVNCSmartSizeMode", falseString));
element.Add(new XAttribute("InheritVNCViewOnly", falseString));
element.Add(new XAttribute("InheritRDGatewayUsageMethod", falseString));
element.Add(new XAttribute("InheritRDGatewayHostname", falseString));
element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", falseString));
element.Add(new XAttribute("InheritRDGatewayUsername", falseString));
element.Add(new XAttribute("InheritRDGatewayPassword", falseString));
element.Add(new XAttribute("InheritRDGatewayDomain", falseString));
}
}
}
}

View File

@@ -22,18 +22,22 @@ using mRemoteNG.UI.TaskDialog;
namespace mRemoteNG.Config.Serializers.Xml
{
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
{
{
private readonly IConnectionsService _connectionsService;
private XmlDocument _xmlDocument;
private double _confVersion;
private XmlConnectionsDecryptor _decryptor;
private string ConnectionFileName = "";
private const double MaxSupportedConfVersion = 2.8;
private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection);
private readonly IWin32Window _dialogWindowParent;
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
public XmlConnectionsDeserializer(Func<Optional<SecureString>> authenticationRequestor = null)
public XmlConnectionsDeserializer(IConnectionsService connectionsService, IWin32Window dialogWindowParent, Func<Optional<SecureString>> authenticationRequestor = null)
{
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
_dialogWindowParent = dialogWindowParent.ThrowIfNull(nameof(dialogWindowParent));
AuthenticationRequestor = authenticationRequestor;
}
@@ -78,13 +82,13 @@ namespace mRemoteNG.Config.Serializers.Xml
AddNodesFromXmlRecursive(_xmlDocument.DocumentElement, _rootNodeInfo);
if (!import)
Runtime.ConnectionsService.IsConnectionsFileLoaded = true;
_connectionsService.IsConnectionsFileLoaded = true;
return connectionTreeModel;
}
catch (Exception ex)
{
Runtime.ConnectionsService.IsConnectionsFileLoaded = false;
_connectionsService.IsConnectionsFileLoaded = false;
Runtime.MessageCollector.AddExceptionStackTrace(Language.strLoadFromXmlFailed, ex);
throw;
}
@@ -114,7 +118,7 @@ namespace mRemoteNG.Config.Serializers.Xml
private void ShowIncompatibleVersionDialogBox()
{
CTaskDialog.ShowTaskDialogBox(
FrmMain.Default,
_dialogWindowParent,
Application.ProductName,
"Incompatible connection file format",
$"The format of this connection file is not supported. Please upgrade to a newer version of {Application.ProductName}.",
@@ -285,14 +289,14 @@ namespace mRemoteNG.Config.Serializers.Xml
if (_confVersion >= 0.5)
{
connectionInfo.RedirectDiskDrives = bool.Parse(xmlnode.Attributes["RedirectDiskDrives"].Value);
connectionInfo.RedirectPrinters = bool.Parse(xmlnode.Attributes["RedirectPrinters"].Value);
connectionInfo.RedirectPrinters = bool.Parse(xmlnode.Attributes["RedirectPrinters"].Value);
connectionInfo.RedirectPorts = bool.Parse(xmlnode.Attributes["RedirectPorts"].Value);
connectionInfo.RedirectSmartCards = bool.Parse(xmlnode.Attributes["RedirectSmartCards"].Value);
}
else
{
connectionInfo.RedirectDiskDrives = false;
connectionInfo.RedirectPrinters = false;
connectionInfo.RedirectPrinters = false;
connectionInfo.RedirectPorts = false;
connectionInfo.RedirectSmartCards = false;
}
@@ -508,6 +512,11 @@ namespace mRemoteNG.Config.Serializers.Xml
connectionInfo.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["RDPAlertIdleTimeout"]?.Value ?? "False");
connectionInfo.Inheritance.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPAlertIdleTimeout"]?.Value ?? "False");
}
if(_confVersion >= 2.7)
{
connectionInfo.RedirectClipboard = bool.Parse(xmlnode.Attributes["RedirectClipboard"].Value);
connectionInfo.Inheritance.RedirectClipboard = bool.Parse(xmlnode.Attributes["InheritRedirectClipboard"].Value);
}
}
catch (Exception ex)
{

View File

@@ -1,4 +1,8 @@
using mRemoteNG.App;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.Http;
@@ -6,35 +10,26 @@ using mRemoteNG.Connection.Protocol.ICA;
using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Container;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security;
using mRemoteNG.Security;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
namespace mRemoteNG.Config.Serializers.MsSql
namespace mRemoteNG.Config.Serializers
{
public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel>
{
private readonly ICryptographyProvider _cryptographyProvider;
private readonly SecureString _decryptionKey;
public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel>
{
private readonly IConnectionsService _connectionsService;
public DataTableDeserializer(ICryptographyProvider cryptographyProvider, SecureString decryptionKey)
{
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
_decryptionKey = decryptionKey.ThrowIfNull(nameof(decryptionKey));
}
public DataTableDeserializer(IConnectionsService connectionsService)
{
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
public ConnectionTreeModel Deserialize(DataTable table)
public ConnectionTreeModel Deserialize(DataTable table)
{
var connectionList = CreateNodesFromTable(table);
var connectionTreeModel = CreateNodeHierarchy(connectionList, table);
Runtime.ConnectionsService.IsConnectionsFileLoaded = true;
_connectionsService.IsConnectionsFileLoaded = true;
return connectionTreeModel;
}
@@ -47,10 +42,10 @@ namespace mRemoteNG.Config.Serializers.MsSql
switch ((string)row["Type"])
{
case "Connection":
nodeList.Add(DeserializeConnectionInfo(row));
nodeList.Add(DeserializeConnectionInfo(row));
break;
case "Container":
nodeList.Add(DeserializeContainerInfo(row));
nodeList.Add(DeserializeContainerInfo(row));
break;
}
}
@@ -81,12 +76,16 @@ namespace mRemoteNG.Config.Serializers.MsSql
// The Parent object is linked properly later in CreateNodeHierarchy()
//connectionInfo.Parent.ConstantID = (string)dataRow["ParentID"];
var info = connectionInfo as ContainerInfo;
if(info != null)
info.IsExpanded = (bool)dataRow["Expanded"];
connectionInfo.Description = (string)dataRow["Description"];
connectionInfo.Icon = (string)dataRow["Icon"];
connectionInfo.Panel = (string)dataRow["Panel"];
connectionInfo.Username = (string)dataRow["Username"];
connectionInfo.Domain = (string)dataRow["DomainName"];
connectionInfo.Password = DecryptValue((string)dataRow["Password"]);
connectionInfo.Password = (string)dataRow["Password"];
connectionInfo.Hostname = (string)dataRow["Hostname"];
connectionInfo.Protocol = (ProtocolType)Enum.Parse(typeof(ProtocolType), (string)dataRow["Protocol"]);
connectionInfo.PuttySession = (string)dataRow["PuttySession"];
@@ -110,10 +109,12 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.RedirectDiskDrives = (bool)dataRow["RedirectDiskDrives"];
connectionInfo.RedirectPorts = (bool)dataRow["RedirectPorts"];
connectionInfo.RedirectPrinters = (bool)dataRow["RedirectPrinters"];
connectionInfo.RedirectClipboard = (bool)dataRow["RedirectClipboard"];
connectionInfo.RedirectSmartCards = (bool)dataRow["RedirectSmartCards"];
connectionInfo.RedirectSound = (RdpProtocol.RDPSounds)Enum.Parse(typeof(RdpProtocol.RDPSounds), (string)dataRow["RedirectSound"]);
connectionInfo.SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), (string)dataRow["SoundQuality"]);
connectionInfo.RedirectKeys = (bool)dataRow["RedirectKeys"];
connectionInfo.PleaseConnect = (bool)dataRow["Connected"];
connectionInfo.PreExtApp = (string)dataRow["PreExtApp"];
connectionInfo.PostExtApp = (string)dataRow["PostExtApp"];
connectionInfo.MacAddress = (string)dataRow["MacAddress"];
@@ -126,7 +127,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.VNCProxyIP = (string)dataRow["VNCProxyIP"];
connectionInfo.VNCProxyPort = (int)dataRow["VNCProxyPort"];
connectionInfo.VNCProxyUsername = (string)dataRow["VNCProxyUsername"];
connectionInfo.VNCProxyPassword = DecryptValue((string)dataRow["VNCProxyPassword"]);
connectionInfo.VNCProxyPassword = (string)dataRow["VNCProxyPassword"];
connectionInfo.VNCColors = (ProtocolVNC.Colors)Enum.Parse(typeof(ProtocolVNC.Colors), (string)dataRow["VNCColors"]);
connectionInfo.VNCSmartSizeMode = (ProtocolVNC.SmartSizeMode)Enum.Parse(typeof(ProtocolVNC.SmartSizeMode), (string)dataRow["VNCSmartSizeMode"]);
connectionInfo.VNCViewOnly = (bool)dataRow["VNCViewOnly"];
@@ -134,7 +135,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.RDGatewayHostname = (string)dataRow["RDGatewayHostname"];
connectionInfo.RDGatewayUseConnectionCredentials = (RdpProtocol.RDGatewayUseConnectionCredentials)Enum.Parse(typeof(RdpProtocol.RDGatewayUseConnectionCredentials), (string)dataRow["RDGatewayUseConnectionCredentials"]);
connectionInfo.RDGatewayUsername = (string)dataRow["RDGatewayUsername"];
connectionInfo.RDGatewayPassword = DecryptValue((string)dataRow["RDGatewayPassword"]);
connectionInfo.RDGatewayPassword = (string)dataRow["RDGatewayPassword"];
connectionInfo.RDGatewayDomain = (string)dataRow["RDGatewayDomain"];
connectionInfo.Inheritance.CacheBitmaps = (bool)dataRow["InheritCacheBitmaps"];
@@ -155,6 +156,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.Inheritance.RedirectKeys = (bool)dataRow["InheritRedirectKeys"];
connectionInfo.Inheritance.RedirectPorts = (bool)dataRow["InheritRedirectPorts"];
connectionInfo.Inheritance.RedirectPrinters = (bool)dataRow["InheritRedirectPrinters"];
connectionInfo.Inheritance.RedirectClipboard = (bool)dataRow["InheritRedirectClipboard"];
connectionInfo.Inheritance.RedirectSmartCards = (bool)dataRow["InheritRedirectSmartCards"];
connectionInfo.Inheritance.RedirectSound = (bool)dataRow["InheritRedirectSound"];
connectionInfo.Inheritance.SoundQuality = (bool)dataRow["InheritSoundQuality"];
@@ -193,26 +195,10 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.Inheritance.RDGatewayDomain = (bool)dataRow["InheritRDGatewayDomain"];
}
private string DecryptValue(string cipherText)
{
try
{
return _cryptographyProvider.Decrypt(cipherText, _decryptionKey);
}
catch (EncryptionException)
{
// value may not be encrypted
return cipherText;
}
}
private ConnectionTreeModel CreateNodeHierarchy(List<ConnectionInfo> connectionList, DataTable dataTable)
{
var connectionTreeModel = new ConnectionTreeModel();
var rootNode = new RootNodeInfo(RootNodeType.Connection, "0")
{
PasswordString = _decryptionKey.ConvertToUnsecureString()
};
var rootNode = new RootNodeInfo(RootNodeType.Connection, "0");
connectionTreeModel.AddRootNode(rootNode);
foreach (DataRow row in dataTable.Rows)

View File

@@ -1,31 +1,25 @@
using mRemoteNG.Connection;
using System;
using System.Data;
using System.Data.SqlTypes;
using System.Linq;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Security;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using System;
using System.Data;
using System.Data.SqlTypes;
using System.Linq;
using System.Security;
using mRemoteNG.Tools;
namespace mRemoteNG.Config.Serializers.MsSql
namespace mRemoteNG.Config.Serializers
{
public class DataTableSerializer : ISerializer<ConnectionInfo,DataTable>
{
private readonly ICryptographyProvider _cryptographyProvider;
private readonly SecureString _encryptionKey;
private DataTable _dataTable;
private const string TableName = "tblCons";
private readonly SaveFilter _saveFilter;
private int _currentNodeIndex;
public DataTableSerializer(SaveFilter saveFilter, ICryptographyProvider cryptographyProvider, SecureString encryptionKey)
public DataTableSerializer(SaveFilter saveFilter)
{
_saveFilter = saveFilter.ThrowIfNull(nameof(saveFilter));
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
_encryptionKey = encryptionKey.ThrowIfNull(nameof(encryptionKey));
_saveFilter = saveFilter;
}
@@ -97,6 +91,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataTable.Columns.Add("RedirectDiskDrives", typeof(bool));
dataTable.Columns.Add("RedirectPorts", typeof(bool));
dataTable.Columns.Add("RedirectPrinters", typeof(bool));
dataTable.Columns.Add("RedirectClipboard", typeof(bool));
dataTable.Columns.Add("RedirectSmartCards", typeof(bool));
dataTable.Columns.Add("RedirectSound", typeof(string));
dataTable.Columns.Add("RedirectKeys", typeof(bool));
@@ -141,6 +136,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataTable.Columns.Add("InheritRedirectKeys", typeof(bool));
dataTable.Columns.Add("InheritRedirectPorts", typeof(bool));
dataTable.Columns.Add("InheritRedirectPrinters", typeof(bool));
dataTable.Columns.Add("InheritRedirectClipboard", typeof(bool));
dataTable.Columns.Add("InheritRedirectSmartCards", typeof(bool));
dataTable.Columns.Add("InheritRedirectSound", typeof(bool));
dataTable.Columns.Add("InheritResolution", typeof(bool));
@@ -210,15 +206,14 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataRow["ParentID"] = connectionInfo.Parent?.ConstantID ?? "";
dataRow["PositionID"] = _currentNodeIndex;
dataRow["LastChange"] = (SqlDateTime)DateTime.Now;
dataRow["Expanded"] = false; // TODO: this column can eventually be removed. we now save this property locally
var info = connectionInfo as ContainerInfo;
dataRow["Expanded"] = info != null && info.IsExpanded;
dataRow["Description"] = connectionInfo.Description;
dataRow["Icon"] = connectionInfo.Icon;
dataRow["Panel"] = connectionInfo.Panel;
dataRow["Username"] = _saveFilter.SaveUsername ? connectionInfo.Username : "";
dataRow["DomainName"] = _saveFilter.SaveDomain ? connectionInfo.Domain : "";
dataRow["Password"] = _saveFilter.SavePassword
? _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey)
: "";
dataRow["Password"] = _saveFilter.SavePassword ? connectionInfo.Password : "";
dataRow["Hostname"] = connectionInfo.Hostname;
dataRow["Protocol"] = connectionInfo.Protocol;
dataRow["PuttySession"] = connectionInfo.PuttySession;
@@ -242,11 +237,12 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataRow["RedirectDiskDrives"] = connectionInfo.RedirectDiskDrives;
dataRow["RedirectPorts"] = connectionInfo.RedirectPorts;
dataRow["RedirectPrinters"] = connectionInfo.RedirectPrinters;
dataRow["RedirectClipboard"] = connectionInfo.RedirectClipboard;
dataRow["RedirectSmartCards"] = connectionInfo.RedirectSmartCards;
dataRow["RedirectSound"] = connectionInfo.RedirectSound;
dataRow["SoundQuality"] = connectionInfo.SoundQuality;
dataRow["RedirectKeys"] = connectionInfo.RedirectKeys;
dataRow["Connected"] = false; // TODO: this column can eventually be removed. we now save this property locally
dataRow["Connected"] = connectionInfo.OpenConnections.Count > 0;
dataRow["PreExtApp"] = connectionInfo.PreExtApp;
dataRow["PostExtApp"] = connectionInfo.PostExtApp;
dataRow["MacAddress"] = connectionInfo.MacAddress;
@@ -259,14 +255,14 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataRow["VNCProxyIP"] = connectionInfo.VNCProxyIP;
dataRow["VNCProxyPort"] = connectionInfo.VNCProxyPort;
dataRow["VNCProxyUsername"] = connectionInfo.VNCProxyUsername;
dataRow["VNCProxyPassword"] = _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey);
dataRow["VNCProxyPassword"] = connectionInfo.VNCProxyPassword;
dataRow["VNCColors"] = connectionInfo.VNCColors;
dataRow["VNCSmartSizeMode"] = connectionInfo.VNCSmartSizeMode;
dataRow["VNCViewOnly"] = connectionInfo.VNCViewOnly;
dataRow["RDGatewayUsageMethod"] = connectionInfo.RDGatewayUsageMethod;
dataRow["RDGatewayHostname"] = connectionInfo.RDGatewayHostname;
dataRow["RDGatewayUseConnectionCredentials"] = connectionInfo.RDGatewayUseConnectionCredentials;
dataRow["RDGatewayUsername"] = _cryptographyProvider.Encrypt(connectionInfo.RDGatewayUsername, _encryptionKey);
dataRow["RDGatewayUsername"] = connectionInfo.RDGatewayUsername;
dataRow["RDGatewayPassword"] = connectionInfo.RDGatewayPassword;
dataRow["RDGatewayDomain"] = connectionInfo.RDGatewayDomain;
if (_saveFilter.SaveInheritance)
@@ -289,6 +285,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataRow["InheritRedirectKeys"] = connectionInfo.Inheritance.RedirectKeys;
dataRow["InheritRedirectPorts"] = connectionInfo.Inheritance.RedirectPorts;
dataRow["InheritRedirectPrinters"] = connectionInfo.Inheritance.RedirectPrinters;
dataRow["InheritRedirectClipboard"] = connectionInfo.Inheritance.RedirectClipboard;
dataRow["InheritRedirectSmartCards"] = connectionInfo.Inheritance.RedirectSmartCards;
dataRow["InheritRedirectSound"] = connectionInfo.Inheritance.RedirectSound;
dataRow["InheritSoundQuality"] = connectionInfo.Inheritance.SoundQuality;
@@ -346,6 +343,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataRow["InheritRedirectKeys"] = false;
dataRow["InheritRedirectPorts"] = false;
dataRow["InheritRedirectPrinters"] = false;
dataRow["InheritRedirectClipboard"] = false;
dataRow["InheritRedirectSmartCards"] = false;
dataRow["InheritRedirectSound"] = false;
dataRow["InheritSoundQuality"] = false;

View File

@@ -108,6 +108,9 @@ namespace mRemoteNG.Config.Serializers
case "redirectprinters":
connectionInfo.RedirectPrinters = value == "1";
break;
case "redirectclipboard":
connectionInfo.RedirectClipboard = value == "1";
break;
case "audiomode":
switch (value)
{

View File

@@ -278,6 +278,7 @@ namespace mRemoteNG.Config.Serializers
connectionInfo.RedirectPorts = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectPorts")?.InnerText ?? "false");
connectionInfo.RedirectPrinters = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectPrinters")?.InnerText ?? "false");
connectionInfo.RedirectSmartCards = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectSmartCards")?.InnerText ?? "false");
connectionInfo.RedirectClipboard = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectClipboard")?.InnerText ?? "false");
}
else
{
@@ -287,6 +288,7 @@ namespace mRemoteNG.Config.Serializers
connectionInfo.Inheritance.RedirectPorts = true;
connectionInfo.Inheritance.RedirectPrinters = true;
connectionInfo.Inheritance.RedirectSmartCards = true;
connectionInfo.Inheritance.RedirectClipboard = true;
}
var securitySettingsNode = xmlNode.SelectSingleNode("./securitySettings");

View File

@@ -5,13 +5,13 @@ using mRemoteNG.App;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Messages;
namespace mRemoteNG.Config.Serializers.MsSql
namespace mRemoteNG.Config.Serializers.Versioning
{
public class SqlDatabaseMetaDataRetriever
public class SqlDatabaseVersionRetriever
{
public SqlConnectionListMetaData GetDatabaseMetaData(SqlDatabaseConnector sqlDatabaseConnector)
public Version GetDatabaseVersion(SqlDatabaseConnector sqlDatabaseConnector)
{
SqlConnectionListMetaData metaData;
Version databaseVersion;
SqlDataReader sqlDataReader = null;
try
{
@@ -20,17 +20,10 @@ namespace mRemoteNG.Config.Serializers.MsSql
sqlDatabaseConnector.Connect();
sqlDataReader = sqlCommand.ExecuteReader();
if (!sqlDataReader.HasRows)
return null; // assume new empty database
return new Version(); // assume new empty database
else
sqlDataReader.Read();
metaData = new SqlConnectionListMetaData
{
Name = sqlDataReader["Name"] as string ?? "",
Protected = sqlDataReader["Protected"] as string ?? "",
Export = (bool)sqlDataReader["Export"],
ConfVersion = new Version(Convert.ToString(sqlDataReader["confVersion"], CultureInfo.InvariantCulture))
};
databaseVersion = new Version(Convert.ToString(sqlDataReader["confVersion"], CultureInfo.InvariantCulture));
}
catch (Exception ex)
{
@@ -42,7 +35,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
if (sqlDataReader != null && !sqlDataReader.IsClosed)
sqlDataReader.Close();
}
return metaData;
return databaseVersion;
}
}
}

View File

@@ -9,6 +9,7 @@ namespace mRemoteNG.Config.Serializers.Versioning
public class SqlDatabaseVersionVerifier
{
private readonly SqlDatabaseConnector _sqlDatabaseConnector;
private readonly SqlDatabaseVersionRetriever _versionRetriever;
public SqlDatabaseVersionVerifier(SqlDatabaseConnector sqlDatabaseConnector)
{
@@ -16,14 +17,15 @@ namespace mRemoteNG.Config.Serializers.Versioning
throw new ArgumentNullException(nameof(sqlDatabaseConnector));
_sqlDatabaseConnector = sqlDatabaseConnector;
_versionRetriever = new SqlDatabaseVersionRetriever();
}
public bool VerifyDatabaseVersion(Version dbVersion)
public bool VerifyDatabaseVersion()
{
var isVerified = false;
try
{
var databaseVersion = dbVersion;
var databaseVersion = _versionRetriever.GetDatabaseVersion(_sqlDatabaseConnector);
if (databaseVersion.Equals(new Version()))
{

View File

@@ -5,6 +5,7 @@ using mRemoteNG.UI.Window;
using System;
using System.IO;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.Config.Settings
@@ -13,16 +14,13 @@ namespace mRemoteNG.Config.Settings
{
private readonly FrmMain _mainForm;
private readonly MessageCollector _messageCollector;
private readonly Windows _windows;
public DockPanelLayoutLoader(FrmMain mainForm, MessageCollector messageCollector)
public DockPanelLayoutLoader(FrmMain mainForm, MessageCollector messageCollector, Windows windows)
{
if (mainForm == null)
throw new ArgumentNullException(nameof(mainForm));
if (messageCollector == null)
throw new ArgumentNullException(nameof(messageCollector));
_mainForm = mainForm;
_messageCollector = messageCollector;
_mainForm = mainForm.ThrowIfNull(nameof(mainForm));
_messageCollector = messageCollector.ThrowIfNull(nameof(messageCollector));
_windows = windows.ThrowIfNull(nameof(windows));
}
public void LoadPanelsFromXml()
@@ -69,16 +67,16 @@ namespace mRemoteNG.Config.Settings
try
{
if (persistString == typeof(ConfigWindow).ToString())
return Windows.ConfigForm;
return _windows.ConfigForm;
if (persistString == typeof(ConnectionTreeWindow).ToString())
return Windows.TreeForm;
return _windows.TreeForm;
if (persistString == typeof(ErrorAndInfoWindow).ToString())
return Windows.ErrorsForm;
return _windows.ErrorsForm;
if (persistString == typeof(ScreenshotManagerWindow).ToString())
return Windows.ScreenshotForm;
return _windows.ScreenshotForm;
}
catch (Exception ex)
{

View File

@@ -25,7 +25,7 @@ namespace mRemoteNG.Config.Settings
_dataProvider = dataProvider;
}
public void Save()
public void Save(DockPanel dockPanel)
{
try
{
@@ -34,7 +34,7 @@ namespace mRemoteNG.Config.Settings
Directory.CreateDirectory(SettingsFileInfo.SettingsPath);
}
var serializedLayout = _dockPanelSerializer.Serialize(FrmMain.Default.pnlDock);
var serializedLayout = _dockPanelSerializer.Serialize(dockPanel);
_dataProvider.Save(serializedLayout);
}
catch (Exception ex)

View File

@@ -4,6 +4,7 @@ using mRemoteNG.App.Info;
using mRemoteNG.UI.Forms;
using System.IO;
using System.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.UI.Controls;
@@ -12,22 +13,20 @@ namespace mRemoteNG.Config.Settings
{
public class ExternalAppsLoader
{
private readonly FrmMain _mainForm;
private readonly MessageCollector _messageCollector;
private readonly ExternalToolsToolStrip _externalToolsToolStrip;
private readonly IConnectionInitiator _connectionInitiator;
private readonly ExternalToolsService _externalToolsService;
private readonly IConnectionsService _connectionsService;
public ExternalAppsLoader(FrmMain mainForm, MessageCollector messageCollector, ExternalToolsToolStrip externalToolsToolStrip)
public ExternalAppsLoader(MessageCollector messageCollector, ExternalToolsToolStrip externalToolsToolStrip,
IConnectionInitiator connectionInitiator, ExternalToolsService externalToolsService, IConnectionsService connectionsService)
{
if (mainForm == null)
throw new ArgumentNullException(nameof(mainForm));
if (messageCollector == null)
throw new ArgumentNullException(nameof(messageCollector));
if (externalToolsToolStrip == null)
throw new ArgumentNullException(nameof(externalToolsToolStrip));
_mainForm = mainForm;
_messageCollector = messageCollector;
_externalToolsToolStrip = externalToolsToolStrip;
_messageCollector = messageCollector.ThrowIfNull(nameof(messageCollector));
_externalToolsToolStrip = externalToolsToolStrip.ThrowIfNull(nameof(externalToolsToolStrip));
_connectionInitiator = connectionInitiator.ThrowIfNull(nameof(connectionInitiator));
_externalToolsService = externalToolsService.ThrowIfNull(nameof(externalToolsService));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
@@ -48,7 +47,6 @@ namespace mRemoteNG.Config.Settings
{
_messageCollector.AddMessage(MessageClass.InformationMsg, $"Loading External Apps from: {oldPath}", true);
xDom.Load(oldPath);
}
#endif
else
@@ -65,7 +63,7 @@ namespace mRemoteNG.Config.Settings
foreach (XmlElement xEl in xDom.DocumentElement.ChildNodes)
{
var extA = new ExternalTool
var extA = new ExternalTool(_connectionInitiator, _connectionsService)
{
DisplayName = xEl.Attributes["DisplayName"].Value,
FileName = xEl.Attributes["FileName"].Value,
@@ -94,7 +92,7 @@ namespace mRemoteNG.Config.Settings
}
_messageCollector.AddMessage(MessageClass.InformationMsg, $"Adding External App: {extA.DisplayName} {extA.FileName} {extA.Arguments}", true);
Runtime.ExternalToolsService.ExternalTools.Add(extA);
_externalToolsService.ExternalTools.Add(extA);
}
_externalToolsToolStrip.SwitchToolBarText(mRemoteNG.Settings.Default.ExtAppsTBShowText);

View File

@@ -23,8 +23,8 @@ namespace mRemoteNG.Config.Settings
private readonly QuickConnectToolStrip _quickConnectToolStrip;
private readonly ExternalToolsToolStrip _externalToolsToolStrip;
private readonly MultiSshToolStrip _multiSshToolStrip;
private FrmMain MainForm { get; }
private readonly Func<NotificationAreaIcon> _notificationAreaIconBuilder;
private readonly FrmMain _frmMain;
public SettingsLoader(
@@ -33,29 +33,19 @@ namespace mRemoteNG.Config.Settings
QuickConnectToolStrip quickConnectToolStrip,
ExternalToolsToolStrip externalToolsToolStrip,
MultiSshToolStrip multiSshToolStrip,
ExternalAppsLoader externalAppsLoader,
Func<NotificationAreaIcon> notificationAreaIconBuilder,
MenuStrip mainMenu)
{
if (mainForm == null)
throw new ArgumentNullException(nameof(mainForm));
if (messageCollector == null)
throw new ArgumentNullException(nameof(messageCollector));
if (quickConnectToolStrip == null)
throw new ArgumentNullException(nameof(quickConnectToolStrip));
if (externalToolsToolStrip == null)
throw new ArgumentNullException(nameof(externalToolsToolStrip));
if (multiSshToolStrip == null)
throw new ArgumentNullException(nameof(multiSshToolStrip));
if (mainMenu == null)
throw new ArgumentNullException(nameof(mainMenu));
MainForm = mainForm;
_messageCollector = messageCollector;
_quickConnectToolStrip = quickConnectToolStrip;
_externalToolsToolStrip = externalToolsToolStrip;
_multiSshToolStrip = multiSshToolStrip;
_mainMenu = mainMenu;
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip);
}
_frmMain = mainForm.ThrowIfNull(nameof(mainForm));
_messageCollector = messageCollector.ThrowIfNull(nameof(messageCollector));
_quickConnectToolStrip = quickConnectToolStrip.ThrowIfNull(nameof(quickConnectToolStrip));
_externalToolsToolStrip = externalToolsToolStrip.ThrowIfNull(nameof(externalToolsToolStrip));
_multiSshToolStrip = multiSshToolStrip.ThrowIfNull(nameof(multiSshToolStrip));
_externalAppsLoader = externalAppsLoader.ThrowIfNull(nameof(externalAppsLoader));
_notificationAreaIconBuilder = notificationAreaIconBuilder.ThrowIfNull(nameof(notificationAreaIconBuilder));
_mainMenu = mainMenu.ThrowIfNull(nameof(mainMenu));
}
#region Public Methods
public void LoadSettings()
@@ -85,10 +75,10 @@ namespace mRemoteNG.Config.Settings
}
}
private static void SetAlwaysShowPanelTabs()
private void SetAlwaysShowPanelTabs()
{
if (mRemoteNG.Settings.Default.AlwaysShowPanelTabs)
FrmMain.Default.pnlDock.DocumentStyle = DocumentStyle.DockingWindow;
_frmMain.pnlDock.DocumentStyle = DocumentStyle.DockingWindow;
}
@@ -103,32 +93,32 @@ namespace mRemoteNG.Config.Settings
private void SetApplicationWindowPositionAndSize()
{
MainForm.WindowState = FormWindowState.Normal;
_frmMain.WindowState = FormWindowState.Normal;
if (mRemoteNG.Settings.Default.MainFormState == FormWindowState.Normal)
{
if (!mRemoteNG.Settings.Default.MainFormLocation.IsEmpty)
MainForm.Location = mRemoteNG.Settings.Default.MainFormLocation;
_frmMain.Location = mRemoteNG.Settings.Default.MainFormLocation;
if (!mRemoteNG.Settings.Default.MainFormSize.IsEmpty)
MainForm.Size = mRemoteNG.Settings.Default.MainFormSize;
_frmMain.Size = mRemoteNG.Settings.Default.MainFormSize;
}
else
{
if (!mRemoteNG.Settings.Default.MainFormRestoreLocation.IsEmpty)
MainForm.Location = mRemoteNG.Settings.Default.MainFormRestoreLocation;
_frmMain.Location = mRemoteNG.Settings.Default.MainFormRestoreLocation;
if (!mRemoteNG.Settings.Default.MainFormRestoreSize.IsEmpty)
MainForm.Size = mRemoteNG.Settings.Default.MainFormRestoreSize;
_frmMain.Size = mRemoteNG.Settings.Default.MainFormRestoreSize;
}
if (mRemoteNG.Settings.Default.MainFormState == FormWindowState.Maximized)
{
MainForm.WindowState = FormWindowState.Maximized;
_frmMain.WindowState = FormWindowState.Maximized;
}
// Make sure the form is visible on the screen
const int minHorizontal = 300;
const int minVertical = 150;
var screenBounds = Screen.FromHandle(MainForm.Handle).Bounds;
var newBounds = MainForm.Bounds;
var screenBounds = Screen.FromHandle(_frmMain.Handle).Bounds;
var newBounds = _frmMain.Bounds;
if (newBounds.Right < screenBounds.Left + minHorizontal)
newBounds.X = screenBounds.Left + minHorizontal - newBounds.Width;
@@ -139,29 +129,29 @@ namespace mRemoteNG.Config.Settings
if (newBounds.Top > screenBounds.Bottom - minVertical)
newBounds.Y = screenBounds.Bottom - minVertical;
MainForm.Location = newBounds.Location;
_frmMain.Location = newBounds.Location;
}
private void SetAutoSave()
{
if (mRemoteNG.Settings.Default.AutoSaveEveryMinutes <= 0) return;
MainForm.tmrAutoSave.Interval = mRemoteNG.Settings.Default.AutoSaveEveryMinutes * 60000;
MainForm.tmrAutoSave.Enabled = true;
_frmMain.tmrAutoSave.Interval = mRemoteNG.Settings.Default.AutoSaveEveryMinutes * 60000;
_frmMain.tmrAutoSave.Enabled = true;
}
private void SetKioskMode()
{
if (!mRemoteNG.Settings.Default.MainFormKiosk) return;
MainForm.Fullscreen.Value = true;
_frmMain.Fullscreen.Value = true;
}
private static void SetShowSystemTrayIcon()
private void SetShowSystemTrayIcon()
{
if (mRemoteNG.Settings.Default.ShowSystemTrayIcon)
Runtime.NotificationAreaIcon = new NotificationAreaIcon();
Runtime.NotificationAreaIcon = _notificationAreaIconBuilder();
}
private static void SetPuttyPath()
private void SetPuttyPath()
{
PuttyBase.PuttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath ? mRemoteNG.Settings.Default.CustomPuttyPath : GeneralAppInfo.PuttyPath;
}
@@ -265,15 +255,15 @@ namespace mRemoteNG.Config.Settings
switch (panel.ToLower())
{
case "top":
return MainForm.tsContainer.TopToolStripPanel;
return _frmMain.tsContainer.TopToolStripPanel;
case "bottom":
return MainForm.tsContainer.BottomToolStripPanel;
return _frmMain.tsContainer.BottomToolStripPanel;
case "left":
return MainForm.tsContainer.LeftToolStripPanel;
return _frmMain.tsContainer.LeftToolStripPanel;
case "right":
return MainForm.tsContainer.RightToolStripPanel;
return _frmMain.tsContainer.RightToolStripPanel;
default:
return MainForm.tsContainer.TopToolStripPanel;
return _frmMain.tsContainer.TopToolStripPanel;
}
}
@@ -283,4 +273,4 @@ namespace mRemoteNG.Config.Settings
}
#endregion
}
}
}

View File

@@ -6,12 +6,20 @@ using mRemoteNG.Config.DataProviders;
using mRemoteNG.Tools;
using mRemoteNG.UI.Controls;
using mRemoteNG.UI.Forms;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.Config.Settings
{
public static class SettingsSaver
public class SettingsSaver
{
public static void SaveSettings(
private readonly ExternalToolsService _externalToolsService;
public SettingsSaver(ExternalToolsService externalToolsService)
{
_externalToolsService = externalToolsService.ThrowIfNull(nameof(externalToolsService));
}
public void SaveSettings(
Control quickConnectToolStrip,
ExternalToolsToolStrip externalToolsToolStrip,
MultiSshToolStrip multiSshToolStrip,
@@ -19,7 +27,7 @@ namespace mRemoteNG.Config.Settings
{
try
{
var windowPlacement = new WindowPlacement(FrmMain.Default);
var windowPlacement = new WindowPlacement(frmMain);
if (frmMain.WindowState == FormWindowState.Minimized & windowPlacement.RestoreToMaximized)
{
frmMain.Opacity = 0;
@@ -53,7 +61,7 @@ namespace mRemoteNG.Config.Settings
mRemoteNG.Settings.Default.Save();
SaveDockPanelLayout();
SaveDockPanelLayout(frmMain.pnlDock);
SaveExternalApps();
}
catch (Exception ex)
@@ -62,7 +70,7 @@ namespace mRemoteNG.Config.Settings
}
}
private static void SaveExternalAppsToolbarLocation(ExternalToolsToolStrip externalToolsToolStrip)
private void SaveExternalAppsToolbarLocation(ExternalToolsToolStrip externalToolsToolStrip)
{
mRemoteNG.Settings.Default.ExtAppsTBLocation = externalToolsToolStrip.Location;
mRemoteNG.Settings.Default.ExtAppsTBVisible = externalToolsToolStrip.Visible;
@@ -74,7 +82,7 @@ namespace mRemoteNG.Config.Settings
}
}
private static void SaveQuickConnectToolbarLocation(Control quickConnectToolStrip)
private void SaveQuickConnectToolbarLocation(Control quickConnectToolStrip)
{
mRemoteNG.Settings.Default.QuickyTBLocation = quickConnectToolStrip.Location;
mRemoteNG.Settings.Default.QuickyTBVisible = quickConnectToolStrip.Visible;
@@ -85,7 +93,7 @@ namespace mRemoteNG.Config.Settings
}
}
private static void SaveMultiSshToolbarLocation(MultiSshToolStrip multiSshToolStrip)
private void SaveMultiSshToolbarLocation(MultiSshToolStrip multiSshToolStrip)
{
mRemoteNG.Settings.Default.MultiSshToolbarLocation = multiSshToolStrip.Location;
mRemoteNG.Settings.Default.MultiSshToolbarVisible = multiSshToolStrip.Visible;
@@ -96,20 +104,20 @@ namespace mRemoteNG.Config.Settings
}
}
private static void SaveDockPanelLayout()
private void SaveDockPanelLayout(DockPanel dockPanel)
{
var panelLayoutXmlFilePath = SettingsFileInfo.SettingsPath + "\\" + SettingsFileInfo.LayoutFileName;
var panelLayoutSaver = new DockPanelLayoutSaver(
new DockPanelLayoutSerializer(),
new FileDataProvider(panelLayoutXmlFilePath)
);
panelLayoutSaver.Save();
panelLayoutSaver.Save(dockPanel);
}
private static void SaveExternalApps()
private void SaveExternalApps()
{
var externalAppsSaver = new ExternalAppsSaver();
externalAppsSaver.Save(Runtime.ExternalToolsService.ExternalTools);
externalAppsSaver.Save(_externalToolsService.ExternalTools);
}
}
}

View File

@@ -57,6 +57,7 @@ namespace mRemoteNG.Connection
private bool _redirectKeys;
private bool _redirectDiskDrives;
private bool _redirectPrinters;
private bool _redirectClipboard;
private bool _redirectPorts;
private bool _redirectSmartCards;
private RdpProtocol.RDPSounds _redirectSound;
@@ -455,6 +456,16 @@ namespace mRemoteNG.Connection
set => SetField(ref _redirectPrinters, value, "RedirectPrinters");
}
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectClipboard"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectClipboard"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectClipboard
{
get { return GetPropertyValue("RedirectClipboard", _redirectClipboard); }
set { SetField(ref _redirectClipboard, value, "RedirectClipboard"); }
}
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectPorts"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectPorts"),
@@ -674,7 +685,7 @@ namespace mRemoteNG.Connection
PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(args.PropertyName));
}
protected void SetField<T>(ref T field, T value, string propertyName = null)
private void SetField<T>(ref T field, T value, string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return;
field = value;

View File

@@ -313,9 +313,10 @@ namespace mRemoteNG.Connection
RedirectKeys = Settings.Default.ConDefaultRedirectKeys;
RedirectDiskDrives = Settings.Default.ConDefaultRedirectDiskDrives;
RedirectPrinters = Settings.Default.ConDefaultRedirectPrinters;
RedirectClipboard = Settings.Default.ConDefaultRedirectClipboard;
RedirectPorts = Settings.Default.ConDefaultRedirectPorts;
RedirectSmartCards = Settings.Default.ConDefaultRedirectSmartCards;
RedirectSound = (RdpProtocol.RDPSounds) Enum.Parse(typeof(RdpProtocol.RDPSounds), Settings.Default.ConDefaultRedirectSound);
RedirectSound = (RdpProtocol.RDPSounds) Enum.Parse(typeof(RdpProtocol.RDPSounds), Settings.Default.ConDefaultRedirectSound);
SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), Settings.Default.ConDefaultSoundQuality);
}

View File

@@ -215,8 +215,13 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectPrinters"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectPrinters"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectPrinters {get; set;}
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7),
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectClipboard"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectClipboard"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectClipboard { get; set; }
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectPorts"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectPorts"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectPorts {get; set;}

View File

@@ -1,28 +1,40 @@
using mRemoteNG.App;
using System;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Container;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.UI;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Panels;
using mRemoteNG.UI.Window;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using TabPage = Crownwood.Magic.Controls.TabPage;
namespace mRemoteNG.Connection
{
public class ConnectionInitiator : IConnectionInitiator
{
private readonly PanelAdder _panelAdder = new PanelAdder();
private readonly List<string> _activeConnections = new List<string>();
public class ConnectionInitiator : IConnectionInitiator
{
private readonly WindowList _windowList;
private readonly ExternalToolsService _externalToolsService;
private readonly ProtocolFactory _protocolFactory;
private readonly FrmMain _frmMain;
/// <summary>
/// List of unique IDs of the currently active connections
/// This is a property because we have a circular dependency.
/// </summary>
public IEnumerable<string> ActiveConnections => _activeConnections;
public PanelAdder Adder { get; set; }
public ConnectionInitiator(WindowList windowList, ExternalToolsService externalToolsService, ProtocolFactory protocolFactory, FrmMain frmMain)
{
_frmMain = frmMain;
_windowList = windowList.ThrowIfNull(nameof(windowList));
_externalToolsService = externalToolsService.ThrowIfNull(nameof(externalToolsService));
_protocolFactory = protocolFactory.ThrowIfNull(nameof(protocolFactory));
}
public void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None)
{
@@ -60,7 +72,7 @@ namespace mRemoteNG.Connection
var connectionWindow = (ConnectionWindow)interfaceControl.FindForm();
connectionWindow?.Focus();
var findForm = (ConnectionWindow)interfaceControl.FindForm();
findForm?.Show(FrmMain.Default.pnlDock);
findForm?.Show(_frmMain.pnlDock);
var tabPage = (TabPage)interfaceControl.Parent;
tabPage.Selected = true;
return true;
@@ -99,8 +111,7 @@ namespace mRemoteNG.Connection
return;
}
var protocolFactory = new ProtocolFactory();
var newProtocol = protocolFactory.CreateProtocol(connectionInfo);
var newProtocol = _protocolFactory.CreateProtocol(connectionInfo);
var connectionPanel = SetConnectionPanel(connectionInfo, force);
if (string.IsNullOrEmpty(connectionPanel)) return;
@@ -125,8 +136,7 @@ namespace mRemoteNG.Connection
}
connectionInfo.OpenConnections.Add(newProtocol);
_activeConnections.Add(connectionInfo.ConstantID);
FrmMain.Default.SelectedConnection = connectionInfo;
_frmMain.SelectedConnection = connectionInfo;
}
catch (Exception ex)
{
@@ -134,19 +144,19 @@ namespace mRemoteNG.Connection
}
}
private static void StartPreConnectionExternalApp(ConnectionInfo connectionInfo)
private void StartPreConnectionExternalApp(ConnectionInfo connectionInfo)
{
if (connectionInfo.PreExtApp == "") return;
var extA = Runtime.ExternalToolsService.GetExtAppByName(connectionInfo.PreExtApp);
var extA = _externalToolsService.GetExtAppByName(connectionInfo.PreExtApp);
extA?.Start(connectionInfo);
}
private static InterfaceControl FindConnectionContainer(ConnectionInfo connectionInfo)
private InterfaceControl FindConnectionContainer(ConnectionInfo connectionInfo)
{
if (connectionInfo.OpenConnections.Count <= 0) return null;
for (var i = 0; i <= Runtime.WindowList.Count - 1; i++)
for (var i = 0; i <= _windowList.Count - 1; i++)
{
var window = Runtime.WindowList[i] as ConnectionWindow;
var window = _windowList[i] as ConnectionWindow;
var connectionWindow = window;
if (connectionWindow?.TabController == null) continue;
foreach (TabPage t in connectionWindow.TabController.TabPages)
@@ -162,12 +172,12 @@ namespace mRemoteNG.Connection
return null;
}
private static string SetConnectionPanel(ConnectionInfo connectionInfo, ConnectionInfo.Force force)
private string SetConnectionPanel(ConnectionInfo connectionInfo, ConnectionInfo.Force force)
{
var connectionPanel = "";
if (connectionInfo.Panel == "" || (force & ConnectionInfo.Force.OverridePanel) == ConnectionInfo.Force.OverridePanel | Settings.Default.AlwaysShowPanelSelectionDlg)
{
var frmPnl = new frmChoosePanel();
var frmPnl = new frmChoosePanel(Adder, _windowList);
if (frmPnl.ShowDialog() == DialogResult.OK)
{
connectionPanel = frmPnl.Panel;
@@ -186,24 +196,24 @@ namespace mRemoteNG.Connection
private Form SetConnectionForm(Form conForm, string connectionPanel)
{
var connectionForm = conForm ?? Runtime.WindowList.FromString(connectionPanel);
var connectionForm = conForm ?? _windowList.FromString(connectionPanel);
if (connectionForm == null)
connectionForm = _panelAdder.AddPanel(connectionPanel);
connectionForm = Adder.AddPanel(connectionPanel);
else
((ConnectionWindow)connectionForm).Show(FrmMain.Default.pnlDock);
((ConnectionWindow)connectionForm).Show(_frmMain.pnlDock);
connectionForm.Focus();
return connectionForm;
}
private static Control SetConnectionContainer(ConnectionInfo connectionInfo, Form connectionForm)
private Control SetConnectionContainer(ConnectionInfo connectionInfo, Form connectionForm)
{
Control connectionContainer = ((ConnectionWindow)connectionForm).AddConnectionTab(connectionInfo);
if (connectionInfo.Protocol != ProtocolType.IntApp) return connectionContainer;
var extT = Runtime.ExternalToolsService.GetExtAppByName(connectionInfo.ExtApp);
var extT = _externalToolsService.GetExtAppByName(connectionInfo.ExtApp);
if(extT == null) return connectionContainer;
@@ -275,11 +285,9 @@ namespace mRemoteNG.Connection
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strConnenctionClosedByUser, connDetail, prot.InterfaceControl.Info.Protocol, Environment.UserName));
prot.InterfaceControl.Info.OpenConnections.Remove(prot);
if (_activeConnections.Contains(prot.InterfaceControl.Info.ConstantID))
_activeConnections.Remove(prot.InterfaceControl.Info.ConstantID);
if (prot.InterfaceControl.Info.PostExtApp == "") return;
var extA = Runtime.ExternalToolsService.GetExtAppByName(prot.InterfaceControl.Info.PostExtApp);
var extA = _externalToolsService.GetExtAppByName(prot.InterfaceControl.Info.PostExtApp);
extA?.Start(prot.InterfaceControl.Info);
}
catch (Exception ex)

View File

@@ -1,10 +1,14 @@
using mRemoteNG.App;
using System;
using System.IO;
using System.Security;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.App.Info;
using mRemoteNG.Config.Connections;
using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Serializers.MsSql;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Messages;
using mRemoteNG.Security;
@@ -12,20 +16,17 @@ using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI;
using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.Config;
using mRemoteNG.UI.TaskDialog;
namespace mRemoteNG.Connection
{
public class ConnectionsService
public class ConnectionsService : IConnectionsService
{
private static readonly object SaveLock = new object();
private bool _showDialogWhenLoadingConnections;
private readonly PuttySessionsManager _puttySessionsManager;
private readonly IDataProvider<string> _localConnectionPropertiesDataProvider;
private readonly LocalConnectionPropertiesXmlSerializer _localConnectionPropertiesSerializer;
private readonly Import _import;
private readonly IWin32Window _dialogWindowParent;
private bool _batchingSaves = false;
private bool _saveRequested = false;
private bool _saveAsyncRequested = false;
@@ -35,18 +36,16 @@ namespace mRemoteNG.Connection
public string ConnectionFileName { get; private set; }
public RemoteConnectionsSyncronizer RemoteConnectionsSyncronizer { get; set; }
public DateTime LastSqlUpdate { get; set; }
public SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
// TODO - this is only a property to break up a circular dependency. move to ctor when able
public DatabaseConnectorFactory DatabaseConnectorFactory { get; set; }
public ConnectionTreeModel ConnectionTreeModel { get; private set; }
public ConnectionsService(PuttySessionsManager puttySessionsManager)
public ConnectionsService(PuttySessionsManager puttySessionsManager, Import import, IWin32Window dialogWindowParent)
{
if (puttySessionsManager == null)
throw new ArgumentNullException(nameof(puttySessionsManager));
_puttySessionsManager = puttySessionsManager;
var path = SettingsFileInfo.SettingsPath;
_localConnectionPropertiesDataProvider = new FileDataProvider(Path.Combine(path, "LocalConnectionProperties.xml"));
_localConnectionPropertiesSerializer = new LocalConnectionPropertiesXmlSerializer();
_puttySessionsManager = puttySessionsManager.ThrowIfNull(nameof(puttySessionsManager));
_import = import.ThrowIfNull(nameof(import));
_dialogWindowParent = dialogWindowParent.ThrowIfNull(nameof(dialogWindowParent));
}
public void NewConnectionsFile(string filename)
@@ -114,18 +113,13 @@ namespace mRemoteNG.Connection
var oldConnectionTreeModel = ConnectionTreeModel;
var oldIsUsingDatabaseValue = UsingDatabase;
var connectionLoader = useDatabase
? (IConnectionsLoader)new SqlConnectionsLoader(_localConnectionPropertiesSerializer, _localConnectionPropertiesDataProvider)
: new XmlConnectionsLoader(connectionFileName);
var newConnectionTreeModel = connectionLoader.Load();
if (useDatabase)
LastSqlUpdate = DateTime.Now;
var newConnectionTreeModel = useDatabase
? new SqlConnectionsLoader(DatabaseConnectorFactory, this).Load()
: new XmlConnectionsLoader(connectionFileName, this, _dialogWindowParent).Load();
if (newConnectionTreeModel == null)
{
DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed", IsConnectionsFileLoaded);
DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed", IsConnectionsFileLoaded, this);
return;
}
@@ -142,7 +136,6 @@ namespace mRemoteNG.Connection
ConnectionTreeModel = newConnectionTreeModel;
UpdateCustomConsPathSetting(connectionFileName);
RaiseConnectionsLoadedEvent(oldConnectionTreeModel, newConnectionTreeModel, oldIsUsingDatabaseValue, useDatabase, connectionFileName);
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Connections loaded using {connectionLoader.GetType().Name}");
}
/// <summary>
@@ -189,17 +182,7 @@ namespace mRemoteNG.Connection
/// <param name="saveFilter"></param>
/// <param name="connectionFileName"></param>
/// <param name="forceSave">Bypasses safety checks that prevent saving if a connection file isn't loaded.</param>
/// <param name="propertyNameTrigger">
/// Optional. The name of the property that triggered
/// this save.
/// </param>
public void SaveConnections(
ConnectionTreeModel connectionTreeModel,
bool useDatabase,
SaveFilter saveFilter,
string connectionFileName,
bool forceSave = false,
string propertyNameTrigger = "")
public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName, bool forceSave = false)
{
if (connectionTreeModel == null)
return;
@@ -219,13 +202,10 @@ namespace mRemoteNG.Connection
RemoteConnectionsSyncronizer?.Disable();
var previouslyUsingDatabase = UsingDatabase;
var saver = useDatabase
? (ISaver<ConnectionTreeModel>)new SqlConnectionsSaver(saveFilter, _localConnectionPropertiesSerializer,
_localConnectionPropertiesDataProvider)
: new XmlConnectionsSaver(connectionFileName, saveFilter);
saver.Save(connectionTreeModel, propertyNameTrigger);
if (useDatabase)
new SqlConnectionsSaver(saveFilter, this, DatabaseConnectorFactory).Save(connectionTreeModel);
else
new XmlConnectionsSaver(connectionFileName, saveFilter).Save(connectionTreeModel);
if (UsingDatabase)
LastSqlUpdate = DateTime.Now;
@@ -245,14 +225,7 @@ namespace mRemoteNG.Connection
}
}
/// <summary>
/// Save the currently loaded connections asynchronously
/// </summary>
/// <param name="propertyNameTrigger">
/// Optional. The name of the property that triggered
/// this save.
/// </param>
public void SaveConnectionsAsync(string propertyNameTrigger = "")
public void SaveConnectionsAsync()
{
if (_batchingSaves)
{
@@ -260,22 +233,170 @@ namespace mRemoteNG.Connection
return;
}
var t = new Thread(() =>
{
lock (SaveLock)
{
SaveConnections(
ConnectionTreeModel,
UsingDatabase,
new SaveFilter(),
ConnectionFileName,
propertyNameTrigger: propertyNameTrigger);
}
});
var t = new Thread(SaveConnectionsBGd);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private void SaveConnectionsBGd()
{
lock (SaveLock)
{
SaveConnections();
}
}
public void LoadConnectionsAsync()
{
_showDialogWhenLoadingConnections = false;
var t = new Thread(LoadConnectionsBGd);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private void LoadConnectionsBGd()
{
LoadConnections(_showDialogWhenLoadingConnections);
}
public void LoadConnections(bool withDialog = false)
{
var connectionFileName = "";
try
{
// disable sql update checking while we are loading updates
RemoteConnectionsSyncronizer?.Disable();
if (!Settings.Default.UseSQLServer)
{
if (withDialog)
{
var loadDialog = DialogFactory.BuildLoadConnectionsDialog();
if (loadDialog.ShowDialog() != DialogResult.OK) return;
connectionFileName = loadDialog.FileName;
}
else
{
connectionFileName = GetStartupConnectionFileName();
}
}
LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
if (Settings.Default.UseSQLServer)
{
LastSqlUpdate = DateTime.Now;
}
else
{
if (connectionFileName == GetDefaultStartupConnectionFileName())
{
Settings.Default.LoadConsFromCustomLocation = false;
}
else
{
Settings.Default.LoadConsFromCustomLocation = true;
Settings.Default.CustomConsPath = connectionFileName;
}
}
// re-enable sql update checking after updates are loaded
RemoteConnectionsSyncronizer?.Enable();
}
catch (Exception ex)
{
if (Settings.Default.UseSQLServer)
{
Runtime.MessageCollector.AddExceptionMessage(Language.strLoadFromSqlFailed, ex);
var commandButtons = string.Join("|", Language.strCommandTryAgain, Language.strCommandOpenConnectionFile, string.Format(Language.strCommandExitProgram, Application.ProductName));
CTaskDialog.ShowCommandBox(Application.ProductName, Language.strLoadFromSqlFailed, Language.strLoadFromSqlFailedContent, MiscTools.GetExceptionMessageRecursive(ex), "", "", commandButtons, false, ESysIcons.Error, ESysIcons.Error);
switch (CTaskDialog.CommandButtonResult)
{
case 0:
LoadConnections(withDialog);
return;
case 1:
Settings.Default.UseSQLServer = false;
LoadConnections(true);
return;
default:
Application.Exit();
return;
}
}
if (ex is FileNotFoundException && !withDialog)
{
Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName), ex, MessageClass.InformationMsg);
string[] commandButtons =
{
Language.ConfigurationCreateNew,
Language.ConfigurationCustomPath,
Language.ConfigurationImportFile,
Language.strMenuExit
};
var answered = false;
while (!answered)
{
try
{
CTaskDialog.ShowTaskDialogBox(
GeneralAppInfo.ProductName,
Language.ConnectionFileNotFound,
"", "", "", "", "",
string.Join(" | ", commandButtons),
ETaskDialogButtons.None,
ESysIcons.Question,
ESysIcons.Question);
switch (CTaskDialog.CommandButtonResult)
{
case 0:
NewConnectionsFile(connectionFileName);
answered = true;
break;
case 1:
LoadConnections(true);
answered = true;
break;
case 2:
NewConnectionsFile(connectionFileName);
_import.ImportFromFile(ConnectionTreeModel.RootNodes[0]);
answered = true;
break;
case 3:
Application.Exit();
answered = true;
break;
}
}
catch (Exception exc)
{
Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName), exc, MessageClass.InformationMsg);
}
}
return;
}
Runtime.MessageCollector.AddExceptionStackTrace(string.Format(Language.strConnectionsFileCouldNotBeLoaded, connectionFileName), ex);
if (connectionFileName != GetStartupConnectionFileName())
{
LoadConnections(withDialog);
}
else
{
MessageBox.Show(_dialogWindowParent,
string.Format(Language.strErrorStartupConnectionFileLoad, Environment.NewLine, Application.ProductName, GetStartupConnectionFileName(), MiscTools.GetExceptionMessageRecursive(ex)),
@"Could not load startup file.", MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.Exit();
}
}
}
public string GetStartupConnectionFileName()
{
return Settings.Default.LoadConsFromCustomLocation == false

View File

@@ -1,12 +1,9 @@
using mRemoteNG.Container;
using System.Collections.Generic;
namespace mRemoteNG.Connection
{
public interface IConnectionInitiator
{
IEnumerable<string> ActiveConnections { get; }
void OpenConnection(ConnectionInfo connectionInfo);
void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None);

View File

@@ -0,0 +1,39 @@
using System;
using System.Security;
using mRemoteNG.Config.Connections;
using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Security;
using mRemoteNG.Tree;
namespace mRemoteNG.Connection
{
public interface IConnectionsService
{
string ConnectionFileName { get; }
ConnectionTreeModel ConnectionTreeModel { get; }
DatabaseConnectorFactory DatabaseConnectorFactory { get; set; }
SecureString EncryptionKey { get; set; }
bool IsConnectionsFileLoaded { get; set; }
DateTime LastSqlUpdate { get; set; }
RemoteConnectionsSyncronizer RemoteConnectionsSyncronizer { get; set; }
bool UsingDatabase { get; }
event EventHandler<ConnectionsLoadedEventArgs> ConnectionsLoaded;
event EventHandler<ConnectionsSavedEventArgs> ConnectionsSaved;
ConnectionInfo CreateQuickConnect(string connectionString, ProtocolType protocol);
string GetDefaultStartupConnectionFileName();
string GetStartupConnectionFileName();
void LoadConnections(bool withDialog = false);
void LoadConnections(bool useDatabase, bool import, string connectionFileName);
void LoadConnectionsAsync();
void NewConnectionsFile(string filename);
void SaveConnections();
void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName, bool forceSave = false);
void SaveConnectionsAsync();
void BeginBatchingSaves();
void EndBatchingSaves();
}
}

View File

@@ -17,12 +17,15 @@ namespace mRemoteNG.Connection.Protocol.ICA
{
private AxICAClient _icaClient;
private ConnectionInfo _info;
private readonly FrmMain _frmMain = FrmMain.Default;
private readonly FrmMain _frmMain;
private readonly IConnectionsService _connectionsService;
#region Public Methods
public IcaProtocol()
public IcaProtocol(FrmMain frmMain, IConnectionsService connectionsService)
{
try
_frmMain = frmMain.ThrowIfNull(nameof(frmMain));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
try
{
Control = new AxICAClient();
}
@@ -144,7 +147,7 @@ namespace mRemoteNG.Connection.Protocol.ICA
if (Settings.Default.DefaultPassword != "")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
_icaClient.SetProp("ClearPassword", cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey));
_icaClient.SetProp("ClearPassword", cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, _connectionsService.EncryptionKey));
}
}
}

View File

@@ -11,19 +11,25 @@ namespace mRemoteNG.Connection.Protocol
{
public class IntegratedProgram : ProtocolBase
{
#region Private Fields
private readonly ExternalToolsService _externalToolsService;
private ExternalTool _externalTool;
private IntPtr _handle;
private Process _process;
#endregion
private readonly IConnectionsService _connectionsService;
#region Public Methods
public IntegratedProgram(ExternalToolsService externalToolsService, IConnectionsService connectionsService)
{
_externalToolsService = externalToolsService.ThrowIfNull(nameof(externalToolsService));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
#region Public Methods
public override bool Initialize()
{
if (InterfaceControl.Info == null)
return base.Initialize();
_externalTool = Runtime.ExternalToolsService.GetExtAppByName(InterfaceControl.Info.ExtApp);
_externalTool = _externalToolsService.GetExtAppByName(InterfaceControl.Info.ExtApp);
if (_externalTool == null)
{
@@ -54,7 +60,7 @@ namespace mRemoteNG.Connection.Protocol
return false;
}
var argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo);
var argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo, _connectionsService);
_process = new Process
{
StartInfo =

View File

@@ -7,11 +7,24 @@ using mRemoteNG.Connection.Protocol.SSH;
using mRemoteNG.Connection.Protocol.Telnet;
using mRemoteNG.Connection.Protocol.VNC;
using System;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms;
namespace mRemoteNG.Connection.Protocol
{
public class ProtocolFactory
{
private readonly ExternalToolsService _externalToolsService;
private readonly FrmMain _frmMain;
private readonly IConnectionsService _connectionsService;
public ProtocolFactory(ExternalToolsService externalToolsService, FrmMain frmMain, IConnectionsService connectionsService)
{
_externalToolsService = externalToolsService.ThrowIfNull(nameof(externalToolsService));
_frmMain = frmMain.ThrowIfNull(nameof(frmMain));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
public ProtocolBase CreateProtocol(ConnectionInfo connectionInfo)
{
var newProtocol = default(ProtocolBase);
@@ -19,7 +32,7 @@ namespace mRemoteNG.Connection.Protocol
switch (connectionInfo.Protocol)
{
case ProtocolType.RDP:
newProtocol = new RdpProtocol
newProtocol = new RdpProtocol(_frmMain, _connectionsService)
{
LoadBalanceInfoUseUtf8 = Settings.Default.RdpLoadBalanceInfoUseUtf8
};
@@ -29,19 +42,19 @@ namespace mRemoteNG.Connection.Protocol
newProtocol = new ProtocolVNC();
break;
case ProtocolType.SSH1:
newProtocol = new ProtocolSSH1();
newProtocol = new ProtocolSSH1(_connectionsService);
break;
case ProtocolType.SSH2:
newProtocol = new ProtocolSSH2();
newProtocol = new ProtocolSSH2(_connectionsService);
break;
case ProtocolType.Telnet:
newProtocol = new ProtocolTelnet();
newProtocol = new ProtocolTelnet(_connectionsService);
break;
case ProtocolType.Rlogin:
newProtocol = new ProtocolRlogin();
newProtocol = new ProtocolRlogin(_connectionsService);
break;
case ProtocolType.RAW:
newProtocol = new RawProtocol();
newProtocol = new RawProtocol(_connectionsService);
break;
case ProtocolType.HTTP:
newProtocol = new ProtocolHTTP(connectionInfo.RenderingEngine);
@@ -50,11 +63,11 @@ namespace mRemoteNG.Connection.Protocol
newProtocol = new ProtocolHTTPS(connectionInfo.RenderingEngine);
break;
case ProtocolType.ICA:
newProtocol = new IcaProtocol();
newProtocol = new IcaProtocol(_frmMain, _connectionsService);
((IcaProtocol) newProtocol).tmrReconnect.Elapsed += ((IcaProtocol) newProtocol).tmrReconnect_Elapsed;
break;
case ProtocolType.IntApp:
newProtocol = new IntegratedProgram();
newProtocol = new IntegratedProgram(_externalToolsService, _connectionsService);
if (connectionInfo.ExtApp == "")
{
throw (new Exception(Language.strNoExtAppDefined));

View File

@@ -16,6 +16,12 @@ namespace mRemoteNG.Connection.Protocol
{
private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID
private bool _isPuttyNg;
private readonly IConnectionsService _connectionsService;
public PuttyBase(IConnectionsService connectionsService)
{
_connectionsService = connectionsService;
}
#region Public Properties
@@ -99,7 +105,7 @@ namespace mRemoteNG.Connection.Protocol
if (Settings.Default.EmptyCredentials == "custom")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, _connectionsService.EncryptionKey);
}
}

View File

@@ -2,7 +2,8 @@ namespace mRemoteNG.Connection.Protocol.RAW
{
public class RawProtocol : PuttyBase
{
public RawProtocol()
public RawProtocol(IConnectionsService connectionsService)
: base(connectionsService)
{
PuttyProtocol = Putty_Protocol.raw;
}

View File

@@ -30,7 +30,8 @@ namespace mRemoteNG.Connection.Protocol.RDP
private bool _loginComplete;
private bool _redirectKeys;
private bool _alertOnIdleDisconnect;
private readonly FrmMain _frmMain = FrmMain.Default;
private readonly FrmMain _frmMain;
private readonly IConnectionsService _connectionsService;
#region Properties
public bool SmartSize
@@ -92,8 +93,10 @@ namespace mRemoteNG.Connection.Protocol.RDP
#endregion
#region Constructors
public RdpProtocol()
public RdpProtocol(FrmMain frmMain, IConnectionsService connectionsService)
{
_frmMain = frmMain;
_connectionsService = connectionsService;
Control = new AxMsRdpClient8NotSafeForScripting();
}
#endregion
@@ -453,7 +456,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
if (Settings.Default.DefaultPassword != "")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
_rdpClient.AdvancedSettings2.ClearTextPassword = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
_rdpClient.AdvancedSettings2.ClearTextPassword = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, _connectionsService.EncryptionKey);
}
}
}
@@ -552,6 +555,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
_rdpClient.AdvancedSettings2.RedirectPrinters = _connectionInfo.RedirectPrinters;
_rdpClient.AdvancedSettings2.RedirectSmartCards = _connectionInfo.RedirectSmartCards;
_rdpClient.SecuredSettings2.AudioRedirectionMode = (int)_connectionInfo.RedirectSound;
_rdpClient.AdvancedSettings.DisableRdpdr = _connectionInfo.RedirectClipboard ? 0 : 1;
}
catch (Exception ex)
{

View File

@@ -3,7 +3,8 @@ namespace mRemoteNG.Connection.Protocol.Rlogin
public class ProtocolRlogin : PuttyBase
{
public ProtocolRlogin()
public ProtocolRlogin(IConnectionsService connectionsService)
: base(connectionsService)
{
this.PuttyProtocol = Putty_Protocol.rlogin;
}

View File

@@ -5,7 +5,7 @@ namespace mRemoteNG.Connection.Protocol.SSH
public class ProtocolSSH1 : PuttyBase
{
public ProtocolSSH1()
public ProtocolSSH1(IConnectionsService connectionsService) : base(connectionsService)
{
this.PuttyProtocol = Putty_Protocol.ssh;
this.PuttySSHVersion = Putty_SSHVersion.ssh1;

View File

@@ -3,7 +3,7 @@ namespace mRemoteNG.Connection.Protocol.SSH
public class ProtocolSSH2 : PuttyBase
{
public ProtocolSSH2()
public ProtocolSSH2(IConnectionsService connectionsService) : base(connectionsService)
{
this.PuttyProtocol = Putty_Protocol.ssh;
this.PuttySSHVersion = Putty_SSHVersion.ssh2;

View File

@@ -3,7 +3,7 @@ namespace mRemoteNG.Connection.Protocol.Serial
public class ProtocolSerial : PuttyBase
{
public ProtocolSerial()
public ProtocolSerial(IConnectionsService connectionsService) : base(connectionsService)
{
this.PuttyProtocol = Putty_Protocol.serial;
}

View File

@@ -3,7 +3,7 @@ namespace mRemoteNG.Connection.Protocol.Telnet
public class ProtocolTelnet : PuttyBase
{
public ProtocolTelnet()
public ProtocolTelnet(IConnectionsService connectionsService) : base(connectionsService)
{
this.PuttyProtocol = Putty_Protocol.telnet;
}

View File

@@ -1,10 +1,18 @@
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection
{
public class WebHelper
{
public static void GoToUrl(string url)
private readonly IConnectionInitiator _connectionInitiator;
public WebHelper(IConnectionInitiator connectionInitiator)
{
_connectionInitiator = connectionInitiator.ThrowIfNull(nameof(connectionInitiator));
}
public void GoToUrl(string url)
{
var connectionInfo = new ConnectionInfo();
connectionInfo.CopyFrom(DefaultConnectionInfo.Instance);
@@ -16,8 +24,7 @@ namespace mRemoteNG.Connection
if (string.IsNullOrEmpty(connectionInfo.Panel))
connectionInfo.Panel = Language.strGeneral;
connectionInfo.IsQuickConnect = true;
var connectionInitiator = new ConnectionInitiator();
connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
_connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
}
}
}

View File

@@ -12,19 +12,13 @@ namespace mRemoteNG.Container
[DefaultProperty("Name")]
public class ContainerInfo : ConnectionInfo, INotifyCollectionChanged
{
private bool _isExpanded;
[Browsable(false)]
[Browsable(false)]
public List<ConnectionInfo> Children { get; } = new List<ConnectionInfo>();
[Category(""), Browsable(false), ReadOnly(false), Bindable(false), DefaultValue(""), DesignOnly(false)]
public bool IsExpanded
{
get => _isExpanded;
set => SetField(ref _isExpanded, value, "IsExpanded");
}
[Category(""), Browsable(false), ReadOnly(false), Bindable(false), DefaultValue(""), DesignOnly(false)]
public bool IsExpanded { get; set; }
[Browsable(false)]
[Browsable(false)]
public override bool IsContainer { get { return true; } set {} }
public ContainerInfo(string uniqueId)

View File

@@ -9,6 +9,8 @@ namespace mRemoteNG.Credential
{
public class CredentialRecordTypeConverter : TypeConverter
{
public static ICredentialRepositoryList CredentialRepositoryList { get; set; }
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(Guid) ||
@@ -34,7 +36,7 @@ namespace mRemoteNG.Credential
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (!(value is Guid)) return base.ConvertFrom(context, culture, value);
var matchedCredentials = Runtime.CredentialProviderCatalog.GetCredentialRecords().Where(record => record.Id.Equals(value)).ToArray();
var matchedCredentials = CredentialRepositoryList.GetCredentialRecords().Where(record => record.Id.Equals(value)).ToArray();
return matchedCredentials.Any() ? matchedCredentials.First() : null;
}
}

View File

@@ -6,11 +6,19 @@ using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.CredentialProviderSerializer;
using mRemoteNG.Config.Serializers.CredentialSerializer;
using mRemoteNG.Security.Factories;
using mRemoteNG.Tools;
namespace mRemoteNG.Credential
{
public class CredentialServiceFactory
{
private ICredentialRepositoryList _credentialRepositoryList;
public CredentialServiceFactory(ICredentialRepositoryList credentialRepositoryList)
{
_credentialRepositoryList = credentialRepositoryList.ThrowIfNull(nameof(credentialRepositoryList));
}
// When we get a true CompositionRoot we can move this to that class. We should only require 1 instance of this service at a time
public CredentialServiceFacade Build()
{
@@ -27,7 +35,7 @@ namespace mRemoteNG.Credential
new CredentialRepositoryListDeserializer(credRepoSerializer, credRepoDeserializer));
var repoListSaver = new CredentialRepositoryListSaver(repoListDataProvider);
return new CredentialServiceFacade(Runtime.CredentialProviderCatalog, repoListLoader, repoListSaver);
return new CredentialServiceFacade(_credentialRepositoryList, repoListLoader, repoListSaver);
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using System.Windows.Forms;
using mRemoteNG.Messages.MessageWriters;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Window;
using WeifenLuo.WinFormsUI.Docking;
@@ -13,13 +14,14 @@ namespace mRemoteNG.Messages.WriterDecorators
private readonly IMessageTypeFilteringOptions _filter;
private readonly IMessageWriter _decoratedWriter;
private readonly ErrorAndInfoWindow _messageWindow;
private readonly FrmMain _frmMain = FrmMain.Default;
private readonly FrmMain _frmMain;
public MessageFocusDecorator(ErrorAndInfoWindow messageWindow, IMessageTypeFilteringOptions filter, IMessageWriter decoratedWriter)
public MessageFocusDecorator(FrmMain frmMain, ErrorAndInfoWindow messageWindow, IMessageTypeFilteringOptions filter, IMessageWriter decoratedWriter)
{
_filter = filter ?? throw new ArgumentNullException(nameof(filter));
_messageWindow = messageWindow ?? throw new ArgumentNullException(nameof(messageWindow));
_decoratedWriter = decoratedWriter ?? throw new ArgumentNullException(nameof(decoratedWriter));
_frmMain = frmMain.ThrowIfNull(nameof(frmMain));
_filter = filter.ThrowIfNull(nameof(filter));
_messageWindow = messageWindow.ThrowIfNull(nameof(messageWindow));
_decoratedWriter = decoratedWriter.ThrowIfNull(nameof(decoratedWriter));
}
public async void Write(IMessage message)
@@ -91,4 +93,4 @@ namespace mRemoteNG.Messages.WriterDecorators
content.DockState == DockState.DockRightAutoHide;
}
}
}
}

View File

@@ -33,5 +33,5 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
// <Assembly: AssemblyVersion("1.0.*")>
[assembly: AssemblyVersion("1.76.12.*")]
[assembly: AssemblyVersion("1.77.0.*")]
[assembly: NeutralResourcesLanguage("en")]

View File

@@ -12,7 +12,11 @@ namespace mRemoteNG {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -563,6 +567,18 @@ namespace mRemoteNG {
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool ConDefaultRedirectClipboard {
get {
return ((bool)(this["ConDefaultRedirectClipboard"]));
}
set {
this["ConDefaultRedirectClipboard"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
@@ -983,6 +999,18 @@ namespace mRemoteNG {
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool InhDefaultRedirectClipboard {
get {
return ((bool)(this["InhDefaultRedirectClipboard"]));
}
set {
this["InhDefaultRedirectClipboard"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]

View File

@@ -137,6 +137,9 @@
<Setting Name="ConDefaultRedirectPrinters" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="ConDefaultRedirectClipboard" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="ConDefaultRedirectPorts" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
@@ -242,6 +245,9 @@
<Setting Name="InhDefaultRedirectPrinters" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="InhDefaultRedirectClipboard" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="InhDefaultRedirectSmartCards" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>

View File

@@ -340,7 +340,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to AdvancedSecurityOptions.
/// Looks up a localized string similar to Advanced security options.
/// </summary>
internal static string strAdvancedSecurityOptions {
get {
@@ -901,7 +901,7 @@ namespace mRemoteNG {
/// <summary>
/// Looks up a localized string similar to For RDP to work properly you need to have at least Remote Desktop Connection (Terminal Services) Client 8.0 installed. You can download it here: http://support.microsoft.com/kb/925876
///If this check still fails or you are unable to use RDP, please consult the mRemoteNG Forum at {0}..
///If this check still fails or you are unable to use RDP, please consult the at {0}..
/// </summary>
internal static string strCcRDPFailed {
get {
@@ -922,7 +922,7 @@ namespace mRemoteNG {
/// <summary>
/// Looks up a localized string similar to VNC requires VncSharp.dll to be located in your mRemoteNG application folder.
///Please make sure that you have the VncSharp.dll file in your mRemoteNG application folder (usually C:\Program Files\mRemoteNG\).
///If you are still not able to pass this check or use VNC in mRemoteNG please consult the mRemoteNG Forum at {0}..
///If you are still not able to pass this check or use VNC in mRemoteNG please consult the at {0}..
/// </summary>
internal static string strCcVNCFailed {
get {
@@ -1094,7 +1094,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Choose Path.
/// Looks up a localized string similar to Choose path.
/// </summary>
internal static string strChoosePath {
get {
@@ -1319,6 +1319,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Are you sure you want to close all connections except for &quot;{0}&quot;?.
/// </summary>
internal static string strConfirmCloseConnectionOthersInstruction {
get {
return ResourceManager.GetString("strConfirmCloseConnectionOthersInstruction", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Are you sure you want to close the panel, &quot;{0}&quot;? Any connections that it contains will also be closed..
/// </summary>
@@ -1328,6 +1337,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Are you sure you want to close all connections to the right of &quot;{0}&quot;?.
/// </summary>
internal static string strConfirmCloseConnectionRightInstruction {
get {
return ResourceManager.GetString("strConfirmCloseConnectionRightInstruction", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Are you sure you want to delete the credential record, {0}?.
/// </summary>
@@ -2679,7 +2697,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Import from .RDP file(s).
/// Looks up a localized string similar to Import from RDP file(s).
/// </summary>
internal static string strImportRDPFiles {
get {
@@ -2976,7 +2994,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Read Only:.
/// Looks up a localized string similar to Read only:.
/// </summary>
internal static string strLabelReadOnly {
get {
@@ -2994,7 +3012,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to seconds.
/// Looks up a localized string similar to Seconds.
/// </summary>
internal static string strLabelSeconds {
get {
@@ -3012,7 +3030,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Server Status:.
/// Looks up a localized string similar to Server status:.
/// </summary>
internal static string strLabelServerStatus {
get {
@@ -3371,6 +3389,24 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Disconnect All But This.
/// </summary>
internal static string strMenuDisconnectOthers {
get {
return ResourceManager.GetString("strMenuDisconnectOthers", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Disconnect Tabs To The Right.
/// </summary>
internal static string strMenuDisconnectOthersRight {
get {
return ResourceManager.GetString("strMenuDisconnectOthersRight", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Donate.
/// </summary>
@@ -3489,7 +3525,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Jump To.
/// Looks up a localized string similar to Jump to.
/// </summary>
internal static string strMenuJumpTo {
get {
@@ -3507,7 +3543,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Lock Toolbar Positions.
/// Looks up a localized string similar to Lock toolbar positions.
/// </summary>
internal static string strMenuLockToolbars {
get {
@@ -3516,7 +3552,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Multi SSH Toolbar.
/// Looks up a localized string similar to Multi SSH toolbar.
/// </summary>
internal static string strMenuMultiSshToolbar {
get {
@@ -4002,7 +4038,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to No Compression.
/// Looks up a localized string similar to No сompression.
/// </summary>
internal static string strNoCompression {
get {
@@ -4047,7 +4083,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to No Ext. App specified..
/// Looks up a localized string similar to No ext. app specified..
/// </summary>
internal static string strNoExtAppDefined {
get {
@@ -4120,7 +4156,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Open File.
/// Looks up a localized string similar to Open file.
/// </summary>
internal static string strOpenFile {
get {
@@ -4192,7 +4228,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Next Tab.
/// Looks up a localized string similar to Next tab.
/// </summary>
internal static string strOptionsKeyboardCommandsNextTab {
get {
@@ -4201,7 +4237,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Previous Tab.
/// Looks up a localized string similar to Previous tab.
/// </summary>
internal static string strOptionsKeyboardCommandsPreviousTab {
get {
@@ -4210,7 +4246,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Modify Shortcut.
/// Looks up a localized string similar to Modify shortcut.
/// </summary>
internal static string strOptionsKeyboardGroupModifyShortcut {
get {
@@ -4219,7 +4255,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Keyboard Shortcuts.
/// Looks up a localized string similar to Keyboard shortcuts.
/// </summary>
internal static string strOptionsKeyboardLabelKeyboardShortcuts {
get {
@@ -4291,7 +4327,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Enable Themes.
/// Looks up a localized string similar to Enable themes.
/// </summary>
internal static string strOptionsThemeEnableTheming {
get {
@@ -4300,7 +4336,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to No themes are loaded, check that the default mremoteNG themes exist in the &apos;themes&apos; folder.
/// Looks up a localized string similar to No themes are loaded, check that the default mRemoteNG themes exist in the &apos;themes&apos; folder.
/// </summary>
internal static string strOptionsThemeErrorNoThemes {
get {
@@ -5011,7 +5047,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Authentication Mode.
/// Looks up a localized string similar to Authentication mode.
/// </summary>
internal static string strPropertyNameAuthenticationMode {
get {
@@ -5020,7 +5056,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Automatic Resize.
/// Looks up a localized string similar to Automatic resize.
/// </summary>
internal static string strPropertyNameAutomaticResize {
get {
@@ -5290,7 +5326,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Alert on Idle Disconnect.
/// Looks up a localized string similar to Alert on Idle disconnect.
/// </summary>
internal static string strPropertyNameRDPAlertIdleTimeout {
get {
@@ -5389,7 +5425,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Sound Quality.
/// Looks up a localized string similar to Sound quality.
/// </summary>
internal static string strPropertyNameSoundQuality {
get {
@@ -7490,7 +7526,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Use Default.
/// Looks up a localized string similar to Use default.
/// </summary>
internal static string strUseDefault {
get {
@@ -7697,7 +7733,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to Test Connection.
/// Looks up a localized string similar to Test connection.
/// </summary>
internal static string TestConnection {
get {

View File

@@ -2569,4 +2569,241 @@ Wählen Sie einen Pfad für die mRemoteNG-Protokolldatei</value>
<data name="LoadBalanceInfoUseUtf8" xml:space="preserve">
<value>Verwenden Sie die UTF8-Codierung für die RDP-Eigenschaft "Load Balance Info"</value>
</data>
<data name="strConnectNoCredentials" xml:space="preserve">
<value>Ohne Anmeldedaten verbinden</value>
</data>
<data name="strExportEverything" xml:space="preserve">
<value>Alles exportieren</value>
</data>
<data name="strExportFile" xml:space="preserve">
<value>Datei exportieren</value>
</data>
<data name="strExportProperties" xml:space="preserve">
<value>Eigenschaften exportieren</value>
</data>
<data name="strExportSelectedConnection" xml:space="preserve">
<value>Die Aktuell gewählte Verbindung exportieren</value>
</data>
<data name="strExportSelectedFolder" xml:space="preserve">
<value>Den Aktuell gewählten Ordner exportieren</value>
</data>
<data name="strFilterAllImportable" xml:space="preserve">
<value>Alle wichtigen Dateien</value>
</data>
<data name="strImportFileFailedMainInstruction" xml:space="preserve">
<value>Import-Vorgang fehlgeschlagen</value>
</data>
<data name="strImportLocationContent" xml:space="preserve">
<value>Wo sollen die importierten Elemente abgelegt werden?</value>
</data>
<data name="strLoadFromSqlFailedContent" xml:space="preserve">
<value>Die Verbindungsinformationen konnten nicht vom SQL-Server geladen werden.</value>
</data>
<data name="strOptionsProxyTesting" xml:space="preserve">
<value>Testen...</value>
</data>
<data name="strOptionsTabKeyboard" xml:space="preserve">
<value>Tastatur</value>
</data>
<data name="strOptionsKeyboardLabelKeyboardShortcuts" xml:space="preserve">
<value>Tastenkombinationen</value>
</data>
<data name="strOptionsKeyboardGroupModifyShortcut" xml:space="preserve">
<value>Hotkeys ändern</value>
</data>
<data name="strOptionsKeyboardCommandsPreviousTab" xml:space="preserve">
<value>Vorheriger Tab</value>
</data>
<data name="strOptionsKeyboardCommandsNextTab" xml:space="preserve">
<value>Nächster Tab</value>
</data>
<data name="strUpdateCheckFailedLabel" xml:space="preserve">
<value>Prüfung fehlgeschlagen</value>
</data>
<data name="strUpdateCheckingLabel" xml:space="preserve">
<value>Nach Updates suchen...</value>
</data>
<data name="strPasswordStatusTooShort" xml:space="preserve">
<value>Das Passwort muss mindestens 3 Zeichen lang sein.</value>
</data>
<data name="strPasswordStatusMustMatch" xml:space="preserve">
<value>Die beide Passwörter müssen übereinstimmen.</value>
</data>
<data name="strPortScanComplete" xml:space="preserve">
<value>Port-Scan abgeschlossen.</value>
</data>
<data name="strTitlePasswordWithName" xml:space="preserve">
<value>Passwort für {0}</value>
</data>
<data name="strShowOnToolbar" xml:space="preserve">
<value>In der Symbolleiste anzeigen</value>
</data>
<data name="strTabSecurity" xml:space="preserve">
<value>Sicherheit</value>
</data>
<data name="strBack" xml:space="preserve">
<value>Zurück</value>
</data>
<data name="strDontConnectToConsoleSessionMenuItem" xml:space="preserve">
<value>Keine Verbindung zur Konsolensitzung herstellen</value>
</data>
<data name="strPuttySessionSettings" xml:space="preserve">
<value>PuTTY Sitzungseinstellungen</value>
</data>
<data name="strPropertyNameLoadBalanceInfo" xml:space="preserve">
<value>Lastausgleichsinfo</value>
</data>
<data name="strUpdateGetChangeLogFailed" xml:space="preserve">
<value>Der Changelog konnte nicht heruntergeladen werden.</value>
</data>
<data name="strRDPSoundQualityHigh" xml:space="preserve">
<value>Hoch</value>
</data>
<data name="strRDPSoundQualityMedium" xml:space="preserve">
<value>Mittel</value>
</data>
<data name="strAccept" xml:space="preserve">
<value>Akzeptieren</value>
</data>
<data name="strAdd" xml:space="preserve">
<value>Hinzufügen</value>
</data>
<data name="strCredentialEditor" xml:space="preserve">
<value>Anmeldeinformationen Editor</value>
</data>
<data name="strCredentialManager" xml:space="preserve">
<value>Anmeldeinformationen Manager</value>
</data>
<data name="strRemove" xml:space="preserve">
<value>Entfernen</value>
</data>
<data name="strTitle" xml:space="preserve">
<value>Titel</value>
</data>
<data name="strPropertyDescriptionCredential" xml:space="preserve">
<value>Wählen Sie aus, welche Anmeldeinformationen für diese Verbindung verwendet werden sollen.</value>
</data>
<data name="strLogFilePath" xml:space="preserve">
<value>Pfad der Protokolldatei</value>
</data>
<data name="strChoosePath" xml:space="preserve">
<value>Pfad auswählen</value>
</data>
<data name="strOpenFile" xml:space="preserve">
<value>Datei öffnen</value>
</data>
<data name="strUseDefault" xml:space="preserve">
<value>Standard verwenden</value>
</data>
<data name="strLogging" xml:space="preserve">
<value>Protokollierung</value>
</data>
<data name="strPopups" xml:space="preserve">
<value>Pop-ups</value>
</data>
<data name="strHttpsInsecureAllowAlways" xml:space="preserve">
<value>Immer zulassen</value>
</data>
<data name="strHttpsInsecureAllowOnce" xml:space="preserve">
<value>Einmal zulassen</value>
</data>
<data name="strHttpsInsecureDontAllow" xml:space="preserve">
<value>Nicht erlauben</value>
</data>
<data name="strHttpsInsecurePromptTitle" xml:space="preserve">
<value>Unsicheres Zertifikat zulassen?</value>
</data>
<data name="TestingConnection" xml:space="preserve">
<value>Verbindung testen</value>
</data>
<data name="IncorrectPassword" xml:space="preserve">
<value>Falsches Passwort</value>
</data>
<data name="Source" xml:space="preserve">
<value>Quelle</value>
</data>
<data name="Unlocking" xml:space="preserve">
<value>Freischalten</value>
</data>
<data name="Unlock" xml:space="preserve">
<value>Freischalten</value>
</data>
<data name="strFAMFAMFAMAttributionURL" xml:space="preserve">
<value>http://www.famfamfam.com/</value>
</data>
<data name="strExportItems" xml:space="preserve">
<value>Element exportieren</value>
</data>
<data name="strErrorCouldNotLaunchPutty" xml:space="preserve">
<value>PuTTY konnte nicht gestartet werden.</value>
</data>
<data name="strExternalToolDefaultName" xml:space="preserve">
<value>Neues externes Werkzeug</value>
</data>
<data name="strHttp" xml:space="preserve">
<value>HTTP</value>
</data>
<data name="strHttpGecko" xml:space="preserve">
<value>Gecko (Firefox)</value>
</data>
<data name="strHttpInternetExplorer" xml:space="preserve">
<value>Internet Explorer</value>
</data>
<data name="strHttps" xml:space="preserve">
<value>HTTPS</value>
</data>
<data name="strICA" xml:space="preserve">
<value>ICA</value>
</data>
<data name="strImportFileFailedContent" xml:space="preserve">
<value>Beim Importieren der Datei ist ein Fehler aufgetreten ("{0}").</value>
</data>
<data name="strOptionsKeyboardCommandsGroupTabs" xml:space="preserve">
<value>Tabs</value>
</data>
<data name="strPropertyNameAutomaticResize" xml:space="preserve">
<value>Automatische Größenänderung</value>
</data>
<data name="strWeifenLuoAttributionURL" xml:space="preserve">
<value>http://sourceforge.net/projects/dockpanelsuite/</value>
</data>
<data name="strRDPOverallConnectionTimeout" xml:space="preserve">
<value>RDP-Verbindungs-Timeout</value>
</data>
<data name="strNodeAlreadyInFolder" xml:space="preserve">
<value>Dieser Knoten befindet sich bereits in diesem Ordner.</value>
</data>
<data name="strNodeCannotDragOnSelf" xml:space="preserve">
<value>Der Knoten kann nicht auf sich selbst gezogen werden.</value>
</data>
<data name="strNodeCannotDragParentOnChild" xml:space="preserve">
<value>Der übergeordnete Knoten kann nicht auf den untergeordneten Knoten gezogen werden.</value>
</data>
<data name="strNodeNotDraggable" xml:space="preserve">
<value>Dieser Knoten ist nicht verschiebbar.</value>
</data>
<data name="strUpdatePortableDownloadComplete" xml:space="preserve">
<value>Download abgeschlossen!</value>
</data>
<data name="strDownloadPortable" xml:space="preserve">
<value>Download</value>
</data>
<data name="strID" xml:space="preserve">
<value>ID</value>
</data>
<data name="strPropertyNameSoundQuality" xml:space="preserve">
<value>Klangqualität</value>
</data>
<data name="TestConnection" xml:space="preserve">
<value>Verbindung testen</value>
</data>
<data name="ConfigurationFileNotFound" xml:space="preserve">
<value>Die Konfigurationsdatei fehlt.</value>
</data>
<data name="DatabaseNotAvailable" xml:space="preserve">
<value>Datenbank '{0}' ist nicht verfügbar.</value>
</data>
<data name="SaveConnectionsAfterEveryEdit" xml:space="preserve">
<value>Verbindungen nach jeder Bearbeitung speichern</value>
</data>
</root>

View File

@@ -372,7 +372,7 @@ Versión de Control {0} de VncSharp</value>
<value>Esperar a Salir</value>
</data>
<data name="strCheckForUpdate" xml:space="preserve">
<value>Comporbar de nuevo</value>
<value>Comprobar de nuevo</value>
</data>
<data name="strCheckForUpdatesOnStartup" xml:space="preserve">
<value>Comprobar actualizaciones y novedades en el arranque</value>
@@ -444,11 +444,11 @@ Versión de Control {0} de VncSharp</value>
<value>Error al Cargar la Interfaz de Configuración de Usuario</value>
</data>
<data name="strConfirmCloseConnectionMainInstruction" xml:space="preserve">
<value>Desea cerrar la conexión:
<value>¿Desea cerrar la conexión:
"{0}"?</value>
</data>
<data name="strConfirmCloseConnectionPanelMainInstruction" xml:space="preserve">
<value>Está seguro de querer cerrar el panel, "{0}"? Cualquier conexión que contenga será también cerrada.</value>
<value>¿Está seguro de querer cerrar el panel, "{0}"? Cualquier conexión que contenga el panel también será cerrada.</value>
</data>
<data name="strConfirmDeleteExternalTool" xml:space="preserve">
<value>¿Está seguro de querer borrar la herramienta externa, "{0}"?</value>
@@ -507,7 +507,7 @@ Descripción del Error: {1}</value>
<value>Conexiones</value>
</data>
<data name="strConnectionSetDefaultPortFailed" xml:space="preserve">
<value>No se pudo definir el puerto por defecto!</value>
<value>¡No se pudo definir el puerto por defecto!</value>
</data>
<data name="strConnectionsFileBackupFailed" xml:space="preserve">
<value>¡No pudo crearse copia de seguridad del archivo de conexiones!</value>
@@ -1295,6 +1295,9 @@ Ver el articulo de soporte de Microsoft en http://support.microsoft.com/kb/81183
<data name="strPropertyDescriptionRedirectPrinters" xml:space="preserve">
<value>Seleccione si las impresoras locales deben ser mostradas en el host remoto.</value>
</data>
<data name="strPropertyDescriptionRedirectClipboard" xml:space="preserve">
<value>Seleccione si el portapapeles debe compartirse con el host remoto.</value>
</data>
<data name="strPropertyDescriptionRedirectSmartCards" xml:space="preserve">
<value>Seleccione si las tarjetas inteligentes deben presentarse a la máquina remota.</value>
</data>
@@ -1445,6 +1448,9 @@ Ver el articulo de soporte de Microsoft en http://support.microsoft.com/kb/81183
<data name="strPropertyNameRedirectPrinters" xml:space="preserve">
<value>Impresoras</value>
</data>
<data name="strPropertyNameRedirectClipboard" xml:space="preserve">
<value>Portapapeles</value>
</data>
<data name="strPropertyNameRedirectSmartCards" xml:space="preserve">
<value>Tarjetas Inteligentes</value>
</data>
@@ -1652,7 +1658,7 @@ Mensaje:
<value>Ajustar al panel</value>
</data>
<data name="strRdpFocusFailed" xml:space="preserve">
<value>!RDP Focus fallido!</value>
<value>¡RDP Focus fallido!</value>
</data>
<data name="strRdpGatewayIsSupported" xml:space="preserve">
<value>RD Gateway soportado.</value>
@@ -1694,10 +1700,10 @@ Mensaje:
<value>¡RDP Asignación de Propiedades fallida!</value>
</data>
<data name="strRdpSetRedirectionFailed" xml:space="preserve">
<value>¡Rdp Asignación de Redirección fallida!</value>
<value>¡RDP Asignación de Redirección fallida!</value>
</data>
<data name="strRdpSetRedirectKeysFailed" xml:space="preserve">
<value>¡Rdp Asignación de Claves de Redirección fallida!</value>
<value>¡RDP Asignación de Claves de Redirección fallida!</value>
</data>
<data name="strRdpSetResolutionFailed" xml:space="preserve">
<value>¡RDP Asignación de Resolución fallida!</value>
@@ -1838,7 +1844,7 @@ Mensaje:
<value>SSH versión 2</value>
</data>
<data name="strSSHStartTransferBG" xml:space="preserve">
<value>¡Tranferencia SSH en background fallida!</value>
<value>¡Tranferencia SSH en segundo plano fallida!</value>
</data>
<data name="strSSHTranferSuccessful" xml:space="preserve">
<value>¡Transferencia Correcta!</value>
@@ -2069,4 +2075,4 @@ mRemoteNG ahora se cerrará y comenzará la instalación.</value>
<data name="strYes" xml:space="preserve">
<value>Sí</value>
</data>
</root>
</root>

View File

@@ -293,7 +293,7 @@ Please use File - Open Connection File for normal connection files!</value>
<value>The (RDP) Sessions feature requires that you have a copy of eolwtscom.dll registered on your system.
mRemoteNG ships with this component but it is not registered automatically if you do not use the mRemoteNG Installer.
To register it manually, run the following command from an elevated command prompt: regsvr32 "C:\Program Files\mRemoteNG\eolwtscom.dll" (where C:\Program Files\mRemoteNG\ is the path to your mRemoteNG installation).
If this check still fails or you are unable to use the (RDP) Sessions feature, please consult the mRemoteNG Forum at {0}.</value>
If this check still fails or you are unable to use the (RDP) Sessions feature, please consult the at {0}.</value>
</data>
<data name="strCcEOLOK" xml:space="preserve">
<value>EOLWTSCOM was found and seems to be registered properly.</value>
@@ -302,7 +302,7 @@ If this check still fails or you are unable to use the (RDP) Sessions feature, p
<value>To use the Gecko Rendering Engine you need to have XULrunner 1.8.1.x and the path to the installation set in your Options.
You can download XULrunner 1.8.1.3 here: ftp://ftp.mozilla.org/pub/xulrunner/releases/1.8.1.3/contrib/win32/
When you are finished downloading extract the package to a path of your choice. Then in mRemoteNG go to Tools - Options - Advanced and enter the correct path in the XULrunner path field.
If you are still not able to pass this check or use the Gecko Engine in mRemoteNG please consult the mRemoteNG Forum at {0}.</value>
If you are still not able to pass this check or use the Gecko Engine in mRemoteNG please consult the at {0}.</value>
</data>
<data name="strCcGeckoOK" xml:space="preserve">
<value>GeckoFx was found and seems to be installed properly.</value>
@@ -311,7 +311,7 @@ If you are still not able to pass this check or use the Gecko Engine in mRemoteN
<value>ICA requires that the XenDesktop Online Plugin is installed and that the wfica.ocx library is registered. You can download the client here: http://www.citrix.com/download/
If you have the XenDesktop Online Plugin installed and the check still fails, try to register wfica.ocx manually.
To do this open up the run dialog (Start - Run) and enter the following: regsvr32 "c:\Program Files\Citrix\ICA Client\wfica.ocx" (Where c:\Program Files\Citrix\ICA Client\ is the path to your XenDesktop Online Plugin installation).
If you are still not able to pass this check or use ICA in mRemoteNG please consult the mRemoteNG Forum at {0}.</value>
If you are still not able to pass this check or use ICA in mRemoteNG please consult the at {0}.</value>
</data>
<data name="strCcICAOK" xml:space="preserve">
<value>All ICA components were found and seem to be registered properly.
@@ -329,7 +329,7 @@ Please make sure that either you have the Putty.exe in your mRemoteNG directory
</data>
<data name="strCcRDPFailed" xml:space="preserve">
<value>For RDP to work properly you need to have at least Remote Desktop Connection (Terminal Services) Client 8.0 installed. You can download it here: http://support.microsoft.com/kb/925876
If this check still fails or you are unable to use RDP, please consult the mRemoteNG Forum at {0}.</value>
If this check still fails or you are unable to use RDP, please consult the at {0}.</value>
</data>
<data name="strCcRDPOK" xml:space="preserve">
<value>All RDP components were found and seem to be registered properly.
@@ -338,7 +338,7 @@ Remote Desktop Connection Control Version {0}</value>
<data name="strCcVNCFailed" xml:space="preserve">
<value>VNC requires VncSharp.dll to be located in your mRemoteNG application folder.
Please make sure that you have the VncSharp.dll file in your mRemoteNG application folder (usually C:\Program Files\mRemoteNG\).
If you are still not able to pass this check or use VNC in mRemoteNG please consult the mRemoteNG Forum at {0}.</value>
If you are still not able to pass this check or use VNC in mRemoteNG please consult the at {0}.</value>
</data>
<data name="strCcVNCOK" xml:space="preserve">
<value>All VNC components were found and seem to be registered properly.
@@ -863,7 +863,7 @@ See the Microsoft Support article at http://support.microsoft.com/kb/811833 for
<value>Import from Port Scan</value>
</data>
<data name="strImportRDPFiles" xml:space="preserve">
<value>Import from .RDP file(s)</value>
<value>Import from RDP file(s)</value>
</data>
<data name="strInactive" xml:space="preserve">
<value>Inactive</value>
@@ -959,13 +959,13 @@ See the Microsoft Support article at http://support.microsoft.com/kb/811833 for
<value>Released under the GNU General Public License (GPL)</value>
</data>
<data name="strLabelSeconds" xml:space="preserve">
<value>seconds</value>
<value>Seconds</value>
</data>
<data name="strLabelSelectPanel" xml:space="preserve">
<value>Select a panel from the list below or click New to add a new one. Click OK to continue.</value>
</data>
<data name="strLabelServerStatus" xml:space="preserve">
<value>Server Status:</value>
<value>Server status:</value>
</data>
<data name="strLabelSQLDatabaseName" xml:space="preserve">
<value>Database:</value>
@@ -1106,7 +1106,7 @@ See the Microsoft Support article at http://support.microsoft.com/kb/811833 for
<value>mRemoteNG Help</value>
</data>
<data name="strMenuJumpTo" xml:space="preserve">
<value>Jump To</value>
<value>Jump to</value>
</data>
<data name="strMenuLaunchExternalTool" xml:space="preserve">
<value>Launch External Tool</value>
@@ -1265,10 +1265,10 @@ See the Microsoft Support article at http://support.microsoft.com/kb/811833 for
<value>No</value>
</data>
<data name="strNoCompression" xml:space="preserve">
<value>No Compression</value>
<value>No сompression</value>
</data>
<data name="strNoExtAppDefined" xml:space="preserve">
<value>No Ext. App specified.</value>
<value>No ext. app specified.</value>
</data>
<data name="strNoInformation" xml:space="preserve">
<value>None</value>
@@ -1311,16 +1311,16 @@ If you run into such an error, please create a new connection file!</value>
<value>Tabs</value>
</data>
<data name="strOptionsKeyboardCommandsNextTab" xml:space="preserve">
<value>Next Tab</value>
<value>Next tab</value>
</data>
<data name="strOptionsKeyboardCommandsPreviousTab" xml:space="preserve">
<value>Previous Tab</value>
<value>Previous tab</value>
</data>
<data name="strOptionsKeyboardGroupModifyShortcut" xml:space="preserve">
<value>Modify Shortcut</value>
<value>Modify shortcut</value>
</data>
<data name="strOptionsKeyboardLabelKeyboardShortcuts" xml:space="preserve">
<value>Keyboard Shortcuts</value>
<value>Keyboard shortcuts</value>
</data>
<data name="strOptionsProxyTesting" xml:space="preserve">
<value>Testing...</value>
@@ -1472,6 +1472,9 @@ If you run into such an error, please create a new connection file!</value>
<data name="strPropertyDescriptionRedirectPrinters" xml:space="preserve">
<value>Select whether local printers should be shown on the remote host.</value>
</data>
<data name="strPropertyDescriptionRedirecClipboard" xml:space="preserve">
<value>Select whether clipboard should be shared.</value>
</data>
<data name="strPropertyDescriptionRedirectSmartCards" xml:space="preserve">
<value>Select whether local smart cards should be available on the remote host.</value>
</data>
@@ -1527,10 +1530,10 @@ If you run into such an error, please create a new connection file!</value>
<value>Server Authentication</value>
</data>
<data name="strPropertyNameAuthenticationMode" xml:space="preserve">
<value>Authentication Mode</value>
<value>Authentication mode</value>
</data>
<data name="strPropertyNameAutomaticResize" xml:space="preserve">
<value>Automatic Resize</value>
<value>Automatic resize</value>
</data>
<data name="strPropertyNameCacheBitmaps" xml:space="preserve">
<value>Cache Bitmaps</value>
@@ -1631,6 +1634,9 @@ If you run into such an error, please create a new connection file!</value>
<data name="strPropertyNameRedirectPrinters" xml:space="preserve">
<value>Printers</value>
</data>
<data name="strPropertyNameRedirectClipboard" xml:space="preserve">
<value>Clipboard</value>
</data>
<data name="strPropertyNameRedirectSmartCards" xml:space="preserve">
<value>Smart Cards</value>
</data>
@@ -2401,7 +2407,7 @@ mRemoteNG will now quit and begin with the installation.</value>
<value>Choose the Sound Quality provided by the protocol: Dynamic, Medium, High</value>
</data>
<data name="strPropertyNameSoundQuality" xml:space="preserve">
<value>Sound Quality</value>
<value>Sound quality</value>
</data>
<data name="strUpdatePortableDownloadComplete" xml:space="preserve">
<value>Download Completed!</value>
@@ -2449,7 +2455,7 @@ mRemoteNG will now quit and begin with the installation.</value>
<value>Select whether to receive an alert after the RDP session disconnects due to inactivity</value>
</data>
<data name="strPropertyNameRDPAlertIdleTimeout" xml:space="preserve">
<value>Alert on Idle Disconnect</value>
<value>Alert on Idle disconnect</value>
</data>
<data name="strPasswordConstainsSpecialCharactersConstraintHint" xml:space="preserve">
<value>Password must contain at least {0} of the following characters: {1}</value>
@@ -2482,13 +2488,13 @@ mRemoteNG will now quit and begin with the installation.</value>
<value>Log these message types</value>
</data>
<data name="strChoosePath" xml:space="preserve">
<value>Choose Path</value>
<value>Choose path</value>
</data>
<data name="strOpenFile" xml:space="preserve">
<value>Open File</value>
<value>Open file</value>
</data>
<data name="strUseDefault" xml:space="preserve">
<value>Use Default</value>
<value>Use default</value>
</data>
<data name="strLogging" xml:space="preserve">
<value>Logging</value>
@@ -2569,7 +2575,7 @@ This page will walk you through the process of upgrading your connections file o
<value>Do you really want to delete the theme?</value>
</data>
<data name="strOptionsThemeEnableTheming" xml:space="preserve">
<value>Enable Themes</value>
<value>Enable themes</value>
</data>
<data name="strOptionsThemeNewThemeCaption" xml:space="preserve">
<value>New theme name</value>
@@ -2584,7 +2590,7 @@ This page will walk you through the process of upgrading your connections file o
<value>Warning: Restart is required to disable the themes or to completely apply a new one</value>
</data>
<data name="strOptionsThemeErrorNoThemes" xml:space="preserve">
<value>No themes are loaded, check that the default mremoteNG themes exist in the 'themes' folder</value>
<value>No themes are loaded, check that the default mRemoteNG themes exist in the 'themes' folder</value>
</data>
<data name="CouldNotFindExternalTool" xml:space="preserve">
<value>Could not find external tool with name "{0}"</value>
@@ -2623,10 +2629,10 @@ This page will walk you through the process of upgrading your connections file o
<value>Filter search matches in connection tree</value>
</data>
<data name="TestConnection" xml:space="preserve">
<value>Test Connection</value>
<value>Test connection</value>
</data>
<data name="strLabelReadOnly" xml:space="preserve">
<value>Read Only:</value>
<value>Read only:</value>
</data>
<data name="LoadBalanceInfoUseUtf8" xml:space="preserve">
<value>Use UTF8 encoding for RDP "Load Balance Info" property</value>
@@ -2662,13 +2668,13 @@ This page will walk you through the process of upgrading your connections file o
<value>Import sub OUs</value>
</data>
<data name="strMenuLockToolbars" xml:space="preserve">
<value>Lock Toolbar Positions</value>
<value>Lock toolbar positions</value>
</data>
<data name="strMenuMultiSshToolbar" xml:space="preserve">
<value>Multi SSH Toolbar</value>
<value>Multi SSH toolbar</value>
</data>
<data name="strAdvancedSecurityOptions" xml:space="preserve">
<value>AdvancedSecurityOptions</value>
<value>Advanced security options</value>
</data>
<data name="strOptionsPageTitle" xml:space="preserve">
<value>mRemoteNG Options</value>
@@ -2694,6 +2700,18 @@ This page will walk you through the process of upgrading your connections file o
<data name="strUltraVNCSingleClick" xml:space="preserve">
<value>UltraVNC SingleClick</value>
</data>
<data name="strMenuDisconnectOthersRight" xml:space="preserve">
<value>Disconnect Tabs To The Right</value>
</data>
<data name="strMenuDisconnectOthers" xml:space="preserve">
<value>Disconnect All But This</value>
</data>
<data name="strConfirmCloseConnectionOthersInstruction" xml:space="preserve">
<value>Are you sure you want to close all connections except for "{0}"?</value>
</data>
<data name="strConfirmCloseConnectionRightInstruction" xml:space="preserve">
<value>Are you sure you want to close all connections to the right of "{0}"?</value>
</data>
<data name="AutomaticReconnectError" xml:space="preserve">
<value>An error occurred while trying to reconnect to RDP host '{0}'</value>
</data>

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
@@ -59,7 +59,7 @@
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
<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>
@@ -105,17 +105,17 @@
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<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=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="strAbout" xml:space="preserve">
<value>关于</value>
@@ -123,6 +123,9 @@
<data name="strActive" xml:space="preserve">
<value>活动连接</value>
</data>
<data name="strActiveDirectory" xml:space="preserve">
<value>活动目录</value>
</data>
<data name="strActivity" xml:space="preserve">
<value>活动</value>
</data>
@@ -216,6 +219,9 @@
<data name="strButtonInheritance" xml:space="preserve">
<value>继承</value>
</data>
<data name="strButtonLaunch" xml:space="preserve">
<value>启动(&amp;L)</value>
</data>
<data name="strButtonLaunchPutty" xml:space="preserve">
<value>启动PuTTY</value>
</data>
@@ -409,9 +415,18 @@ VncSharp 版本 {0}</value>
<data name="strColumnWaitForExit" xml:space="preserve">
<value>等待退出</value>
</data>
<data name="strCommandExitProgram" xml:space="preserve">
<value>退出{0}(&amp;X)</value>
</data>
<data name="strCommandLineArgsCouldNotBeParsed" xml:space="preserve">
<value>无法解析命令行参数!</value>
</data>
<data name="strCommandOpenConnectionFile" xml:space="preserve">
<value>打开一个连接文件(&amp;O)</value>
</data>
<data name="strCommandTryAgain" xml:space="preserve">
<value>再试一次(&amp;T)</value>
</data>
<data name="strCompatibilityLenovoAutoScrollUtilityDetected" xml:space="preserve">
<value>{0} 检测到联想Auto Scroll程序在本机上运行。该程序程序明确会导致问题 {0} 的出现。建议您禁用或卸载该程序。</value>
</data>
@@ -559,6 +574,9 @@ VncSharp 版本 {0}</value>
<data name="strDetect" xml:space="preserve">
<value>检测</value>
</data>
<data name="strDontConnectToConsoleSessionMenuItem" xml:space="preserve">
<value>不要连接到控制台会话</value>
</data>
<data name="strDontConnectWhenAuthFails" xml:space="preserve">
<value>身份验证失败时取消连接</value>
</data>
@@ -583,6 +601,12 @@ VncSharp 版本 {0}</value>
<data name="strEnc128BitLogonOnly" xml:space="preserve">
<value>128位(仅用于登录)</value>
</data>
<data name="strEnc40Bit" xml:space="preserve">
<value>40位</value>
</data>
<data name="strEnc56Bit" xml:space="preserve">
<value>56位</value>
</data>
<data name="strEncBasic" xml:space="preserve">
<value>基本</value>
</data>
@@ -613,6 +637,9 @@ VncSharp 版本 {0}</value>
<data name="strErrorConnectionListSaveFailed" xml:space="preserve">
<value>无法保存连接列表。</value>
</data>
<data name="strErrorCouldNotLaunchPutty" xml:space="preserve">
<value>PuTTY无法启动。</value>
</data>
<data name="strErrorDecryptionFailed" xml:space="preserve">
<value>解密失败。{0}</value>
</data>
@@ -642,18 +669,48 @@ VncSharp 版本 {0}</value>
<data name="strExport" xml:space="preserve">
<value>导出</value>
</data>
<data name="strExportEverything" xml:space="preserve">
<value>导出所有内容</value>
</data>
<data name="strExportFile" xml:space="preserve">
<value>导出文件</value>
</data>
<data name="strExportItems" xml:space="preserve">
<value>导出项目</value>
</data>
<data name="strExportmRemoteXML" xml:space="preserve">
<value>导出mRemote/mRemoteNG XML</value>
</data>
<data name="strExportProperties" xml:space="preserve">
<value>导出属性</value>
</data>
<data name="strExportSelectedConnection" xml:space="preserve">
<value>导出当前选定的连接</value>
</data>
<data name="strExportSelectedFolder" xml:space="preserve">
<value>导出当前选定的文件夹</value>
</data>
<data name="strExportToFileMenuItem" xml:space="preserve">
<value>导出到文件(&amp;E)...</value>
</data>
<data name="strExtApp" xml:space="preserve">
<value>外部应用</value>
</data>
<data name="strExternalToolDefaultName" xml:space="preserve">
<value>新建外部工具</value>
</data>
<data name="strFAMFAMFAMAttribution" xml:space="preserve">
<value>内置图标由[FAMFAMFAM]制作</value>
</data>
<data name="strFileFormatLabel" xml:space="preserve">
<value>文件格式(&amp;F):</value>
</data>
<data name="strFilterAll" xml:space="preserve">
<value>所有文件(*.*)</value>
</data>
<data name="strFilterAllImportable" xml:space="preserve">
<value>所有可导入的文件</value>
</data>
<data name="strFilterApplication" xml:space="preserve">
<value>应用程序(*.exe)</value>
</data>
@@ -663,11 +720,17 @@ VncSharp 版本 {0}</value>
<data name="strFiltermRemoteXML" xml:space="preserve">
<value>mRemote XML(*.xml)</value>
</data>
<data name="strFilterPuttyConnectionManager" xml:space="preserve">
<value>PuTTY连接管理器文件</value>
</data>
<data name="strFilterRdgFiles" xml:space="preserve">
<value>远程桌面连接管理器文件(*.rdg</value>
</data>
<data name="strFilterRDP" xml:space="preserve">
<value>RDP文件(*.rdp)</value>
</data>
<data name="strFiltervRD2008CSV" xml:space="preserve">
<value>visionapp Remote Desktop 2008 CSV Files (*.csv)</value>
<value>visionapp远程桌面2008 CSV文件* .csv</value>
</data>
<data name="strFormatInherit" xml:space="preserve">
<value>继承 {0}</value>
@@ -735,12 +798,36 @@ VncSharp 版本 {0}</value>
<data name="strIcaSetResolutionFailed" xml:space="preserve">
<value>ICA 分辨率设置失败!</value>
</data>
<data name="strIdentifyQuickConnectTabs" xml:space="preserve">
<value>通过添加前缀“快速:”来识别快速连接选项卡</value>
</data>
<data name="strImportAD" xml:space="preserve">
<value>导入 Active Directory</value>
</data>
<data name="strImportExport" xml:space="preserve">
<value>导入/导出</value>
</data>
<data name="strImportFileFailedContent" xml:space="preserve">
<value>导入文件“{0}”时发生错误。</value>
</data>
<data name="strImportFileFailedMainInstruction" xml:space="preserve">
<value>导入失败</value>
</data>
<data name="strImportFromFileMenuItem" xml:space="preserve">
<value>从文件导入(&amp;F)...</value>
</data>
<data name="strImportLocationCommandButtons" xml:space="preserve">
<value>在根目录{0}{1}下|在所选文件夹{0}{2}下</value>
</data>
<data name="strImportLocationContent" xml:space="preserve">
<value>您希望将导入的项目放在哪里?</value>
</data>
<data name="strImportLocationMainInstruction" xml:space="preserve">
<value>导入位置</value>
</data>
<data name="strImportMenuItem" xml:space="preserve">
<value>导入(&amp;I)</value>
</data>
<data name="strImportmRemoteXML" xml:space="preserve">
<value>导入mRemote/mRemoteNG XML</value>
</data>
@@ -876,6 +963,9 @@ VncSharp 版本 {0}</value>
<data name="strLoadFromSqlFailed" xml:space="preserve">
<value>从SQL加载配置失败</value>
</data>
<data name="strLoadFromSqlFailedContent" xml:space="preserve">
<value>连接信息无法从SQL服务器加载。</value>
</data>
<data name="strLoadFromXmlFailed" xml:space="preserve">
<value>从XML加载配置失败</value>
</data>
@@ -1062,6 +1152,9 @@ VncSharp 版本 {0}</value>
<data name="strMenuSendSpecialKeys" xml:space="preserve">
<value>发送特殊键(VNC)</value>
</data>
<data name="strMenuSessionRetrieve" xml:space="preserve">
<value>取回</value>
</data>
<data name="strMenuSessions" xml:space="preserve">
<value>会话</value>
</data>
@@ -1164,6 +1257,39 @@ VncSharp 版本 {0}</value>
<data name="strOpenPorts" xml:space="preserve">
<value>打开端口</value>
</data>
<data name="strOptionsKeyboardButtonDelete" xml:space="preserve">
<value>删除(&amp;D)</value>
</data>
<data name="strOptionsKeyboardButtonNew" xml:space="preserve">
<value>新建(&amp;N)</value>
</data>
<data name="strOptionsKeyboardButtonReset" xml:space="preserve">
<value>重置为默认值(&amp;R)</value>
</data>
<data name="strOptionsKeyboardButtonResetAll" xml:space="preserve">
<value>全部重置为默认值(&amp;A)</value>
</data>
<data name="strOptionsKeyboardCommandsGroupTabs" xml:space="preserve">
<value>标签</value>
</data>
<data name="strOptionsKeyboardCommandsNextTab" xml:space="preserve">
<value>下一个标签</value>
</data>
<data name="strOptionsKeyboardCommandsPreviousTab" xml:space="preserve">
<value>上一个标签</value>
</data>
<data name="strOptionsKeyboardGroupModifyShortcut" xml:space="preserve">
<value>修改快捷方式</value>
</data>
<data name="strOptionsKeyboardLabelKeyboardShortcuts" xml:space="preserve">
<value>键盘快捷键</value>
</data>
<data name="strOptionsProxyTesting" xml:space="preserve">
<value>测试...</value>
</data>
<data name="strOptionsTabKeyboard" xml:space="preserve">
<value>键盘</value>
</data>
<data name="strOptionsTabTheme" xml:space="preserve">
<value>主题</value>
</data>
@@ -1179,9 +1305,18 @@ VncSharp 版本 {0}</value>
<data name="strPasswordProtect" xml:space="preserve">
<value>密码保护</value>
</data>
<data name="strPasswordStatusMustMatch" xml:space="preserve">
<value>两个密码必须匹配。</value>
</data>
<data name="strPasswordStatusTooShort" xml:space="preserve">
<value>密码必须至少有3个字符。</value>
</data>
<data name="strPleaseFillAllFields" xml:space="preserve">
<value>请填写所有字段</value>
</data>
<data name="strPortScanComplete" xml:space="preserve">
<value>端口扫描完成。</value>
</data>
<data name="strPortScanCouldNotLoadPanel" xml:space="preserve">
<value>无法载入端口扫描面板!</value>
</data>
@@ -1200,6 +1335,9 @@ VncSharp 版本 {0}</value>
<data name="strPropertyDescriptionAuthenticationMode" xml:space="preserve">
<value>请选择VNC服务器的身份验证方式。</value>
</data>
<data name="strPropertyDescriptionAutomaticResize" xml:space="preserve">
<value>在调整窗口大小时或在切换全屏模式时选择是否自动调整连接大小。需要RDC 8.0或更高版本。</value>
</data>
<data name="strPropertyDescriptionCacheBitmaps" xml:space="preserve">
<value>请选择是否启用位图缓存功能。</value>
</data>
@@ -1245,6 +1383,9 @@ VncSharp 版本 {0}</value>
<data name="strPropertyDescriptionIcon" xml:space="preserve">
<value>请选择连接到主机时所要显示的图标。</value>
</data>
<data name="strPropertyDescriptionLoadBalanceInfo" xml:space="preserve">
<value>指定负载均衡信息,供负载均衡路由器使用以选择最佳服务器。</value>
</data>
<data name="strPropertyDescriptionMACAddress" xml:space="preserve">
<value>请输入远程主机的MAC地址如果您需要在外部工具中使用此项。</value>
</data>
@@ -1311,6 +1452,9 @@ VncSharp 版本 {0}</value>
<data name="strPropertyDescriptionUseConsoleSession" xml:space="preserve">
<value>连接到远程主机的控制台会话。</value>
</data>
<data name="strPropertyDescriptionUseCredSsp" xml:space="preserve">
<value>如果可用请使用凭证安全支持提供程序CredSSP进行身份验证。</value>
</data>
<data name="strPropertyDescriptionUser1" xml:space="preserve">
<value>请在此随意输入任何你所需的信息。</value>
</data>
@@ -1347,6 +1491,9 @@ VncSharp 版本 {0}</value>
<data name="strPropertyNameAuthenticationMode" xml:space="preserve">
<value>身份验证模式</value>
</data>
<data name="strPropertyNameAutomaticResize" xml:space="preserve">
<value>自动调整大小</value>
</data>
<data name="strPropertyNameCacheBitmaps" xml:space="preserve">
<value>位图缓存</value>
</data>
@@ -1392,6 +1539,9 @@ VncSharp 版本 {0}</value>
<data name="strPropertyNameIcon" xml:space="preserve">
<value>图标</value>
</data>
<data name="strPropertyNameLoadBalanceInfo" xml:space="preserve">
<value>负载均衡信息</value>
</data>
<data name="strPropertyNameMACAddress" xml:space="preserve">
<value>MAC地址</value>
</data>
@@ -1533,6 +1683,9 @@ VncSharp 版本 {0}</value>
<data name="strPuttySavedSessionsRootName" xml:space="preserve">
<value>PuTTY 会话已保存</value>
</data>
<data name="strPuttySessionSettings" xml:space="preserve">
<value>PuTTY会话设置</value>
</data>
<data name="strPuttySettings" xml:space="preserve">
<value>PuTTY 设置</value>
</data>
@@ -1572,12 +1725,6 @@ VncSharp 版本 {0}</value>
<data name="strRadioCloseWarnNever" xml:space="preserve">
<value>关闭连接时不需确认</value>
</data>
<data name="strRAW" xml:space="preserve">
<value>RAW</value>
</data>
<data name="strRDP" xml:space="preserve">
<value>RDP</value>
</data>
<data name="strRDP16777216Colors" xml:space="preserve">
<value>24位色</value>
</data>
@@ -1755,9 +1902,6 @@ VncSharp 版本 {0}</value>
<data name="strRename" xml:space="preserve">
<value>重命名</value>
</data>
<data name="strRlogin" xml:space="preserve">
<value>Rlogin</value>
</data>
<data name="strSave" xml:space="preserve">
<value>保存</value>
</data>
@@ -1830,9 +1974,6 @@ VncSharp 版本 {0}</value>
<data name="strSmartSizeModeNone" xml:space="preserve">
<value>禁用窗口自适应</value>
</data>
<data name="strSocks5" xml:space="preserve">
<value>Socks 5</value>
</data>
<data name="strSort" xml:space="preserve">
<value>排序</value>
</data>
@@ -1899,9 +2040,6 @@ VncSharp 版本 {0}</value>
<data name="strTabUpdates" xml:space="preserve">
<value>升级</value>
</data>
<data name="strTelnet" xml:space="preserve">
<value>Telnet</value>
</data>
<data name="strTheFollowing" xml:space="preserve">
<value>以下:</value>
</data>
@@ -1914,6 +2052,57 @@ VncSharp 版本 {0}</value>
<data name="strThemeCategoryGeneral" xml:space="preserve">
<value>常规</value>
</data>
<data name="strThemeDescriptionConfigPanelBackgroundColor" xml:space="preserve">
<value>配置面板的背景颜色。</value>
</data>
<data name="strThemeDescriptionConfigPanelCategoryTextColor" xml:space="preserve">
<value>配置面板中类别文本的颜色。</value>
</data>
<data name="strThemeDescriptionConfigPanelGridLineColor" xml:space="preserve">
<value>配置面板中网格线的颜色</value>
</data>
<data name="strThemeDescriptionConfigPanelHelpBackgroundColor" xml:space="preserve">
<value>配置面板的帮助区域的背景颜色。</value>
</data>
<data name="strThemeDescriptionConfigPanelHelpTextColor" xml:space="preserve">
<value>配置面板帮助区域中文本的颜色。</value>
</data>
<data name="strThemeDescriptionConfigPanelTextColor" xml:space="preserve">
<value>配置面板中文本的颜色。</value>
</data>
<data name="strThemeDescriptionConnectionsPanelBackgroundColor" xml:space="preserve">
<value>连接面板的背景颜色。</value>
</data>
<data name="strThemeDescriptionConnectionsPanelTextColor" xml:space="preserve">
<value>连接面板中文本的颜色。</value>
</data>
<data name="strThemeDescriptionConnectionsPanelTreeLineColor" xml:space="preserve">
<value>连接面板中树形线的颜色。</value>
</data>
<data name="strThemeDescriptionMenuBackgroundColor" xml:space="preserve">
<value>菜单的背景颜色。</value>
</data>
<data name="strThemeDescriptionMenuTextColor" xml:space="preserve">
<value>菜单中文本的颜色。</value>
</data>
<data name="strThemeDescriptionSearchBoxBackgroundColor" xml:space="preserve">
<value>搜索框的背景颜色。</value>
</data>
<data name="strThemeDescriptionSearchBoxTextColor" xml:space="preserve">
<value>搜索框中文本的颜色。</value>
</data>
<data name="strThemeDescriptionSearchBoxTextPromptColor" xml:space="preserve">
<value>搜索框中提示文本的颜色。</value>
</data>
<data name="strThemeDescriptionToolbarBackgroundColor" xml:space="preserve">
<value>工具栏的背景颜色。</value>
</data>
<data name="strThemeDescriptionToolbarTextColor" xml:space="preserve">
<value>工具栏中文本的颜色。</value>
</data>
<data name="strThemeDescriptionWindowBackgroundColor" xml:space="preserve">
<value>主窗口的背景颜色。</value>
</data>
<data name="strThemeNameConfigPanelBackgroundColor" xml:space="preserve">
<value>配置面板背景色</value>
</data>
@@ -1974,6 +2163,9 @@ VncSharp 版本 {0}</value>
<data name="strTitlePassword" xml:space="preserve">
<value>密码</value>
</data>
<data name="strTitlePasswordWithName" xml:space="preserve">
<value>{0}的密码</value>
</data>
<data name="strTitleSelectPanel" xml:space="preserve">
<value>选择面板</value>
</data>
@@ -1989,12 +2181,12 @@ VncSharp 版本 {0}</value>
<data name="strTryIntegrate" xml:space="preserve">
<value>尝试进行集成</value>
</data>
<data name="strShowOnToolbar" xml:space="preserve">
<value>在工具栏上显示</value>
</data>
<data name="strType" xml:space="preserve">
<value>类型</value>
</data>
<data name="strUltraVncRepeater" xml:space="preserve">
<value>Ultra VNC Repeater</value>
</data>
<data name="strUltraVNCSCListeningPort" xml:space="preserve">
<value>UltraVNC SingleClick端口</value>
</data>
@@ -2013,15 +2205,15 @@ VncSharp 版本 {0}</value>
<data name="strUpdateCheckCompleteFailed" xml:space="preserve">
<value>升级检查未完成!</value>
</data>
<data name="strUpdateCheckFailed" xml:space="preserve">
<value>升级检查失败</value>
<data name="strUpdateCheckFailedLabel" xml:space="preserve">
<value>检查失败</value>
</data>
<data name="strUpdateCheckingLabel" xml:space="preserve">
<value>检查更新...</value>
</data>
<data name="strUpdateCheckPortableEdition" xml:space="preserve">
<value>mRemoteNG便携版目前不支持自动更新。</value>
</data>
<data name="strUpdateDeleteFailed" xml:space="preserve">
<value>升级文件删除失败!</value>
</data>
<data name="strUpdateDownloadComplete" xml:space="preserve">
<value>下载完成!
mRemoteNG 将退出并安装更新。</value>
@@ -2044,15 +2236,12 @@ mRemoteNG 将退出并安装更新。</value>
<data name="strUpdateFrequencyWeekly" xml:space="preserve">
<value>每周</value>
</data>
<data name="strUpdateStartFailed" xml:space="preserve">
<value>升级启动失败!</value>
<data name="strUpdateGetChangeLogFailed" xml:space="preserve">
<value>更改日志无法下载。</value>
</data>
<data name="strUseDifferentUsernameAndPassword" xml:space="preserve">
<value>使用不同的用户名和密码</value>
</data>
<data name="strUseOnlyErrorsAndInfosPanel" xml:space="preserve">
<value>仅适用通知面板(不弹出消息窗口)</value>
</data>
<data name="strUser" xml:space="preserve">
<value>用户</value>
</data>
@@ -2068,9 +2257,6 @@ mRemoteNG 将退出并安装更新。</value>
<data name="strVersion" xml:space="preserve">
<value>版本</value>
</data>
<data name="strVnc" xml:space="preserve">
<value>VNC</value>
</data>
<data name="strVncConnectionDisconnectFailed" xml:space="preserve">
<value>VNC 连接断开失败!</value>
</data>
@@ -2104,13 +2290,324 @@ mRemoteNG 将退出并安装更新。</value>
<data name="strWeifenLuoAttribution" xml:space="preserve">
<value>使用DockPanel Suite[Weifen Luo]</value>
</data>
<data name="strWriteLogFile" xml:space="preserve">
<value>记录日志(mRemoteNG.log)</value>
</data>
<data name="strXULrunnerPath" xml:space="preserve">
<value>XULrunner路径</value>
</data>
<data name="strYes" xml:space="preserve">
<value>确定</value>
</data>
<data name="strMenuReconnectAll" xml:space="preserve">
<value>重新连接所有打开的连接</value>
</data>
<data name="strRDPOverallConnectionTimeout" xml:space="preserve">
<value>RDP连接超时</value>
</data>
<data name="strNodeAlreadyInFolder" xml:space="preserve">
<value>此节点已在此文件夹中。</value>
</data>
<data name="strNodeCannotDragOnSelf" xml:space="preserve">
<value>无法将节点拖到自身上。</value>
</data>
<data name="strNodeCannotDragParentOnChild" xml:space="preserve">
<value>无法将父节点拖放到子节点上。</value>
</data>
<data name="strNodeNotDraggable" xml:space="preserve">
<value>该节点不可拖动。</value>
</data>
<data name="strEncryptionBlockCipherMode" xml:space="preserve">
<value>分组密码模式</value>
</data>
<data name="strEncryptionEngine" xml:space="preserve">
<value>加密引擎</value>
</data>
<data name="strTabSecurity" xml:space="preserve">
<value>安全</value>
</data>
<data name="strEncryptionKeyDerivationIterations" xml:space="preserve">
<value>关键推导函数迭代</value>
</data>
<data name="strRDPSoundQualityDynamic" xml:space="preserve">
<value>动态</value>
</data>
<data name="strRDPSoundQualityHigh" xml:space="preserve">
<value>高</value>
</data>
<data name="strRDPSoundQualityMedium" xml:space="preserve">
<value>中</value>
</data>
<data name="strPropertyDescriptionSoundQuality" xml:space="preserve">
<value>选择由协议提供的声音质量:动态,中,高</value>
</data>
<data name="strPropertyNameSoundQuality" xml:space="preserve">
<value>音质</value>
</data>
<data name="strUpdatePortableDownloadComplete" xml:space="preserve">
<value>下载完成!</value>
</data>
<data name="strDownloadPortable" xml:space="preserve">
<value>下载</value>
</data>
<data name="strPropertyDescriptionRDPMinutesToIdleTimeout" xml:space="preserve">
<value>RDP会话在自动断开连接之前闲置的分钟数无限制使用0</value>
</data>
<data name="strPropertyNameRDPMinutesToIdleTimeout" xml:space="preserve">
<value>空闲等待分钟数</value>
</data>
<data name="strAccept" xml:space="preserve">
<value>接受</value>
</data>
<data name="strAdd" xml:space="preserve">
<value>添加</value>
</data>
<data name="strCredentialEditor" xml:space="preserve">
<value>凭据编辑器</value>
</data>
<data name="strCredentialManager" xml:space="preserve">
<value>凭证管理器</value>
</data>
<data name="strRemove" xml:space="preserve">
<value>移除</value>
</data>
<data name="strTitle" xml:space="preserve">
<value>标题</value>
</data>
<data name="strPropertyDescriptionCredential" xml:space="preserve">
<value>选择用于此连接的凭证。</value>
</data>
<data name="strConfirmDeleteCredentialRecord" xml:space="preserve">
<value>您确定要删除凭据记录{0}吗?</value>
</data>
<data name="strFindMatchingCredentialFailed" xml:space="preserve">
<value>找不到名为“{1}”的连接记录的ID为“{0}”的凭证记录。</value>
</data>
<data name="strPropertyDescriptionRDPAlertIdleTimeout" xml:space="preserve">
<value>选择是否在RDP会话由于不活动而断开连接后收到警报</value>
</data>
<data name="strPropertyNameRDPAlertIdleTimeout" xml:space="preserve">
<value>空闲断开警报</value>
</data>
<data name="strPasswordConstainsSpecialCharactersConstraintHint" xml:space="preserve">
<value>密码必须至少包含{0}个以下所示字符:{1}</value>
</data>
<data name="strPasswordContainsLowerCaseConstraintHint" xml:space="preserve">
<value>密码必须至少包含{0}个小写字符</value>
</data>
<data name="strPasswordContainsNumbersConstraint" xml:space="preserve">
<value>密码必须至少包含{0}个数字</value>
</data>
<data name="strPasswordContainsUpperCaseConstraintHint" xml:space="preserve">
<value>密码必须至少包含{0}大写字符</value>
</data>
<data name="strPasswordLengthConstraintHint" xml:space="preserve">
<value>密码长度必须介于{0}和{1}之间</value>
</data>
<data name="strChooseLogPath" xml:space="preserve">
<value>为mRemoteNG日志文件选择一个路径</value>
</data>
<data name="strDebug" xml:space="preserve">
<value>调试</value>
</data>
<data name="strShowTheseMessageTypes" xml:space="preserve">
<value>显示这些消息类型</value>
</data>
<data name="strLogFilePath" xml:space="preserve">
<value>日志文件路径</value>
</data>
<data name="strLogTheseMessageTypes" xml:space="preserve">
<value>记录这些消息类型</value>
</data>
<data name="strChoosePath" xml:space="preserve">
<value>选择路径</value>
</data>
<data name="strOpenFile" xml:space="preserve">
<value>打开文件</value>
</data>
<data name="strUseDefault" xml:space="preserve">
<value>使用默认</value>
</data>
<data name="strLogging" xml:space="preserve">
<value>记录</value>
</data>
<data name="strPopups" xml:space="preserve">
<value>弹出窗口</value>
</data>
<data name="strLogToAppDir" xml:space="preserve">
<value>登录到应用程序目录</value>
</data>
<data name="strAssignedCredential" xml:space="preserve">
<value>分配凭据</value>
</data>
<data name="strHttpsInsecureAllowAlways" xml:space="preserve">
<value>始终允许</value>
</data>
<data name="strHttpsInsecureAllowOnce" xml:space="preserve">
<value>允许一次</value>
</data>
<data name="strHttpsInsecureDontAllow" xml:space="preserve">
<value>不允许</value>
</data>
<data name="strHttpsInsecurePrompt" xml:space="preserve">
<value>允许网址{0}的不安全证书?</value>
</data>
<data name="strHttpsInsecurePromptTitle" xml:space="preserve">
<value>允许不安全的证书?</value>
</data>
<data name="RepositoryIsUnlocked" xml:space="preserve">
<value>选定的存储库已解锁</value>
</data>
<data name="IncorrectPassword" xml:space="preserve">
<value>密码错误</value>
</data>
<data name="Source" xml:space="preserve">
<value>资源</value>
</data>
<data name="Unlocking" xml:space="preserve">
<value>解锁</value>
</data>
<data name="UnlockCredentialRepository" xml:space="preserve">
<value>解锁凭据存储库</value>
</data>
<data name="Unlock" xml:space="preserve">
<value>解锁</value>
</data>
<data name="PromptUnlockCredReposOnStartup" xml:space="preserve">
<value>提示在启动时解锁凭据存储库</value>
</data>
<data name="Credentials" xml:space="preserve">
<value>凭据</value>
</data>
<data name="strUpgrade" xml:space="preserve">
<value>升级</value>
</data>
<data name="strBack" xml:space="preserve">
<value>后退</value>
</data>
<data name="strConnectionFilePath" xml:space="preserve">
<value>连接文件路径</value>
</data>
<data name="strCreateAndOpenNewFile" xml:space="preserve">
<value>创建并打开新文件</value>
</data>
<data name="strOpenADifferentFile" xml:space="preserve">
<value>打开一个不同的文件</value>
</data>
<data name="strCredentialManagerUpgradeDescription" xml:space="preserve">
<value>在v1.76中我们引入了凭证管理系统。此功能要求我们在mRemoteNG中存储和交互凭据的方式发生重大变化。您将需要执行mRemoteNG连接文件的单向升级。
如果您不想执行升级,此页面将引导您完成升级连接文件的过程,或者让您有机会打开不同的连接文件。</value>
</data>
<data name="CredentialUnavailable" xml:space="preserve">
<value>凭据不可用</value>
</data>
<data name="strOptionsThemeDeleteConfirmation" xml:space="preserve">
<value>你真的想删除主题吗?</value>
</data>
<data name="strOptionsThemeEnableTheming" xml:space="preserve">
<value>启用主题</value>
</data>
<data name="strOptionsThemeNewThemeCaption" xml:space="preserve">
<value>新主题名称</value>
</data>
<data name="strOptionsThemeNewThemeError" xml:space="preserve">
<value>无法创建主题,名称已存在或名称中有特殊字符</value>
</data>
<data name="strOptionsThemeNewThemeText" xml:space="preserve">
<value>输入新的主题名称</value>
</data>
<data name="strOptionsThemeThemeChaangeWarning" xml:space="preserve">
<value>警告:需要重新启动才能禁用主题或完全应用新主题</value>
</data>
<data name="strOptionsThemeErrorNoThemes" xml:space="preserve">
<value>未加载任何主题请检查默认的mremoteNG主题是否存在于“主题”文件夹中</value>
</data>
<data name="CouldNotFindExternalTool" xml:space="preserve">
<value>无法找到名称为“{0}”的外部工具</value>
</data>
<data name="ConfigurationCreateNew" xml:space="preserve">
<value>创建一个新的连接文件</value>
</data>
<data name="ConnectionFileNotFound" xml:space="preserve">
<value>无法找到连接文件。</value>
</data>
<data name="ConfigurationImportFile" xml:space="preserve">
<value>导入现有文件</value>
</data>
<data name="ConfigurationCustomPath" xml:space="preserve">
<value>使用自定义文件路径</value>
</data>
<data name="TestingConnection" xml:space="preserve">
<value>测试连接</value>
</data>
<data name="ServerNotAccessible" xml:space="preserve">
<value>服务器“{0}”无法访问。</value>
</data>
<data name="ConnectionSuccessful" xml:space="preserve">
<value>连接成功</value>
</data>
<data name="LoginFailedForUser" xml:space="preserve">
<value>用户“{0}”登录失败。</value>
</data>
<data name="DatabaseNotAvailable" xml:space="preserve">
<value>数据库“{0}”不可用。</value>
</data>
<data name="SaveConnectionsAfterEveryEdit" xml:space="preserve">
<value>每次编辑后保存连接</value>
</data>
<data name="FilterSearchMatchesInConnectionTree" xml:space="preserve">
<value>在连接树中过滤搜索匹配</value>
</data>
<data name="TestConnection" xml:space="preserve">
<value>测试连接</value>
</data>
<data name="strLabelReadOnly" xml:space="preserve">
<value>只读:</value>
</data>
<data name="LoadBalanceInfoUseUtf8" xml:space="preserve">
<value>对RDP“负载均衡信息”属性使用UTF8编码</value>
</data>
<data name="strTimeoutInSeconds" xml:space="preserve">
<value>超时(秒)</value>
</data>
<data name="srtWorkingDirectory" xml:space="preserve">
<value>工作目录:</value>
</data>
<data name="strRunElevated" xml:space="preserve">
<value>运行已提升</value>
</data>
<data name="strRunElevateHeader" xml:space="preserve">
<value>运行提升</value>
</data>
<data name="strShowOnToolbarColumnHeader" xml:space="preserve">
<value>显示在工具栏上</value>
</data>
<data name="strTryToIntegrateColumnHeader" xml:space="preserve">
<value>尝试整合</value>
</data>
<data name="strWorkingDirColumnHeader" xml:space="preserve">
<value>工作目录</value>
</data>
<data name="strLockToolbars" xml:space="preserve">
<value>锁定工具栏位置</value>
</data>
<data name="strMultiSshToolbar" xml:space="preserve">
<value>多SSH工具栏</value>
</data>
<data name="strImportSubOUs" xml:space="preserve">
<value>导入子OU</value>
</data>
<data name="strMenuLockToolbars" xml:space="preserve">
<value>锁定工具栏位置</value>
</data>
<data name="strMenuMultiSshToolbar" xml:space="preserve">
<value>多SSH工具栏</value>
</data>
<data name="strAdvancedSecurityOptions" xml:space="preserve">
<value>高级安全选项</value>
</data>
<data name="strOptionsPageTitle" xml:space="preserve">
<value>mRemoteNG选项</value>
</data>
<data name="strLoadBalanceInfoUseUtf8" xml:space="preserve">
<value>对RDP“负载均衡信息”属性使用UTF8编码</value>
</data>
</root>

View File

@@ -57,6 +57,7 @@
<xs:attribute name="RedirectDiskDrives" type="xs:boolean" use="required" />
<xs:attribute name="RedirectPorts" type="xs:boolean" use="required" />
<xs:attribute name="RedirectPrinters" type="xs:boolean" use="required" />
<xs:attribute name="RedirectClipboard" type="xs:boolean" use="required" />
<xs:attribute name="RedirectSmartCards" type="xs:boolean" use="required" />
<xs:attribute name="RedirectSound" type="xs:string" use="required" />
<xs:attribute name="SoundQuality" type="xs:string" use="required" />
@@ -103,6 +104,7 @@
<xs:attribute name="InheritRedirectKeys" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRedirectPorts" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRedirectPrinters" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRedirectClipboard" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRedirectSmartCards" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRedirectSound" type="xs:boolean" use="optional" />
<xs:attribute name="InheritSoundQuality" type="xs:boolean" use="optional" />

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