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
This commit is contained in:
David Sparer
2018-07-23 15:06:15 -05:00
54 changed files with 1216 additions and 518 deletions

View File

@@ -1,4 +1,19 @@
1.76.4 Alpha 6 (2018-xx-xx):
1.76.5 (2018-xx-xx):
Fixes:
------
#1030: Exception thrown if importing from port scan and no tree node is selected
#1020: BackupFileKeepCount setting not limiting backup file count
#1004: Duplicating root or PuTTy node through hotkey causes unhandled exception
#1002: Disabling filtering without clearing keyword leaves filtered state
#1001: Connection tree context menu hotkeys stop working and disappear in some cases
#999: Some hotkeys stop working if File menu was called when PuTTy Saved Sessions was selected
#998: Can sometimes add connection under PuTTY Sessions node
#991: Error when deleting host in filtered view
#961: Connections file overwritten if correct decryption password not provided
1.76.4 Alpha 6 (2018-06-03):
Features/Enhancements:
----------------------
@@ -6,6 +21,7 @@ Features/Enhancements:
#942: Improved Russian translation of several items
#924: Notification for "No Host Specified" when clicking folders in quick-connect menu
#902: Menu bar can once again be moved. View -> "Lock toolbar positions" now also locks the menu position
Added option for creating an empty panel on startup
Fixes:
------

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -3,7 +3,7 @@
License for use and distribution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copyright (C) 1999-2016 Igor Pavlov.
Copyright (C) 1999-2018 Igor Pavlov.
7-Zip Extra files are under the GNU LGPL license.

View File

@@ -1,6 +1,25 @@
7-Zip Extra history
-------------------
This file contains only information about changes related to that package exclusively.
The full history of changes is listed in history.txt in main 7-Zip program.
18.05 2018-04-30
-------------------------
- The speed for LZMA/LZMA2 compressing was increased
by 8% for fastest/fast compression levels and
by 3% for normal/maximum compression levels.
18.03 beta 2018-03-04
-------------------------
- The speed for single-thread LZMA/LZMA2 decoding
was increased by 30% in x64 version and by 3% in x86 version.
- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
if there are multiple independent data chunks in LZMA2 stream.
9.35 beta 2014-12-07
------------------------------
- SFX modules were moved to LZMA SDK package.

View File

@@ -1,9 +1,9 @@
7-Zip Extra 16.02
7-Zip Extra 18.05
-----------------
7-Zip Extra is package of extra modules of 7-Zip.
7-Zip Copyright (C) 1999-2016 Igor Pavlov.
7-Zip Copyright (C) 1999-2018 Igor Pavlov.
7-Zip is free software. Read License.txt for more information about license.

View File

@@ -13,13 +13,46 @@ param (
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
$path_packageZipScript = Join-Path -Path $SolutionDir -ChildPath "Tools\build-relport.cmd"
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
Exit
}
Write-Output "Solution Dir: '$($SolutionDir)'"
Write-Output "Target Dir: '$($TargetDir)'"
$ConfigurationName = $ConfigurationName.Trim()
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
# Package Zip
if ($ConfigurationName -match "Release" -and $ConfigurationName -match "Portable") {
if ($ConfigurationName -eq "Release Portable") {
Write-Output "Packaging Release Portable ZIP"
& $path_packageZipScript
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
Write-Output "Version is $($version)"
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
Remove-Item -Recurse "$($SolutionDir)mRemoteV1\bin\package" -ErrorAction SilentlyContinue | Out-Null
New-Item "$($SolutionDir)mRemoteV1\bin\package" -ItemType "directory" | Out-Null
Copy-Item "$($SolutionDir)mRemoteV1\Resources\PuTTYNG.exe" -Destination "$($SolutionDir)mRemoteV1\bin\package"
#Write-Output "$($SolutionDir)mRemoteV1\bin\$ConfigurationName"
#Write-Output "$($SolutionDir)mRemoteV1\bin\package"
Copy-Item "$($SolutionDir)mRemoteV1\bin\$ConfigurationName\*" -Destination "$($SolutionDir)mRemoteV1\bin\package" -Recurse -Force
Copy-Item "$($SolutionDir)*.txt" -Destination "$($SolutionDir)mRemoteV1\bin\package"
Write-Output "Creating portable ZIP file $($PortableZip)"
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip "$($SolutionDir)mRemoteV1\bin\package\*.*"
#& $SEVENZIP a -bt -mx=9 -tzip -y $PortableZip "$($SolutionDir)*.TXT"
}
else {
Write-Output "We will not zip anything - this isnt a portable release build."

View File

@@ -0,0 +1,39 @@
if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
Write-Output "NOT running via Appveyor - Exiting"
Exit
}
$appvDir = $Env:APPVEYOR_BUILD_FOLDER
Write-Output "Appveyor Build Dir: '$($appvDir)'"
$ConfigurationName = $Env:CONFIGURATION.Trim()
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
if ($ConfigurationName -eq "Release Portable") {
Write-Output "Packaging Release Portable ZIP"
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
Write-Output "Version is $($version)"
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
Remove-Item -Recurse "$($SolutionDir)mRemoteV1\bin\package" -ErrorAction SilentlyContinue | Out-Null
New-Item "$($SolutionDir)mRemoteV1\bin\package" -ItemType "directory" | Out-Null
Copy-Item "$($SolutionDir)mRemoteV1\Resources\PuTTYNG.exe" -Destination "$($SolutionDir)mRemoteV1\bin\package"
Copy-Item "$($SolutionDir)mRemoteV1\bin\$ConfigurationName\*" -Destination "$($SolutionDir)mRemoteV1\bin\package" -Recurse -Force
Copy-Item "$($SolutionDir)*.txt" -Destination "$($SolutionDir)mRemoteV1\bin\package"
Write-Output "Creating portable ZIP file $($PortableZip)"
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip "$($SolutionDir)mRemoteV1\bin\package\*.*"
}
else {
Write-Output "We will not zip anything - this isnt a portable release build."
}

View File

@@ -1,10 +1,11 @@
version: 1.0.{build}
version: 1.76.{build}
pull_requests:
do_not_increment_build_number: true
image: Visual Studio 2017
configuration:
- Release
- Release Portable
- Release Installer
platform: x86
clone_depth: 1
install:
@@ -14,7 +15,14 @@ before_build:
build:
project: mRemoteV1.sln
verbosity: normal
after_build:
- ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"$($SolutionDir)Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"$($SolutionDir)Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"$($SolutionDir)mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"$($SolutionDir)Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"$($SolutionDir)mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"$($SolutionDir)mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"$($SolutionDir)mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\"\n\n Copy-Item \"$($SolutionDir)mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"$($SolutionDir)*.txt\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \"$($SolutionDir)mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}"
test:
assemblies:
only:
- mRemoteNGTests\bin\$(configuration)\mRemoteNGTests.dll
- mRemoteNGTests\bin\$(configuration)\mRemoteNGTests.dll
artifacts:
- path: Release\*.msi
name: mRemoteNG-installer.msi
- path: Release\*.zip
name: mRemoteNG-portable.zip

View File

@@ -5,7 +5,6 @@ using System.Windows.Forms;
using System.Xml.Linq;
using mRemoteNG.App;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Container;
@@ -27,7 +26,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
var connectionsService = new ConnectionsService(PuttySessionsManager.Instance,
new Import(Substitute.For<IWin32Window>()),
Substitute.For<IWin32Window>());
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(connectionsService, Substitute.For<IWin32Window>(), password.ConvertToSecureString);
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(connectionsService, Substitute.For<IWin32Window>(), () => password.ConvertToSecureString);
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize(confCons);
}

View File

@@ -2,6 +2,7 @@
using mRemoteNG.Security;
using mRemoteNG.Security.Authentication;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using NUnit.Framework;
@@ -9,35 +10,31 @@ namespace mRemoteNGTests.Security.Authentication
{
public class PasswordAuthenticatorTests
{
private PasswordAuthenticator _authenticator;
private ICryptographyProvider _cryptographyProvider;
private string _cipherText;
private readonly SecureString _correctPassword = "9theCorrectPass#5".ConvertToSecureString();
private readonly SecureString _wrongPassword = "wrongPassword".ConvertToSecureString();
[SetUp]
public void Setup()
{
var cryptoProvider = new AeadCryptographyProvider {KeyDerivationIterations = 10000};
const string cipherText = "MPELiwk7+xeNlruIyt5uxTvVB+/RLVoLdUGnwY4CWCqwKe7T2IBwWo4oaKum5hdv7447g5m2nZsYPrfARSlotQB4r1KZQg==";
_authenticator = new PasswordAuthenticator(cryptoProvider, cipherText);
}
[TearDown]
public void Teardown()
{
_authenticator = null;
_cryptographyProvider = new AeadCryptographyProvider {KeyDerivationIterations = 10000};
_cipherText = "MPELiwk7+xeNlruIyt5uxTvVB+/RLVoLdUGnwY4CWCqwKe7T2IBwWo4oaKum5hdv7447g5m2nZsYPrfARSlotQB4r1KZQg==";
}
[Test]
public void AuthenticatingWithCorrectPasswordReturnsTrue()
{
var authenticated = _authenticator.Authenticate(_correctPassword);
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => Optional<SecureString>.Empty);
var authenticated = authenticator.Authenticate(_correctPassword);
Assert.That(authenticated);
}
[Test]
public void AuthenticatingWithWrongPasswordReturnsFalse()
{
var authenticated = _authenticator.Authenticate(_wrongPassword);
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => Optional<SecureString>.Empty);
var authenticated = authenticator.Authenticate(_wrongPassword);
Assert.That(!authenticated);
}
@@ -45,12 +42,15 @@ namespace mRemoteNGTests.Security.Authentication
public void AuthenticationRequestorIsCalledWhenInitialPasswordIsWrong()
{
var wasCalled = false;
_authenticator.AuthenticationRequestor = () =>
Optional<SecureString> AuthenticationRequestor()
{
wasCalled = true;
return _correctPassword;
};
_authenticator.Authenticate(_wrongPassword);
}
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
authenticator.Authenticate(_wrongPassword);
Assert.That(wasCalled);
}
@@ -58,28 +58,30 @@ namespace mRemoteNGTests.Security.Authentication
public void AuthenticationRequestorNotCalledWhenInitialPasswordIsCorrect()
{
var wasCalled = false;
_authenticator.AuthenticationRequestor = () =>
Optional<SecureString> AuthenticationRequestor()
{
wasCalled = true;
return _correctPassword;
};
_authenticator.Authenticate(_correctPassword);
}
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
authenticator.Authenticate(_correctPassword);
Assert.That(!wasCalled);
}
[Test]
public void ProvidingCorrectPasswordToTheAuthenticationRequestorReturnsTrue()
{
_authenticator.AuthenticationRequestor = () => _correctPassword;
var authenticated = _authenticator.Authenticate(_wrongPassword);
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => _correctPassword);
var authenticated = authenticator.Authenticate(_wrongPassword);
Assert.That(authenticated);
}
[Test]
public void AuthenticationFailsWhenAuthenticationRequestorGivenEmptyPassword()
{
_authenticator.AuthenticationRequestor = () => new SecureString();
var authenticated = _authenticator.Authenticate(_wrongPassword);
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => new SecureString());
var authenticated = authenticator.Authenticate(_wrongPassword);
Assert.That(!authenticated);
}
@@ -87,27 +89,34 @@ namespace mRemoteNGTests.Security.Authentication
public void AuthenticatorRespectsMaxAttempts()
{
var authAttempts = 0;
_authenticator.AuthenticationRequestor = () =>
Optional<SecureString> AuthenticationRequestor()
{
authAttempts++;
return _wrongPassword;
};
_authenticator.Authenticate(_wrongPassword);
Assert.That(authAttempts == _authenticator.MaxAttempts);
}
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
authenticator.Authenticate(_wrongPassword);
Assert.That(authAttempts == authenticator.MaxAttempts);
}
[Test]
public void AuthenticatorRespectsMaxAttemptsCustomValue()
{
const int customMaxAttempts = 5;
_authenticator.MaxAttempts = customMaxAttempts;
var authAttempts = 0;
_authenticator.AuthenticationRequestor = () =>
Optional<SecureString> AuthenticationRequestor()
{
authAttempts++;
return _wrongPassword;
};
_authenticator.Authenticate(_wrongPassword);
}
var authenticator =
new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor)
{
MaxAttempts = customMaxAttempts
};
authenticator.Authenticate(_wrongPassword);
Assert.That(authAttempts == customMaxAttempts);
}
}

View File

@@ -1,4 +1,5 @@
using mRemoteNG.Tree.Root;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using NUnit.Framework;
@@ -46,5 +47,13 @@ namespace mRemoteNGTests.Tree
_rootNodeInfo.PasswordString = password;
Assert.That(_rootNodeInfo.PasswordString, Is.EqualTo(password));
}
[TestCase(RootNodeType.Connection, TreeNodeType.Root)]
[TestCase(RootNodeType.PuttySessions, TreeNodeType.PuttyRoot)]
public void RootNodeHasCorrectTreeNodeType(RootNodeType rootNodeType, TreeNodeType expectedTreeNodeType)
{
var rootNode = new RootNodeInfo(rootNodeType);
Assert.That(rootNode.GetTreeNodeType(), Is.EqualTo(expectedTreeNodeType));
}
}
}

View File

@@ -0,0 +1,188 @@
using System.Linq;
using System.Threading;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Controls;
using NUnit.Framework;
namespace mRemoteNGTests.UI.Controls
{
public class ConnectionTreeTests
{
private ConnectionTreeSearchTextFilter _filter;
private ConnectionTree _connectionTree;
[SetUp]
public void Setup()
{
_filter = new ConnectionTreeSearchTextFilter();
_connectionTree = new ConnectionTree
{
UseFiltering = true
};
}
[Test]
[Apartment(ApartmentState.STA)]
public void FilteringIsRetainedAndUpdatedWhenNodeDeleted()
{
// root
// |- folder1
// | |- con1
// | |- dontshowme
// |- folder2
// |- con2
var connectionTreeModel = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
var folder1 = new ContainerInfo {Name = "folder1"};
var folder2 = new ContainerInfo {Name = "folder2"};
var con1 = new ConnectionInfo {Name = "con1"};
var con2 = new ConnectionInfo {Name = "con2"};
var conDontShow = new ConnectionInfo {Name = "dontshowme" };
root.AddChildRange(new []{folder1, folder2});
folder1.AddChildRange(new []{con1, conDontShow});
folder2.AddChild(con2);
connectionTreeModel.AddRootNode(root);
_connectionTree.ConnectionTreeModel = connectionTreeModel;
// ensure all folders expanded
_connectionTree.ExpandAll();
// apply filtering on the tree
_filter.FilterText = "con";
_connectionTree.ModelFilter = _filter;
connectionTreeModel.DeleteNode(con1);
Assert.That(_connectionTree.IsFiltering, Is.True);
Assert.That(_connectionTree.FilteredObjects, Does.Not.Contain(con1));
Assert.That(_connectionTree.FilteredObjects, Does.Not.Contain(conDontShow));
Assert.That(_connectionTree.FilteredObjects, Does.Contain(con2));
}
[Test]
[Apartment(ApartmentState.STA)]
public void CannotAddConnectionToPuttySessionNode()
{
var connectionTreeModel = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
connectionTreeModel.AddRootNode(root);
connectionTreeModel.AddRootNode(puttyRoot);
_connectionTree.ConnectionTreeModel = connectionTreeModel;
_connectionTree.SelectedObject = puttyRoot;
_connectionTree.AddConnection();
Assert.That(puttyRoot.Children, Is.Empty);
}
[Test]
[Apartment(ApartmentState.STA)]
public void CannotAddFolderToPuttySessionNode()
{
var connectionTreeModel = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
connectionTreeModel.AddRootNode(root);
connectionTreeModel.AddRootNode(puttyRoot);
_connectionTree.ConnectionTreeModel = connectionTreeModel;
_connectionTree.SelectedObject = puttyRoot;
_connectionTree.AddFolder();
Assert.That(puttyRoot.Children, Is.Empty);
}
[Test]
[Apartment(ApartmentState.STA)]
public void CannotDuplicateRootConnectionNode()
{
var connectionTreeModel = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
connectionTreeModel.AddRootNode(root);
_connectionTree.ConnectionTreeModel = connectionTreeModel;
_connectionTree.SelectedObject = root;
_connectionTree.DuplicateSelectedNode();
Assert.That(connectionTreeModel.RootNodes, Has.One.Items);
}
[Test]
[Apartment(ApartmentState.STA)]
public void CannotDuplicateRootPuttyNode()
{
var connectionTreeModel = new ConnectionTreeModel();
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
connectionTreeModel.AddRootNode(puttyRoot);
_connectionTree.ConnectionTreeModel = connectionTreeModel;
_connectionTree.SelectedObject = puttyRoot;
_connectionTree.DuplicateSelectedNode();
Assert.That(connectionTreeModel.RootNodes, Has.One.Items);
}
[Test]
[Apartment(ApartmentState.STA)]
public void CannotDuplicatePuttyConnectionNode()
{
var connectionTreeModel = new ConnectionTreeModel();
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
var puttyConnection = new PuttySessionInfo();
puttyRoot.AddChild(puttyConnection);
connectionTreeModel.AddRootNode(puttyRoot);
_connectionTree.ConnectionTreeModel = connectionTreeModel;
_connectionTree.ExpandAll();
_connectionTree.SelectedObject = puttyConnection;
_connectionTree.DuplicateSelectedNode();
Assert.That(puttyRoot.Children, Has.One.Items);
}
[Test]
[Apartment(ApartmentState.STA)]
public void DuplicatingWithNoNodeSelectedDoesNothing()
{
var connectionTreeModel = new ConnectionTreeModel();
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
connectionTreeModel.AddRootNode(puttyRoot);
_connectionTree.ConnectionTreeModel = connectionTreeModel;
_connectionTree.SelectedObject = null;
_connectionTree.DuplicateSelectedNode();
Assert.That(connectionTreeModel.RootNodes, Has.One.Items);
}
[Test]
[Apartment(ApartmentState.STA)]
public void ExpandingAllItemsUpdatesColumnWidthAppropriately()
{
var connectionTreeModel = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
connectionTreeModel.AddRootNode(root);
ContainerInfo parent = root;
foreach (var i in Enumerable.Repeat("", 8))
{
var newContainer = new ContainerInfo {IsExpanded = false};
parent.AddChild(newContainer);
parent = newContainer;
}
_connectionTree.ConnectionTreeModel = connectionTreeModel;
var widthBefore = _connectionTree.Columns[0].Width;
_connectionTree.ExpandAll();
var widthAfter = _connectionTree.Columns[0].Width;
Assert.That(widthAfter, Is.GreaterThan(widthBefore));
}
}
}

View File

@@ -209,6 +209,7 @@
<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">
<SubType>Form</SubType>

View File

@@ -33,16 +33,19 @@ Global
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|Any CPU.ActiveCfg = Debug Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|Any CPU.Build.0 = Debug Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.Build.0 = Debug Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|Any CPU.ActiveCfg = Debug|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|Any CPU.Build.0 = Debug|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.ActiveCfg = Debug|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.Build.0 = Debug|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.ActiveCfg = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.Build.0 = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.ActiveCfg = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.Build.0 = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.ActiveCfg = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.Build.0 = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|Any CPU.Build.0 = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.ActiveCfg = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.Build.0 = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|Any CPU.ActiveCfg = Release|x86
@@ -50,24 +53,26 @@ Global
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.ActiveCfg = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.Build.0 = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|Any CPU.ActiveCfg = Debug Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|Any CPU.Build.0 = Debug Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.Build.0 = Debug Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|Any CPU.ActiveCfg = Debug|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|Any CPU.Build.0 = Debug|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.ActiveCfg = Debug|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.Build.0 = Debug|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.ActiveCfg = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.Build.0 = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.ActiveCfg = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.Build.0 = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.ActiveCfg = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.Build.0 = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|Any CPU.Build.0 = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.ActiveCfg = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.Build.0 = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|Any CPU.ActiveCfg = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|Any CPU.Build.0 = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.ActiveCfg = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.Build.0 = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.Build.0 = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.ActiveCfg = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|x86.ActiveCfg = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|Any CPU.ActiveCfg = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x86.ActiveCfg = Debug|x86
@@ -77,7 +82,6 @@ Global
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.Build.0 = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|Any CPU.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|Any CPU.Build.0 = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|x86.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|Any CPU.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|Any CPU.Build.0 = Release|x86
@@ -86,8 +90,8 @@ Global
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|Any CPU.ActiveCfg = Debug|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x86.ActiveCfg = Debug|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.ActiveCfg = Release Portable|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.Build.0 = Release Portable|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.ActiveCfg = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.Build.0 = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.ActiveCfg = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.Build.0 = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86

View File

@@ -20,10 +20,9 @@ namespace mRemoteNG.Config.Connections
private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
{
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged;
connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
{
oldTree.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
@@ -45,7 +44,8 @@ namespace mRemoteNG.Config.Connections
{
if (!mRemoteNG.Settings.Default.SaveConnectionsAfterEveryEdit)
return;
_connectionsService.SaveConnections();
_connectionsService.SaveConnectionsAsync();
}
}
}

View File

@@ -1,14 +1,14 @@
using System.Security;
using System.Windows.Forms;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
namespace mRemoteNG.Config.Connections
{
public class XmlConnectionsLoader
public class XmlConnectionsLoader
{
private readonly IConnectionsService _connectionsService;
private readonly string _connectionFilePath;
@@ -29,7 +29,7 @@ namespace mRemoteNG.Config.Connections
return deserializer.Deserialize(xmlString);
}
private SecureString PromptForPassword()
private Optional<SecureString> PromptForPassword()
{
return MiscTools.PasswordDialog("", false);
}

View File

@@ -1,26 +1,29 @@
using System;
using System.IO;
using System.IO;
using System.Linq;
namespace mRemoteNG.Config.DataProviders
{
public class FileBackupPruner
{
public void PruneBackupFiles(string baseName)
public void PruneBackupFiles(string filePath, int maxBackupsToKeep)
{
var fileName = Path.GetFileName(baseName);
var directoryName = Path.GetDirectoryName(baseName);
var fileName = Path.GetFileName(filePath);
var directoryName = Path.GetDirectoryName(filePath);
if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(directoryName)) return;
if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(directoryName))
return;
var searchPattern = string.Format(mRemoteNG.Settings.Default.BackupFileNameFormat, fileName, "*");
var files = Directory.GetFiles(directoryName, searchPattern);
if (files.Length <= mRemoteNG.Settings.Default.BackupFileKeepCount) return;
if (files.Length <= maxBackupsToKeep)
return;
Array.Sort(files);
Array.Resize(ref files, files.Length - mRemoteNG.Settings.Default.BackupFileKeepCount);
var filesToDelete = files
.OrderByDescending(s => s)
.Skip(maxBackupsToKeep);
foreach (var file in files)
foreach (var file in filesToDelete)
{
File.Delete(file);
}

View File

@@ -21,7 +21,7 @@ using mRemoteNG.UI.TaskDialog;
namespace mRemoteNG.Config.Serializers.Xml
{
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
{
private readonly IConnectionsService _connectionsService;
private XmlDocument _xmlDocument;
@@ -32,9 +32,9 @@ namespace mRemoteNG.Config.Serializers.Xml
private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection);
private readonly IWin32Window _dialogWindowParent;
public Func<SecureString> AuthenticationRequestor { get; set; }
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
public XmlConnectionsDeserializer(IConnectionsService connectionsService, IWin32Window dialogWindowParent, Func<SecureString> authenticationRequestor = null)
public XmlConnectionsDeserializer(IConnectionsService connectionsService, IWin32Window dialogWindowParent, Func<Optional<SecureString>> authenticationRequestor = null)
{
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
_dialogWindowParent = dialogWindowParent.ThrowIfNull(nameof(dialogWindowParent));
@@ -52,8 +52,6 @@ namespace mRemoteNG.Config.Serializers.Xml
{
LoadXmlConnectionData(xml);
ValidateConnectionFileVersion();
if (!import)
_connectionsService.IsConnectionsFileLoaded = false;
var rootXmlElement = _xmlDocument.DocumentElement;
InitializeRootNode(rootXmlElement);
@@ -67,8 +65,6 @@ namespace mRemoteNG.Config.Serializers.Xml
var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value;
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString()))
{
mRemoteNG.Settings.Default.LoadConsFromCustomLocation = false;
mRemoteNG.Settings.Default.CustomConsPath = "";
return null;
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
@@ -7,8 +9,6 @@ using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using System.Security.Cryptography;
using System.Text;
namespace mRemoteNG.Config.Serializers
@@ -60,7 +60,7 @@ namespace mRemoteNG.Config.Serializers
}
else
{
var versionNode = rdcManNode.SelectSingleNode("./version")?.InnerText;
var versionNode = rdcManNode?.SelectSingleNode("./version")?.InnerText;
if (versionNode != null)
{
var version = new Version(versionNode);
@@ -101,15 +101,16 @@ namespace mRemoteNG.Config.Serializers
{
if (_schemaVersion == 1)
{
// Program Verison 2.2 wraps all setting inside the Properties tags
// Program Version 2.2 wraps all setting inside the Properties tags
containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties");
}
var newContainer = new ContainerInfo();
var connectionInfo = ConnectionInfoFromXml(containerPropertiesNode);
newContainer.CopyFrom(connectionInfo);
if (_schemaVersion == 3)
{
// Program Verison 2.7 wraps these properties
// Program Version 2.7 wraps these properties
containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties");
}
newContainer.Name = containerPropertiesNode?.SelectSingleNode("./name")?.InnerText ?? Language.strNewFolder;
@@ -130,20 +131,22 @@ namespace mRemoteNG.Config.Serializers
var propertiesNode = xmlNode.SelectSingleNode("./properties");
if (_schemaVersion == 1) propertiesNode = xmlNode; // Version 2.2 defines the container name at the root instead
connectionInfo.Hostname = propertiesNode.SelectSingleNode("./name")?.InnerText;
connectionInfo.Name = propertiesNode.SelectSingleNode("./displayName")?.InnerText ?? connectionInfo.Hostname;
connectionInfo.Description = propertiesNode.SelectSingleNode("./comment")?.InnerText ?? String.Empty;
if (_schemaVersion == 1) propertiesNode = xmlNode; // Version 2.2 defines the container name at the root instead
connectionInfo.Hostname = propertiesNode?.SelectSingleNode("./name")?.InnerText ?? "";
connectionInfo.Name = propertiesNode?.SelectSingleNode("./displayName")?.InnerText ?? connectionInfo.Hostname;
connectionInfo.Description = propertiesNode?.SelectSingleNode("./comment")?.InnerText ?? string.Empty;
var logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials");
if (logonCredentialsNode?.Attributes?["inherit"].Value == "None")
if (logonCredentialsNode?.Attributes?["inherit"]?.Value == "None")
{
connectionInfo.Username = logonCredentialsNode.SelectSingleNode("userName")?.InnerText;
var passwordNode = logonCredentialsNode.SelectSingleNode("./password");
if (_schemaVersion == 1) // Version 2.2 allows clear text passwords
{
connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"].Value == "True" ? passwordNode.InnerText : DecryptRdcManPassword(passwordNode?.InnerText);
connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
? passwordNode.InnerText
: DecryptRdcManPassword(passwordNode?.InnerText);
}
else
{
@@ -160,7 +163,7 @@ namespace mRemoteNG.Config.Serializers
}
var connectionSettingsNode = xmlNode.SelectSingleNode("./connectionSettings");
if (connectionSettingsNode?.Attributes?["inherit"].Value == "None")
if (connectionSettingsNode?.Attributes?["inherit"]?.Value == "None")
{
connectionInfo.UseConsoleSession = bool.Parse(connectionSettingsNode.SelectSingleNode("./connectToConsole")?.InnerText ?? "false");
// ./startProgram
@@ -174,7 +177,7 @@ namespace mRemoteNG.Config.Serializers
}
var gatewaySettingsNode = xmlNode.SelectSingleNode("./gatewaySettings");
if (gatewaySettingsNode?.Attributes?["inherit"].Value == "None")
if (gatewaySettingsNode?.Attributes?["inherit"]?.Value == "None")
{
connectionInfo.RDGatewayUsageMethod = gatewaySettingsNode.SelectSingleNode("./enabled")?.InnerText == "True" ? RdpProtocol.RDGatewayUsageMethod.Always : RdpProtocol.RDGatewayUsageMethod.Never;
connectionInfo.RDGatewayHostname = gatewaySettingsNode.SelectSingleNode("./hostName")?.InnerText;
@@ -198,7 +201,7 @@ namespace mRemoteNG.Config.Serializers
}
var remoteDesktopNode = xmlNode.SelectSingleNode("./remoteDesktop");
if (remoteDesktopNode?.Attributes?["inherit"].Value == "None")
if (remoteDesktopNode?.Attributes?["inherit"]?.Value == "None")
{
var resolutionString = remoteDesktopNode.SelectSingleNode("./size")?.InnerText.Replace(" ", "");
try
@@ -231,7 +234,7 @@ namespace mRemoteNG.Config.Serializers
}
var localResourcesNode = xmlNode.SelectSingleNode("./localResources");
if (localResourcesNode?.Attributes?["inherit"].Value == "None")
if (localResourcesNode?.Attributes?["inherit"]?.Value == "None")
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (localResourcesNode.SelectSingleNode("./audioRedirection")?.InnerText)
@@ -271,10 +274,10 @@ namespace mRemoteNG.Config.Serializers
}
// ./redirectClipboard
connectionInfo.RedirectDiskDrives = bool.Parse(localResourcesNode.SelectSingleNode("./redirectDrives")?.InnerText ?? "false");
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.RedirectDiskDrives = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectDrives")?.InnerText ?? "false");
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");
}
else
{
@@ -287,7 +290,7 @@ namespace mRemoteNG.Config.Serializers
}
var securitySettingsNode = xmlNode.SelectSingleNode("./securitySettings");
if (securitySettingsNode?.Attributes?["inherit"].Value == "None")
if (securitySettingsNode?.Attributes?["inherit"]?.Value == "None")
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (securitySettingsNode.SelectSingleNode("./authentication")?.InnerText)
@@ -321,7 +324,7 @@ namespace mRemoteNG.Config.Serializers
private static string DecryptRdcManPassword(string ciphertext)
{
if (string.IsNullOrEmpty(ciphertext))
return null;
return string.Empty;
try
{
@@ -332,7 +335,7 @@ namespace mRemoteNG.Config.Serializers
catch (Exception /*ex*/)
{
//Runtime.MessageCollector.AddExceptionMessage("RemoteDesktopConnectionManager.DecryptPassword() failed.", ex, logOnly: true);
return null;
return string.Empty;
}
}
}

View File

@@ -4,6 +4,7 @@ using mRemoteNG.Security;
using mRemoteNG.Security.Authentication;
using mRemoteNG.Security.Factories;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Serializers
@@ -13,7 +14,7 @@ namespace mRemoteNG.Config.Serializers
private readonly ICryptographyProvider _cryptographyProvider;
private readonly RootNodeInfo _rootNodeInfo;
public Func<SecureString> AuthenticationRequestor { get; set; }
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
public int KeyDerivationIterations
{
@@ -91,16 +92,14 @@ namespace mRemoteNG.Config.Serializers
private bool Authenticate(string cipherText, SecureString password)
{
var authenticator = new PasswordAuthenticator(_cryptographyProvider, cipherText)
{
AuthenticationRequestor = AuthenticationRequestor
};
var authenticator = new PasswordAuthenticator(_cryptographyProvider, cipherText, AuthenticationRequestor);
var authenticated = authenticator.Authenticate(password);
if (!authenticated) return authenticated;
if (!authenticated)
return false;
_rootNodeInfo.PasswordString = authenticator.LastAuthenticatedPassword.ConvertToUnsecureString();
return authenticated;
return true;
}
}
}

View File

@@ -87,8 +87,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionName")]
public virtual string Name
{
get { return _name; }
set { SetField(ref _name, value, "Name"); }
get => _name;
set => SetField(ref _name, value, "Name");
}
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
@@ -96,8 +96,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDescription")]
public virtual string Description
{
get { return GetPropertyValue("Description", _description); }
set { SetField(ref _description, value, "Description"); }
get => GetPropertyValue("Description", _description);
set => SetField(ref _description, value, "Description");
}
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
@@ -106,8 +106,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionIcon")]
public virtual string Icon
{
get { return GetPropertyValue("Icon", _icon); }
set { SetField(ref _icon, value, "Icon"); }
get => GetPropertyValue("Icon", _icon);
set => SetField(ref _icon, value, "Icon");
}
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
@@ -115,8 +115,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPanel")]
public virtual string Panel
{
get { return GetPropertyValue("Panel", _panel); }
set { SetField(ref _panel, value, "Panel"); }
get => GetPropertyValue("Panel", _panel);
set => SetField(ref _panel, value, "Panel");
}
#endregion
@@ -126,8 +126,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAddress")]
public virtual string Hostname
{
get { return _hostname.Trim(); }
set { SetField(ref _hostname, value?.Trim(), "Hostname"); }
get => _hostname.Trim();
set => SetField(ref _hostname, value?.Trim(), "Hostname");
}
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
@@ -135,8 +135,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUsername")]
public virtual string Username
{
get { return GetPropertyValue("Username", _username); }
set { SetField(ref _username, value?.Trim(), "Username"); }
get => GetPropertyValue("Username", _username);
set => SetField(ref _username, value?.Trim(), "Username");
}
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
@@ -145,8 +145,8 @@ namespace mRemoteNG.Connection
PasswordPropertyText(true)]
public virtual string Password
{
get { return GetPropertyValue("Password", _password); }
set { SetField(ref _password, value, "Password"); }
get => GetPropertyValue("Password", _password);
set => SetField(ref _password, value, "Password");
}
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
@@ -154,8 +154,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDomain")]
public string Domain
{
get { return GetPropertyValue("Domain", _domain).Trim(); }
set { SetField(ref _domain, value?.Trim(), "Domain"); }
get => GetPropertyValue("Domain", _domain).Trim();
set => SetField(ref _domain, value?.Trim(), "Domain");
}
#endregion
@@ -166,8 +166,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public virtual ProtocolType Protocol
{
get { return GetPropertyValue("Protocol", _protocol); }
set { SetField(ref _protocol, value, "Protocol"); }
get => GetPropertyValue("Protocol", _protocol);
set => SetField(ref _protocol, value, "Protocol");
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -176,8 +176,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(ExternalToolsTypeConverter))]
public string ExtApp
{
get { return GetPropertyValue("ExtApp", _extApp); }
set { SetField(ref _extApp, value, "ExtApp"); }
get => GetPropertyValue("ExtApp", _extApp);
set => SetField(ref _extApp, value, "ExtApp");
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -185,8 +185,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPort")]
public virtual int Port
{
get { return GetPropertyValue("Port", _port); }
set { SetField(ref _port, value, "Port"); }
get => GetPropertyValue("Port", _port);
set => SetField(ref _port, value, "Port");
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -195,8 +195,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(Config.Putty.PuttySessionsManager.SessionList))]
public virtual string PuttySession
{
get { return GetPropertyValue("PuttySession", _puttySession); }
set { SetField(ref _puttySession, value, "PuttySession"); }
get => GetPropertyValue("PuttySession", _puttySession);
set => SetField(ref _puttySession, value, "PuttySession");
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -205,8 +205,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public IcaProtocol.EncryptionStrength ICAEncryptionStrength
{
get { return GetPropertyValue("ICAEncryptionStrength", _icaEncryption); }
set { SetField(ref _icaEncryption, value, "ICAEncryptionStrength"); }
get => GetPropertyValue("ICAEncryptionStrength", _icaEncryption);
set => SetField(ref _icaEncryption, value, "ICAEncryptionStrength");
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -215,8 +215,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool UseConsoleSession
{
get { return GetPropertyValue("UseConsoleSession", _useConsoleSession); }
set { SetField(ref _useConsoleSession, value, "UseConsoleSession"); }
get => GetPropertyValue("UseConsoleSession", _useConsoleSession);
set => SetField(ref _useConsoleSession, value, "UseConsoleSession");
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -225,8 +225,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.AuthenticationLevel RDPAuthenticationLevel
{
get { return GetPropertyValue("RDPAuthenticationLevel", _rdpAuthenticationLevel); }
set { SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel"); }
get => GetPropertyValue("RDPAuthenticationLevel", _rdpAuthenticationLevel);
set => SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel");
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -234,7 +234,7 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPMinutesToIdleTimeout")]
public virtual int RDPMinutesToIdleTimeout
{
get { return GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout); }
get => GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout);
set {
if(value < 0)
value = 0;
@@ -249,8 +249,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPAlertIdleTimeout")]
public bool RDPAlertIdleTimeout
{
get { return GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout); }
set { SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout"); }
get => GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout);
set => SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout");
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -258,8 +258,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionLoadBalanceInfo")]
public string LoadBalanceInfo
{
get { return GetPropertyValue("LoadBalanceInfo", _loadBalanceInfo).Trim(); }
set { SetField(ref _loadBalanceInfo, value?.Trim(), "LoadBalanceInfo"); }
get => GetPropertyValue("LoadBalanceInfo", _loadBalanceInfo).Trim();
set => SetField(ref _loadBalanceInfo, value?.Trim(), "LoadBalanceInfo");
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -268,8 +268,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public HTTPBase.RenderingEngine RenderingEngine
{
get { return GetPropertyValue("RenderingEngine", _renderingEngine); }
set { SetField(ref _renderingEngine, value, "RenderingEngine"); }
get => GetPropertyValue("RenderingEngine", _renderingEngine);
set => SetField(ref _renderingEngine, value, "RenderingEngine");
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -278,8 +278,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool UseCredSsp
{
get { return GetPropertyValue("UseCredSsp", _useCredSsp); }
set { SetField(ref _useCredSsp, value, "UseCredSsp"); }
get => GetPropertyValue("UseCredSsp", _useCredSsp);
set => SetField(ref _useCredSsp, value, "UseCredSsp");
}
#endregion
@@ -290,8 +290,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDGatewayUsageMethod RDGatewayUsageMethod
{
get { return GetPropertyValue("RDGatewayUsageMethod", _rdGatewayUsageMethod); }
set { SetField(ref _rdGatewayUsageMethod, value, "RDGatewayUsageMethod"); }
get => GetPropertyValue("RDGatewayUsageMethod", _rdGatewayUsageMethod);
set => SetField(ref _rdGatewayUsageMethod, value, "RDGatewayUsageMethod");
}
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
@@ -299,8 +299,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayHostname")]
public string RDGatewayHostname
{
get { return GetPropertyValue("RDGatewayHostname", _rdGatewayHostname).Trim(); }
set { SetField(ref _rdGatewayHostname, value?.Trim(), "RDGatewayHostname"); }
get => GetPropertyValue("RDGatewayHostname", _rdGatewayHostname).Trim();
set => SetField(ref _rdGatewayHostname, value?.Trim(), "RDGatewayHostname");
}
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
@@ -309,8 +309,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDGatewayUseConnectionCredentials RDGatewayUseConnectionCredentials
{
get { return GetPropertyValue("RDGatewayUseConnectionCredentials", _rdGatewayUseConnectionCredentials); }
set { SetField(ref _rdGatewayUseConnectionCredentials, value, "RDGatewayUseConnectionCredentials"); }
get => GetPropertyValue("RDGatewayUseConnectionCredentials", _rdGatewayUseConnectionCredentials);
set => SetField(ref _rdGatewayUseConnectionCredentials, value, "RDGatewayUseConnectionCredentials");
}
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
@@ -318,8 +318,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUsername")]
public string RDGatewayUsername
{
get { return GetPropertyValue("RDGatewayUsername", _rdGatewayUsername).Trim(); }
set { SetField(ref _rdGatewayUsername, value?.Trim(), "RDGatewayUsername"); }
get => GetPropertyValue("RDGatewayUsername", _rdGatewayUsername).Trim();
set => SetField(ref _rdGatewayUsername, value?.Trim(), "RDGatewayUsername");
}
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
@@ -328,8 +328,8 @@ namespace mRemoteNG.Connection
PasswordPropertyText(true)]
public string RDGatewayPassword
{
get { return GetPropertyValue("RDGatewayPassword", _rdGatewayPassword); }
set { SetField(ref _rdGatewayPassword, value, "RDGatewayPassword"); }
get => GetPropertyValue("RDGatewayPassword", _rdGatewayPassword);
set => SetField(ref _rdGatewayPassword, value, "RDGatewayPassword");
}
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
@@ -337,8 +337,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayDomain")]
public string RDGatewayDomain
{
get { return GetPropertyValue("RDGatewayDomain", _rdGatewayDomain).Trim(); }
set { SetField(ref _rdGatewayDomain, value?.Trim(), "RDGatewayDomain"); }
get => GetPropertyValue("RDGatewayDomain", _rdGatewayDomain).Trim();
set => SetField(ref _rdGatewayDomain, value?.Trim(), "RDGatewayDomain");
}
#endregion
@@ -349,8 +349,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDPResolutions Resolution
{
get { return GetPropertyValue("Resolution", _resolution); }
set { SetField(ref _resolution, value, "Resolution"); }
get => GetPropertyValue("Resolution", _resolution);
set => SetField(ref _resolution, value, "Resolution");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -359,8 +359,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool AutomaticResize
{
get { return GetPropertyValue("AutomaticResize", _automaticResize); }
set { SetField(ref _automaticResize, value, "AutomaticResize"); }
get => GetPropertyValue("AutomaticResize", _automaticResize);
set => SetField(ref _automaticResize, value, "AutomaticResize");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -369,8 +369,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDPColors Colors
{
get { return GetPropertyValue("Colors", _colors); }
set { SetField(ref _colors, value, "Colors"); }
get => GetPropertyValue("Colors", _colors);
set => SetField(ref _colors, value, "Colors");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -379,8 +379,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool CacheBitmaps
{
get { return GetPropertyValue("CacheBitmaps", _cacheBitmaps); }
set { SetField(ref _cacheBitmaps, value, "CacheBitmaps"); }
get => GetPropertyValue("CacheBitmaps", _cacheBitmaps);
set => SetField(ref _cacheBitmaps, value, "CacheBitmaps");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -389,8 +389,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool DisplayWallpaper
{
get { return GetPropertyValue("DisplayWallpaper", _displayWallpaper); }
set { SetField(ref _displayWallpaper, value, "DisplayWallpaper"); }
get => GetPropertyValue("DisplayWallpaper", _displayWallpaper);
set => SetField(ref _displayWallpaper, value, "DisplayWallpaper");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -399,8 +399,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool DisplayThemes
{
get { return GetPropertyValue("DisplayThemes", _displayThemes); }
set { SetField(ref _displayThemes, value, "DisplayThemes"); }
get => GetPropertyValue("DisplayThemes", _displayThemes);
set => SetField(ref _displayThemes, value, "DisplayThemes");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -409,8 +409,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool EnableFontSmoothing
{
get { return GetPropertyValue("EnableFontSmoothing", _enableFontSmoothing); }
set { SetField(ref _enableFontSmoothing, value, "EnableFontSmoothing"); }
get => GetPropertyValue("EnableFontSmoothing", _enableFontSmoothing);
set => SetField(ref _enableFontSmoothing, value, "EnableFontSmoothing");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -419,8 +419,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool EnableDesktopComposition
{
get { return GetPropertyValue("EnableDesktopComposition", _enableDesktopComposition); }
set { SetField(ref _enableDesktopComposition, value, "EnableDesktopComposition"); }
get => GetPropertyValue("EnableDesktopComposition", _enableDesktopComposition);
set => SetField(ref _enableDesktopComposition, value, "EnableDesktopComposition");
}
#endregion
@@ -431,8 +431,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectKeys
{
get { return GetPropertyValue("RedirectKeys", _redirectKeys); }
set { SetField(ref _redirectKeys, value, "RedirectKeys"); }
get => GetPropertyValue("RedirectKeys", _redirectKeys);
set => SetField(ref _redirectKeys, value, "RedirectKeys");
}
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -441,8 +441,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectDiskDrives
{
get { return GetPropertyValue("RedirectDiskDrives", _redirectDiskDrives); }
set { SetField(ref _redirectDiskDrives, value, "RedirectDiskDrives"); }
get => GetPropertyValue("RedirectDiskDrives", _redirectDiskDrives);
set => SetField(ref _redirectDiskDrives, value, "RedirectDiskDrives");
}
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -451,8 +451,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectPrinters
{
get { return GetPropertyValue("RedirectPrinters", _redirectPrinters); }
set { SetField(ref _redirectPrinters, value, "RedirectPrinters"); }
get => GetPropertyValue("RedirectPrinters", _redirectPrinters);
set => SetField(ref _redirectPrinters, value, "RedirectPrinters");
}
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -461,8 +461,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectPorts
{
get { return GetPropertyValue("RedirectPorts", _redirectPorts); }
set { SetField(ref _redirectPorts, value, "RedirectPorts"); }
get => GetPropertyValue("RedirectPorts", _redirectPorts);
set => SetField(ref _redirectPorts, value, "RedirectPorts");
}
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -471,8 +471,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectSmartCards
{
get { return GetPropertyValue("RedirectSmartCards", _redirectSmartCards); }
set { SetField(ref _redirectSmartCards, value, "RedirectSmartCards"); }
get => GetPropertyValue("RedirectSmartCards", _redirectSmartCards);
set => SetField(ref _redirectSmartCards, value, "RedirectSmartCards");
}
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -481,8 +481,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDPSounds RedirectSound
{
get { return GetPropertyValue("RedirectSound", _redirectSound); }
set { SetField(ref _redirectSound, value, "RedirectSound"); }
get => GetPropertyValue("RedirectSound", _redirectSound);
set => SetField(ref _redirectSound, value, "RedirectSound");
}
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -491,8 +491,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDPSoundQuality SoundQuality
{
get { return GetPropertyValue("SoundQuality", _soundQuality); }
set { SetField(ref _soundQuality, value, "SoundQuality"); }
get => GetPropertyValue("SoundQuality", _soundQuality);
set => SetField(ref _soundQuality, value, "SoundQuality");
}
#endregion
@@ -506,8 +506,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(ExternalToolsTypeConverter))]
public virtual string PreExtApp
{
get { return GetPropertyValue("PreExtApp", _preExtApp); }
set { SetField(ref _preExtApp, value, "PreExtApp"); }
get => GetPropertyValue("PreExtApp", _preExtApp);
set => SetField(ref _preExtApp, value, "PreExtApp");
}
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -516,8 +516,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(ExternalToolsTypeConverter))]
public virtual string PostExtApp
{
get { return GetPropertyValue("PostExtApp", _postExtApp); }
set { SetField(ref _postExtApp, value, "PostExtApp"); }
get => GetPropertyValue("PostExtApp", _postExtApp);
set => SetField(ref _postExtApp, value, "PostExtApp");
}
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -525,8 +525,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionMACAddress")]
public virtual string MacAddress
{
get { return GetPropertyValue("MacAddress", _macAddress); }
set { SetField(ref _macAddress, value, "MacAddress"); }
get => GetPropertyValue("MacAddress", _macAddress);
set => SetField(ref _macAddress, value, "MacAddress");
}
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -534,8 +534,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUser1")]
public virtual string UserField
{
get { return GetPropertyValue("UserField", _userField); }
set { SetField(ref _userField, value, "UserField"); }
get => GetPropertyValue("UserField", _userField);
set => SetField(ref _userField, value, "UserField");
}
#endregion
@@ -547,8 +547,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.Compression VNCCompression
{
get { return GetPropertyValue("VNCCompression", _vncCompression); }
set { SetField(ref _vncCompression, value, "VNCCompression"); }
get => GetPropertyValue("VNCCompression", _vncCompression);
set => SetField(ref _vncCompression, value, "VNCCompression");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -558,8 +558,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.Encoding VNCEncoding
{
get { return GetPropertyValue("VNCEncoding", _vncEncoding); }
set { SetField(ref _vncEncoding, value, "VNCEncoding"); }
get => GetPropertyValue("VNCEncoding", _vncEncoding);
set => SetField(ref _vncEncoding, value, "VNCEncoding");
}
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
@@ -569,8 +569,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.AuthMode VNCAuthMode
{
get { return GetPropertyValue("VNCAuthMode", _vncAuthMode); }
set { SetField(ref _vncAuthMode, value, "VNCAuthMode"); }
get => GetPropertyValue("VNCAuthMode", _vncAuthMode);
set => SetField(ref _vncAuthMode, value, "VNCAuthMode");
}
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -580,8 +580,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.ProxyType VNCProxyType
{
get { return GetPropertyValue("VNCProxyType", _vncProxyType); }
set { SetField(ref _vncProxyType, value, "VNCProxyType"); }
get => GetPropertyValue("VNCProxyType", _vncProxyType);
set => SetField(ref _vncProxyType, value, "VNCProxyType");
}
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -590,8 +590,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyAddress")]
public string VNCProxyIP
{
get { return GetPropertyValue("VNCProxyIP", _vncProxyIp); }
set { SetField(ref _vncProxyIp, value, "VNCProxyIP"); }
get => GetPropertyValue("VNCProxyIP", _vncProxyIp);
set => SetField(ref _vncProxyIp, value, "VNCProxyIP");
}
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -600,8 +600,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyPort")]
public int VNCProxyPort
{
get { return GetPropertyValue("VNCProxyPort", _vncProxyPort); }
set { SetField(ref _vncProxyPort, value, "VNCProxyPort"); }
get => GetPropertyValue("VNCProxyPort", _vncProxyPort);
set => SetField(ref _vncProxyPort, value, "VNCProxyPort");
}
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -610,8 +610,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyUsername")]
public string VNCProxyUsername
{
get { return GetPropertyValue("VNCProxyUsername", _vncProxyUsername); }
set { SetField(ref _vncProxyUsername, value, "VNCProxyUsername"); }
get => GetPropertyValue("VNCProxyUsername", _vncProxyUsername);
set => SetField(ref _vncProxyUsername, value, "VNCProxyUsername");
}
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -621,8 +621,8 @@ namespace mRemoteNG.Connection
PasswordPropertyText(true)]
public string VNCProxyPassword
{
get { return GetPropertyValue("VNCProxyPassword", _vncProxyPassword); }
set { SetField(ref _vncProxyPassword, value, "VNCProxyPassword"); }
get => GetPropertyValue("VNCProxyPassword", _vncProxyPassword);
set => SetField(ref _vncProxyPassword, value, "VNCProxyPassword");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -632,8 +632,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.Colors VNCColors
{
get { return GetPropertyValue("VNCColors", _vncColors); }
set { SetField(ref _vncColors, value, "VNCColors"); }
get => GetPropertyValue("VNCColors", _vncColors);
set => SetField(ref _vncColors, value, "VNCColors");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -642,8 +642,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.SmartSizeMode VNCSmartSizeMode
{
get { return GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode); }
set { SetField(ref _vncSmartSizeMode, value, "VNCSmartSizeMode"); }
get => GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode);
set => SetField(ref _vncSmartSizeMode, value, "VNCSmartSizeMode");
}
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -652,8 +652,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool VNCViewOnly
{
get { return GetPropertyValue("VNCViewOnly", _vncViewOnly); }
set { SetField(ref _vncViewOnly, value, "VNCViewOnly"); }
get => GetPropertyValue("VNCViewOnly", _vncViewOnly);
set => SetField(ref _vncViewOnly, value, "VNCViewOnly");
}
#endregion
#endregion
@@ -665,7 +665,7 @@ namespace mRemoteNG.Connection
protected virtual TPropertyType GetPropertyValue<TPropertyType>(string propertyName, TPropertyType value)
{
return (TPropertyType)GetType().GetProperty(propertyName).GetValue(this, null);
return (TPropertyType)GetType().GetProperty(propertyName)?.GetValue(this, null);
}
public event PropertyChangedEventHandler PropertyChanged;
@@ -674,12 +674,11 @@ namespace mRemoteNG.Connection
PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(args.PropertyName));
}
protected bool 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 false;
if (EqualityComparer<T>.Default.Equals(field, value)) return;
field = value;
RaisePropertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
return true;
}
}
}

View File

@@ -173,9 +173,7 @@ namespace mRemoteNG.Connection
return value;
var inheritedValue = GetInheritedPropertyValue<TPropertyType>(propertyName);
if (inheritedValue.Equals(default(TPropertyType)))
return value;
return inheritedValue;
return inheritedValue.Equals(default(TPropertyType)) ? value : inheritedValue;
}
private bool ShouldThisPropertyBeInherited(string propertyName)

View File

@@ -8,7 +8,6 @@ using mRemoteNG.App.Info;
using mRemoteNG.Config.Connections;
using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Putty;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Messages;
@@ -17,7 +16,6 @@ using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.TaskDialog;
namespace mRemoteNG.Connection
@@ -29,6 +27,9 @@ namespace mRemoteNG.Connection
private readonly PuttySessionsManager _puttySessionsManager;
private readonly Import _import;
private readonly IWin32Window _dialogWindowParent;
private bool _batchingSaves = false;
private bool _saveRequested = false;
private bool _saveAsyncRequested = false;
public bool IsConnectionsFileLoaded { get; set; }
public bool UsingDatabase { get; private set; }
@@ -58,9 +59,8 @@ namespace mRemoteNG.Connection
{
var newConnectionsModel = new ConnectionTreeModel();
newConnectionsModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename);
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename, true);
LoadConnections(false, false, filename);
UpdateCustomConsPathSetting(filename);
}
catch (Exception ex)
{
@@ -108,16 +108,24 @@ namespace mRemoteNG.Connection
/// <param name="useDatabase"></param>
/// <param name="import"></param>
/// <param name="connectionFileName"></param>
public ConnectionTreeModel LoadConnections(bool useDatabase, bool import, string connectionFileName)
public void LoadConnections(bool useDatabase, bool import, string connectionFileName)
{
var oldConnectionTreeModel = ConnectionTreeModel;
var oldIsUsingDatabaseValue = UsingDatabase;
var newConnectionTreeModel =
(useDatabase
var newConnectionTreeModel = useDatabase
? new SqlConnectionsLoader(DatabaseConnectorFactory, this).Load()
: new XmlConnectionsLoader(connectionFileName, this, _dialogWindowParent).Load())
?? new ConnectionTreeModel();
: new XmlConnectionsLoader(connectionFileName, this, _dialogWindowParent).Load();
if (newConnectionTreeModel == null)
{
DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed", IsConnectionsFileLoaded);
return;
}
IsConnectionsFileLoaded = true;
ConnectionFileName = connectionFileName;
UsingDatabase = useDatabase;
if (!import)
{
@@ -125,12 +133,24 @@ namespace mRemoteNG.Connection
newConnectionTreeModel.RootNodes.AddRange(_puttySessionsManager.RootPuttySessionsNodes);
}
IsConnectionsFileLoaded = true;
ConnectionFileName = connectionFileName;
UsingDatabase = useDatabase;
ConnectionTreeModel = newConnectionTreeModel;
UpdateCustomConsPathSetting(connectionFileName);
RaiseConnectionsLoadedEvent(oldConnectionTreeModel, newConnectionTreeModel, oldIsUsingDatabaseValue, useDatabase, connectionFileName);
return newConnectionTreeModel;
}
public void BeginBatchingSaves()
{
_batchingSaves = true;
}
public void EndBatchingSaves()
{
_batchingSaves = false;
if (_saveAsyncRequested)
SaveConnectionsAsync();
else if(_saveRequested)
SaveConnections();
}
/// <summary>
@@ -139,8 +159,6 @@ namespace mRemoteNG.Connection
/// </summary>
public void SaveConnections()
{
if (!IsConnectionsFileLoaded)
return;
SaveConnections(ConnectionTreeModel, UsingDatabase, new SaveFilter(), ConnectionFileName);
}
@@ -152,12 +170,24 @@ namespace mRemoteNG.Connection
/// <param name="useDatabase"></param>
/// <param name="saveFilter"></param>
/// <param name="connectionFileName"></param>
public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName)
/// <param name="forceSave">Bypasses safety checks that prevent saving if a connection file isn't loaded.</param>
public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName, bool forceSave = false)
{
if (connectionTreeModel == null) return;
if (connectionTreeModel == null)
return;
if (!forceSave && !IsConnectionsFileLoaded)
return;
if (_batchingSaves)
{
_saveRequested = true;
return;
}
try
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Saving connections...");
RemoteConnectionsSyncronizer?.Disable();
var previouslyUsingDatabase = UsingDatabase;
@@ -172,6 +202,7 @@ namespace mRemoteNG.Connection
UsingDatabase = useDatabase;
ConnectionFileName = connectionFileName;
RaiseConnectionsSavedEvent(connectionTreeModel, previouslyUsingDatabase, UsingDatabase, connectionFileName);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Successfully saved connections");
}
catch (Exception ex)
{
@@ -185,6 +216,12 @@ namespace mRemoteNG.Connection
public void SaveConnectionsAsync()
{
if (_batchingSaves)
{
_saveAsyncRequested = true;
return;
}
var t = new Thread(SaveConnectionsBGd);
t.SetApartmentState(ApartmentState.STA);
t.Start();
@@ -233,12 +270,6 @@ namespace mRemoteNG.Connection
{
connectionFileName = GetStartupConnectionFileName();
}
var backupFileCreator = new FileBackupCreator();
backupFileCreator.CreateBackupFile(connectionFileName);
var backupPruner = new FileBackupPruner();
backupPruner.PruneBackupFiles(connectionFileName);
}
LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
@@ -356,12 +387,16 @@ namespace mRemoteNG.Connection
public string GetStartupConnectionFileName()
{
return Settings.Default.LoadConsFromCustomLocation == false ? GetDefaultStartupConnectionFileName() : Settings.Default.CustomConsPath;
return Settings.Default.LoadConsFromCustomLocation == false
? GetDefaultStartupConnectionFileName()
: Settings.Default.CustomConsPath;
}
public string GetDefaultStartupConnectionFileName()
{
return Runtime.IsPortableEdition ? GetDefaultStartupConnectionFileNamePortableEdition() : GetDefaultStartupConnectionFileNameNormalEdition();
return Runtime.IsPortableEdition
? GetDefaultStartupConnectionFileNamePortableEdition()
: GetDefaultStartupConnectionFileNameNormalEdition();
}
private void UpdateCustomConsPathSetting(string filename)

View File

@@ -27,11 +27,11 @@ namespace mRemoteNG.Connection
string GetDefaultStartupConnectionFileName();
string GetStartupConnectionFileName();
void LoadConnections(bool withDialog = false);
ConnectionTreeModel LoadConnections(bool useDatabase, bool import, string connectionFileName);
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);
void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName, bool forceSave = false);
void SaveConnectionsAsync();
}
}

View File

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

View File

@@ -12,7 +12,7 @@ namespace mRemoteNG {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -2698,5 +2698,29 @@ namespace mRemoteNG {
this["MultiSshToolbarVisible"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool CreateEmptyPanelOnStartUp {
get {
return ((bool)(this["CreateEmptyPanelOnStartUp"]));
}
set {
this["CreateEmptyPanelOnStartUp"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("General")]
public string StartUpPanelName {
get {
return ((string)(this["StartUpPanelName"]));
}
set {
this["StartUpPanelName"] = value;
}
}
}
}

View File

@@ -671,5 +671,11 @@
<Setting Name="MultiSshToolbarVisible" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="CreateEmptyPanelOnStartUp" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="StartUpPanelName" Type="System.String" Scope="User">
<Value Profile="(Default)">General</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@@ -1646,6 +1646,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Create an empty panel when mRemoteNG starts.
/// </summary>
internal static string strCreateEmptyPanelOnStartUp {
get {
return ResourceManager.GetString("strCreateEmptyPanelOnStartUp", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Credential Editor.
/// </summary>

View File

@@ -2676,4 +2676,7 @@ This page will walk you through the process of upgrading your connections file o
<data name="strLoadBalanceInfoUseUtf8" xml:space="preserve">
<value>Use UTF8 encoding for RDP "Load Balance Info" property</value>
</data>
<data name="strCreateEmptyPanelOnStartUp" xml:space="preserve">
<value>Create an empty panel when mRemoteNG starts</value>
</data>
</root>

View File

@@ -1,5 +1,7 @@
using System;
using System.Linq;
using System.Security;
using mRemoteNG.Tools;
namespace mRemoteNG.Security.Authentication
{
@@ -7,15 +9,16 @@ namespace mRemoteNG.Security.Authentication
{
private readonly ICryptographyProvider _cryptographyProvider;
private readonly string _cipherText;
private readonly Func<Optional<SecureString>> _authenticationRequestor;
public Func<SecureString> AuthenticationRequestor { get; set; }
public int MaxAttempts { get; set; } = 3;
public SecureString LastAuthenticatedPassword { get; private set; }
public PasswordAuthenticator(ICryptographyProvider cryptographyProvider, string cipherText)
public PasswordAuthenticator(ICryptographyProvider cryptographyProvider, string cipherText, Func<Optional<SecureString>> authenticationRequestor)
{
_cryptographyProvider = cryptographyProvider;
_cipherText = cipherText;
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
_cipherText = cipherText.ThrowIfNullOrEmpty(nameof(cipherText));
_authenticationRequestor = authenticationRequestor.ThrowIfNull(nameof(authenticationRequestor));
}
public bool Authenticate(SecureString password)
@@ -32,7 +35,11 @@ namespace mRemoteNG.Security.Authentication
}
catch
{
password = AuthenticationRequestor?.Invoke();
var providedPassword = _authenticationRequestor();
if (!providedPassword.Any())
return false;
password = providedPassword.First();
if (password == null || password.Length == 0) break;
}
attempts++;

View File

@@ -1,9 +1,10 @@
using System.Security;
using mRemoteNG.Tools;
namespace mRemoteNG.Security
{
public interface IKeyProvider
{
SecureString GetKey();
Optional<SecureString> GetKey();
}
}

View File

@@ -12,7 +12,7 @@ using static System.String;
namespace mRemoteNG.Tools
{
public static class MiscTools
public static class MiscTools
{
public static Icon GetIconFromFile(string FileName)
{
@@ -34,7 +34,7 @@ namespace mRemoteNG.Tools
}
}
public static SecureString PasswordDialog(string passwordName = null, bool verify = true)
public static Optional<SecureString> PasswordDialog(string passwordName = null, bool verify = true)
{
var passwordForm = new PasswordForm(passwordName, verify);
return passwordForm.GetKey();

View File

@@ -1,50 +1,152 @@
using System.Collections;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace mRemoteNG.Tools
{
public class Optional<T> : IEnumerable<T>
{
private readonly T[] _maybe;
/// <summary>
/// Represents a type that may or may not have been assigned a value.
/// A strongly typed collection that contains either 0 or 1 values.
/// </summary>
/// <typeparam name="T">The underlying type that may or may not have a value</typeparam>
public class Optional<T> : IEnumerable<T>, IComparable<Optional<T>>
{
private readonly T[] _optional;
/// <summary>
/// Create a new empty instance of Optional
/// </summary>
public Optional()
{
_maybe = new T[0];
_optional = new T[0];
}
/// <summary>
/// Create a new instance of Optional from the given value.
/// If the value is null, the Optional will be empty
/// </summary>
public Optional(T value)
{
_maybe = value != null
_optional = value != null
? new[] {value}
: new T[0];
}
IEnumerator IEnumerable.GetEnumerator()
public override string ToString()
{
return _optional.Any() ? _optional.First().ToString() : "";
}
public static implicit operator Optional<T>(T value)
{
return new Optional<T>(value);
}
public static Optional<TOut> FromNullable<TOut>(TOut? value) where TOut : struct
{
return value.HasValue
? new Optional<TOut>(value.Value)
: new Optional<TOut>();
}
/// <summary>
/// Returns an empty <see cref="Optional{T}"/>
/// </summary>
public static Optional<T> Empty => new Optional<T>();
#region IEnumerable
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)_maybe).GetEnumerator();
return ((IEnumerable<T>)_optional).GetEnumerator();
}
#endregion
public override string ToString()
#region IComparable
/// <summary>
/// Compares this <see cref="Optional{T}"/> to another instance
/// of the same type. For purposes of comparison, empty Optional
/// objects are treated like Null and will be valued lower than
/// an Optional that contains a value. If both Optionals contain
/// values, the values are compared directly.
/// </summary>
/// <param name="other"></param>
public int CompareTo(Optional<T> other)
{
var otherHasAnything = other.Any();
var thisHasAnything = _optional.Length > 0;
// both are empty, equivalent value
if (!thisHasAnything && !otherHasAnything)
return 0;
// we are empty, they are greater value
if (!thisHasAnything)
return -1;
// they are empty, we are greater value
if (!otherHasAnything)
return 1;
// neither are empty, compare wrapped objects directly
if (_optional[0] is IComparable<T>)
return ((IComparable<T>)_optional[0]).CompareTo(other.First());
throw new ArgumentException(string.Format(
"Cannot compare objects. Optional type {0} is not comparable to itself",
typeof(T).FullName));
}
#endregion
#region Override Equals and GetHashCode
public override bool Equals(object obj)
{
return _maybe.Any() ? _maybe.First().ToString() : "";
if (ReferenceEquals(this, obj))
return true;
var objAsOptional = obj as Optional<T>;
if (objAsOptional != null)
return Equals(objAsOptional);
if (obj is T)
Equals((T)obj);
return false;
}
public static implicit operator Optional<T>(T value)
public bool Equals(Optional<T> other)
{
return new Optional<T>(value);
var otherObj = other.FirstOrDefault();
var thisObj = _optional.FirstOrDefault();
if (thisObj == null && otherObj == null)
return true;
if (thisObj == null)
return false;
return thisObj.Equals(otherObj);
}
public static Optional<TOut> FromNullable<TOut>(TOut? value) where TOut : struct
public override int GetHashCode()
{
return value.HasValue
? new Optional<TOut>(value.Value)
: new Optional<TOut>();
return _optional != null
? _optional.GetHashCode()
: 0;
}
#endregion
#region Operators
public static bool operator ==(Optional<T> left, Optional<T> right)
{
return Equals(left, right);
}
public static bool operator !=(Optional<T> left, Optional<T> right)
{
return !Equals(left, right);
}
#endregion
}
}

View File

@@ -8,7 +8,7 @@ using mRemoteNG.Tree.Root;
namespace mRemoteNG.Tree
{
public sealed class ConnectionTreeModel : INotifyCollectionChanged, INotifyPropertyChanged
public sealed class ConnectionTreeModel : INotifyCollectionChanged, INotifyPropertyChanged
{
public List<ContainerInfo> RootNodes { get; } = new List<ContainerInfo>();

View File

@@ -66,7 +66,9 @@ namespace mRemoteNG.Tree.Root
public override TreeNodeType GetTreeNodeType()
{
return TreeNodeType.Root;
return Type == RootNodeType.Connection
? TreeNodeType.Root
: TreeNodeType.PuttyRoot;
}
#endregion

View File

@@ -17,6 +17,9 @@ namespace mRemoteNG.Tree
public bool Confirm(ConnectionInfo deletionTarget)
{
if (deletionTarget == null)
return false;
var deletionTargetAsContainer = deletionTarget as ContainerInfo;
if (deletionTargetAsContainer != null)
return deletionTargetAsContainer.HasChildren()

View File

@@ -16,7 +16,7 @@ using mRemoteNG.Tree.Root;
namespace mRemoteNG.UI.Controls
{
public partial class ConnectionTree : TreeListView, IConnectionTree
public partial class ConnectionTree : TreeListView, IConnectionTree
{
private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler();
private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance;
@@ -262,6 +262,9 @@ namespace mRemoteNG.UI.Controls
private void AddNode(ConnectionInfo newNode)
{
if (SelectedNode?.GetTreeNodeType() == TreeNodeType.PuttyRoot || SelectedNode?.GetTreeNodeType() == TreeNodeType.PuttySession)
return;
// use root node if no node is selected
ConnectionInfo parentNode = SelectedNode ?? GetRootConnectionNode();
DefaultConnectionInfo.Instance.SaveTo(newNode);
@@ -278,6 +281,13 @@ namespace mRemoteNG.UI.Controls
public void DuplicateSelectedNode()
{
if (SelectedNode == null)
return;
var selectedNodeType = SelectedNode.GetTreeNodeType();
if (selectedNodeType != TreeNodeType.Connection && selectedNodeType != TreeNodeType.Container)
return;
var newNode = SelectedNode.Clone();
SelectedNode.Parent.AddChildBelow(newNode, SelectedNode);
newNode.Parent.SetChildBelow(newNode, SelectedNode);
@@ -301,17 +311,53 @@ namespace mRemoteNG.UI.Controls
if (sortTarget == null)
sortTarget = GetRootConnectionNode();
Runtime.ConnectionsService.BeginBatchingSaves();
var sortTargetAsContainer = sortTarget as ContainerInfo;
if (sortTargetAsContainer != null)
sortTargetAsContainer.SortRecursive(sortDirection);
else
SelectedNode.Parent.SortRecursive(sortDirection);
Runtime.ConnectionsService.EndBatchingSaves();
}
/// <summary>
/// Expands all tree objects and recalculates the
/// column widths.
/// </summary>
public override void ExpandAll()
{
base.ExpandAll();
AutoResizeColumn(Columns[0]);
}
protected override void UpdateFiltering()
{
base.UpdateFiltering();
AutoResizeColumn(Columns[0]);
}
private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
RefreshObject(sender);
// disable filtering if necessary. prevents RefreshObjects from
// throwing an exception
var filteringEnabled = IsFiltering;
var filter = ModelFilter;
if (filteringEnabled)
{
ResetColumnFiltering();
}
RefreshObject(sender);
AutoResizeColumn(Columns[0]);
// turn filtering back on
if (filteringEnabled)
{
ModelFilter = filter;
UpdateFiltering();
}
}
private void OnMouse_DoubleClick(object sender, MouseEventArgs mouseEventArgs)

View File

@@ -1,5 +1,10 @@
using System.Windows.Forms;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.App.Info;
using mRemoteNG.Messages;
using mRemoteNG.UI.TaskDialog;
namespace mRemoteNG.UI
{
@@ -15,5 +20,86 @@ namespace mRemoteNG.UI
Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*"
};
}
/// <summary>
/// Creates and shows a dialog to either create a new connections file, load a different one,
/// exit, or optionally cancel the operation.
/// </summary>
/// <param name="connectionFileName"></param>
/// <param name="messageText"></param>
/// <param name="showCancelButton"></param>
public static void ShowLoadConnectionsFailedDialog(string connectionFileName, string messageText, bool showCancelButton)
{
var commandButtons = new List<string>
{
Language.ConfigurationCreateNew,
Language.strOpenADifferentFile,
Language.strMenuExit
};
if (showCancelButton)
commandButtons.Add(Language.strButtonCancel);
var answered = false;
while (!answered)
{
try
{
CTaskDialog.ShowTaskDialogBox(
GeneralAppInfo.ProductName,
messageText,
"", "", "", "", "",
string.Join(" | ", commandButtons),
ETaskDialogButtons.None,
ESysIcons.Question,
ESysIcons.Question);
switch (CTaskDialog.CommandButtonResult)
{
case 0: // New
var saveAsDialog = ConnectionsSaveAsDialog();
saveAsDialog.ShowDialog();
Runtime.ConnectionsService.NewConnectionsFile(saveAsDialog.FileName);
answered = true;
break;
case 1: // Load
Runtime.LoadConnections(true);
answered = true;
break;
case 2: // Exit
Application.Exit();
answered = true;
break;
case 3: // Cancel
answered = true;
break;
}
}
catch (Exception exception)
{
Runtime.MessageCollector.AddExceptionMessage(
string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName),
exception,
MessageClass.WarningMsg);
}
}
}
/// <summary>
/// Creates a new dialog that allows the user to select an mRemoteNG
/// connections file path. Don't forget to dispose the dialog when you
/// are done!
/// </summary>
public static SaveFileDialog ConnectionsSaveAsDialog()
{
return new SaveFileDialog
{
CheckPathExists = true,
InitialDirectory = ConnectionsFileInfo.DefaultConnectionsPath,
FileName = ConnectionsFileInfo.DefaultConnectionsFile,
OverwritePrompt = true,
Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*"
};
}
}
}

View File

@@ -9,27 +9,27 @@ namespace mRemoteNG.UI.Forms
private void InitializeComponent()
{
this.btnCancel = new Controls.Base.NGButton();
this.btnOK = new Controls.Base.NGButton();
this.lblUncheckProperties = new Controls.Base.NGLabel();
this.chkUsername = new Controls.Base.NGCheckBox();
this.chkPassword = new Controls.Base.NGCheckBox();
this.chkDomain = new Controls.Base.NGCheckBox();
this.chkInheritance = new Controls.Base.NGCheckBox();
this.txtFileName = new Controls.Base.NGTextBox();
this.btnBrowse = new Controls.Base.NGButton();
this.btnCancel = new mRemoteNG.UI.Controls.Base.NGButton();
this.btnOK = new mRemoteNG.UI.Controls.Base.NGButton();
this.lblUncheckProperties = new mRemoteNG.UI.Controls.Base.NGLabel();
this.chkUsername = new mRemoteNG.UI.Controls.Base.NGCheckBox();
this.chkPassword = new mRemoteNG.UI.Controls.Base.NGCheckBox();
this.chkDomain = new mRemoteNG.UI.Controls.Base.NGCheckBox();
this.chkInheritance = new mRemoteNG.UI.Controls.Base.NGCheckBox();
this.txtFileName = new mRemoteNG.UI.Controls.Base.NGTextBox();
this.btnBrowse = new mRemoteNG.UI.Controls.Base.NGButton();
this.grpProperties = new System.Windows.Forms.GroupBox();
this.chkAssignedCredential = new Controls.Base.NGCheckBox();
this.chkAssignedCredential = new mRemoteNG.UI.Controls.Base.NGCheckBox();
this.grpFile = new System.Windows.Forms.GroupBox();
this.lblFileFormat = new Controls.Base.NGLabel();
this.lblFileName = new Controls.Base.NGLabel();
this.cboFileFormat = new Controls.Base.NGComboBox();
this.lblFileFormat = new mRemoteNG.UI.Controls.Base.NGLabel();
this.lblFileName = new mRemoteNG.UI.Controls.Base.NGLabel();
this.cboFileFormat = new mRemoteNG.UI.Controls.Base.NGComboBox();
this.grpItems = new System.Windows.Forms.GroupBox();
this.lblSelectedConnection = new Controls.Base.NGLabel();
this.lblSelectedFolder = new Controls.Base.NGLabel();
this.rdoExportSelectedConnection = new Controls.Base.NGRadioButton();
this.rdoExportSelectedFolder = new Controls.Base.NGRadioButton();
this.rdoExportEverything = new Controls.Base.NGRadioButton();
this.lblSelectedConnection = new mRemoteNG.UI.Controls.Base.NGLabel();
this.lblSelectedFolder = new mRemoteNG.UI.Controls.Base.NGLabel();
this.rdoExportSelectedConnection = new mRemoteNG.UI.Controls.Base.NGRadioButton();
this.rdoExportSelectedFolder = new mRemoteNG.UI.Controls.Base.NGRadioButton();
this.rdoExportEverything = new mRemoteNG.UI.Controls.Base.NGRadioButton();
this.grpProperties.SuspendLayout();
this.grpFile.SuspendLayout();
this.grpItems.SuspendLayout();
@@ -37,6 +37,7 @@ namespace mRemoteNG.UI.Forms
//
// btnCancel
//
this.btnCancel._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER;
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(447, 473);
this.btnCancel.Name = "btnCancel";
@@ -48,6 +49,7 @@ namespace mRemoteNG.UI.Forms
//
// btnOK
//
this.btnOK._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER;
this.btnOK.Location = new System.Drawing.Point(366, 473);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(75, 23);
@@ -67,6 +69,7 @@ namespace mRemoteNG.UI.Forms
//
// chkUsername
//
this.chkUsername._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
this.chkUsername.AutoSize = true;
this.chkUsername.Checked = true;
this.chkUsername.CheckState = System.Windows.Forms.CheckState.Checked;
@@ -79,6 +82,7 @@ namespace mRemoteNG.UI.Forms
//
// chkPassword
//
this.chkPassword._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
this.chkPassword.AutoSize = true;
this.chkPassword.Checked = true;
this.chkPassword.CheckState = System.Windows.Forms.CheckState.Checked;
@@ -91,6 +95,7 @@ namespace mRemoteNG.UI.Forms
//
// chkDomain
//
this.chkDomain._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
this.chkDomain.AutoSize = true;
this.chkDomain.Checked = true;
this.chkDomain.CheckState = System.Windows.Forms.CheckState.Checked;
@@ -103,6 +108,7 @@ namespace mRemoteNG.UI.Forms
//
// chkInheritance
//
this.chkInheritance._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
this.chkInheritance.AutoSize = true;
this.chkInheritance.Checked = true;
this.chkInheritance.CheckState = System.Windows.Forms.CheckState.Checked;
@@ -124,6 +130,7 @@ namespace mRemoteNG.UI.Forms
//
// btnBrowse
//
this.btnBrowse._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER;
this.btnBrowse.Location = new System.Drawing.Point(417, 46);
this.btnBrowse.Name = "btnBrowse";
this.btnBrowse.Size = new System.Drawing.Size(75, 23);
@@ -149,6 +156,7 @@ namespace mRemoteNG.UI.Forms
//
// chkAssignedCredential
//
this.chkAssignedCredential._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
this.chkAssignedCredential.AutoSize = true;
this.chkAssignedCredential.Checked = true;
this.chkAssignedCredential.CheckState = System.Windows.Forms.CheckState.Checked;
@@ -158,6 +166,7 @@ namespace mRemoteNG.UI.Forms
this.chkAssignedCredential.TabIndex = 5;
this.chkAssignedCredential.Text = "Assigned Credential";
this.chkAssignedCredential.UseVisualStyleBackColor = true;
this.chkAssignedCredential.Visible = false;
//
// grpFile
//
@@ -193,7 +202,8 @@ namespace mRemoteNG.UI.Forms
//
// cboFileFormat
//
this.cboFileFormat.DropDownStyle = ComboBoxStyle.DropDownList;
this.cboFileFormat._mice = mRemoteNG.UI.Controls.Base.NGComboBox.MouseState.HOVER;
this.cboFileFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboFileFormat.FormattingEnabled = true;
this.cboFileFormat.Location = new System.Drawing.Point(15, 100);
this.cboFileFormat.Name = "cboFileFormat";

View File

@@ -226,20 +226,21 @@ namespace mRemoteNG.UI.Forms
private void cboFileformat_SelectedIndexChanged(object sender, EventArgs e)
{
if (SaveFormat == SaveFormat.mRXML)
{
chkUsername.Enabled = false;
chkPassword.Enabled = false;
chkDomain.Enabled = false;
chkAssignedCredential.Enabled = true;
}
else
{
chkUsername.Enabled = true;
chkPassword.Enabled = true;
chkDomain.Enabled = true;
chkAssignedCredential.Enabled = false;
}
// should only be active if we are using the credential manager feature
//if (SaveFormat == SaveFormat.mRXML)
//{
// chkUsername.Enabled = false;
// chkPassword.Enabled = false;
// chkDomain.Enabled = false;
// chkAssignedCredential.Enabled = true;
//}
//else
//{
// chkUsername.Enabled = true;
// chkPassword.Enabled = true;
// chkDomain.Enabled = true;
// chkAssignedCredential.Enabled = false;
//}
}
#endregion

View File

@@ -38,6 +38,9 @@ namespace mRemoteNG.UI.Forms.OptionsPages
this.chkShowLogonInfoOnTabs = new mRemoteNG.UI.Controls.Base.NGCheckBox();
this.chkDoubleClickClosesTab = new mRemoteNG.UI.Controls.Base.NGCheckBox();
this.chkShowProtocolOnTabs = new mRemoteNG.UI.Controls.Base.NGCheckBox();
this.chkCreateEmptyPanelOnStart = new mRemoteNG.UI.Controls.Base.NGCheckBox();
this.txtBoxPanelName = new mRemoteNG.UI.Controls.Base.NGTextBox();
this.lblPanelName = new mRemoteNG.UI.Controls.Base.NGLabel();
this.SuspendLayout();
//
// chkAlwaysShowPanelTabs
@@ -117,10 +120,41 @@ namespace mRemoteNG.UI.Forms.OptionsPages
this.chkShowProtocolOnTabs.Text = "Show protocols on tab names";
this.chkShowProtocolOnTabs.UseVisualStyleBackColor = true;
//
// chkCreateEmptyPanelOnStart
//
this.chkCreateEmptyPanelOnStart._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
this.chkCreateEmptyPanelOnStart.AutoSize = true;
this.chkCreateEmptyPanelOnStart.Location = new System.Drawing.Point(3, 164);
this.chkCreateEmptyPanelOnStart.Name = "chkCreateEmptyPanelOnStart";
this.chkCreateEmptyPanelOnStart.Size = new System.Drawing.Size(253, 17);
this.chkCreateEmptyPanelOnStart.TabIndex = 7;
this.chkCreateEmptyPanelOnStart.Text = "Create an empty panel when mRemoteNG starts";
this.chkCreateEmptyPanelOnStart.UseVisualStyleBackColor = true;
this.chkCreateEmptyPanelOnStart.CheckedChanged += new System.EventHandler(this.chkCreateEmptyPanelOnStart_CheckedChanged);
//
// txtBoxPanelName
//
this.txtBoxPanelName.Location = new System.Drawing.Point(43, 200);
this.txtBoxPanelName.Name = "txtBoxPanelName";
this.txtBoxPanelName.Size = new System.Drawing.Size(213, 20);
this.txtBoxPanelName.TabIndex = 8;
//
// lblPanelName
//
this.lblPanelName.AutoSize = true;
this.lblPanelName.Location = new System.Drawing.Point(40, 184);
this.lblPanelName.Name = "lblPanelName";
this.lblPanelName.Size = new System.Drawing.Size(66, 13);
this.lblPanelName.TabIndex = 9;
this.lblPanelName.Text = "Panel name:";
//
// TabsPanelsPage
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.lblPanelName);
this.Controls.Add(this.txtBoxPanelName);
this.Controls.Add(this.chkCreateEmptyPanelOnStart);
this.Controls.Add(this.chkAlwaysShowPanelTabs);
this.Controls.Add(this.chkIdentifyQuickConnectTabs);
this.Controls.Add(this.chkOpenNewTabRightOfSelected);
@@ -142,6 +176,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages
internal Controls.Base.NGCheckBox chkShowLogonInfoOnTabs;
internal Controls.Base.NGCheckBox chkDoubleClickClosesTab;
internal Controls.Base.NGCheckBox chkShowProtocolOnTabs;
}
private Controls.Base.NGCheckBox chkCreateEmptyPanelOnStart;
private Controls.Base.NGTextBox txtBoxPanelName;
private Controls.Base.NGLabel lblPanelName;
}
}

View File

@@ -30,6 +30,8 @@ namespace mRemoteNG.UI.Forms.OptionsPages
chkIdentifyQuickConnectTabs.Text = Language.strIdentifyQuickConnectTabs;
chkDoubleClickClosesTab.Text = Language.strDoubleClickTabClosesIt;
chkAlwaysShowPanelSelectionDlg.Text = Language.strAlwaysShowPanelSelection;
chkCreateEmptyPanelOnStart.Text = Language.strCreateEmptyPanelOnStartUp;
lblPanelName.Text = $"{Language.strPanelName}:";
}
public override void LoadSettings()
@@ -43,6 +45,9 @@ namespace mRemoteNG.UI.Forms.OptionsPages
chkIdentifyQuickConnectTabs.Checked = Settings.Default.IdentifyQuickConnectTabs;
chkDoubleClickClosesTab.Checked = Settings.Default.DoubleClickOnTabClosesIt;
chkAlwaysShowPanelSelectionDlg.Checked = Settings.Default.AlwaysShowPanelSelectionDlg;
chkCreateEmptyPanelOnStart.Checked = Settings.Default.CreateEmptyPanelOnStartUp;
txtBoxPanelName.Text = Settings.Default.StartUpPanelName;
UpdatePanelNameTextBox();
}
public override void SaveSettings()
@@ -58,8 +63,20 @@ namespace mRemoteNG.UI.Forms.OptionsPages
Settings.Default.IdentifyQuickConnectTabs = chkIdentifyQuickConnectTabs.Checked;
Settings.Default.DoubleClickOnTabClosesIt = chkDoubleClickClosesTab.Checked;
Settings.Default.AlwaysShowPanelSelectionDlg = chkAlwaysShowPanelSelectionDlg.Checked;
Settings.Default.CreateEmptyPanelOnStartUp = chkCreateEmptyPanelOnStart.Checked;
Settings.Default.StartUpPanelName = txtBoxPanelName.Text;
Settings.Default.Save();
}
private void UpdatePanelNameTextBox()
{
txtBoxPanelName.Enabled = chkCreateEmptyPanelOnStart.Checked;
}
private void chkCreateEmptyPanelOnStart_CheckedChanged(object sender, System.EventArgs e)
{
UpdatePanelNameTextBox();
}
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Security;
using System.Windows.Forms;
using mRemoteNG.Security;
using mRemoteNG.Tools;
namespace mRemoteNG.UI.Forms
{
@@ -19,12 +20,12 @@ namespace mRemoteNG.UI.Forms
Verify = verify;
}
public SecureString GetKey()
public Optional<SecureString> GetKey()
{
var dialog = ShowDialog();
return dialog == DialogResult.OK
? _password
: new SecureString();
: Optional<SecureString>.Empty;
}
#region Event Handlers

View File

@@ -190,7 +190,7 @@ namespace mRemoteNG.UI.Forms
this.Controls.Add(this.tsContainer);
this.Icon = global::mRemoteNG.Resources.mRemote_Icon;
this.MainMenuStrip = this.msMain;
this.MinimumSize = new System.Drawing.Size(1145, 610);
this.MinimumSize = new System.Drawing.Size(400, 400);
this.Name = "FrmMain";
this.Opacity = 0D;
this.Text = "mRemoteNG";

View File

@@ -17,8 +17,8 @@ using mRemoteNG.App.Update;
using mRemoteNG.Config;
using mRemoteNG.Config.Connections;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Config.Settings;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
@@ -40,7 +40,7 @@ using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.UI.Forms
{
public partial class FrmMain
public partial class FrmMain
{
private static ClipboardchangeEventHandler _clipboardChangedEvent;
private bool _inSizeMove;
@@ -70,6 +70,7 @@ namespace mRemoteNG.UI.Forms
private readonly AppUpdater _appUpdater;
private readonly DatabaseConnectorFactory _databaseConnectorFactory;
private readonly Screens _screens;
private readonly FileBackupPruner _backupPruner;
private readonly MessageCollector _messageCollector = Runtime.MessageCollector;
internal FullscreenHandler Fullscreen { get; set; }
@@ -86,7 +87,8 @@ namespace mRemoteNG.UI.Forms
var externalToolsService = new ExternalToolsService();
_import = new Import(this);
_connectionsService = new ConnectionsService(PuttySessionsManager.Instance, _import, this);
_import.ConnectionsService = _connectionsService;
_backupPruner = new FileBackupPruner();
_import.ConnectionsService = _connectionsService;
Func<SecureString> encryptionKeySelectionFunc = () => _connectionsService.EncryptionKey;
_appUpdater = new AppUpdater(encryptionKeySelectionFunc);
ExternalToolsTypeConverter.ExternalToolsService = externalToolsService;
@@ -109,7 +111,7 @@ namespace mRemoteNG.UI.Forms
Func<UpdateWindow> updateWindowBuilder = () => new UpdateWindow(new DockContent(), _shutdown, _appUpdater);
_notificationAreaIconBuilder = () => new NotificationAreaIcon(this, _connectionInitiator, _shutdown, _connectionsService);
Func<ExternalToolsWindow> externalToolsWindowBuilder = () => new ExternalToolsWindow(_connectionInitiator, externalToolsService, () => connectionTree.SelectedNode, this, _connectionsService);
Func<PortScanWindow> portScanWindowBuilder = () => new PortScanWindow(() => connectionTreeWindow.SelectedNode, _import);
Func<PortScanWindow> portScanWindowBuilder = () => new PortScanWindow(connectionTreeWindow, _import);
Func<ActiveDirectoryImportWindow> activeDirectoryImportWindowBuilder = () => new ActiveDirectoryImportWindow(() => connectionTreeWindow.SelectedNode, _import, _connectionsService);
_databaseConnectorFactory = new DatabaseConnectorFactory(encryptionKeySelectionFunc);
_windows = new Windows(_connectionInitiator, connectionTreeWindow, configWindow, errorAndInfoWindow, screenshotManagerWindow,
@@ -233,6 +235,7 @@ namespace mRemoteNG.UI.Forms
SetDefaultLayout();
_connectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded;
_connectionsService.ConnectionsSaved += ConnectionsServiceOnConnectionsSaved;
var credsAndConsSetup = new CredsAndConsSetup(_connectionsService);
credsAndConsSetup.LoadCredsAndCons();
@@ -250,7 +253,13 @@ namespace mRemoteNG.UI.Forms
Opacity = 1;
//Fix missing general panel at the first run
_panelAdder.AddPanel();
if (Settings.Default.CreateEmptyPanelOnStartUp)
{
var panelName = !string.IsNullOrEmpty(Settings.Default.StartUpPanelName)
? Settings.Default.StartUpPanelName
: Language.strNewPanel;
_panelAdder.AddPanel(panelName);
}
}
private void ApplyLanguage()
@@ -285,6 +294,14 @@ namespace mRemoteNG.UI.Forms
UpdateWindowTitle();
}
private void ConnectionsServiceOnConnectionsSaved(object sender, ConnectionsSavedEventArgs connectionsSavedEventArgs)
{
if (connectionsSavedEventArgs.UsingDatabase)
return;
_backupPruner.PruneBackupFiles(connectionsSavedEventArgs.ConnectionFileName, Settings.Default.BackupFileKeepCount);
}
private void SetMenuDependencies()
{
fileMenu.TreeWindow = _windows.TreeForm;

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.App.Info;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Security;
@@ -103,6 +102,7 @@ namespace mRemoteNG.UI.Menu
Size = new System.Drawing.Size(37, 20);
Text = Language.strMenuFile;
//DropDownOpening += mMenFile_DropDownOpening;
DropDownClosed += OnDropDownClosed;
//
// mMenFileNewConnection
//
@@ -352,6 +352,16 @@ namespace mRemoteNG.UI.Menu
}
}
private void OnDropDownClosed(object sender, EventArgs eventArgs)
{
_mMenFileNewConnection.Enabled = true;
_mMenFileNewFolder.Enabled = true;
_mMenFileDelete.Enabled = true;
_mMenFileRename.Enabled = true;
_mMenFileDuplicate.Enabled = true;
_mMenReconnectAll.Enabled = true;
}
private void mMenFileNewConnection_Click(object sender, EventArgs e)
{
TreeWindow.ConnectionTree.AddConnection();
@@ -364,13 +374,15 @@ namespace mRemoteNG.UI.Menu
private void mMenFileNew_Click(object sender, EventArgs e)
{
var saveFileDialog = ConnectionsSaveAsDialog();
if (saveFileDialog.ShowDialog() != DialogResult.OK)
using (var saveFileDialog = DialogFactory.ConnectionsSaveAsDialog())
{
return;
}
if (saveFileDialog.ShowDialog() != DialogResult.OK)
{
return;
}
ConnectionsService.NewConnectionsFile(saveFileDialog.FileName);
}
}
private void mMenFileLoad_Click(object sender, EventArgs e)
@@ -399,15 +411,11 @@ namespace mRemoteNG.UI.Menu
private void mMenFileSaveAs_Click(object sender, EventArgs e)
{
using (var saveFileDialog = new SaveFileDialog())
using (var saveFileDialog = DialogFactory.ConnectionsSaveAsDialog())
{
saveFileDialog.CheckPathExists = true;
saveFileDialog.InitialDirectory = ConnectionsFileInfo.DefaultConnectionsPath;
saveFileDialog.FileName = ConnectionsFileInfo.DefaultConnectionsFile;
saveFileDialog.OverwritePrompt = true;
saveFileDialog.Filter = $@"{Language.strFiltermRemoteXML}|*.xml|{Language.strFilterAll}|*.*";
if (saveFileDialog.ShowDialog(FrmMain.Default) != DialogResult.OK)
return;
if (saveFileDialog.ShowDialog(DialogWindowParent) != DialogResult.OK) return;
var newFileName = saveFileDialog.FileName;
ConnectionsService.SaveConnections(ConnectionsService.ConnectionTreeModel, false, new SaveFilter(), newFileName);
@@ -501,18 +509,6 @@ namespace mRemoteNG.UI.Menu
{
Shutdown.Quit();
}
public static SaveFileDialog ConnectionsSaveAsDialog()
{
return new SaveFileDialog
{
CheckPathExists = true,
InitialDirectory = ConnectionsFileInfo.DefaultConnectionsPath,
FileName = ConnectionsFileInfo.DefaultConnectionsFile,
OverwritePrompt = true,
Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*"
};
}
#endregion
}
}

View File

@@ -24,7 +24,7 @@ using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.UI.Window
{
public class ConfigWindow : BaseWindow
public class ConfigWindow : BaseWindow
{
private bool _originalPropertyGridToolStripItemCountValid;
private int _originalPropertyGridToolStripItemCount;
@@ -740,29 +740,32 @@ namespace mRemoteNG.UI.Window
private void UpdateRootInfoNode(PropertyValueChangedEventArgs e)
{
var rootInfo = _pGrid.SelectedObject as RootNodeInfo;
if (rootInfo == null) return;
if (e.ChangedItem.PropertyDescriptor == null) return;
// ReSharper disable once SwitchStatementMissingSomeCases
switch (e.ChangedItem.PropertyDescriptor.Name)
{
case "Password":
if (rootInfo.Password)
{
var passwordName = Settings.Default.UseSQLServer ? Language.strSQLServer.TrimEnd(':') : Path.GetFileName(_connectionsService.GetStartupConnectionFileName());
if (rootInfo == null)
return;
var password = MiscTools.PasswordDialog(passwordName);
if (password.Length == 0)
rootInfo.Password = false;
else
rootInfo.PasswordString = password.ConvertToUnsecureString();
}
else
{
rootInfo.PasswordString = "";
}
break;
case "Name":
break;
if (e.ChangedItem.PropertyDescriptor?.Name != "Password")
return;
if (rootInfo.Password)
{
var passwordName = Settings.Default.UseSQLServer
? Language.strSQLServer.TrimEnd(':')
: Path.GetFileName(_connectionsService.GetStartupConnectionFileName());
var password = MiscTools.PasswordDialog(passwordName);
// operation cancelled, dont set a password
if (!password.Any() || password.First().Length == 0)
{
rootInfo.Password = false;
return;
}
rootInfo.PasswordString = password.First().ConvertToUnsecureString();
}
else
{
rootInfo.PasswordString = "";
}
}

View File

@@ -15,7 +15,7 @@ using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.UI.Window
{
public partial class ConnectionTreeWindow
public partial class ConnectionTreeWindow
{
private readonly IConnectionInitiator _connectionInitiator;
private readonly IConnectionsService _connectionsService;
@@ -44,11 +44,22 @@ namespace mRemoteNG.UI.Window
InitializeComponent();
SetMenuEventHandlers();
SetConnectionTreeEventHandlers();
Settings.Default.PropertyChanged += (sender, args) => SetConnectionTreeEventHandlers();
Settings.Default.PropertyChanged += OnAppSettingsChanged;
olvConnections.ModelFilter = _connectionTreeSearchTextFilter;
}
private void OnAppSettingsChanged(object o, PropertyChangedEventArgs propertyChangedEventArgs)
{
if (propertyChangedEventArgs.PropertyName == nameof(Settings.UseFilterSearch))
{
ConnectionTree.UseFiltering = Settings.Default.UseFilterSearch;
ApplyFiltering();
}
SetConnectionTreeEventHandlers();
}
#region Form Stuff
#region Form Stuff
private void Tree_Load(object sender, EventArgs e)
{
ApplyLanguage();
@@ -100,8 +111,6 @@ namespace mRemoteNG.UI.Window
private void SetConnectionTreeEventHandlers()
{
olvConnections.NodeDeletionConfirmer = new SelectedConnectionDeletionConfirmer(MessageBox.Show);
olvConnections.BeforeLabelEdit += tvConnections_BeforeLabelEdit;
olvConnections.AfterLabelEdit += tvConnections_AfterLabelEdit;
olvConnections.KeyDown += tvConnections_KeyDown;
olvConnections.KeyPress += tvConnections_KeyPress;
SetTreePostSetupActions();
@@ -177,24 +186,6 @@ namespace mRemoteNG.UI.Window
{
olvConnections.AddFolder();
}
private void tvConnections_BeforeLabelEdit(object sender, LabelEditEventArgs e)
{
ConnectionTreeContextMenu.DisableShortcutKeys();
}
private void tvConnections_AfterLabelEdit(object sender, LabelEditEventArgs e)
{
try
{
ConnectionTreeContextMenu.EnableShortcutKeys();
ConnectionTree.ConnectionTreeModel.RenameNode(SelectedNode, e.Label);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_AfterLabelEdit (UI.Window.ConnectionTreeWindow) failed", ex);
}
}
#endregion
#region Search
@@ -243,25 +234,30 @@ namespace mRemoteNG.UI.Window
}
private void txtSearch_TextChanged(object sender, EventArgs e)
{
if (Settings.Default.UseFilterSearch)
{
if (txtSearch.Text == "" || txtSearch.Text == Language.strSearchPrompt)
{
olvConnections.UseFiltering = false;
olvConnections.ResetColumnFiltering();
return;
}
olvConnections.UseFiltering = true;
_connectionTreeSearchTextFilter.FilterText = txtSearch.Text;
olvConnections.ModelFilter = _connectionTreeSearchTextFilter;
}
else
{
if (txtSearch.Text == "") return;
olvConnections.NodeSearcher?.SearchByName(txtSearch.Text);
JumpToNode(olvConnections.NodeSearcher?.CurrentMatch);
}
{
ApplyFiltering();
}
private void ApplyFiltering()
{
if (Settings.Default.UseFilterSearch)
{
if (txtSearch.Text == "" || txtSearch.Text == Language.strSearchPrompt)
{
olvConnections.UseFiltering = false;
olvConnections.ResetColumnFiltering();
return;
}
olvConnections.UseFiltering = true;
_connectionTreeSearchTextFilter.FilterText = txtSearch.Text;
olvConnections.ModelFilter = _connectionTreeSearchTextFilter;
}
else
{
if (txtSearch.Text == "") return;
olvConnections.NodeSearcher?.SearchByName(txtSearch.Text);
JumpToNode(olvConnections.NodeSearcher?.CurrentMatch);
}
}
private void JumpToNode(ConnectionInfo connectionInfo)

View File

@@ -10,47 +10,48 @@ namespace mRemoteNG.UI.Window
{
#region Form Init
internal TreeView tvIndex;
private TreeView tvIndex;
internal ImageList imgListHelp;
private System.ComponentModel.Container components;
internal SplitContainer pnlSplitter;
internal Label lblDocName;
internal WebBrowser wbHelp;
private SplitContainer pnlSplitter;
private Label lblDocName;
private WebBrowser wbHelp;
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
Load += new EventHandler(Help_Load);
Shown += new EventHandler(Help_Shown);
TreeNode TreeNode1 = new TreeNode("Introduction");
TreeNode TreeNode2 = new TreeNode("Prerequisites");
TreeNode TreeNode3 = new TreeNode("Installation");
TreeNode TreeNode4 = new TreeNode("Configuration");
TreeNode TreeNode5 = new TreeNode("SQL Configuration");
TreeNode TreeNode6 = new TreeNode("Command-Line Switches");
TreeNode TreeNode7 = new TreeNode("Getting Started", new[] {TreeNode2, TreeNode3, TreeNode4, TreeNode5, TreeNode6});
TreeNode TreeNode8 = new TreeNode("Main Menu");
TreeNode TreeNode9 = new TreeNode("Connections");
TreeNode TreeNode10 = new TreeNode("Config");
TreeNode TreeNode11 = new TreeNode("Errors and Infos");
TreeNode TreeNode12 = new TreeNode("Save As / Export");
TreeNode TreeNode14 = new TreeNode("Screenshot Manager");
TreeNode TreeNode15 = new TreeNode("Connection");
TreeNode TreeNode16 = new TreeNode("Options");
TreeNode TreeNode17 = new TreeNode("Update");
TreeNode TreeNode18 = new TreeNode("SSH File Transfer");
TreeNode TreeNode19 = new TreeNode("Quick Connect");
TreeNode TreeNode20 = new TreeNode("Import From Active Directory");
TreeNode TreeNode21 = new TreeNode("External Applications");
TreeNode TreeNode22 = new TreeNode("Port Scan");
TreeNode TreeNode23 = new TreeNode("User Interface", new[] {TreeNode8, TreeNode9, TreeNode10, TreeNode11, TreeNode12, TreeNode14, TreeNode15, TreeNode16, TreeNode17, TreeNode18, TreeNode19, TreeNode20, TreeNode21, TreeNode22});
TreeNode TreeNode24 = new TreeNode("Quick Reference");
TreeNode TreeNode25 = new TreeNode("Help", new[] {TreeNode1, TreeNode7, TreeNode23, TreeNode24});
Load += Help_Load;
Shown += Help_Shown;
var TreeNode1 = new TreeNode("Introduction");
var TreeNode2 = new TreeNode("Prerequisites");
var TreeNode3 = new TreeNode("Installation");
var TreeNode4 = new TreeNode("Configuration");
var TreeNode5 = new TreeNode("SQL Configuration");
var TreeNode6 = new TreeNode("Command-Line Switches");
var TreeNode7 = new TreeNode("Getting Started", new[] {TreeNode2, TreeNode3, TreeNode4, TreeNode5, TreeNode6});
var TreeNode8 = new TreeNode("Main Menu");
var TreeNode9 = new TreeNode("Connections");
var TreeNode10 = new TreeNode("Config");
var TreeNode11 = new TreeNode("Errors and Infos");
var TreeNode12 = new TreeNode("Save As / Export");
var TreeNode14 = new TreeNode("Screenshot Manager");
var TreeNode15 = new TreeNode("Connection");
var TreeNode16 = new TreeNode("Options");
var TreeNode17 = new TreeNode("Update");
var TreeNode18 = new TreeNode("SSH File Transfer");
var TreeNode19 = new TreeNode("Quick Connect");
var TreeNode20 = new TreeNode("Import From Active Directory");
var TreeNode21 = new TreeNode("External Applications");
var TreeNode22 = new TreeNode("Port Scan");
var TreeNode23 = new TreeNode("User Interface", new[] {TreeNode8, TreeNode9, TreeNode10, TreeNode11, TreeNode12, TreeNode14, TreeNode15, TreeNode16, TreeNode17, TreeNode18, TreeNode19, TreeNode20, TreeNode21, TreeNode22});
var TreeNode24 = new TreeNode("Quick Reference");
var TreeNode25 = new TreeNode("Help", new[] {TreeNode1, TreeNode7, TreeNode23, TreeNode24});
wbHelp = new WebBrowser();
wbHelp.DocumentTitleChanged += new EventHandler(wbHelp_DocumentTitleChanged);
wbHelp.DocumentTitleChanged += wbHelp_DocumentTitleChanged;
tvIndex = new TreeView();
tvIndex.NodeMouseClick += new TreeNodeMouseClickEventHandler(tvIndex_NodeMouseClick);
tvIndex.AfterSelect += new TreeViewEventHandler(tvIndex_AfterSelect);
tvIndex.NodeMouseClick += tvIndex_NodeMouseClick;
tvIndex.AfterSelect += tvIndex_AfterSelect;
imgListHelp = new ImageList(components);
pnlSplitter = new SplitContainer();
lblDocName = new Label();
@@ -80,75 +81,27 @@ namespace mRemoteNG.UI.Window
tvIndex.HideSelection = false;
tvIndex.Location = new System.Drawing.Point(1, 1);
tvIndex.Name = "tvIndex";
TreeNode1.Name = "Node0";
TreeNode1.Tag = "Introduction";
TreeNode1.Text = "Introduction";
TreeNode2.Name = "Node0";
TreeNode2.Tag = "Prerequisites";
TreeNode2.Text = "Prerequisites";
TreeNode3.Name = "Node3";
TreeNode3.Tag = "Installation";
TreeNode3.Text = "Installation";
TreeNode4.Name = "Node4";
TreeNode4.Tag = "Configuration";
TreeNode4.Text = "Configuration";
TreeNode5.Name = "Node0";
TreeNode5.Tag = "ConfigurationSQL";
TreeNode5.Text = "SQL Configuration";
TreeNode6.Name = "Node5";
TreeNode6.Tag = "CMDSwitches";
TreeNode6.Text = "Command-Line Switches";
TreeNode7.Name = "Node1";
TreeNode7.Text = "Getting Started";
TreeNode8.Name = "Node7";
TreeNode8.Tag = "MainMenu";
TreeNode8.Text = "Main Menu";
TreeNode9.Name = "Node8";
TreeNode9.Tag = "Connections";
TreeNode9.Text = "Connections";
TreeNode10.Name = "Node9";
TreeNode10.Tag = "Config";
TreeNode10.Text = "Config";
TreeNode11.Name = "Node10";
TreeNode11.Tag = "ErrorsAndInfos";
TreeNode11.Text = "Errors and Infos";
TreeNode12.Name = "Node11";
TreeNode12.Tag = "SaveAsExport";
TreeNode12.Text = "Save As / Export";
TreeNode14.Name = "Node13";
TreeNode14.Tag = "ScreenshotManager";
TreeNode14.Text = "Screenshot Manager";
TreeNode15.Name = "Node14";
TreeNode15.Tag = "Connection";
TreeNode15.Text = "Connection";
TreeNode16.Name = "Node15";
TreeNode16.Tag = "Options";
TreeNode16.Text = "Options";
TreeNode17.Name = "Node16";
TreeNode17.Tag = "Update";
TreeNode17.Text = "Update";
TreeNode18.Name = "Node17";
TreeNode18.Tag = "SSHFileTransfer";
TreeNode18.Text = "SSH File Transfer";
TreeNode19.Name = "Node18";
TreeNode19.Tag = "QuickConnect";
TreeNode19.Text = "Quick Connect";
TreeNode20.Name = "Node19";
TreeNode20.Tag = "ImportFromAD";
TreeNode20.Text = "Import From Active Directory";
TreeNode21.Name = "Node1";
TreeNode21.Tag = "ExternalTools";
TreeNode21.Text = "External Tools";
TreeNode22.Name = "Node0";
TreeNode22.Tag = "PortScan";
TreeNode22.Text = "Port Scan";
TreeNode23.Name = "Node6";
TreeNode23.Text = "User Interface";
TreeNode24.Name = "Node20";
TreeNode24.Tag = "QuickReference";
TreeNode24.Text = "Quick Reference";
TreeNode25.Name = "Node0";
TreeNode25.Text = "Help";
TreeNode25.Tag = "Index";
tvIndex.Nodes.AddRange(new[] {TreeNode25});
tvIndex.ShowRootLines = false;
@@ -193,7 +146,7 @@ namespace mRemoteNG.UI.Window
lblDocName.Name = "lblDocName";
lblDocName.Size = new System.Drawing.Size(327, 35);
lblDocName.TabIndex = 2;
lblDocName.Text = "Introduction";
lblDocName.Text = @"Introduction";
lblDocName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
//Help
@@ -201,9 +154,8 @@ namespace mRemoteNG.UI.Window
ClientSize = new System.Drawing.Size(542, 323);
Controls.Add(pnlSplitter);
Icon = Resources.Help_Icon;
Name = "Help";
TabText = "Help";
Text = "Help";
TabText = @"Help";
Text = @"Help";
pnlSplitter.Panel1.ResumeLayout(false);
pnlSplitter.Panel2.ResumeLayout(false);
pnlSplitter.ResumeLayout(false);
@@ -245,7 +197,7 @@ namespace mRemoteNG.UI.Window
private void tvIndex_AfterSelect(object sender, TreeViewEventArgs e)
{
if ((string)e.Node.Tag != "" && e.Node.Tag != null)
if (!string.IsNullOrEmpty((string)e.Node.Tag))
{
wbHelp.Navigate(GeneralAppInfo.HomePath + "\\Help\\" + Convert.ToString(e.Node.Tag) +".htm");
}
@@ -263,7 +215,7 @@ namespace mRemoteNG.UI.Window
imgListHelp.Images.Add("Help", Resources.Help);
}
private void SetImages(TreeNode node)
private static void SetImages(TreeNode node)
{
node.ImageIndex = 2;
node.SelectedImageIndex = 2;

View File

@@ -88,7 +88,7 @@ namespace mRemoteNG.UI.Window
this.ipStart.Location = new System.Drawing.Point(5, 19);
this.ipStart.Name = "ipStart";
this.ipStart.Size = new System.Drawing.Size(130, 20);
this.ipStart.TabIndex = 10;
this.ipStart.TabIndex = 1;
this.ipStart.ToolTipText = "";
//
// ipEnd
@@ -96,7 +96,7 @@ namespace mRemoteNG.UI.Window
this.ipEnd.Location = new System.Drawing.Point(155, 19);
this.ipEnd.Name = "ipEnd";
this.ipEnd.Size = new System.Drawing.Size(130, 20);
this.ipEnd.TabIndex = 15;
this.ipEnd.TabIndex = 2;
this.ipEnd.ToolTipText = "";
//
// lblStartIP
@@ -126,7 +126,7 @@ namespace mRemoteNG.UI.Window
this.btnScan.Location = new System.Drawing.Point(769, 5);
this.btnScan.Name = "btnScan";
this.btnScan.Size = new System.Drawing.Size(110, 55);
this.btnScan.TabIndex = 20;
this.btnScan.TabIndex = 6;
this.btnScan.Text = "&Scan";
this.btnScan.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.btnScan.UseVisualStyleBackColor = true;
@@ -222,7 +222,7 @@ namespace mRemoteNG.UI.Window
this.btnImport.Location = new System.Drawing.Point(800, 5);
this.btnImport.Name = "btnImport";
this.btnImport.Size = new System.Drawing.Size(80, 40);
this.btnImport.TabIndex = 101;
this.btnImport.TabIndex = 8;
this.btnImport.Text = "&Import";
this.btnImport.UseVisualStyleBackColor = true;
this.btnImport.Click += new System.EventHandler(this.btnImport_Click);
@@ -244,7 +244,7 @@ namespace mRemoteNG.UI.Window
this.cbProtocol.Location = new System.Drawing.Point(5, 25);
this.cbProtocol.Name = "cbProtocol";
this.cbProtocol.Size = new System.Drawing.Size(122, 21);
this.cbProtocol.TabIndex = 28;
this.cbProtocol.TabIndex = 7;
//
// lblOnlyImport
//
@@ -360,7 +360,7 @@ namespace mRemoteNG.UI.Window
0});
this.numericSelectorTimeout.Name = "numericSelectorTimeout";
this.numericSelectorTimeout.Size = new System.Drawing.Size(67, 22);
this.numericSelectorTimeout.TabIndex = 17;
this.numericSelectorTimeout.TabIndex = 5;
//
// lblTimeout
//
@@ -381,7 +381,7 @@ namespace mRemoteNG.UI.Window
0});
this.portEnd.Name = "portEnd";
this.portEnd.Size = new System.Drawing.Size(67, 22);
this.portEnd.TabIndex = 15;
this.portEnd.TabIndex = 4;
this.portEnd.Enter += new System.EventHandler(this.portEnd_Enter);
//
// portStart
@@ -394,7 +394,7 @@ namespace mRemoteNG.UI.Window
0});
this.portStart.Name = "portStart";
this.portStart.Size = new System.Drawing.Size(67, 22);
this.portStart.TabIndex = 5;
this.portStart.TabIndex = 3;
this.portStart.Enter += new System.EventHandler(this.portStart_Enter);
//
// Label2

View File

@@ -1,25 +1,26 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.Tree.Root;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.UI.Window
{
public partial class PortScanWindow
public partial class PortScanWindow
{
private readonly Func<ConnectionInfo> _getSelectedConnectionFunc;
private readonly ConnectionTreeWindow _connectionTreeWindow;
private readonly Import _import;
#region Constructors
public PortScanWindow(Func<ConnectionInfo> getSelectedConnectionFunc, Import import)
public PortScanWindow(ConnectionTreeWindow connectionTreeWindow, Import import)
{
_getSelectedConnectionFunc = getSelectedConnectionFunc;
_connectionTreeWindow = connectionTreeWindow.ThrowIfNull(nameof(connectionTreeWindow));
_import = import.ThrowIfNull(nameof(import));
InitializeComponent();
@@ -136,8 +137,6 @@ namespace mRemoteNG.UI.Window
{
ProtocolType protocol = (ProtocolType)Enum.Parse(typeof(ProtocolType), Convert.ToString(cbProtocol.SelectedItem), true);
importSelectedHosts(protocol);
DialogResult = DialogResult.OK;
Close();
}
#endregion
@@ -263,11 +262,28 @@ namespace mRemoteNG.UI.Window
return;
}
var selectedNode = _getSelectedConnectionFunc();
var selectedTreeNodeAsContainer = selectedNode as ContainerInfo ?? selectedNode.Parent;
_import.ImportFromPortScan(hosts, protocol, selectedTreeNodeAsContainer);
var destinationContainer = GetDestinationContainerForImportedHosts();
_import.ImportFromPortScan(hosts, protocol, destinationContainer);
}
/// <summary>
/// Determines where the imported hosts will be placed
/// in the connection tree.
/// </summary>
private ContainerInfo GetDestinationContainerForImportedHosts()
{
var selectedNode = _connectionTreeWindow.SelectedNode
?? _connectionTreeWindow.ConnectionTree.ConnectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
// if a putty node is selected, place imported connections in the root connection node
if (selectedNode is RootPuttySessionsNodeInfo || selectedNode is PuttySessionInfo)
selectedNode = _connectionTreeWindow.ConnectionTree.ConnectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
// if the selected node is a connection, use its parent container
var selectedTreeNodeAsContainer = selectedNode as ContainerInfo ?? selectedNode.Parent;
return selectedTreeNodeAsContainer;
}
private void importVNCToolStripMenuItem_Click(object sender, EventArgs e)
{
importSelectedHosts(ProtocolType.VNC);

View File

@@ -692,6 +692,12 @@
<setting name="MultiSshToolbarVisible" serializeAs="String">
<value>False</value>
</setting>
<setting name="CreateEmptyPanelOnStartUp" serializeAs="String">
<value>False</value>
</setting>
<setting name="StartUpPanelName" serializeAs="String">
<value>General</value>
</setting>
</mRemoteNG.Settings>
</userSettings>
<applicationSettings>