diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e7c6b8d42..b5554a857 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -11,7 +11,7 @@ There are many ways that you can help improve mRemoteNG, even if you don't know For example, you might: - add documentation or "how-to" articles on the [Wiki](https://github.com/mRemoteNG/mRemoteNG/wiki) - answer support questions on the [forum](http://forum.mremoteng.org) -- [add or improve a translation](https://github.com/mRemoteNG/mRemoteNG/wiki/How to Help Translating mRemoteNG) +- [add or improve a translation](https://github.com/mRemoteNG/mRemoteNG/wiki/How-to-Help-Translating-mRemoteNG) - submit a [pull request](https://github.com/mRemoteNG/mRemoteNG/pulls) for a [bug or feature ticket](https://github.com/mRemoteNG/mRemoteNG/issues) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index abf047f13..53cb42df3 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,16 +1,30 @@ - -Before opening an issue, please search for a duplicate or closed issue. -Please provide as much detail as possible for us to fix your issue. ---> +## Expected Behavior + + - -|Detail|Value| -|--:|---| -|Operating system | Windows 10 x64 | -|mRemoteNG version| 1.75.7008 | +## Current Behavior + + +## Possible Solution + + - - +## Steps to Reproduce (for bugs) + + +1. +2. +3. +4. + +## Context + + + +## Your Environment + +* Version used: +* Operating System and version (e.g. Windows 10 1709 x64): diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index fe2262d3f..5ead5d438 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,29 @@ - + + +## Description + + +## Motivation and Context + + + +## How Has This Been Tested? + + + + +## Screenshots (if appropriate): + +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Checklist: + + +- [ ] My code follows the code style of this project. +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have read the **CONTRIBUTING** document. diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index e284970c0..7695cb09d 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,13 +1,140 @@ -1.76.0 Alpha 2 (201x-xx-xx): +1.77.0 (2018-xx-xx): + +Features/Enhancements: +---------------------- +#1072: Russian translation improvements +#1016: Chinese (simplified) translation improvements +#928: Add context menu items to 'Close all but this' and 'Close all tabs to the right' + + +1.76.10 (2018-10-07): + +Fixes: +------ +#1124: Enabling themes causes an exception + + +1.76.9 (2018-10-07): + +Fixes: +------ +#1117: Duplicate panel created when "Reconnect on Startup" and "Create Empty Panel" settings enabled +#1115: Exception when changing from xml data storage to SQL +#1110: Pressing Delete button during connection rename attempts to delete the connection instead of the text +#1106: Inheritance does not work when parent has C# default type set +#1092: Invalid Cast Exceptions loading default connectioninfo +#1091: Minor themeing issues +#853: Added some additional safety checks and logging to help address RDP crashes + + +1.76.8 (2018-08-25): + +Fixes: +------ +#1088: Delete and Launch buttons are not disabled when last external tool deleted +#1087: 'Save connections after every edit' setting not honored +#1082: Connections not given GUID if Id is empty in connection xml + + +1.76.7 (2018-08-22): + +Fixes: +------ +#1076: Wrong object selected when duplicating connection then switching between properties and inheritance in config window +#1068: Fixed some toolbar positioning bugs + + +1.76.6 (2018-08-03): + +Fixes: +------ +#1062: Entering correct password when starting app does not load connections file + +1.76.5 (2018-08-02): + +Fixes: +------ +#1057: Hitting F2 with no connection node selected caused unhandled exception +#1052: 'Switch to notification panel' feature does not always switch +#1051: Tooltips always displayed regardless of 'Show description tooltips in connection tree' setting +#1050: Config window retains access to previously selected node after loading new connections file +#1045: Config window shows several incorrect properties for HTTPS connections +#1040: Canceling "select panel" form does not cancel +#1039: Set default theme when themes disabled +#1038: Unable to add connection with active filter +#1036: Exception when themes are active and options page closed on Connections then reopened +#1034: Connection context menu not being translated +#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 +#971: Portable Settings now apply to any machine they are used on +#961: Connections file overwritten if correct decryption password not provided +#893: Removed unneeded files from build/package +#868: if statement returned the same value +#762: Increased button size to fit locaized text + + +1.76.4 Alpha 6 (2018-06-03): + +Features/Enhancements: +---------------------- +#948: Fixed issue where many menu item translations were not being used +#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: +------ +#938: Minor layout improvements on the Port Scan screen +#916: Default properties were not being saved + + +1.76.3 Alpha 5 (2018-03-14): + +Fixes: +------ +#911: Csv exports sometimes do not include all fields +#807: Inheritance is sometimes turned on for nodes under root Connections node + + +1.76.2 Alpha 4 (2018-03-03): + +Fixes: +------ +#899: DoNotPlay is Case Sensitive in XML Serialization + + +1.76.1 Alpha 3 (2018-02-24): + +Features/Enhancements: +---------------------- +#625: Added ability to import mRemoteNG formatted CSV files +#648: The port scan ping timeout is now configurable + +Fixes: +------ +Fixed a few Xml serialization bugs that would occur if boolean values weren't capitalized + + +1.76.0 Alpha 2 (2018-02-01): Features/Enhancements: ---------------------- #838: Added an option to lock toolbars +#836: Added a Read Only option for SQL connections #829: Add option that fixes connecting to Azure instances with LoadBalanceInfo Fixes: ------ - +#840: Fix theme loading issue in installer version +#800: Fixed issue with PuTTY sessions not showing some extended characters +Fixed a few toolbar layout issues 1.76.0 Alpha 1 (2017-12-08): @@ -21,6 +148,7 @@ Features/Enhancements: #671: Revamped UI theme system #611: Added multi-ssh toolbar for sending commands to many SSH clients at once #558: Connection tree now shows customizable icons instead of play/pause icon +#519: You can now import normal mRemoteNG files - they do not have to be exports #504: Added Korean translation #485: The Domain field is now visible/editable for connection with the IntApp protocol #468: Default connection info Panel property is now saved diff --git a/CREDITS.TXT b/CREDITS.TXT index 234c5db11..8b53c62ed 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -22,6 +22,9 @@ Camilo Alvarez (github.com/jotatsu) github.com/DamianBis github.com/pfjason github.com/sirLoaf +github.com/Fyers +Vladimir Semenov (github.com/sli-pro) +Aleksey Reytsman (github.com/areytsman) Past Contributors @@ -58,6 +61,9 @@ Lukas Plachy (github.com/rheingold) Gyuha Shin Stefan (github.com/polluks) github.com/emazv72 +Vladimir Semenov (github.com/sli-pro) +Marco Sousa (github.com/marcomsousa) +github.com/wwj402 Included Source Code @@ -72,10 +78,6 @@ FilteredPropertyGrid Copyright 2006 Azuria http://www.codeproject.com/KB/cs/FilteredPropertyGrid.aspx -Hotkey Selection Control for .NET -Copyright 2006 Thomas Backman -http://www.codeproject.com/Articles/15085/A-simple-hotkey-selection-control-for-NET - InputBox Copyright 2016 Jan Slama http://www.csharp-examples.net/inputbox/ diff --git a/Jenkinsfile b/Jenkinsfile index a8551788a..40047a3e4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,8 +1,8 @@ +#!groovy​ node('windows') { def jobDir = pwd() def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\"" - def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools" - def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow" + def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe" def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.7.0\\tools\\nunit3-console.exe" def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe" def reportGeneratorPath = "${jobDir}\\packages\\ReportGenerator.3.0.2\\tools\\ReportGenerator.exe" @@ -24,11 +24,11 @@ node('windows') { } stage ('Build mRemoteNG (Normal)') { - bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /p:Platform=x86 \"${jobDir}\\mRemoteV1.sln\"" + bat "\"${msBuild}\" /nologo /p:Platform=x86 \"${jobDir}\\mRemoteV1.sln\"" } stage ('Build mRemoteNG (Portable)') { - bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /p:Configuration=\"Debug Portable\";Platform=x86 \"${jobDir}\\mRemoteV1.sln\"" + bat "\"${msBuild}\" /nologo /p:Configuration=\"Debug Portable\";Platform=x86 \"${jobDir}\\mRemoteV1.sln\"" } stage ('Run Unit Tests (Normal, w/coverage)') { diff --git a/Jenkinsfile_publish.groovy b/Jenkinsfile_publish.groovy index 2c30f8792..4ced70c2d 100644 --- a/Jenkinsfile_publish.groovy +++ b/Jenkinsfile_publish.groovy @@ -1,9 +1,13 @@ node('windows') { def jobDir = pwd() def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\"" - def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools" - def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow" - def nunitTestAdapterPath = "C:\\Users\\Administrator\\AppData\\Local\\Microsoft\\VisualStudio\\14.0\\Extensions" + def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe" + def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.7.0\\tools\\nunit3-console.exe" + def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe" + def testResultFilePrefix = "TestResult" + def testResultFileNormal = "${testResultFilePrefix}_UnitTests_normal.xml" + def testResultFilePortable = "${testResultFilePrefix}_UnitTests_portable.xml" + def coverageReport = "code_coverage_report.xml" stage ('Clean output dir') { @@ -32,24 +36,24 @@ node('windows') { withCredentials([file(credentialsId: '9b674d57-6792-48e3-984a-4d1bab2abb64', variable: 'CODE_SIGNING_CERT')]) { withCredentials([usernamePassword(credentialsId: '05b7449b-05c0-490f-8661-236242526e62', passwordVariable: 'MRNG_CERT_PASSWORD', usernameVariable: 'NO_USERNAME')]) { stage ('Build mRemoteNG (Normal - MSI)') { - bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /t:Clean,Build /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\"" + bat "\"${msBuild}\" /nologo /t:Clean,Build /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\"" archiveArtifacts artifacts: "Release\\*.msi", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true } stage ('Build mRemoteNG (Portable)') { - bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /t:Clean,Build /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\"" + bat "\"${msBuild}\" /nologo /t:Clean,Build /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\"" archiveArtifacts artifacts: "Release\\*.zip", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true } } } - stage ('Run Unit Tests (Normal - MSI)') { - bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release\\mRemoteNGTests.dll\"" - } - - stage ('Run Unit Tests (Portable)') { - bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release Portable\\mRemoteNGTests.dll\"" - } + stage ('Run Unit Tests (Normal - MSI)') { + bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release\\mRemoteNGTests.dll\" --result=${testResultFileNormal} --x86" + } + + stage ('Run Unit Tests (Portable)') { + bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release portable\\mRemoteNGTests.dll\" --result=${testResultFilePortable} --x86" + } stage ('Generate UpdateCheck Files') { bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\create_upg_chk_files.ps1\" -TagName \"${env.TagName}\" -UpdateChannel \"${env.UpdateChannel}\"" @@ -58,11 +62,10 @@ node('windows') { stage ('Publish to GitHub') { withCredentials([string(credentialsId: '5443a369-dbe8-42d3-b4e8-04d0b4e9039a', variable: 'GH_AUTH_TOKEN')]) { - def zipPath = "${jobDir}\\Release\\*.zip" - def msiPath = "${jobDir}\\Release\\*.msi" + def releaseFolder = "${jobDir}\\Release" // because batch files suck at handling newline characters, we have to convert to base64 in groovy and back to text in powershell def base64Description = env.ReleaseDescription.bytes.encodeBase64().toString() - bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\publish_to_github.ps1\" -Owner \"mRemoteNG\" -Repository \"mRemoteNG\" -ReleaseTitle \"${env.ReleaseTitle}\" -TagName \"${env.TagName}\" -TargetCommitish \"${env.TargetBranch}\" -Description \"${base64Description}\" -IsDraft ${env.IsDraft} -IsPrerelease ${env.IsPreRelease} -ZipFilePath \"${zipPath}\" -MsiFilePath \"${msiPath}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded" + bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\publish_to_github.ps1\" -Owner \"mRemoteNG\" -Repository \"mRemoteNG\" -ReleaseTitle \"${env.ReleaseTitle}\" -TagName \"${env.TagName}\" -TargetCommitish \"${env.TargetBranch}\" -Description \"${base64Description}\" -IsDraft ${env.IsDraft} -IsPrerelease ${env.IsPreRelease} -ReleaseFolderPath \"${releaseFolder}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded" } } } \ No newline at end of file diff --git a/README.MD b/README.MD index b56ad2bca..2f84aa7ee 100644 --- a/README.MD +++ b/README.MD @@ -10,9 +10,9 @@ | Update Channel | Build Status | Downloads | | ---------------|--------------|-----------| -| Stable | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/master)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/master/) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75.7011/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75.7011) | -| Beta | | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75.7011/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75.7011) | -| Development | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/develop)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/develop/) | - | +| Stable | [![Build status](https://ci.appveyor.com/api/projects/status/k0sdbxmq90fgdmj6/branch/master?svg=true)](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/master) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75.7012/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75.7012) | +| Beta | | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75.7012/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75.7012) | +| Development | [![Build status](https://ci.appveyor.com/api/projects/status/k0sdbxmq90fgdmj6/branch/develop?svg=true)](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/develop) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.76Alpha5/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76Alpha5) | mRemoteNG is the next generation of mRemote, a full-featured, multi-tab remote connections manager. diff --git a/Tools/7zip/7za.dll b/Tools/7zip/7za.dll index f63e760c5..e95542c39 100644 Binary files a/Tools/7zip/7za.dll and b/Tools/7zip/7za.dll differ diff --git a/Tools/7zip/7za.exe b/Tools/7zip/7za.exe index 3bc851d5f..d516eb5c1 100644 Binary files a/Tools/7zip/7za.exe and b/Tools/7zip/7za.exe differ diff --git a/Tools/7zip/7zxa.dll b/Tools/7zip/7zxa.dll index e5591acb0..1e3778ae3 100644 Binary files a/Tools/7zip/7zxa.dll and b/Tools/7zip/7zxa.dll differ diff --git a/Tools/7zip/License.txt b/Tools/7zip/License.txt index 7b8e9a04c..2a0f37730 100644 --- a/Tools/7zip/License.txt +++ b/Tools/7zip/License.txt @@ -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. diff --git a/Tools/7zip/history.txt b/Tools/7zip/history.txt index fe8fb9d8e..e9bac39da 100644 --- a/Tools/7zip/history.txt +++ b/Tools/7zip/history.txt @@ -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. diff --git a/Tools/7zip/readme.txt b/Tools/7zip/readme.txt index 8f9bd7b73..c3de12587 100644 --- a/Tools/7zip/readme.txt +++ b/Tools/7zip/readme.txt @@ -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. diff --git a/Tools/CreateBulkConnections_ConfCons2_6.ps1 b/Tools/CreateBulkConnections_ConfCons2_6.ps1 new file mode 100644 index 000000000..f0f92a041 --- /dev/null +++ b/Tools/CreateBulkConnections_ConfCons2_6.ps1 @@ -0,0 +1,114 @@ +##################################### +# Author: David Sparer +# Summary: +# This is intended to be a template for creating connections in bulk. This uses the serializers directly from the mRemoteNG binaries. +# You will still need to create the connection info objects, but the library will handle serialization. It is expected that you +# are familiar with PowerShell. If this is not the case, reach out to the mRemoteNG community for help. +# Usage: +# Replace or modify the examples that are shown toward the end of the script to create your own connection info objects. +##################################### + +$EncryptionKey = (Get-Credential -Message "Enter the encryption key you would like to use. This must match the encryption key used by the rest of the confCons file." -UserName "DontNeedUsername").Password +$PathToMrngFolder = "" + +if ($PathToMrngFolder -eq "") { + Write-Error -Message 'You must set the $PathToMrngFolder variable in this script to the folder which contains mRemoteNG.exe' +} + +$assembly = [System.Reflection.Assembly]::LoadFile((Join-Path -Path $PathToMrngFolder -ChildPath "mRemoteNG.exe")) +$assembly = [System.Reflection.Assembly]::LoadFile((Join-Path -Path $PathToMrngFolder -ChildPath "BouncyCastle.Crypto.dll")) + +function New-mRemoteNGXmlSerializer { + [CmdletBinding()] + param ( + [SecureString] + $EncryptionKey + ) + + PROCESS { + $cryptoProvider = New-Object -TypeName mRemoteNG.Security.SymmetricEncryption.AeadCryptographyProvider + $saveFilter = New-Object -TypeName mRemoteNG.Security.SaveFilter -ArgumentList @($false) + $xmlSerializer = New-Object -TypeName mRemoteNG.Config.Serializers.XmlConnectionNodeSerializer -ArgumentList @($cryptoProvider, $encryptionKey, $saveFilter) + Write-Output $xmlSerializer + } +} + +function New-mRemoteNGConnectionInfo { + [CmdletBinding()] + param () + + PROCESS { + $connectionInfo = New-Object -TypeName mRemoteNG.Connection.ConnectionInfo + Write-Output $connectionInfo + } +} + +function New-mRemoteNGContainerInfo { + [CmdletBinding()] + param () + + PROCESS { + $connectionInfo = New-Object -TypeName mRemoteNG.Container.ContainerInfo + Write-Output $connectionInfo + } +} + +# Setup the services needed to do serialization +$xmlSerializer = New-mRemoteNGXmlSerializer -EncryptionKey $EncryptionKey + + + +#---------------------------------------------------------------- +# Example 1: serialize many connections, no containers +# Here you can define the number of connection info objects to create +# You can also provide a list of desired hostnames and iterate over those +$xml = "" +foreach($i in 1..5) +{ + $connectionInfo = New-mRemoteNGConnectionInfo + + # Set connection info properties + $connectionInfo.Name = "server-$i" + $connectionInfo.Hostname = "some-win-server-$i" + $connectionInfo.Protocol = [mRemoteNG.Connection.Protocol.ProtocolType]::RDP + $connectionInfo.Inheritance.Username = $true + $connectionInfo.Inheritance.Domain = $true + $connectionInfo.Inheritance.Password = $true + + $serializedConnection = $xmlSerializer.SerializeConnectionInfo($connectionInfo).ToString() + $xml += $serializedConnection + [System.Environment]::NewLine +} + +Write-Output $xml + + + + +#---------------------------------------------------------------- +# Example 2: serialize a container which has connections +# You can also create containers and add connections to them, which will be nested correctly when serialized +$xml = "" +$container = New-mRemoteNGContainerInfo +$container.Name = "ProductionServers" +$serializedContainer = $xmlSerializer.SerializeConnectionInfo($container) + +foreach($i in 1..3) +{ + $connectionInfo = New-mRemoteNGConnectionInfo + + # Set connection info properties + $connectionInfo.Name = "server-$i" + $connectionInfo.Hostname = "some-linux-server-$i" + $connectionInfo.Protocol = [mRemoteNG.Connection.Protocol.ProtocolType]::SSH2 + $connectionInfo.Inheritance.Username = $true + $connectionInfo.Inheritance.Domain = $true + $connectionInfo.Inheritance.Password = $true + + # serialize the connection + $serializedConnection = $xmlSerializer.SerializeConnectionInfo($connectionInfo) + # add the connection to the container + $serializedContainer.Add($serializedConnection) +} + +# Call ToString() on the top-level container to get the XML of it and all its children +Write-Output $serializedContainer.ToString() \ No newline at end of file diff --git a/Tools/build-relport.cmd b/Tools/build-relport.cmd index b00178b3e..b76ba441e 100644 --- a/Tools/build-relport.cmd +++ b/Tools/build-relport.cmd @@ -5,7 +5,7 @@ setlocal enabledelayedexpansion set SOLUTIONDIR=%~dp0.. rem Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441 -set SIGCHECK="%SOLUTIONDIR%\Tools\sigcheck.exe" +set SIGCHECK="%SOLUTIONDIR%\Tools\exes\sigcheck.exe" set SEVENZIP="%SOLUTIONDIR%\Tools\7zip\7za.exe" set VCVARSALL="%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" diff --git a/Tools/exes/dumpbin.exe b/Tools/exes/dumpbin.exe new file mode 100644 index 000000000..140de4d0e Binary files /dev/null and b/Tools/exes/dumpbin.exe differ diff --git a/Tools/exes/editbin.exe b/Tools/exes/editbin.exe new file mode 100644 index 000000000..489043c29 Binary files /dev/null and b/Tools/exes/editbin.exe differ diff --git a/Tools/exes/link.exe b/Tools/exes/link.exe new file mode 100644 index 000000000..117c00116 Binary files /dev/null and b/Tools/exes/link.exe differ diff --git a/Tools/exes/mspdbcore.dll b/Tools/exes/mspdbcore.dll new file mode 100644 index 000000000..7e87f6fd9 Binary files /dev/null and b/Tools/exes/mspdbcore.dll differ diff --git a/Tools/sigcheck.exe b/Tools/exes/sigcheck.exe similarity index 100% rename from Tools/sigcheck.exe rename to Tools/exes/sigcheck.exe diff --git a/Tools/find_vstool.ps1 b/Tools/find_vstool.ps1 index 85ae07a28..da2be6e1b 100644 --- a/Tools/find_vstool.ps1 +++ b/Tools/find_vstool.ps1 @@ -1,3 +1,5 @@ +[CmdletBinding()] + param ( [string] # Name of the file to find @@ -46,6 +48,7 @@ $rootSearchPaths = @( # Returns the first full path to the $FileName that our search can find foreach ($searchPath in $rootSearchPaths) { foreach ($visualStudioFolder in $searchPath) { + Write-Verbose "Searching in folder '$visualStudioFolder'" $matchingExes = [System.IO.Directory]::EnumerateFileSystemEntries($visualStudioFolder, $FileName, [System.IO.SearchOption]::AllDirectories) foreach ($matchingExe in $matchingExes) { if ((EditBinCertificateIsValid -Path $matchingExe) -and (ToolCanBeExecuted -Path $matchingExe)) { diff --git a/Tools/github_functions.ps1 b/Tools/github_functions.ps1 index 8f38fbda4..f4b3881a3 100644 --- a/Tools/github_functions.ps1 +++ b/Tools/github_functions.ps1 @@ -1,5 +1,6 @@ $githubUrl = 'https://api.github.com' - +# GitHub doesn't support the default powershell protocol (TLS 1.0) +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 function Publish-GitHubRelease { param ( @@ -170,13 +171,27 @@ function Upload-GitHubReleaseAsset { [string] [Parameter(Mandatory=$true)] # The OAuth2 token to use for authentication. - $AuthToken + $AuthToken, + + [string] + # A short description label for the asset + $Label = "" ) $UploadUri = $UploadUri -replace "(\{[\w,\?]*\})$" - $file = Get-Item -Path $FilePath + $files = Get-Item -Path $FilePath - $req_uploadZipAsset = Invoke-WebRequest -Uri "$($UploadUri)?name=$($file.Name)" -Method Post -Headers @{"Authorization"="token $AuthToken"} -ContentType $ContentType -InFile $file.FullName -ErrorAction Stop + $labelParam = "" + if ($Label -ne "") { + $labelParam = "&label=$Label" + } + + # Get-Item could produce an array of files if a wildcard is provided. (C:\*.txt) + # Upload each matching item individually + foreach ($file in $files) { + Write-Output "Uploading asset to GitHub release: '$($file.FullName)'" + $req_uploadZipAsset = Invoke-WebRequest -Uri "$($UploadUri)?name=$($file.Name)$labelParam" -Method Post -Headers @{"Authorization"="token $AuthToken"} -ContentType $ContentType -InFile $file.FullName -ErrorAction Stop + } } diff --git a/Tools/postbuild_mremotev1.ps1 b/Tools/postbuild_mremotev1.ps1 index af64186f2..7129950d1 100644 --- a/Tools/postbuild_mremotev1.ps1 +++ b/Tools/postbuild_mremotev1.ps1 @@ -45,5 +45,6 @@ Format-Table -AutoSize -Wrap -InputObject @{ & "$PSScriptRoot\verify_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName & "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName & "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning -& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName +& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath +& "$PSScriptRoot\zip_symbols.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName & "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName \ No newline at end of file diff --git a/Tools/publish_to_github.ps1 b/Tools/publish_to_github.ps1 index 4f920a0d8..ca8ed0a46 100644 --- a/Tools/publish_to_github.ps1 +++ b/Tools/publish_to_github.ps1 @@ -43,13 +43,8 @@ param ( [string] [Parameter(Mandatory=$true)] - # Path to the zip file to upload with the release - $ZipFilePath, - - [string] - [Parameter(Mandatory=$true)] - #Path to the msi file to upload with the release - $MsiFilePath, + # Path to the folder which contains release assets to upload + $ReleaseFolderPath, [string] [Parameter(Mandatory=$true)] @@ -70,7 +65,17 @@ if ($DescriptionIsBase64Encoded) { . "$PSScriptRoot\github_functions.ps1" +$releaseFolderItems = Get-ChildItem -Path $ReleaseFolderPath +$mrngPortablePath = ($releaseFolderItems | ?{$_.Name -match "portable-[\d\.]+\.zip"}).FullName +$mrngNormalPath = ($releaseFolderItems | ?{$_.Name -match "installer-[\d\.]+\.msi"}).FullName +$mrngPortableSymbolsPath = ($releaseFolderItems | ?{$_.Name -match "mremoteng-portable-symbols-[\d\.]+\.zip"}).FullName +$mrngNormalSymbolsPath = ($releaseFolderItems | ?{$_.Name -match "mremoteng-symbols-[\d\.]+\.zip"}).FullName + + $release = Publish-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseTitle $ReleaseTitle -TagName $TagName -TargetCommitish $TargetCommitish -Description $Description -IsDraft ([bool]::Parse($IsDraft)) -IsPrerelease ([bool]::Parse($IsPrerelease)) -AuthToken $AuthToken -$zipUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $ZipFilePath -ContentType "application/zip" -AuthToken $AuthToken -$msiUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $MsiFilePath -ContentType "application/octet-stream" -AuthToken $AuthToken +$zipUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngPortablePath -ContentType "application/zip" -AuthToken $AuthToken -Label "Portable Edition (zip)" +$msiUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngNormalPath -ContentType "application/octet-stream" -AuthToken $AuthToken -Label "Normal Edition (msi)" + +$portableEditionSymbols = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngPortableSymbolsPath -ContentType "application/zip" -AuthToken $AuthToken -Label "Portable Edition Debug Symbols" +$normalEditionSymbols = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngNormalSymbolsPath -ContentType "application/zip" -AuthToken $AuthToken -Label "Normal Edition Debug Symbols" Write-Output (Get-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseId $release.id -AuthToken $AuthToken) \ No newline at end of file diff --git a/Tools/rename_installer_with_version.ps1 b/Tools/rename_installer_with_version.ps1 index eec9fae0a..e06867e12 100644 --- a/Tools/rename_installer_with_version.ps1 +++ b/Tools/rename_installer_with_version.ps1 @@ -9,7 +9,7 @@ Write-Host $SolutionDir Write-Host $renameTarget $targetVersionedFile = "$SolutionDir\mRemoteV1\bin\Release\mRemoteNG.exe" -$version = &"$SolutionDir\Tools\sigcheck.exe" /accepteula -q -n $targetVersionedFile +$version = &"$SolutionDir\Tools\exes\sigcheck.exe" /accepteula -q -n $targetVersionedFile $renameTargetFileObject = Get-Item -Path $renameTarget -ErrorAction SilentlyContinue diff --git a/Tools/set_LargeAddressAware.ps1 b/Tools/set_LargeAddressAware.ps1 index 71018fc72..de3783510 100644 --- a/Tools/set_LargeAddressAware.ps1 +++ b/Tools/set_LargeAddressAware.ps1 @@ -1,3 +1,5 @@ +[CmdletBinding()] + param ( [string] [Parameter(Mandatory=$true)] @@ -10,13 +12,11 @@ param ( Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) =====" -# Find editbin.exe -$path_editBin = & "$PSScriptRoot\find_vstool.ps1" -FileName "editbin.exe" - +$path_editBin = Join-Path -Path $PSScriptRoot -ChildPath "exes\editbin.exe" $path_outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName # Set LargeAddressAware Write-Output "Setting LargeAddressAware on binary file:`n`"$path_outputExe`" `nwith:`n`"$path_editBin`"" -& $path_editBin "/largeaddressaware" "$path_outputExe" +& "$path_editBin" /largeaddressaware "$path_outputExe" Write-Output "" \ No newline at end of file diff --git a/Tools/tidy_files_for_release.ps1 b/Tools/tidy_files_for_release.ps1 index c02e7e48a..b56218fb1 100644 --- a/Tools/tidy_files_for_release.ps1 +++ b/Tools/tidy_files_for_release.ps1 @@ -15,7 +15,6 @@ if ($ConfigurationName -match "Release") { Write-Output "Removing unnecessary files from Release versions" Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "app.publish") -Recurse -Force $filesToDelete = Get-ChildItem -Path $TargetDir -Recurse -Include @( - "*.pdb", "*.publish", "*.xml", "*.backup", diff --git a/Tools/verify_LargeAddressAware.ps1 b/Tools/verify_LargeAddressAware.ps1 index 2a3525f44..0c77bef8f 100644 --- a/Tools/verify_LargeAddressAware.ps1 +++ b/Tools/verify_LargeAddressAware.ps1 @@ -1,3 +1,5 @@ +[CmdletBinding()] + param ( [string] [Parameter(Mandatory=$true)] @@ -10,13 +12,11 @@ param ( Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) =====" -# Find editbin.exe -$path_dumpBin = & "$PSScriptRoot\find_vstool.ps1" -FileName "dumpbin.exe" - +$path_dumpBin = Join-Path -Path $PSScriptRoot -ChildPath "exes\dumpbin.exe" $path_outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName # Dump exe header -$output = & "$path_dumpBin" /NOLOGO /HEADERS $path_outputExe | Select-String large +$output = & "$path_dumpBin" /NOLOGO /HEADERS "$path_outputExe" | Select-String large if ($output -eq $null) { @@ -27,6 +27,4 @@ else Write-Output $output.ToString().TrimStart(" ") } - - Write-Output "" \ No newline at end of file diff --git a/Tools/verify_binary_signatures.ps1 b/Tools/verify_binary_signatures.ps1 index 6e65b58a3..a54555c26 100644 --- a/Tools/verify_binary_signatures.ps1 +++ b/Tools/verify_binary_signatures.ps1 @@ -8,6 +8,7 @@ param ( $ConfigurationName, [string] + [Parameter(Mandatory=$true)] # The code signing certificate to use when signing the files. $CertificatePath ) @@ -17,11 +18,11 @@ Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) =====" # validate release versions and if the certificate is available if ($ConfigurationName -match "Release") { - if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf)) - { + if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf)) + { Write-Output "Certificate is not present - files likely not signed - we won't verify file signatures." return - } + } Write-Output "Verifying signature of binaries" Write-Output "Getting files from path: $TargetDir" diff --git a/Tools/zip_portable_files.ps1 b/Tools/zip_portable_files.ps1 index 97ddeebc0..6af31e7ce 100644 --- a/Tools/zip_portable_files.ps1 +++ b/Tools/zip_portable_files.ps1 @@ -13,13 +13,49 @@ 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" + + $tempFolderPath = Join-Path -Path $SolutionDir -ChildPath "mRemoteV1\bin\package" + Remove-Item -Recurse $tempFolderPath -ErrorAction SilentlyContinue | Out-Null + New-Item $tempFolderPath -ItemType "directory" | Out-Null + + Copy-Item "$($SolutionDir)mRemoteV1\Resources\PuTTYNG.exe" -Destination $tempFolderPath + + #Write-Output "$($SolutionDir)mRemoteV1\bin\$ConfigurationName" + #Write-Output "$($SolutionDir)mRemoteV1\bin\package" + Copy-Item "$($SolutionDir)mRemoteV1\bin\$ConfigurationName\*" -Destination $tempFolderPath -Recurse -Force + # Delete any PDB files that accidentally get copied into the temp folder + Get-ChildItem -Path $tempFolderPath -Filter "*.pdb" | Remove-Item + Copy-Item "$($SolutionDir)*.txt" -Destination $tempFolderPath + + Write-Output "Creating portable ZIP file $($PortableZip)" + Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue + & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip (Join-Path -Path $tempFolderPath -ChildPath "*.*") + #& $SEVENZIP a -bt -mx=9 -tzip -y $PortableZip "$($SolutionDir)*.TXT" } else { Write-Output "We will not zip anything - this isnt a portable release build." diff --git a/Tools/zip_portable_files_appv.ps1 b/Tools/zip_portable_files_appv.ps1 new file mode 100644 index 000000000..52a72ce33 --- /dev/null +++ b/Tools/zip_portable_files_appv.ps1 @@ -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." +} \ No newline at end of file diff --git a/Tools/zip_symbols.ps1 b/Tools/zip_symbols.ps1 new file mode 100644 index 000000000..bf2d2878a --- /dev/null +++ b/Tools/zip_symbols.ps1 @@ -0,0 +1,56 @@ +param ( + [string] + [Parameter(Mandatory=$true)] + $SolutionDir, + + [string] + [Parameter(Mandatory=$true)] + $TargetDir, + + [string] + [Parameter(Mandatory=$true)] + $ConfigurationName +) + +Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) =====" + +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 (trimmed): '$($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") { + Write-Output "Packaging debug symbols" + + $version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe" + + Write-Output "Version is $($version)" + + if ($ConfigurationName -match "Portable") { + $zipFilePrefix = "mRemoteNG-Portable-symbols" + } else { + $zipFilePrefix = "mRemoteNG-symbols" + } + + $outputZipPath="$($SolutionDir)Release\$zipFilePrefix-$($version).zip" + + Write-Output "Creating debug symbols ZIP file $($outputZipPath)" + Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue + & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath (Join-Path -Path $TargetDir -ChildPath "*.pdb") +} +else { + Write-Output "We will not package debug symbols - this isnt a release build." +} + +Write-Output "" \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..1aa639bce --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,28 @@ +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: +- ps: C:\projects\mremoteng\mRemoteV1\Resources\CitrixReceiver.exe DONOTSTARTCC=1 ENABLE_SSON="No" /silent | out-null +before_build: +- cmd: nuget restore +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 +artifacts: +- path: Release\*.msi + name: mRemoteNG-installer.msi +- path: Release\*.zip + name: mRemoteNG-portable.zip \ No newline at end of file diff --git a/mRemoteNG.Specs/App.config b/mRemoteNG.Specs/App.config index a855e3c77..7695b8383 100644 --- a/mRemoteNG.Specs/App.config +++ b/mRemoteNG.Specs/App.config @@ -1,4 +1,4 @@ - +
@@ -9,6 +9,10 @@ + + + + diff --git a/mRemoteNG.Specs/Features/CredentialRepository.feature.cs b/mRemoteNG.Specs/Features/CredentialRepository.feature.cs index c25ebd7d7..3d9845e23 100644 --- a/mRemoteNG.Specs/Features/CredentialRepository.feature.cs +++ b/mRemoteNG.Specs/Features/CredentialRepository.feature.cs @@ -9,6 +9,9 @@ // // ------------------------------------------------------------------------------ #region Designer generated code + +using NUnit.Framework; + #pragma warning disable namespace mRemoteNG.Specs.Features { @@ -67,6 +70,7 @@ namespace mRemoteNG.Specs.Features [NUnit.Framework.TestAttribute()] [NUnit.Framework.DescriptionAttribute("Load credential repository")] [NUnit.Framework.CategoryAttribute("credentials")] + [Ignore("Cred Repo not implmented currently.")] public virtual void LoadCredentialRepository() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Load credential repository", new string[] { @@ -87,6 +91,7 @@ this.ScenarioSetup(scenarioInfo); [NUnit.Framework.TestAttribute()] [NUnit.Framework.DescriptionAttribute("Add credential record")] + [Ignore("Cred Repo not implmented currently.")] public virtual void AddCredentialRecord() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Add credential record", ((string[])(null))); @@ -108,6 +113,7 @@ this.ScenarioSetup(scenarioInfo); [NUnit.Framework.TestAttribute()] [NUnit.Framework.DescriptionAttribute("Unload credential repository")] + [Ignore("Cred Repo not implmented currently.")] public virtual void UnloadCredentialRepository() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Unload credential repository", ((string[])(null))); diff --git a/mRemoteNG.Specs/Features/CredentialRepositoryList.feature.cs b/mRemoteNG.Specs/Features/CredentialRepositoryList.feature.cs index f5cd04509..c1f517c06 100644 --- a/mRemoteNG.Specs/Features/CredentialRepositoryList.feature.cs +++ b/mRemoteNG.Specs/Features/CredentialRepositoryList.feature.cs @@ -9,6 +9,9 @@ // // ------------------------------------------------------------------------------ #region Designer generated code + +using NUnit.Framework; + #pragma warning disable namespace mRemoteNG.Specs.Features { @@ -19,6 +22,7 @@ namespace mRemoteNG.Specs.Features [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [NUnit.Framework.TestFixtureAttribute()] [NUnit.Framework.DescriptionAttribute("CredentialRepositoryList")] + [Ignore("Cred Repo not implmented currently.")] public partial class CredentialRepositoryListFeature { @@ -67,6 +71,7 @@ namespace mRemoteNG.Specs.Features [NUnit.Framework.TestAttribute()] [NUnit.Framework.DescriptionAttribute("Add a new credential repository")] [NUnit.Framework.CategoryAttribute("credentials")] + [Ignore("Cred Repo not implmented currently.")] public virtual void AddANewCredentialRepository() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Add a new credential repository", new string[] { @@ -87,6 +92,7 @@ this.ScenarioSetup(scenarioInfo); [NUnit.Framework.TestAttribute()] [NUnit.Framework.DescriptionAttribute("Remove a credential repository")] + [Ignore("Cred Repo not implmented currently.")] public virtual void RemoveACredentialRepository() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Remove a credential repository", ((string[])(null))); diff --git a/mRemoteNG.Specs/mRemoteNG.Specs.csproj b/mRemoteNG.Specs/mRemoteNG.Specs.csproj index 4bb34ad15..0a02eb4af 100644 --- a/mRemoteNG.Specs/mRemoteNG.Specs.csproj +++ b/mRemoteNG.Specs/mRemoteNG.Specs.csproj @@ -34,8 +34,8 @@ ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll - - ..\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll + + ..\packages\NUnit.3.9.0\lib\net45\nunit.framework.dll diff --git a/mRemoteNG.Specs/packages.config b/mRemoteNG.Specs/packages.config index 1451c1386..95c1d0242 100644 --- a/mRemoteNG.Specs/packages.config +++ b/mRemoteNG.Specs/packages.config @@ -1,14 +1,14 @@  - + - - + + diff --git a/mRemoteNGTests/Config/CredentialHarvesterTests.cs b/mRemoteNGTests/Config/CredentialHarvesterTests.cs index 5ad9d6c2e..cfefafede 100644 --- a/mRemoteNGTests/Config/CredentialHarvesterTests.cs +++ b/mRemoteNGTests/Config/CredentialHarvesterTests.cs @@ -4,6 +4,7 @@ using System.Security; using System.Xml.Linq; using mRemoteNG.Config; using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Security; diff --git a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormatTests.cs b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormatTests.cs new file mode 100644 index 000000000..92d844b0f --- /dev/null +++ b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormatTests.cs @@ -0,0 +1,185 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using mRemoteNG.Config.Serializers.Csv; +using mRemoteNG.Connection; +using mRemoteNG.Connection.Protocol; +using mRemoteNG.Connection.Protocol.Http; +using mRemoteNG.Connection.Protocol.ICA; +using mRemoteNG.Connection.Protocol.RDP; +using mRemoteNG.Connection.Protocol.VNC; +using mRemoteNG.Credential; +using mRemoteNG.Security; +using mRemoteNGTests.TestHelpers; +using NSubstitute; +using NUnit.Framework; + +namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Csv +{ + public class CsvConnectionsDeserializerMremotengFormatTests + { + private CsvConnectionsDeserializerMremotengFormat _deserializer; + private CsvConnectionsSerializerMremotengFormat _serializer; + + [SetUp] + public void Setup() + { + _deserializer = new CsvConnectionsDeserializerMremotengFormat(); + var credentialRepositoryList = Substitute.For(); + _serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), credentialRepositoryList); + } + + [TestCaseSource(typeof(DeserializationTestSource), nameof(DeserializationTestSource.ConnectionPropertyTestCases))] + public object ConnectionPropertiesDeserializedCorrectly(string propertyToCheck) + { + var csv = _serializer.Serialize(GetTestConnection()); + var deserializedConnections = _deserializer.Deserialize(csv); + var connection = deserializedConnections.GetRecursiveChildList().FirstOrDefault(); + var propertyValue = typeof(ConnectionInfo).GetProperty(propertyToCheck)?.GetValue(connection); + return propertyValue; + } + + [TestCaseSource(typeof(DeserializationTestSource), nameof(DeserializationTestSource.InheritanceTestCases))] + public object InheritancePropertiesDeserializedCorrectly(string propertyToCheck) + { + var csv = _serializer.Serialize(GetTestConnectionWithAllInherited()); + var deserializedConnections = _deserializer.Deserialize(csv); + var connection = deserializedConnections.GetRecursiveChildList().FirstOrDefault(); + connection?.RemoveParent(); + var propertyValue = typeof(ConnectionInfoInheritance).GetProperty(propertyToCheck)?.GetValue(connection?.Inheritance); + return propertyValue; + } + + [Test] + public void TreeStructureDeserializedCorrectly() + { + //Root + // |- folder1 + // | |- Con1 + // |- Con2 + var treeModel = new ConnectionTreeModelBuilder().Build(); + var csv = _serializer.Serialize(treeModel); + var deserializedConnections = _deserializer.Deserialize(csv); + var con1 = deserializedConnections.GetRecursiveChildList().First(info => info.Name == "Con1"); + var folder1 = deserializedConnections.GetRecursiveChildList().First(info => info.Name == "folder1"); + Assert.That(con1.Parent, Is.EqualTo(folder1)); + } + + internal static ConnectionInfo GetTestConnection() + { + return new ConnectionInfo + { + Name = "SomeName", + Description = "SomeDescription", + Icon = "SomeIcon", + Panel = "SomePanel", + Username = "SomeUsername", + Password = "SomePassword", + Domain = "SomeDomain", + Hostname = "SomeHostname", + PuttySession = "SomePuttySession", + LoadBalanceInfo = "SomeLoadBalanceInfo", + PreExtApp = "SomePreExtApp", + PostExtApp = "SomePostExtApp", + MacAddress = "SomeMacAddress", + UserField = "SomeUserField", + ExtApp = "SomeExtApp", + VNCProxyUsername = "SomeVNCProxyUsername", + VNCProxyPassword = "SomeVNCProxyPassword", + RDGatewayUsername = "SomeRDGatewayUsername", + RDGatewayPassword = "SomeRDGatewayPassword", + RDGatewayDomain = "SomeRDGatewayDomain", + VNCProxyIP = "SomeVNCProxyIP", + RDGatewayHostname = "SomeRDGatewayHostname", + Protocol = ProtocolType.ICA, + Port = 999, + UseConsoleSession = true, + UseCredSsp = true, + RenderingEngine = HTTPBase.RenderingEngine.Gecko, + ICAEncryptionStrength = IcaProtocol.EncryptionStrength.Encr40Bit, + RDPAuthenticationLevel = RdpProtocol.AuthenticationLevel.WarnOnFailedAuth, + Colors = RdpProtocol.RDPColors.Colors16Bit, + Resolution = RdpProtocol.RDPResolutions.Res1366x768, + AutomaticResize = true, + DisplayWallpaper = true, + DisplayThemes = true, + EnableFontSmoothing = true, + EnableDesktopComposition = true, + CacheBitmaps = true, + RedirectDiskDrives = true, + RedirectPorts = true, + RedirectPrinters = true, + RedirectSmartCards = true, + RedirectSound = RdpProtocol.RDPSounds.LeaveAtRemoteComputer, + RedirectKeys = true, + VNCCompression = ProtocolVNC.Compression.Comp4, + VNCEncoding = ProtocolVNC.Encoding.EncRRE, + VNCAuthMode = ProtocolVNC.AuthMode.AuthVNC, + VNCProxyType = ProtocolVNC.ProxyType.ProxySocks5, + VNCProxyPort = 123, + VNCColors = ProtocolVNC.Colors.Col8Bit, + VNCSmartSizeMode = ProtocolVNC.SmartSizeMode.SmartSAspect, + VNCViewOnly = true, + RDGatewayUsageMethod = RdpProtocol.RDGatewayUsageMethod.Detect, + RDGatewayUseConnectionCredentials = RdpProtocol.RDGatewayUseConnectionCredentials.SmartCard + }; + } + + internal static ConnectionInfo GetTestConnectionWithAllInherited() + { + var connectionInfo = new ConnectionInfo(); + connectionInfo.Inheritance.TurnOnInheritanceCompletely(); + return connectionInfo; + } + + private class DeserializationTestSource + { + public static IEnumerable ConnectionPropertyTestCases() + { + var ignoreProperties = new[] + { + nameof(ConnectionInfo.Inheritance), + nameof(ConnectionInfo.ConstantID), + nameof(ConnectionInfo.Parent) + }; + var properties = typeof(ConnectionInfo) + .GetProperties() + .Where(property => !ignoreProperties.Contains(property.Name)); + var testCases = new List(); + var testConnectionInfo = GetTestConnection(); + + foreach (var property in properties) + { + testCases.Add( + new TestCaseData(property.Name) + .Returns(property.GetValue(testConnectionInfo))); + } + + return testCases; + } + + public static IEnumerable InheritanceTestCases() + { + var ignoreProperties = new[] + { + nameof(ConnectionInfoInheritance.EverythingInherited), + nameof(ConnectionInfoInheritance.Parent) + }; + var properties = typeof(ConnectionInfoInheritance) + .GetProperties() + .Where(property => !ignoreProperties.Contains(property.Name)); + var testCases = new List(); + var testInheritance = GetTestConnectionWithAllInherited().Inheritance; + + foreach (var property in properties) + { + testCases.Add( + new TestCaseData(property.Name) + .Returns(property.GetValue(testInheritance))); + } + + return testCases; + } + } + } +} diff --git a/mRemoteNGTests/Config/Serializers/MiscSerializers/CsvConnectionsSerializerMremotengFormatTests.cs b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormatTests.cs similarity index 56% rename from mRemoteNGTests/Config/Serializers/MiscSerializers/CsvConnectionsSerializerMremotengFormatTests.cs rename to mRemoteNGTests/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormatTests.cs index e5d14ac91..c0c562d1d 100644 --- a/mRemoteNGTests/Config/Serializers/MiscSerializers/CsvConnectionsSerializerMremotengFormatTests.cs +++ b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormatTests.cs @@ -1,13 +1,17 @@ using System; +using System.Linq; using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Csv; using mRemoteNG.Connection; +using mRemoteNG.Container; using mRemoteNG.Credential; using mRemoteNG.Security; using mRemoteNG.Tree; +using mRemoteNGTests.TestHelpers; using NSubstitute; using NUnit.Framework; -namespace mRemoteNGTests.Config.Serializers.MiscSerializers +namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Csv { public class CsvConnectionsSerializerMremotengFormatTests { @@ -28,6 +32,24 @@ namespace mRemoteNGTests.Config.Serializers.MiscSerializers _credentialRepositoryList.GetCredentialRecord(new Guid()).ReturnsForAnyArgs(credRecord); } + [Test] + public void SerializesNodeId() + { + var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList); + var connectionInfo = BuildConnectionInfo(); + var csv = serializer.Serialize(connectionInfo); + Assert.That(csv, Does.Match(connectionInfo.ConstantID)); + } + + [Test] + public void DoesntSerializeTheRootNode() + { + var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList); + var treeModel = new ConnectionTreeModelBuilder().Build(); + var csv = serializer.Serialize(treeModel); + Assert.That(csv, Does.Not.Match($"{treeModel.RootNodes[0].ConstantID};.*;{TreeNodeType.Root}")); + } + [TestCase(Username)] [TestCase(Domain)] [TestCase(Password)] @@ -82,6 +104,32 @@ namespace mRemoteNGTests.Config.Serializers.MiscSerializers Assert.Throws(() => serializer.Serialize((ConnectionTreeModel)null)); } + [Test] + public void FoldersAreSerialized() + { + var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList); + var container = BuildContainer(); + var csv = serializer.Serialize(container); + Assert.That(csv, Does.Match(container.Name)); + Assert.That(csv, Does.Match(container.Username)); + Assert.That(csv, Does.Match(container.Domain)); + Assert.That(csv, Does.Match(container.Password)); + Assert.That(csv, Does.Contain(TreeNodeType.Container.ToString())); + } + + [Test] + public void SerializationIncludesRawInheritedValuesIfObjectInheritsFromParentOutsideOfSerializationScope() + { + var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList); + var treeModel = new ConnectionTreeModelBuilder().Build(); + var serializationTarget = treeModel.GetRecursiveChildList().First(info => info.Name == "folder3"); + var csv = serializer.Serialize(serializationTarget); + var lineWithFolder3 = csv.Split(new[] {Environment.NewLine}, StringSplitOptions.None).First(s => s.Contains(serializationTarget.Name)); + Assert.That(lineWithFolder3, Does.Contain(serializationTarget.Username)); + Assert.That(lineWithFolder3, Does.Contain(serializationTarget.Domain)); + Assert.That(lineWithFolder3, Does.Contain(serializationTarget.Password)); + } + private ConnectionInfo BuildConnectionInfo() { return new ConnectionInfo @@ -93,5 +141,16 @@ namespace mRemoteNGTests.Config.Serializers.MiscSerializers Inheritance = {Colors = true} }; } + + private ContainerInfo BuildContainer() + { + return new ContainerInfo + { + Name = "MyFolder", + Username = "BlahBlah1", + Domain = "aklkskkksh8", + Password = "qweraslkdjf87" + }; + } } } \ No newline at end of file diff --git a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/ValidateXmlSchemas.cs b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/ValidateXmlSchemas.cs new file mode 100644 index 000000000..c0818b866 --- /dev/null +++ b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/ValidateXmlSchemas.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using mRemoteNG.Config.Serializers.Xml; +using mRemoteNG.Security; +using mRemoteNG.Security.SymmetricEncryption; +using mRemoteNG.Tree; +using mRemoteNG.Tree.Root; +using mRemoteNGTests.TestHelpers; +using NUnit.Framework; + +namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml +{ + public class ValidateXmlSchemas + { + private XmlConnectionsSerializer _serializer; + private ConnectionTreeModel _connectionTreeModel; + private ICryptographyProvider _cryptographyProvider; + private XmlReaderSettings _xmlReaderSettings; + + [SetUp] + public void Setup() + { + _connectionTreeModel = new ConnectionTreeModelBuilder().Build(); + _cryptographyProvider = new AeadCryptographyProvider(); + var connectionNodeSerializer = new XmlConnectionNodeSerializer26( + _cryptographyProvider, + _connectionTreeModel.RootNodes.OfType().First().PasswordString.ConvertToSecureString(), + new SaveFilter()); + _serializer = new XmlConnectionsSerializer(_cryptographyProvider, connectionNodeSerializer); + _xmlReaderSettings = new XmlReaderSettings + { + ValidationType = ValidationType.Schema, + ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema | + XmlSchemaValidationFlags.ProcessSchemaLocation | + XmlSchemaValidationFlags.ReportValidationWarnings + }; + } + + [Test] + public void ValidateSchema() + { + var sb = new StringBuilder(); + var xml = _serializer.Serialize(_connectionTreeModel); + + var schemaFile = GetTargetPath("mremoteng_confcons_v2_6.xsd"); + _xmlReaderSettings.Schemas.Add("http://mremoteng.org", schemaFile); + _xmlReaderSettings.ValidationEventHandler += (sender, args) => + { + sb.AppendLine($"{args.Severity}: {args.Message}"); + }; + + using (var stream = GenerateStreamFromString(xml)) + { + var reader = XmlReader.Create(stream, _xmlReaderSettings); + while (reader.Read()) ; + } + + Assert.That(sb.ToString(), Is.Empty); + } + + public string GetTargetPath(string fileName, [CallerFilePath] string sourceFilePath = "") + { + const string debugOrRelease = +#if DEBUG + "Debug"; +#else + "Release"; +#endif + + const string normalOrPortable = +#if PORTABLE + " Portable"; +#else + ""; +#endif + var path = Path.GetDirectoryName(sourceFilePath); + var filePath = $@"{path}\..\..\..\..\bin\{debugOrRelease}{normalOrPortable}\Schemas\{fileName}"; + return filePath; + } + + private Stream GenerateStreamFromString(string s) + { + var stream = new MemoryStream(); + var writer = new StreamWriter(stream); + writer.Write(s); + writer.Flush(); + stream.Position = 0; + return stream; + } + } +} diff --git a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsDeserializerTests.cs b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializerTests.cs similarity index 93% rename from mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsDeserializerTests.cs rename to mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializerTests.cs index aad9cc078..9b20a0e33 100644 --- a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsDeserializerTests.cs +++ b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializerTests.cs @@ -1,7 +1,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Security; @@ -9,7 +9,7 @@ using mRemoteNG.Tree; using mRemoteNGTests.Properties; using NUnit.Framework; -namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers +namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml { public class XmlConnectionsDeserializerTests { @@ -18,7 +18,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers public void Setup(string confCons, string password) { - _xmlConnectionsDeserializer = new XmlConnectionsDeserializer(password.ConvertToSecureString); + _xmlConnectionsDeserializer = new XmlConnectionsDeserializer(() => password.ConvertToSecureString()); _connectionTreeModel = _xmlConnectionsDeserializer.Deserialize(confCons); } @@ -104,6 +104,14 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers Assert.That(folder22.Inheritance.Username, Is.True); } + [TestCaseSource(typeof(XmlConnectionsDeserializerFixtureData), nameof(XmlConnectionsDeserializerFixtureData.FixtureParams))] + public void ExpandedPropertyGetsDeserialized(Datagram testData) + { + Setup(testData.ConfCons, testData.Password); + var folder1 = GetFolderNamed("Folder1", _connectionTreeModel.GetRecursiveChildList()); + Assert.That(folder1.IsExpanded, Is.True); + } + private bool ContainsNodeNamed(string name, IEnumerable list) { return list.Any(node => node.Name == name); diff --git a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentCompilerTests.cs b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentCompilerTests.cs similarity index 98% rename from mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentCompilerTests.cs rename to mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentCompilerTests.cs index d114e45b7..d932fa698 100644 --- a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentCompilerTests.cs +++ b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentCompilerTests.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Xml.XPath; using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Security; @@ -9,7 +10,7 @@ using mRemoteNG.Tree; using mRemoteNG.Tree.Root; using NUnit.Framework; -namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers +namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml { public class XmlConnectionsDocumentCompilerTests { diff --git a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentEncryptorTests.cs b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentEncryptorTests.cs similarity index 98% rename from mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentEncryptorTests.cs rename to mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentEncryptorTests.cs index cd06aee14..563eeef4a 100644 --- a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentEncryptorTests.cs +++ b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentEncryptorTests.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Xml.Linq; using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Security; @@ -9,7 +10,7 @@ using mRemoteNG.Tree; using mRemoteNG.Tree.Root; using NUnit.Framework; -namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers +namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml { public class XmlConnectionsDocumentEncryptorTests { diff --git a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsSerializerTests.cs b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializerTests.cs similarity index 97% rename from mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsSerializerTests.cs rename to mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializerTests.cs index fc3e518c5..a3b3310ad 100644 --- a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlConnectionsSerializerTests.cs +++ b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializerTests.cs @@ -2,6 +2,7 @@ using System.Xml; using System.Xml.Linq; using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Security; @@ -10,7 +11,7 @@ using mRemoteNG.Tree; using mRemoteNG.Tree.Root; using NUnit.Framework; -namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers +namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml { public class XmlConnectionsSerializerTests { @@ -55,7 +56,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers [TestCase("Username", "")] [TestCase("Domain", "")] [TestCase("Password", "")] - [TestCase("InheritAutomaticResize", "False")] + [TestCase("InheritAutomaticResize", "false")] public void SerializerRespectsSaveFilterSettings(string attributeName, string expectedValue) { var connectionNodeSerializer = new XmlConnectionNodeSerializer26( diff --git a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlRootNodeSerializerTests.cs b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlRootNodeSerializerTests.cs similarity index 97% rename from mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlRootNodeSerializerTests.cs rename to mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlRootNodeSerializerTests.cs index f00d8c9ae..8a04af9d2 100644 --- a/mRemoteNGTests/Config/Serializers/ConnectionSerializers/XmlRootNodeSerializerTests.cs +++ b/mRemoteNGTests/Config/Serializers/ConnectionSerializers/Xml/XmlRootNodeSerializerTests.cs @@ -2,13 +2,14 @@ using System.Collections; using System.Xml.Linq; using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Security; using mRemoteNG.Security.Factories; using mRemoteNG.Security.SymmetricEncryption; using mRemoteNG.Tree.Root; using NUnit.Framework; -namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers +namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml { public class XmlRootNodeSerializerTests { @@ -75,7 +76,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers { var element = _rootNodeSerializer.SerializeRootNodeInfo(_rootNodeInfo, _cryptographyProvider, fullFileEncryption); var attributeValue = element.Attribute(XName.Get("FullFileEncryption"))?.Value; - Assert.That(attributeValue, Is.EqualTo(fullFileEncryption.ToString())); + Assert.That(bool.Parse(attributeValue), Is.EqualTo(fullFileEncryption)); } [TestCase("", "ThisIsNotProtected")] diff --git a/mRemoteNGTests/Config/Serializers/DataTableSerializerTests.cs b/mRemoteNGTests/Config/Serializers/DataTableSerializerTests.cs index 17bd78031..5176fa1a9 100644 --- a/mRemoteNGTests/Config/Serializers/DataTableSerializerTests.cs +++ b/mRemoteNGTests/Config/Serializers/DataTableSerializerTests.cs @@ -1,4 +1,5 @@ -using mRemoteNG.Config.Serializers; +using System.Linq; +using mRemoteNG.Config.Serializers; using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Security; @@ -26,7 +27,7 @@ namespace mRemoteNGTests.Config.Serializers { var model = CreateConnectionTreeModel(); var dataTable = _dataTableSerializer.Serialize(model); - Assert.That(dataTable.Rows.Count, Is.EqualTo(3)); + Assert.That(dataTable.Rows.Count, Is.EqualTo(model.GetRecursiveChildList().Count())); } [Test] diff --git a/mRemoteNGTests/Connection/AbstractConnectionInfoDataTests.cs b/mRemoteNGTests/Connection/AbstractConnectionInfoDataTests.cs index 3e012cd8d..950134060 100644 --- a/mRemoteNGTests/Connection/AbstractConnectionInfoDataTests.cs +++ b/mRemoteNGTests/Connection/AbstractConnectionInfoDataTests.cs @@ -1,4 +1,5 @@ -using mRemoteNG.Connection; +using System; +using mRemoteNG.Connection; using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol.Http; using mRemoteNG.Connection.Protocol.ICA; @@ -9,10 +10,14 @@ using NUnit.Framework; namespace mRemoteNGTests.Connection { - public class AbstractConnectionInfoDataTests + public class AbstractConnectionInfoDataTests { #pragma warning disable 618 - private class TestAbstractConnectionInfoData : AbstractConnectionRecord {} + private class TestAbstractConnectionInfoData : AbstractConnectionRecord { + public TestAbstractConnectionInfoData() : base(Guid.NewGuid().ToString()) + { + } + } #pragma warning restore 618 private TestAbstractConnectionInfoData _testAbstractConnectionInfoData; diff --git a/mRemoteNGTests/Connection/ConnectionInfoInheritanceTests.cs b/mRemoteNGTests/Connection/ConnectionInfoInheritanceTests.cs index 5778e2ac5..2b18a5dc0 100644 --- a/mRemoteNGTests/Connection/ConnectionInfoInheritanceTests.cs +++ b/mRemoteNGTests/Connection/ConnectionInfoInheritanceTests.cs @@ -1,8 +1,9 @@ using mRemoteNG.Connection; +using mRemoteNG.Container; using NUnit.Framework; -using System.Reflection; using System.Collections; using System.Linq; +using System.Reflection; namespace mRemoteNGTests.Connection { @@ -74,6 +75,22 @@ namespace mRemoteNGTests.Connection Assert.That(hasEverythingInheritedProperty, Is.False); } + [Test] + public void AlwaysReturnInheritedValueIfRequested() + { + var expectedSetting = false; + + var container = new ContainerInfo { AutomaticResize = expectedSetting }; + var con1 = new ConnectionInfo + { + AutomaticResize = true, + Inheritance = {AutomaticResize = true} + }; + container.AddChild(con1); + + Assert.That(con1.AutomaticResize, Is.EqualTo(expectedSetting)); + } + private bool AllInheritancePropertiesAreTrue() { var allPropertiesTrue = true; diff --git a/mRemoteNGTests/Connection/ConnectionInfoTests.cs b/mRemoteNGTests/Connection/ConnectionInfoTests.cs index 5475bdb63..9e127a0ba 100644 --- a/mRemoteNGTests/Connection/ConnectionInfoTests.cs +++ b/mRemoteNGTests/Connection/ConnectionInfoTests.cs @@ -27,22 +27,6 @@ namespace mRemoteNGTests.Connection _connectionInfo = null; } - [Test] - public void CreatingConnectionInfoWithParentSetsTheParentProperty() - { - var container = new ContainerInfo(); - var connectionInfo = new ConnectionInfo(container); - Assert.That(connectionInfo.Parent, Is.EqualTo(container)); - } - - [Test] - public void CreatingConnectionInfoWithParentAddsToTheParentsChildList() - { - var container = new ContainerInfo(); - var connectionInfo = new ConnectionInfo(container); - Assert.That(container.Children, Does.Contain(connectionInfo)); - } - [Test] public void CopyCreatesMemberwiseCopy() { @@ -59,6 +43,20 @@ namespace mRemoteNGTests.Connection Assert.That(clonedConnection.Parent, Is.Null); } + [Test] + public void CloneAlsoCopiesInheritanceObject() + { + var clonedConnection = _connectionInfo.Clone(); + Assert.That(clonedConnection.Inheritance, Is.Not.EqualTo(_connectionInfo.Inheritance)); + } + + [Test] + public void CloneCorrectlySetsParentOfInheritanceObject() + { + var clonedConnection = _connectionInfo.Clone(); + Assert.That(clonedConnection.Inheritance.Parent, Is.EqualTo(clonedConnection)); + } + [Test] public void CopyFromCopiesProperties() { diff --git a/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs b/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs index 0d9cf4a37..1bf631285 100644 --- a/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs +++ b/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs @@ -1,73 +1,62 @@ -using mRemoteNG.Connection; -using mRemoteNG.Connection.Protocol; +using System.Collections.Generic; +using System.Reflection; +using mRemoteNG.Connection; +using mRemoteNGTests.TestHelpers; using NUnit.Framework; namespace mRemoteNGTests.Connection { - public class DefaultConnectionInfoTests - { - private string _testDomain = "somedomain"; + public class DefaultConnectionInfoTests + { + private ConnectionInfo _randomizedConnectionInfo; [SetUp] public void Setup() { - DefaultConnectionInfo.Instance.Domain = ""; + _randomizedConnectionInfo = ConnectionInfoHelpers.GetRandomizedConnectionInfo(); } - [Test] - public void LoadingDefaultInfoUpdatesAllProperties() + [TestCaseSource(nameof(GetConnectionInfoProperties))] + public void LoadingDefaultInfoUpdatesAllProperties(PropertyInfo property) { - var connectionInfoSource = new ConnectionInfo { Domain = _testDomain }; - DefaultConnectionInfo.Instance.LoadFrom(connectionInfoSource); - Assert.That(DefaultConnectionInfo.Instance.Domain, Is.EqualTo(_testDomain)); + DefaultConnectionInfo.Instance.LoadFrom(_randomizedConnectionInfo); + var valueInDestination = property.GetValue(DefaultConnectionInfo.Instance); + var valueInSource = property.GetValue(_randomizedConnectionInfo); + Assert.That(valueInDestination, Is.EqualTo(valueInSource)); } - [Test] - public void SavingDefaultConnectionInfoExportsAllProperties() + [TestCaseSource(nameof(GetConnectionInfoProperties))] + public void SavingDefaultConnectionInfoExportsAllProperties(PropertyInfo property) { var saveTarget = new ConnectionInfo(); - DefaultConnectionInfo.Instance.Domain = _testDomain; + var randomizedValue = property.GetValue(_randomizedConnectionInfo); + property.SetValue(DefaultConnectionInfo.Instance, randomizedValue); DefaultConnectionInfo.Instance.SaveTo(saveTarget); - Assert.That(saveTarget.Domain, Is.EqualTo(_testDomain)); + var valueInDestination = property.GetValue(saveTarget); + var valueInSource = property.GetValue(DefaultConnectionInfo.Instance); + Assert.That(valueInDestination, Is.EqualTo(valueInSource)); } - [Test] - public void CanSaveEnumValuesToString() - { - const ProtocolType targetProtocol = ProtocolType.RAW; - var saveTarget = new AllStringPropertySaveTarget(); - DefaultConnectionInfo.Instance.Protocol = targetProtocol; + [TestCaseSource(nameof(GetConnectionInfoProperties))] + public void CanSaveDefaultConnectionToModelWithAllStringProperties(PropertyInfo property) + { + var saveTarget = new SerializableConnectionInfoAllPropertiesOfType(); + + // randomize default connnection values to ensure we dont get false passing tests + var randomizedValue = property.GetValue(_randomizedConnectionInfo); + property.SetValue(DefaultConnectionInfo.Instance, randomizedValue); + DefaultConnectionInfo.Instance.SaveTo(saveTarget); - Assert.That(saveTarget.Protocol, Is.EqualTo(targetProtocol.ToString())); + + var valueInSource = property.GetValue(DefaultConnectionInfo.Instance).ToString(); + var valueInDestination = saveTarget.GetType().GetProperty(property.Name).GetValue(saveTarget).ToString(); + Assert.That(valueInDestination, Is.EqualTo(valueInSource)); } - [Test] - public void CanSaveIntegerValuesToString() - { - const int targetValue = 123; - var saveTarget = new AllStringPropertySaveTarget(); - DefaultConnectionInfo.Instance.RDPMinutesToIdleTimeout = targetValue; - DefaultConnectionInfo.Instance.SaveTo(saveTarget); - Assert.That(saveTarget.RDPMinutesToIdleTimeout, Is.EqualTo(targetValue.ToString())); - } - - [Test] - public void CanSaveStringValuesToString() - { - const string targetName = "hello"; - var saveTarget = new AllStringPropertySaveTarget(); - DefaultConnectionInfo.Instance.Username = targetName; - DefaultConnectionInfo.Instance.SaveTo(saveTarget); - Assert.That(saveTarget.Username, Is.EqualTo(targetName)); - } - - - private class AllStringPropertySaveTarget - { - public string Username { get; set; } - public string Protocol { get; set; } - public string RDPMinutesToIdleTimeout { get; set; } - } + private static IEnumerable GetConnectionInfoProperties() + { + return new ConnectionInfo().GetSerializableProperties(); + } } } \ No newline at end of file diff --git a/mRemoteNGTests/Connection/DefaultConnectionInheritanceTests.cs b/mRemoteNGTests/Connection/DefaultConnectionInheritanceTests.cs index 91d2d45b5..b86f15de7 100644 --- a/mRemoteNGTests/Connection/DefaultConnectionInheritanceTests.cs +++ b/mRemoteNGTests/Connection/DefaultConnectionInheritanceTests.cs @@ -1,34 +1,40 @@ -using mRemoteNG.Connection; +using System.Collections.Generic; +using System.Reflection; +using mRemoteNG.Connection; using NUnit.Framework; namespace mRemoteNGTests.Connection { - public class DefaultConnectionInheritanceTests + public class DefaultConnectionInheritanceTests { - [SetUp] - public void Setup() + [TestCaseSource(nameof(GetInheritanceProperties))] + public void LoadingDefaultInheritanceUpdatesAllProperties(PropertyInfo property) { - DefaultConnectionInheritance.Instance.TurnOffInheritanceCompletely(); - } - - [Test] - public void LoadingDefaultInheritanceUpdatesAllProperties() - { - var inheritanceSource = new ConnectionInfoInheritance(new object(), true); + var inheritanceSource = new ConnectionInfoInheritance(new object(), true); inheritanceSource.TurnOnInheritanceCompletely(); - DefaultConnectionInheritance.Instance.LoadFrom(inheritanceSource); - Assert.That(DefaultConnectionInheritance.Instance.EverythingInherited, Is.True); - } + DefaultConnectionInheritance.Instance.TurnOffInheritanceCompletely(); - [Test] - public void SavingDefaultInheritanceExportsAllProperties() + DefaultConnectionInheritance.Instance.LoadFrom(inheritanceSource); + + var valueInDestination = property.GetValue(DefaultConnectionInheritance.Instance); + var valueInSource = property.GetValue(inheritanceSource); + Assert.That(valueInDestination, Is.EqualTo(valueInSource)); + } + + [TestCaseSource(nameof(GetInheritanceProperties))] + public void SavingDefaultInheritanceExportsAllProperties(PropertyInfo property) { - var inheritanceDestination = new ConnectionInfoInheritance(new object(), true); - DefaultConnectionInheritance.Instance.AutomaticResize = true; - DefaultConnectionInheritance.Instance.SaveTo(inheritanceDestination); - Assert.That(inheritanceDestination.AutomaticResize, Is.True); - } + var saveTarget = new ConnectionInfoInheritance(new object(), true); + saveTarget.TurnOffInheritanceCompletely(); + DefaultConnectionInheritance.Instance.TurnOnInheritanceCompletely(); + + DefaultConnectionInheritance.Instance.SaveTo(saveTarget); + + var valueInDestination = property.GetValue(saveTarget); + var valueInSource = property.GetValue(DefaultConnectionInheritance.Instance); + Assert.That(valueInDestination, Is.EqualTo(valueInSource)); + } [Test] public void NewInheritanceInstancesCreatedWithDefaultInheritanceValues() @@ -38,12 +44,20 @@ namespace mRemoteNGTests.Connection Assert.That(inheritanceInstance.Domain, Is.True); } - [Test] - public void NewInheritanceInstancesCreatedWithAllDefaultInheritanceValues() + [TestCaseSource(nameof(GetInheritanceProperties))] + public void NewInheritanceInstancesCreatedWithAllDefaultInheritanceValues(PropertyInfo property) { DefaultConnectionInheritance.Instance.TurnOnInheritanceCompletely(); var inheritanceInstance = new ConnectionInfoInheritance(new object()); - Assert.That(inheritanceInstance.EverythingInherited, Is.True); - } - } + + var valueInDestination = property.GetValue(inheritanceInstance); + var valueInSource = property.GetValue(DefaultConnectionInheritance.Instance); + Assert.That(valueInDestination, Is.EqualTo(valueInSource)); + } + + private static IEnumerable GetInheritanceProperties() + { + return new ConnectionInfoInheritance(new object(), true).GetProperties(); + } + } } \ No newline at end of file diff --git a/mRemoteNGTests/Container/RootNodeInfoTests.cs b/mRemoteNGTests/Container/RootNodeInfoTests.cs new file mode 100644 index 000000000..fbd5894ec --- /dev/null +++ b/mRemoteNGTests/Container/RootNodeInfoTests.cs @@ -0,0 +1,18 @@ +using mRemoteNG.Connection; +using mRemoteNG.Tree.Root; +using NUnit.Framework; + +namespace mRemoteNGTests.Container +{ + public class RootNodeInfoTests + { + [Test] + public void InheritanceIsDisabledForNodesDirectlyUnderRootNode() + { + var rootNode = new RootNodeInfo(RootNodeType.Connection); + var con1 = new ConnectionInfo { Inheritance = { Password = true } }; + rootNode.AddChild(con1); + Assert.That(con1.Inheritance.Password, Is.False); + } + } +} diff --git a/mRemoteNGTests/IntegrationTests/XmlSerializationLifeCycleTests.cs b/mRemoteNGTests/IntegrationTests/XmlSerializationLifeCycleTests.cs index f1a62efde..4bcb698d9 100644 --- a/mRemoteNGTests/IntegrationTests/XmlSerializationLifeCycleTests.cs +++ b/mRemoteNGTests/IntegrationTests/XmlSerializationLifeCycleTests.cs @@ -1,5 +1,8 @@ -using System.Linq; +using System; +using System.Linq; +using System.Xml.Linq; using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Security; @@ -28,20 +31,19 @@ namespace mRemoteNGTests.IntegrationTests _originalModel.RootNodes.OfType().First().PasswordString.ConvertToSecureString(), new SaveFilter()); _serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer); + _deserializer = new XmlConnectionsDeserializer(); } [TearDown] public void Teardown() { _serializer = null; - _deserializer = null; } [Test] public void SerializeThenDeserialize() { var serializedContent = _serializer.Serialize(_originalModel); - _deserializer = new XmlConnectionsDeserializer(); var deserializedModel = _deserializer.Deserialize(serializedContent); var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name); var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name); @@ -53,7 +55,6 @@ namespace mRemoteNGTests.IntegrationTests { _serializer.UseFullEncryption = true; var serializedContent = _serializer.Serialize(_originalModel); - _deserializer = new XmlConnectionsDeserializer(); var deserializedModel = _deserializer.Deserialize(serializedContent); var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name); var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name); @@ -65,7 +66,6 @@ namespace mRemoteNGTests.IntegrationTests { var originalConnectionInfo = new ConnectionInfo {Name = "con1", Description = "£°úg¶┬ä" }; var serializedContent = _serializer.Serialize(originalConnectionInfo); - _deserializer = new XmlConnectionsDeserializer(); var deserializedModel = _deserializer.Deserialize(serializedContent); var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name); Assert.That(deserializedConnectionInfo.Description, Is.EqualTo(originalConnectionInfo.Description)); @@ -83,13 +83,26 @@ namespace mRemoteNGTests.IntegrationTests new SaveFilter()); _serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer); var serializedContent = _serializer.Serialize(_originalModel); - _deserializer = new XmlConnectionsDeserializer(); var deserializedModel = _deserializer.Deserialize(serializedContent); var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name); var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name); Assert.That(nodeNamesFromDeserializedModel, Is.EquivalentTo(nodeNamesFromOriginalModel)); } + [Test] + public void GuidCreatedIfNonExistedInXml() + { + var originalConnectionInfo = new ConnectionInfo { Name = "con1" }; + var serializedContent = _serializer.Serialize(originalConnectionInfo); + + // remove GUID from connection xml + serializedContent = serializedContent.Replace(originalConnectionInfo.ConstantID, ""); + + var deserializedModel = _deserializer.Deserialize(serializedContent); + var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name); + Assert.That(Guid.TryParse(deserializedConnectionInfo.ConstantID, out var guid)); + } + private ConnectionTreeModel SetupConnectionTreeModel() { diff --git a/mRemoteNGTests/ListViewTester.cs b/mRemoteNGTests/ListViewTester.cs index a0e558b6f..5160fa97e 100644 --- a/mRemoteNGTests/ListViewTester.cs +++ b/mRemoteNGTests/ListViewTester.cs @@ -34,8 +34,9 @@ using System.Collections; using System.Windows.Forms; +using NUnit.Extensions.Forms; -namespace NUnit.Extensions.Forms +namespace mRemoteNGTests { /// /// A ControlTester for testing List Views. diff --git a/mRemoteNGTests/Security/Authentication/PasswordAuthenticatorTests.cs b/mRemoteNGTests/Security/Authentication/PasswordAuthenticatorTests.cs index d12bcee36..2dc92a77c 100644 --- a/mRemoteNGTests/Security/Authentication/PasswordAuthenticatorTests.cs +++ b/mRemoteNGTests/Security/Authentication/PasswordAuthenticatorTests.cs @@ -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.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.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 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 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 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 AuthenticationRequestor() { authAttempts++; return _wrongPassword; - }; - _authenticator.Authenticate(_wrongPassword); + } + + var authenticator = + new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor) + { + MaxAttempts = customMaxAttempts + }; + authenticator.Authenticate(_wrongPassword); Assert.That(authAttempts == customMaxAttempts); } } diff --git a/mRemoteNGTests/TestHelpers/ConnectionInfoHelpers.cs b/mRemoteNGTests/TestHelpers/ConnectionInfoHelpers.cs new file mode 100644 index 000000000..81e8eb511 --- /dev/null +++ b/mRemoteNGTests/TestHelpers/ConnectionInfoHelpers.cs @@ -0,0 +1,132 @@ +using System; +using mRemoteNG.Connection; +using mRemoteNG.Connection.Protocol; +using mRemoteNG.Connection.Protocol.Http; +using mRemoteNG.Connection.Protocol.ICA; +using mRemoteNG.Connection.Protocol.RDP; +using mRemoteNG.Connection.Protocol.VNC; + +namespace mRemoteNGTests.TestHelpers +{ + internal static class ConnectionInfoHelpers + { + private static readonly Random _random = new Random(); + + /// + /// Returns a object with randomized + /// values in all fields. + /// + internal static ConnectionInfo GetRandomizedConnectionInfo(bool randomizeInheritance = false) + { + var connectionInfo = new ConnectionInfo + { + // string types + Name = RandomString(), + Hostname = RandomString(), + Description = RandomString(), + Domain = RandomString(), + ExtApp = RandomString(), + Icon = RandomString(), + LoadBalanceInfo = RandomString(), + MacAddress = RandomString(), + Panel = RandomString(), + Password = RandomString(), + PostExtApp = RandomString(), + PreExtApp = RandomString(), + PuttySession = RandomString(), + RDGatewayHostname = RandomString(), + RDGatewayUsername = RandomString(), + RDGatewayDomain = RandomString(), + RDGatewayPassword = RandomString(), + UserField = RandomString(), + Username = RandomString(), + VNCProxyIP = RandomString(), + VNCProxyPassword = RandomString(), + VNCProxyUsername = RandomString(), + + // bool types + AutomaticResize = RandomBool(), + CacheBitmaps = RandomBool(), + DisplayThemes = RandomBool(), + DisplayWallpaper = RandomBool(), + EnableDesktopComposition = RandomBool(), + EnableFontSmoothing = RandomBool(), + IsContainer = RandomBool(), + IsDefault = RandomBool(), + IsQuickConnect = RandomBool(), + PleaseConnect = RandomBool(), + RDPAlertIdleTimeout = RandomBool(), + RedirectDiskDrives = RandomBool(), + RedirectKeys = RandomBool(), + RedirectPorts = RandomBool(), + RedirectPrinters = RandomBool(), + RedirectSmartCards = RandomBool(), + UseConsoleSession = RandomBool(), + UseCredSsp = RandomBool(), + VNCViewOnly = RandomBool(), + + // ints + Port = RandomInt(), + RDPMinutesToIdleTimeout = RandomInt(), + VNCProxyPort = RandomInt(), + + // enums + Colors = RandomEnum(), + ICAEncryptionStrength = RandomEnum (), + Protocol = RandomEnum(), + RDGatewayUsageMethod = RandomEnum(), + RDGatewayUseConnectionCredentials = RandomEnum(), + RDPAuthenticationLevel = RandomEnum(), + RedirectSound = RandomEnum(), + RenderingEngine = RandomEnum(), + Resolution = RandomEnum(), + SoundQuality = RandomEnum(), + VNCAuthMode = RandomEnum(), + VNCColors = RandomEnum(), + VNCCompression = RandomEnum(), + VNCEncoding = RandomEnum(), + VNCProxyType = RandomEnum(), + VNCSmartSizeMode = RandomEnum(), + }; + + if (randomizeInheritance) + connectionInfo.Inheritance = GetRandomizedInheritance(connectionInfo); + + return connectionInfo; + } + + internal static ConnectionInfoInheritance GetRandomizedInheritance(ConnectionInfo parent) + { + var inheritance = new ConnectionInfoInheritance(parent, true); + foreach (var property in inheritance.GetProperties()) + { + property.SetValue(inheritance, RandomBool()); + } + return inheritance; + } + + internal static string RandomString() + { + return Guid.NewGuid().ToString("N"); + } + + internal static bool RandomBool() + { + return _random.Next() % 2 == 0; + } + + internal static int RandomInt() + { + return _random.Next(); + } + + internal static T RandomEnum() where T : struct, IConvertible + { + if (!typeof(T).IsEnum) + throw new ArgumentException("T must be an enum"); + + var values = Enum.GetValues(typeof(T)); + return (T)values.GetValue(_random.Next(values.Length)); + } + } +} diff --git a/mRemoteNGTests/TestHelpers/ConnectionTreeModelBuilder.cs b/mRemoteNGTests/TestHelpers/ConnectionTreeModelBuilder.cs index efe99b634..87e7ef972 100644 --- a/mRemoteNGTests/TestHelpers/ConnectionTreeModelBuilder.cs +++ b/mRemoteNGTests/TestHelpers/ConnectionTreeModelBuilder.cs @@ -7,17 +7,52 @@ namespace mRemoteNGTests.TestHelpers { public class ConnectionTreeModelBuilder { + /// + /// Builds a tree which looks like: + /// Root + /// |- folder1 + /// | |- con1 + /// |- con2 + /// |- folder2 + /// |- folder3 + /// |- con3 + /// + /// public ConnectionTreeModel Build() { var model = new ConnectionTreeModel(); var root = new RootNodeInfo(RootNodeType.Connection); var folder1 = new ContainerInfo { Name = "folder1", Username = "user1", Domain = "domain1", Password = "password1" }; + var folder2 = new ContainerInfo { Name = "folder2", Username = "user2", Domain = "domain2", Password = "password2" }; + var folder3 = new ContainerInfo + { + Name = "folder3", + Inheritance = + { + Username = true, + Domain = true, + Password = true + } + }; var con1 = new ConnectionInfo { Name = "Con1", Username = "user1", Domain = "domain1", Password = "password1" }; var con2 = new ConnectionInfo { Name = "Con2", Username = "user2", Domain = "domain2", Password = "password2" }; + var con3 = new ContainerInfo + { + Name = "con3", + Inheritance = + { + Username = true, + Domain = true, + Password = true + } + }; root.AddChild(folder1); root.AddChild(con2); folder1.AddChild(con1); + root.AddChild(folder2); + folder2.AddChild(folder3); + folder3.AddChild(con3); model.AddRootNode(root); return model; } diff --git a/mRemoteNGTests/TestHelpers/SerializableConnectionInfoAllPropertiesOfType.cs b/mRemoteNGTests/TestHelpers/SerializableConnectionInfoAllPropertiesOfType.cs new file mode 100644 index 000000000..de17b756a --- /dev/null +++ b/mRemoteNGTests/TestHelpers/SerializableConnectionInfoAllPropertiesOfType.cs @@ -0,0 +1,64 @@ +namespace mRemoteNGTests.TestHelpers +{ + /// + /// A ConnectionInfo that has only the serializable properties as string types. + /// Only used for testing. + /// + internal class SerializableConnectionInfoAllPropertiesOfType + { + public TType Description { get; set; } + public TType Icon { get; set; } + public TType Panel { get; set; } + public TType Username { get; set; } + public TType Password { get; set; } + public TType Domain { get; set; } + public TType Protocol { get; set; } + public TType ExtApp { get; set; } + public TType PuttySession { get; set; } + public TType ICAEncryptionStrength { get; set; } + public TType UseConsoleSession { get; set; } + public TType RDPAuthenticationLevel { get; set; } + public TType RDPMinutesToIdleTimeout { get; set; } + public TType RDPAlertIdleTimeout { get; set; } + public TType LoadBalanceInfo { get; set; } + public TType RenderingEngine { get; set; } + public TType UseCredSsp { get; set; } + public TType RDGatewayUsageMethod { get; set; } + public TType RDGatewayHostname { get; set; } + public TType RDGatewayUseConnectionCredentials { get; set; } + public TType RDGatewayUsername { get; set; } + public TType RDGatewayPassword { get; set; } + public TType RDGatewayDomain { get; set; } + public TType Resolution { get; set; } + public TType AutomaticResize { get; set; } + public TType Colors { get; set; } + public TType CacheBitmaps { get; set; } + public TType DisplayWallpaper { get; set; } + public TType DisplayThemes { get; set; } + public TType EnableFontSmoothing { get; set; } + public TType EnableDesktopComposition { get; set; } + public TType RedirectKeys { get; set; } + public TType RedirectDiskDrives { get; set; } + public TType RedirectPrinters { get; set; } + public TType RedirectClipboard { get; set; } + public TType RedirectPorts { get; set; } + public TType RedirectSmartCards { get; set; } + public TType RedirectSound { get; set; } + public TType SoundQuality { get; set; } + public TType PreExtApp { get; set; } + public TType PostExtApp { get; set; } + public TType MacAddress { get; set; } + public TType UserField { get; set; } + public TType VNCCompression { get; set; } + public TType VNCEncoding { get; set; } + public TType VNCAuthMode { get; set; } + public TType VNCProxyType { get; set; } + public TType VNCProxyIP { get; set; } + public TType VNCProxyPort { get; set; } + public TType VNCProxyUsername { get; set; } + public TType VNCProxyPassword { get; set; } + public TType VNCColors { get; set; } + public TType VNCSmartSizeMode { get; set; } + public TType VNCViewOnly { get; set; } + } +} diff --git a/mRemoteNGTests/Tools/MaybeTests.cs b/mRemoteNGTests/Tools/OptionalTests.cs similarity index 81% rename from mRemoteNGTests/Tools/MaybeTests.cs rename to mRemoteNGTests/Tools/OptionalTests.cs index 1cebaa51d..222d08a7f 100644 --- a/mRemoteNGTests/Tools/MaybeTests.cs +++ b/mRemoteNGTests/Tools/OptionalTests.cs @@ -3,12 +3,12 @@ using NUnit.Framework; namespace mRemoteNGTests.Tools { - public class MaybeTests + public class OptionalTests { [Test] public void MaybeReturnsEmptyListWhenGivenNullValue() { - var sut = new Maybe(null); + var sut = new Optional(null); Assert.That(sut, Is.Empty); } @@ -16,7 +16,7 @@ namespace mRemoteNGTests.Tools public void MaybeReturnsValueIfNotNull() { var expected = new object(); - var sut = new Maybe(expected); + var sut = new Optional(expected); Assert.That(sut, Has.Member(expected)); } diff --git a/mRemoteNGTests/Tools/Registry/WindowsRegistryTests.cs b/mRemoteNGTests/Tools/Registry/WindowsRegistryTests.cs new file mode 100644 index 000000000..292b1b8aa --- /dev/null +++ b/mRemoteNGTests/Tools/Registry/WindowsRegistryTests.cs @@ -0,0 +1,50 @@ +using System; +using System.Linq; +using mRemoteNG.Tools.WindowsRegistry; +using NUnit.Framework; + +namespace mRemoteNGTests.Tools.Registry +{ + public class WindowsRegistryTests + { + private WindowsRegistry _registry; + + [SetUp] + public void Setup() + { + _registry = new WindowsRegistry(); + } + + [Test] + public void CanGetSubkeyNames() + { + var subKeyNames = _registry.GetSubKeyNames(RegistryHive.CurrentUser, "Software"); + Assert.That(subKeyNames, Does.Contain("Microsoft")); + } + + [Test] + public void GetSubkeyNamesThrowsIfGivenNullKeyPath() + { + Assert.Throws(() => _registry.GetSubKeyNames(RegistryHive.CurrentUser, null)); + } + + [Test] + public void CanGetKeyValue() + { + var keyValue = _registry.GetKeyValue(RegistryHive.ClassesRoot, @".dll\PersistentHandler", ""); + Assert.That(keyValue.FirstOrDefault(), Is.EqualTo("{098f2470-bae0-11cd-b579-08002b30bfeb}")); + } + + [Test] + public void GetKeyValueThrowsIfGivenNullKeyPath() + { + Assert.Throws(() => _registry.GetKeyValue(RegistryHive.CurrentUser, null, "")); + } + + [Test] + public void GetKeyValueThrowsIfGivenNullPropertyName() + { + Assert.Throws(() => _registry.GetKeyValue(RegistryHive.CurrentUser, "", null)); + } + } +} diff --git a/mRemoteNGTests/Tree/NodeSearcherTests.cs b/mRemoteNGTests/Tree/NodeSearcherTests.cs index 692aa2b76..a43287059 100644 --- a/mRemoteNGTests/Tree/NodeSearcherTests.cs +++ b/mRemoteNGTests/Tree/NodeSearcherTests.cs @@ -8,7 +8,7 @@ using NUnit.Framework; namespace mRemoteNGTests.Tree { - public class NodeSearcherTests + public class NodeSearcherTests { private NodeSearcher _nodeSearcher; private ContainerInfo _folder1; @@ -104,6 +104,14 @@ namespace mRemoteNGTests.Tree _con4 = new ConnectionInfo { Name = "con4", Description="description6", Hostname="hostname6" }; _con5 = new ConnectionInfo { Name = "con5", Description="description7", Hostname="hostname7" }; + _folder1.Inheritance.TurnOffInheritanceCompletely(); + _con1.Inheritance.TurnOffInheritanceCompletely(); + _con2.Inheritance.TurnOffInheritanceCompletely(); + _folder2.Inheritance.TurnOffInheritanceCompletely(); + _con3.Inheritance.TurnOffInheritanceCompletely(); + _con4.Inheritance.TurnOffInheritanceCompletely(); + _con5.Inheritance.TurnOffInheritanceCompletely(); + connectionTreeModel.AddRootNode(root); root.AddChildRange(new [] { _folder1, _folder2, _con5 }); _folder1.AddChildRange(new [] { _con1, _con2 }); diff --git a/mRemoteNGTests/Tree/RootNodeInfoTests.cs b/mRemoteNGTests/Tree/RootNodeInfoTests.cs index 355a73338..4baf33ee2 100644 --- a/mRemoteNGTests/Tree/RootNodeInfoTests.cs +++ b/mRemoteNGTests/Tree/RootNodeInfoTests.cs @@ -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)); + } } } \ No newline at end of file diff --git a/mRemoteNGTests/UI/Controls/ConnectionTreeTests.cs b/mRemoteNGTests/UI/Controls/ConnectionTreeTests.cs new file mode 100644 index 000000000..142caed7c --- /dev/null +++ b/mRemoteNGTests/UI/Controls/ConnectionTreeTests.cs @@ -0,0 +1,202 @@ +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)); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void RenamingNodeWithNothingSelectedDoesNothing() + { + var connectionTreeModel = new ConnectionTreeModel(); + var root = new RootNodeInfo(RootNodeType.Connection); + connectionTreeModel.AddRootNode(root); + + _connectionTree.ConnectionTreeModel = connectionTreeModel; + _connectionTree.SelectedObject = null; + + Assert.DoesNotThrow(() => _connectionTree.RenameSelectedNode()); + } + } +} diff --git a/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowGeneralTests.cs b/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowGeneralTests.cs new file mode 100644 index 000000000..2519479b1 --- /dev/null +++ b/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowGeneralTests.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using mRemoteNG.Connection; +using mRemoteNG.Connection.Protocol; +using mRemoteNG.Connection.Protocol.RDP; +using mRemoteNG.Connection.Protocol.VNC; +using mRemoteNG.Container; +using mRemoteNG.Tree.Root; +using mRemoteNG.UI.Window; +using NUnit.Framework; + +namespace mRemoteNGTests.UI.Window.ConfigWindowTests +{ + public class ConfigWindowGeneralTests + { + private ConfigWindow _configWindow; + + [SetUp] + public void Setup() + { + _configWindow = new ConfigWindow + { + PropertiesVisible = true + }; + } + + [TestCaseSource(nameof(ConnectionInfoGeneralTestCases))] + public void PropertyGridShowCorrectPropertiesForConnectionInfo(ConnectionInfo connectionInfo, IEnumerable expectedVisibleProperties) + { + _configWindow.SelectedTreeNode = connectionInfo; + Assert.That(_configWindow.VisibleObjectProperties, Is.EquivalentTo(expectedVisibleProperties)); + } + + [Test] + public void PropertyGridShowCorrectPropertiesForRootConnectionInfo() + { + var expectedVisibleProperties = new[] + { + nameof(RootNodeInfo.Name), + nameof(RootNodeInfo.Password), + }; + + _configWindow.SelectedTreeNode = new RootNodeInfo(RootNodeType.Connection); + Assert.That(_configWindow.VisibleObjectProperties, Is.EquivalentTo(expectedVisibleProperties)); + } + + [Test] + public void PropertyGridShowCorrectPropertiesForRootPuttyInfo() + { + var expectedVisibleProperties = new[] + { + nameof(RootNodeInfo.Name), + }; + + _configWindow.SelectedTreeNode = new RootPuttySessionsNodeInfo(); + Assert.That(_configWindow.VisibleObjectProperties, Is.EquivalentTo(expectedVisibleProperties)); + } + + private static IEnumerable ConnectionInfoGeneralTestCases() + { + var protocolTypes = typeof(ProtocolType).GetEnumValues().OfType(); + var testCases = new List(); + + foreach (var protocol in protocolTypes) + { + var expectedPropertyListConnection = BuildExpectedConnectionInfoPropertyList(protocol, false); + var connectionInfo = ConstructConnectionInfo(protocol, false); + var testCaseConnection = new TestCaseData(connectionInfo, expectedPropertyListConnection) + .SetName(protocol + ", ConnectionInfo"); + testCases.Add(testCaseConnection); + + var expectedPropertyListContainer = BuildExpectedConnectionInfoPropertyList(protocol, true); + var containerInfo = ConstructConnectionInfo(protocol, true); + var testCaseContainer = new TestCaseData(containerInfo, expectedPropertyListContainer) + .SetName(protocol + ", ContainerInfo"); + testCases.Add(testCaseContainer); + } + + return testCases; + } + + internal static ConnectionInfo ConstructConnectionInfo(ProtocolType protocol, bool isContainer) + { + // build connection info. set certain connection properties so + // that toggled properties are hidden in the property grid. We + // will test those separately in the special protocol tests. + var node = isContainer + ? new ContainerInfo() + : new ConnectionInfo(); + + node.Protocol = protocol; + node.Resolution = RdpProtocol.RDPResolutions.Res800x600; + node.RDGatewayUsageMethod = RdpProtocol.RDGatewayUsageMethod.Never; + node.RDGatewayUseConnectionCredentials = RdpProtocol.RDGatewayUseConnectionCredentials.Yes; + node.RedirectSound = RdpProtocol.RDPSounds.DoNotPlay; + node.VNCAuthMode = ProtocolVNC.AuthMode.AuthVNC; + node.VNCProxyType = ProtocolVNC.ProxyType.ProxyNone; + node.Inheritance.TurnOffInheritanceCompletely(); + + return node; + } + + internal static List BuildExpectedConnectionInfoPropertyList(ProtocolType protocol, bool isContainer) + { + var expectedProperties = new List + { + nameof(ConnectionInfo.Name), + nameof(ConnectionInfo.Description), + nameof(ConnectionInfo.Icon), + nameof(ConnectionInfo.Panel), + nameof(ConnectionInfo.Protocol), + nameof(ConnectionInfo.PreExtApp), + nameof(ConnectionInfo.PostExtApp), + nameof(ConnectionInfo.MacAddress), + nameof(ConnectionInfo.UserField), + }; + + if (!isContainer) + { + expectedProperties.AddRange(new [] + { + nameof(ConnectionInfo.Hostname), + }); + } + + switch (protocol) + { + case ProtocolType.RDP: + expectedProperties.AddRange(new [] + { + nameof(ConnectionInfo.Username), + nameof(ConnectionInfo.Password), + nameof(ConnectionInfo.Domain), + nameof(ConnectionInfo.Port), + nameof(ConnectionInfo.UseConsoleSession), + nameof(ConnectionInfo.RDPAuthenticationLevel), + nameof(ConnectionInfo.RDPMinutesToIdleTimeout), + nameof(ConnectionInfo.LoadBalanceInfo), + nameof(ConnectionInfo.UseCredSsp), + nameof(ConnectionInfo.RDGatewayUsageMethod), + nameof(ConnectionInfo.Resolution), + nameof(ConnectionInfo.Colors), + nameof(ConnectionInfo.CacheBitmaps), + nameof(ConnectionInfo.DisplayWallpaper), + nameof(ConnectionInfo.DisplayThemes), + nameof(ConnectionInfo.EnableFontSmoothing), + nameof(ConnectionInfo.EnableDesktopComposition), + nameof(ConnectionInfo.RedirectKeys), + nameof(ConnectionInfo.RedirectDiskDrives), + nameof(ConnectionInfo.RedirectPrinters), + nameof(ConnectionInfo.RedirectClipboard), + nameof(ConnectionInfo.RedirectPorts), + nameof(ConnectionInfo.RedirectSmartCards), + nameof(ConnectionInfo.RedirectSound), + }); + break; + case ProtocolType.VNC: + expectedProperties.AddRange(new [] + { + nameof(ConnectionInfo.Password), + nameof(ConnectionInfo.Port), + nameof(ConnectionInfo.VNCSmartSizeMode), + nameof(ConnectionInfo.VNCViewOnly), + }); + break; + case ProtocolType.SSH1: + case ProtocolType.SSH2: + expectedProperties.AddRange(new [] + { + nameof(ConnectionInfo.Username), + nameof(ConnectionInfo.Password), + nameof(ConnectionInfo.Port), + nameof(ConnectionInfo.PuttySession) + }); + break; + case ProtocolType.Telnet: + case ProtocolType.Rlogin: + case ProtocolType.RAW: + expectedProperties.AddRange(new[] + { + nameof(ConnectionInfo.Port), + nameof(ConnectionInfo.PuttySession), + }); + break; + case ProtocolType.HTTP: + case ProtocolType.HTTPS: + expectedProperties.AddRange(new [] + { + nameof(ConnectionInfo.Username), + nameof(ConnectionInfo.Password), + nameof(ConnectionInfo.Port), + nameof(ConnectionInfo.RenderingEngine), + }); + break; + case ProtocolType.ICA: + expectedProperties.AddRange(new [] + { + nameof(ConnectionInfo.Username), + nameof(ConnectionInfo.Password), + nameof(ConnectionInfo.Domain), + nameof(ConnectionInfo.ICAEncryptionStrength), + nameof(ConnectionInfo.Resolution), + nameof(ConnectionInfo.Colors), + nameof(ConnectionInfo.CacheBitmaps), + }); + break; + case ProtocolType.IntApp: + expectedProperties.AddRange(new[] + { + nameof(ConnectionInfo.Username), + nameof(ConnectionInfo.Password), + nameof(ConnectionInfo.Domain), + nameof(ConnectionInfo.Port), + nameof(ConnectionInfo.ExtApp), + }); + break; + default: + throw new ArgumentOutOfRangeException(nameof(protocol), protocol, null); + } + + return expectedProperties; + } + } +} diff --git a/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowRdpSpecialTests.cs b/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowRdpSpecialTests.cs new file mode 100644 index 000000000..0804652ec --- /dev/null +++ b/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowRdpSpecialTests.cs @@ -0,0 +1,73 @@ +using mRemoteNG.Connection; +using mRemoteNG.Connection.Protocol; +using mRemoteNG.Connection.Protocol.RDP; +using NUnit.Framework; + +namespace mRemoteNGTests.UI.Window.ConfigWindowTests +{ + public class ConfigWindowRdpSpecialTests : ConfigWindowSpecialTestsBase + { + protected override ProtocolType Protocol => ProtocolType.RDP; + + [Test] + public void PropertyShownWhenActive_RdpMinutesToIdleTimeout() + { + ConnectionInfo.RDPMinutesToIdleTimeout = 1; + ExpectedPropertyList.Add(nameof(mRemoteNG.Connection.ConnectionInfo.RDPAlertIdleTimeout)); + + RunVerification(); + } + + [TestCase(RdpProtocol.RDGatewayUsageMethod.Always)] + [TestCase(RdpProtocol.RDGatewayUsageMethod.Detect)] + public void RdGatewayPropertiesShown_WhenRdGatewayUsageMethodIsNotNever(RdpProtocol.RDGatewayUsageMethod gatewayUsageMethod) + { + ConnectionInfo.RDGatewayUsageMethod = gatewayUsageMethod; + ConnectionInfo.RDGatewayUseConnectionCredentials = RdpProtocol.RDGatewayUseConnectionCredentials.Yes; + ExpectedPropertyList.AddRange(new [] + { + nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayHostname), + nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayUseConnectionCredentials) + }); + + RunVerification(); + } + + [TestCase(RdpProtocol.RDGatewayUseConnectionCredentials.No)] + [TestCase(RdpProtocol.RDGatewayUseConnectionCredentials.SmartCard)] + public void RdGatewayPropertiesShown_WhenRDGatewayUseConnectionCredentialsIsNotYes(RdpProtocol.RDGatewayUseConnectionCredentials useConnectionCredentials) + { + ConnectionInfo.RDGatewayUsageMethod = RdpProtocol.RDGatewayUsageMethod.Always; + ConnectionInfo.RDGatewayUseConnectionCredentials = useConnectionCredentials; + ExpectedPropertyList.AddRange(new [] + { + nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayHostname), + nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayUsername), + nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayPassword), + nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayDomain), + nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayUseConnectionCredentials) + }); + + RunVerification(); + } + + [Test] + public void SoundQualityPropertyShown_WhenRdpSoundsSetToBringToThisComputer() + { + ConnectionInfo.RedirectSound = RdpProtocol.RDPSounds.BringToThisComputer; + ExpectedPropertyList.Add(nameof(mRemoteNG.Connection.ConnectionInfo.SoundQuality)); + + RunVerification(); + } + + [TestCase(RdpProtocol.RDPResolutions.FitToWindow)] + [TestCase(RdpProtocol.RDPResolutions.Fullscreen)] + public void AutomaticResizePropertyShown_WhenResolutionIsDynamic(RdpProtocol.RDPResolutions resolution) + { + ConnectionInfo.Resolution = resolution; + ExpectedPropertyList.Add(nameof(mRemoteNG.Connection.ConnectionInfo.AutomaticResize)); + + RunVerification(); + } + } +} diff --git a/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowSpecialTestsBase.cs b/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowSpecialTestsBase.cs new file mode 100644 index 000000000..e5f9169c4 --- /dev/null +++ b/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowSpecialTestsBase.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using mRemoteNG.Connection; +using mRemoteNG.Connection.Protocol; +using mRemoteNG.UI.Window; +using NUnit.Framework; + +namespace mRemoteNGTests.UI.Window.ConfigWindowTests +{ + public abstract class ConfigWindowSpecialTestsBase + { + protected abstract ProtocolType Protocol { get; } + protected bool TestAgainstContainerInfo { get; set; } = false; + protected ConfigWindow ConfigWindow; + protected ConnectionInfo ConnectionInfo; + protected List ExpectedPropertyList; + + [SetUp] + public virtual void Setup() + { + ConnectionInfo = ConfigWindowGeneralTests.ConstructConnectionInfo(Protocol, TestAgainstContainerInfo); + ExpectedPropertyList = ConfigWindowGeneralTests.BuildExpectedConnectionInfoPropertyList(Protocol, TestAgainstContainerInfo); + + ConfigWindow = new ConfigWindow + { + PropertiesVisible = true, + }; + } + + public void RunVerification() + { + ConfigWindow.SelectedTreeNode = ConnectionInfo; + Assert.That( + ConfigWindow.VisibleObjectProperties, + Is.EquivalentTo(ExpectedPropertyList)); + } + } +} diff --git a/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowVncSpecialTests.cs b/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowVncSpecialTests.cs new file mode 100644 index 000000000..50cc49b03 --- /dev/null +++ b/mRemoteNGTests/UI/Window/ConfigWindowTests/ConfigWindowVncSpecialTests.cs @@ -0,0 +1,37 @@ +using mRemoteNG.Connection.Protocol; +using mRemoteNG.Connection.Protocol.VNC; +using NUnit.Framework; + +namespace mRemoteNGTests.UI.Window.ConfigWindowTests +{ + public class ConfigWindowVncSpecialTests : ConfigWindowSpecialTestsBase + { + protected override ProtocolType Protocol => ProtocolType.VNC; + + [Test] + public void UserDomainPropertiesShown_WhenAuthModeIsWindows() + { + ConnectionInfo.VNCAuthMode = ProtocolVNC.AuthMode.AuthWin; + ExpectedPropertyList.AddRange(new [] + { + nameof(ConnectionInfo.Username), + nameof(ConnectionInfo.Domain), + }); + } + + [TestCase(ProtocolVNC.ProxyType.ProxyHTTP)] + [TestCase(ProtocolVNC.ProxyType.ProxySocks5)] + [TestCase(ProtocolVNC.ProxyType.ProxyUltra)] + public void ProxyPropertiesShown_WhenProxyModeIsNotNone(ProtocolVNC.ProxyType proxyType) + { + ConnectionInfo.VNCProxyType = proxyType; + ExpectedPropertyList.AddRange(new[] + { + nameof(ConnectionInfo.VNCProxyIP), + nameof(ConnectionInfo.VNCProxyPort), + nameof(ConnectionInfo.VNCProxyUsername), + nameof(ConnectionInfo.VNCProxyPassword), + }); + } + } +} diff --git a/mRemoteNGTests/mRemoteNGTests.csproj b/mRemoteNGTests/mRemoteNGTests.csproj index 6937cd196..bf8250062 100644 --- a/mRemoteNGTests/mRemoteNGTests.csproj +++ b/mRemoteNGTests/mRemoteNGTests.csproj @@ -68,8 +68,8 @@ ..\packages\NSubstitute.3.1.0\lib\net46\NSubstitute.dll - - ..\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll + + ..\packages\NUnit.3.9.0\lib\net45\nunit.framework.dll nUnitForms\bin\NUnitForms.dll @@ -114,6 +114,7 @@ + @@ -121,20 +122,21 @@ - + + - + - - - + + + - + @@ -144,6 +146,7 @@ + @@ -167,12 +170,15 @@ + + - + + @@ -202,6 +208,7 @@ + Form @@ -226,6 +233,10 @@ + + + + diff --git a/mRemoteNGTests/packages.config b/mRemoteNGTests/packages.config index c6074ee32..2e6c2f63e 100644 --- a/mRemoteNGTests/packages.config +++ b/mRemoteNGTests/packages.config @@ -5,14 +5,14 @@ - + - - + + diff --git a/mRemoteV1.sln b/mRemoteV1.sln index ca43211c8..5466c8d33 100644 --- a/mRemoteV1.sln +++ b/mRemoteV1.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27004.2008 +VisualStudioVersion = 15.0.27130.2010 MinimumVisualStudioVersion = 14.0.25420.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mRemoteV1", "mRemoteV1\mRemoteV1.csproj", "{4934A491-40BC-4E5B-9166-EA1169A220F6}" EndProject @@ -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 @@ -101,7 +105,6 @@ Global {16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|Any CPU.Build.0 = Debug|Any CPU {16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x86.ActiveCfg = Debug|Any CPU - {16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x86.Build.0 = Debug|Any CPU {16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|Any CPU.ActiveCfg = Release|Any CPU {16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|Any CPU.Build.0 = Release|Any CPU {16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|x86.ActiveCfg = Release|Any CPU diff --git a/mRemoteV1/App/Export.cs b/mRemoteV1/App/Export.cs index 5a4f210e9..a6feb2295 100644 --- a/mRemoteV1/App/Export.cs +++ b/mRemoteV1/App/Export.cs @@ -4,6 +4,8 @@ using System.Windows.Forms; using mRemoteNG.Config.Connections; using mRemoteNG.Config.DataProviders; using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Csv; +using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Security; @@ -77,7 +79,7 @@ namespace mRemoteNG.App case SaveFormat.mRXML: var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build(); var rootNode = exportTarget.GetRootParent() as RootNodeInfo; - var connectionNodeSerializer = new XmlConnectionNodeSerializer26( + var connectionNodeSerializer = new XmlConnectionNodeSerializer27( cryptographyProvider, rootNode?.PasswordString.ConvertToSecureString() ?? new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString(), saveFilter); diff --git a/mRemoteV1/App/Import.cs b/mRemoteV1/App/Import.cs index 1a7bdbf81..119b98264 100644 --- a/mRemoteV1/App/Import.cs +++ b/mRemoteV1/App/Import.cs @@ -7,22 +7,10 @@ using mRemoteNG.Connection.Protocol; using mRemoteNG.Container; using mRemoteNG.Tools; - namespace mRemoteNG.App { public static class Import { - private enum FileType - { - Unknown = 0, - // ReSharper disable once InconsistentNaming - mRemoteXml, - RemoteDesktopConnection, - RemoteDesktopConnectionManager, - PuttyConnectionManager - } - - #region Public Methods public static void ImportFromFile(ContainerInfo importDestinationContainer) { try @@ -34,8 +22,9 @@ namespace mRemoteNG.App openFileDialog.Multiselect = true; var fileTypes = new List(); - fileTypes.AddRange(new[] {Language.strFilterAllImportable, "*.xml;*.rdp;*.rdg;*.dat"}); + fileTypes.AddRange(new[] {Language.strFilterAllImportable, "*.xml;*.rdp;*.rdg;*.dat;*.csv"}); fileTypes.AddRange(new[] {Language.strFiltermRemoteXML, "*.xml"}); + fileTypes.AddRange(new[] {Language.strFiltermRemoteCSV, "*.csv"}); fileTypes.AddRange(new[] {Language.strFilterRDP, "*.rdp"}); fileTypes.AddRange(new[] {Language.strFilterRdgFiles, "*.rdg"}); fileTypes.AddRange(new[] {Language.strFilterPuttyConnectionManager, "*.dat"}); @@ -50,32 +39,14 @@ namespace mRemoteNG.App { try { - IConnectionImporter importer; - // ReSharper disable once SwitchStatementMissingSomeCases - switch (DetermineFileType(fileName)) - { - case FileType.mRemoteXml: - importer = new mRemoteNGImporter(); - break; - case FileType.RemoteDesktopConnection: - importer = new RemoteDesktopConnectionImporter(); - break; - case FileType.RemoteDesktopConnectionManager: - importer = new RemoteDesktopConnectionManagerImporter(); - break; - case FileType.PuttyConnectionManager: - importer = new PuttyConnectionManagerImporter(); - break; - default: - throw new FileFormatException("Unrecognized file format."); - } + var importer = BuildConnectionImporterFromFileExtension(fileName); importer.Import(fileName, importDestinationContainer); } catch (Exception ex) { MessageBox.Show(string.Format(Language.strImportFileFailedContent, fileName), Language.strImportFileFailedMainInstruction, MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); - Runtime.MessageCollector.AddExceptionMessage("App.Import.ImportFromFile() failed:1", ex); + Runtime.MessageCollector.AddExceptionMessage("Unable to import file.", ex); } } @@ -84,15 +55,15 @@ namespace mRemoteNG.App } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("App.Import.ImportFromFile() failed:2", ex); + Runtime.MessageCollector.AddExceptionMessage("Unable to import file.", ex); } } - public static void ImportFromActiveDirectory(string ldapPath, ContainerInfo importDestinationContainer, bool importSubOU) + public static void ImportFromActiveDirectory(string ldapPath, ContainerInfo importDestinationContainer, bool importSubOu) { try { - ActiveDirectoryImporter.Import(ldapPath, importDestinationContainer, importSubOU); + ActiveDirectoryImporter.Import(ldapPath, importDestinationContainer, importSubOu); Runtime.ConnectionsService.SaveConnectionsAsync(); } catch (Exception ex) @@ -114,25 +85,25 @@ namespace mRemoteNG.App Runtime.MessageCollector.AddExceptionMessage("App.Import.ImportFromPortScan() failed.", ex); } } - #endregion - private static FileType DetermineFileType(string fileName) + private static IConnectionImporter BuildConnectionImporterFromFileExtension(string fileName) { // TODO: Use the file contents to determine the file type instead of trusting the extension - var extension = Path.GetExtension(fileName); - if (extension == null) return FileType.Unknown; + var extension = Path.GetExtension(fileName) ?? ""; switch (extension.ToLowerInvariant()) { case ".xml": - return FileType.mRemoteXml; + return new MRemoteNGXmlImporter(); + case ".csv": + return new MRemoteNGCsvImporter(); case ".rdp": - return FileType.RemoteDesktopConnection; + return new RemoteDesktopConnectionImporter(); case ".rdg": - return FileType.RemoteDesktopConnectionManager; + return new RemoteDesktopConnectionManagerImporter(); case ".dat": - return FileType.PuttyConnectionManager; + return new PuttyConnectionManagerImporter(); default: - return FileType.Unknown; + throw new FileFormatException("Unrecognized file format."); } } } diff --git a/mRemoteV1/App/Info/SettingsFileInfo.cs b/mRemoteV1/App/Info/SettingsFileInfo.cs index f4ce9d720..812259a7a 100644 --- a/mRemoteV1/App/Info/SettingsFileInfo.cs +++ b/mRemoteV1/App/Info/SettingsFileInfo.cs @@ -13,5 +13,7 @@ namespace mRemoteNG.App.Info public static string LayoutFileName { get; } = "pnlLayout.xml"; public static string ExtAppsFilesName { get; } = "extApps.xml"; public static string ThemesFileName { get; } = "Themes.xml"; + public static string ThemeFolder { get; } = SettingsPath != null ? Path.Combine(SettingsPath, "Themes") : String.Empty; + public static string InstalledThemeFolder { get; } = ExePath != null ? Path.Combine(ExePath, "Themes") : String.Empty; } } \ No newline at end of file diff --git a/mRemoteV1/App/Runtime.cs b/mRemoteV1/App/Runtime.cs index aae2811a9..b1921a8c0 100644 --- a/mRemoteV1/App/Runtime.cs +++ b/mRemoteV1/App/Runtime.cs @@ -4,8 +4,6 @@ using System.Security; using System.Threading; using System.Windows.Forms; using mRemoteNG.App.Info; -using mRemoteNG.Config.Connections.Multiuser; -using mRemoteNG.Config.DataProviders; using mRemoteNG.Config.Putty; using mRemoteNG.Connection; using mRemoteNG.Credential; @@ -20,7 +18,7 @@ using mRemoteNG.UI.TaskDialog; namespace mRemoteNG.App { - public static class Runtime + public static class Runtime { public static bool IsPortableEdition { @@ -79,12 +77,6 @@ namespace mRemoteNG.App { connectionFileName = ConnectionsService.GetStartupConnectionFileName(); } - - var backupFileCreator = new FileBackupCreator(); - backupFileCreator.CreateBackupFile(connectionFileName); - - var backupPruner = new FileBackupPruner(); - backupPruner.PruneBackupFiles(connectionFileName); } ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName); @@ -93,18 +85,6 @@ namespace mRemoteNG.App { ConnectionsService.LastSqlUpdate = DateTime.Now; } - else - { - if (connectionFileName == ConnectionsService.GetDefaultStartupConnectionFileName()) - { - Settings.Default.LoadConsFromCustomLocation = false; - } - else - { - Settings.Default.LoadConsFromCustomLocation = true; - Settings.Default.CustomConsPath = connectionFileName; - } - } // re-enable sql update checking after updates are loaded ConnectionsService.RemoteConnectionsSyncronizer?.Enable(); @@ -147,7 +127,14 @@ namespace mRemoteNG.App { try { - CTaskDialog.ShowTaskDialogBox(GeneralAppInfo.ProductName, Language.ConfigurationFileNotFound, "", "", "", "", "", string.Join(" | ", commandButtons), ETaskDialogButtons.None, ESysIcons.Question, ESysIcons.Question); + CTaskDialog.ShowTaskDialogBox( + GeneralAppInfo.ProductName, + Language.ConnectionFileNotFound, + "", "", "", "", "", + string.Join(" | ", commandButtons), + ETaskDialogButtons.None, + ESysIcons.Question, + ESysIcons.Question); switch (CTaskDialog.CommandButtonResult) { diff --git a/mRemoteV1/App/Shutdown.cs b/mRemoteV1/App/Shutdown.cs index 3d81dcbd5..56977bba7 100644 --- a/mRemoteV1/App/Shutdown.cs +++ b/mRemoteV1/App/Shutdown.cs @@ -25,14 +25,14 @@ namespace mRemoteNG.App ProgramRoot.CloseSingletonInstanceMutex(); } - public static void Cleanup(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, FrmMain frmMain) + public static void Cleanup(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, MultiSshToolStrip multiSshToolStrip, FrmMain frmMain) { try { StopPuttySessionWatcher(); DisposeNotificationAreaIcon(); SaveConnections(); - SaveSettings(quickConnectToolStrip, externalToolsToolStrip, frmMain); + SaveSettings(quickConnectToolStrip, externalToolsToolStrip, multiSshToolStrip, frmMain); UnregisterBrowsers(); } catch (Exception ex) @@ -58,9 +58,9 @@ namespace mRemoteNG.App Runtime.ConnectionsService.SaveConnections(); } - private static void SaveSettings(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, FrmMain frmMain) + private static void SaveSettings(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, MultiSshToolStrip multiSshToolStrip, FrmMain frmMain) { - Config.Settings.SettingsSaver.SaveSettings(quickConnectToolStrip, externalToolsToolStrip, frmMain); + Config.Settings.SettingsSaver.SaveSettings(quickConnectToolStrip, externalToolsToolStrip, multiSshToolStrip, frmMain); } private static void UnregisterBrowsers() diff --git a/mRemoteV1/App/Windows.cs b/mRemoteV1/App/Windows.cs index 73fc901ad..3ffc26a4c 100644 --- a/mRemoteV1/App/Windows.cs +++ b/mRemoteV1/App/Windows.cs @@ -1,8 +1,8 @@ -using mRemoteNG.UI.Forms; -using mRemoteNG.UI.Window; -using System; +using System; using mRemoteNG.Messages; using mRemoteNG.UI; +using mRemoteNG.UI.Forms; +using mRemoteNG.UI.Window; namespace mRemoteNG.App { @@ -15,8 +15,14 @@ namespace mRemoteNG.App private static PortScanWindow _portscanForm; private static UltraVNCWindow _ultravncscForm; private static ComponentsCheckWindow _componentscheckForm; + private static ConnectionTreeWindow _treeForm; + + internal static ConnectionTreeWindow TreeForm + { + get => _treeForm ?? (_treeForm = new ConnectionTreeWindow()); + set => _treeForm = value; + } - internal static ConnectionTreeWindow TreeForm { get; set; } = new ConnectionTreeWindow(); internal static ConfigWindow ConfigForm { get; set; } = new ConfigWindow(); internal static ErrorAndInfoWindow ErrorsForm { get; set; } = new ErrorAndInfoWindow(); internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow(); diff --git a/mRemoteV1/Config/Connections/ConnectionsLoadedEventArgs.cs b/mRemoteV1/Config/Connections/ConnectionsLoadedEventArgs.cs index 2a0fb6eb4..f6faaae2d 100644 --- a/mRemoteV1/Config/Connections/ConnectionsLoadedEventArgs.cs +++ b/mRemoteV1/Config/Connections/ConnectionsLoadedEventArgs.cs @@ -10,7 +10,7 @@ namespace mRemoteNG.Config.Connections /// The previous that is being /// unloaded. /// - public Maybe PreviousConnectionTreeModel { get; } + public Optional PreviousConnectionTreeModel { get; } /// /// True if the previous was loaded from @@ -37,7 +37,7 @@ namespace mRemoteNG.Config.Connections public string NewSourcePath { get; } public ConnectionsLoadedEventArgs( - Maybe previousTreeModelModel, ConnectionTreeModel newTreeModelModel, + Optional previousTreeModelModel, ConnectionTreeModel newTreeModelModel, bool previousSourceWasDatabase, bool newSourceIsDatabase, string newSourcePath) { diff --git a/mRemoteV1/Config/Connections/CsvConnectionsSaver.cs b/mRemoteV1/Config/Connections/CsvConnectionsSaver.cs index feb45bfcb..28e7b79e2 100644 --- a/mRemoteV1/Config/Connections/CsvConnectionsSaver.cs +++ b/mRemoteV1/Config/Connections/CsvConnectionsSaver.cs @@ -2,6 +2,7 @@ using mRemoteNG.App; using mRemoteNG.Config.DataProviders; using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Csv; using mRemoteNG.Security; using mRemoteNG.Tree; diff --git a/mRemoteV1/Config/Connections/SaveConnectionsOnEdit.cs b/mRemoteV1/Config/Connections/SaveConnectionsOnEdit.cs index 91c76b983..4ff069e0f 100644 --- a/mRemoteV1/Config/Connections/SaveConnectionsOnEdit.cs +++ b/mRemoteV1/Config/Connections/SaveConnectionsOnEdit.cs @@ -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(); } } } diff --git a/mRemoteV1/Config/Connections/XmlConnectionsLoader.cs b/mRemoteV1/Config/Connections/XmlConnectionsLoader.cs index 2d29c5e43..c79e13d81 100644 --- a/mRemoteV1/Config/Connections/XmlConnectionsLoader.cs +++ b/mRemoteV1/Config/Connections/XmlConnectionsLoader.cs @@ -1,14 +1,14 @@ using System; +using System.IO; using System.Security; using mRemoteNG.Config.DataProviders; -using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Tools; using mRemoteNG.Tree; -using System.IO; namespace mRemoteNG.Config.Connections { - public class XmlConnectionsLoader + public class XmlConnectionsLoader { private readonly string _connectionFilePath; @@ -31,7 +31,7 @@ namespace mRemoteNG.Config.Connections return deserializer.Deserialize(xmlString); } - private SecureString PromptForPassword() + private Optional PromptForPassword() { var password = MiscTools.PasswordDialog("", false); return password; diff --git a/mRemoteV1/Config/Connections/XmlConnectionsSaver.cs b/mRemoteV1/Config/Connections/XmlConnectionsSaver.cs index 79a53c9fa..060c2c2b8 100644 --- a/mRemoteV1/Config/Connections/XmlConnectionsSaver.cs +++ b/mRemoteV1/Config/Connections/XmlConnectionsSaver.cs @@ -3,6 +3,7 @@ using System.Linq; using mRemoteNG.App; using mRemoteNG.Config.DataProviders; using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Security; using mRemoteNG.Security.Factories; using mRemoteNG.Tree; @@ -31,7 +32,7 @@ namespace mRemoteNG.Config.Connections try { var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build(); - var connectionNodeSerializer = new XmlConnectionNodeSerializer26( + var connectionNodeSerializer = new XmlConnectionNodeSerializer27( cryptographyProvider, connectionTreeModel.RootNodes.OfType().First().PasswordString.ConvertToSecureString(), _saveFilter); diff --git a/mRemoteV1/Config/DataProviders/FileBackupPruner.cs b/mRemoteV1/Config/DataProviders/FileBackupPruner.cs index d371647d0..5572a3456 100644 --- a/mRemoteV1/Config/DataProviders/FileBackupPruner.cs +++ b/mRemoteV1/Config/DataProviders/FileBackupPruner.cs @@ -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); } diff --git a/mRemoteV1/Config/DataProviders/FileDataProvider.cs b/mRemoteV1/Config/DataProviders/FileDataProvider.cs index 6ef87a437..4798fee15 100644 --- a/mRemoteV1/Config/DataProviders/FileDataProvider.cs +++ b/mRemoteV1/Config/DataProviders/FileDataProvider.cs @@ -20,6 +20,10 @@ namespace mRemoteNG.Config.DataProviders { fileContents = File.ReadAllText(FilePath); } + catch (FileNotFoundException ex) + { + Runtime.MessageCollector.AddExceptionStackTrace($"Could not load file. File does not exist '{FilePath}'", ex); + } catch (Exception ex) { Runtime.MessageCollector.AddExceptionStackTrace($"Failed to load file {FilePath}", ex); diff --git a/mRemoteV1/Config/Import/ActiveDirectoryImporter.cs b/mRemoteV1/Config/Import/ActiveDirectoryImporter.cs index ad4cd0fa4..9c59b3850 100644 --- a/mRemoteV1/Config/Import/ActiveDirectoryImporter.cs +++ b/mRemoteV1/Config/Import/ActiveDirectoryImporter.cs @@ -3,24 +3,23 @@ using System.Linq; using mRemoteNG.App; using mRemoteNG.Config.Serializers; using mRemoteNG.Container; - +using mRemoteNG.Tools; namespace mRemoteNG.Config.Import { - public class ActiveDirectoryImporter : IConnectionImporter + public class ActiveDirectoryImporter : IConnectionImporter { - public void Import(object ldapPath, ContainerInfo destinationContainer) + public void Import(string ldapPath, ContainerInfo destinationContainer) { - var ldapPathAsString = ldapPath as string; - if (ldapPathAsString == null) return; - Import(ldapPathAsString, destinationContainer); + Import(ldapPath, destinationContainer, false); } - public static void Import(string ldapPath, ContainerInfo destinationContainer, bool importSubOU = false) + public static void Import(string ldapPath, ContainerInfo destinationContainer, bool importSubOu) { try { - var deserializer = new ActiveDirectoryDeserializer(ldapPath, importSubOU); + ldapPath.ThrowIfNullOrEmpty(nameof(ldapPath)); + var deserializer = new ActiveDirectoryDeserializer(ldapPath, importSubOu); var connectionTreeModel = deserializer.Deserialize(); var importedRootNode = connectionTreeModel.RootNodes.First(); if (importedRootNode == null) return; diff --git a/mRemoteV1/Config/Import/IConnectionImporter.cs b/mRemoteV1/Config/Import/IConnectionImporter.cs index f09f9ae99..5614c42ec 100644 --- a/mRemoteV1/Config/Import/IConnectionImporter.cs +++ b/mRemoteV1/Config/Import/IConnectionImporter.cs @@ -1,10 +1,10 @@ using mRemoteNG.Container; - namespace mRemoteNG.Config.Import { - public interface IConnectionImporter + public interface IConnectionImporter + where TSource : class { - void Import(object source, ContainerInfo destinationContainer); + void Import(TSource source, ContainerInfo destinationContainer); } } \ No newline at end of file diff --git a/mRemoteV1/Config/Import/mRemoteNGImporter.cs b/mRemoteV1/Config/Import/MRemoteNGCsvImporter.cs similarity index 50% rename from mRemoteV1/Config/Import/mRemoteNGImporter.cs rename to mRemoteV1/Config/Import/MRemoteNGCsvImporter.cs index 56e19d651..821a711a4 100644 --- a/mRemoteV1/Config/Import/mRemoteNGImporter.cs +++ b/mRemoteV1/Config/Import/MRemoteNGCsvImporter.cs @@ -1,42 +1,34 @@ -using System.IO; +using System.IO; using System.Linq; using mRemoteNG.App; using mRemoteNG.Config.DataProviders; -using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Csv; using mRemoteNG.Container; using mRemoteNG.Messages; - namespace mRemoteNG.Config.Import { - // ReSharper disable once InconsistentNaming - public class mRemoteNGImporter : IConnectionImporter - { - public void Import(object filePath, ContainerInfo destinationContainer) - { - var filePathAsString = filePath as string; - if (filePathAsString == null) - { + public class MRemoteNGCsvImporter : IConnectionImporter + { + public void Import(string filePath, ContainerInfo destinationContainer) + { + if (string.IsNullOrEmpty(filePath)) + { Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Unable to import file. File path is null."); return; } - if(File.Exists(filePathAsString)) - Import(filePathAsString, destinationContainer); - else - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Unable to import file. File does not exist. Path: {filePathAsString}"); - } + if (!File.Exists(filePath)) + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Unable to import file. File does not exist. Path: {filePath}"); - public void Import(string fileName, ContainerInfo destinationContainer) - { - var dataProvider = new FileDataProvider(fileName); + var dataProvider = new FileDataProvider(filePath); var xmlString = dataProvider.Load(); - var xmlConnectionsDeserializer = new XmlConnectionsDeserializer(); - var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString, true); + var xmlConnectionsDeserializer = new CsvConnectionsDeserializerMremotengFormat(); + var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString); - var rootImportContainer = new ContainerInfo { Name = Path.GetFileNameWithoutExtension(fileName) }; + var rootImportContainer = new ContainerInfo { Name = Path.GetFileNameWithoutExtension(filePath) }; rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray()); destinationContainer.AddChild(rootImportContainer); - } - } -} \ No newline at end of file + } + } +} diff --git a/mRemoteV1/Config/Import/MRemoteNGXmlImporter.cs b/mRemoteV1/Config/Import/MRemoteNGXmlImporter.cs new file mode 100644 index 000000000..13c0fe449 --- /dev/null +++ b/mRemoteV1/Config/Import/MRemoteNGXmlImporter.cs @@ -0,0 +1,37 @@ +using System.IO; +using System.Linq; +using mRemoteNG.App; +using mRemoteNG.Config.DataProviders; +using mRemoteNG.Config.Serializers; +using mRemoteNG.Config.Serializers.Xml; +using mRemoteNG.Container; +using mRemoteNG.Messages; + + +namespace mRemoteNG.Config.Import +{ + // ReSharper disable once InconsistentNaming + public class MRemoteNGXmlImporter : IConnectionImporter + { + public void Import(string fileName, ContainerInfo destinationContainer) + { + if (fileName == null) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Unable to import file. File path is null."); + return; + } + + if(!File.Exists(fileName)) + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Unable to import file. File does not exist. Path: {fileName}"); + + var dataProvider = new FileDataProvider(fileName); + var xmlString = dataProvider.Load(); + var xmlConnectionsDeserializer = new XmlConnectionsDeserializer(); + var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString, true); + + var rootImportContainer = new ContainerInfo { Name = Path.GetFileNameWithoutExtension(fileName) }; + rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray()); + destinationContainer.AddChild(rootImportContainer); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Config/Import/PortScanImporter.cs b/mRemoteV1/Config/Import/PortScanImporter.cs index 4331abd55..aa0c9442e 100644 --- a/mRemoteV1/Config/Import/PortScanImporter.cs +++ b/mRemoteV1/Config/Import/PortScanImporter.cs @@ -8,7 +8,7 @@ using mRemoteNG.Tools; namespace mRemoteNG.Config.Import { - public class PortScanImporter : IConnectionImporter + public class PortScanImporter : IConnectionImporter> { private readonly ProtocolType _targetProtocolType; @@ -17,13 +17,6 @@ namespace mRemoteNG.Config.Import _targetProtocolType = targetProtocolType; } - public void Import(object hosts, ContainerInfo destinationContainer) - { - var hostsAsEnumerableScanHost = hosts as IEnumerable; - if (hostsAsEnumerableScanHost == null) return; - Import(hostsAsEnumerableScanHost, destinationContainer); - } - public void Import(IEnumerable hosts, ContainerInfo destinationContainer) { var deserializer = new PortScanDeserializer(_targetProtocolType); diff --git a/mRemoteV1/Config/Import/PuttyConnectionManagerImporter.cs b/mRemoteV1/Config/Import/PuttyConnectionManagerImporter.cs index f41f2db82..e147556c9 100644 --- a/mRemoteV1/Config/Import/PuttyConnectionManagerImporter.cs +++ b/mRemoteV1/Config/Import/PuttyConnectionManagerImporter.cs @@ -1,4 +1,3 @@ -using System.IO; using System.Linq; using mRemoteNG.Config.DataProviders; using mRemoteNG.Config.Serializers; @@ -7,17 +6,8 @@ using mRemoteNG.Container; namespace mRemoteNG.Config.Import { - public class PuttyConnectionManagerImporter : IConnectionImporter + public class PuttyConnectionManagerImporter : IConnectionImporter { - public void Import(object filePath, ContainerInfo destinationContainer) - { - var filePathAsString = filePath as string; - if (filePathAsString == null) - return; - if (File.Exists(filePathAsString)) - Import(filePathAsString, destinationContainer); - } - public void Import(string filePath, ContainerInfo destinationContainer) { var dataProvider = new FileDataProvider(filePath); diff --git a/mRemoteV1/Config/Import/RemoteDesktopConnectionImporter.cs b/mRemoteV1/Config/Import/RemoteDesktopConnectionImporter.cs index 90bbfbbdc..a46da5f61 100644 --- a/mRemoteV1/Config/Import/RemoteDesktopConnectionImporter.cs +++ b/mRemoteV1/Config/Import/RemoteDesktopConnectionImporter.cs @@ -1,4 +1,3 @@ -using System; using System.IO; using System.Linq; using mRemoteNG.Config.DataProviders; @@ -8,17 +7,8 @@ using mRemoteNG.Container; namespace mRemoteNG.Config.Import { - public class RemoteDesktopConnectionImporter : IConnectionImporter + public class RemoteDesktopConnectionImporter : IConnectionImporter { - public void Import(object fileName, ContainerInfo destinationContainer) - { - var fileNameAsString = fileName as string; - if(fileNameAsString == null) - return; - if (File.Exists(fileNameAsString)) - Import(fileNameAsString, destinationContainer); - } - public void Import(string fileName, ContainerInfo destinationContainer) { var dataProvider = new FileDataProvider(fileName); diff --git a/mRemoteV1/Config/Import/RemoteDesktopConnectionManagerImporter.cs b/mRemoteV1/Config/Import/RemoteDesktopConnectionManagerImporter.cs index 79852b735..fe6001916 100644 --- a/mRemoteV1/Config/Import/RemoteDesktopConnectionManagerImporter.cs +++ b/mRemoteV1/Config/Import/RemoteDesktopConnectionManagerImporter.cs @@ -1,4 +1,3 @@ -using System.IO; using System.Linq; using mRemoteNG.Config.DataProviders; using mRemoteNG.Config.Serializers; @@ -7,18 +6,9 @@ using mRemoteNG.Container; namespace mRemoteNG.Config.Import { - public class RemoteDesktopConnectionManagerImporter : IConnectionImporter + public class RemoteDesktopConnectionManagerImporter : IConnectionImporter { - public void Import(object filePath, ContainerInfo destinationContainer) - { - var fileNameAsString = filePath as string; - if (fileNameAsString == null) - return; - if (File.Exists(fileNameAsString)) - Import(fileNameAsString, destinationContainer); - } - - private static void Import(string filePath, ContainerInfo destinationContainer) + public void Import(string filePath, ContainerInfo destinationContainer) { var dataProvider = new FileDataProvider(filePath); var fileContent = dataProvider.Load(); diff --git a/mRemoteV1/Config/Putty/PuttySessionsManager.cs b/mRemoteV1/Config/Putty/PuttySessionsManager.cs index 42eab5677..72e9a1ce0 100644 --- a/mRemoteV1/Config/Putty/PuttySessionsManager.cs +++ b/mRemoteV1/Config/Putty/PuttySessionsManager.cs @@ -1,13 +1,13 @@ -using mRemoteNG.Tools; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; +using mRemoteNG.Tools; using mRemoteNG.Tree.Root; // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.Config.Putty { - public class PuttySessionsManager + public class PuttySessionsManager { public static PuttySessionsManager Instance { get; } = new PuttySessionsManager(); @@ -35,10 +35,12 @@ namespace mRemoteNG.Config.Putty } } - private void AddSessionsFromProvider(AbstractPuttySessionsProvider provider) + private void AddSessionsFromProvider(AbstractPuttySessionsProvider puttySessionProvider) { - var rootTreeNode = provider.RootInfo; - provider.GetSessions(); + puttySessionProvider.ThrowIfNull(nameof(puttySessionProvider)); + + var rootTreeNode = puttySessionProvider.RootInfo; + puttySessionProvider.GetSessions(); if (!RootPuttySessionsNodes.Contains(rootTreeNode) && rootTreeNode.HasChildren()) RootPuttySessionsNodes.Add(rootTreeNode); diff --git a/mRemoteV1/Config/Putty/PuttySessionsRegistryProvider.cs b/mRemoteV1/Config/Putty/PuttySessionsRegistryProvider.cs index 030e3716c..929b66be4 100644 --- a/mRemoteV1/Config/Putty/PuttySessionsRegistryProvider.cs +++ b/mRemoteV1/Config/Putty/PuttySessionsRegistryProvider.cs @@ -1,19 +1,19 @@ -using Microsoft.Win32; -using mRemoteNG.App; -using mRemoteNG.Connection; -using mRemoteNG.Connection.Protocol; -using mRemoteNG.Messages; using System; using System.Collections.Generic; using System.Management; using System.Security.Principal; using System.Text; using System.Web; +using Microsoft.Win32; +using mRemoteNG.App; +using mRemoteNG.Connection; +using mRemoteNG.Connection.Protocol; +using mRemoteNG.Messages; namespace mRemoteNG.Config.Putty { - public class PuttySessionsRegistryProvider : AbstractPuttySessionsProvider + public class PuttySessionsRegistryProvider : AbstractPuttySessionsProvider { private const string PuttySessionsKey = "Software\\SimonTatham\\PuTTY\\Sessions"; private static ManagementEventWatcher _eventWatcher; @@ -39,7 +39,10 @@ namespace mRemoteNG.Config.Putty } public override PuttySessionInfo GetSession(string sessionName) - { + { + if (string.IsNullOrEmpty(sessionName)) + return null; + var sessionsKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey); var sessionKey = sessionsKey?.OpenSubKey(sessionName); if (sessionKey == null) return null; @@ -50,10 +53,15 @@ namespace mRemoteNG.Config.Putty { PuttySession = sessionName, Name = sessionName, - Hostname = Convert.ToString(sessionKey.GetValue("HostName")), - Username = Convert.ToString(sessionKey.GetValue("UserName")) + Hostname = sessionKey.GetValue("HostName")?.ToString() ?? "", + Username = sessionKey.GetValue("UserName")?.ToString() ?? "" }; - var protocol = Convert.ToString(sessionKey.GetValue("Protocol")) ?? "ssh"; + + + var protocol = string.IsNullOrEmpty(sessionKey.GetValue("Protocol")?.ToString()) + ? "ssh" + : sessionKey.GetValue("Protocol").ToString(); + switch (protocol.ToLowerInvariant()) { case "raw": @@ -65,16 +73,15 @@ namespace mRemoteNG.Config.Putty case "serial": return null; case "ssh": - var sshVersionObject = sessionKey.GetValue("SshProt"); - if (sshVersionObject != null) - { - var sshVersion = Convert.ToInt32(sshVersionObject); - sessionInfo.Protocol = sshVersion >= 2 ? ProtocolType.SSH2 : ProtocolType.SSH1; - } - else - { - sessionInfo.Protocol = ProtocolType.SSH2; - } + int.TryParse(sessionKey.GetValue("SshProt")?.ToString(), out var sshVersion); + /* Per PUTTY.H in PuTTYNG & PuTTYNG Upstream (PuTTY proper currently) + * expect 0 for SSH1, 3 for SSH2 ONLY + * 1 for SSH1 with a 2 fallback + * 2 for SSH2 with a 1 fallback + * + * default to SSH2 if any other value is received + */ + sessionInfo.Protocol = sshVersion == 1 || sshVersion == 0 ? ProtocolType.SSH1 : ProtocolType.SSH2; break; case "telnet": sessionInfo.Protocol = ProtocolType.Telnet; @@ -82,7 +89,12 @@ namespace mRemoteNG.Config.Putty default: return null; } - sessionInfo.Port = Convert.ToInt32(sessionKey.GetValue("PortNumber")); + + int.TryParse(sessionKey.GetValue("PortNumber")?.ToString(), out var portNumber); + if (portNumber == default(int)) + sessionInfo.SetDefaultPort(); + else + sessionInfo.Port = portNumber; return sessionInfo; } diff --git a/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs b/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs index 4df1132d5..4b99a02a8 100644 --- a/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs +++ b/mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs @@ -33,6 +33,7 @@ namespace mRemoteNG.Config.Putty foreach (var sessionName in Directory.GetFiles(sessionsFolderPath)) { var sessionFileName = Path.GetFileName(sessionName); + // ReSharper disable once ConstantConditionalAccessQualifier sessionNames.Add(raw ? sessionFileName : System.Web.HttpUtility.UrlDecode(sessionFileName?.Replace("+", "%2B"))); } @@ -125,9 +126,6 @@ namespace mRemoteNG.Config.Putty public override void StartWatcher() { - PuttySessionsRegistryProvider.StartWatcher(); - PuttySessionsRegistryProvider.PuttySessionChanged += OnRegistrySessionChanged; - if (_eventWatcher != null) { return; @@ -136,18 +134,22 @@ namespace mRemoteNG.Config.Putty try { var sessionsFolderPath = GetSessionsFolderPath(); - if (Directory.Exists(sessionsFolderPath)) - { - _eventWatcher = new FileSystemWatcher(sessionsFolderPath) - { - NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite - }; - _eventWatcher.Changed += OnFileSystemEventArrived; - _eventWatcher.Created += OnFileSystemEventArrived; - _eventWatcher.Deleted += OnFileSystemEventArrived; - _eventWatcher.Renamed += OnFileSystemEventArrived; - _eventWatcher.EnableRaisingEvents = true; - } + + if (!Directory.Exists(sessionsFolderPath)) + { + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"XmingPortablePuttySessions.Watcher.StartWatching() failed: '{sessionsFolderPath}' does not exist.", true); + return; + } + + _eventWatcher = new FileSystemWatcher(sessionsFolderPath) + { + NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite + }; + _eventWatcher.Changed += OnFileSystemEventArrived; + _eventWatcher.Created += OnFileSystemEventArrived; + _eventWatcher.Deleted += OnFileSystemEventArrived; + _eventWatcher.Renamed += OnFileSystemEventArrived; + _eventWatcher.EnableRaisingEvents = true; } catch (Exception ex) { @@ -173,7 +175,8 @@ namespace mRemoteNG.Config.Putty private static string GetPuttyConfPath() { var puttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath ? mRemoteNG.Settings.Default.CustomPuttyPath : App.Info.GeneralAppInfo.PuttyPath; - return Path.Combine(Path.GetDirectoryName(puttyPath), "putty.conf"); + puttyPath = Path.GetDirectoryName(puttyPath); + return string.IsNullOrEmpty(puttyPath) ? null : Path.Combine(puttyPath, "putty.conf"); } private static string GetSessionsFolderPath() @@ -200,6 +203,9 @@ namespace mRemoteNG.Config.Putty private static PuttySessionInfo ModifyRegistrySessionInfo(PuttySessionInfo sessionInfo) { + if (sessionInfo == null) + return null; + sessionInfo.Name = string.Format(RegistrySessionNameFormat, sessionInfo.Name); sessionInfo.PuttySession = string.Format(RegistrySessionNameFormat, sessionInfo.PuttySession); return sessionInfo; diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs new file mode 100644 index 000000000..0bef17557 --- /dev/null +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs @@ -0,0 +1,725 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using mRemoteNG.Connection; +using mRemoteNG.Connection.Protocol; +using mRemoteNG.Connection.Protocol.Http; +using mRemoteNG.Connection.Protocol.ICA; +using mRemoteNG.Connection.Protocol.RDP; +using mRemoteNG.Connection.Protocol.VNC; +using mRemoteNG.Container; +using mRemoteNG.Tree; +using mRemoteNG.Tree.Root; + +namespace mRemoteNG.Config.Serializers.Csv +{ + public class CsvConnectionsDeserializerMremotengFormat : IDeserializer + { + public ConnectionTreeModel Deserialize(string serializedData) + { + var lines = serializedData.Split(new []{"\r\n", "\r", "\n"}, StringSplitOptions.RemoveEmptyEntries); + var csvHeaders = new List(); + // used to map a connectioninfo to it's parent's GUID + var parentMapping = new Dictionary(); + + for (var lineNumber = 0; lineNumber < lines.Length; lineNumber++) + { + var line = lines[lineNumber].Split(';'); + if (lineNumber == 0) + csvHeaders = line.ToList(); + else + { + var connectionInfo = ParseConnectionInfo(csvHeaders, line); + parentMapping.Add(connectionInfo, line[csvHeaders.IndexOf("Parent")]); + } + } + + var root = CreateTreeStructure(parentMapping); + var connectionTreeModel = new ConnectionTreeModel(); + connectionTreeModel.AddRootNode(root); + return connectionTreeModel; + } + + private RootNodeInfo CreateTreeStructure(Dictionary parentMapping) + { + var root = new RootNodeInfo(RootNodeType.Connection); + + foreach (var node in parentMapping) + { + // no parent mapped, add to root + if (string.IsNullOrEmpty(node.Value)) + { + root.AddChild(node.Key); + continue; + } + + // search for parent in the list by GUID + var parent = parentMapping + .Keys + .OfType() + .FirstOrDefault(info => info.ConstantID == node.Value); + + if (parent != null) + { + parent.AddChild(node.Key); + } + else + { + root.AddChild(node.Key); + } + } + + return root; + } + + private ConnectionInfo ParseConnectionInfo(IList headers, string[] connectionCsv) + { + var nodeType = headers.Contains("NodeType") + ? (TreeNodeType)Enum.Parse(typeof(TreeNodeType), connectionCsv[headers.IndexOf("NodeType")], true) + : TreeNodeType.Connection; + + var nodeId = headers.Contains("Id") + ? connectionCsv[headers.IndexOf("Id")] + : Guid.NewGuid().ToString(); + + var connectionRecord = nodeType == TreeNodeType.Connection + ? new ConnectionInfo(nodeId) + : new ContainerInfo(nodeId); + + connectionRecord.Name = headers.Contains("Name") ? connectionCsv[headers.IndexOf("Name")] : ""; + connectionRecord.Description = headers.Contains("Description") ? connectionCsv[headers.IndexOf("Description")] : ""; + connectionRecord.Icon = headers.Contains("Icon") ? connectionCsv[headers.IndexOf("Icon")] : ""; + connectionRecord.Panel = headers.Contains("Panel") ? connectionCsv[headers.IndexOf("Panel")] : ""; + connectionRecord.Username = headers.Contains("Username") ? connectionCsv[headers.IndexOf("Username")] : ""; + connectionRecord.Password = headers.Contains("Password") ? connectionCsv[headers.IndexOf("Password")] : ""; + connectionRecord.Domain = headers.Contains("Domain") ? connectionCsv[headers.IndexOf("Domain")] : ""; + connectionRecord.Hostname = headers.Contains("Hostname") ? connectionCsv[headers.IndexOf("Hostname")] : ""; + connectionRecord.PuttySession = headers.Contains("PuttySession") ? connectionCsv[headers.IndexOf("PuttySession")] : ""; + connectionRecord.LoadBalanceInfo = headers.Contains("LoadBalanceInfo") ? connectionCsv[headers.IndexOf("LoadBalanceInfo")] : ""; + connectionRecord.PreExtApp = headers.Contains("PreExtApp") ? connectionCsv[headers.IndexOf("PreExtApp")] : ""; + connectionRecord.PostExtApp = headers.Contains("PostExtApp") ? connectionCsv[headers.IndexOf("PostExtApp")] : ""; + connectionRecord.MacAddress = headers.Contains("MacAddress") ? connectionCsv[headers.IndexOf("MacAddress")] : ""; + connectionRecord.UserField = headers.Contains("UserField") ? connectionCsv[headers.IndexOf("UserField")] : ""; + connectionRecord.ExtApp = headers.Contains("ExtApp") ? connectionCsv[headers.IndexOf("ExtApp")] : ""; + connectionRecord.VNCProxyUsername = headers.Contains("VNCProxyUsername") ? connectionCsv[headers.IndexOf("VNCProxyUsername")] : ""; + connectionRecord.VNCProxyPassword = headers.Contains("VNCProxyPassword") ? connectionCsv[headers.IndexOf("VNCProxyPassword")] : ""; + connectionRecord.RDGatewayUsername = headers.Contains("RDGatewayUsername") ? connectionCsv[headers.IndexOf("RDGatewayUsername")] : ""; + connectionRecord.RDGatewayPassword = headers.Contains("RDGatewayPassword") ? connectionCsv[headers.IndexOf("RDGatewayPassword")] : ""; + connectionRecord.RDGatewayDomain = headers.Contains("RDGatewayDomain") ? connectionCsv[headers.IndexOf("RDGatewayDomain")] : ""; + connectionRecord.VNCProxyIP = headers.Contains("VNCProxyIP") ? connectionCsv[headers.IndexOf("VNCProxyIP")] : ""; + connectionRecord.RDGatewayHostname = headers.Contains("RDGatewayHostname") ? connectionCsv[headers.IndexOf("RDGatewayHostname")] : ""; + + if (headers.Contains("Protocol")) + { + ProtocolType protocolType; + if (Enum.TryParse(connectionCsv[headers.IndexOf("Protocol")], out protocolType)) + connectionRecord.Protocol = protocolType; + } + + if (headers.Contains("Port")) + { + int port; + if (int.TryParse(connectionCsv[headers.IndexOf("Port")], out port)) + connectionRecord.Port = port; + } + + if (headers.Contains("ConnectToConsole")) + { + bool useConsoleSession; + if (bool.TryParse(connectionCsv[headers.IndexOf("ConnectToConsole")], out useConsoleSession)) + connectionRecord.UseConsoleSession = useConsoleSession; + } + + if (headers.Contains("UseCredSsp")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("UseCredSsp")], out value)) + connectionRecord.UseCredSsp = value; + } + + if (headers.Contains("RenderingEngine")) + { + HTTPBase.RenderingEngine value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("RenderingEngine")], out value)) + connectionRecord.RenderingEngine = value; + } + + if (headers.Contains("ICAEncryptionStrength")) + { + IcaProtocol.EncryptionStrength value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("ICAEncryptionStrength")], out value)) + connectionRecord.ICAEncryptionStrength = value; + } + + if (headers.Contains("RDPAuthenticationLevel")) + { + RdpProtocol.AuthenticationLevel value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("RDPAuthenticationLevel")], out value)) + connectionRecord.RDPAuthenticationLevel = value; + } + + if (headers.Contains("Colors")) + { + RdpProtocol.RDPColors value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("Colors")], out value)) + connectionRecord.Colors = value; + } + + if (headers.Contains("Resolution")) + { + RdpProtocol.RDPResolutions value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("Resolution")], out value)) + connectionRecord.Resolution = value; + } + + if (headers.Contains("AutomaticResize")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("AutomaticResize")], out value)) + connectionRecord.AutomaticResize = value; + } + + if (headers.Contains("DisplayWallpaper")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("DisplayWallpaper")], out value)) + connectionRecord.DisplayWallpaper = value; + } + + if (headers.Contains("DisplayThemes")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("DisplayThemes")], out value)) + connectionRecord.DisplayThemes = value; + } + + if (headers.Contains("EnableFontSmoothing")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("EnableFontSmoothing")], out value)) + connectionRecord.EnableFontSmoothing = value; + } + + if (headers.Contains("EnableDesktopComposition")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("EnableDesktopComposition")], out value)) + connectionRecord.EnableDesktopComposition = value; + } + + if (headers.Contains("CacheBitmaps")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("CacheBitmaps")], out value)) + connectionRecord.CacheBitmaps = value; + } + + if (headers.Contains("RedirectDiskDrives")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("RedirectDiskDrives")], out value)) + connectionRecord.RedirectDiskDrives = value; + } + + if (headers.Contains("RedirectPorts")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("RedirectPorts")], out value)) + connectionRecord.RedirectPorts = value; + } + + if (headers.Contains("RedirectPrinters")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("RedirectPrinters")], out value)) + connectionRecord.RedirectPrinters = value; + } + if (headers.Contains("RedirectClipboard")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("RedirectClipboard")], out value)) + connectionRecord.RedirectClipboard = value; + } + + if (headers.Contains("RedirectSmartCards")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("RedirectSmartCards")], out value)) + connectionRecord.RedirectSmartCards = value; + } + + if (headers.Contains("RedirectSound")) + { + RdpProtocol.RDPSounds value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("RedirectSound")], out value)) + connectionRecord.RedirectSound = value; + } + + if (headers.Contains("RedirectKeys")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("RedirectKeys")], out value)) + connectionRecord.RedirectKeys = value; + } + + if (headers.Contains("VNCCompression")) + { + ProtocolVNC.Compression value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("VNCCompression")], out value)) + connectionRecord.VNCCompression = value; + } + + if (headers.Contains("VNCEncoding")) + { + ProtocolVNC.Encoding value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("VNCEncoding")], out value)) + connectionRecord.VNCEncoding = value; + } + + if (headers.Contains("VNCAuthMode")) + { + ProtocolVNC.AuthMode value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("VNCAuthMode")], out value)) + connectionRecord.VNCAuthMode = value; + } + + if (headers.Contains("VNCProxyType")) + { + ProtocolVNC.ProxyType value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("VNCProxyType")], out value)) + connectionRecord.VNCProxyType = value; + } + + if (headers.Contains("VNCProxyPort")) + { + int value; + if (int.TryParse(connectionCsv[headers.IndexOf("VNCProxyPort")], out value)) + connectionRecord.VNCProxyPort = value; + } + + if (headers.Contains("VNCColors")) + { + ProtocolVNC.Colors value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("VNCColors")], out value)) + connectionRecord.VNCColors = value; + } + + if (headers.Contains("VNCSmartSizeMode")) + { + ProtocolVNC.SmartSizeMode value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("VNCSmartSizeMode")], out value)) + connectionRecord.VNCSmartSizeMode = value; + } + + if (headers.Contains("VNCViewOnly")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("VNCViewOnly")], out value)) + connectionRecord.VNCViewOnly = value; + } + + if (headers.Contains("RDGatewayUsageMethod")) + { + RdpProtocol.RDGatewayUsageMethod value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("RDGatewayUsageMethod")], out value)) + connectionRecord.RDGatewayUsageMethod = value; + } + + if (headers.Contains("RDGatewayUseConnectionCredentials")) + { + RdpProtocol.RDGatewayUseConnectionCredentials value; + if (Enum.TryParse(connectionCsv[headers.IndexOf("RDGatewayUseConnectionCredentials")], out value)) + connectionRecord.RDGatewayUseConnectionCredentials = value; + } + + #region Inheritance + if (headers.Contains("InheritCacheBitmaps")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritCacheBitmaps")], out value)) + connectionRecord.Inheritance.CacheBitmaps = value; + } + + if (headers.Contains("InheritColors")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritColors")], out value)) + connectionRecord.Inheritance.Colors = value; + } + + if (headers.Contains("InheritDescription")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritDescription")], out value)) + connectionRecord.Inheritance.Description = value; + } + + if (headers.Contains("InheritDisplayThemes")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritDisplayThemes")], out value)) + connectionRecord.Inheritance.DisplayThemes = value; + } + + if (headers.Contains("InheritDisplayWallpaper")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritDisplayWallpaper")], out value)) + connectionRecord.Inheritance.DisplayWallpaper = value; + } + + if (headers.Contains("InheritEnableFontSmoothing")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritEnableFontSmoothing")], out value)) + connectionRecord.Inheritance.EnableFontSmoothing = value; + } + + if (headers.Contains("InheritEnableDesktopComposition")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritEnableDesktopComposition")], out value)) + connectionRecord.Inheritance.EnableDesktopComposition = value; + } + + if (headers.Contains("InheritDomain")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritDomain")], out value)) + connectionRecord.Inheritance.Domain = value; + } + + if (headers.Contains("InheritIcon")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritIcon")], out value)) + connectionRecord.Inheritance.Icon = value; + } + + if (headers.Contains("InheritPanel")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritPanel")], out value)) + connectionRecord.Inheritance.Panel = value; + } + + if (headers.Contains("InheritPassword")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritPassword")], out value)) + connectionRecord.Inheritance.Password = value; + } + + if (headers.Contains("InheritPort")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritPort")], out value)) + connectionRecord.Inheritance.Port = value; + } + + if (headers.Contains("InheritProtocol")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritProtocol")], out value)) + connectionRecord.Inheritance.Protocol = value; + } + + if (headers.Contains("InheritPuttySession")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritPuttySession")], out value)) + connectionRecord.Inheritance.PuttySession = value; + } + + if (headers.Contains("InheritRedirectDiskDrives")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRedirectDiskDrives")], out value)) + connectionRecord.Inheritance.RedirectDiskDrives = value; + } + + if (headers.Contains("InheritRedirectKeys")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRedirectKeys")], out value)) + connectionRecord.Inheritance.RedirectKeys = value; + } + + if (headers.Contains("InheritRedirectPorts")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRedirectPorts")], out value)) + connectionRecord.Inheritance.RedirectPorts = value; + } + + if (headers.Contains("InheritRedirectPrinters")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRedirectPrinters")], out value)) + connectionRecord.Inheritance.RedirectPrinters = value; + } + + if (headers.Contains("InheritRedirectClipboard")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRedirectClipboard")], out value)) + connectionRecord.Inheritance.RedirectClipboard = value; + } + + if (headers.Contains("InheritRedirectSmartCards")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRedirectSmartCards")], out value)) + connectionRecord.Inheritance.RedirectSmartCards = value; + } + + if (headers.Contains("InheritRedirectSound")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRedirectSound")], out value)) + connectionRecord.Inheritance.RedirectSound = value; + } + + if (headers.Contains("InheritResolution")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritResolution")], out value)) + connectionRecord.Inheritance.Resolution = value; + } + + if (headers.Contains("InheritAutomaticResize")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritAutomaticResize")], out value)) + connectionRecord.Inheritance.AutomaticResize = value; + } + + if (headers.Contains("InheritUseConsoleSession")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritUseConsoleSession")], out value)) + connectionRecord.Inheritance.UseConsoleSession = value; + } + + if (headers.Contains("InheritUseCredSsp")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritUseCredSsp")], out value)) + connectionRecord.Inheritance.UseCredSsp = value; + } + + if (headers.Contains("InheritRenderingEngine")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRenderingEngine")], out value)) + connectionRecord.Inheritance.RenderingEngine = value; + } + + if (headers.Contains("InheritUsername")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritUsername")], out value)) + connectionRecord.Inheritance.Username = value; + } + + if (headers.Contains("InheritICAEncryptionStrength")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritICAEncryptionStrength")], out value)) + connectionRecord.Inheritance.ICAEncryptionStrength = value; + } + + if (headers.Contains("InheritRDPAuthenticationLevel")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDPAuthenticationLevel")], out value)) + connectionRecord.Inheritance.RDPAuthenticationLevel = value; + } + + if (headers.Contains("InheritLoadBalanceInfo")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritLoadBalanceInfo")], out value)) + connectionRecord.Inheritance.LoadBalanceInfo = value; + } + + if (headers.Contains("InheritPreExtApp")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritPreExtApp")], out value)) + connectionRecord.Inheritance.PreExtApp = value; + } + + if (headers.Contains("InheritPostExtApp")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritPostExtApp")], out value)) + connectionRecord.Inheritance.PostExtApp = value; + } + + if (headers.Contains("InheritMacAddress")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritMacAddress")], out value)) + connectionRecord.Inheritance.MacAddress = value; + } + + if (headers.Contains("InheritUserField")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritUserField")], out value)) + connectionRecord.Inheritance.UserField = value; + } + + if (headers.Contains("InheritExtApp")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritExtApp")], out value)) + connectionRecord.Inheritance.ExtApp = value; + } + + if (headers.Contains("InheritVNCCompression")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCCompression")], out value)) + connectionRecord.Inheritance.VNCCompression = value; + } + + if (headers.Contains("InheritVNCEncoding")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCEncoding")], out value)) + connectionRecord.Inheritance.VNCEncoding = value; + } + + if (headers.Contains("InheritVNCAuthMode")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCAuthMode")], out value)) + connectionRecord.Inheritance.VNCAuthMode = value; + } + + if (headers.Contains("InheritVNCProxyType")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCProxyType")], out value)) + connectionRecord.Inheritance.VNCProxyType = value; + } + + if (headers.Contains("InheritVNCProxyIP")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCProxyIP")], out value)) + connectionRecord.Inheritance.VNCProxyIP = value; + } + + if (headers.Contains("InheritVNCProxyPort")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCProxyPort")], out value)) + connectionRecord.Inheritance.VNCProxyPort = value; + } + + if (headers.Contains("InheritVNCProxyUsername")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCProxyUsername")], out value)) + connectionRecord.Inheritance.VNCProxyUsername = value; + } + + if (headers.Contains("InheritVNCProxyPassword")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCProxyPassword")], out value)) + connectionRecord.Inheritance.VNCProxyPassword = value; + } + + if (headers.Contains("InheritVNCColors")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCColors")], out value)) + connectionRecord.Inheritance.VNCColors = value; + } + + if (headers.Contains("InheritVNCSmartSizeMode")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCSmartSizeMode")], out value)) + connectionRecord.Inheritance.VNCSmartSizeMode = value; + } + + if (headers.Contains("InheritVNCViewOnly")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritVNCViewOnly")], out value)) + connectionRecord.Inheritance.VNCViewOnly = value; + } + + if (headers.Contains("InheritRDGatewayUsageMethod")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDGatewayUsageMethod")], out value)) + connectionRecord.Inheritance.RDGatewayUsageMethod = value; + } + + if (headers.Contains("InheritRDGatewayHostname")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDGatewayHostname")], out value)) + connectionRecord.Inheritance.RDGatewayHostname = value; + } + + if (headers.Contains("InheritRDGatewayUseConnectionCredentials")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDGatewayUseConnectionCredentials")], out value)) + connectionRecord.Inheritance.RDGatewayUseConnectionCredentials = value; + } + + if (headers.Contains("InheritRDGatewayUsername")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDGatewayUsername")], out value)) + connectionRecord.Inheritance.RDGatewayUsername = value; + } + + if (headers.Contains("InheritRDGatewayPassword")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDGatewayPassword")], out value)) + connectionRecord.Inheritance.RDGatewayPassword = value; + } + + if (headers.Contains("InheritRDGatewayDomain")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDGatewayDomain")], out value)) + connectionRecord.Inheritance.RDGatewayDomain = value; + } + + if (headers.Contains("InheritRDPAlertIdleTimeout")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDPAlertIdleTimeout")], out value)) + connectionRecord.Inheritance.RDPAlertIdleTimeout = value; + } + + if (headers.Contains("InheritRDPMinutesToIdleTimeout")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRDPMinutesToIdleTimeout")], out value)) + connectionRecord.Inheritance.RDPMinutesToIdleTimeout = value; + } + + if (headers.Contains("InheritSoundQuality")) + { + bool value; + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritSoundQuality")], out value)) + connectionRecord.Inheritance.SoundQuality = value; + } + #endregion + + return connectionRecord; + } + } +} diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs new file mode 100644 index 000000000..e8ecdd602 --- /dev/null +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs @@ -0,0 +1,213 @@ +using System; +using System.Linq; +using System.Text; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.Credential; +using mRemoteNG.Security; +using mRemoteNG.Tools; +using mRemoteNG.Tree; +using mRemoteNG.Tree.Root; + +namespace mRemoteNG.Config.Serializers.Csv +{ + public class CsvConnectionsSerializerMremotengFormat : ISerializer + { + private readonly SaveFilter _saveFilter; + private readonly ICredentialRepositoryList _credentialRepositoryList; + + public CsvConnectionsSerializerMremotengFormat(SaveFilter saveFilter, ICredentialRepositoryList credentialRepositoryList) + { + saveFilter.ThrowIfNull(nameof(saveFilter)); + credentialRepositoryList.ThrowIfNull(nameof(credentialRepositoryList)); + + _saveFilter = saveFilter; + _credentialRepositoryList = credentialRepositoryList; + } + + public string Serialize(ConnectionTreeModel connectionTreeModel) + { + connectionTreeModel.ThrowIfNull(nameof(connectionTreeModel)); + + var rootNode = connectionTreeModel.RootNodes.First(node => node is RootNodeInfo); + return Serialize(rootNode); + } + + public string Serialize(ConnectionInfo serializationTarget) + { + serializationTarget.ThrowIfNull(nameof(serializationTarget)); + var sb = new StringBuilder(); + + WriteCsvHeader(sb); + SerializeNodesRecursive(serializationTarget, sb); + return sb.ToString(); + } + + private void WriteCsvHeader(StringBuilder sb) + { + sb.Append("Name;Id;Parent;NodeType;Description;Icon;Panel;"); + if (_saveFilter.SaveUsername) + sb.Append("Username;"); + if (_saveFilter.SavePassword) + sb.Append("Password;"); + if (_saveFilter.SaveDomain) + sb.Append("Domain;"); + sb.Append("Hostname;Protocol;PuttySession;Port;ConnectToConsole;UseCredSsp;RenderingEngine;ICAEncryptionStrength;RDPAuthenticationLevel;LoadBalanceInfo;Colors;Resolution;AutomaticResize;DisplayWallpaper;DisplayThemes;EnableFontSmoothing;EnableDesktopComposition;CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectClipboard;RedirectSmartCards;RedirectSound;RedirectKeys;PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;VNCProxyPort;VNCProxyUsername;VNCProxyPassword;VNCColors;VNCSmartSizeMode;VNCViewOnly;RDGatewayUsageMethod;RDGatewayHostname;RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;"); + if (_saveFilter.SaveInheritance) + sb.Append("InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;InheritEnableFontSmoothing;InheritEnableDesktopComposition;InheritDomain;InheritIcon;InheritPanel;InheritPassword;InheritPort;InheritProtocol;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;InheritRedirectClipboard;InheritRedirectSmartCards;InheritRedirectSound;InheritResolution;InheritAutomaticResize;InheritUseConsoleSession;InheritUseCredSsp;InheritRenderingEngine;InheritUsername;InheritICAEncryptionStrength;InheritRDPAuthenticationLevel;InheritLoadBalanceInfo;InheritPreExtApp;InheritPostExtApp;InheritMacAddress;InheritUserField;InheritExtApp;InheritVNCCompression;InheritVNCEncoding;InheritVNCAuthMode;InheritVNCProxyType;InheritVNCProxyIP;InheritVNCProxyPort;InheritVNCProxyUsername;InheritVNCProxyPassword;InheritVNCColors;InheritVNCSmartSizeMode;InheritVNCViewOnly;InheritRDGatewayUsageMethod;InheritRDGatewayHostname;InheritRDGatewayUseConnectionCredentials;InheritRDGatewayUsername;InheritRDGatewayPassword;InheritRDGatewayDomain;InheritRDPAlertIdleTimeout;InheritRDPMinutesToIdleTimeout;InheritSoundQuality"); + } + + private void SerializeNodesRecursive(ConnectionInfo node, StringBuilder sb) + { + var nodeAsContainer = node as ContainerInfo; + if (nodeAsContainer != null) + { + foreach (var child in nodeAsContainer.Children) + { + SerializeNodesRecursive(child, sb); + } + } + + // dont serialize the root node + if (node is RootNodeInfo) + return; + + SerializeConnectionInfo(node, sb); + } + + private void SerializeConnectionInfo(ConnectionInfo con, StringBuilder sb) + { + sb.AppendLine(); + sb.Append(FormatForCsv(con.Name)) + .Append(FormatForCsv(con.ConstantID)) + .Append(FormatForCsv(con.Parent?.ConstantID ?? "")) + .Append(FormatForCsv(con.GetTreeNodeType())) + .Append(FormatForCsv(con.Description)) + .Append(FormatForCsv(con.Icon)) + .Append(FormatForCsv(con.Panel)); + + if (_saveFilter.SaveUsername) + sb.Append(FormatForCsv(con.Username)); + + if (_saveFilter.SavePassword) + sb.Append(FormatForCsv(con.Password)); + + if (_saveFilter.SaveDomain) + sb.Append(FormatForCsv(con.Domain)); + + sb.Append(FormatForCsv(con.Hostname)) + .Append(FormatForCsv(con.Protocol)) + .Append(FormatForCsv(con.PuttySession)) + .Append(FormatForCsv(con.Port)) + .Append(FormatForCsv(con.UseConsoleSession)) + .Append(FormatForCsv(con.UseCredSsp)) + .Append(FormatForCsv(con.RenderingEngine)) + .Append(FormatForCsv(con.ICAEncryptionStrength)) + .Append(FormatForCsv(con.RDPAuthenticationLevel)) + .Append(FormatForCsv(con.LoadBalanceInfo)) + .Append(FormatForCsv(con.Colors)) + .Append(FormatForCsv(con.Resolution)) + .Append(FormatForCsv(con.AutomaticResize)) + .Append(FormatForCsv(con.DisplayWallpaper)) + .Append(FormatForCsv(con.DisplayThemes)) + .Append(FormatForCsv(con.EnableFontSmoothing)) + .Append(FormatForCsv(con.EnableDesktopComposition)) + .Append(FormatForCsv(con.CacheBitmaps)) + .Append(FormatForCsv(con.RedirectDiskDrives)) + .Append(FormatForCsv(con.RedirectPorts)) + .Append(FormatForCsv(con.RedirectPrinters)) + .Append(FormatForCsv(con.RedirectClipboard)) + .Append(FormatForCsv(con.RedirectSmartCards)) + .Append(FormatForCsv(con.RedirectSound)) + .Append(FormatForCsv(con.RedirectKeys)) + .Append(FormatForCsv(con.PreExtApp)) + .Append(FormatForCsv(con.PostExtApp)) + .Append(FormatForCsv(con.MacAddress)) + .Append(FormatForCsv(con.UserField)) + .Append(FormatForCsv(con.ExtApp)) + .Append(FormatForCsv(con.VNCCompression)) + .Append(FormatForCsv(con.VNCEncoding)) + .Append(FormatForCsv(con.VNCAuthMode)) + .Append(FormatForCsv(con.VNCProxyType)) + .Append(FormatForCsv(con.VNCProxyIP)) + .Append(FormatForCsv(con.VNCProxyPort)) + .Append(FormatForCsv(con.VNCProxyUsername)) + .Append(FormatForCsv(con.VNCProxyPassword)) + .Append(FormatForCsv(con.VNCColors)) + .Append(FormatForCsv(con.VNCSmartSizeMode)) + .Append(FormatForCsv(con.VNCViewOnly)) + .Append(FormatForCsv(con.RDGatewayUsageMethod)) + .Append(FormatForCsv(con.RDGatewayHostname)) + .Append(FormatForCsv(con.RDGatewayUseConnectionCredentials)) + .Append(FormatForCsv(con.RDGatewayUsername)) + .Append(FormatForCsv(con.RDGatewayPassword)) + .Append(FormatForCsv(con.RDGatewayDomain)); + + + if (!_saveFilter.SaveInheritance) + return; + + sb.Append(FormatForCsv(con.Inheritance.CacheBitmaps)) + .Append(FormatForCsv(con.Inheritance.Colors)) + .Append(FormatForCsv(con.Inheritance.Description)) + .Append(FormatForCsv(con.Inheritance.DisplayThemes)) + .Append(FormatForCsv(con.Inheritance.DisplayWallpaper)) + .Append(FormatForCsv(con.Inheritance.EnableFontSmoothing)) + .Append(FormatForCsv(con.Inheritance.EnableDesktopComposition)) + .Append(FormatForCsv(con.Inheritance.Domain)) + .Append(FormatForCsv(con.Inheritance.Icon)) + .Append(FormatForCsv(con.Inheritance.Panel)) + .Append(FormatForCsv(con.Inheritance.Password)) + .Append(FormatForCsv(con.Inheritance.Port)) + .Append(FormatForCsv(con.Inheritance.Protocol)) + .Append(FormatForCsv(con.Inheritance.PuttySession)) + .Append(FormatForCsv(con.Inheritance.RedirectDiskDrives)) + .Append(FormatForCsv(con.Inheritance.RedirectKeys)) + .Append(FormatForCsv(con.Inheritance.RedirectPorts)) + .Append(FormatForCsv(con.Inheritance.RedirectPrinters)) + .Append(FormatForCsv(con.Inheritance.RedirectClipboard)) + .Append(FormatForCsv(con.Inheritance.RedirectSmartCards)) + .Append(FormatForCsv(con.Inheritance.RedirectSound)) + .Append(FormatForCsv(con.Inheritance.Resolution)) + .Append(FormatForCsv(con.Inheritance.AutomaticResize)) + .Append(FormatForCsv(con.Inheritance.UseConsoleSession)) + .Append(FormatForCsv(con.Inheritance.UseCredSsp)) + .Append(FormatForCsv(con.Inheritance.RenderingEngine)) + .Append(FormatForCsv(con.Inheritance.Username)) + .Append(FormatForCsv(con.Inheritance.ICAEncryptionStrength)) + .Append(FormatForCsv(con.Inheritance.RDPAuthenticationLevel)) + .Append(FormatForCsv(con.Inheritance.LoadBalanceInfo)) + .Append(FormatForCsv(con.Inheritance.PreExtApp)) + .Append(FormatForCsv(con.Inheritance.PostExtApp)) + .Append(FormatForCsv(con.Inheritance.MacAddress)) + .Append(FormatForCsv(con.Inheritance.UserField)) + .Append(FormatForCsv(con.Inheritance.ExtApp)) + .Append(FormatForCsv(con.Inheritance.VNCCompression)) + .Append(FormatForCsv(con.Inheritance.VNCEncoding)) + .Append(FormatForCsv(con.Inheritance.VNCAuthMode)) + .Append(FormatForCsv(con.Inheritance.VNCProxyType)) + .Append(FormatForCsv(con.Inheritance.VNCProxyIP)) + .Append(FormatForCsv(con.Inheritance.VNCProxyPort)) + .Append(FormatForCsv(con.Inheritance.VNCProxyUsername)) + .Append(FormatForCsv(con.Inheritance.VNCProxyPassword)) + .Append(FormatForCsv(con.Inheritance.VNCColors)) + .Append(FormatForCsv(con.Inheritance.VNCSmartSizeMode)) + .Append(FormatForCsv(con.Inheritance.VNCViewOnly)) + .Append(FormatForCsv(con.Inheritance.RDGatewayUsageMethod)) + .Append(FormatForCsv(con.Inheritance.RDGatewayHostname)) + .Append(FormatForCsv(con.Inheritance.RDGatewayUseConnectionCredentials)) + .Append(FormatForCsv(con.Inheritance.RDGatewayUsername)) + .Append(FormatForCsv(con.Inheritance.RDGatewayPassword)) + .Append(FormatForCsv(con.Inheritance.RDGatewayDomain)) + .Append(FormatForCsv(con.Inheritance.RDPAlertIdleTimeout)) + .Append(FormatForCsv(con.Inheritance.RDPMinutesToIdleTimeout)) + .Append(FormatForCsv(con.Inheritance.SoundQuality)); + } + + private string FormatForCsv(object value) + { + var cleanedString = value.ToString().Replace(";", ""); + return cleanedString + ";"; + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionNodeSerializer26.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer26.cs similarity index 72% rename from mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionNodeSerializer26.cs rename to mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer26.cs index dd0bebedb..15b012d24 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionNodeSerializer26.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer26.cs @@ -5,8 +5,7 @@ using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Security; - -namespace mRemoteNG.Config.Serializers +namespace mRemoteNG.Config.Serializers.Xml { // ReSharper disable once InconsistentNaming public class XmlConnectionNodeSerializer26 : ISerializer @@ -43,7 +42,7 @@ namespace mRemoteNG.Config.Serializers element.Add(new XAttribute("Name", connectionInfo.Name)); element.Add(new XAttribute("Type", connectionInfo.GetTreeNodeType().ToString())); if (nodeAsContainer != null) - element.Add(new XAttribute("Expanded", nodeAsContainer.IsExpanded.ToString())); + element.Add(new XAttribute("Expanded", nodeAsContainer.IsExpanded.ToString().ToLowerInvariant())); element.Add(new XAttribute("Descr", connectionInfo.Description)); element.Add(new XAttribute("Icon", connectionInfo.Icon)); element.Add(new XAttribute("Panel", connectionInfo.Panel)); @@ -66,30 +65,30 @@ namespace mRemoteNG.Config.Serializers element.Add(new XAttribute("Protocol", connectionInfo.Protocol)); element.Add(new XAttribute("PuttySession", connectionInfo.PuttySession)); element.Add(new XAttribute("Port", connectionInfo.Port)); - element.Add(new XAttribute("ConnectToConsole", connectionInfo.UseConsoleSession.ToString())); - element.Add(new XAttribute("UseCredSsp", connectionInfo.UseCredSsp.ToString())); + element.Add(new XAttribute("ConnectToConsole", connectionInfo.UseConsoleSession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("UseCredSsp", connectionInfo.UseCredSsp.ToString().ToLowerInvariant())); element.Add(new XAttribute("RenderingEngine", connectionInfo.RenderingEngine)); element.Add(new XAttribute("ICAEncryptionStrength", connectionInfo.ICAEncryptionStrength)); element.Add(new XAttribute("RDPAuthenticationLevel", connectionInfo.RDPAuthenticationLevel)); element.Add(new XAttribute("RDPMinutesToIdleTimeout", connectionInfo.RDPMinutesToIdleTimeout)); - element.Add(new XAttribute("RDPAlertIdleTimeout", connectionInfo.RDPAlertIdleTimeout)); + element.Add(new XAttribute("RDPAlertIdleTimeout", connectionInfo.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); element.Add(new XAttribute("LoadBalanceInfo", connectionInfo.LoadBalanceInfo)); element.Add(new XAttribute("Colors", connectionInfo.Colors)); element.Add(new XAttribute("Resolution", connectionInfo.Resolution)); - element.Add(new XAttribute("AutomaticResize", connectionInfo.AutomaticResize.ToString())); - element.Add(new XAttribute("DisplayWallpaper", connectionInfo.DisplayWallpaper.ToString())); - element.Add(new XAttribute("DisplayThemes", connectionInfo.DisplayThemes.ToString())); - element.Add(new XAttribute("EnableFontSmoothing", connectionInfo.EnableFontSmoothing.ToString())); - element.Add(new XAttribute("EnableDesktopComposition", connectionInfo.EnableDesktopComposition.ToString())); - element.Add(new XAttribute("CacheBitmaps", connectionInfo.CacheBitmaps.ToString())); - element.Add(new XAttribute("RedirectDiskDrives", connectionInfo.RedirectDiskDrives.ToString())); - element.Add(new XAttribute("RedirectPorts", connectionInfo.RedirectPorts.ToString())); - element.Add(new XAttribute("RedirectPrinters", connectionInfo.RedirectPrinters.ToString())); - element.Add(new XAttribute("RedirectSmartCards", connectionInfo.RedirectSmartCards.ToString())); + element.Add(new XAttribute("AutomaticResize", connectionInfo.AutomaticResize.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisplayWallpaper", connectionInfo.DisplayWallpaper.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisplayThemes", connectionInfo.DisplayThemes.ToString().ToLowerInvariant())); + element.Add(new XAttribute("EnableFontSmoothing", connectionInfo.EnableFontSmoothing.ToString().ToLowerInvariant())); + element.Add(new XAttribute("EnableDesktopComposition", connectionInfo.EnableDesktopComposition.ToString().ToLowerInvariant())); + element.Add(new XAttribute("CacheBitmaps", connectionInfo.CacheBitmaps.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectDiskDrives", connectionInfo.RedirectDiskDrives.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectPorts", connectionInfo.RedirectPorts.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectPrinters", connectionInfo.RedirectPrinters.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectSmartCards", connectionInfo.RedirectSmartCards.ToString().ToLowerInvariant())); element.Add(new XAttribute("RedirectSound", connectionInfo.RedirectSound.ToString())); element.Add(new XAttribute("SoundQuality", connectionInfo.SoundQuality.ToString())); - element.Add(new XAttribute("RedirectKeys", connectionInfo.RedirectKeys.ToString())); - element.Add(new XAttribute("Connected", (connectionInfo.OpenConnections.Count > 0).ToString())); + element.Add(new XAttribute("RedirectKeys", connectionInfo.RedirectKeys.ToString().ToLowerInvariant())); + element.Add(new XAttribute("Connected", (connectionInfo.OpenConnections.Count > 0).ToString().ToLowerInvariant())); element.Add(new XAttribute("PreExtApp", connectionInfo.PreExtApp)); element.Add(new XAttribute("PostExtApp", connectionInfo.PostExtApp)); element.Add(new XAttribute("MacAddress", connectionInfo.MacAddress)); @@ -113,7 +112,7 @@ namespace mRemoteNG.Config.Serializers element.Add(new XAttribute("VNCColors", connectionInfo.VNCColors)); element.Add(new XAttribute("VNCSmartSizeMode", connectionInfo.VNCSmartSizeMode)); - element.Add(new XAttribute("VNCViewOnly", connectionInfo.VNCViewOnly.ToString())); + element.Add(new XAttribute("VNCViewOnly", connectionInfo.VNCViewOnly.ToString().ToLowerInvariant())); element.Add(new XAttribute("RDGatewayUsageMethod", connectionInfo.RDGatewayUsageMethod)); element.Add(new XAttribute("RDGatewayHostname", connectionInfo.RDGatewayHostname)); element.Add(new XAttribute("RDGatewayUseConnectionCredentials", connectionInfo.RDGatewayUseConnectionCredentials)); @@ -136,117 +135,118 @@ namespace mRemoteNG.Config.Serializers { if (_saveFilter.SaveInheritance) { - element.Add(new XAttribute("InheritCacheBitmaps", connectionInfo.Inheritance.CacheBitmaps.ToString())); - element.Add(new XAttribute("InheritColors", connectionInfo.Inheritance.Colors.ToString())); - element.Add(new XAttribute("InheritDescription", connectionInfo.Inheritance.Description.ToString())); - element.Add(new XAttribute("InheritDisplayThemes", connectionInfo.Inheritance.DisplayThemes.ToString())); - element.Add(new XAttribute("InheritDisplayWallpaper", connectionInfo.Inheritance.DisplayWallpaper.ToString())); - element.Add(new XAttribute("InheritEnableFontSmoothing", connectionInfo.Inheritance.EnableFontSmoothing.ToString())); - element.Add(new XAttribute("InheritEnableDesktopComposition", connectionInfo.Inheritance.EnableDesktopComposition.ToString())); - element.Add(new XAttribute("InheritDomain", connectionInfo.Inheritance.Domain.ToString())); - element.Add(new XAttribute("InheritIcon", connectionInfo.Inheritance.Icon.ToString())); - element.Add(new XAttribute("InheritPanel", connectionInfo.Inheritance.Panel.ToString())); - element.Add(new XAttribute("InheritPassword", connectionInfo.Inheritance.Password.ToString())); - element.Add(new XAttribute("InheritPort", connectionInfo.Inheritance.Port.ToString())); - element.Add(new XAttribute("InheritProtocol", connectionInfo.Inheritance.Protocol.ToString())); - element.Add(new XAttribute("InheritPuttySession", connectionInfo.Inheritance.PuttySession.ToString())); - element.Add(new XAttribute("InheritRedirectDiskDrives", connectionInfo.Inheritance.RedirectDiskDrives.ToString())); - element.Add(new XAttribute("InheritRedirectKeys", connectionInfo.Inheritance.RedirectKeys.ToString())); - element.Add(new XAttribute("InheritRedirectPorts", connectionInfo.Inheritance.RedirectPorts.ToString())); - element.Add(new XAttribute("InheritRedirectPrinters", connectionInfo.Inheritance.RedirectPrinters.ToString())); - element.Add(new XAttribute("InheritRedirectSmartCards", connectionInfo.Inheritance.RedirectSmartCards.ToString())); - element.Add(new XAttribute("InheritRedirectSound", connectionInfo.Inheritance.RedirectSound.ToString())); - element.Add(new XAttribute("InheritSoundQuality", connectionInfo.Inheritance.SoundQuality.ToString())); - element.Add(new XAttribute("InheritResolution", connectionInfo.Inheritance.Resolution.ToString())); - element.Add(new XAttribute("InheritAutomaticResize", connectionInfo.Inheritance.AutomaticResize.ToString())); - element.Add(new XAttribute("InheritUseConsoleSession", connectionInfo.Inheritance.UseConsoleSession.ToString())); - element.Add(new XAttribute("InheritUseCredSsp", connectionInfo.Inheritance.UseCredSsp.ToString())); - element.Add(new XAttribute("InheritRenderingEngine", connectionInfo.Inheritance.RenderingEngine.ToString())); - element.Add(new XAttribute("InheritUsername", connectionInfo.Inheritance.Username.ToString())); - element.Add(new XAttribute("InheritICAEncryptionStrength", connectionInfo.Inheritance.ICAEncryptionStrength.ToString())); - element.Add(new XAttribute("InheritRDPAuthenticationLevel", connectionInfo.Inheritance.RDPAuthenticationLevel.ToString())); - element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", connectionInfo.Inheritance.RDPMinutesToIdleTimeout.ToString())); - element.Add(new XAttribute("InheritRDPAlertIdleTimeout", connectionInfo.Inheritance.RDPAlertIdleTimeout.ToString())); - element.Add(new XAttribute("InheritLoadBalanceInfo", connectionInfo.Inheritance.LoadBalanceInfo.ToString())); - element.Add(new XAttribute("InheritPreExtApp", connectionInfo.Inheritance.PreExtApp.ToString())); - element.Add(new XAttribute("InheritPostExtApp", connectionInfo.Inheritance.PostExtApp.ToString())); - element.Add(new XAttribute("InheritMacAddress", connectionInfo.Inheritance.MacAddress.ToString())); - element.Add(new XAttribute("InheritUserField", connectionInfo.Inheritance.UserField.ToString())); - element.Add(new XAttribute("InheritExtApp", connectionInfo.Inheritance.ExtApp.ToString())); - element.Add(new XAttribute("InheritVNCCompression", connectionInfo.Inheritance.VNCCompression.ToString())); - element.Add(new XAttribute("InheritVNCEncoding", connectionInfo.Inheritance.VNCEncoding.ToString())); - element.Add(new XAttribute("InheritVNCAuthMode", connectionInfo.Inheritance.VNCAuthMode.ToString())); - element.Add(new XAttribute("InheritVNCProxyType", connectionInfo.Inheritance.VNCProxyType.ToString())); - element.Add(new XAttribute("InheritVNCProxyIP", connectionInfo.Inheritance.VNCProxyIP.ToString())); - element.Add(new XAttribute("InheritVNCProxyPort", connectionInfo.Inheritance.VNCProxyPort.ToString())); - element.Add(new XAttribute("InheritVNCProxyUsername", connectionInfo.Inheritance.VNCProxyUsername.ToString())); - element.Add(new XAttribute("InheritVNCProxyPassword", connectionInfo.Inheritance.VNCProxyPassword.ToString())); - element.Add(new XAttribute("InheritVNCColors", connectionInfo.Inheritance.VNCColors.ToString())); - element.Add(new XAttribute("InheritVNCSmartSizeMode", connectionInfo.Inheritance.VNCSmartSizeMode.ToString())); - element.Add(new XAttribute("InheritVNCViewOnly", connectionInfo.Inheritance.VNCViewOnly.ToString())); - element.Add(new XAttribute("InheritRDGatewayUsageMethod", connectionInfo.Inheritance.RDGatewayUsageMethod.ToString())); - element.Add(new XAttribute("InheritRDGatewayHostname", connectionInfo.Inheritance.RDGatewayHostname.ToString())); - element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", connectionInfo.Inheritance.RDGatewayUseConnectionCredentials.ToString())); - element.Add(new XAttribute("InheritRDGatewayUsername", connectionInfo.Inheritance.RDGatewayUsername.ToString())); - element.Add(new XAttribute("InheritRDGatewayPassword", connectionInfo.Inheritance.RDGatewayPassword.ToString())); - element.Add(new XAttribute("InheritRDGatewayDomain", connectionInfo.Inheritance.RDGatewayDomain.ToString())); + element.Add(new XAttribute("InheritCacheBitmaps", connectionInfo.Inheritance.CacheBitmaps.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritColors", connectionInfo.Inheritance.Colors.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDescription", connectionInfo.Inheritance.Description.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDisplayThemes", connectionInfo.Inheritance.DisplayThemes.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDisplayWallpaper", connectionInfo.Inheritance.DisplayWallpaper.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritEnableFontSmoothing", connectionInfo.Inheritance.EnableFontSmoothing.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritEnableDesktopComposition", connectionInfo.Inheritance.EnableDesktopComposition.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDomain", connectionInfo.Inheritance.Domain.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritIcon", connectionInfo.Inheritance.Icon.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPanel", connectionInfo.Inheritance.Panel.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPassword", connectionInfo.Inheritance.Password.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPort", connectionInfo.Inheritance.Port.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritProtocol", connectionInfo.Inheritance.Protocol.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPuttySession", connectionInfo.Inheritance.PuttySession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectDiskDrives", connectionInfo.Inheritance.RedirectDiskDrives.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectKeys", connectionInfo.Inheritance.RedirectKeys.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectPorts", connectionInfo.Inheritance.RedirectPorts.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectPrinters", connectionInfo.Inheritance.RedirectPrinters.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectSmartCards", connectionInfo.Inheritance.RedirectSmartCards.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectSound", connectionInfo.Inheritance.RedirectSound.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritSoundQuality", connectionInfo.Inheritance.SoundQuality.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritResolution", connectionInfo.Inheritance.Resolution.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritAutomaticResize", connectionInfo.Inheritance.AutomaticResize.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUseConsoleSession", connectionInfo.Inheritance.UseConsoleSession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUseCredSsp", connectionInfo.Inheritance.UseCredSsp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRenderingEngine", connectionInfo.Inheritance.RenderingEngine.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUsername", connectionInfo.Inheritance.Username.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritICAEncryptionStrength", connectionInfo.Inheritance.ICAEncryptionStrength.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPAuthenticationLevel", connectionInfo.Inheritance.RDPAuthenticationLevel.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", connectionInfo.Inheritance.RDPMinutesToIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPAlertIdleTimeout", connectionInfo.Inheritance.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritLoadBalanceInfo", connectionInfo.Inheritance.LoadBalanceInfo.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPreExtApp", connectionInfo.Inheritance.PreExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPostExtApp", connectionInfo.Inheritance.PostExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritMacAddress", connectionInfo.Inheritance.MacAddress.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUserField", connectionInfo.Inheritance.UserField.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritExtApp", connectionInfo.Inheritance.ExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCCompression", connectionInfo.Inheritance.VNCCompression.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCEncoding", connectionInfo.Inheritance.VNCEncoding.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCAuthMode", connectionInfo.Inheritance.VNCAuthMode.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyType", connectionInfo.Inheritance.VNCProxyType.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyIP", connectionInfo.Inheritance.VNCProxyIP.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyPort", connectionInfo.Inheritance.VNCProxyPort.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyUsername", connectionInfo.Inheritance.VNCProxyUsername.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyPassword", connectionInfo.Inheritance.VNCProxyPassword.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCColors", connectionInfo.Inheritance.VNCColors.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCSmartSizeMode", connectionInfo.Inheritance.VNCSmartSizeMode.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCViewOnly", connectionInfo.Inheritance.VNCViewOnly.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUsageMethod", connectionInfo.Inheritance.RDGatewayUsageMethod.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayHostname", connectionInfo.Inheritance.RDGatewayHostname.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", connectionInfo.Inheritance.RDGatewayUseConnectionCredentials.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUsername", connectionInfo.Inheritance.RDGatewayUsername.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayPassword", connectionInfo.Inheritance.RDGatewayPassword.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayDomain", connectionInfo.Inheritance.RDGatewayDomain.ToString().ToLowerInvariant())); } else { - element.Add(new XAttribute("InheritCacheBitmaps", false.ToString())); - element.Add(new XAttribute("InheritColors", false.ToString())); - element.Add(new XAttribute("InheritDescription", false.ToString())); - element.Add(new XAttribute("InheritDisplayThemes", false.ToString())); - element.Add(new XAttribute("InheritDisplayWallpaper", false.ToString())); - element.Add(new XAttribute("InheritEnableFontSmoothing", false.ToString())); - element.Add(new XAttribute("InheritEnableDesktopComposition", false.ToString())); - element.Add(new XAttribute("InheritDomain", false.ToString())); - element.Add(new XAttribute("InheritIcon", false.ToString())); - element.Add(new XAttribute("InheritPanel", false.ToString())); - element.Add(new XAttribute("InheritPassword", false.ToString())); - element.Add(new XAttribute("InheritPort", false.ToString())); - element.Add(new XAttribute("InheritProtocol", false.ToString())); - element.Add(new XAttribute("InheritPuttySession", false.ToString())); - element.Add(new XAttribute("InheritRedirectDiskDrives", false.ToString())); - element.Add(new XAttribute("InheritRedirectKeys", false.ToString())); - element.Add(new XAttribute("InheritRedirectPorts", false.ToString())); - element.Add(new XAttribute("InheritRedirectPrinters", false.ToString())); - element.Add(new XAttribute("InheritRedirectSmartCards", false.ToString())); - element.Add(new XAttribute("InheritRedirectSound", false.ToString())); - element.Add(new XAttribute("InheritSoundQuality", false.ToString())); - element.Add(new XAttribute("InheritResolution", false.ToString())); - element.Add(new XAttribute("InheritAutomaticResize", false.ToString())); - element.Add(new XAttribute("InheritUseConsoleSession", false.ToString())); - element.Add(new XAttribute("InheritUseCredSsp", false.ToString())); - element.Add(new XAttribute("InheritRenderingEngine", false.ToString())); - element.Add(new XAttribute("InheritUsername", false.ToString())); - element.Add(new XAttribute("InheritICAEncryptionStrength", false.ToString())); - element.Add(new XAttribute("InheritRDPAuthenticationLevel", false.ToString())); - element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", false.ToString())); - element.Add(new XAttribute("InheritRDPAlertIdleTimeout", false.ToString())); - element.Add(new XAttribute("InheritLoadBalanceInfo", false.ToString())); - element.Add(new XAttribute("InheritPreExtApp", false.ToString())); - element.Add(new XAttribute("InheritPostExtApp", false.ToString())); - element.Add(new XAttribute("InheritMacAddress", false.ToString())); - element.Add(new XAttribute("InheritUserField", false.ToString())); - element.Add(new XAttribute("InheritExtApp", false.ToString())); - element.Add(new XAttribute("InheritVNCCompression", false.ToString())); - element.Add(new XAttribute("InheritVNCEncoding", false.ToString())); - element.Add(new XAttribute("InheritVNCAuthMode", false.ToString())); - element.Add(new XAttribute("InheritVNCProxyType", false.ToString())); - element.Add(new XAttribute("InheritVNCProxyIP", false.ToString())); - element.Add(new XAttribute("InheritVNCProxyPort", false.ToString())); - element.Add(new XAttribute("InheritVNCProxyUsername", false.ToString())); - element.Add(new XAttribute("InheritVNCProxyPassword", false.ToString())); - element.Add(new XAttribute("InheritVNCColors", false.ToString())); - element.Add(new XAttribute("InheritVNCSmartSizeMode", false.ToString())); - element.Add(new XAttribute("InheritVNCViewOnly", false.ToString())); - element.Add(new XAttribute("InheritRDGatewayUsageMethod", false.ToString())); - element.Add(new XAttribute("InheritRDGatewayHostname", false.ToString())); - element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", false.ToString())); - element.Add(new XAttribute("InheritRDGatewayUsername", false.ToString())); - element.Add(new XAttribute("InheritRDGatewayPassword", false.ToString())); - element.Add(new XAttribute("InheritRDGatewayDomain", false.ToString())); + var falseString = false.ToString().ToLowerInvariant(); + element.Add(new XAttribute("InheritCacheBitmaps", falseString)); + element.Add(new XAttribute("InheritColors", falseString)); + element.Add(new XAttribute("InheritDescription", falseString)); + element.Add(new XAttribute("InheritDisplayThemes", falseString)); + element.Add(new XAttribute("InheritDisplayWallpaper", falseString)); + element.Add(new XAttribute("InheritEnableFontSmoothing", falseString)); + element.Add(new XAttribute("InheritEnableDesktopComposition", falseString)); + element.Add(new XAttribute("InheritDomain", falseString)); + element.Add(new XAttribute("InheritIcon", falseString)); + element.Add(new XAttribute("InheritPanel", falseString)); + element.Add(new XAttribute("InheritPassword", falseString)); + element.Add(new XAttribute("InheritPort", falseString)); + element.Add(new XAttribute("InheritProtocol", falseString)); + element.Add(new XAttribute("InheritPuttySession", falseString)); + element.Add(new XAttribute("InheritRedirectDiskDrives", falseString)); + element.Add(new XAttribute("InheritRedirectKeys", falseString)); + element.Add(new XAttribute("InheritRedirectPorts", falseString)); + element.Add(new XAttribute("InheritRedirectPrinters", falseString)); + element.Add(new XAttribute("InheritRedirectSmartCards", falseString)); + element.Add(new XAttribute("InheritRedirectSound", falseString)); + element.Add(new XAttribute("InheritSoundQuality", falseString)); + element.Add(new XAttribute("InheritResolution", falseString)); + element.Add(new XAttribute("InheritAutomaticResize", falseString)); + element.Add(new XAttribute("InheritUseConsoleSession", falseString)); + element.Add(new XAttribute("InheritUseCredSsp", falseString)); + element.Add(new XAttribute("InheritRenderingEngine", falseString)); + element.Add(new XAttribute("InheritUsername", falseString)); + element.Add(new XAttribute("InheritICAEncryptionStrength", falseString)); + element.Add(new XAttribute("InheritRDPAuthenticationLevel", falseString)); + element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", falseString)); + element.Add(new XAttribute("InheritRDPAlertIdleTimeout", falseString)); + element.Add(new XAttribute("InheritLoadBalanceInfo", falseString)); + element.Add(new XAttribute("InheritPreExtApp", falseString)); + element.Add(new XAttribute("InheritPostExtApp", falseString)); + element.Add(new XAttribute("InheritMacAddress", falseString)); + element.Add(new XAttribute("InheritUserField", falseString)); + element.Add(new XAttribute("InheritExtApp", falseString)); + element.Add(new XAttribute("InheritVNCCompression", falseString)); + element.Add(new XAttribute("InheritVNCEncoding", falseString)); + element.Add(new XAttribute("InheritVNCAuthMode", falseString)); + element.Add(new XAttribute("InheritVNCProxyType", falseString)); + element.Add(new XAttribute("InheritVNCProxyIP", falseString)); + element.Add(new XAttribute("InheritVNCProxyPort", falseString)); + element.Add(new XAttribute("InheritVNCProxyUsername", falseString)); + element.Add(new XAttribute("InheritVNCProxyPassword", falseString)); + element.Add(new XAttribute("InheritVNCColors", falseString)); + element.Add(new XAttribute("InheritVNCSmartSizeMode", falseString)); + element.Add(new XAttribute("InheritVNCViewOnly", falseString)); + element.Add(new XAttribute("InheritRDGatewayUsageMethod", falseString)); + element.Add(new XAttribute("InheritRDGatewayHostname", falseString)); + element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", falseString)); + element.Add(new XAttribute("InheritRDGatewayUsername", falseString)); + element.Add(new XAttribute("InheritRDGatewayPassword", falseString)); + element.Add(new XAttribute("InheritRDGatewayDomain", falseString)); } } } diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer27.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer27.cs new file mode 100644 index 000000000..29c124929 --- /dev/null +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer27.cs @@ -0,0 +1,256 @@ +using System; +using System.Security; +using System.Xml.Linq; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.Security; + +namespace mRemoteNG.Config.Serializers.Xml +{ + // ReSharper disable once InconsistentNaming + public class XmlConnectionNodeSerializer27 : ISerializer + { + private readonly ICryptographyProvider _cryptographyProvider; + private readonly SecureString _encryptionKey; + private readonly SaveFilter _saveFilter; + + public XmlConnectionNodeSerializer27(ICryptographyProvider cryptographyProvider, SecureString encryptionKey, SaveFilter saveFilter) + { + if (cryptographyProvider == null) + throw new ArgumentNullException(nameof(cryptographyProvider)); + if (encryptionKey == null) + throw new ArgumentNullException(nameof(encryptionKey)); + if (saveFilter == null) + throw new ArgumentNullException(nameof(saveFilter)); + + _cryptographyProvider = cryptographyProvider; + _encryptionKey = encryptionKey; + _saveFilter = saveFilter; + } + + public XElement Serialize(ConnectionInfo connectionInfo) + { + var element = new XElement(XName.Get("Node", "")); + SetElementAttributes(element, connectionInfo); + SetInheritanceAttributes(element, connectionInfo); + return element; + } + + private void SetElementAttributes(XContainer element, ConnectionInfo connectionInfo) + { + var nodeAsContainer = connectionInfo as ContainerInfo; + element.Add(new XAttribute("Name", connectionInfo.Name)); + element.Add(new XAttribute("Type", connectionInfo.GetTreeNodeType().ToString())); + if (nodeAsContainer != null) + element.Add(new XAttribute("Expanded", nodeAsContainer.IsExpanded.ToString().ToLowerInvariant())); + element.Add(new XAttribute("Descr", connectionInfo.Description)); + element.Add(new XAttribute("Icon", connectionInfo.Icon)); + element.Add(new XAttribute("Panel", connectionInfo.Panel)); + element.Add(new XAttribute("Id", connectionInfo.ConstantID)); + + element.Add(_saveFilter.SaveUsername + ? new XAttribute("Username", connectionInfo.Username) + : new XAttribute("Username", "")); + + element.Add(_saveFilter.SaveDomain + ? new XAttribute("Domain", connectionInfo.Domain) + : new XAttribute("Domain", "")); + + if (_saveFilter.SavePassword && !connectionInfo.Inheritance.Password) + element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey))); + else + element.Add(new XAttribute("Password", "")); + + element.Add(new XAttribute("Hostname", connectionInfo.Hostname)); + element.Add(new XAttribute("Protocol", connectionInfo.Protocol)); + element.Add(new XAttribute("PuttySession", connectionInfo.PuttySession)); + element.Add(new XAttribute("Port", connectionInfo.Port)); + element.Add(new XAttribute("ConnectToConsole", connectionInfo.UseConsoleSession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("UseCredSsp", connectionInfo.UseCredSsp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RenderingEngine", connectionInfo.RenderingEngine)); + element.Add(new XAttribute("ICAEncryptionStrength", connectionInfo.ICAEncryptionStrength)); + element.Add(new XAttribute("RDPAuthenticationLevel", connectionInfo.RDPAuthenticationLevel)); + element.Add(new XAttribute("RDPMinutesToIdleTimeout", connectionInfo.RDPMinutesToIdleTimeout)); + element.Add(new XAttribute("RDPAlertIdleTimeout", connectionInfo.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("LoadBalanceInfo", connectionInfo.LoadBalanceInfo)); + element.Add(new XAttribute("Colors", connectionInfo.Colors)); + element.Add(new XAttribute("Resolution", connectionInfo.Resolution)); + element.Add(new XAttribute("AutomaticResize", connectionInfo.AutomaticResize.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisplayWallpaper", connectionInfo.DisplayWallpaper.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisplayThemes", connectionInfo.DisplayThemes.ToString().ToLowerInvariant())); + element.Add(new XAttribute("EnableFontSmoothing", connectionInfo.EnableFontSmoothing.ToString().ToLowerInvariant())); + element.Add(new XAttribute("EnableDesktopComposition", connectionInfo.EnableDesktopComposition.ToString().ToLowerInvariant())); + element.Add(new XAttribute("CacheBitmaps", connectionInfo.CacheBitmaps.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectDiskDrives", connectionInfo.RedirectDiskDrives.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectPorts", connectionInfo.RedirectPorts.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectPrinters", connectionInfo.RedirectPrinters.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectClipboard", connectionInfo.RedirectClipboard.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectSmartCards", connectionInfo.RedirectSmartCards.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectSound", connectionInfo.RedirectSound.ToString())); + element.Add(new XAttribute("SoundQuality", connectionInfo.SoundQuality.ToString())); + element.Add(new XAttribute("RedirectKeys", connectionInfo.RedirectKeys.ToString().ToLowerInvariant())); + element.Add(new XAttribute("Connected", (connectionInfo.OpenConnections.Count > 0).ToString().ToLowerInvariant())); + element.Add(new XAttribute("PreExtApp", connectionInfo.PreExtApp)); + element.Add(new XAttribute("PostExtApp", connectionInfo.PostExtApp)); + element.Add(new XAttribute("MacAddress", connectionInfo.MacAddress)); + element.Add(new XAttribute("UserField", connectionInfo.UserField)); + element.Add(new XAttribute("ExtApp", connectionInfo.ExtApp)); + element.Add(new XAttribute("VNCCompression", connectionInfo.VNCCompression)); + element.Add(new XAttribute("VNCEncoding", connectionInfo.VNCEncoding)); + element.Add(new XAttribute("VNCAuthMode", connectionInfo.VNCAuthMode)); + element.Add(new XAttribute("VNCProxyType", connectionInfo.VNCProxyType)); + element.Add(new XAttribute("VNCProxyIP", connectionInfo.VNCProxyIP)); + element.Add(new XAttribute("VNCProxyPort", connectionInfo.VNCProxyPort)); + + element.Add(_saveFilter.SaveUsername + ? new XAttribute("VNCProxyUsername", connectionInfo.VNCProxyUsername) + : new XAttribute("VNCProxyUsername", "")); + + element.Add(_saveFilter.SavePassword + ? new XAttribute("VNCProxyPassword", + _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey)) + : new XAttribute("VNCProxyPassword", "")); + + element.Add(new XAttribute("VNCColors", connectionInfo.VNCColors)); + element.Add(new XAttribute("VNCSmartSizeMode", connectionInfo.VNCSmartSizeMode)); + element.Add(new XAttribute("VNCViewOnly", connectionInfo.VNCViewOnly.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RDGatewayUsageMethod", connectionInfo.RDGatewayUsageMethod)); + element.Add(new XAttribute("RDGatewayHostname", connectionInfo.RDGatewayHostname)); + element.Add(new XAttribute("RDGatewayUseConnectionCredentials", connectionInfo.RDGatewayUseConnectionCredentials)); + + element.Add(_saveFilter.SaveUsername + ? new XAttribute("RDGatewayUsername", connectionInfo.RDGatewayUsername) + : new XAttribute("RDGatewayUsername", "")); + + element.Add(_saveFilter.SavePassword + ? new XAttribute("RDGatewayPassword", + _cryptographyProvider.Encrypt(connectionInfo.RDGatewayPassword, _encryptionKey)) + : new XAttribute("RDGatewayPassword", "")); + + element.Add(_saveFilter.SaveDomain + ? new XAttribute("RDGatewayDomain", connectionInfo.RDGatewayDomain) + : new XAttribute("RDGatewayDomain", "")); + } + + private void SetInheritanceAttributes(XContainer element, IInheritable connectionInfo) + { + if (_saveFilter.SaveInheritance) + { + element.Add(new XAttribute("InheritCacheBitmaps", connectionInfo.Inheritance.CacheBitmaps.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritColors", connectionInfo.Inheritance.Colors.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDescription", connectionInfo.Inheritance.Description.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDisplayThemes", connectionInfo.Inheritance.DisplayThemes.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDisplayWallpaper", connectionInfo.Inheritance.DisplayWallpaper.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritEnableFontSmoothing", connectionInfo.Inheritance.EnableFontSmoothing.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritEnableDesktopComposition", connectionInfo.Inheritance.EnableDesktopComposition.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritDomain", connectionInfo.Inheritance.Domain.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritIcon", connectionInfo.Inheritance.Icon.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPanel", connectionInfo.Inheritance.Panel.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPassword", connectionInfo.Inheritance.Password.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPort", connectionInfo.Inheritance.Port.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritProtocol", connectionInfo.Inheritance.Protocol.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPuttySession", connectionInfo.Inheritance.PuttySession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectDiskDrives", connectionInfo.Inheritance.RedirectDiskDrives.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectKeys", connectionInfo.Inheritance.RedirectKeys.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectPorts", connectionInfo.Inheritance.RedirectPorts.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectPrinters", connectionInfo.Inheritance.RedirectPrinters.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectClipboard", connectionInfo.Inheritance.RedirectClipboard.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectSmartCards", connectionInfo.Inheritance.RedirectSmartCards.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRedirectSound", connectionInfo.Inheritance.RedirectSound.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritSoundQuality", connectionInfo.Inheritance.SoundQuality.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritResolution", connectionInfo.Inheritance.Resolution.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritAutomaticResize", connectionInfo.Inheritance.AutomaticResize.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUseConsoleSession", connectionInfo.Inheritance.UseConsoleSession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUseCredSsp", connectionInfo.Inheritance.UseCredSsp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRenderingEngine", connectionInfo.Inheritance.RenderingEngine.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUsername", connectionInfo.Inheritance.Username.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritICAEncryptionStrength", connectionInfo.Inheritance.ICAEncryptionStrength.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPAuthenticationLevel", connectionInfo.Inheritance.RDPAuthenticationLevel.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", connectionInfo.Inheritance.RDPMinutesToIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDPAlertIdleTimeout", connectionInfo.Inheritance.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritLoadBalanceInfo", connectionInfo.Inheritance.LoadBalanceInfo.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPreExtApp", connectionInfo.Inheritance.PreExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritPostExtApp", connectionInfo.Inheritance.PostExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritMacAddress", connectionInfo.Inheritance.MacAddress.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritUserField", connectionInfo.Inheritance.UserField.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritExtApp", connectionInfo.Inheritance.ExtApp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCCompression", connectionInfo.Inheritance.VNCCompression.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCEncoding", connectionInfo.Inheritance.VNCEncoding.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCAuthMode", connectionInfo.Inheritance.VNCAuthMode.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyType", connectionInfo.Inheritance.VNCProxyType.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyIP", connectionInfo.Inheritance.VNCProxyIP.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyPort", connectionInfo.Inheritance.VNCProxyPort.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyUsername", connectionInfo.Inheritance.VNCProxyUsername.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCProxyPassword", connectionInfo.Inheritance.VNCProxyPassword.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCColors", connectionInfo.Inheritance.VNCColors.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCSmartSizeMode", connectionInfo.Inheritance.VNCSmartSizeMode.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritVNCViewOnly", connectionInfo.Inheritance.VNCViewOnly.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUsageMethod", connectionInfo.Inheritance.RDGatewayUsageMethod.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayHostname", connectionInfo.Inheritance.RDGatewayHostname.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", connectionInfo.Inheritance.RDGatewayUseConnectionCredentials.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayUsername", connectionInfo.Inheritance.RDGatewayUsername.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayPassword", connectionInfo.Inheritance.RDGatewayPassword.ToString().ToLowerInvariant())); + element.Add(new XAttribute("InheritRDGatewayDomain", connectionInfo.Inheritance.RDGatewayDomain.ToString().ToLowerInvariant())); + } + else + { + var falseString = false.ToString().ToLowerInvariant(); + element.Add(new XAttribute("InheritCacheBitmaps", falseString)); + element.Add(new XAttribute("InheritColors", falseString)); + element.Add(new XAttribute("InheritDescription", falseString)); + element.Add(new XAttribute("InheritDisplayThemes", falseString)); + element.Add(new XAttribute("InheritDisplayWallpaper", falseString)); + element.Add(new XAttribute("InheritEnableFontSmoothing", falseString)); + element.Add(new XAttribute("InheritEnableDesktopComposition", falseString)); + element.Add(new XAttribute("InheritDomain", falseString)); + element.Add(new XAttribute("InheritIcon", falseString)); + element.Add(new XAttribute("InheritPanel", falseString)); + element.Add(new XAttribute("InheritPassword", falseString)); + element.Add(new XAttribute("InheritPort", falseString)); + element.Add(new XAttribute("InheritProtocol", falseString)); + element.Add(new XAttribute("InheritPuttySession", falseString)); + element.Add(new XAttribute("InheritRedirectDiskDrives", falseString)); + element.Add(new XAttribute("InheritRedirectKeys", falseString)); + element.Add(new XAttribute("InheritRedirectPorts", falseString)); + element.Add(new XAttribute("InheritRedirectPrinters", falseString)); + element.Add(new XAttribute("InheritRedirectClipboard", falseString)); + element.Add(new XAttribute("InheritRedirectSmartCards", falseString)); + element.Add(new XAttribute("InheritRedirectSound", falseString)); + element.Add(new XAttribute("InheritSoundQuality", falseString)); + element.Add(new XAttribute("InheritResolution", falseString)); + element.Add(new XAttribute("InheritAutomaticResize", falseString)); + element.Add(new XAttribute("InheritUseConsoleSession", falseString)); + element.Add(new XAttribute("InheritUseCredSsp", falseString)); + element.Add(new XAttribute("InheritRenderingEngine", falseString)); + element.Add(new XAttribute("InheritUsername", falseString)); + element.Add(new XAttribute("InheritICAEncryptionStrength", falseString)); + element.Add(new XAttribute("InheritRDPAuthenticationLevel", falseString)); + element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", falseString)); + element.Add(new XAttribute("InheritRDPAlertIdleTimeout", falseString)); + element.Add(new XAttribute("InheritLoadBalanceInfo", falseString)); + element.Add(new XAttribute("InheritPreExtApp", falseString)); + element.Add(new XAttribute("InheritPostExtApp", falseString)); + element.Add(new XAttribute("InheritMacAddress", falseString)); + element.Add(new XAttribute("InheritUserField", falseString)); + element.Add(new XAttribute("InheritExtApp", falseString)); + element.Add(new XAttribute("InheritVNCCompression", falseString)); + element.Add(new XAttribute("InheritVNCEncoding", falseString)); + element.Add(new XAttribute("InheritVNCAuthMode", falseString)); + element.Add(new XAttribute("InheritVNCProxyType", falseString)); + element.Add(new XAttribute("InheritVNCProxyIP", falseString)); + element.Add(new XAttribute("InheritVNCProxyPort", falseString)); + element.Add(new XAttribute("InheritVNCProxyUsername", falseString)); + element.Add(new XAttribute("InheritVNCProxyPassword", falseString)); + element.Add(new XAttribute("InheritVNCColors", falseString)); + element.Add(new XAttribute("InheritVNCSmartSizeMode", falseString)); + element.Add(new XAttribute("InheritVNCViewOnly", falseString)); + element.Add(new XAttribute("InheritRDGatewayUsageMethod", falseString)); + element.Add(new XAttribute("InheritRDGatewayHostname", falseString)); + element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", falseString)); + element.Add(new XAttribute("InheritRDGatewayUsername", falseString)); + element.Add(new XAttribute("InheritRDGatewayPassword", falseString)); + element.Add(new XAttribute("InheritRDGatewayDomain", falseString)); + } + } + } +} \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsDeserializer.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs similarity index 86% rename from mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsDeserializer.cs rename to mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs index 7a69077fa..bb590cef0 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsDeserializer.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs @@ -19,9 +19,9 @@ using mRemoteNG.Tree.Root; using mRemoteNG.UI.Forms; using mRemoteNG.UI.TaskDialog; -namespace mRemoteNG.Config.Serializers +namespace mRemoteNG.Config.Serializers.Xml { - public class XmlConnectionsDeserializer : IDeserializer + public class XmlConnectionsDeserializer : IDeserializer { private XmlDocument _xmlDocument; private double _confVersion; @@ -30,9 +30,9 @@ namespace mRemoteNG.Config.Serializers private const double MaxSupportedConfVersion = 2.8; private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection); - public Func AuthenticationRequestor { get; set; } + public Func> AuthenticationRequestor { get; set; } - public XmlConnectionsDeserializer(Func authenticationRequestor = null) + public XmlConnectionsDeserializer(Func> authenticationRequestor = null) { AuthenticationRequestor = authenticationRequestor; } @@ -48,8 +48,6 @@ namespace mRemoteNG.Config.Serializers { LoadXmlConnectionData(xml); ValidateConnectionFileVersion(); - if (!import) - Runtime.ConnectionsService.IsConnectionsFileLoaded = false; var rootXmlElement = _xmlDocument.DocumentElement; InitializeRootNode(rootXmlElement); @@ -63,15 +61,14 @@ namespace mRemoteNG.Config.Serializers 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; } } if (_confVersion >= 2.6) { - if (rootXmlElement?.Attributes["FullFileEncryption"].Value == "True") + var fullFileEncryptionValue = rootXmlElement?.Attributes["FullFileEncryption"].Value ?? ""; + if (bool.Parse(fullFileEncryptionValue)) { var decryptedContent = _decryptor.Decrypt(rootXmlElement.InnerText); rootXmlElement.InnerXml = decryptedContent; @@ -143,10 +140,10 @@ namespace mRemoteNG.Config.Serializers if (_confVersion >= 2.6) { BlockCipherEngines engine; - Enum.TryParse(connectionsRootElement?.Attributes["EncryptionEngine"].Value, out engine); + Enum.TryParse(connectionsRootElement?.Attributes["EncryptionEngine"].Value, true, out engine); BlockCipherModes mode; - Enum.TryParse(connectionsRootElement?.Attributes["BlockCipherMode"].Value, out mode); + Enum.TryParse(connectionsRootElement?.Attributes["BlockCipherMode"].Value, true, out mode); int keyDerivationIterations; int.TryParse(connectionsRootElement?.Attributes["KdfIterations"].Value, out keyDerivationIterations); @@ -186,7 +183,10 @@ namespace mRemoteNG.Config.Serializers if (_confVersion >= 0.9) containerInfo.CopyFrom(GetConnectionInfoFromXml(xmlNode)); if (_confVersion >= 0.8) - containerInfo.IsExpanded = xmlNode.Attributes?["Expanded"].Value == "True"; + { + var expandedValue = xmlNode.Attributes?["Expanded"].Value ?? ""; + containerInfo.IsExpanded = bool.Parse(expandedValue); + } parentContainer.AddChild(containerInfo); AddNodesFromXmlRecursive(xmlNode, containerInfo); @@ -204,7 +204,11 @@ namespace mRemoteNG.Config.Serializers private ConnectionInfo GetConnectionInfoFromXml(XmlNode xmlnode) { if (xmlnode.Attributes == null) return null; - var connectionInfo = new ConnectionInfo(); + + var connectionId = xmlnode.Attributes["Id"]?.Value; + if (string.IsNullOrWhiteSpace(connectionId)) + connectionId = Guid.NewGuid().ToString(); + var connectionInfo = new ConnectionInfo(connectionId); try { @@ -219,7 +223,9 @@ namespace mRemoteNG.Config.Serializers if (_confVersion < 1.1) //1.0 - 0.1 { - connectionInfo.Resolution = Convert.ToBoolean(xmlnode.Attributes["Fullscreen"].Value) ? RdpProtocol.RDPResolutions.Fullscreen : RdpProtocol.RDPResolutions.FitToWindow; + connectionInfo.Resolution = Convert.ToBoolean(xmlnode.Attributes["Fullscreen"].Value) + ? RdpProtocol.RDPResolutions.Fullscreen + : RdpProtocol.RDPResolutions.FitToWindow; } if (_confVersion <= 2.6) // 0.2 - 2.6 @@ -257,7 +263,9 @@ namespace mRemoteNG.Config.Serializers { if (_confVersion < 0.7) { - connectionInfo.Port = Convert.ToInt32(Convert.ToBoolean(xmlnode.Attributes["UseVNC"].Value) ? xmlnode.Attributes["VNCPort"].Value : xmlnode.Attributes["RDPPort"].Value); + connectionInfo.Port = Convert.ToInt32(Convert.ToBoolean(xmlnode.Attributes["UseVNC"].Value) + ? xmlnode.Attributes["VNCPort"].Value + : xmlnode.Attributes["RDPPort"].Value); } connectionInfo.UseConsoleSession = bool.Parse(xmlnode.Attributes["ConnectToConsole"].Value); @@ -277,21 +285,23 @@ namespace mRemoteNG.Config.Serializers if (_confVersion >= 0.5) { connectionInfo.RedirectDiskDrives = bool.Parse(xmlnode.Attributes["RedirectDiskDrives"].Value); - connectionInfo.RedirectPrinters = bool.Parse(xmlnode.Attributes["RedirectPrinters"].Value); + connectionInfo.RedirectPrinters = bool.Parse(xmlnode.Attributes["RedirectPrinters"].Value); connectionInfo.RedirectPorts = bool.Parse(xmlnode.Attributes["RedirectPorts"].Value); connectionInfo.RedirectSmartCards = bool.Parse(xmlnode.Attributes["RedirectSmartCards"].Value); } else { connectionInfo.RedirectDiskDrives = false; - connectionInfo.RedirectPrinters = false; + connectionInfo.RedirectPrinters = false; connectionInfo.RedirectPorts = false; connectionInfo.RedirectSmartCards = false; } if (_confVersion >= 0.7) { - connectionInfo.Protocol = (ProtocolType)MiscTools.StringToEnum(typeof(ProtocolType), xmlnode.Attributes["Protocol"].Value); + ProtocolType protocolType; + Enum.TryParse(xmlnode.Attributes["Protocol"].Value, true, out protocolType); + connectionInfo.Protocol = protocolType; connectionInfo.Port = Convert.ToInt32(xmlnode.Attributes["Port"].Value); } @@ -307,9 +317,9 @@ namespace mRemoteNG.Config.Serializers if (_confVersion >= 1.3) { - connectionInfo.Colors = (RdpProtocol.RDPColors)MiscTools.StringToEnum(typeof(RdpProtocol.RDPColors), xmlnode.Attributes["Colors"].Value); - connectionInfo.Resolution = (RdpProtocol.RDPResolutions)MiscTools.StringToEnum(typeof(RdpProtocol.RDPResolutions), Convert.ToString(xmlnode.Attributes["Resolution"].Value)); - connectionInfo.RedirectSound = (RdpProtocol.RDPSounds)MiscTools.StringToEnum(typeof(RdpProtocol.RDPSounds), Convert.ToString(xmlnode.Attributes["RedirectSound"].Value)); + connectionInfo.Colors = (RdpProtocol.RDPColors)Enum.Parse(typeof(RdpProtocol.RDPColors), xmlnode.Attributes["Colors"].Value, true); + connectionInfo.Resolution = (RdpProtocol.RDPResolutions)Enum.Parse(typeof(RdpProtocol.RDPResolutions), xmlnode.Attributes["Resolution"].Value, true); + connectionInfo.RedirectSound = (RdpProtocol.RDPSounds)Enum.Parse(typeof(RdpProtocol.RDPSounds), xmlnode.Attributes["RedirectSound"].Value, true); } else { @@ -385,7 +395,7 @@ namespace mRemoteNG.Config.Serializers if (_confVersion >= 1.6) { - connectionInfo.ICAEncryptionStrength = (IcaProtocol.EncryptionStrength)MiscTools.StringToEnum(typeof(IcaProtocol.EncryptionStrength), xmlnode.Attributes["ICAEncryptionStrength"].Value); + connectionInfo.ICAEncryptionStrength = (IcaProtocol.EncryptionStrength)Enum.Parse(typeof(IcaProtocol.EncryptionStrength), xmlnode.Attributes["ICAEncryptionStrength"].Value, true); connectionInfo.Inheritance.ICAEncryptionStrength = bool.Parse(xmlnode.Attributes["InheritICAEncryptionStrength"].Value); connectionInfo.PreExtApp = xmlnode.Attributes["PreExtApp"].Value; connectionInfo.PostExtApp = xmlnode.Attributes["PostExtApp"].Value; @@ -395,16 +405,16 @@ namespace mRemoteNG.Config.Serializers if (_confVersion >= 1.7) { - connectionInfo.VNCCompression = (ProtocolVNC.Compression)MiscTools.StringToEnum(typeof(ProtocolVNC.Compression), xmlnode.Attributes["VNCCompression"].Value); - connectionInfo.VNCEncoding = (ProtocolVNC.Encoding)MiscTools.StringToEnum(typeof(ProtocolVNC.Encoding), Convert.ToString(xmlnode.Attributes["VNCEncoding"].Value)); - connectionInfo.VNCAuthMode = (ProtocolVNC.AuthMode)MiscTools.StringToEnum(typeof(ProtocolVNC.AuthMode), xmlnode.Attributes["VNCAuthMode"].Value); - connectionInfo.VNCProxyType = (ProtocolVNC.ProxyType)MiscTools.StringToEnum(typeof(ProtocolVNC.ProxyType), xmlnode.Attributes["VNCProxyType"].Value); + connectionInfo.VNCCompression = (ProtocolVNC.Compression)Enum.Parse(typeof(ProtocolVNC.Compression), xmlnode.Attributes["VNCCompression"].Value, true); + connectionInfo.VNCEncoding = (ProtocolVNC.Encoding)Enum.Parse(typeof(ProtocolVNC.Encoding), xmlnode.Attributes["VNCEncoding"].Value, true); + connectionInfo.VNCAuthMode = (ProtocolVNC.AuthMode)Enum.Parse(typeof(ProtocolVNC.AuthMode), xmlnode.Attributes["VNCAuthMode"].Value, true); + connectionInfo.VNCProxyType = (ProtocolVNC.ProxyType)Enum.Parse(typeof(ProtocolVNC.ProxyType), xmlnode.Attributes["VNCProxyType"].Value, true); connectionInfo.VNCProxyIP = xmlnode.Attributes["VNCProxyIP"].Value; connectionInfo.VNCProxyPort = Convert.ToInt32(xmlnode.Attributes["VNCProxyPort"].Value); connectionInfo.VNCProxyUsername = xmlnode.Attributes["VNCProxyUsername"].Value; connectionInfo.VNCProxyPassword = _decryptor.Decrypt(xmlnode.Attributes["VNCProxyPassword"].Value); - connectionInfo.VNCColors = (ProtocolVNC.Colors)MiscTools.StringToEnum(typeof(ProtocolVNC.Colors), xmlnode.Attributes["VNCColors"].Value); - connectionInfo.VNCSmartSizeMode = (ProtocolVNC.SmartSizeMode)MiscTools.StringToEnum(typeof(ProtocolVNC.SmartSizeMode), xmlnode.Attributes["VNCSmartSizeMode"].Value); + connectionInfo.VNCColors = (ProtocolVNC.Colors)Enum.Parse(typeof(ProtocolVNC.Colors), xmlnode.Attributes["VNCColors"].Value, true); + connectionInfo.VNCSmartSizeMode = (ProtocolVNC.SmartSizeMode)Enum.Parse(typeof(ProtocolVNC.SmartSizeMode), xmlnode.Attributes["VNCSmartSizeMode"].Value, true); connectionInfo.VNCViewOnly = bool.Parse(xmlnode.Attributes["VNCViewOnly"].Value); connectionInfo.Inheritance.VNCCompression = bool.Parse(xmlnode.Attributes["InheritVNCCompression"].Value); connectionInfo.Inheritance.VNCEncoding = bool.Parse(xmlnode.Attributes["InheritVNCEncoding"].Value); @@ -421,13 +431,13 @@ namespace mRemoteNG.Config.Serializers if (_confVersion >= 1.8) { - connectionInfo.RDPAuthenticationLevel = (RdpProtocol.AuthenticationLevel)MiscTools.StringToEnum(typeof(RdpProtocol.AuthenticationLevel), xmlnode.Attributes["RDPAuthenticationLevel"].Value); + connectionInfo.RDPAuthenticationLevel = (RdpProtocol.AuthenticationLevel)Enum.Parse(typeof(RdpProtocol.AuthenticationLevel), xmlnode.Attributes["RDPAuthenticationLevel"].Value, true); connectionInfo.Inheritance.RDPAuthenticationLevel = bool.Parse(xmlnode.Attributes["InheritRDPAuthenticationLevel"].Value); } if (_confVersion >= 1.9) { - connectionInfo.RenderingEngine = (HTTPBase.RenderingEngine)MiscTools.StringToEnum(typeof(HTTPBase.RenderingEngine), xmlnode.Attributes["RenderingEngine"].Value); + connectionInfo.RenderingEngine = (HTTPBase.RenderingEngine)Enum.Parse(typeof(HTTPBase.RenderingEngine), xmlnode.Attributes["RenderingEngine"].Value, true); connectionInfo.MacAddress = xmlnode.Attributes["MacAddress"].Value; connectionInfo.Inheritance.RenderingEngine = bool.Parse(xmlnode.Attributes["InheritRenderingEngine"].Value); connectionInfo.Inheritance.MacAddress = bool.Parse(xmlnode.Attributes["InheritMacAddress"].Value); @@ -448,9 +458,9 @@ namespace mRemoteNG.Config.Serializers if (_confVersion >= 2.2) { // Get settings - connectionInfo.RDGatewayUsageMethod = (RdpProtocol.RDGatewayUsageMethod)MiscTools.StringToEnum(typeof(RdpProtocol.RDGatewayUsageMethod), Convert.ToString(xmlnode.Attributes["RDGatewayUsageMethod"].Value)); + connectionInfo.RDGatewayUsageMethod = (RdpProtocol.RDGatewayUsageMethod)Enum.Parse(typeof(RdpProtocol.RDGatewayUsageMethod), xmlnode.Attributes["RDGatewayUsageMethod"].Value, true); connectionInfo.RDGatewayHostname = xmlnode.Attributes["RDGatewayHostname"].Value; - connectionInfo.RDGatewayUseConnectionCredentials = (RdpProtocol.RDGatewayUseConnectionCredentials)MiscTools.StringToEnum(typeof(RdpProtocol.RDGatewayUseConnectionCredentials), Convert.ToString(xmlnode.Attributes["RDGatewayUseConnectionCredentials"].Value)); + connectionInfo.RDGatewayUseConnectionCredentials = (RdpProtocol.RDGatewayUseConnectionCredentials)Enum.Parse(typeof(RdpProtocol.RDGatewayUseConnectionCredentials), xmlnode.Attributes["RDGatewayUseConnectionCredentials"].Value, true); connectionInfo.RDGatewayUsername = xmlnode.Attributes["RDGatewayUsername"].Value; connectionInfo.RDGatewayPassword = _decryptor.Decrypt(Convert.ToString(xmlnode.Attributes["RDGatewayPassword"].Value)); connectionInfo.RDGatewayDomain = xmlnode.Attributes["RDGatewayDomain"].Value; @@ -491,14 +501,18 @@ namespace mRemoteNG.Config.Serializers if (_confVersion >= 2.6) { - connectionInfo.ConstantID = xmlnode.Attributes["Id"]?.Value ?? connectionInfo.ConstantID; - connectionInfo.SoundQuality = (RdpProtocol.RDPSoundQuality)MiscTools.StringToEnum(typeof(RdpProtocol.RDPSoundQuality), Convert.ToString(xmlnode.Attributes["SoundQuality"].Value)); + connectionInfo.SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), xmlnode.Attributes["SoundQuality"].Value, true); connectionInfo.Inheritance.SoundQuality = bool.Parse(xmlnode.Attributes["InheritSoundQuality"].Value); connectionInfo.RDPMinutesToIdleTimeout = Convert.ToInt32(xmlnode.Attributes["RDPMinutesToIdleTimeout"]?.Value ?? "0"); connectionInfo.Inheritance.RDPMinutesToIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPMinutesToIdleTimeout"]?.Value ?? "False"); connectionInfo.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["RDPAlertIdleTimeout"]?.Value ?? "False"); connectionInfo.Inheritance.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPAlertIdleTimeout"]?.Value ?? "False"); } + if(_confVersion >= 2.7) + { + connectionInfo.RedirectClipboard = bool.Parse(xmlnode.Attributes["RedirectClipboard"].Value); + connectionInfo.Inheritance.RedirectClipboard = bool.Parse(xmlnode.Attributes["InheritRedirectClipboard"].Value); + } } catch (Exception ex) { diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentCompiler.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentCompiler.cs similarity index 98% rename from mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentCompiler.cs rename to mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentCompiler.cs index d640d49d5..28fe8d747 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentCompiler.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentCompiler.cs @@ -8,8 +8,7 @@ using mRemoteNG.Security; using mRemoteNG.Tree; using mRemoteNG.Tree.Root; - -namespace mRemoteNG.Config.Serializers +namespace mRemoteNG.Config.Serializers.Xml { public class XmlConnectionsDocumentCompiler { diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentEncryptor.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentEncryptor.cs similarity index 97% rename from mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentEncryptor.cs rename to mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentEncryptor.cs index f4de60883..62f3d6413 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsDocumentEncryptor.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDocumentEncryptor.cs @@ -2,8 +2,7 @@ using System.Xml.Linq; using mRemoteNG.Security; - -namespace mRemoteNG.Config.Serializers +namespace mRemoteNG.Config.Serializers.Xml { public class XmlConnectionsDocumentEncryptor { diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsSerializer.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializer.cs similarity index 98% rename from mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsSerializer.cs rename to mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializer.cs index 80298edc3..94d9c7c16 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlConnectionsSerializer.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializer.cs @@ -10,7 +10,7 @@ using mRemoteNG.Security; using mRemoteNG.Tree; using mRemoteNG.Tree.Root; -namespace mRemoteNG.Config.Serializers +namespace mRemoteNG.Config.Serializers.Xml { public class XmlConnectionsSerializer : ISerializer, ISerializer { diff --git a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlRootNodeSerializer.cs b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlRootNodeSerializer.cs similarity index 72% rename from mRemoteV1/Config/Serializers/ConnectionSerializers/XmlRootNodeSerializer.cs rename to mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlRootNodeSerializer.cs index 84e2dde8f..de69ba12e 100644 --- a/mRemoteV1/Config/Serializers/ConnectionSerializers/XmlRootNodeSerializer.cs +++ b/mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlRootNodeSerializer.cs @@ -2,19 +2,21 @@ using mRemoteNG.Security; using mRemoteNG.Tree.Root; - -namespace mRemoteNG.Config.Serializers +namespace mRemoteNG.Config.Serializers.Xml { - public class XmlRootNodeSerializer + public class XmlRootNodeSerializer { public XElement SerializeRootNodeInfo(RootNodeInfo rootNodeInfo, ICryptographyProvider cryptographyProvider, bool fullFileEncryption = false) { - var element = new XElement("Connections"); + XNamespace xmlNamespace = "http://mremoteng.org"; + var element = new XElement(xmlNamespace + "Connections"); + element.Add(new XAttribute(XNamespace.Xmlns+"mrng", xmlNamespace)); element.Add(new XAttribute(XName.Get("Name"), rootNodeInfo.Name)); - element.Add(new XAttribute(XName.Get("EncryptionEngine"), cryptographyProvider.CipherEngine)); + element.Add(new XAttribute(XName.Get("Export"), "false")); + element.Add(new XAttribute(XName.Get("EncryptionEngine"), cryptographyProvider.CipherEngine)); element.Add(new XAttribute(XName.Get("BlockCipherMode"), cryptographyProvider.CipherMode)); element.Add(new XAttribute(XName.Get("KdfIterations"), cryptographyProvider.KeyDerivationIterations)); - element.Add(new XAttribute(XName.Get("FullFileEncryption"), fullFileEncryption.ToString())); + element.Add(new XAttribute(XName.Get("FullFileEncryption"), fullFileEncryption.ToString().ToLowerInvariant())); element.Add(CreateProtectedAttribute(rootNodeInfo, cryptographyProvider)); element.Add(new XAttribute(XName.Get("ConfVersion"), "2.6")); return element; diff --git a/mRemoteV1/Config/Serializers/DataTableDeserializer.cs b/mRemoteV1/Config/Serializers/DataTableDeserializer.cs index c7c220b01..52f358773 100644 --- a/mRemoteV1/Config/Serializers/DataTableDeserializer.cs +++ b/mRemoteV1/Config/Serializers/DataTableDeserializer.cs @@ -15,7 +15,7 @@ using mRemoteNG.Tree.Root; namespace mRemoteNG.Config.Serializers { - public class DataTableDeserializer : IDeserializer + public class DataTableDeserializer : IDeserializer { public ConnectionTreeModel Deserialize(DataTable table) { @@ -46,14 +46,16 @@ namespace mRemoteNG.Config.Serializers private ConnectionInfo DeserializeConnectionInfo(DataRow row) { - var connectionInfo = new ConnectionInfo(); + var connectionId = row["ConstantID"] as string ?? Guid.NewGuid().ToString(); + var connectionInfo = new ConnectionInfo(connectionId); PopulateConnectionInfoFromDatarow(row, connectionInfo); return connectionInfo; } private ContainerInfo DeserializeContainerInfo(DataRow row) { - var containerInfo = new ContainerInfo(); + var containerId = row["ConstantID"] as string ?? Guid.NewGuid().ToString(); + var containerInfo = new ContainerInfo(containerId); PopulateConnectionInfoFromDatarow(row, containerInfo); return containerInfo; } @@ -61,7 +63,6 @@ namespace mRemoteNG.Config.Serializers private void PopulateConnectionInfoFromDatarow(DataRow dataRow, ConnectionInfo connectionInfo) { connectionInfo.Name = (string)dataRow["Name"]; - connectionInfo.ConstantID = (string)dataRow["ConstantID"]; // This throws a NPE - Parent is a connectionInfo object which will be null at this point. // The Parent object is linked properly later in CreateNodeHierarchy() @@ -100,6 +101,7 @@ namespace mRemoteNG.Config.Serializers connectionInfo.RedirectDiskDrives = (bool)dataRow["RedirectDiskDrives"]; connectionInfo.RedirectPorts = (bool)dataRow["RedirectPorts"]; connectionInfo.RedirectPrinters = (bool)dataRow["RedirectPrinters"]; + connectionInfo.RedirectClipboard = (bool)dataRow["RedirectClipboard"]; connectionInfo.RedirectSmartCards = (bool)dataRow["RedirectSmartCards"]; connectionInfo.RedirectSound = (RdpProtocol.RDPSounds)Enum.Parse(typeof(RdpProtocol.RDPSounds), (string)dataRow["RedirectSound"]); connectionInfo.SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), (string)dataRow["SoundQuality"]); @@ -146,6 +148,7 @@ namespace mRemoteNG.Config.Serializers connectionInfo.Inheritance.RedirectKeys = (bool)dataRow["InheritRedirectKeys"]; connectionInfo.Inheritance.RedirectPorts = (bool)dataRow["InheritRedirectPorts"]; connectionInfo.Inheritance.RedirectPrinters = (bool)dataRow["InheritRedirectPrinters"]; + connectionInfo.Inheritance.RedirectClipboard = (bool)dataRow["InheritRedirectClipboard"]; connectionInfo.Inheritance.RedirectSmartCards = (bool)dataRow["InheritRedirectSmartCards"]; connectionInfo.Inheritance.RedirectSound = (bool)dataRow["InheritRedirectSound"]; connectionInfo.Inheritance.SoundQuality = (bool)dataRow["InheritSoundQuality"]; @@ -187,7 +190,7 @@ namespace mRemoteNG.Config.Serializers private ConnectionTreeModel CreateNodeHierarchy(List connectionList, DataTable dataTable) { var connectionTreeModel = new ConnectionTreeModel(); - var rootNode = new RootNodeInfo(RootNodeType.Connection) {ConstantID = "0"}; + var rootNode = new RootNodeInfo(RootNodeType.Connection, "0"); connectionTreeModel.AddRootNode(rootNode); foreach (DataRow row in dataTable.Rows) diff --git a/mRemoteV1/Config/Serializers/DataTableSerializer.cs b/mRemoteV1/Config/Serializers/DataTableSerializer.cs index db43749c1..05fd2ba86 100644 --- a/mRemoteV1/Config/Serializers/DataTableSerializer.cs +++ b/mRemoteV1/Config/Serializers/DataTableSerializer.cs @@ -91,6 +91,7 @@ namespace mRemoteNG.Config.Serializers dataTable.Columns.Add("RedirectDiskDrives", typeof(bool)); dataTable.Columns.Add("RedirectPorts", typeof(bool)); dataTable.Columns.Add("RedirectPrinters", typeof(bool)); + dataTable.Columns.Add("RedirectClipboard", typeof(bool)); dataTable.Columns.Add("RedirectSmartCards", typeof(bool)); dataTable.Columns.Add("RedirectSound", typeof(string)); dataTable.Columns.Add("RedirectKeys", typeof(bool)); @@ -135,6 +136,7 @@ namespace mRemoteNG.Config.Serializers dataTable.Columns.Add("InheritRedirectKeys", typeof(bool)); dataTable.Columns.Add("InheritRedirectPorts", typeof(bool)); dataTable.Columns.Add("InheritRedirectPrinters", typeof(bool)); + dataTable.Columns.Add("InheritRedirectClipboard", typeof(bool)); dataTable.Columns.Add("InheritRedirectSmartCards", typeof(bool)); dataTable.Columns.Add("InheritRedirectSound", typeof(bool)); dataTable.Columns.Add("InheritResolution", typeof(bool)); @@ -235,6 +237,7 @@ namespace mRemoteNG.Config.Serializers dataRow["RedirectDiskDrives"] = connectionInfo.RedirectDiskDrives; dataRow["RedirectPorts"] = connectionInfo.RedirectPorts; dataRow["RedirectPrinters"] = connectionInfo.RedirectPrinters; + dataRow["RedirectClipboard"] = connectionInfo.RedirectClipboard; dataRow["RedirectSmartCards"] = connectionInfo.RedirectSmartCards; dataRow["RedirectSound"] = connectionInfo.RedirectSound; dataRow["SoundQuality"] = connectionInfo.SoundQuality; @@ -282,6 +285,7 @@ namespace mRemoteNG.Config.Serializers dataRow["InheritRedirectKeys"] = connectionInfo.Inheritance.RedirectKeys; dataRow["InheritRedirectPorts"] = connectionInfo.Inheritance.RedirectPorts; dataRow["InheritRedirectPrinters"] = connectionInfo.Inheritance.RedirectPrinters; + dataRow["InheritRedirectClipboard"] = connectionInfo.Inheritance.RedirectClipboard; dataRow["InheritRedirectSmartCards"] = connectionInfo.Inheritance.RedirectSmartCards; dataRow["InheritRedirectSound"] = connectionInfo.Inheritance.RedirectSound; dataRow["InheritSoundQuality"] = connectionInfo.Inheritance.SoundQuality; @@ -339,6 +343,7 @@ namespace mRemoteNG.Config.Serializers dataRow["InheritRedirectKeys"] = false; dataRow["InheritRedirectPorts"] = false; dataRow["InheritRedirectPrinters"] = false; + dataRow["InheritRedirectClipboard"] = false; dataRow["InheritRedirectSmartCards"] = false; dataRow["InheritRedirectSound"] = false; dataRow["InheritSoundQuality"] = false; diff --git a/mRemoteV1/Config/Serializers/MiscSerializers/ActiveDirectoryDeserializer.cs b/mRemoteV1/Config/Serializers/MiscSerializers/ActiveDirectoryDeserializer.cs index c8c168943..d9789f0fa 100644 --- a/mRemoteV1/Config/Serializers/MiscSerializers/ActiveDirectoryDeserializer.cs +++ b/mRemoteV1/Config/Serializers/MiscSerializers/ActiveDirectoryDeserializer.cs @@ -5,6 +5,7 @@ using mRemoteNG.App; using mRemoteNG.Config.Import; using mRemoteNG.Connection; using mRemoteNG.Container; +using mRemoteNG.Tools; using mRemoteNG.Tree; using mRemoteNG.Tree.Root; @@ -14,12 +15,12 @@ namespace mRemoteNG.Config.Serializers public class ActiveDirectoryDeserializer { private readonly string _ldapPath; - private readonly bool _importSubOU; + private readonly bool _importSubOu; - public ActiveDirectoryDeserializer(string ldapPath, bool importSubOU) + public ActiveDirectoryDeserializer(string ldapPath, bool importSubOu) { - _ldapPath = ldapPath; - _importSubOU = importSubOU; + _ldapPath = ldapPath.ThrowIfNullOrEmpty(nameof(ldapPath)); + _importSubOu = importSubOu; } public ConnectionTreeModel Deserialize() @@ -64,9 +65,10 @@ namespace mRemoteNG.Config.Serializers if (directoryEntry.Properties["objectClass"].Contains("organizationalUnit")) { // check/continue here so we don't create empty connection objects - if(!_importSubOU) continue; + if(!_importSubOu) continue; - ActiveDirectoryImporter.Import(ldapResult.Path, parentContainer, _importSubOU); + // TODO - this is a circular call. A deserializer should not call an importer + ActiveDirectoryImporter.Import(ldapResult.Path, parentContainer, _importSubOu); continue; } diff --git a/mRemoteV1/Config/Serializers/MiscSerializers/CsvConnectionsSerializerMremotengFormat.cs b/mRemoteV1/Config/Serializers/MiscSerializers/CsvConnectionsSerializerMremotengFormat.cs deleted file mode 100644 index f42b2758e..000000000 --- a/mRemoteV1/Config/Serializers/MiscSerializers/CsvConnectionsSerializerMremotengFormat.cs +++ /dev/null @@ -1,221 +0,0 @@ -using System; -using System.Linq; -using mRemoteNG.Connection; -using mRemoteNG.Container; -using mRemoteNG.Credential; -using mRemoteNG.Security; -using mRemoteNG.Tree; -using mRemoteNG.Tree.Root; - -namespace mRemoteNG.Config.Serializers -{ - public class CsvConnectionsSerializerMremotengFormat : ISerializer - { - private string _csv = ""; - private ConnectionInfo _serializationTarget; - private readonly SaveFilter _saveFilter; - private readonly ICredentialRepositoryList _credentialRepositoryList; - - - public CsvConnectionsSerializerMremotengFormat(SaveFilter saveFilter, ICredentialRepositoryList credentialRepositoryList) - { - if (saveFilter == null) - throw new ArgumentNullException(nameof(saveFilter)); - if (credentialRepositoryList == null) - throw new ArgumentNullException(nameof(credentialRepositoryList)); - - _saveFilter = saveFilter; - _credentialRepositoryList = credentialRepositoryList; - } - - public string Serialize(ConnectionTreeModel connectionTreeModel) - { - if (connectionTreeModel == null) - throw new ArgumentNullException(nameof(connectionTreeModel)); - - var rootNode = connectionTreeModel.RootNodes.First(node => node is RootNodeInfo); - return Serialize(rootNode); - } - - public string Serialize(ConnectionInfo serializationTarget) - { - if (serializationTarget == null) - throw new ArgumentNullException(nameof(serializationTarget)); - - _csv = ""; - _serializationTarget = serializationTarget; - WriteCsvHeader(); - SerializeNodesRecursive(serializationTarget); - return _csv; - } - - private void WriteCsvHeader() - { - var csvHeader = string.Empty; - csvHeader += "Name;Folder;Description;Icon;Panel;"; - if (_saveFilter.SaveUsername) - csvHeader += "Username;"; - if (_saveFilter.SavePassword) - csvHeader += "Password;"; - if (_saveFilter.SaveDomain) - csvHeader += "Domain;"; - csvHeader += "Hostname;Protocol;PuttySession;Port;ConnectToConsole;UseCredSsp;RenderingEngine;ICAEncryptionStrength;RDPAuthenticationLevel;LoadBalanceInfo;Colors;Resolution;AutomaticResize;DisplayWallpaper;DisplayThemes;EnableFontSmoothing;EnableDesktopComposition;CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectSmartCards;RedirectSound;RedirectKeys;PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;VNCProxyPort;VNCProxyUsername;VNCProxyPassword;VNCColors;VNCSmartSizeMode;VNCViewOnly;RDGatewayUsageMethod;RDGatewayHostname;RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;"; - if (_saveFilter.SaveInheritance) - csvHeader += "InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;InheritEnableFontSmoothing;InheritEnableDesktopComposition;InheritDomain;InheritIcon;InheritPanel;InheritPassword;InheritPort;InheritProtocol;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;InheritRedirectSmartCards;InheritRedirectSound;InheritResolution;InheritAutomaticResize;InheritUseConsoleSession;InheritUseCredSsp;InheritRenderingEngine;InheritUsername;InheritICAEncryptionStrength;InheritRDPAuthenticationLevel;InheritLoadBalanceInfo;InheritPreExtApp;InheritPostExtApp;InheritMacAddress;InheritUserField;InheritExtApp;InheritVNCCompression;InheritVNCEncoding;InheritVNCAuthMode;InheritVNCProxyType;InheritVNCProxyIP;InheritVNCProxyPort;InheritVNCProxyUsername;InheritVNCProxyPassword;InheritVNCColors;InheritVNCSmartSizeMode;InheritVNCViewOnly;InheritRDGatewayUsageMethod;InheritRDGatewayHostname;InheritRDGatewayUseConnectionCredentials;InheritRDGatewayUsername;InheritRDGatewayPassword;InheritRDGatewayDomain"; - _csv += csvHeader; - } - - private void SerializeNodesRecursive(ConnectionInfo node) - { - var nodeAsContainer = node as ContainerInfo; - if (nodeAsContainer != null) - { - foreach (var child in nodeAsContainer.Children) - { - var info = child as ContainerInfo; - if (info != null) - SerializeNodesRecursive(info); - else - SerializeConnectionInfo(child); - } - } - else - SerializeConnectionInfo(node); - } - - private void SerializeConnectionInfo(ConnectionInfo con) - { - var csvLine = Environment.NewLine; - - csvLine += con.Name + ";" + GetNodePath(con) + ";" + con.Description + ";" + con.Icon + ";" + con.Panel + ";"; - - if (_saveFilter.SaveUsername) - csvLine += con.Username + ";"; - - if (_saveFilter.SavePassword) - csvLine += con.Password + ";"; - - if (_saveFilter.SaveDomain) - csvLine += con.Domain + ";"; - - csvLine += con.Hostname + ";" + - con.Protocol + ";" + - con.PuttySession + ";" + - Convert.ToString(con.Port) + ";" + - Convert.ToString(con.UseConsoleSession) + ";" + - Convert.ToString(con.UseCredSsp) + ";" + - con.RenderingEngine + ";" + - con.ICAEncryptionStrength + ";" + - con.RDPAuthenticationLevel + ";" + - con.LoadBalanceInfo + ";" + - con.Colors + ";" + - con.Resolution + ";" + - Convert.ToString(con.AutomaticResize) + ";" + - Convert.ToString(con.DisplayWallpaper) + ";" + - Convert.ToString(con.DisplayThemes) + ";" + - Convert.ToString(con.EnableFontSmoothing) + ";" + - Convert.ToString(con.EnableDesktopComposition) + ";" + - Convert.ToString(con.CacheBitmaps) + ";" + - Convert.ToString(con.RedirectDiskDrives) + ";" + - Convert.ToString(con.RedirectPorts) + ";" + - Convert.ToString(con.RedirectPrinters) + ";" + - Convert.ToString(con.RedirectSmartCards) + ";" + - con.RedirectSound + ";" + - Convert.ToString(con.RedirectKeys) + ";" + - con.PreExtApp + ";" + - con.PostExtApp + ";" + - con.MacAddress + ";" + - con.UserField + ";" + - con.ExtApp + ";" + - con.VNCCompression + ";" + - con.VNCEncoding + ";" + - con.VNCAuthMode + ";" + - con.VNCProxyType + ";" + - con.VNCProxyIP + ";" + - Convert.ToString(con.VNCProxyPort) + ";" + - con.VNCProxyUsername + ";" + - con.VNCProxyPassword + ";" + - con.VNCColors + ";" + - con.VNCSmartSizeMode + ";" + - Convert.ToString(con.VNCViewOnly) + ";" + - con.RDGatewayUsageMethod + ";" + - con.RDGatewayHostname + ";" + - con.RDGatewayUseConnectionCredentials + ";" + - con.RDGatewayUsername + ";" + - con.RDGatewayPassword + ";" + - con.RDGatewayDomain + ";"; - - - if (_saveFilter.SaveInheritance) - { - csvLine += con.Inheritance.CacheBitmaps + ";" + - con.Inheritance.Colors + ";" + - con.Inheritance.Description + ";" + - con.Inheritance.DisplayThemes + ";" + - con.Inheritance.DisplayWallpaper + ";" + - con.Inheritance.EnableFontSmoothing + ";" + - con.Inheritance.EnableDesktopComposition + ";" + - con.Inheritance.Domain + ";" + - con.Inheritance.Icon + ";" + - con.Inheritance.Panel + ";" + - con.Inheritance.Password + ";" + - con.Inheritance.Port + ";" + - con.Inheritance.Protocol + ";" + - con.Inheritance.PuttySession + ";" + - con.Inheritance.RedirectDiskDrives + ";" + - con.Inheritance.RedirectKeys + ";" + - con.Inheritance.RedirectPorts + ";" + - con.Inheritance.RedirectPrinters + ";" + - con.Inheritance.RedirectSmartCards + ";" + - con.Inheritance.RedirectSound + ";" + - con.Inheritance.Resolution + ";" + - con.Inheritance.AutomaticResize + ";" + - con.Inheritance.UseConsoleSession + ";" + - con.Inheritance.UseCredSsp + ";" + - con.Inheritance.RenderingEngine + ";" + - con.Inheritance.Username + ";" + - con.Inheritance.ICAEncryptionStrength + ";" + - con.Inheritance.RDPAuthenticationLevel + ";" + - con.Inheritance.LoadBalanceInfo + ";" + - con.Inheritance.PreExtApp + ";" + - con.Inheritance.PostExtApp + ";" + - con.Inheritance.MacAddress + ";" + - con.Inheritance.UserField + ";" + - con.Inheritance.ExtApp + ";" + - con.Inheritance.VNCCompression + ";" + - con.Inheritance.VNCEncoding + ";" + - con.Inheritance.VNCAuthMode + ";" + - con.Inheritance.VNCProxyType + ";" + - con.Inheritance.VNCProxyIP + ";" + - con.Inheritance.VNCProxyPort + ";" + - con.Inheritance.VNCProxyUsername + ";" + - con.Inheritance.VNCProxyPassword + ";" + - con.Inheritance.VNCColors + ";" + - con.Inheritance.VNCSmartSizeMode + ";" + - con.Inheritance.VNCViewOnly + - con.Inheritance.RDGatewayUsageMethod + ";" + - con.Inheritance.RDGatewayHostname + ";" + - con.Inheritance.RDGatewayUseConnectionCredentials + ";" + - con.Inheritance.RDGatewayUsername + ";" + - con.Inheritance.RDGatewayPassword + ";" + - con.Inheritance.RDGatewayDomain + ";"; - } - - _csv += csvLine; - } - - private string GetNodePath(ConnectionInfo connectionInfo) - { - var nodePath = ""; - var container = connectionInfo.Parent; - if (container == null) return nodePath; - while (container != _serializationTarget) - { - container = container.Parent; - nodePath += $@"{container.Name}\"; - } - nodePath = nodePath.TrimEnd('\\'); - return nodePath; - } - } -} \ No newline at end of file diff --git a/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs b/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs index e12065c6b..2453a948d 100644 --- a/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs +++ b/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs @@ -24,8 +24,8 @@ namespace mRemoteNG.Config.Serializers continue; } - var key = parts[0]; - var value = parts[2]; + var key = parts[0].Trim(); + var value = parts[2].Trim(); SetConnectionInfoParameter(connectionInfo, key, value); } @@ -108,6 +108,9 @@ namespace mRemoteNG.Config.Serializers case "redirectprinters": connectionInfo.RedirectPrinters = value == "1"; break; + case "redirectclipboard": + connectionInfo.RedirectClipboard = value == "1"; + break; case "audiomode": switch (value) { diff --git a/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs b/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs index 5df6a8ca6..27c2b0300 100644 --- a/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs +++ b/mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs @@ -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,11 @@ 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"); + connectionInfo.RedirectClipboard = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectClipboard")?.InnerText ?? "false"); } else { @@ -284,10 +288,11 @@ namespace mRemoteNG.Config.Serializers connectionInfo.Inheritance.RedirectPorts = true; connectionInfo.Inheritance.RedirectPrinters = true; connectionInfo.Inheritance.RedirectSmartCards = true; + connectionInfo.Inheritance.RedirectClipboard = true; } var securitySettingsNode = xmlNode.SelectSingleNode("./securitySettings"); - if (securitySettingsNode?.Attributes?["inherit"].Value == "None") + if (securitySettingsNode?.Attributes?["inherit"]?.Value == "None") { // ReSharper disable once SwitchStatementMissingSomeCases switch (securitySettingsNode.SelectSingleNode("./authentication")?.InnerText) @@ -321,7 +326,7 @@ namespace mRemoteNG.Config.Serializers private static string DecryptRdcManPassword(string ciphertext) { if (string.IsNullOrEmpty(ciphertext)) - return null; + return string.Empty; try { @@ -332,7 +337,7 @@ namespace mRemoteNG.Config.Serializers catch (Exception /*ex*/) { //Runtime.MessageCollector.AddExceptionMessage("RemoteDesktopConnectionManager.DecryptPassword() failed.", ex, logOnly: true); - return null; + return string.Empty; } } } diff --git a/mRemoteV1/Config/Serializers/XmlConnectionsDecryptor.cs b/mRemoteV1/Config/Serializers/XmlConnectionsDecryptor.cs index 45be38de1..efa0683a9 100644 --- a/mRemoteV1/Config/Serializers/XmlConnectionsDecryptor.cs +++ b/mRemoteV1/Config/Serializers/XmlConnectionsDecryptor.cs @@ -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 AuthenticationRequestor { get; set; } + public Func> 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; } } } \ No newline at end of file diff --git a/mRemoteV1/Config/Settings/Providers/ChooseProvider.cs b/mRemoteV1/Config/Settings/Providers/ChooseProvider.cs index 5edbde037..10a1a342b 100644 --- a/mRemoteV1/Config/Settings/Providers/ChooseProvider.cs +++ b/mRemoteV1/Config/Settings/Providers/ChooseProvider.cs @@ -1,4 +1,6 @@ -using System.Configuration; +#if !PORTABLE +using System.Configuration; +#endif namespace mRemoteNG.Config.Settings.Providers { diff --git a/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs b/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs index 3e42acfe7..51349b26f 100644 --- a/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs +++ b/mRemoteV1/Config/Settings/Providers/PortableSettingsProvider.cs @@ -1,37 +1,37 @@ -/// The MIT License (MIT) -/// -/// Copyright(c) crdx -/// -/// Permission is hereby granted, free of charge, to any person obtaining -/// a copy of this software and associated documentation files (the -/// "Software"), to deal in the Software without restriction, including -/// without limitation the rights to use, copy, modify, merge, publish, -/// distribute, sublicense, and/or sell copies of the Software, and to -/// permit persons to whom the Software is furnished to do so, subject to -/// the following conditions: -/// -/// The above copyright notice and this permission notice shall be -/// included in all copies or substantial portions of the Software. -/// -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -/// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -/// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -/// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -/// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -/// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -/// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -/// -/// https://raw.githubusercontent.com/crdx/PortableSettingsProvider -/// -using System.Linq; +// The MIT License (MIT) +// +// Copyright(c) crdx +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// https://raw.githubusercontent.com/crdx/PortableSettingsProvider +// + using System; using System.Collections; -using System.Collections.Generic; using System.Configuration; using System.Windows.Forms; using System.Collections.Specialized; using System.Xml; using System.IO; +//using mRemoteNG.App; namespace mRemoteNG.Config.Settings.Providers { @@ -43,63 +43,34 @@ namespace mRemoteNG.Config.Settings.Providers private const string _className = "PortableSettingsProvider"; private XmlDocument _xmlDocument; - private string _filePath - { - get - { - return Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), - string.Format("{0}.settings", ApplicationName)); - } - } + private string _filePath => Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? throw new InvalidOperationException(), $"{ApplicationName}.settings"); - private XmlNode _localSettingsNode - { - get - { - XmlNode settingsNode = GetSettingsNode(_localSettingsNodeName); - XmlNode machineNode = settingsNode.SelectSingleNode(Environment.MachineName.ToLowerInvariant()); + private XmlNode _localSettingsNode => GetSettingsNode(_localSettingsNodeName); - if (machineNode == null) - { - machineNode = _rootDocument.CreateElement(Environment.MachineName.ToLowerInvariant()); - settingsNode.AppendChild(machineNode); - } + private XmlNode _globalSettingsNode => GetSettingsNode(_globalSettingsNodeName); - return machineNode; - } - } - - private XmlNode _globalSettingsNode - { - get { return GetSettingsNode(_globalSettingsNodeName); } - } - - private XmlNode _rootNode - { - get { return _rootDocument.SelectSingleNode(_rootNodeName); } - } + private XmlNode _rootNode => _rootDocument.SelectSingleNode(_rootNodeName); private XmlDocument _rootDocument { get { - if (_xmlDocument == null) + if (_xmlDocument != null) return _xmlDocument; + try { - try - { - _xmlDocument = new XmlDocument(); - _xmlDocument.Load(_filePath); - } - catch (Exception) - { - - } - - if (_xmlDocument.SelectSingleNode(_rootNodeName) != null) - return _xmlDocument; - - _xmlDocument = GetBlankXmlDocument(); + _xmlDocument = new XmlDocument(); + _xmlDocument.Load(_filePath); } + catch (Exception /*ex*/) + { + // This casues hundreds of unit tests to fail for some reason... + //Runtime.MessageCollector.AddExceptionStackTrace("PortableSettingsProvider: Error getting XML", ex); + } + + if (_xmlDocument?.SelectSingleNode(_rootNodeName) != null) + return _xmlDocument; + + _xmlDocument = GetBlankXmlDocument(); return _xmlDocument; } @@ -107,14 +78,11 @@ namespace mRemoteNG.Config.Settings.Providers public override string ApplicationName { - get { return Path.GetFileNameWithoutExtension(Application.ExecutablePath); } + get => Path.GetFileNameWithoutExtension(Application.ExecutablePath); set { } } - public override string Name - { - get { return _className; } - } + public override string Name => _className; public override void Initialize(string name, NameValueCollection config) { @@ -143,7 +111,7 @@ namespace mRemoteNG.Config.Settings.Providers public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection) { - SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); + var values = new SettingsPropertyValueCollection(); foreach (SettingsProperty property in collection) { @@ -158,11 +126,9 @@ namespace mRemoteNG.Config.Settings.Providers private void SetValue(SettingsPropertyValue propertyValue) { - XmlNode targetNode = IsGlobal(propertyValue.Property) - ? _globalSettingsNode - : _localSettingsNode; + var targetNode = IsGlobal(propertyValue.Property) ? _globalSettingsNode : _localSettingsNode; - XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[@name='{0}']", propertyValue.Name)); + var settingNode = targetNode.SelectSingleNode($"setting[@name='{propertyValue.Name}']"); if (settingNode != null) settingNode.InnerText = propertyValue.SerializedValue.ToString(); @@ -170,10 +136,10 @@ namespace mRemoteNG.Config.Settings.Providers { settingNode = _rootDocument.CreateElement("setting"); - XmlAttribute nameAttribute = _rootDocument.CreateAttribute("name"); + var nameAttribute = _rootDocument.CreateAttribute("name"); nameAttribute.Value = propertyValue.Name; - settingNode.Attributes.Append(nameAttribute); + settingNode.Attributes?.Append(nameAttribute); settingNode.InnerText = propertyValue.SerializedValue.ToString(); targetNode.AppendChild(settingNode); @@ -182,8 +148,8 @@ namespace mRemoteNG.Config.Settings.Providers private string GetValue(SettingsProperty property) { - XmlNode targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode; - XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[@name='{0}']", property.Name)); + var targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode; + var settingNode = targetNode.SelectSingleNode($"setting[@name='{property.Name}']"); if (settingNode == null) return property.DefaultValue != null ? property.DefaultValue.ToString() : string.Empty; @@ -191,7 +157,7 @@ namespace mRemoteNG.Config.Settings.Providers return settingNode.InnerText; } - private bool IsGlobal(SettingsProperty property) + private static bool IsGlobal(SettingsProperty property) { foreach (DictionaryEntry attribute in property.Attributes) { @@ -204,20 +170,18 @@ namespace mRemoteNG.Config.Settings.Providers private XmlNode GetSettingsNode(string name) { - XmlNode settingsNode = _rootNode.SelectSingleNode(name); + var settingsNode = _rootNode.SelectSingleNode(name); - if (settingsNode == null) - { - settingsNode = _rootDocument.CreateElement(name); - _rootNode.AppendChild(settingsNode); - } + if (settingsNode != null) return settingsNode; + settingsNode = _rootDocument.CreateElement(name); + _rootNode.AppendChild(settingsNode); return settingsNode; } - public XmlDocument GetBlankXmlDocument() + private static XmlDocument GetBlankXmlDocument() { - XmlDocument blankXmlDocument = new XmlDocument(); + var blankXmlDocument = new XmlDocument(); blankXmlDocument.AppendChild(blankXmlDocument.CreateXmlDeclaration("1.0", "utf-8", string.Empty)); blankXmlDocument.AppendChild(blankXmlDocument.CreateElement(_rootNodeName)); diff --git a/mRemoteV1/Config/Settings/SettingsLoader.cs b/mRemoteV1/Config/Settings/SettingsLoader.cs index fcc93d9e2..a730dac69 100644 --- a/mRemoteV1/Config/Settings/SettingsLoader.cs +++ b/mRemoteV1/Config/Settings/SettingsLoader.cs @@ -19,13 +19,21 @@ namespace mRemoteNG.Config.Settings { private readonly ExternalAppsLoader _externalAppsLoader; private readonly MessageCollector _messageCollector; + private readonly MenuStrip _mainMenu; private readonly QuickConnectToolStrip _quickConnectToolStrip; private readonly ExternalToolsToolStrip _externalToolsToolStrip; + private readonly MultiSshToolStrip _multiSshToolStrip; private FrmMain MainForm { get; } - public SettingsLoader(FrmMain mainForm, MessageCollector messageCollector, QuickConnectToolStrip quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip) + public SettingsLoader( + FrmMain mainForm, + MessageCollector messageCollector, + QuickConnectToolStrip quickConnectToolStrip, + ExternalToolsToolStrip externalToolsToolStrip, + MultiSshToolStrip multiSshToolStrip, + MenuStrip mainMenu) { if (mainForm == null) throw new ArgumentNullException(nameof(mainForm)); @@ -35,12 +43,18 @@ namespace mRemoteNG.Config.Settings throw new ArgumentNullException(nameof(quickConnectToolStrip)); if (externalToolsToolStrip == null) throw new ArgumentNullException(nameof(externalToolsToolStrip)); + if (multiSshToolStrip == null) + throw new ArgumentNullException(nameof(multiSshToolStrip)); + if (mainMenu == null) + throw new ArgumentNullException(nameof(mainMenu)); MainForm = mainForm; _messageCollector = messageCollector; _quickConnectToolStrip = quickConnectToolStrip; _externalToolsToolStrip = externalToolsToolStrip; - _externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip); + _multiSshToolStrip = multiSshToolStrip; + _mainMenu = mainMenu; + _externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip); } #region Public Methods @@ -187,31 +201,64 @@ namespace mRemoteNG.Config.Settings private void LoadToolbarsFromSettings() { - if (mRemoteNG.Settings.Default.QuickyTBLocation.X > mRemoteNG.Settings.Default.ExtAppsTBLocation.X) - { - AddExternalAppsPanel(); - AddQuickConnectPanel(); - } - else - { - AddQuickConnectPanel(); - AddExternalAppsPanel(); - } - } - + ResetAllToolbarLocations(); + AddMainMenuPanel(); + AddExternalAppsPanel(); + AddQuickConnectPanel(); + AddMultiSshPanel(); + } + + /// + /// This prevents odd positioning issues due to toolbar load order. + /// Since all toolbars start in this temp panel, no toolbar load + /// can be blocked by pre-existing toolbars. + /// + private void ResetAllToolbarLocations() + { + var tempToolStrip = new ToolStripPanel(); + tempToolStrip.Join(_mainMenu); + tempToolStrip.Join(_quickConnectToolStrip); + tempToolStrip.Join(_externalToolsToolStrip); + tempToolStrip.Join(_multiSshToolStrip); + } + + private void AddMainMenuPanel() + { + SetToolstripGripStyle(_mainMenu); + var toolStripPanel = ToolStripPanelFromString("top"); + toolStripPanel.Join(_mainMenu, new Point(3, 0)); + } + private void AddQuickConnectPanel() { + SetToolstripGripStyle(_quickConnectToolStrip); + _quickConnectToolStrip.Visible = mRemoteNG.Settings.Default.QuickyTBVisible; var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.QuickyTBParentDock); toolStripPanel.Join(_quickConnectToolStrip, mRemoteNG.Settings.Default.QuickyTBLocation); - _quickConnectToolStrip.Visible = mRemoteNG.Settings.Default.QuickyTBVisible; } private void AddExternalAppsPanel() { - var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock); - toolStripPanel.Join(_externalToolsToolStrip, mRemoteNG.Settings.Default.ExtAppsTBLocation); + SetToolstripGripStyle(_externalToolsToolStrip); _externalToolsToolStrip.Visible = mRemoteNG.Settings.Default.ExtAppsTBVisible; + var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock); + toolStripPanel.Join(_externalToolsToolStrip, mRemoteNG.Settings.Default.ExtAppsTBLocation); } + + private void AddMultiSshPanel() + { + SetToolstripGripStyle(_multiSshToolStrip); + _multiSshToolStrip.Visible = mRemoteNG.Settings.Default.MultiSshToolbarVisible; + var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.MultiSshToolbarParentDock); + toolStripPanel.Join(_multiSshToolStrip, mRemoteNG.Settings.Default.MultiSshToolbarLocation); + } + + private void SetToolstripGripStyle(ToolStrip toolbar) + { + toolbar.GripStyle = mRemoteNG.Settings.Default.LockToolbars + ? ToolStripGripStyle.Hidden + : ToolStripGripStyle.Visible; + } private ToolStripPanel ToolStripPanelFromString(string panel) { diff --git a/mRemoteV1/Config/Settings/SettingsSaver.cs b/mRemoteV1/Config/Settings/SettingsSaver.cs index 7ebb4dd53..f41ed382e 100644 --- a/mRemoteV1/Config/Settings/SettingsSaver.cs +++ b/mRemoteV1/Config/Settings/SettingsSaver.cs @@ -11,7 +11,11 @@ namespace mRemoteNG.Config.Settings { public static class SettingsSaver { - public static void SaveSettings(Control quickConnectToolStrip, ExternalToolsToolStrip externalToolsToolStrip, FrmMain frmMain) + public static void SaveSettings( + Control quickConnectToolStrip, + ExternalToolsToolStrip externalToolsToolStrip, + MultiSshToolStrip multiSshToolStrip, + FrmMain frmMain) { try { @@ -43,20 +47,10 @@ namespace mRemoteNG.Config.Settings mRemoteNG.Settings.Default.ResetToolbars = false; mRemoteNG.Settings.Default.NoReconnect = false; - mRemoteNG.Settings.Default.ExtAppsTBLocation = externalToolsToolStrip.Location; - if (externalToolsToolStrip.Parent != null) - { - mRemoteNG.Settings.Default.ExtAppsTBParentDock = externalToolsToolStrip.Parent.Dock.ToString(); - } - mRemoteNG.Settings.Default.ExtAppsTBVisible = externalToolsToolStrip.Visible; - mRemoteNG.Settings.Default.ExtAppsTBShowText = externalToolsToolStrip.CMenToolbarShowText.Checked; - - mRemoteNG.Settings.Default.QuickyTBLocation = quickConnectToolStrip.Location; - if (quickConnectToolStrip.Parent != null) - { - mRemoteNG.Settings.Default.QuickyTBParentDock = quickConnectToolStrip.Parent.Dock.ToString(); - } - mRemoteNG.Settings.Default.QuickyTBVisible = quickConnectToolStrip.Visible; + SaveExternalAppsToolbarLocation(externalToolsToolStrip); + SaveQuickConnectToolbarLocation(quickConnectToolStrip); + SaveMultiSshToolbarLocation(multiSshToolStrip); + mRemoteNG.Settings.Default.Save(); SaveDockPanelLayout(); @@ -68,6 +62,40 @@ namespace mRemoteNG.Config.Settings } } + private static void SaveExternalAppsToolbarLocation(ExternalToolsToolStrip externalToolsToolStrip) + { + mRemoteNG.Settings.Default.ExtAppsTBLocation = externalToolsToolStrip.Location; + mRemoteNG.Settings.Default.ExtAppsTBVisible = externalToolsToolStrip.Visible; + mRemoteNG.Settings.Default.ExtAppsTBShowText = externalToolsToolStrip.CMenToolbarShowText.Checked; + + if (externalToolsToolStrip.Parent != null) + { + mRemoteNG.Settings.Default.ExtAppsTBParentDock = externalToolsToolStrip.Parent.Dock.ToString(); + } + } + + private static void SaveQuickConnectToolbarLocation(Control quickConnectToolStrip) + { + mRemoteNG.Settings.Default.QuickyTBLocation = quickConnectToolStrip.Location; + mRemoteNG.Settings.Default.QuickyTBVisible = quickConnectToolStrip.Visible; + + if (quickConnectToolStrip.Parent != null) + { + mRemoteNG.Settings.Default.QuickyTBParentDock = quickConnectToolStrip.Parent.Dock.ToString(); + } + } + + private static void SaveMultiSshToolbarLocation(MultiSshToolStrip multiSshToolStrip) + { + mRemoteNG.Settings.Default.MultiSshToolbarLocation = multiSshToolStrip.Location; + mRemoteNG.Settings.Default.MultiSshToolbarVisible = multiSshToolStrip.Visible; + + if (multiSshToolStrip.Parent != null) + { + mRemoteNG.Settings.Default.MultiSshToolbarParentDock = multiSshToolStrip.Parent.Dock.ToString(); + } + } + private static void SaveDockPanelLayout() { var panelLayoutXmlFilePath = SettingsFileInfo.SettingsPath + "\\" + SettingsFileInfo.LayoutFileName; diff --git a/mRemoteV1/Connection/AbstractConnectionRecord.cs b/mRemoteV1/Connection/AbstractConnectionRecord.cs index 794904e1e..835bd9a6c 100644 --- a/mRemoteV1/Connection/AbstractConnectionRecord.cs +++ b/mRemoteV1/Connection/AbstractConnectionRecord.cs @@ -57,6 +57,7 @@ namespace mRemoteNG.Connection private bool _redirectKeys; private bool _redirectDiskDrives; private bool _redirectPrinters; + private bool _redirectClipboard; private bool _redirectPorts; private bool _redirectSmartCards; private RdpProtocol.RDPSounds _redirectSound; @@ -87,8 +88,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 +97,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 +107,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 +116,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 +127,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 +136,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 +146,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 +155,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 +167,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 +177,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 +186,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 +196,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 +206,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 +216,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 +226,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 +235,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 +250,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 +259,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 +269,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 +279,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 +291,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 +300,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 +310,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 +319,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 +329,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 +338,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 +350,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 +360,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 +370,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 +380,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 +390,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 +400,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 +410,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 +420,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 +432,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 +442,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 +452,18 @@ 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), + LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectClipboard"), + LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectClipboard"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RedirectClipboard + { + get { return GetPropertyValue("RedirectClipboard", _redirectClipboard); } + set { SetField(ref _redirectClipboard, value, "RedirectClipboard"); } } [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), @@ -461,8 +472,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 +482,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 +492,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,14 +502,14 @@ 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 #region Misc [Browsable(false)] - public string ConstantID { get; set; } + public string ConstantID { get; /*set;*/ } [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), LocalizedAttributes.LocalizedDisplayName("strPropertyNameExternalToolBefore"), @@ -506,8 +517,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 +527,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 +536,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 +545,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 +558,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 +569,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 +580,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 +591,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 +601,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 +611,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 +621,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 +632,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 +643,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 +653,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,15 +663,20 @@ 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 + protected AbstractConnectionRecord(string uniqueId) + { + ConstantID = uniqueId.ThrowIfNullOrEmpty(nameof(uniqueId)); + } + protected virtual TPropertyType GetPropertyValue(string propertyName, TPropertyType value) { - return (TPropertyType)GetType().GetProperty(propertyName).GetValue(this, null); + return (TPropertyType)GetType().GetProperty(propertyName)?.GetValue(this, null); } public event PropertyChangedEventHandler PropertyChanged; @@ -669,12 +685,11 @@ namespace mRemoteNG.Connection PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(args.PropertyName)); } - protected bool SetField(ref T field, T value, string propertyName = null) + private void SetField(ref T field, T value, string propertyName = null) { - if (EqualityComparer.Default.Equals(field, value)) return false; + if (EqualityComparer.Default.Equals(field, value)) return; field = value; RaisePropertyChangedEvent(this, new PropertyChangedEventArgs(propertyName)); - return true; } } } \ No newline at end of file diff --git a/mRemoteV1/Connection/ConnectionInfo.cs b/mRemoteV1/Connection/ConnectionInfo.cs index 915f45385..46fe5ff87 100644 --- a/mRemoteV1/Connection/ConnectionInfo.cs +++ b/mRemoteV1/Connection/ConnectionInfo.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Reflection; using mRemoteNG.App; using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol.Http; @@ -14,14 +9,17 @@ using mRemoteNG.Connection.Protocol.SSH; using mRemoteNG.Connection.Protocol.Telnet; using mRemoteNG.Connection.Protocol.VNC; using mRemoteNG.Container; -using mRemoteNG.Tools; using mRemoteNG.Tree; -using mRemoteNG.Tree.Root; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; namespace mRemoteNG.Connection { - [DefaultProperty("Name")] + [DefaultProperty("Name")] public class ConnectionInfo : AbstractConnectionRecord, IHasParent, IInheritable { #region Public Properties @@ -32,7 +30,7 @@ namespace mRemoteNG.Connection public ProtocolList OpenConnections { get; protected set; } [Browsable(false)] - public bool IsContainer { get; set; } + public virtual bool IsContainer { get; set; } [Browsable(false)] public bool IsDefault { get; set; } @@ -52,7 +50,14 @@ namespace mRemoteNG.Connection #endregion #region Constructors - public ConnectionInfo() + + public ConnectionInfo() + : this(Guid.NewGuid().ToString()) + { + } + + public ConnectionInfo(string uniqueId) + : base(uniqueId) { SetTreeDisplayDefaults(); SetConnectionDefaults(); @@ -65,12 +70,6 @@ namespace mRemoteNG.Connection SetNonBrowsablePropertiesDefaults(); SetDefaults(); } - - public ConnectionInfo(ContainerInfo parent) : this() - { - IsContainer = true; - parent.AddChild(this); - } #endregion #region Public Methods @@ -78,9 +77,9 @@ namespace mRemoteNG.Connection { var newConnectionInfo = new ConnectionInfo(); newConnectionInfo.CopyFrom(this); - newConnectionInfo.ConstantID = MiscTools.CreateConstantID(); newConnectionInfo.Inheritance = Inheritance.Clone(); - return newConnectionInfo; + newConnectionInfo.Inheritance.Parent = newConnectionInfo; + return newConnectionInfo; } public void CopyFrom(ConnectionInfo sourceConnectionInfo) @@ -128,19 +127,22 @@ namespace mRemoteNG.Connection return filteredProperties; } + public virtual IEnumerable GetSerializableProperties() + { + var excludedProperties = new[] { "Parent", "Name", "Hostname", "Port", "Inheritance", "OpenConnections", + "IsContainer", "IsDefault", "PositionID", "ConstantID", "TreeNode", "IsQuickConnect", "PleaseConnect" }; + + return GetProperties(excludedProperties); + } + public virtual void SetParent(ContainerInfo newParent) { RemoveParent(); newParent?.AddChild(this); - if (newParent is RootNodeInfo) - Inheritance.DisableInheritance(); } public void RemoveParent() { - if (Parent is RootNodeInfo) - Inheritance.EnableInheritance(); - Parent?.RemoveChild(this); } @@ -168,7 +170,14 @@ namespace mRemoteNG.Connection #region Private Methods protected override TPropertyType GetPropertyValue(string propertyName, TPropertyType value) { - return ShouldThisPropertyBeInherited(propertyName) ? GetInheritedPropertyValue(propertyName) : value; + if (!ShouldThisPropertyBeInherited(propertyName)) + return value; + + var couldGetInheritedValue = TryGetInheritedPropertyValue(propertyName, out var inheritedValue); + + return couldGetInheritedValue + ? inheritedValue + : value; } private bool ShouldThisPropertyBeInherited(string propertyName) @@ -189,17 +198,24 @@ namespace mRemoteNG.Connection return inheritPropertyValue; } - private TPropertyType GetInheritedPropertyValue(string propertyName) + private bool TryGetInheritedPropertyValue(string propertyName, out TPropertyType inheritedValue) { - var connectionInfoType = Parent.GetType(); - var parentPropertyInfo = connectionInfoType.GetProperty(propertyName); - if (parentPropertyInfo == null) - return default(TPropertyType); // shouldn't get here... - var parentPropertyValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null); + try + { + var connectionInfoType = Parent.GetType(); + var parentPropertyInfo = connectionInfoType.GetProperty(propertyName); + if (parentPropertyInfo == null) + throw new NullReferenceException($"Could not retrieve property data for property '{propertyName}' on parent node '{Parent?.Name}'"); - return parentPropertyValue; - - + inheritedValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null); + return true; + } + catch (Exception e) + { + Runtime.MessageCollector.AddExceptionStackTrace($"Error retrieving inherited property '{propertyName}'", e); + inheritedValue = default(TPropertyType); + return false; + } } private static int GetDefaultPort(ProtocolType protocol) @@ -297,15 +313,15 @@ namespace mRemoteNG.Connection RedirectKeys = Settings.Default.ConDefaultRedirectKeys; RedirectDiskDrives = Settings.Default.ConDefaultRedirectDiskDrives; RedirectPrinters = Settings.Default.ConDefaultRedirectPrinters; + RedirectClipboard = Settings.Default.ConDefaultRedirectClipboard; RedirectPorts = Settings.Default.ConDefaultRedirectPorts; RedirectSmartCards = Settings.Default.ConDefaultRedirectSmartCards; - RedirectSound = (RdpProtocol.RDPSounds) Enum.Parse(typeof(RdpProtocol.RDPSounds), Settings.Default.ConDefaultRedirectSound); + RedirectSound = (RdpProtocol.RDPSounds) Enum.Parse(typeof(RdpProtocol.RDPSounds), Settings.Default.ConDefaultRedirectSound); SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), Settings.Default.ConDefaultSoundQuality); } private void SetMiscDefaults() { - ConstantID = MiscTools.CreateConstantID(); PreExtApp = Settings.Default.ConDefaultPreExtApp; PostExtApp = Settings.Default.ConDefaultPostExtApp; MacAddress = Settings.Default.ConDefaultMacAddress; diff --git a/mRemoteV1/Connection/ConnectionInfoInheritance.cs b/mRemoteV1/Connection/ConnectionInfoInheritance.cs index 9acca54fa..c937f72a9 100644 --- a/mRemoteV1/Connection/ConnectionInfoInheritance.cs +++ b/mRemoteV1/Connection/ConnectionInfoInheritance.cs @@ -215,8 +215,13 @@ namespace mRemoteNG.Connection LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectPrinters"), LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectPrinters"), TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectPrinters {get; set;} - - [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), + + [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), + LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectClipboard"), + LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectClipboard"), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectClipboard { get; set; } + + [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 7), LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRedirectPorts"), LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRedirectPorts"), TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RedirectPorts {get; set;} diff --git a/mRemoteV1/Connection/ConnectionInitiator.cs b/mRemoteV1/Connection/ConnectionInitiator.cs index 4502df26d..19a8813b7 100644 --- a/mRemoteV1/Connection/ConnectionInitiator.cs +++ b/mRemoteV1/Connection/ConnectionInitiator.cs @@ -96,6 +96,7 @@ namespace mRemoteNG.Connection var newProtocol = protocolFactory.CreateProtocol(connectionInfo); var connectionPanel = SetConnectionPanel(connectionInfo, force); + if (string.IsNullOrEmpty(connectionPanel)) return; var connectionForm = SetConnectionForm(conForm, connectionPanel); var connectionContainer = SetConnectionContainer(connectionInfo, connectionForm); SetConnectionFormEventHandlers(newProtocol, connectionForm); @@ -163,6 +164,10 @@ namespace mRemoteNG.Connection { connectionPanel = frmPnl.Panel; } + else + { + return null; + } } else { diff --git a/mRemoteV1/Connection/ConnectionsService.cs b/mRemoteV1/Connection/ConnectionsService.cs index eca7a6e3e..c6240ec92 100644 --- a/mRemoteV1/Connection/ConnectionsService.cs +++ b/mRemoteV1/Connection/ConnectionsService.cs @@ -8,10 +8,12 @@ using mRemoteNG.Config.Connections; using mRemoteNG.Config.Connections.Multiuser; using mRemoteNG.Config.Putty; using mRemoteNG.Connection.Protocol; +using mRemoteNG.Messages; using mRemoteNG.Security; using mRemoteNG.Tools; using mRemoteNG.Tree; using mRemoteNG.Tree.Root; +using mRemoteNG.UI; namespace mRemoteNG.Connection { @@ -19,6 +21,9 @@ namespace mRemoteNG.Connection { private static readonly object SaveLock = new object(); private readonly PuttySessionsManager _puttySessionsManager; + private bool _batchingSaves = false; + private bool _saveRequested = false; + private bool _saveAsyncRequested = false; public bool IsConnectionsFileLoaded { get; set; } public bool UsingDatabase { get; private set; } @@ -27,11 +32,6 @@ namespace mRemoteNG.Connection public DateTime LastSqlUpdate { get; set; } public ConnectionTreeModel ConnectionTreeModel { get; private set; } - //public ConnectionTreeModel ConnectionTreeModel - //{ - // get { return Windows.TreeForm.ConnectionTree.ConnectionTreeModel; } - // set { Windows.TreeForm.ConnectionTree.ConnectionTreeModel = value; } - //} public ConnectionsService(PuttySessionsManager puttySessionsManager) { @@ -45,11 +45,11 @@ namespace mRemoteNG.Connection { try { + filename.ThrowIfNullOrEmpty(nameof(filename)); 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) { @@ -79,6 +79,10 @@ namespace mRemoteNG.Connection { newConnectionInfo.Port = uri.Port; } + + if (string.IsNullOrEmpty(newConnectionInfo.Panel)) + newConnectionInfo.Panel = Language.strGeneral; + newConnectionInfo.IsQuickConnect = true; return newConnectionInfo; @@ -97,16 +101,24 @@ namespace mRemoteNG.Connection /// /// /// - 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 - ? new SqlConnectionsLoader().Load() - : new XmlConnectionsLoader(connectionFileName).Load()) - ?? new ConnectionTreeModel(); + var newConnectionTreeModel = useDatabase + ? new SqlConnectionsLoader().Load() + : new XmlConnectionsLoader(connectionFileName).Load(); + + if (newConnectionTreeModel == null) + { + DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed", IsConnectionsFileLoaded); + return; + } + + IsConnectionsFileLoaded = true; + ConnectionFileName = connectionFileName; + UsingDatabase = useDatabase; if (!import) { @@ -114,12 +126,35 @@ 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; + } + + /// + /// When turned on, calls to or + /// will not immediately execute. + /// Instead, they will be deferred until + /// is called. + /// + public void BeginBatchingSaves() + { + _batchingSaves = true; + } + + /// + /// Immediately executes a single or + /// if one has been requested + /// since calling . + /// + public void EndBatchingSaves() + { + _batchingSaves = false; + + if (_saveAsyncRequested) + SaveConnectionsAsync(); + else if(_saveRequested) + SaveConnections(); } /// @@ -128,8 +163,6 @@ namespace mRemoteNG.Connection /// public void SaveConnections() { - if (!IsConnectionsFileLoaded) - return; SaveConnections(ConnectionTreeModel, UsingDatabase, new SaveFilter(), ConnectionFileName); } @@ -141,12 +174,24 @@ namespace mRemoteNG.Connection /// /// /// - public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName) + /// Bypasses safety checks that prevent saving if a connection file isn't loaded. + 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; @@ -161,6 +206,7 @@ namespace mRemoteNG.Connection UsingDatabase = useDatabase; ConnectionFileName = connectionFileName; RaiseConnectionsSavedEvent(connectionTreeModel, previouslyUsingDatabase, UsingDatabase, connectionFileName); + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Successfully saved connections"); } catch (Exception ex) { @@ -174,6 +220,12 @@ namespace mRemoteNG.Connection public void SaveConnectionsAsync() { + if (_batchingSaves) + { + _saveAsyncRequested = true; + return; + } + var t = new Thread(SaveConnectionsBGd); t.SetApartmentState(ApartmentState.STA); t.Start(); @@ -181,19 +233,24 @@ namespace mRemoteNG.Connection private void SaveConnectionsBGd() { - Monitor.Enter(SaveLock); - SaveConnections(); - Monitor.Exit(SaveLock); + lock (SaveLock) + { + SaveConnections(); + } } 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) @@ -227,7 +284,7 @@ namespace mRemoteNG.Connection public event EventHandler ConnectionsLoaded; public event EventHandler ConnectionsSaved; - private void RaiseConnectionsLoadedEvent(Maybe previousTreeModel, ConnectionTreeModel newTreeModel, + private void RaiseConnectionsLoadedEvent(Optional previousTreeModel, ConnectionTreeModel newTreeModel, bool previousSourceWasDatabase, bool newSourceIsDatabase, string newSourcePath) { diff --git a/mRemoteV1/Connection/DefaultConnectionInfo.cs b/mRemoteV1/Connection/DefaultConnectionInfo.cs index 8bf0f990d..9a4df225c 100644 --- a/mRemoteV1/Connection/DefaultConnectionInfo.cs +++ b/mRemoteV1/Connection/DefaultConnectionInfo.cs @@ -1,35 +1,44 @@ using System; -using System.ComponentModel; +using System.Configuration; using mRemoteNG.App; namespace mRemoteNG.Connection { - public class DefaultConnectionInfo : ConnectionInfo + public class DefaultConnectionInfo : ConnectionInfo { public static DefaultConnectionInfo Instance { get; } = new DefaultConnectionInfo(); - private readonly string[] _excludedProperties = { "Parent", "Name", "Hostname", "Port", "Inheritance", - "OpenConnections", "IsContainer", "IsDefault", "PositionID", "ConstantID", "TreeNode", "IsQuickConnect", "PleaseConnect" }; private DefaultConnectionInfo() { IsDefault = true; + Inheritance = DefaultConnectionInheritance.Instance; } public void LoadFrom(TSource sourceInstance, Func propertyNameMutator = null) { - if (propertyNameMutator == null) propertyNameMutator = a => a; - var connectionProperties = GetProperties(_excludedProperties); + if (propertyNameMutator == null) + propertyNameMutator = a => a; + + var connectionProperties = GetSerializableProperties(); foreach (var property in connectionProperties) { try { - var propertyFromSource = typeof(TSource).GetProperty(propertyNameMutator(property.Name)); - if (propertyFromSource == null) continue; - var valueFromSource = propertyFromSource.GetValue(sourceInstance, null); - var typeConverter = TypeDescriptor.GetConverter(property.PropertyType); - if (typeConverter.CanConvertFrom(valueFromSource.GetType())) - property.SetValue(Instance, typeConverter.ConvertFrom(valueFromSource), null); + var expectedPropertyName = propertyNameMutator(property.Name); + var propertyFromSource = typeof(TSource).GetProperty(expectedPropertyName); + if (propertyFromSource == null) + throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found."); + + var valueFromSource = propertyFromSource.GetValue(sourceInstance, null); + + if (property.PropertyType.IsEnum) + { + property.SetValue(Instance, Enum.Parse(property.PropertyType, valueFromSource.ToString()), null); + continue; + } + + property.SetValue(Instance, Convert.ChangeType(valueFromSource, property.PropertyType), null); } catch (Exception ex) { @@ -40,19 +49,25 @@ namespace mRemoteNG.Connection public void SaveTo(TDestination destinationInstance, Func propertyNameMutator = null) { - if (propertyNameMutator == null) propertyNameMutator = (a) => a; - var inheritanceProperties = GetProperties(_excludedProperties); - foreach (var property in inheritanceProperties) + if (propertyNameMutator == null) + propertyNameMutator = (a) => a; + + var connectionProperties = GetSerializableProperties(); + + foreach (var property in connectionProperties) { try { - var propertyFromDestination = typeof(TDestination).GetProperty(propertyNameMutator(property.Name)); - var localValue = property.GetValue(Instance, null); - var typeConverter = TypeDescriptor.GetConverter(property.PropertyType); - if (propertyFromDestination != null && !typeConverter.CanConvertTo(propertyFromDestination.PropertyType)) continue; - if (propertyFromDestination == null) continue; - var convertedValue = typeConverter.ConvertTo(localValue, propertyFromDestination.PropertyType); - propertyFromDestination.SetValue(destinationInstance, convertedValue, null); + var expectedPropertyName = propertyNameMutator(property.Name); + var propertyFromDestination = typeof(TDestination).GetProperty(expectedPropertyName); + + if (propertyFromDestination == null) + throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found."); + + // ensure value is of correct type + var value = Convert.ChangeType(property.GetValue(Instance, null), propertyFromDestination.PropertyType); + + propertyFromDestination.SetValue(destinationInstance, value, null); } catch (Exception ex) { diff --git a/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs b/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs index 198aabdbc..6c978e4a3 100644 --- a/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs +++ b/mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs @@ -316,10 +316,19 @@ namespace mRemoteNG.Connection.Protocol.RDP return; } - var size = !Fullscreen ? Control.Size : Screen.FromControl(Control).Bounds.Size; + try + { + Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Resizing RDP connection to host '{_connectionInfo.Hostname}'"); + var size = !Fullscreen ? Control.Size : Screen.FromControl(Control).Bounds.Size; - IMsRdpClient8 msRdpClient8 = _rdpClient; - msRdpClient8.Reconnect((uint)size.Width, (uint)size.Height); + IMsRdpClient8 msRdpClient8 = _rdpClient; + msRdpClient8.Reconnect((uint)size.Width, (uint)size.Height); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.ChangeConnectionResolutionError, _connectionInfo.Hostname), + ex, MessageClass.WarningMsg, false); + } } private void SetRdGateway() @@ -543,6 +552,7 @@ namespace mRemoteNG.Connection.Protocol.RDP _rdpClient.AdvancedSettings2.RedirectPrinters = _connectionInfo.RedirectPrinters; _rdpClient.AdvancedSettings2.RedirectSmartCards = _connectionInfo.RedirectSmartCards; _rdpClient.SecuredSettings2.AudioRedirectionMode = (int)_connectionInfo.RedirectSound; + _rdpClient.AdvancedSettings.DisableRdpdr = _connectionInfo.RedirectClipboard ? 0 : 1; } catch (Exception ex) { @@ -916,17 +926,25 @@ namespace mRemoteNG.Connection.Protocol.RDP #region Reconnect Stuff public void tmrReconnect_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { - var srvReady = PortScanner.IsPortOpen(_connectionInfo.Hostname, Convert.ToString(_connectionInfo.Port)); + try + { + var srvReady = PortScanner.IsPortOpen(_connectionInfo.Hostname, Convert.ToString(_connectionInfo.Port)); - ReconnectGroup.ServerReady = srvReady; + ReconnectGroup.ServerReady = srvReady; - if (ReconnectGroup.ReconnectWhenReady && srvReady) - { - tmrReconnect.Enabled = false; - ReconnectGroup.DisposeReconnectGroup(); - //SetProps() - _rdpClient.Connect(); - } + if (ReconnectGroup.ReconnectWhenReady && srvReady) + { + tmrReconnect.Enabled = false; + ReconnectGroup.DisposeReconnectGroup(); + //SetProps() + _rdpClient.Connect(); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.AutomaticReconnectError, _connectionInfo.Hostname), + ex, MessageClass.WarningMsg, false); + } } #endregion } diff --git a/mRemoteV1/Connection/WebHelper.cs b/mRemoteV1/Connection/WebHelper.cs index 75e51a24d..276738051 100644 --- a/mRemoteV1/Connection/WebHelper.cs +++ b/mRemoteV1/Connection/WebHelper.cs @@ -13,6 +13,8 @@ namespace mRemoteNG.Connection connectionInfo.Hostname = url; connectionInfo.Protocol = url.StartsWith("https:") ? ProtocolType.HTTPS : ProtocolType.HTTP; connectionInfo.SetDefaultPort(); + if (string.IsNullOrEmpty(connectionInfo.Panel)) + connectionInfo.Panel = Language.strGeneral; connectionInfo.IsQuickConnect = true; var connectionInitiator = new ConnectionInitiator(); connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump); diff --git a/mRemoteV1/Container/ContainerInfo.cs b/mRemoteV1/Container/ContainerInfo.cs index 9650e822e..c6c6b4c8f 100644 --- a/mRemoteV1/Container/ContainerInfo.cs +++ b/mRemoteV1/Container/ContainerInfo.cs @@ -1,16 +1,15 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; -using mRemoteNG.Connection; using System.ComponentModel; using System.Linq; +using mRemoteNG.Connection; using mRemoteNG.Connection.Protocol; -using mRemoteNG.Tools; using mRemoteNG.Tree; namespace mRemoteNG.Container { - [DefaultProperty("Name")] + [DefaultProperty("Name")] public class ContainerInfo : ConnectionInfo, INotifyCollectionChanged { [Browsable(false)] @@ -19,13 +18,20 @@ namespace mRemoteNG.Container [Category(""), Browsable(false), ReadOnly(false), Bindable(false), DefaultValue(""), DesignOnly(false)] public bool IsExpanded { get; set; } + [Browsable(false)] + public override bool IsContainer { get { return true; } set {} } - public ContainerInfo() + public ContainerInfo(string uniqueId) + : base(uniqueId) { SetDefaults(); - IsContainer = true; } + public ContainerInfo() + : this(Guid.NewGuid().ToString()) + { + } + public override TreeNodeType GetTreeNodeType() { return TreeNodeType.Container; @@ -57,7 +63,7 @@ namespace mRemoteNG.Container AddChildAt(newChildItem, newChildIndex); } - public void AddChildAt(ConnectionInfo newChildItem, int index) + public virtual void AddChildAt(ConnectionInfo newChildItem, int index) { if (Children.Contains(newChildItem)) return; newChildItem.Parent?.RemoveChild(newChildItem); @@ -75,7 +81,7 @@ namespace mRemoteNG.Container } } - public void RemoveChild(ConnectionInfo removalTarget) + public virtual void RemoveChild(ConnectionInfo removalTarget) { if (!Children.Contains(removalTarget)) return; removalTarget.Parent = null; @@ -178,7 +184,6 @@ namespace mRemoteNG.Container { var newContainer = new ContainerInfo(); newContainer.CopyFrom(this); - newContainer.ConstantID = MiscTools.CreateConstantID(); newContainer.OpenConnections = new ProtocolList(); newContainer.Inheritance = Inheritance.Clone(); foreach (var child in Children.ToArray()) diff --git a/mRemoteV1/Messages/WriterDecorators/MessageFocusDecorator.cs b/mRemoteV1/Messages/WriterDecorators/MessageFocusDecorator.cs index 1f26c713c..c9d7d9dc6 100644 --- a/mRemoteV1/Messages/WriterDecorators/MessageFocusDecorator.cs +++ b/mRemoteV1/Messages/WriterDecorators/MessageFocusDecorator.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using System.Windows.Forms; using mRemoteNG.Messages.MessageWriters; using mRemoteNG.UI.Forms; @@ -12,29 +13,21 @@ namespace mRemoteNG.Messages.WriterDecorators private readonly IMessageTypeFilteringOptions _filter; private readonly IMessageWriter _decoratedWriter; private readonly ErrorAndInfoWindow _messageWindow; - private Timer _ecTimer; private readonly FrmMain _frmMain = FrmMain.Default; public MessageFocusDecorator(ErrorAndInfoWindow messageWindow, IMessageTypeFilteringOptions filter, IMessageWriter decoratedWriter) { - if (filter == null) - throw new ArgumentNullException(nameof(filter)); - if (messageWindow == null) - throw new ArgumentNullException(nameof(messageWindow)); - if (decoratedWriter == null) - throw new ArgumentNullException(nameof(decoratedWriter)); - - _filter = filter; - _messageWindow = messageWindow; - _decoratedWriter = decoratedWriter; - CreateTimer(); + _filter = filter ?? throw new ArgumentNullException(nameof(filter)); + _messageWindow = messageWindow ?? throw new ArgumentNullException(nameof(messageWindow)); + _decoratedWriter = decoratedWriter ?? throw new ArgumentNullException(nameof(decoratedWriter)); } - public void Write(IMessage message) + public async void Write(IMessage message) { - if (WeShouldFocusNotificationPanel(message)) - BeginSwitchToPanel(); _decoratedWriter.Write(message); + + if (WeShouldFocusNotificationPanel(message)) + await SwitchToMessageAsync(); } private bool WeShouldFocusNotificationPanel(IMessage message) @@ -43,7 +36,8 @@ namespace mRemoteNG.Messages.WriterDecorators switch (message.Class) { case MessageClass.InformationMsg: - if (_filter.AllowInfoMessages) return true; + if (_filter.AllowInfoMessages) + return true; break; case MessageClass.WarningMsg: if (_filter.AllowWarningMessages) return true; @@ -55,43 +49,46 @@ namespace mRemoteNG.Messages.WriterDecorators return false; } - private void CreateTimer() + private async Task SwitchToMessageAsync() { - _ecTimer = new Timer - { - Enabled = false, - Interval = 300 - }; - _ecTimer.Tick += SwitchTimerTick; - } - - private void BeginSwitchToPanel() - { - _ecTimer.Enabled = true; - } - - private void SwitchTimerTick(object sender, EventArgs e) - { - SwitchToMessage(); - _ecTimer.Enabled = false; + await Task + .Delay(TimeSpan.FromMilliseconds(300)) + .ContinueWith(task => SwitchToMessage()); } private void SwitchToMessage() { + if (_messageWindow.InvokeRequired) + { + _frmMain.Invoke((MethodInvoker)SwitchToMessage); + return; + } + + // do not attempt to focus the notification panel if it is in an inconsistent state + if (_messageWindow.DockState == DockState.Unknown) + return; + _messageWindow.PreviousActiveForm = (DockContent)_frmMain.pnlDock.ActiveContent; - ShowMcForm(); + + // Show the notifications panel solution: + // https://stackoverflow.com/questions/13843604/calling-up-dockpanel-suites-autohidden-dockcontent-programmatically + if (AutoHideEnabled(_messageWindow)) + _frmMain.pnlDock.ActiveAutoHideContent = _messageWindow; + else + _messageWindow.Show(_frmMain.pnlDock); + _messageWindow.lvErrorCollector.Focus(); _messageWindow.lvErrorCollector.SelectedItems.Clear(); _messageWindow.lvErrorCollector.Items[0].Selected = true; _messageWindow.lvErrorCollector.FocusedItem = _messageWindow.lvErrorCollector.Items[0]; } - private void ShowMcForm() + private bool AutoHideEnabled(DockContent content) { - if (_frmMain.pnlDock.InvokeRequired) - _frmMain.pnlDock.Invoke((MethodInvoker)ShowMcForm); - else - _messageWindow.Show(_frmMain.pnlDock); + return content.DockState == DockState.DockBottomAutoHide || + content.DockState == DockState.DockTopAutoHide || + content.DockState == DockState.DockLeftAutoHide || + content.DockState == DockState.DockRightAutoHide; } } } \ No newline at end of file diff --git a/mRemoteV1/Properties/AssemblyInfo.cs b/mRemoteV1/Properties/AssemblyInfo.cs index e149ed4cc..78e360d69 100644 --- a/mRemoteV1/Properties/AssemblyInfo.cs +++ b/mRemoteV1/Properties/AssemblyInfo.cs @@ -14,7 +14,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("Multi-protocol remote connections manager")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("mRemoteNG")] -[assembly: AssemblyCopyright("Copyright © 2017 mRemoteNG Dev Team; 2010-2013 Riley McArdle; 2007-2009 Felix Deimel")] +[assembly: AssemblyCopyright("Copyright © 2018 mRemoteNG Dev Team; 2010-2013 Riley McArdle; 2007-2009 Felix Deimel")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] @@ -33,5 +33,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // -[assembly: AssemblyVersion("1.76.0.*")] +[assembly: AssemblyVersion("1.77.0.*")] [assembly: NeutralResourcesLanguage("en")] \ No newline at end of file diff --git a/mRemoteV1/Properties/Settings.Designer.cs b/mRemoteV1/Properties/Settings.Designer.cs index df4e94521..0f631838e 100644 --- a/mRemoteV1/Properties/Settings.Designer.cs +++ b/mRemoteV1/Properties/Settings.Designer.cs @@ -12,7 +12,11 @@ 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.7.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -563,6 +567,18 @@ namespace mRemoteNG { } } + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ConDefaultRedirectClipboard { + get { + return ((bool)(this["ConDefaultRedirectClipboard"])); + } + set { + this["ConDefaultRedirectClipboard"] = value; + } + } + [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] @@ -983,6 +999,18 @@ namespace mRemoteNG { } } + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool InhDefaultRedirectClipboard { + get { + return ((bool)(this["InhDefaultRedirectClipboard"])); + } + set { + this["InhDefaultRedirectClipboard"] = value; + } + } + [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] @@ -2593,7 +2621,7 @@ namespace mRemoteNG { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] + [global::System.Configuration.DefaultSettingValueAttribute("General")] public string ConDefaultPanel { get { return ((string)(this["ConDefaultPanel"])); @@ -2662,5 +2690,65 @@ namespace mRemoteNG { this["RdpLoadBalanceInfoUseUtf8"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0, 0")] + public global::System.Drawing.Point MultiSshToolbarLocation { + get { + return ((global::System.Drawing.Point)(this["MultiSshToolbarLocation"])); + } + set { + this["MultiSshToolbarLocation"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string MultiSshToolbarParentDock { + get { + return ((string)(this["MultiSshToolbarParentDock"])); + } + set { + this["MultiSshToolbarParentDock"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool MultiSshToolbarVisible { + get { + return ((bool)(this["MultiSshToolbarVisible"])); + } + set { + 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; + } + } } } diff --git a/mRemoteV1/Properties/Settings.settings b/mRemoteV1/Properties/Settings.settings index be2beae49..7ee752fe1 100644 --- a/mRemoteV1/Properties/Settings.settings +++ b/mRemoteV1/Properties/Settings.settings @@ -137,6 +137,9 @@ False + + False + False @@ -242,6 +245,9 @@ False + + False + False @@ -645,7 +651,7 @@ - + General True @@ -662,5 +668,20 @@ False + + 0, 0 + + + + + + False + + + False + + + General + \ No newline at end of file diff --git a/mRemoteV1/Properties/app.manifest b/mRemoteV1/Properties/app.manifest index 4c249cd2c..3b4845c3d 100644 --- a/mRemoteV1/Properties/app.manifest +++ b/mRemoteV1/Properties/app.manifest @@ -1,6 +1,6 @@  - + @@ -17,6 +17,10 @@ --> + + + + - + \ No newline at end of file diff --git a/mRemoteV1/Resources/CitrixReceiver.exe b/mRemoteV1/Resources/CitrixReceiver.exe new file mode 100644 index 000000000..b1b7c8bcd Binary files /dev/null and b/mRemoteV1/Resources/CitrixReceiver.exe differ diff --git a/mRemoteV1/Resources/Language/Language.Designer.cs b/mRemoteV1/Resources/Language/Language.Designer.cs index 466e4c6d8..37c38c881 100644 --- a/mRemoteV1/Resources/Language/Language.Designer.cs +++ b/mRemoteV1/Resources/Language/Language.Designer.cs @@ -19,7 +19,7 @@ namespace mRemoteNG { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Language { @@ -61,7 +61,25 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Create a New Configuration File. + /// Looks up a localized string similar to An error occurred while trying to reconnect to RDP host '{0}'. + /// + internal static string AutomaticReconnectError { + get { + return ResourceManager.GetString("AutomaticReconnectError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An error occurred while trying to change the connection resolution to host '{0}'. + /// + internal static string ChangeConnectionResolutionError { + get { + return ResourceManager.GetString("ChangeConnectionResolutionError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create a New Connection File. /// internal static string ConfigurationCreateNew { get { @@ -78,15 +96,6 @@ namespace mRemoteNG { } } - /// - /// Looks up a localized string similar to The Configuration File is Missing.. - /// - internal static string ConfigurationFileNotFound { - get { - return ResourceManager.GetString("ConfigurationFileNotFound", resourceCulture); - } - } - /// /// Looks up a localized string similar to Import an Existing File. /// @@ -96,6 +105,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to The connection file could not be found.. + /// + internal static string ConnectionFileNotFound { + get { + return ResourceManager.GetString("ConnectionFileNotFound", resourceCulture); + } + } + /// /// Looks up a localized string similar to Connection successful. /// @@ -222,6 +240,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Working directory:. + /// + internal static string srtWorkingDirectory { + get { + return ResourceManager.GetString("srtWorkingDirectory", resourceCulture); + } + } + /// /// Looks up a localized string similar to About. /// @@ -312,6 +339,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Advanced security options. + /// + internal static string strAdvancedSecurityOptions { + get { + return ResourceManager.GetString("strAdvancedSecurityOptions", resourceCulture); + } + } + /// /// Looks up a localized string similar to Allow only a single instance of the application (mRemoteNG restart required). /// @@ -439,7 +475,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Auto save every:. + /// Looks up a localized string similar to Auto save time in minutes (0 means disabled):. /// internal static string strAutoSaveEvery { get { @@ -865,7 +901,7 @@ namespace mRemoteNG { /// /// Looks up a localized string similar to For RDP to work properly you need to have at least Remote Desktop Connection (Terminal Services) Client 8.0 installed. You can download it here: http://support.microsoft.com/kb/925876 - ///If this check still fails or you are unable to use RDP, please consult the mRemoteNG Forum at {0}.. + ///If this check still fails or you are unable to use RDP, please consult the at {0}.. /// internal static string strCcRDPFailed { get { @@ -886,7 +922,7 @@ namespace mRemoteNG { /// /// Looks up a localized string similar to VNC requires VncSharp.dll to be located in your mRemoteNG application folder. ///Please make sure that you have the VncSharp.dll file in your mRemoteNG application folder (usually C:\Program Files\mRemoteNG\). - ///If you are still not able to pass this check or use VNC in mRemoteNG please consult the mRemoteNG Forum at {0}.. + ///If you are still not able to pass this check or use VNC in mRemoteNG please consult the at {0}.. /// internal static string strCcVNCFailed { get { @@ -1058,7 +1094,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Choose Path. + /// Looks up a localized string similar to Choose path. /// internal static string strChoosePath { get { @@ -1283,6 +1319,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Are you sure you want to close all connections except for "{0}"?. + /// + internal static string strConfirmCloseConnectionOthersInstruction { + get { + return ResourceManager.GetString("strConfirmCloseConnectionOthersInstruction", resourceCulture); + } + } + /// /// Looks up a localized string similar to Are you sure you want to close the panel, "{0}"? Any connections that it contains will also be closed.. /// @@ -1292,6 +1337,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Are you sure you want to close all connections to the right of "{0}"?. + /// + internal static string strConfirmCloseConnectionRightInstruction { + get { + return ResourceManager.GetString("strConfirmCloseConnectionRightInstruction", resourceCulture); + } + } + /// /// Looks up a localized string similar to Are you sure you want to delete the credential record, {0}?. /// @@ -1628,6 +1682,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Create an empty panel when mRemoteNG starts. + /// + internal static string strCreateEmptyPanelOnStartUp { + get { + return ResourceManager.GetString("strCreateEmptyPanelOnStartUp", resourceCulture); + } + } + /// /// Looks up a localized string similar to Credential Editor. /// @@ -1684,6 +1747,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Delete.... + /// + internal static string strDelete { + get { + return ResourceManager.GetString("strDelete", resourceCulture); + } + } + /// /// Looks up a localized string similar to Detect. /// @@ -2544,7 +2616,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to An error occurred while importing the file, "{0}".. + /// Looks up a localized string similar to An error occurred while importing the file "{0}".. /// internal static string strImportFileFailedContent { get { @@ -2625,7 +2697,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Import from .RDP file(s). + /// Looks up a localized string similar to Import from RDP file(s). /// internal static string strImportRDPFiles { get { @@ -2633,6 +2705,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Import sub OUs. + /// + internal static string strImportSubOUs { + get { + return ResourceManager.GetString("strImportSubOUs", resourceCulture); + } + } + /// /// Looks up a localized string similar to Inactive. /// @@ -2741,6 +2822,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Must Be Between 0 and 255. + /// + internal static string strIPRange { + get { + return ResourceManager.GetString("strIPRange", resourceCulture); + } + } + /// /// Looks up a localized string similar to CTRL-ALT-DEL. /// @@ -2904,7 +2994,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Read Only:. + /// Looks up a localized string similar to Read only:. /// internal static string strLabelReadOnly { get { @@ -2922,7 +3012,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to seconds. + /// Looks up a localized string similar to Seconds. /// internal static string strLabelSeconds { get { @@ -2940,7 +3030,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Server Status:. + /// Looks up a localized string similar to Server status:. /// internal static string strLabelServerStatus { get { @@ -3011,6 +3101,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Use UTF8 encoding for RDP "Load Balance Info" property. + /// + internal static string strLoadBalanceInfoUseUtf8 { + get { + return ResourceManager.GetString("strLoadBalanceInfoUseUtf8", resourceCulture); + } + } + /// /// Looks up a localized string similar to Load from SQL failed. /// @@ -3056,6 +3155,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Lock toolbar positions. + /// + internal static string strLockToolbars { + get { + return ResourceManager.GetString("strLockToolbars", resourceCulture); + } + } + /// /// Looks up a localized string similar to Log file path. /// @@ -3281,6 +3389,24 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Disconnect All But This. + /// + internal static string strMenuDisconnectOthers { + get { + return ResourceManager.GetString("strMenuDisconnectOthers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disconnect Tabs To The Right. + /// + internal static string strMenuDisconnectOthersRight { + get { + return ResourceManager.GetString("strMenuDisconnectOthersRight", resourceCulture); + } + } + /// /// Looks up a localized string similar to Donate. /// @@ -3399,7 +3525,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Jump To. + /// Looks up a localized string similar to Jump to. /// internal static string strMenuJumpTo { get { @@ -3416,6 +3542,24 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Lock toolbar positions. + /// + internal static string strMenuLockToolbars { + get { + return ResourceManager.GetString("strMenuLockToolbars", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multi SSH toolbar. + /// + internal static string strMenuMultiSshToolbar { + get { + return ResourceManager.GetString("strMenuMultiSshToolbar", resourceCulture); + } + } + /// /// Looks up a localized string similar to New Connection File. /// @@ -3812,6 +3956,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Multi SSH toolbar. + /// + internal static string strMultiSshToolbar { + get { + return ResourceManager.GetString("strMultiSshToolbar", resourceCulture); + } + } + /// /// Looks up a localized string similar to My current credentials (Windows logon information). /// @@ -3885,7 +4038,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to No Compression. + /// Looks up a localized string similar to No сompression. /// internal static string strNoCompression { get { @@ -3930,7 +4083,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to No Ext. App specified.. + /// Looks up a localized string similar to No ext. app specified.. /// internal static string strNoExtAppDefined { get { @@ -4003,7 +4156,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Open File. + /// Looks up a localized string similar to Open file. /// internal static string strOpenFile { get { @@ -4075,7 +4228,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Next Tab. + /// Looks up a localized string similar to Next tab. /// internal static string strOptionsKeyboardCommandsNextTab { get { @@ -4084,7 +4237,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Previous Tab. + /// Looks up a localized string similar to Previous tab. /// internal static string strOptionsKeyboardCommandsPreviousTab { get { @@ -4093,7 +4246,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Modify Shortcut. + /// Looks up a localized string similar to Modify shortcut. /// internal static string strOptionsKeyboardGroupModifyShortcut { get { @@ -4102,7 +4255,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Keyboard Shortcuts. + /// Looks up a localized string similar to Keyboard shortcuts. /// internal static string strOptionsKeyboardLabelKeyboardShortcuts { get { @@ -4110,6 +4263,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to mRemoteNG Options. + /// + internal static string strOptionsPageTitle { + get { + return ResourceManager.GetString("strOptionsPageTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to Testing.... /// @@ -4165,7 +4327,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Enable Themes. + /// Looks up a localized string similar to Enable themes. /// internal static string strOptionsThemeEnableTheming { get { @@ -4174,7 +4336,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to No themes are loaded, check that the default mremoteNG themes exist in the slash themes folder. + /// Looks up a localized string similar to No themes are loaded, check that the default mRemoteNG themes exist in the 'themes' folder. /// internal static string strOptionsThemeErrorNoThemes { get { @@ -4218,6 +4380,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Out Of Range. + /// + internal static string strOutOfRange { + get { + return ResourceManager.GetString("strOutOfRange", resourceCulture); + } + } + /// /// Looks up a localized string similar to Panel Name. /// @@ -4876,7 +5047,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Authentication Mode. + /// Looks up a localized string similar to Authentication mode. /// internal static string strPropertyNameAuthenticationMode { get { @@ -4885,7 +5056,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Automatic Resize. + /// Looks up a localized string similar to Automatic resize. /// internal static string strPropertyNameAutomaticResize { get { @@ -5155,7 +5326,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Alert on Idle Disconnect. + /// Looks up a localized string similar to Alert on Idle disconnect. /// internal static string strPropertyNameRDPAlertIdleTimeout { get { @@ -5254,7 +5425,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Sound Quality. + /// Looks up a localized string similar to Sound quality. /// internal static string strPropertyNameSoundQuality { get { @@ -6147,6 +6318,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Reconnect All Connections. + /// + internal static string strReconnectAllConnections { + get { + return ResourceManager.GetString("strReconnectAllConnections", resourceCulture); + } + } + /// /// Looks up a localized string similar to Reconnect to previously opened sessions on startup. /// @@ -6210,6 +6390,24 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Run elevated. + /// + internal static string strRunElevated { + get { + return ResourceManager.GetString("strRunElevated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Run elevate. + /// + internal static string strRunElevateHeader { + get { + return ResourceManager.GetString("strRunElevateHeader", resourceCulture); + } + } + /// /// Looks up a localized string similar to Save. /// @@ -6381,6 +6579,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Show on toolbar column. + /// + internal static string strShowOnToolbarColumnHeader { + get { + return ResourceManager.GetString("strShowOnToolbarColumnHeader", resourceCulture); + } + } + /// /// Looks up a localized string similar to Show protocols on tab names. /// @@ -7011,6 +7218,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Timeout (seconds). + /// + internal static string strTimeoutInSeconds { + get { + return ResourceManager.GetString("strTimeoutInSeconds", resourceCulture); + } + } + /// /// Looks up a localized string similar to Title. /// @@ -7101,6 +7317,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Try to integrate. + /// + internal static string strTryToIntegrateColumnHeader { + get { + return ResourceManager.GetString("strTryToIntegrateColumnHeader", resourceCulture); + } + } + /// /// Looks up a localized string similar to Type. /// @@ -7128,6 +7353,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to UltraVNC SingleClick. + /// + internal static string strUltraVNCSingleClick { + get { + return ResourceManager.GetString("strUltraVNCSingleClick", resourceCulture); + } + } + /// /// Looks up a localized string similar to Uncheck the properties you want not to be saved!. /// @@ -7292,7 +7526,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Use Default. + /// Looks up a localized string similar to Use default. /// internal static string strUseDefault { get { @@ -7471,6 +7705,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Working directory. + /// + internal static string strWorkingDirColumnHeader { + get { + return ResourceManager.GetString("strWorkingDirColumnHeader", resourceCulture); + } + } + /// /// Looks up a localized string similar to XULrunner path:. /// @@ -7490,7 +7733,7 @@ namespace mRemoteNG { } /// - /// Looks up a localized string similar to Test Connection. + /// Looks up a localized string similar to Test connection. /// internal static string TestConnection { get { diff --git a/mRemoteV1/Resources/Language/Language.es.resx b/mRemoteV1/Resources/Language/Language.es.resx index b35cadf1f..994cf6231 100644 --- a/mRemoteV1/Resources/Language/Language.es.resx +++ b/mRemoteV1/Resources/Language/Language.es.resx @@ -59,7 +59,7 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -105,17 +105,17 @@ - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - text/microsoft-resx 2.0 + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Acerca de @@ -1154,7 +1154,7 @@ Ver el articulo de soporte de Microsoft en http://support.microsoft.com/kb/81183 Sin SmartSize - Sin actualizaciones dosponibles + Sin actualizaciones disponibles Está intentando cargar un archivo de conexión que ha sido creado con una versión muy antigua de mRemote, ésto puede causar un error en tiempo de ejecución. @@ -1224,7 +1224,7 @@ Ver el articulo de soporte de Microsoft en http://support.microsoft.com/kb/81183 Introduzca su dominio. - Seleccione si emplear composición de escrotorio o no. + Seleccione si emplear composición de escritorio o no. Seleccione si emplear suavizado de fuentes o no. @@ -1295,6 +1295,9 @@ Ver el articulo de soporte de Microsoft en http://support.microsoft.com/kb/81183 Seleccione si las impresoras locales deben ser mostradas en el host remoto. + + Seleccione si el portapapeles debe compartirse con el host remoto. + Seleccione si las tarjetas inteligentes deben presentarse a la máquina remota. @@ -1445,6 +1448,9 @@ Ver el articulo de soporte de Microsoft en http://support.microsoft.com/kb/81183 Impresoras + + Portapapeles + Tarjetas Inteligentes diff --git a/mRemoteV1/Resources/Language/Language.resx b/mRemoteV1/Resources/Language/Language.resx index 2073b5ed5..f697fc45e 100644 --- a/mRemoteV1/Resources/Language/Language.resx +++ b/mRemoteV1/Resources/Language/Language.resx @@ -181,7 +181,7 @@ Automatically get session information - Auto save every: + Auto save time in minutes (0 means disabled): Minutes (0 means disabled) @@ -293,7 +293,7 @@ Please use File - Open Connection File for normal connection files! The (RDP) Sessions feature requires that you have a copy of eolwtscom.dll registered on your system. mRemoteNG ships with this component but it is not registered automatically if you do not use the mRemoteNG Installer. To register it manually, run the following command from an elevated command prompt: regsvr32 "C:\Program Files\mRemoteNG\eolwtscom.dll" (where C:\Program Files\mRemoteNG\ is the path to your mRemoteNG installation). -If this check still fails or you are unable to use the (RDP) Sessions feature, please consult the mRemoteNG Forum at {0}. +If this check still fails or you are unable to use the (RDP) Sessions feature, please consult the at {0}. EOLWTSCOM was found and seems to be registered properly. @@ -302,7 +302,7 @@ If this check still fails or you are unable to use the (RDP) Sessions feature, p To use the Gecko Rendering Engine you need to have XULrunner 1.8.1.x and the path to the installation set in your Options. You can download XULrunner 1.8.1.3 here: ftp://ftp.mozilla.org/pub/xulrunner/releases/1.8.1.3/contrib/win32/ When you are finished downloading extract the package to a path of your choice. Then in mRemoteNG go to Tools - Options - Advanced and enter the correct path in the XULrunner path field. -If you are still not able to pass this check or use the Gecko Engine in mRemoteNG please consult the mRemoteNG Forum at {0}. +If you are still not able to pass this check or use the Gecko Engine in mRemoteNG please consult the at {0}. GeckoFx was found and seems to be installed properly. @@ -311,7 +311,7 @@ If you are still not able to pass this check or use the Gecko Engine in mRemoteN ICA requires that the XenDesktop Online Plugin is installed and that the wfica.ocx library is registered. You can download the client here: http://www.citrix.com/download/ If you have the XenDesktop Online Plugin installed and the check still fails, try to register wfica.ocx manually. To do this open up the run dialog (Start - Run) and enter the following: regsvr32 "c:\Program Files\Citrix\ICA Client\wfica.ocx" (Where c:\Program Files\Citrix\ICA Client\ is the path to your XenDesktop Online Plugin installation). -If you are still not able to pass this check or use ICA in mRemoteNG please consult the mRemoteNG Forum at {0}. +If you are still not able to pass this check or use ICA in mRemoteNG please consult the at {0}. All ICA components were found and seem to be registered properly. @@ -329,7 +329,7 @@ Please make sure that either you have the Putty.exe in your mRemoteNG directory For RDP to work properly you need to have at least Remote Desktop Connection (Terminal Services) Client 8.0 installed. You can download it here: http://support.microsoft.com/kb/925876 -If this check still fails or you are unable to use RDP, please consult the mRemoteNG Forum at {0}. +If this check still fails or you are unable to use RDP, please consult the at {0}. All RDP components were found and seem to be registered properly. @@ -338,7 +338,7 @@ Remote Desktop Connection Control Version {0} VNC requires VncSharp.dll to be located in your mRemoteNG application folder. Please make sure that you have the VncSharp.dll file in your mRemoteNG application folder (usually C:\Program Files\mRemoteNG\). -If you are still not able to pass this check or use VNC in mRemoteNG please consult the mRemoteNG Forum at {0}. +If you are still not able to pass this check or use VNC in mRemoteNG please consult the at {0}. All VNC components were found and seem to be registered properly. @@ -836,7 +836,7 @@ See the Microsoft Support article at http://support.microsoft.com/kb/811833 for Import/Export - An error occurred while importing the file, "{0}". + An error occurred while importing the file "{0}". Import failed @@ -863,7 +863,7 @@ See the Microsoft Support article at http://support.microsoft.com/kb/811833 for Import from Port Scan - Import from .RDP file(s) + Import from RDP file(s) Inactive @@ -959,13 +959,13 @@ See the Microsoft Support article at http://support.microsoft.com/kb/811833 for Released under the GNU General Public License (GPL) - seconds + Seconds Select a panel from the list below or click New to add a new one. Click OK to continue. - Server Status: + Server status: Database: @@ -1106,7 +1106,7 @@ See the Microsoft Support article at http://support.microsoft.com/kb/811833 for mRemoteNG Help - Jump To + Jump to Launch External Tool @@ -1265,10 +1265,10 @@ See the Microsoft Support article at http://support.microsoft.com/kb/811833 for No - No Compression + No сompression - No Ext. App specified. + No ext. app specified. None @@ -1311,16 +1311,16 @@ If you run into such an error, please create a new connection file! Tabs - Next Tab + Next tab - Previous Tab + Previous tab - Modify Shortcut + Modify shortcut - Keyboard Shortcuts + Keyboard shortcuts Testing... @@ -1472,6 +1472,9 @@ If you run into such an error, please create a new connection file! Select whether local printers should be shown on the remote host. + + Select whether clipboard should be shared. + Select whether local smart cards should be available on the remote host. @@ -1527,10 +1530,10 @@ If you run into such an error, please create a new connection file! Server Authentication - Authentication Mode + Authentication mode - Automatic Resize + Automatic resize Cache Bitmaps @@ -1631,6 +1634,9 @@ If you run into such an error, please create a new connection file! Printers + + Clipboard + Smart Cards @@ -2401,7 +2407,7 @@ mRemoteNG will now quit and begin with the installation. Choose the Sound Quality provided by the protocol: Dynamic, Medium, High - Sound Quality + Sound quality Download Completed! @@ -2449,7 +2455,7 @@ mRemoteNG will now quit and begin with the installation. Select whether to receive an alert after the RDP session disconnects due to inactivity - Alert on Idle Disconnect + Alert on Idle disconnect Password must contain at least {0} of the following characters: {1} @@ -2482,13 +2488,13 @@ mRemoteNG will now quit and begin with the installation. Log these message types - Choose Path + Choose path - Open File + Open file - Use Default + Use default Logging @@ -2569,7 +2575,7 @@ This page will walk you through the process of upgrading your connections file o Do you really want to delete the theme? - Enable Themes + Enable themes New theme name @@ -2584,16 +2590,16 @@ This page will walk you through the process of upgrading your connections file o Warning: Restart is required to disable the themes or to completely apply a new one - No themes are loaded, check that the default mremoteNG themes exist in the slash themes folder + No themes are loaded, check that the default mRemoteNG themes exist in the 'themes' folder Could not find external tool with name "{0}" - Create a New Configuration File + Create a New Connection File - - The Configuration File is Missing. + + The connection file could not be found. Import an Existing File @@ -2623,12 +2629,93 @@ This page will walk you through the process of upgrading your connections file o Filter search matches in connection tree - Test Connection + Test connection - Read Only: + Read only: Use UTF8 encoding for RDP "Load Balance Info" property + + Timeout (seconds) + + + Working directory: + + + Run elevated + + + Run elevate + + + Show on toolbar column + + + Try to integrate + + + Working directory + + + Lock toolbar positions + + + Multi SSH toolbar + + + Import sub OUs + + + Lock toolbar positions + + + Multi SSH toolbar + + + Advanced security options + + + mRemoteNG Options + + + Use UTF8 encoding for RDP "Load Balance Info" property + + + Create an empty panel when mRemoteNG starts + + + Must Be Between 0 and 255 + + + Out Of Range + + + Delete... + + + Reconnect All Connections + + + UltraVNC SingleClick + + + Disconnect Tabs To The Right + + + Disconnect All But This + + + Are you sure you want to close all connections except for "{0}"? + + + Are you sure you want to close all connections to the right of "{0}"? + + + An error occurred while trying to reconnect to RDP host '{0}' + + + An error occurred while trying to change the connection resolution to host '{0}' + \ No newline at end of file diff --git a/mRemoteV1/Resources/Language/Language.ru.resx b/mRemoteV1/Resources/Language/Language.ru.resx index b3ac83eed..397583444 100644 --- a/mRemoteV1/Resources/Language/Language.ru.resx +++ b/mRemoteV1/Resources/Language/Language.ru.resx @@ -1,6 +1,6 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + О программе - + Активно - + Активность - + Новое подключение - + Новая папка - + AddNodeFromXML не удалось! - + AddNodesFromSQL не удалось! - - Разрешить только один экземпляр приложения (требуется перезапуск) + + Разрешить только один экземпляр приложения (требуется перезапуск mRemoteNG) - + Всегда - + Подключаться, даже если не прошел проверку - + Всегда показывать диалог выбора панели при открытии подключения - + Всегда показывать панель закладок - + Всегда показывать значок в системном трее - + Спросить позже - + Настроить параметры сейчас - + Использовать рекомендуемые параметры - + {0} автоматически проверяет наличие обновлений с новыми возможностями и исправлениями ошибок. Рекомендуется разрешить {0} еженедельную проверку обновлений. - + Параметры автоматического обновления - + Вид - + Автоматически получать информацию о сессии - + Автосохранение каждые: - + минут (0 означает отключено) - + Текущая версия - - &Обзор ... + + &Обзор... - + &Отменить - - Измененить + + Изменить - + &Закрыть - + Наследовать по умолчанию - + Свойства по умолчанию - + Отключиться - + Значок - + &Импорт - + Наследование - + Запуск PuTTY - + &Новая - - &ОК + + &Да - + Свойства - + &Сканировать - + &Стоп - + Проверка прокси - + Вы не можете импортировать обычный файл подключения. Для обычных файлов подключений используйте Файл - Открыть подключение! - + Не удается запустить сканирование портов, неверный формат IP! - + Внешний вид - + Подключение - + Учетные данные - + Вид - + Шлюз - + Общие - + Разное - + Протокол - + Локальные ресурсы - + Всегда показывать это окно при запуске - + Обновление - + Ошибка проверки! - + Успешно проверено! - + Для (RDP) сессий должна быть зарегистрирована в системе eolwtscom.dll. - mRemoteNG загрузится с этим компонентом, но не зарегистрирует его автоматически. - Чтобы зарегистрировать его вручную: Откройте (Пуск - Выполнить) и введите следующую команду: regsvr32 "C:\Program Files\mRemoteNG\eolwtscom.dll" (где C:\Program Files\mRemoteNG\ это путь к установленному mRemoteNG). - Если у вас все же не получается зарегистрировать компонент для RDP - обратитесь на форум mRemoteNG http://forum.mremoteng.org/ +mRemoteNG загрузится с этим компонентом, но не зарегистрирует его автоматически. +Чтобы зарегистрировать его вручную: Откройте (Пуск - Выполнить) и введите следующую команду: regsvr32 "C:\Program Files\mRemoteNG\eolwtscom.dll" (где C:\Program Files\mRemoteNG\ это путь к установленному mRemoteNG). +Если у вас все же не получается зарегистрировать компонент для RDP - обратитесь на {0}. - + EOLWTSCOM был найден и зарегистрирован. - + Для использования движка Gecko у Вас должен быть установлен XULRunner 1.8.1.x - Вы можете скачать XULRunner 1.8.1.3 здесь: ftp://ftp.mozilla.org/pub/xulrunner/releases/1.8.1.3/contrib/win32/ - После загрузки извлеките пакет в любую папку. Потом в mRemoteNG перейдите в меню Инструменты - Опции - Дополнительно и введите правильный путь в поле Путь XULRunner. - Если у вас ничего не получилось обратитесь на форум mRemoteNG http://forum.mremoteng.org/ +Вы можете скачать XULRunner 1.8.1.3 здесь: ftp://ftp.mozilla.org/pub/xulrunner/releases/1.8.1.3/contrib/win32/ +После загрузки извлеките пакет в любую папку. Потом в mRemoteNG перейдите в меню Инструменты - Опции - Дополнительно и введите правильный путь в поле Путь XULRunner. +Если у вас ничего не получилось обратитесь на {0}. - + GeckoFx был найден и установлен правильно. - - ICA требуется установленный XenDesktop Online Plugin и зарегистрированная библиотека wfica.ocx. Вы можете скачать клиент здесь: http://www.citrix.com/download/ - Если у вас есть установленный XenDesktop Online Plugin и ничего не работает, попробуйте зарегистрировать wfica.ocx вручную. - Для этого откройте (Пуск - Выполнить) и введите следующую команду: regsvr32 "C:\Program Files\Citrix\ICA Client\wfica.ocx" (где C:\Program Files\Citrix \ICA Client\ это путь к XenDesktop Online Plugin). - Если у вас все же не работает ICA в mRemoteNG обратитесь на форум mRemoteNG http://forum.mremoteng.org/ " + + ICA требуется установленный XenDesktop Online Plugin и зарегистрированная библиотека wfica.ocx. Вы можете скачать клиент здесь: http://www.citrix.com/download/ +Если у вас есть установленный XenDesktop Online Plugin и ничего не работает, попробуйте зарегистрировать wfica.ocx вручную. +Для этого откройте (Пуск - Выполнить) и введите следующую команду: regsvr32 "C:\Program Files\Citrix\ICA Client\wfica.ocx" (где C:\Program Files\Citrix \ICA Client\ это путь к XenDesktop Online Plugin). +Если у вас все же не работает ICA в mRemoteNG обратитесь на {0}. - + Все компоненты ICA были найдены и зарегистрированы. - Citrix ICA Client Control версии {0} +Citrix ICA Client Control версии {0} - + установлен неправильно - + SSH, Telnet, Rlogin и RAW протоколам нужен для работы PuTTY. PuTTY поставляется с каждым mRemoteNG и находится в папке с программой. - Убедитесь, что putty.exe есть в папке с mRemoteNG (по умолчанию: C:\Program Files\mRemoteNG\), или что вы указали правильный путь к исполняемому файлу PuTTY в Инструменты - Опции - Дополнительно - Путь к PuTTY) +Убедитесь, что putty.exe есть в папке с mRemoteNG (по умолчанию: C:\Program Files\mRemoteNG\), или что вы указали правильный путь к исполняемому файлу PuTTY в Инструменты - Опции - Дополнительно - Путь к PuTTY) - - Испольняемый файл PuTTY найден и готов к использованию. + + Исполняемый файл PuTTY найден и готов к использованию. - + Для правильной работы RDP необходимо иметь установленный Remote Desktop Connection (Terminal Services Client) 8.0. Вы можете получить его здесь: https://support.microsoft.com/kb/2592687 - Если у вас есть установленный RDP 8.0 и подключиться не удается, попробуйте зарегистрироваться mstscax.dll вручную. Для этого откройте (Пуск - Выполнить) и введите следующую команду: regsvr32 "C:\Windows\system32\mstscax.dll" (где C:\ваш системный диск). - Если у вас возникли проблемы при работе с RDP обратитесь на форум mRemoteNGhttp://forum.mremoteng.org/ +Если у вас есть установленный RDP 8.0 и подключиться не удается, попробуйте зарегистрироваться mstscax.dll вручную. Для этого откройте (Пуск - Выполнить) и введите следующую команду: regsvr32 "C:\Windows\system32\mstscax.dll" (где C:\ваш системный диск). +Если у вас возникли проблемы при работе с RDP обратитесь на {0}. - + Все RDP компоненты были найдены и зарегистрированы. - Remote Desktop Connection, Control Version {0} +Remote Desktop Connection, Control Version {0} - + VNC требуется VncSharp.dll который находится в папке с mRemoteNG. - Убедитесь, что у вас есть VncSharp.dll в папке mRemoteNG (обычно C:\Program Files\mRemoteNG\). - Если у вас все же не работает VNC в mRemoteNG обратитесь на форум mRemoteNGhttp://forum.mremoteng.org/ +Убедитесь, что у вас есть VncSharp.dll в папке mRemoteNG (обычно C:\Program Files\mRemoteNG\). +Если у вас все же не работает VNC в mRemoteNG обратитесь на {0}. - + Все VNC компоненты были найдены и зарегистрированы. - VncSharp Control Version {0} +VncSharp Control Version {0} - + Автоматически пытаться восстановить связь при отключении от сервера (только RDP и ICA) - + Домен - + Больше не показывать это сообщение. - + Наследование - + Пароль - + Требуется авторизация - + Использовать собственный путь к PuTTY: - + Переподключиться, когда будет готово - + Использовать прокси-сервер - + Пользователь - + Ждать выхода - + Проверить - + Проверять наличие обновлений при запуске - + Проверить - + При запуске проверять правильность установки компонентов - + Выбрать панель перед подключением - + Закрытые порты - + Свернуть все папки - + Аргументы - + Отображаемое имя - + Имя файла - + Имя хоста/IP - + Сообщение - + Пользователь - + Ждать выхода - + Невозможно разобрать аргументы командной строки! - - {0} обнаружено что на этой системе работает утилита Lenovo Auto Scroll. Известно, что эта утилита вызвает проблемы с {0}. Рекомендуется отключить или удалить ее. + + {0} обнаружено что на этой системе работает утилита Lenovo Auto Scroll. Известно, что эта утилита вызывает проблемы с {0}. Рекомендуется отключить или удалить ее. - + Обнаружена проблема совместимости - + Проверка компонентов - + Ошибка btnIcon_Click! - + Ошибка ShowHideGridItems! - + Ошибка IconMenu_Click! - + Ошибка свойства Grid opject! - + Ошибка SetHostStatus! - + Ошибка pGrid_PopertyValueChanged! - + Ошибка загрузки Config UI! - + Хотите закрыть подключение: "{0}"? - + Хотите закрыть панель "{0}"? Все ее подключения также будут закрыты. - + Хотите удалить внешний инструмент, "{0}"? - + Хотите удалить {0} выбранные внешние инструменты? - + Хотите удалить подключение, "{0}"? - + Хотите удалить пустую папку, "{0}"? - + Хотите удалить папку "{0}"? Любые папки или подключения, которые она содержит также будут удалены. - + Хотите закрыть все открытые подключения? - + Вы действительно хотите сбросить панели в настройки по умолчанию? - + Подключиться - + Подключение в полноэкранном режиме - + Подключение... - + Журнал подключений - + Подключение к системе "{0}" через "{1}" созданого пользователя "{2}" (Описание: "{3}"; Пользователь: "{4}") - + Подключиться не удалось! - + Журнал событий ErrorOccured - + Открыть подключение не удалась! - + Невозможно открыть подключение: имя хоста не указано! - + Ошибка RDP! Код ошибки: {0} Описание ошибки: {1} - + Подключения - + Не удается установить порт по умолчанию! - + Не удалось создать резервную копию файла подключений! - + Не удалось импортировать подключения в файл! - + Файл подключений "{0}" невозможно загрузить! - + Файл подключений "{0}" невозможно загрузить! Создайте новый файл подключений. - + Невозможно сохранить файл подключений! - + Невозможно сохранить файл в качестве подключения "{0}"! - + Подключение к сеансу пользователя (Сеанс консоли) - + Подключение (с параметрами) - + Подключение к {0} по {1} закрыто пользователем {2}. - + Подключение к {0} по {1} закрыто пользователем {2}. (Описание: "{3}"; Пользователь: "{4}") - + Подключение закрыто - + Подключение закрыть не удалось! - + Не удается создать новый файл подключений! - + Не удалось найти элемент управления ToolStrip в FilteredPropertyGrid. - + Установленная версия - + Тема по умолчанию - + Обнаружение - + Не подключать без проверки - - Двойной щелчок для закрытия вкладки + + Двойной щелчок для закрытия вкладки - + Загрузка и установка - + Дублировать - + Хотите продолжить без пароля? - + Использовать пустое имя пользователя пароль или домен: - + 128-бит - + 128-бит (только при входе) - + 40-бит - + 56-бит - + Основное - + Шифровать файл подключения - + Конечный IP - - Конечн. порт + + Конечный порт - + Ошибка добавления внешнего приложения на Панель (frmMain). {0} - + Ошибка AddFolder (UI.Window.Tree). {0} - + Версия базы данных {0} не совместима с этой версией {1}. - + Ошибка CloneNode (Tree.Node). {0} - + Код ошибки {0}. - + Невозможно сохранить список подключений. - + Не удалось расшифровать. {0} - + Не удалось зашифровать. {0} - + Настройки системы безопасности Windows: "Использование системной криптографии FIPS-совместимых алгоритмов шифрования, хеширования и подписывания», включено. Эта установка не совместима с {0}. См. статью Microsoft Support на http://support.microsoft.com/kb/811833 для получения дополнительной информации. {0} будет закрыто. - + Ошибки - + Ошибка загрузки файла соединения.{0}{0}{2}{0}{3}{0}{0}Для предотвращения потери данных, {1} будет выполнен выход. - + Ошибка VerifyDatabaseVersion (Config.Connections.Save). {0} - + Раскрыть все папки - + Экспериментально - + Экспорт - - Экспорт mRemote / mRemoteNG XML + + Экспорт mRemote/mRemoteNG XML - + Внешнее Приложение - + Использованы значки [FAMFAMFAM] - + Все файлы (*.*) - + Файлы приложений (*. EXE) - + mRemote CSV-файлы (*. CSV) - + mRemote XML-файлы (*. XML) - + RDP-файлы (*. RDP) - + visionapp Remote Desktop 2008 CSV-файлы (*. CSV) - + Наследовать {0} - + Описание наследованного свойства: {0} - - Free + + Свободный - + Во весь экран - + Главная - + Получить информацию о подключении из SQL не удалось - + Ошибка при загрузке подключения "{0}" на "{1}". {2} - + Автопереподключение - + Соединение - - Свройства внешнего инструмента + + Свойства внешнего инструмента - + Файлы - + Хост - + Ошибка HTTP подключения! - + Не удается создать новое подключение HTTP! - + Изменение HTTP документа не удалось! - + Не удалось задать параметры HTTP! - + Не удается создать новое подключение ICA! - + Не удалось загрузить ICA-плагин! - + Ошибка установки учетных данных ICA! - + Не удалось установить обработчик событий ICA! - + Не удалось задать параметры ICA! - + Ошибка установки разрешений ICA! - + Определить вкладки быстрых подключений, добавляя префикс «Quick:» - + Импорт из Active Directory - - Импорт / Экспорт + + Импорт/Экспорт - - Импорт mRemote / mRemoteNG XML + + Импорт mRemote/mRemoteNG XML - + Импорт из просканированных портов - - Импорт из. RDP-файла (ов) + + Импорт из RDP-файла (ов) - + Неактивный - + Информация - + mRemoteNG в актуальном состоянии - + Подключение не удалось! - + Не удалось завершить процесс внутреннего приложения! - + Внутренний инструмент: Ошибка получения фокуса! - + Обработчик Внутр. инструментов: {0} - + Не удалось завершить процесс внутреннего приложения! - + Панель обработчика событий: {0} - + Внутренний инструмент: Ошибка изменения размера! - + --- Внутреннее приложение --- - + Заголовок внешнего инструмента: {0} - + CTRL+ALT+DEL - + CTRL-ESC - + Адрес: - + Аргументы: - + История версий: - + При закрытии подключений: - + &Подключение: - - Отображаемое имя + + Отображаемое имя: - + Домен: - + Имя файла: - + Имя хоста: - + Опции: - + Пароль: - + Порт: - - Portable Edition + + Портативная версия - + Протокол: - + Нажмите на эту кнопку для настройки сессий PuTTY: - - Max. PuTTY && Integrated Ext. Apps wait time: + + Максимальное время ожидание PuTTY и внешнего приложения: - + Выпущено под лицензией GNU General Public License (GPL) - - сек + + Секунд - + Выберите панель из списка или нажмите кнопку Новая, чтобы создать новую. Нажмите кнопку OK, чтобы продолжить. - + Состояние сервера: - + База данных: - + База данных: - + Пользователь: - + Проверка: - + Язык - + (Автоопределение) - + {0} необходимо перезапустить, чтобы изменения языка вступили в силу. - + Загрузить из SQL не удалось! - + Загрузить из XML не удалось! - - Локал. файл + + Локальный файл - + Локальный файл не существует! - + Выход - + Записать в файл отчета не удалось! - + Невозможно сохранить отчет в папке назначения. - + Использовано Magic library от [Crownwood Software] - + О программе - + Добавить Панель подключения - + Проверка наличия обновлений - + Конфигурация - + Подключаться - + Панель подключений - + Подключения - + Подключения и конфигурация - + Копировать - + Ctrl-Alt-Del - + Ctrl-Esc - + Удалить... - - Удалить подключение ... + + Удалить подключение... - - Удалить Внешний инструмент... + + Удалить внешний инструмент... - + Удалить папку... - + Отключить - + Помочь проекту - + Дублировать - + Дубликат подключения - + Дублировать папку - + Дублировать вкладку - + Выход - + Внешние инструменты - + Внешние инструменты - + &Файл - + Во весь экран - + Во весь экран (RDP) - + &Справка - + Справка mRemoteNG - - Перейти к... + + Перейти к - + Запуск внешних инструментов - + Новый файл подключения - + Новый внешний инструмент - + Уведомления - + Скопировать все - + Удалить - + Удалить все - + Открыть файл подключения... - + Опции - + Вставить - + Сканер портов - + Панель Быстрое подключение - + Переподключение - + Обновить экран (VNC) - + Переименовать - + Переименовать подключение - + Переименовать папку - + Переименовать закладку - + Сообщить об ошибке - + Сброс - + Сохранить подключение - + Сохранить подключение как... - + Скриншот - + Менеджер скриншотов - + Отправить спец. клавиши (VNC) - + Сессии - + Сессии и скриншоты - + Показать текст справки - + Показать текст - - SmartSize (RDP / VNC) + + SmartSize (RDP/VNC) - + Передача файлов по SSH - + Начать чат (VNC) - + Форум поддержки - + &Инструменты - + Передача файлов (SSH) - + &Вид - + Просмотр (VNC) - + Веб-сайт - + Минимизировать в системный трей - + Вниз - + Вверх - + Мои текущие учетные данные (Windows учетные данные) - + Никогда - + Новое подключение - + Новая папка - + Новая панель - + Новый корень - + Новое название - + Нет - + Без сжатия - + Не указано внешнее приложение. - + Нет - + Нет - + Нормальный - + SmartSize недоступен - + Нет доступных обновлений - + Вы пытаетесь загрузить файл подключения, созданного с помощью очень ранней версии mRemote, это может привести к ошибке выполнения. Пожалуйста, создайте новый файл подключения! - + Открытие новой вкладки справа от выбранной вкладки - + Открытые порты - + Тема - - Удалить + + &Удалить - - Новая + + &Новая - + Название группы - + Защита паролем - + Пожалуйста, заполните все поля - + Не удалось загрузить панель Сканера портов! - + (Эти свойства будут сохранены только если вы выберете mRemote/mRemoteNG XML в качестве выходного формата файлов!) - + Введите имя хоста или IP к которому вы хотите подключиться. - + Переключить все наследуемые параметры. - + Выберите используемый уровень авторизации. - + Выберите способ авторизации на сервере VNC. - + Выберите использовать или нет, кэширование графики. - + Выберите качество цвета, которое будет использоваться. - + Выберите значение сжатия, которое будет использоваться. - + Введите здесь заметки или описания для подключения. - + Выберите Да, если хотите использовать тему Рабочего стола на удаленном хоста. - + Выберите Да, если хотите использовать обои Рабочего стола на удаленном хосте. - + Введите имя домена. - + Использование композиции Рабочего стола на удаленном хосте. - + Использование сглаживания шрифтов. - + Режим кодирования. - + Шифрование на удаленном хосте. - + Внешний инструмент, который нужно запустить. - + Внешний инструмент, который нужно запустить на удаленном компьютере после отключения. - + Внешний инструмент, который нужно запустить на удаленном компьютере до подключения. - + Значок, который будет отображаться при подключении к хосту. - + Введите МАС-адрес удаленного хоста, если вы хотите использовать его во внешнем инструменте. - + Это имя, которое будет отображаться в дереве подключений. - - Устанавить панель, в которой будет открыто подключение. + + Установить панель, в которой будет открыто подключение. - + Введите пароль. - + Введите порт выбранного протокола. - + Выберите протокол, который должен использоваться для подключения. - + Выберите сессию PuTTY, которая будет использоваться при подключении. - - Определите доменное имя, для подключения к шлюзу Служб терминалов + + Определите доменное имя, для подключения к шлюзу Служб терминалов. - + Определите имя хоста шлюза Служб терминалов. - + Укажите, когда использовать шлюз Служб терминалов. - + Укажите, следует ли войти на шлюз, использующий то же имя пользователя и пароль подключения. - + Укажите имя пользователя, которому разрешено подключаться к шлюзу Служб терминалов. - + Укажите, будут ли доступны локальные диски на удаленном хосте. - + Укажите, будут ли перенаправлены локальные комбинации клавиш (например, Alt-Tab) на удаленный хост. - + Укажите, будут ли доступны локальные порты (т.е. COM, LPT) на удаленном хосте. - + Укажите, будут ли локальные принтеры доступны на удаленном хосте. - + Укажите, будут ли локальные смарт-карты доступны на удаленном хосте. - + Укажите, будет ли перенаправлен удаленный звук на локальный компьютер. - + Выберите один из доступных движков рендеринга, который будет использоваться для отображения HTML. - + Выберите разрешение экрана в дюймах или режим отображения для этого подключения - + Выберите SmartSize. - + Подключение к текущему сеансу удаленного пользователя. - + Использовать поставщика поддержки безопасности (CredSSP) для проверки подлинности учетных данных, если он доступен. - + Введите любую информацию. - + Введите имя пользователя. - + Если вы хотите установить режим Просмотра - выберите Да. - + Введите адрес прокси-сервера. - + Введите пароль для авторизации на прокси-сервере. - + Введите порт прокси-сервера. - + Если вы используете прокси для туннелирования VNC подключений, выберите тип туннелирования. - + Введите имя пользователя для авторизации на прокси-сервере. - + Имя хоста / IP - + Все - + Авторизация - + Режим авторизации - + Кэш графики - + Цвета - + Сжатие - + Описание - + Показать темы - + Показать обои - + Домен - + Композиция рабочего стола - + Шрифты - + Кодирование - + Шифрование - + Внешний инструмент - + Внеш. Инстр. После - + Внеш. Инстр. До - + Значок - + MAC-адрес - + Имя - + Имя вкладки - + Пароль - + Порт - + Протокол - + Сессии PuTTY - + Шлюз Домена - + Хост Шлюза - + Пароль шлюза Служб терминалов - + Шлюз - + Учетные данные шлюза - + Имя пользователя шлюза - + Диски - + Комбинации клавиш - + Порты - + Принтеры - + Смарт-карты - + Звуки - + Рендеринг - + Размер экрана - + SmartSize режим - + Сеанс консоли - + Использовать проверку подлинности CredSSP - + Дополнительно - + Пользователь - + Только Просмотр - + Адрес прокси - + Пароль Прокси - + Порт Прокси - + Тип Прокси - + Пользователь Прокси - + Протокол событий Отключен. Сообщение: {0} - + Протокол событий Отключение не удалось. {0} - + Протокол импорта - + Проверка прокси - неудачна! - + Проверка Прокси - удачна! - + Подключение не удалось! - + Завершить Putty - не удалось! - + Не удается установить фокус! - + Получить сессию Putty не удалось! - + Обработчик Putty: {0} - + Убить процесс Putty не удалось! - + Панель обработчиков: {0} - + Ошибка изменения размера окна Putty! - + Сохраненные сессии PuTTY - + Настройки PuTTY - + Показать настройки PuTTY не удалось! - + Не удалось запустить Putty! - + --- PuTTY --- - + Заголовок PuTTY: {0} - + Быстрое: {0} - + Быстрое подключение - + Ошибка добавления Быстрого подключения! - - Созданить быстрое подключение не удалось + + Создать быстрое подключение не удалось - + Предупреждать при закрытии подключений - + Предупреждать меня только при выходе из mRemoteNG - + Предупреждать меня только при закрытии нескольких подключений - + Не предупреждать при закрытии подключений - + RAW - + RDP - + 16777216 цв. (24-бит) - + 256 цв. (8-бит) - + 32768 цв. (15-бит) - + 16777216 цв. (32-бит) - + 65536 цв. (16-бит) - + RDP Добавить разрешение не удалось! - + RDP Добавить разрешение не удалось! - + Добавить сессию не удалось - + Закрыть подключение RDP не удалось! - + Не удается создать RDP подключение, пожалуйста, проверьте настройки mRemoteNG. - + Отключить мигание курсора - + Отключить тень курсора - + Отключить отображение окна при перетаскивании - + Отключить Анимацию - + Отключить Темы - + Отключить обои Рабочего стола - + RDP отключен! - + RDP не удалось отключить, попробуйте закрыть его! - + Внутренняя ошибка: код 1. - + Внутренняя ошибка: код 2. - + Внутренняя ошибка: код 3. Это недопустимый режим. - + Внутренняя ошибка: код 4. - + Произошла неисправимая ошибка во время подключения клиента. - + Невозможно получить GetError (Критическая ошибка) - + Произошла неизвестная критическая ошибка RDP. Код ошибки {0}. - + Произошла ошибка из-за нехватки памяти. - + Неизвестная ошибка. - + При создании окна произошла ошибка. - + Ошибка инициализации Winsock. - + Не удалось импортировать RDP файл! - + В окне - + RDP: Ошибка получения фокуса! - + Шлюз Служб терминалов поддерживается. - + Шлюз Служб терминалов не поддерживается! - + Ошибка сессии! - - К-ство переподключений RDP: + + Количество переподключений RDP: - + RDP: Установить уровень проверки подлинности не удалась! - + RDP: Не удалось использовать консольную сессию! - + Настройка переключения консолей для RDC {0}. - + Ошибка установки учетных данных RDP! - + Ошибка RDP SetEventHandlers! - + Ошибка установки шлюза RDP! - + Ошибка RDP SetPerformanceFlags! - + Не удалось задать порт RDP! - + Не удалось задать параметры RDP! - + Установить перенаправление в RDP не удалось! - + Установить перенаправление клавиш в RDP не удалось! - + Ошибка установки разрешения RDP! - + Smart Size - + Передать на этот компьютер - + Не воспроизводить - + Оставить на удаленном компьютере - + Не удалось переключить RDP в режим Fullscreen! - + Не удалось переключить RDP в режим SmartSize! - + При запуске подключаться к предыдущим сессиям - + Обновление - - Удаленн. файл + + Удалить файл - + Удалить все - + Переименовать - + Rlogin - + Сохранить - + Сохранить все - + Перед загрузкой нового подключения, хотите сохранить текущий файл подключения? - + Сохранять подключения при выходе - + Файл Graphics Interchange Format (GIF.) | *. GIF | Файл Joint Photographic Experts Group (JPEG.) | *. JPEG | Файл Joint Photographic Experts Group (JPG.) | *. JPG | Файл Portable Network Graphics (PNG). | *. PNG - + Экран - + Скриншот - + Скриншоты - + Поиск - + Отправить... - + Получить фоновую сессию не удалось - + Завершение фоновой сессии не удалось - + Установить имя хоста, как отображаемое имя при создании новых подключений - + Настройка основной текстовой формы не удалось - + Не удалось сохранить настройки, или разместить значок в системном трее! - + Показывать подсказки в дереве подключений - + Показывать в заголовке окна полный путь к файлу подключений - + Показать сведения о входе в названии вкладок - + Показывать протокол в названии вкладок - + Один клик по подключению для его открытия - + Один клик по открытому подключению переключается на него - + Вид - - Free + + Свободный - + SmartSize недоступен - + Socks 5 - + Сортировать - + По возрастанию (A-Z) - + По убыванию (Z-A) - + Специальные клавиши - + Для дополнительной информации см. справку - Начало работы - конфигурация SQL! - - SQL Server: + + SQL Server - + Доступно обновление для SQL! Обновите подключения. - + SSH version 1 - + SSH version 2 - + Фоновая передача по SSH - не удалась! - - Передано успешо! + + Передано успешно! - + Передача по SSH завершена с ошибкой (UI.Window.SSHTransfer)! - + SSH ошибка передачи. - + Начальный IP - - Начальн. порт + + Начальный порт - + Запуск / Выход - + Статус - + Переключится на панель уведомлений: - + Дополнительно - + Внешний вид - + Вкладки и панели - + Обновления - + Telnet - + Установить вручную: - + Конфигурация - + Подключения - + Общие - + Цвет фона панели конфигурации. - + Цвет текста категории на панели конфигурации. - + Цвет линий сетки на панели конфигурации - + Цвет фона области справки панели конфигурации. - + Цвет текста в области справки панели конфигурации. - + Цвет текста в панели конфигурации. - + Цвет фона панели подключений. - + Цвет текста в панели подключений. - + Цвет линий дерева на панели подключений. - + Цвет фона меню. - + Цвет текста в меню. - + Цвет фона поля поиска. - + Цвет текста в поле поиска. - + Цвет текста подсказки в поле поиска. - + Цвет фона панели инструментов. - + Цвет текста в панели инструментов. - + Цвет фона главного окна. - + Цвет фона панели конфигурации - + Цвет текста категории панели конфигурации - + Цвет линий сетки панели конфигурации - + Цвет фона справки панели конфигурации - + Цвет текста справки панели конфигурации - + Цвет текста панели конфигурации - + Цвет фона панели подключений - + Цвет текста панели подключений - + Цвет линий дерева панели подключений - + Цвет фона меню - + Цвет текста меню - + Цвет фона поля поиска - + Цвет текста поля поиска - + Цвет текста подсказки поля поиска - + Цвет фона панели инструментов - + Цвет текста панели инструментов - + Цвет фона окна - + Ошибка ({0}) - + Информация ({0}) - + Пароль - + Выбор Панели - + Предупреждение ({0}) - + Передача - + Передача не удалась! - + Интеграция - + Тип - + Ultra VNC Repeater - + Порт UltraVNC SingleClick: - + Снимите свойства, которые не хотите сохранять! - + Безымянный тема - + Требуется обновление mRemoteNG - - mRemoteNG может периодически подключаться к сайту mRemoteNG для проверки наличия обновлений. + + mRemoteNG может периодически подключаться к сайту mRemoteNG для проверки наличия обновлений. - + Не удалось завершить проверку обновлений! - - Не удалось проверить наличие обновлений! + + Портативная версия mRemoteNG не поддерживает автообновление. - - mRemoteNG Portable Edition не поддерживает автообновление. - - - Ошибка при удалении файла обновления! - - + Загрузка завершена! mRemoteNG сейчас прекратит работу и начнет процесс установки обновлений. - + Не удалось завершить загрузку! - + Не удалось скачать обновление! - - Каждые {0} дн. + + Каждые {0} дней - + Ежедневно - + Ежемесячно - + Еженедельно - - Ошибка при запуске обновления! - - + Использовать другое имя пользователя и пароль - - Использовать только панель уведомлений (без всплывающих подсказок) - - + Пользователь - + Использовать те же имя пользователя и пароль - + Использовать смарт-карты - + Использовать SQL Server для загрузки и сохранения подключений - + Версия - + VNC - + Не удалось отключить VNC! - + Не удалось обновить экран VNC! - + Не удалось послать VNC спец. клавиши! - + Не удалось установить обработчик событий VNC! - + Не удалось задать параметры VNC! - - Не удалось начать VNC-чат! + + Не удалось начать VNC чат! - + Не удалось переключить VNC в SmartSize! - + Не удалось переключить VNC в режим Просмотра! - + Предупреждать, если не прошел проверку - + Предупреждения - + Использовано DockPanel Suite от [Weifen Luo] - + http://sourceforge.net/projects/dockpanelsuite/ - - Запись в лог-файл (mRemoteNG.log) - - + Путь XULRunner: - + Да - + Переподключить все открытые соединения + + + Рабочий каталог: + + + &Запуск + + + Выполнить с повышенными правами + + + Выполнить с повышенными правами + + + Отобразить на панели инструментов: + + + Отобразить на панели инструментов + + + Попробовать интегрировать + + + Рабочий каталог + + + Экспорт в файл... + + + Импорт из &файла... + + + &Импорт + + + Закрепить позицию панели инструментов + + + Панель инструментов SSH + + + Назначенные учетные данные + + + Экспортировать все + + + Файл экспорта + + + Пункт импорта + + + Экспорт свойств + + + Экспорт выбранного соединения + + + Экспорт выбранной папки + + + Формат файла: + + + Импорт подразделений + + + Используйте кодировку UTF8 для свойства RDP "Информация о балансе нагрузки" + + + Время ожидания в секундах: + + + Active Directory + + + В&ыход {0} + + + &Открыть файл подключения + + + &Попробуй еще раз + + + Подключение без учетных данных + + + Не подключайтесь к сеансу консоли + + + PuTTY не может быть запущен. + + + Новый внешний инструмент + + + http://www.famfamfam.com/ + + + Все импортируемые файлы + + + Файлы диспетчера соединений PuTTY + + + Файлы диспетчера подключений удаленного рабочего стола (* .rdg) + + + HTTP + + + Gecko (Firefox) + + + Internet Explorer + + + HTTPS + + + ICA + + + Произошла ошибка при импорте файла "{0}". + + + Импортировать не удалось + + + Under the root{0}{1}|Under the selected folder{0}{2} + + + Где бы вы хотели разместить импортируемое содержимое? + + + Место импорта + + + Не удалось загрузить информацию о соединении с SQL-сервера. + + + http://www.dotnetmagic.com/ + + + Извлечь + + + mRemoteNG CSV + + + mRemoteNG XML + + + &Удалить + + + &Новый + + + &Восстановить значения по умолчанию + + + Сбросить &все по умолчанию + + + Вкладки + + + Новая вкладка + + + Предыдущая вкладка + + + Изменить ярлык + + + Горячие клавиши + + + Тестирование... + + + Клавиатура + + + Оба пароля должны совпадать. + + + Пароль должен содержать не менее 3 символов. + + + Сканирование портов завершено. + + + Выберите, следует ли автоматически изменять размер соединения при изменении размера окна или при переключении полноэкранного режима. Требуется RDC 8.0 или выше. + + + Задает информацию о балансировке нагрузки для использования маршрутизаторами балансировки нагрузки для выбора лучшего сервера. + + + Автоматическое изменение размера + + + Информация о балансе нагрузки + + + Настройки сеанса PuTTY + + + Пароль для {0} + + + Ошибка проверки + + + Проверка обновлений... + + + Журнал изменений не может быть загружен. + + + Время ожидания соединения RDP + + + Этот узел уже находится в этой папке. + + + Не удается перетащить узел на себя. + + + Не удается перетащить родительский узел на дочерний. + + + Этот узел не перетаскивается. + + + Режим блочного шифрования + + + Механизм шифрования + + + Безопасность + + + Инициирование функции вывода ключей + + + Динамический + + + Высокий + + + Cредний + + + Выберите Качество звука, предоставляемое протоколом: Динамический, Средний, Высокий + + + Качество звука + + + Скачивание завершено! + + + Скачать + + + Количество минут для сеанса RDP, чтобы сидеть без дела перед автоматическим отключением (для неограниченного использования 0) + + + Минуты в режим ожидания + + + Приминить + + + Добавить + + + Редактор учетных данных + + + Менеджер учетных данных + + + Номер + + + Удалить + + + Заглавие + + + Выберите, какие учетные данные использовать для этого подключения. + + + Вы действительно хотите удалить учетную запись, {0}? + + + Не удалось найти запись учетных данных с идентификатором соответствия "{0}" для записи соединения с именем "{1}". + + + Выберите, следует ли получать оповещение после отключения сеанса RDP из-за неактивности + + + Предупреждение о отключении питания + + + Пароль должен содержать не менее {0} следующих символов: {1} + + + Пароль должен содержать не менее {0} символов нижнего регистра + + + Пароль должен содержать не менее {0} номер (а) + + + Пароль должен содержать не менее {0} символ верхнего регистра + + + Длина пароля должна быть между {0} и {1} + + + Выберите путь для файла журнала mRemoteNG + + + Отладка + + + Показывать эти типы сообщений + + + Путь к файлу журнала + + + Зарегистрируйте эти типы сообщений + + + Выберите путь + + + Открыть файл + + + Использовать по умолчанию + + + Логирование + + + Всплывающие окна + + + Войдите в каталог приложений + + + Разрешить однократно + + + Разрешить однократно + + + Не разрешать + + + Разрешить небезопасный сертификат для ссылки: {0}? + + + Разрешить небезопасный сертификат? + + + Выбранный репозиторий разблокирован + + + неверный пароль + + + Источник + + + Разблокирование + + + Разблокировать репозиторий учетных данных + + + Разблокировать + + + Запрос на разблокирование учетных записей при запуске + + + Полномочия + + + Обновить + + + Назад + + + Путь к файлу подключения + + + Создание и открытие нового файла + + + Открыть другой файл + + + В v1.76 мы внедрили систему управления учетными данными. Эта функция требует значительных изменений в том, как мы храним и взаимодействуем с учетными данными в mRemoteNG. Вам потребуется выполнить одностороннее обновление файла соединений mRemoteNG. + +На этой странице вы расскажете о процессе обновления файла подключений или предоставите возможность открыть другой файл подключений, если вы не хотите выполнять обновление. + + + Учетные данные недоступны + + + Вы действительно хотите удалить тему? + + + Включить темы + + + Новое название темы + + + Невозможно создать тему, имя уже присутствующее или специальные символы в названии + + + Введите новое название темы + + + Внимание: для отключения тем требуется перезапуск или полностью применить новый + + + Темы не загружены, проверьте, существуют ли по умолчанию темы mRemoteNG в папке «Темы» + + + Не удалось найти внешний инструмент с именем "{0}" + + + Создать новый файл подключения + + + Файл подключения не найден. + + + Импорт существующего файла + + + Использовать настраиваемый путь к файлу + + + Тестирование соединения + + + Сервер '{0}' не был доступен. + + + Соединение успешно + + + Ошибка входа для пользователя '{0}'. + + + База данных '{0}' недоступна. + + + Сохранять соединения после каждого редактирования + + + Фильтрация совпадений поиска в дереве соединений + + + Тестовое соединение + + + Только чтение: + + + Использовать кодировку UTF8 для свойства RDP «Информация о балансе загрузки» + + + Заблокировать позиции панели инструментов + + + Панель инструментов Multi SSH + + + Расширенные параметры безопасности + + + Параметры mRemoteNG + + + Создайте пустую панель при запуске mRemoteNG + + + Отключить остальные вкладки + + + Отключить вкладки справа + + + Хотите закрыть все подключения, кроме "{0}"? + + + Хотите закрыть все подключения справа от "{0}"? \ No newline at end of file diff --git a/mRemoteV1/Resources/Language/Language.zh-CN.resx b/mRemoteV1/Resources/Language/Language.zh-CN.resx index 8062adb7d..8c1f8a6cd 100644 --- a/mRemoteV1/Resources/Language/Language.zh-CN.resx +++ b/mRemoteV1/Resources/Language/Language.zh-CN.resx @@ -1,4 +1,4 @@ - + - + @@ -105,17 +105,17 @@ - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - text/microsoft-resx 2.0 + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 关于 @@ -123,6 +123,9 @@ 活动连接 + + 活动目录 + 活动 @@ -216,6 +219,9 @@ 继承 + + 启动(&L) + 启动PuTTY @@ -409,9 +415,18 @@ VncSharp 版本 {0} 等待退出 + + 退出{0}(&X) + 无法解析命令行参数! + + 打开一个连接文件(&O) + + + 再试一次(&T) + {0} 检测到联想Auto Scroll程序在本机上运行。该程序程序明确会导致问题 {0} 的出现。建议您禁用或卸载该程序。 @@ -559,6 +574,9 @@ VncSharp 版本 {0} 检测 + + 不要连接到控制台会话 + 身份验证失败时取消连接 @@ -583,6 +601,12 @@ VncSharp 版本 {0} 128位(仅用于登录) + + 40位 + + + 56位 + 基本 @@ -613,6 +637,9 @@ VncSharp 版本 {0} 无法保存连接列表。 + + PuTTY无法启动。 + 解密失败。{0} @@ -642,18 +669,48 @@ VncSharp 版本 {0} 导出 + + 导出所有内容 + + + 导出文件 + + + 导出项目 + 导出mRemote/mRemoteNG XML + + 导出属性 + + + 导出当前选定的连接 + + + 导出当前选定的文件夹 + + + 导出到文件(&E)... + 外部应用 + + 新建外部工具 + 内置图标由[FAMFAMFAM]制作 + + 文件格式(&F): + 所有文件(*.*) + + 所有可导入的文件 + 应用程序(*.exe) @@ -663,11 +720,17 @@ VncSharp 版本 {0} mRemote XML(*.xml) + + PuTTY连接管理器文件 + + + 远程桌面连接管理器文件(*.rdg) + RDP文件(*.rdp) - visionapp Remote Desktop 2008 CSV Files (*.csv) + visionapp远程桌面2008 CSV文件(* .csv) 继承 {0} @@ -735,12 +798,36 @@ VncSharp 版本 {0} ICA 分辨率设置失败! + + 通过添加前缀“快速:”来识别快速连接选项卡 + 导入 Active Directory 导入/导出 + + 导入文件“{0}”时发生错误。 + + + 导入失败 + + + 从文件导入(&F)... + + + 在根目录{0}{1}下|在所选文件夹{0}{2}下 + + + 您希望将导入的项目放在哪里? + + + 导入位置 + + + 导入(&I) + 导入mRemote/mRemoteNG XML @@ -876,6 +963,9 @@ VncSharp 版本 {0} 从SQL加载配置失败! + + 连接信息无法从SQL服务器加载。 + 从XML加载配置失败! @@ -1062,6 +1152,9 @@ VncSharp 版本 {0} 发送特殊键(VNC) + + 取回 + 会话 @@ -1164,6 +1257,39 @@ VncSharp 版本 {0} 打开端口 + + 删除(&D) + + + 新建(&N) + + + 重置为默认值(&R) + + + 全部重置为默认值(&A) + + + 标签 + + + 下一个标签 + + + 上一个标签 + + + 修改快捷方式 + + + 键盘快捷键 + + + 测试... + + + 键盘 + 主题 @@ -1179,9 +1305,18 @@ VncSharp 版本 {0} 密码保护 + + 两个密码必须匹配。 + + + 密码必须至少有3个字符。 + 请填写所有字段 + + 端口扫描完成。 + 无法载入端口扫描面板! @@ -1200,6 +1335,9 @@ VncSharp 版本 {0} 请选择VNC服务器的身份验证方式。 + + 在调整窗口大小时或在切换全屏模式时选择是否自动调整连接大小。需要RDC 8.0或更高版本。 + 请选择是否启用位图缓存功能。 @@ -1245,6 +1383,9 @@ VncSharp 版本 {0} 请选择连接到主机时所要显示的图标。 + + 指定负载均衡信息,供负载均衡路由器使用以选择最佳服务器。 + 请输入远程主机的MAC地址(如果您需要在外部工具中使用此项)。 @@ -1311,6 +1452,9 @@ VncSharp 版本 {0} 连接到远程主机的控制台会话。 + + 如果可用,请使用凭证安全支持提供程序(CredSSP)进行身份验证。 + 请在此随意输入任何你所需的信息。 @@ -1347,6 +1491,9 @@ VncSharp 版本 {0} 身份验证模式 + + 自动调整大小 + 位图缓存 @@ -1392,6 +1539,9 @@ VncSharp 版本 {0} 图标 + + 负载均衡信息 + MAC地址 @@ -1533,6 +1683,9 @@ VncSharp 版本 {0} PuTTY 会话已保存 + + PuTTY会话设置 + PuTTY 设置 @@ -1572,12 +1725,6 @@ VncSharp 版本 {0} 关闭连接时不需确认 - - RAW - - - RDP - 24位色 @@ -1755,9 +1902,6 @@ VncSharp 版本 {0} 重命名 - - Rlogin - 保存 @@ -1830,9 +1974,6 @@ VncSharp 版本 {0} 禁用窗口自适应 - - Socks 5 - 排序 @@ -1899,9 +2040,6 @@ VncSharp 版本 {0} 升级 - - Telnet - 以下: @@ -1914,6 +2052,57 @@ VncSharp 版本 {0} 常规 + + 配置面板的背景颜色。 + + + 配置面板中类别文本的颜色。 + + + 配置面板中网格线的颜色 + + + 配置面板的帮助区域的背景颜色。 + + + 配置面板帮助区域中文本的颜色。 + + + 配置面板中文本的颜色。 + + + 连接面板的背景颜色。 + + + 连接面板中文本的颜色。 + + + 连接面板中树形线的颜色。 + + + 菜单的背景颜色。 + + + 菜单中文本的颜色。 + + + 搜索框的背景颜色。 + + + 搜索框中文本的颜色。 + + + 搜索框中提示文本的颜色。 + + + 工具栏的背景颜色。 + + + 工具栏中文本的颜色。 + + + 主窗口的背景颜色。 + 配置面板背景色 @@ -1974,6 +2163,9 @@ VncSharp 版本 {0} 密码 + + {0}的密码 + 选择面板 @@ -1989,12 +2181,12 @@ VncSharp 版本 {0} 尝试进行集成 + + 在工具栏上显示 + 类型 - - Ultra VNC Repeater - UltraVNC SingleClick端口: @@ -2013,15 +2205,15 @@ VncSharp 版本 {0} 升级检查未完成! - - 升级检查失败! + + 检查失败 + + + 检查更新... mRemoteNG便携版目前不支持自动更新。 - - 升级文件删除失败! - 下载完成! mRemoteNG 将退出并安装更新。 @@ -2044,15 +2236,12 @@ mRemoteNG 将退出并安装更新。 每周 - - 升级启动失败! + + 更改日志无法下载。 使用不同的用户名和密码 - - 仅适用通知面板(不弹出消息窗口) - 用户 @@ -2068,9 +2257,6 @@ mRemoteNG 将退出并安装更新。 版本 - - VNC - VNC 连接断开失败! @@ -2104,13 +2290,324 @@ mRemoteNG 将退出并安装更新。 使用DockPanel Suite[Weifen Luo] - - 记录日志(mRemoteNG.log) - XULrunner路径: 确定 + + 重新连接所有打开的连接 + + + RDP连接超时 + + + 此节点已在此文件夹中。 + + + 无法将节点拖到自身上。 + + + 无法将父节点拖放到子节点上。 + + + 该节点不可拖动。 + + + 分组密码模式 + + + 加密引擎 + + + 安全 + + + 关键推导函数迭代 + + + 动态 + + + + + + + + + 选择由协议提供的声音质量:动态,中,高 + + + 音质 + + + 下载完成! + + + 下载 + + + RDP会话在自动断开连接之前闲置的分钟数(无限制使用0) + + + 空闲等待分钟数 + + + 接受 + + + 添加 + + + 凭据编辑器 + + + 凭证管理器 + + + 移除 + + + 标题 + + + 选择用于此连接的凭证。 + + + 您确定要删除凭据记录{0}吗? + + + 找不到名为“{1}”的连接记录的ID为“{0}”的凭证记录。 + + + 选择是否在RDP会话由于不活动而断开连接后收到警报 + + + 空闲断开警报 + + + 密码必须至少包含{0}个以下所示字符:{1} + + + 密码必须至少包含{0}个小写字符 + + + 密码必须至少包含{0}个数字 + + + 密码必须至少包含{0}大写字符 + + + 密码长度必须介于{0}和{1}之间 + + + 为mRemoteNG日志文件选择一个路径 + + + 调试 + + + 显示这些消息类型 + + + 日志文件路径 + + + 记录这些消息类型 + + + 选择路径 + + + 打开文件 + + + 使用默认 + + + 记录 + + + 弹出窗口 + + + 登录到应用程序目录 + + + 分配凭据 + + + 始终允许 + + + 允许一次 + + + 不允许 + + + 允许网址{0}的不安全证书? + + + 允许不安全的证书? + + + 选定的存储库已解锁 + + + 密码错误 + + + 资源 + + + 解锁 + + + 解锁凭据存储库 + + + 解锁 + + + 提示在启动时解锁凭据存储库 + + + 凭据 + + + 升级 + + + 后退 + + + 连接文件路径 + + + 创建并打开新文件 + + + 打开一个不同的文件 + + + 在v1.76中,我们引入了凭证管理系统。此功能要求我们在mRemoteNG中存储和交互凭据的方式发生重大变化。您将需要执行mRemoteNG连接文件的单向升级。 + +如果您不想执行升级,此页面将引导您完成升级连接文件的过程,或者让您有机会打开不同的连接文件。 + + + 凭据不可用 + + + 你真的想删除主题吗? + + + 启用主题 + + + 新主题名称 + + + 无法创建主题,名称已存在或名称中有特殊字符 + + + 输入新的主题名称 + + + 警告:需要重新启动才能禁用主题或完全应用新主题 + + + 未加载任何主题,请检查默认的mremoteNG主题是否存在于“主题”文件夹中 + + + 无法找到名称为“{0}”的外部工具 + + + 创建一个新的连接文件 + + + 无法找到连接文件。 + + + 导入现有文件 + + + 使用自定义文件路径 + + + 测试连接 + + + 服务器“{0}”无法访问。 + + + 连接成功 + + + 用户“{0}”登录失败。 + + + 数据库“{0}”不可用。 + + + 每次编辑后保存连接 + + + 在连接树中过滤搜索匹配 + + + 测试连接 + + + 只读: + + + 对RDP“负载均衡信息”属性使用UTF8编码 + + + 超时(秒) + + + 工作目录: + + + 运行已提升 + + + 运行提升 + + + 显示在工具栏上 + + + 尝试整合 + + + 工作目录 + + + 锁定工具栏位置 + + + 多SSH工具栏 + + + 导入子OU + + + 锁定工具栏位置 + + + 多SSH工具栏 + + + 高级安全选项 + + + mRemoteNG选项 + + + 对RDP“负载均衡信息”属性使用UTF8编码 + \ No newline at end of file diff --git a/mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd b/mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd index 8f2b79160..e9df6b67e 100644 --- a/mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd +++ b/mRemoteV1/Schemas/mremoteng_confcons_v2_6.xsd @@ -1,16 +1,16 @@  - + @@ -31,6 +31,7 @@ + diff --git a/mRemoteV1/Schemas/mremoteng_confcons_v2_7.xsd b/mRemoteV1/Schemas/mremoteng_confcons_v2_7.xsd index b8d378003..1ab3d981d 100644 --- a/mRemoteV1/Schemas/mremoteng_confcons_v2_7.xsd +++ b/mRemoteV1/Schemas/mremoteng_confcons_v2_7.xsd @@ -57,6 +57,7 @@ + @@ -103,6 +104,7 @@ + diff --git a/mRemoteV1/Security/Authentication/PasswordAuthenticator.cs b/mRemoteV1/Security/Authentication/PasswordAuthenticator.cs index 1d6904e87..83bf82a6d 100644 --- a/mRemoteV1/Security/Authentication/PasswordAuthenticator.cs +++ b/mRemoteV1/Security/Authentication/PasswordAuthenticator.cs @@ -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> _authenticationRequestor; - public Func 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> 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++; diff --git a/mRemoteV1/Security/IKeyProvider.cs b/mRemoteV1/Security/IKeyProvider.cs index ed46749ab..425351113 100644 --- a/mRemoteV1/Security/IKeyProvider.cs +++ b/mRemoteV1/Security/IKeyProvider.cs @@ -1,9 +1,10 @@ using System.Security; +using mRemoteNG.Tools; namespace mRemoteNG.Security { public interface IKeyProvider { - SecureString GetKey(); + Optional GetKey(); } } \ No newline at end of file diff --git a/mRemoteV1/Themes/ExtendedColorPalette.cs b/mRemoteV1/Themes/ExtendedColorPalette.cs index dfaa7e0c7..4ecc1c528 100644 --- a/mRemoteV1/Themes/ExtendedColorPalette.cs +++ b/mRemoteV1/Themes/ExtendedColorPalette.cs @@ -9,35 +9,14 @@ namespace mRemoteNG.Themes /// public class PseudoKeyColor { - private string key; - private Color value; public PseudoKeyColor(string _key, Color _value) { - key = _key; - value = _value; - } - public string Key - { - get - { - return key; - } - set - { - key = value; - } - } - public Color Value - { - get - { - return value; - } - set - { - this.value = value; - } + Key = _key; + Value = _value; } + public string Key { get; set; } + + public Color Value { get; set; } } @@ -48,15 +27,14 @@ namespace mRemoteNG.Themes { #region Private Variables //Collection for color values that are not loaded by dock panels (list, buttons,panel content, etc) - private Dictionary _extendedColors; - private Dictionary _default; + #endregion #region Constructors public ExtendedColorPalette() { - _extendedColors = new Dictionary(); - _default = new Dictionary(); // If this is the default palette, it will not have a default-default palette + ExtColorPalette = new Dictionary(); + DefaultColorPalette = new Dictionary(); // If this is the default palette, it will not have a default-default palette } #endregion @@ -65,7 +43,7 @@ namespace mRemoteNG.Themes // Set the default theme, that theme should contain all color values used by the application public void setDefault(ExtendedColorPalette inPalettte) { - _default = inPalettte._extendedColors; + DefaultColorPalette = inPalettte.ExtColorPalette; } #endregion @@ -76,12 +54,12 @@ namespace mRemoteNG.Themes /// public Color getColor(string colorKey) { - var retColor = _extendedColors.ContainsKey(colorKey) ? _extendedColors[colorKey]:Color.Empty; + var retColor = ExtColorPalette.ContainsKey(colorKey) ? ExtColorPalette[colorKey]:Color.Empty; //Invisible colors are not good, might indicate missing color from the palette as is represented by 00000000 if (retColor != Color.Empty && retColor.A != 0) return retColor; - if(_default != null) + if(DefaultColorPalette != null) { - retColor = _default.ContainsKey(colorKey) ? _default[colorKey] : Color.Empty; + retColor = DefaultColorPalette.ContainsKey(colorKey) ? DefaultColorPalette[colorKey] : Color.Empty; } //why are we here?, just avoid a crash if(retColor == Color.Empty) @@ -100,7 +78,7 @@ namespace mRemoteNG.Themes /// public void addColor(string colorKey,Color inColor) { - _extendedColors.Add(colorKey, inColor); + ExtColorPalette.Add(colorKey, inColor); } @@ -111,33 +89,13 @@ namespace mRemoteNG.Themes /// public void replaceColor(string colorKey, Color inColor) { - _extendedColors[colorKey]= inColor; + ExtColorPalette[colorKey]= inColor; } - public Dictionary DefaultColorPalette - { - get - { - return _default; - } - set - { - _default = value; - } - } + public Dictionary DefaultColorPalette { get; set; } - public Dictionary ExtColorPalette - { - get - { - return _extendedColors; - } - set - { - _extendedColors = value; - } - } + public Dictionary ExtColorPalette { get; set; } } } diff --git a/mRemoteV1/Themes/MremoteNGPaletteManipulator.cs b/mRemoteV1/Themes/MremoteNGPaletteManipulator.cs index adca1727b..2ee357cb6 100644 --- a/mRemoteV1/Themes/MremoteNGPaletteManipulator.cs +++ b/mRemoteV1/Themes/MremoteNGPaletteManipulator.cs @@ -34,7 +34,7 @@ namespace mRemoteNG.Themes foreach (DictionaryEntry entry in resourceSet) { var colorName = entry.Key.ToString(); - var xmlQueryPath = (string)entry.Value; + var xmlQueryPath = entry.Value.ToString(); if (_xml.DocumentElement == null) continue; var colorNodeList = _xml.DocumentElement.FirstChild.SelectNodes(xmlQueryPath); var color = colorNodeList != null && colorNodeList.Count > 0 ? colorNodeList[0].Value : null; @@ -60,7 +60,7 @@ namespace mRemoteNG.Themes foreach (DictionaryEntry entry in resourceSet) { var colorName = entry.Key.ToString(); - var xmlQueryPath = (string)entry.Value; + var xmlQueryPath = entry.Value.ToString(); var colorNodeList = _xml.DocumentElement?.FirstChild.SelectNodes(xmlQueryPath); if (colorNodeList == null || colorNodeList.Count <= 0) continue; var paletteColor = colorPalette.getColor(colorName); diff --git a/mRemoteV1/Themes/ThemeInfo.cs b/mRemoteV1/Themes/ThemeInfo.cs index 1fa032699..86db8d847 100644 --- a/mRemoteV1/Themes/ThemeInfo.cs +++ b/mRemoteV1/Themes/ThemeInfo.cs @@ -7,6 +7,7 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.Themes { + /// /// /// Container class for all the color and style elements to define a theme /// @@ -15,34 +16,32 @@ namespace mRemoteNG.Themes #region Private Variables private string _name; private ThemeBase _theme; - private String _URI; + private string _URI; private VisualStudioToolStripExtender.VsVersion _version; private ExtendedColorPalette _extendedPalette; - private bool _isThemeBase; - private bool _isExtendable; #endregion #region Constructors - public ThemeInfo(string themeName, ThemeBase inTheme, String inURI, VisualStudioToolStripExtender.VsVersion inVersion, ExtendedColorPalette inExtendedPalette) + public ThemeInfo(string themeName, ThemeBase inTheme, string inURI, VisualStudioToolStripExtender.VsVersion inVersion, ExtendedColorPalette inExtendedPalette) { _name = themeName; _theme = inTheme; _URI = inURI; _version = inVersion; _extendedPalette = inExtendedPalette; - _isThemeBase = false; - _isExtendable = false; + IsThemeBase = false; + IsExtendable = false; } - public ThemeInfo(string themeName, ThemeBase inTheme, String inURI, VisualStudioToolStripExtender.VsVersion inVersion) + public ThemeInfo(string themeName, ThemeBase inTheme, string inURI, VisualStudioToolStripExtender.VsVersion inVersion) { _name = themeName; _theme = inTheme; _URI = inURI; _version = inVersion; - _isThemeBase = false; - _isExtendable = false; + IsThemeBase = false; + IsExtendable = false; } #endregion @@ -57,8 +56,8 @@ namespace mRemoteNG.Themes }; var clonedObj = new ThemeInfo(_name, _theme, _URI, _version, extPalette) { - IsExtendable = _isExtendable, - IsThemeBase = _isThemeBase + IsExtendable = IsExtendable, + IsThemeBase = IsThemeBase }; return clonedObj; @@ -71,8 +70,8 @@ namespace mRemoteNG.Themes [Browsable(false)] public string Name { - get { return _name; } - set + get => _name; + set { if (string.Equals(_name, value, StringComparison.InvariantCulture)) { @@ -84,7 +83,7 @@ namespace mRemoteNG.Themes public ThemeBase Theme { - get { return _theme; } + get => _theme; set { if (value != null && _theme == value) @@ -97,7 +96,7 @@ namespace mRemoteNG.Themes public string URI { - get { return _URI; } + get => _URI; set { if (value != null && _URI == value) @@ -110,7 +109,7 @@ namespace mRemoteNG.Themes public VisualStudioToolStripExtender.VsVersion Version { - get { return _version; } + get => _version; set { if (Equals(_version, value)) @@ -123,7 +122,7 @@ namespace mRemoteNG.Themes public ExtendedColorPalette ExtendedPalette { - get { return _extendedPalette; } + get => _extendedPalette; set { if (_extendedPalette != null && _extendedPalette == value) @@ -134,23 +133,10 @@ namespace mRemoteNG.Themes } } - public bool IsThemeBase - { - get { return _isThemeBase; } - set - { - _isThemeBase = value; - } - } + public bool IsThemeBase { get; set; } + + public bool IsExtendable { get; set; } - public bool IsExtendable - { - get { return _isExtendable; } - set - { - _isExtendable = value; - } - } #endregion } } \ No newline at end of file diff --git a/mRemoteV1/Themes/ThemeManager.cs b/mRemoteV1/Themes/ThemeManager.cs index 772cd4e27..a3b9a2e23 100644 --- a/mRemoteV1/Themes/ThemeManager.cs +++ b/mRemoteV1/Themes/ThemeManager.cs @@ -1,3 +1,6 @@ +using mRemoteNG.App; +using mRemoteNG.Messages; +using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; @@ -43,11 +46,7 @@ namespace mRemoteNG.Themes #region Public Methods public static ThemeManager getInstance() { - if(themeInstance == null) - { - themeInstance = new ThemeManager(); - } - return themeInstance; + return themeInstance ?? (themeInstance = new ThemeManager()); } @@ -61,55 +60,74 @@ namespace mRemoteNG.Themes //THe manager precharges all the themes at once public List LoadThemes() { - if (themes == null) + if (themes != null) return themes.Values.OfType().ToList(); + themes = new Hashtable(); + + //Load the files in theme folder first, to incluide vstheme light as default + var themePath = App.Info.SettingsFileInfo.ThemeFolder; + if (themePath == null) return themes.Values.OfType().ToList(); + try { - themes = new Hashtable(); - - //Load the files in theme folder first, to incluide vstheme light as default - string execPath = App.Info.SettingsFileInfo.SettingsPath; - if(execPath != null) + //In install mode first time is necesary to copy the themes folder + if (!Directory.Exists(themePath)) { - //Check that theme folder exist before trying to load themes - if(Directory.Exists(Path.Combine(execPath, "themes"))) - { - string[] themeFiles = Directory.GetFiles(Path.Combine(execPath, "themes"), "*.vstheme"); - string defaultThemeURL = Directory.GetFiles(Path.Combine(execPath, "themes"), "vs2015light" + ".vstheme")[0]; - //First we load the default theme, its vs2015light - ThemeInfo defaultTheme = ThemeSerializer.LoadFromXmlFile(defaultThemeURL); - themes.Add(defaultTheme.Name, defaultTheme); - //Then the rest - foreach (string themeFile in themeFiles) - { - //filter default one - ThemeInfo extTheme = ThemeSerializer.LoadFromXmlFile(themeFile, defaultTheme); - if (extTheme.Theme != null && !themes.ContainsKey(extTheme.Name)) - { - themes.Add(extTheme.Name, extTheme); - } - } + Directory.CreateDirectory(themePath); + } + var orig = new DirectoryInfo(App.Info.SettingsFileInfo.InstalledThemeFolder); + var files = orig.GetFiles(); + foreach (var file in files) + { - //Load the embedded themes, extended palettes are taken from the vs2015 themes, trying to match the color theme - ThemeInfo vs2003 = new ThemeInfo("Vs2003", new VS2003Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2003, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); - themes.Add(vs2003.Name, vs2003); - ThemeInfo vs2005 = new ThemeInfo("Vs2005", new VS2005Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2005, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); - themes.Add(vs2005.Name, vs2005); - ThemeInfo vs2012Light = new ThemeInfo("vs2012Light", new VS2012LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); - themes.Add(vs2012Light.Name, vs2012Light); - ThemeInfo vs2012Dark = new ThemeInfo("vs2012Dark", new VS2012DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); - themes.Add(vs2012Dark.Name, vs2012Dark); - ThemeInfo vs2012Blue = new ThemeInfo("vs2012Blue", new VS2012BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); - themes.Add(vs2012Blue.Name, vs2012Blue); - ThemeInfo vs2013Light = new ThemeInfo("vs2013Light", new VS2013LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); - themes.Add(vs2013Light.Name, vs2013Light); - ThemeInfo vs2013Dark = new ThemeInfo("vs2013Dark", new VS2013DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); - themes.Add(vs2013Dark.Name, vs2013Dark); - ThemeInfo vs2013Blue = new ThemeInfo("vs2013Blue", new VS2013BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); - themes.Add(vs2013Blue.Name, vs2013Blue); - } + if (!File.Exists(Path.Combine(themePath, file.Name))) + file.CopyTo(Path.Combine(themePath, file.Name), true); } - } + + + //Check that theme folder exist before trying to load themes + if (Directory.Exists(themePath)) + { + var themeFiles = Directory.GetFiles(themePath, "*.vstheme"); + var defaultThemeURL = Directory.GetFiles(themePath, "vs2015light" + ".vstheme")[0]; + //First we load the default theme, its vs2015light + var defaultTheme = ThemeSerializer.LoadFromXmlFile(defaultThemeURL); + themes.Add(defaultTheme.Name, defaultTheme); + //Then the rest + foreach (var themeFile in themeFiles) + { + //filter default one + var extTheme = ThemeSerializer.LoadFromXmlFile(themeFile, defaultTheme); + if (extTheme.Theme != null && !themes.ContainsKey(extTheme.Name)) + { + themes.Add(extTheme.Name, extTheme); + } + } + + + //Load the embedded themes, extended palettes are taken from the vs2015 themes, trying to match the color theme + var vs2003 = new ThemeInfo("Vs2003", new VS2003Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2003, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + themes.Add(vs2003.Name, vs2003); + var vs2005 = new ThemeInfo("Vs2005", new VS2005Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2005, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + themes.Add(vs2005.Name, vs2005); + var vs2012Light = new ThemeInfo("vs2012Light", new VS2012LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + themes.Add(vs2012Light.Name, vs2012Light); + var vs2012Dark = new ThemeInfo("vs2012Dark", new VS2012DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); + themes.Add(vs2012Dark.Name, vs2012Dark); + var vs2012Blue = new ThemeInfo("vs2012Blue", new VS2012BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); + themes.Add(vs2012Blue.Name, vs2012Blue); + var vs2013Light = new ThemeInfo("vs2013Light", new VS2013LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette); + themes.Add(vs2013Light.Name, vs2013Light); + var vs2013Dark = new ThemeInfo("vs2013Dark", new VS2013DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette); + themes.Add(vs2013Dark.Name, vs2013Dark); + var vs2013Blue = new ThemeInfo("vs2013Blue", new VS2013BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette); + themes.Add(vs2013Blue.Name, vs2013Blue); + } + } + catch(Exception ex) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Error loading themes" + Environment.NewLine + ex.Message, true); + } return themes.Values.OfType().ToList(); } @@ -121,29 +139,24 @@ namespace mRemoteNG.Themes /// public ThemeInfo addTheme(ThemeInfo baseTheme, string newThemeName) { - if (!themes.Contains(newThemeName)) - { - ThemeInfo modifiedTheme = (ThemeInfo)baseTheme.Clone(); - modifiedTheme.Name = newThemeName; - modifiedTheme.IsExtendable = true; - modifiedTheme.IsThemeBase = false; - ThemeSerializer.SaveToXmlFile(modifiedTheme,baseTheme); - themes.Add(newThemeName,modifiedTheme); - return modifiedTheme; - } - return null; + if (themes.Contains(newThemeName)) return null; + var modifiedTheme = (ThemeInfo)baseTheme.Clone(); + modifiedTheme.Name = newThemeName; + modifiedTheme.IsExtendable = true; + modifiedTheme.IsThemeBase = false; + ThemeSerializer.SaveToXmlFile(modifiedTheme,baseTheme); + themes.Add(newThemeName,modifiedTheme); + return modifiedTheme; } //Delete a theme from memory and disk public void deleteTheme(ThemeInfo themeToDelete) { - if (themes.Contains(themeToDelete.Name)) - { - if(ActiveTheme == themeToDelete) - ActiveTheme = DefaultTheme; - themes.Remove(themeToDelete.Name); - ThemeSerializer.DeleteFile(themeToDelete); - } + if (!themes.Contains(themeToDelete.Name)) return; + if(ActiveTheme == themeToDelete) + ActiveTheme = DefaultTheme; + themes.Remove(themeToDelete.Name); + ThemeSerializer.DeleteFile(themeToDelete); } //Sincronize the theme XML values from memory to disk @@ -163,10 +176,8 @@ namespace mRemoteNG.Themes { if (themes.Contains(name)) return false; - char[] badChars = Path.GetInvalidFileNameChars(); - if (name.IndexOfAny(badChars) != -1) - return false; - return true; + var badChars = Path.GetInvalidFileNameChars(); + return name.IndexOfAny(badChars) == -1; } @@ -178,10 +189,11 @@ namespace mRemoteNG.Themes public event ThemeChangedEventHandler ThemeChanged { - add { ThemeChangedEvent = (ThemeChangedEventHandler)System.Delegate.Combine(ThemeChangedEvent, value); } - remove { ThemeChangedEvent = (ThemeChangedEventHandler)System.Delegate.Remove(ThemeChangedEvent, value); } + add => ThemeChangedEvent = (ThemeChangedEventHandler)Delegate.Combine(ThemeChangedEvent, value); + remove => ThemeChangedEvent = (ThemeChangedEventHandler)Delegate.Remove(ThemeChangedEvent, value); } + // ReSharper disable once UnusedParameter.Local private void NotifyThemeChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "Name") @@ -195,44 +207,29 @@ namespace mRemoteNG.Themes #region Properties public bool ThemingActive { - get - { - return _themeActive; - } + get => _themeActive; set { - if(themes.Count != 0) - { - _themeActive = value; - Settings.Default.ThemingActive = value; - NotifyThemeChanged(this, new PropertyChangedEventArgs("")); - } + if (themes.Count == 0) return; + _themeActive = value; + Settings.Default.ThemingActive = value; + NotifyThemeChanged(this, new PropertyChangedEventArgs("")); } } - private ThemeInfo DefaultTheme - { - get - { - return (ThemeInfo) themes["vs2015light"]; - } - } - + public ThemeInfo DefaultTheme => (ThemeInfo) themes["vs2015light"]; + public ThemeInfo ActiveTheme { - get - { - return _activeTheme; - } - set + // default if themes are not enabled + get => ThemingActive == false ? DefaultTheme : _activeTheme; + set { //You can only enable theming if there are themes laoded - if(value != null) - { - _activeTheme = value; - Settings.Default.ThemeName = value.Name; - NotifyThemeChanged(this, new PropertyChangedEventArgs("theme")); - } + if (value == null) return; + _activeTheme = value; + Settings.Default.ThemeName = value.Name; + NotifyThemeChanged(this, new PropertyChangedEventArgs("theme")); } } #endregion diff --git a/mRemoteV1/Themes/ThemeSerializer.cs b/mRemoteV1/Themes/ThemeSerializer.cs index d23c97e55..25eacc971 100644 --- a/mRemoteV1/Themes/ThemeSerializer.cs +++ b/mRemoteV1/Themes/ThemeSerializer.cs @@ -1,25 +1,22 @@ -using System.Collections.Generic; -using System; -using System.Drawing; using System.IO; -using System.Xml; using WeifenLuo.WinFormsUI.Docking; using System.Linq; namespace mRemoteNG.Themes { - public class ThemeSerializer + public static class ThemeSerializer { - /// - /// Save the theme to file, name property is used as filename - /// The baseTheme is used as a template, by copy that file and rewrite the extpalette values - /// - /// - public static void SaveToXmlFile(ThemeInfo themeToSave,ThemeInfo baseTheme) + /// + /// Save the theme to file, name property is used as filename + /// The baseTheme is used as a template, by copy that file and rewrite the extpalette values + /// + /// + /// + public static void SaveToXmlFile(ThemeInfo themeToSave,ThemeInfo baseTheme) { - string oldURI = baseTheme.URI; - String directoryName = Path.GetDirectoryName(oldURI); - string toSaveURI = directoryName + Path.DirectorySeparatorChar + themeToSave.Name + ".vstheme"; + var oldURI = baseTheme.URI; + var directoryName = Path.GetDirectoryName(oldURI); + var toSaveURI = directoryName + Path.DirectorySeparatorChar + themeToSave.Name + ".vstheme"; File.Copy(baseTheme.URI, toSaveURI); themeToSave.URI = toSaveURI; } @@ -35,10 +32,9 @@ namespace mRemoteNG.Themes /// public static void UpdateThemeXMLValues(ThemeInfo themeToUpdate) { - byte[] bytesIn = File.ReadAllBytes(themeToUpdate.URI); - MremoteNGPaletteManipulator manipulator; - manipulator = new MremoteNGPaletteManipulator(bytesIn, themeToUpdate.ExtendedPalette); - byte[] bytesOut = manipulator.mergePalette(themeToUpdate.ExtendedPalette); + var bytesIn = File.ReadAllBytes(themeToUpdate.URI); + var manipulator = new MremoteNGPaletteManipulator(bytesIn, themeToUpdate.ExtendedPalette); + var bytesOut = manipulator.mergePalette(themeToUpdate.ExtendedPalette); File.WriteAllBytes(themeToUpdate.URI, bytesOut); } @@ -50,22 +46,22 @@ namespace mRemoteNG.Themes /// public static ThemeInfo LoadFromXmlFile(string filename, ThemeInfo defaultTheme=null) { - byte[] bytes = File.ReadAllBytes(filename); + var bytes = File.ReadAllBytes(filename); //Load the dockpanel part - MremoteNGThemeBase themeBaseLoad= new MremoteNGThemeBase(bytes); + var themeBaseLoad= new MremoteNGThemeBase(bytes); //Load the mremote part - MremoteNGPaletteManipulator extColorLoader; - //Cause we cannot default the theme for the default theme - extColorLoader = new MremoteNGPaletteManipulator(bytes, defaultTheme ==null ? null:defaultTheme.ExtendedPalette); - ThemeInfo loadedTheme = new ThemeInfo(Path.GetFileNameWithoutExtension(filename), themeBaseLoad, filename, VisualStudioToolStripExtender.VsVersion.Vs2015, extColorLoader.getColors()); - if((new string[] { "darcula", "vs2015blue", "vs2015dark" , "vs2015light" }).Contains(Path.GetFileNameWithoutExtension(filename))) + //Cause we cannot default the theme for the default theme + var extColorLoader = new MremoteNGPaletteManipulator(bytes, defaultTheme?.ExtendedPalette); + var loadedTheme = new ThemeInfo(Path.GetFileNameWithoutExtension(filename), themeBaseLoad, filename, VisualStudioToolStripExtender.VsVersion.Vs2015, extColorLoader.getColors()); + if(new[] { "darcula", "vs2015blue", "vs2015dark" , "vs2015light" }.Contains(Path.GetFileNameWithoutExtension(filename))) { loadedTheme.IsThemeBase = true; } loadedTheme.IsExtendable = true; return loadedTheme; } - + + /* private static string EncodeColorName(Color color) { // best/simplest answer to converting to hex: http://stackoverflow.com/questions/12078942/how-to-convert-from-argb-to-hex-aarrggbb @@ -77,7 +73,7 @@ namespace mRemoteNG.Themes var regex = new System.Text.RegularExpressions.Regex("^[0-9a-fA-F]{8}$"); return regex.Match(name).Success ? Color.FromArgb(Convert.ToInt32(name, 16)) : Color.FromName(name); } - + */ } } diff --git a/mRemoteV1/Tools/DesignModeTest.cs b/mRemoteV1/Tools/DesignModeTest.cs deleted file mode 100644 index 17c04eb30..000000000 --- a/mRemoteV1/Tools/DesignModeTest.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Reflection; - - -//Taken from https://www.codeproject.com/Tips/447319/Resolve-DesignMode-for-a-user-control -//Help to determine design mode is true in custom controls -namespace mRemoteNG.Tools -{ - public static class DesignModeTest - { - /// - /// Extension method to return if the control is in design mode - /// - /// Control to examine - /// True if in design mode, otherwise false - public static bool IsInDesignMode(this System.Windows.Forms.Control control) - { - return ResolveDesignMode(control); - } - - /// - /// Method to test if the control or it's parent is in design mode - /// - /// Control to examine - /// True if in design mode, otherwise false - private static bool ResolveDesignMode(System.Windows.Forms.Control control) - { - // Get the protected property - var designModeProperty = control.GetType().GetProperty( - "DesignMode", - BindingFlags.Instance - | BindingFlags.NonPublic); - - // Get the controls DesignMode value - var designMode = designModeProperty != null && (bool)designModeProperty.GetValue(control, null); - - // Test the parent if it exists - if (control.Parent != null) - { - designMode |= ResolveDesignMode(control.Parent); - } - - return designMode; - } - } -} diff --git a/mRemoteV1/Tools/DisposableOptional.cs b/mRemoteV1/Tools/DisposableOptional.cs new file mode 100644 index 000000000..10fa2cf0c --- /dev/null +++ b/mRemoteV1/Tools/DisposableOptional.cs @@ -0,0 +1,33 @@ +using System; +using System.Linq; + +namespace mRemoteNG.Tools +{ + public class DisposableOptional : Optional, IDisposable + where T : IDisposable + { + public DisposableOptional() + : base() + { + } + + public DisposableOptional(T value) + : base(value) + { + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public void Dispose(bool disposing) + { + if (!disposing || !this.Any()) + return; + + this.First().Dispose(); + } + } +} diff --git a/mRemoteV1/Tools/Extensions.cs b/mRemoteV1/Tools/Extensions.cs index 06e18c769..76bcba778 100644 --- a/mRemoteV1/Tools/Extensions.cs +++ b/mRemoteV1/Tools/Extensions.cs @@ -5,21 +5,50 @@ namespace mRemoteNG.Tools { public static class Extensions { - public static Maybe Maybe(this T value) + public static Optional Maybe(this T value) { - return new Maybe(value); + return new Optional(value); } - public static Maybe MaybeParse(this T value, Func parseFunc) + public static Optional MaybeParse(this T value, Func parseFunc) { try { - return new Maybe(parseFunc(value)); + return new Optional(parseFunc(value)); } catch { - return new Maybe(); + return new Optional(); } } + + /// + /// Throws an if the given value is + /// null. Otherwise, return the value. + /// + /// + /// + /// + /// The name of the argument + /// + public static T ThrowIfNull(this T value, string argName) + { + if (value == null) + throw new ArgumentNullException(argName); + return value; + } + + /// + /// Throws an if the value + /// is null or an empty string. Otherwise, returns the value. + /// + /// + /// + public static string ThrowIfNullOrEmpty(this string value, string argName) + { + if (string.IsNullOrEmpty(value)) + throw new ArgumentException("Value cannot be null or empty", argName); + return value; + } } } diff --git a/mRemoteV1/Tools/IeBrowserEmulation.cs b/mRemoteV1/Tools/IeBrowserEmulation.cs index b7e9fba87..ad6c85ca5 100644 --- a/mRemoteV1/Tools/IeBrowserEmulation.cs +++ b/mRemoteV1/Tools/IeBrowserEmulation.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Linq; using System.Security.AccessControl; using Microsoft.Win32; using mRemoteNG.App; @@ -38,14 +39,16 @@ namespace mRemoteNG.Tools { using (var key = Registry.CurrentUser.OpenSubKey(string.Concat("Software\\Wow6432Node\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", feature), RegistryKeyPermissionCheck.ReadWriteSubTree)) { - key?.DeleteValue(appName); + if (key?.GetValueNames().Contains(appName) ?? false) + key.DeleteValue(appName); } } using (var key = Registry.CurrentUser.CreateSubKey(string.Concat("Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", feature), RegistryKeyPermissionCheck.ReadWriteSubTree)) { - key?.DeleteValue(appName); + if (key?.GetValueNames().Contains(appName) ?? false) + key.DeleteValue(appName); } } #endif diff --git a/mRemoteV1/Tools/Maybe.cs b/mRemoteV1/Tools/Maybe.cs deleted file mode 100644 index 311591e48..000000000 --- a/mRemoteV1/Tools/Maybe.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -namespace mRemoteNG.Tools -{ - public class Maybe : IEnumerable - { - private readonly T[] _maybe; - - public Maybe() - { - _maybe = new T[0]; - } - - public Maybe(T value) - { - _maybe = value != null - ? new[] {value} - : new T[0]; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return ((IEnumerable)_maybe).GetEnumerator(); - } - - public override string ToString() - { - return _maybe.Any() ? _maybe.First().ToString() : ""; - } - - public static implicit operator Maybe(T value) - { - return new Maybe(value); - } - - public static Maybe FromNullable(TOut? value) where TOut : struct - { - return value.HasValue - ? new Maybe(value.Value) - : new Maybe(); - } - } -} diff --git a/mRemoteV1/Tools/MiscTools.cs b/mRemoteV1/Tools/MiscTools.cs index be663f300..03da94394 100644 --- a/mRemoteV1/Tools/MiscTools.cs +++ b/mRemoteV1/Tools/MiscTools.cs @@ -34,7 +34,7 @@ namespace mRemoteNG.Tools } } - public static SecureString PasswordDialog(string passwordName = null, bool verify = true) + public static Optional PasswordDialog(string passwordName = null, bool verify = true) { var passwordForm = new PasswordForm(passwordName, verify); return passwordForm.GetKey(); @@ -68,13 +68,6 @@ namespace mRemoteNG.Tools { return Text.Replace("\'", "\'\'"); } - - - public static object StringToEnum(Type t, string value) - { - return Enum.Parse(t, value); - } - public static string GetExceptionMessageRecursive(Exception ex) { diff --git a/mRemoteV1/Tools/Optional.cs b/mRemoteV1/Tools/Optional.cs new file mode 100644 index 000000000..dc1dc0c18 --- /dev/null +++ b/mRemoteV1/Tools/Optional.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace mRemoteNG.Tools +{ + /// + /// Represents a type that may or may not have been assigned a value. + /// A strongly typed collection that contains either 0 or 1 values. + /// + /// The underlying type that may or may not have a value + public class Optional : IEnumerable, IComparable> + { + private readonly T[] _optional; + + /// + /// Create a new empty instance of Optional + /// + public Optional() + { + _optional = new T[0]; + } + + /// + /// Create a new instance of Optional from the given value. + /// If the value is null, the Optional will be empty + /// + public Optional(T value) + { + _optional = value != null + ? new[] {value} + : new T[0]; + } + + public override string ToString() + { + return _optional.Any() ? _optional.First().ToString() : ""; + } + + public static implicit operator Optional(T value) + { + return new Optional(value); + } + + public static Optional FromNullable(TOut? value) where TOut : struct + { + return value.HasValue + ? new Optional(value.Value) + : new Optional(); + } + + /// + /// Returns an empty + /// + public static Optional Empty => new Optional(); + + #region IEnumerable + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)_optional).GetEnumerator(); + } + #endregion + + #region IComparable + /// + /// Compares this 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. + /// + /// + public int CompareTo(Optional 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) + return ((IComparable)_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) + { + if (ReferenceEquals(this, obj)) + return true; + + var objAsOptional = obj as Optional; + if (objAsOptional != null) + return Equals(objAsOptional); + + if (obj is T) + Equals((T)obj); + + return false; + } + + public bool Equals(Optional other) + { + 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 override int GetHashCode() + { + return _optional != null + ? _optional.GetHashCode() + : 0; + } + #endregion + + #region Operators + + public static bool operator ==(Optional left, Optional right) + { + return Equals(left, right); + } + + public static bool operator !=(Optional left, Optional right) + { + return !Equals(left, right); + } + #endregion + } +} diff --git a/mRemoteV1/Tools/PortScanner.cs b/mRemoteV1/Tools/PortScanner.cs index 864ba7011..2ee08ca67 100644 --- a/mRemoteV1/Tools/PortScanner.cs +++ b/mRemoteV1/Tools/PortScanner.cs @@ -17,17 +17,24 @@ namespace mRemoteNG.Tools private readonly List _ports = new List(); private Thread _scanThread; private readonly List _scannedHosts = new List(); + private readonly int _timeoutInMilliseconds; #region Public Methods - public PortScanner(IPAddress ipAddress1, IPAddress ipAddress2, int port1, int port2) + public PortScanner(IPAddress ipAddress1, IPAddress ipAddress2, int port1, int port2, int timeoutInMilliseconds = 5000) { var ipAddressStart = IpAddressMin(ipAddress1, ipAddress2); var ipAddressEnd = IpAddressMax(ipAddress1, ipAddress2); var portStart = Math.Min(port1, port2); var portEnd = Math.Max(port1, port2); - + + if (timeoutInMilliseconds < 0) + throw new ArgumentOutOfRangeException(nameof(timeoutInMilliseconds)); + + _timeoutInMilliseconds = timeoutInMilliseconds; + + _ports.Clear(); for (var port = portStart; port <= portEnd; port++) { @@ -87,7 +94,7 @@ namespace mRemoteNG.Tools try { pingSender.PingCompleted += PingSender_PingCompleted; - pingSender.SendAsync(ipAddress, ipAddress); + pingSender.SendAsync(ipAddress, _timeoutInMilliseconds, ipAddress); } catch (Exception ex) { diff --git a/mRemoteV1/Tools/WindowsRegistry/IRegistry.cs b/mRemoteV1/Tools/WindowsRegistry/IRegistry.cs new file mode 100644 index 000000000..32cff52a8 --- /dev/null +++ b/mRemoteV1/Tools/WindowsRegistry/IRegistry.cs @@ -0,0 +1,8 @@ +namespace mRemoteNG.Tools.WindowsRegistry +{ + public interface IRegistry + { + Optional GetKeyValue(RegistryHive hive, string keyPath, string propertyName); + string[] GetSubKeyNames(RegistryHive hive, string keyPath); + } +} \ No newline at end of file diff --git a/mRemoteV1/Tools/WindowsRegistry/RegistryHive.cs b/mRemoteV1/Tools/WindowsRegistry/RegistryHive.cs new file mode 100644 index 000000000..56f6cbc01 --- /dev/null +++ b/mRemoteV1/Tools/WindowsRegistry/RegistryHive.cs @@ -0,0 +1,11 @@ +namespace mRemoteNG.Tools.WindowsRegistry +{ + public enum RegistryHive + { + ClassesRoot, + CurrentConfig, + CurrentUser, + Users, + LocalMachine + } +} diff --git a/mRemoteV1/Tools/WindowsRegistry/WindowsRegistry.cs b/mRemoteV1/Tools/WindowsRegistry/WindowsRegistry.cs new file mode 100644 index 000000000..aa2919bb3 --- /dev/null +++ b/mRemoteV1/Tools/WindowsRegistry/WindowsRegistry.cs @@ -0,0 +1,54 @@ +using System; +using System.Linq; +using Microsoft.Win32; + +namespace mRemoteNG.Tools.WindowsRegistry +{ + public class WindowsRegistry : IRegistry + { + public string[] GetSubKeyNames(RegistryHive hive, string keyPath) + { + keyPath.ThrowIfNull(nameof(keyPath)); + + using (var key = OpenSubKey(hive, keyPath)) + { + return key.Any() + ? key.First().GetSubKeyNames() + : new string[0]; + } + } + + public Optional GetKeyValue(RegistryHive hive, string keyPath, string propertyName) + { + keyPath.ThrowIfNull(nameof(keyPath)); + propertyName.ThrowIfNull(nameof(propertyName)); + + using (var key = OpenSubKey(hive, keyPath)) + { + if (!key.Any()) + return Optional.Empty; + + return key.First().GetValue(propertyName) as string; + } + } + + private DisposableOptional OpenSubKey(RegistryHive hive, string keyPath) + { + switch (hive) + { + case RegistryHive.ClassesRoot: + return new DisposableOptional(Registry.ClassesRoot.OpenSubKey(keyPath)); + case RegistryHive.CurrentConfig: + return new DisposableOptional(Registry.CurrentConfig.OpenSubKey(keyPath)); + case RegistryHive.CurrentUser: + return new DisposableOptional(Registry.CurrentUser.OpenSubKey(keyPath)); + case RegistryHive.Users: + return new DisposableOptional(Registry.Users.OpenSubKey(keyPath)); + case RegistryHive.LocalMachine: + return new DisposableOptional(Registry.LocalMachine.OpenSubKey(keyPath)); + default: + throw new ArgumentOutOfRangeException(nameof(hive), hive, null); + } + } + } +} diff --git a/mRemoteV1/Tree/ConnectionTreeModel.cs b/mRemoteV1/Tree/ConnectionTreeModel.cs index 0d75a7802..502cf36ee 100644 --- a/mRemoteV1/Tree/ConnectionTreeModel.cs +++ b/mRemoteV1/Tree/ConnectionTreeModel.cs @@ -30,7 +30,7 @@ namespace mRemoteNG.Tree RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, rootNode)); } - public IEnumerable GetRecursiveChildList() + public IReadOnlyList GetRecursiveChildList() { var list = new List(); foreach (var rootNode in RootNodes) diff --git a/mRemoteV1/Tree/NodeSearcher.cs b/mRemoteV1/Tree/NodeSearcher.cs index 111ad88a2..cb9bd8234 100644 --- a/mRemoteV1/Tree/NodeSearcher.cs +++ b/mRemoteV1/Tree/NodeSearcher.cs @@ -5,7 +5,7 @@ using mRemoteNG.Connection; namespace mRemoteNG.Tree { - public class NodeSearcher + public class NodeSearcher { private readonly ConnectionTreeModel _connectionTreeModel; @@ -22,7 +22,7 @@ namespace mRemoteNG.Tree { ResetMatches(); if (searchText == "") return Matches; - var nodes = (List)_connectionTreeModel.GetRecursiveChildList(); + var nodes = _connectionTreeModel.GetRecursiveChildList(); var searchTextLower = searchText.ToLowerInvariant(); foreach (var node in nodes) { diff --git a/mRemoteV1/Tree/Root/RootNodeInfo.cs b/mRemoteV1/Tree/Root/RootNodeInfo.cs index 12701795f..47e863a71 100644 --- a/mRemoteV1/Tree/Root/RootNodeInfo.cs +++ b/mRemoteV1/Tree/Root/RootNodeInfo.cs @@ -1,8 +1,8 @@ -using mRemoteNG.Tools; +using System; using System.ComponentModel; -using System.Security; +using mRemoteNG.Connection; using mRemoteNG.Container; -using mRemoteNG.Security; +using mRemoteNG.Tools; namespace mRemoteNG.Tree.Root @@ -13,11 +13,17 @@ namespace mRemoteNG.Tree.Root private string _name; private string _customPassword = ""; - public RootNodeInfo(RootNodeType rootType) + public RootNodeInfo(RootNodeType rootType, string uniqueId) + : base(uniqueId) { _name = Language.strConnections; Type = rootType; } + + public RootNodeInfo(RootNodeType rootType) + : this(rootType, Guid.NewGuid().ToString()) + { + } #region Public Properties @@ -60,8 +66,22 @@ namespace mRemoteNG.Tree.Root public override TreeNodeType GetTreeNodeType() { - return TreeNodeType.Root; + return Type == RootNodeType.Connection + ? TreeNodeType.Root + : TreeNodeType.PuttyRoot; } #endregion - } + + public override void AddChildAt(ConnectionInfo newChildItem, int index) + { + newChildItem.Inheritance.DisableInheritance(); + base.AddChildAt(newChildItem, index); + } + + public override void RemoveChild(ConnectionInfo removalTarget) + { + removalTarget.Inheritance.EnableInheritance(); + base.RemoveChild(removalTarget); + } + } } \ No newline at end of file diff --git a/mRemoteV1/Tree/SelectedConnectionDeletionConfirmer.cs b/mRemoteV1/Tree/SelectedConnectionDeletionConfirmer.cs index ade37a24d..5b4c464d9 100644 --- a/mRemoteV1/Tree/SelectedConnectionDeletionConfirmer.cs +++ b/mRemoteV1/Tree/SelectedConnectionDeletionConfirmer.cs @@ -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() diff --git a/mRemoteV1/UI/Controls/Base/NGButton.cs b/mRemoteV1/UI/Controls/Base/NGButton.cs index cdd8d1a3c..5403d93d5 100644 --- a/mRemoteV1/UI/Controls/Base/NGButton.cs +++ b/mRemoteV1/UI/Controls/Base/NGButton.cs @@ -13,6 +13,9 @@ namespace mRemoteNG.UI.Controls.Base { private ThemeManager _themeManager ; + /// + /// Store the mouse state, required for coloring the component according to the mouse state + /// public enum MouseState { HOVER, @@ -27,10 +30,12 @@ namespace mRemoteNG.UI.Controls.Base public MouseState _mice { get; set; } + /// + /// Rewrite the function to allow for coloring the component depending on the mouse state + /// protected override void OnCreateControl() { - base.OnCreateControl(); - if (Tools.DesignModeTest.IsInDesignMode(this)) return; + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (_themeManager.ThemingActive) { @@ -63,9 +68,14 @@ namespace mRemoteNG.UI.Controls.Base } } + + /// + /// Repaint the componente, the elements considered are the clipping rectangle, text and an icon + /// + /// protected override void OnPaint(PaintEventArgs e) { - if (Tools.DesignModeTest.IsInDesignMode(this) || !_themeManager.ThemingActive) + if (!_themeManager.ThemingActive) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGCheckBox.cs b/mRemoteV1/UI/Controls/Base/NGCheckBox.cs index 1019e10f4..fb75a6511 100644 --- a/mRemoteV1/UI/Controls/Base/NGCheckBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGCheckBox.cs @@ -26,8 +26,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); - if (Tools.DesignModeTest.IsInDesignMode(this)) return; + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; _mice = MouseState.OUT; @@ -60,7 +59,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if (Tools.DesignModeTest.IsInDesignMode(this) || !_themeManager.ThemingActive) + if ( !_themeManager.ThemingActive) { base.OnPaint(e); return; @@ -108,7 +107,7 @@ namespace mRemoteNG.UI.Controls.Base if (Checked) { - e.Graphics.DrawString("ü", new Font("Wingdings", 9f), new SolidBrush(glyph), -1, 1); + e.Graphics.DrawString("\u2714", new Font(Font.FontFamily, 7f), new SolidBrush(glyph), -1, 1); } var textRect = new Rectangle(16, 0, Width - 16, Height); diff --git a/mRemoteV1/UI/Controls/Base/NGComboBox.cs b/mRemoteV1/UI/Controls/Base/NGComboBox.cs index ed0d1b2e7..4163aade9 100644 --- a/mRemoteV1/UI/Controls/Base/NGComboBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGComboBox.cs @@ -24,8 +24,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); - if (Tools.DesignModeTest.IsInDesignMode(this)) return; + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; _themeManager = ThemeManager.getInstance(); @@ -74,7 +73,7 @@ namespace mRemoteNG.UI.Controls.Base else e.Graphics.FillRectangle(new SolidBrush(_themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Background")), e.Bounds); - if(DisplayMember == null || DisplayMember == "") + if(string.IsNullOrEmpty(DisplayMember)) e.Graphics.DrawString(Items[index].ToString(), e.Font, itemBrush, e.Bounds, StringFormat.GenericDefault); else { @@ -89,7 +88,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if (Tools.DesignModeTest.IsInDesignMode(this) || !_themeManager.ThemingActive) + if ( !_themeManager.ThemingActive) { base.OnPaint(e); return; @@ -130,7 +129,7 @@ namespace mRemoteNG.UI.Controls.Base } //Arrow - e.Graphics.DrawString("q", new Font("Wingdings 3", 8f), new SolidBrush(ButtFore), Width-17, Height/2 -5); + e.Graphics.DrawString("\u25BC", Font, new SolidBrush(ButtFore), Width-17, Height/2 -5); //Text var textRect = new Rectangle(2, 2, Width - 20, Height - 4); diff --git a/mRemoteV1/UI/Controls/Base/NGGroupBox.cs b/mRemoteV1/UI/Controls/Base/NGGroupBox.cs index 093b61239..3d369529f 100644 --- a/mRemoteV1/UI/Controls/Base/NGGroupBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGGroupBox.cs @@ -10,7 +10,7 @@ namespace mRemoteNG.UI.Controls.Base { private ThemeManager _themeManager; - public NGGroupBox() : base() + public NGGroupBox() { ThemeManager.getInstance().ThemeChanged += OnCreateControl; } @@ -18,8 +18,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); - if (Tools.DesignModeTest.IsInDesignMode(this)) return; + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (_themeManager.ThemingActive) { @@ -29,7 +28,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if (Tools.DesignModeTest.IsInDesignMode(this) || !_themeManager.ThemingActive) + if ( !_themeManager.ThemingActive) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGLabel.cs b/mRemoteV1/UI/Controls/Base/NGLabel.cs index 2e49dc461..80ad21aa0 100644 --- a/mRemoteV1/UI/Controls/Base/NGLabel.cs +++ b/mRemoteV1/UI/Controls/Base/NGLabel.cs @@ -22,32 +22,35 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { base.OnCreateControl(); - if (!Tools.DesignModeTest.IsInDesignMode(this)) - { - _themeManager = ThemeManager.getInstance(); - Invalidate(); - } + _themeManager = ThemeManager.getInstance(); + if (!_themeManager.ThemingActive) return; + // Use the Dialog_* colors since Labels generally have the same colors as panels/dialogs/windows/etc... + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + FontOverrider.FontOverride(this); + Invalidate(); } protected override void OnPaint(PaintEventArgs e) { - if (Tools.DesignModeTest.IsInDesignMode(this) || !_themeManager.ThemingActive) + if (!_themeManager.ThemingActive) { base.OnPaint(e); return; } - e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; - e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias; + // let's use the defaults - this looks terrible in my testing.... + //e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; + //e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias; if (Enabled) { - TextRenderer.DrawText(e.Graphics, this.Text, Font, ClientRectangle, ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); + TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); } else { var disabledtextLabel = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Foreground"); - TextRenderer.DrawText(e.Graphics, this.Text, Font, ClientRectangle, disabledtextLabel, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); + TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, disabledtextLabel, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); } } diff --git a/mRemoteV1/UI/Controls/Base/NGListView.cs b/mRemoteV1/UI/Controls/Base/NGListView.cs index f42f03086..35c69c7a1 100644 --- a/mRemoteV1/UI/Controls/Base/NGListView.cs +++ b/mRemoteV1/UI/Controls/Base/NGListView.cs @@ -24,9 +24,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); - if (Tools.DesignModeTest.IsInDesignMode(this)) - return; + base.OnCreateControl(); var _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; //List back color diff --git a/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs b/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs index 370b19ac8..4b6cec616 100644 --- a/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs +++ b/mRemoteV1/UI/Controls/Base/NGNumericUpDown.cs @@ -1,7 +1,8 @@ -using mRemoteNG.Themes; -using System; +using System; using System.Drawing; using System.Windows.Forms; +using mRemoteNG.Themes; +// ReSharper disable LocalizableElement namespace mRemoteNG.UI.Controls.Base { @@ -14,34 +15,34 @@ namespace mRemoteNG.UI.Controls.Base private NGButton Up; private NGButton Down; - public NGNumericUpDown() : base() + public NGNumericUpDown() { + _themeManager = ThemeManager.getInstance(); ThemeManager.getInstance().ThemeChanged += OnCreateControl; } protected override void OnCreateControl() { - base.OnCreateControl(); - if (Tools.DesignModeTest.IsInDesignMode(this)) return; - _themeManager = ThemeManager.getInstance(); + base.OnCreateControl(); if (!_themeManager.ThemingActive) return; ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true); //Hide those nonthemable butons - Controls[0].Hide(); + if (Controls.Count > 0) + Controls[0].Hide(); //Add new themable buttons Up = new NGButton { - Text = "p", - Font = new Font("Wingdings 3", 6f) + Text = "\u25B2", + Font = new Font(Font.FontFamily, 6f) }; Up.SetBounds(Width - 17, 1, 16, Height / 2 - 1); Up.Click += Up_Click; Down = new NGButton { - Text = "q", - Font = new Font("Wingdings 3", 6f) + Text = "\u25BC", + Font = new Font(Font.FontFamily, 6f) }; Down.SetBounds(Width - 17, Height/2, 16, Height / 2 - 1); Down.Click += Down_Click; @@ -63,22 +64,18 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnEnabledChanged(EventArgs e) { - if (!Tools.DesignModeTest.IsInDesignMode(this)) + if (_themeManager.ThemingActive) { - _themeManager = ThemeManager.getInstance(); - if (_themeManager.ThemingActive) + if (Enabled) { - if (Enabled) - { - ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); - BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); - } - else - { - BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Background"); - } + ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); } - } + else + { + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Background"); + } + } base.OnEnabledChanged(e); Invalidate(); } @@ -88,7 +85,6 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); - if (Tools.DesignModeTest.IsInDesignMode(this)) return; if (!_themeManager.ThemingActive) return; //Fix Border if (BorderStyle != BorderStyle.None) diff --git a/mRemoteV1/UI/Controls/Base/NGProgressBar.cs b/mRemoteV1/UI/Controls/Base/NGProgressBar.cs index 5a10cd9c9..f45bfe732 100644 --- a/mRemoteV1/UI/Controls/Base/NGProgressBar.cs +++ b/mRemoteV1/UI/Controls/Base/NGProgressBar.cs @@ -18,8 +18,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); - if (Tools.DesignModeTest.IsInDesignMode(this)) return; + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; SetStyle(ControlStyles.UserPaint, true); @@ -29,7 +28,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnPaint(PaintEventArgs e) { - if (Tools.DesignModeTest.IsInDesignMode(this) || !_themeManager.ThemingActive) + if ( !_themeManager.ThemingActive) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGRadioButton.cs b/mRemoteV1/UI/Controls/Base/NGRadioButton.cs index f5282dfde..6b480f5ea 100644 --- a/mRemoteV1/UI/Controls/Base/NGRadioButton.cs +++ b/mRemoteV1/UI/Controls/Base/NGRadioButton.cs @@ -34,8 +34,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); - if (Tools.DesignModeTest.IsInDesignMode(this)) return; + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; // Allows for Overlaying @@ -71,7 +70,7 @@ namespace mRemoteNG.UI.Controls.Base //This class is painted with the checkbox colors, the glyph color is used for the radio inside protected override void OnPaint(PaintEventArgs e) { - if (Tools.DesignModeTest.IsInDesignMode(this) || !_themeManager.ThemingActive) + if ( !_themeManager.ThemingActive) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Controls/Base/NGTextBox.cs b/mRemoteV1/UI/Controls/Base/NGTextBox.cs index 0e99e1979..0d51c25e3 100644 --- a/mRemoteV1/UI/Controls/Base/NGTextBox.cs +++ b/mRemoteV1/UI/Controls/Base/NGTextBox.cs @@ -17,8 +17,7 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnCreateControl() { - base.OnCreateControl(); - if (Tools.DesignModeTest.IsInDesignMode(this)) return; + base.OnCreateControl(); _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); @@ -30,7 +29,8 @@ namespace mRemoteNG.UI.Controls.Base protected override void OnEnabledChanged(EventArgs e) { - if (!Tools.DesignModeTest.IsInDesignMode(this)) + _themeManager = ThemeManager.getInstance(); + if (_themeManager.ThemingActive) { _themeManager = ThemeManager.getInstance(); if(_themeManager.ThemingActive) diff --git a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs index 15560d2b9..c7759def3 100644 --- a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs +++ b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs @@ -15,12 +15,13 @@ 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; private readonly StatusImageList _statusImageList = new StatusImageList(); - private bool _nodeInEditMode; + private readonly ConnectionTreeSearchTextFilter _connectionTreeSearchTextFilter = new ConnectionTreeSearchTextFilter(); + private bool _nodeInEditMode; private bool _allowEdit; private ConnectionContextMenu _contextMenu; private ConnectionTreeModel _connectionTreeModel; @@ -54,8 +55,6 @@ namespace mRemoteNG.UI.Controls UseOverlays = false; } - - protected override void Dispose(bool disposing) { if (disposing) @@ -221,14 +220,19 @@ namespace mRemoteNG.UI.Controls return (RootNodeInfo)ConnectionTreeModel.RootNodes.First(item => item is RootNodeInfo); } + public void Invoke(Action action) + { + Invoke((Delegate)action); + } + public void InvokeExpand(object model) { - Invoke((MethodInvoker)(() => Expand(model))); + Invoke(() => Expand(model)); } public void InvokeRebuildAll(bool preserveState) { - Invoke((MethodInvoker)(() => RebuildAll(preserveState))); + Invoke(() => RebuildAll(preserveState)); } public IEnumerable GetRootPuttyNodes() @@ -262,6 +266,12 @@ namespace mRemoteNG.UI.Controls private void AddNode(ConnectionInfo newNode) { + if (SelectedNode?.GetTreeNodeType() == TreeNodeType.PuttyRoot || SelectedNode?.GetTreeNodeType() == TreeNodeType.PuttySession) + return; + + // the new node will survive filtering if filtering is active + _connectionTreeSearchTextFilter.SpecialInclusionList.Add(newNode); + // use root node if no node is selected ConnectionInfo parentNode = SelectedNode ?? GetRootConnectionNode(); DefaultConnectionInfo.Instance.SaveTo(newNode); @@ -272,11 +282,19 @@ namespace mRemoteNG.UI.Controls Expand(parent); SelectObject(newNode, true); EnsureModelVisible(newNode); + _allowEdit = true; SelectedItem.BeginEdit(); } 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); @@ -284,8 +302,11 @@ namespace mRemoteNG.UI.Controls public void RenameSelectedNode() { - _allowEdit = true; - SelectedItem.BeginEdit(); + if (SelectedItem != null) + { + _allowEdit = true; + SelectedItem.BeginEdit(); + } } public void DeleteSelectedNode() @@ -300,19 +321,75 @@ 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(); + } + + /// + /// Expands all tree objects and recalculates the + /// column widths. + /// + public override void ExpandAll() + { + base.ExpandAll(); + AutoResizeColumn(Columns[0]); + } + + /// + /// Filters tree items based on the given + /// + /// The text to filter by + public void ApplyFilter(string filterText) + { + UseFiltering = true; + _connectionTreeSearchTextFilter.FilterText = filterText; + ModelFilter = _connectionTreeSearchTextFilter; + } + + /// + /// Removes all item filtering from the connection tree + /// + public void RemoveFilter() + { + UseFiltering = false; + ResetColumnFiltering(); } 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(); + } } + protected override void UpdateFiltering() + { + base.UpdateFiltering(); + AutoResizeColumn(Columns[0]); + } + private void tvConnections_AfterSelect(object sender, EventArgs e) { try @@ -349,6 +426,13 @@ namespace mRemoteNG.UI.Controls { try { + if (!Settings.Default.ShowDescriptionTooltipsInTree) + { + // setting text to null prevents the tooltip from being shown + e.Text = null; + return; + } + var nodeProducingTooltip = (ConnectionInfo)e.Model; e.Text = nodeProducingTooltip.Description; } @@ -384,6 +468,9 @@ namespace mRemoteNG.UI.Controls ConnectionTreeModel.RenameNode(SelectedNode, e.Label); _nodeInEditMode = false; _allowEdit = false; + // ensures that if we are filtering and a new item is added that doesn't match the filter, it will be filtered out + _connectionTreeSearchTextFilter.SpecialInclusionList.Clear(); + UpdateFiltering(); Windows.ConfigForm.SelectedTreeNode = SelectedNode; } catch (Exception ex) @@ -393,4 +480,4 @@ namespace mRemoteNG.UI.Controls } #endregion } -} \ No newline at end of file +} diff --git a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTreeSearchTextFilter.cs b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTreeSearchTextFilter.cs index e31c0a5aa..82e388584 100644 --- a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTreeSearchTextFilter.cs +++ b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTreeSearchTextFilter.cs @@ -1,4 +1,5 @@ -using BrightIdeasSoftware; +using System.Collections.Generic; +using BrightIdeasSoftware; using mRemoteNG.Connection; namespace mRemoteNG.UI.Controls @@ -7,12 +8,22 @@ namespace mRemoteNG.UI.Controls { public string FilterText { get; set; } = ""; + /// + /// A list of objects that should + /// always be included in the output, regardless of matching + /// the desired . + /// + public List SpecialInclusionList { get; } = new List(); + public bool Filter(object modelObject) { var objectAsConnectionInfo = modelObject as ConnectionInfo; if (objectAsConnectionInfo == null) return false; + if (SpecialInclusionList.Contains(objectAsConnectionInfo)) + return true; + var filterTextLower = FilterText.ToLowerInvariant(); if (objectAsConnectionInfo.Name.ToLowerInvariant().Contains(filterTextLower) || diff --git a/mRemoteV1/UI/Controls/FilteredPropertyGrid/FilteredPropertyGrid.cs b/mRemoteV1/UI/Controls/FilteredPropertyGrid/FilteredPropertyGrid.cs index 37c1829b0..127654ba5 100644 --- a/mRemoteV1/UI/Controls/FilteredPropertyGrid/FilteredPropertyGrid.cs +++ b/mRemoteV1/UI/Controls/FilteredPropertyGrid/FilteredPropertyGrid.cs @@ -1,171 +1,263 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Linq; using System.Windows.Forms; using mRemoteNG.App; namespace mRemoteNG.UI.Controls.FilteredPropertyGrid { - /// - /// This class overrides the standard PropertyGrid provided by Microsoft. - /// It also allows to hide (or filter) the properties of the SelectedObject displayed by the PropertyGrid. - /// - public partial class FilteredPropertyGrid : PropertyGrid + /// + /// This class overrides the standard PropertyGrid provided by Microsoft. + /// It also allows to hide (or filter) the properties of the SelectedObject displayed by the PropertyGrid. + /// + public partial class FilteredPropertyGrid : PropertyGrid { - /// Contain a reference to the collection of properties to show in the parent PropertyGrid. + /// + /// Contain a reference to the collection of properties to show in the parent PropertyGrid. + /// /// By default, m_PropertyDescriptors contain all the properties of the object. - readonly List m_PropertyDescriptors = new List(); - /// Contain a reference to the array of properties to display in the PropertyGrid. - private AttributeCollection m_HiddenAttributes, m_BrowsableAttributes; - /// Contain references to the arrays of properties or categories to hide. - private string[] m_BrowsableProperties, m_HiddenProperties; - /// Contain a reference to the wrapper that contains the object to be displayed into the PropertyGrid. - private ObjectWrapper m_Wrapper; + readonly List _propertyDescriptors = new List(); - /// Public constructor. - public FilteredPropertyGrid() { + /// + /// Contain a reference to the array of properties to display in the PropertyGrid. + /// + private AttributeCollection _hiddenAttributes; + private AttributeCollection _browsableAttributes; + + /// + /// Contain references to the arrays of properties or categories to hide. + /// + private string[] _mBrowsableProperties; + private string[] _mHiddenProperties; + /// + /// Contain a reference to the wrapper that contains the object to be displayed into the PropertyGrid. + /// + private ObjectWrapper _mWrapper; + + /// + /// Public constructor. + /// + public FilteredPropertyGrid() + { InitializeComponent(); - base.SelectedObject = m_Wrapper; + base.SelectedObject = _mWrapper; } - public new AttributeCollection BrowsableAttributes { - get { return m_BrowsableAttributes; } + /// + /// A list of all currently properties being shown by the property grid. + /// + public IEnumerable VisibleProperties => _propertyDescriptors.Select(p => p.Name); + + public new AttributeCollection BrowsableAttributes { + get { return _browsableAttributes; } set { - if (m_BrowsableAttributes == value) return; - m_HiddenAttributes = null; - m_BrowsableAttributes = value; + if (_browsableAttributes == value) return; + _hiddenAttributes = null; + _browsableAttributes = value; RefreshProperties(); } } - /// Get or set the categories to hide. + /// + /// Get or set the categories to hide. + /// public AttributeCollection HiddenAttributes { - get { return m_HiddenAttributes; } + get { return _hiddenAttributes; } set { - if (value == m_HiddenAttributes) return; - m_HiddenAttributes = value; - m_BrowsableAttributes = null; + if (value == _hiddenAttributes) return; + _hiddenAttributes = value; + _browsableAttributes = null; RefreshProperties(); } } - /// Get or set the properties to show. + + /// + /// Get or set the properties to show. + /// /// if one or several properties don't exist. public string[] BrowsableProperties { - get { return m_BrowsableProperties; } + get { return _mBrowsableProperties; } set { - if (value == m_BrowsableProperties) return; - m_BrowsableProperties = value; - //m_HiddenProperties = null; + if (value == _mBrowsableProperties) return; + _mBrowsableProperties = value; RefreshProperties(); } } /// Get or set the properties to hide. public string[] HiddenProperties { - get { return m_HiddenProperties; } + get { return _mHiddenProperties; } set { - if (value == m_HiddenProperties) return; - //m_BrowsableProperties = null; - m_HiddenProperties = value; + if (value == _mHiddenProperties) return; + _mHiddenProperties = value; RefreshProperties(); } } - /// Overwrite the PropertyGrid.SelectedObject property. + /// + /// Overwrite the PropertyGrid.SelectedObject property. + /// /// The object passed to the base PropertyGrid is the wrapper. public new object SelectedObject { - get { return m_Wrapper != null ? ((ObjectWrapper)base.SelectedObject).SelectedObject : null; } + get + { + return _mWrapper != null + ? ((ObjectWrapper)base.SelectedObject).SelectedObject + : null; + } set { // Set the new object to the wrapper and create one if necessary. - if(m_Wrapper == null) { - m_Wrapper = new ObjectWrapper(value); + if(_mWrapper == null) + { + _mWrapper = new ObjectWrapper(value); RefreshProperties(); } - else if(m_Wrapper.SelectedObject != value) { - var needrefresh = value.GetType() != m_Wrapper.SelectedObject.GetType(); - m_Wrapper.SelectedObject = value; - if(needrefresh) RefreshProperties(); + else if(_mWrapper.SelectedObject != value) + { + var needrefresh = value.GetType() != _mWrapper.SelectedObject.GetType(); + _mWrapper.SelectedObject = value; + if(needrefresh) + RefreshProperties(); } // Set the list of properties to the wrapper. - m_Wrapper.PropertyDescriptors = m_PropertyDescriptors; + _mWrapper.PropertyDescriptors = _propertyDescriptors; // Link the wrapper to the parent PropertyGrid. - base.SelectedObject = m_Wrapper; + base.SelectedObject = _mWrapper; } } - /* - /// Called when the browsable properties have changed. - private void OnBrowsablePropertiesChanged() { - if(m_Wrapper == null) return; - } - */ + /// + /// Build the list of the properties to be displayed in the PropertyGrid, following the filters defined the Browsable and Hidden properties. + /// + private void RefreshProperties() + { + if(_mWrapper == null) + return; - /// Build the list of the properties to be displayed in the PropertyGrid, following the filters defined the Browsable and Hidden properties. - private void RefreshProperties() { - if(m_Wrapper == null) return; // Clear the list of properties to be displayed. - m_PropertyDescriptors.Clear(); + _propertyDescriptors.Clear(); // Check whether the list is filtered - if(m_BrowsableAttributes != null && m_BrowsableAttributes.Count > 0) { + if(_browsableAttributes != null && _browsableAttributes.Count > 0) + { // Add to the list the attributes that need to be displayed. - foreach(Attribute attribute in m_BrowsableAttributes) ShowAttribute(attribute); - } else { - // Fill the collection with all the properties. - var originalpropertydescriptors = TypeDescriptor.GetProperties(m_Wrapper.SelectedObject); - foreach(PropertyDescriptor propertydescriptor in originalpropertydescriptors) m_PropertyDescriptors.Add(propertydescriptor); - // Remove from the list the attributes that mustn't be displayed. - if(m_HiddenAttributes != null) foreach(Attribute attribute in m_HiddenAttributes) HideAttribute(attribute); + foreach(Attribute attribute in _browsableAttributes) + ShowAttribute(attribute); } + else + { + // Fill the collection with all the properties. + var originalPropertyDescriptors = TypeDescriptor + .GetProperties(_mWrapper.SelectedObject) + .OfType() + .Where(PropertyDoesntHaveBrowsableFalseAttribute); + + foreach(PropertyDescriptor propertyDescriptor in originalPropertyDescriptors) + _propertyDescriptors.Add(propertyDescriptor); + + // Remove from the list the attributes that mustn't be displayed. + if(_hiddenAttributes != null) + foreach (Attribute attribute in _hiddenAttributes) + HideAttribute(attribute); + } + // Get all the properties of the SelectedObject - var allproperties = TypeDescriptor.GetProperties(m_Wrapper.SelectedObject); - // Hide if necessary, some properties - if(m_HiddenProperties != null && m_HiddenProperties.Length > 0) { + var allproperties = TypeDescriptor.GetProperties(_mWrapper.SelectedObject); + + // Hide if necessary, some properties + if(_mHiddenProperties != null && _mHiddenProperties.Length > 0) + { // Remove from the list the properties that mustn't be displayed. - foreach(var propertyname in m_HiddenProperties) { - try { + foreach(var propertyname in _mHiddenProperties) + { + try + { var property = allproperties[propertyname]; // Remove from the list the property HideProperty(property); - } catch(Exception ex) { + } + catch (Exception ex) + { Runtime.MessageCollector.AddExceptionMessage("FilteredPropertyGrid: Could not hide Property.", ex); } } } + // Display if necessary, some properties - if(m_BrowsableProperties != null && m_BrowsableProperties.Length > 0) { - foreach(var propertyname in m_BrowsableProperties) { - try { + if(_mBrowsableProperties != null && _mBrowsableProperties.Length > 0) + { + foreach(var propertyname in _mBrowsableProperties) + { + try + { ShowProperty(allproperties[propertyname]); - } catch(Exception knfe) { - Runtime.MessageCollector.AddExceptionMessage("FilteredPropertyGrid: Property not found", knfe); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("FilteredPropertyGrid: Property not found", ex); } } } } - /// Allows to hide a set of properties to the parent PropertyGrid. + + /// + /// Predicate to determine if a property has a Browsable(false) attribute + /// attatched to it. If so, it should not be shown. + /// + /// + /// + private bool PropertyDoesntHaveBrowsableFalseAttribute(PropertyDescriptor propertyDescriptor) + { + return !propertyDescriptor.Attributes.Contains(new BrowsableAttribute(false)); + } + + /// + /// Allows to hide a set of properties to the parent PropertyGrid. + /// /// A set of attributes that filter the original collection of properties. /// For better performance, include the BrowsableAttribute with true value. - private void HideAttribute(Attribute attribute) { - var filteredoriginalpropertydescriptors = TypeDescriptor.GetProperties(m_Wrapper.SelectedObject,new[] { attribute }); - if(filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0) throw new ArgumentException("Attribute not found",attribute.ToString()); - foreach(PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors) HideProperty(propertydescriptor); + private void HideAttribute(Attribute attribute) + { + var filteredoriginalpropertydescriptors = TypeDescriptor.GetProperties(_mWrapper.SelectedObject,new[] { attribute }); + if(filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0) + throw new ArgumentException("Attribute not found", attribute.ToString()); + + foreach(PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors) + HideProperty(propertydescriptor); } - /// Add all the properties that match an attribute to the list of properties to be displayed in the PropertyGrid. + + /// + /// Add all the properties that match an attribute to the list of properties to be displayed in the PropertyGrid. + /// /// The attribute to be added. - private void ShowAttribute(Attribute attribute) { - var filteredoriginalpropertydescriptors = TypeDescriptor.GetProperties(m_Wrapper.SelectedObject,new[] { attribute }); - if(filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0) throw new ArgumentException("Attribute not found",attribute.ToString()); - foreach(PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors) ShowProperty(propertydescriptor); + private void ShowAttribute(Attribute attribute) + { + var filteredoriginalpropertydescriptors = TypeDescriptor.GetProperties(_mWrapper.SelectedObject,new[] { attribute }); + if(filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0) + throw new ArgumentException("Attribute not found", attribute.ToString()); + + foreach(PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors) + ShowProperty(propertydescriptor); } - /// Add a property to the list of properties to be displayed in the PropertyGrid. + + /// + /// Add a property to the list of properties to be displayed in the PropertyGrid. + /// /// The property to be added. - private void ShowProperty(PropertyDescriptor property) { - if(!m_PropertyDescriptors.Contains(property)) m_PropertyDescriptors.Add(property); + private void ShowProperty(PropertyDescriptor property) + { + if(!_propertyDescriptors.Contains(property)) + _propertyDescriptors.Add(property); } - /// Allows to hide a property to the parent PropertyGrid. + + /// + /// Allows to hide a property to the parent PropertyGrid. + /// /// The name of the property to be hidden. - private void HideProperty(PropertyDescriptor property) { - if(m_PropertyDescriptors.Contains(property)) m_PropertyDescriptors.Remove(property); + private void HideProperty(PropertyDescriptor property) + { + if(_propertyDescriptors.Contains(property)) + _propertyDescriptors.Remove(property); } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Controls/FilteredPropertyGrid/ObjectWrapper.cs b/mRemoteV1/UI/Controls/FilteredPropertyGrid/ObjectWrapper.cs index b93985529..a67abef46 100644 --- a/mRemoteV1/UI/Controls/FilteredPropertyGrid/ObjectWrapper.cs +++ b/mRemoteV1/UI/Controls/FilteredPropertyGrid/ObjectWrapper.cs @@ -4,96 +4,119 @@ using System.ComponentModel; namespace mRemoteNG.UI.Controls.FilteredPropertyGrid { - /// This class is a wrapper. It contains the object the propertyGrid has to display. - internal class ObjectWrapper : ICustomTypeDescriptor + /// + /// This class is a wrapper. It contains the object the PropertyGrid has to display. + /// + internal class ObjectWrapper : ICustomTypeDescriptor { - /// Contain a reference to the selected objet that will linked to the parent PropertyGrid. - private object m_SelectedObject; - /// Contain a reference to the collection of properties to show in the parent PropertyGrid. - /// By default, m_PropertyDescriptors contain all the properties of the object. - List m_PropertyDescriptors = new List(); - - /// Simple constructor. + /// + /// Creates a new instance of an with the given object to be wrapped. + /// /// A reference to the selected object that will linked to the parent PropertyGrid. - internal ObjectWrapper(object obj) { - m_SelectedObject = obj; + internal ObjectWrapper(object obj) + { + SelectedObject = obj; } - /// Get or set a reference to the selected objet that will linked to the parent PropertyGrid. - public object SelectedObject { - get { return m_SelectedObject; } - set { m_SelectedObject = value; } - } + /// + /// Get or set a reference to the selected objet that will linked to the parent PropertyGrid. + /// + public object SelectedObject { get; set; } - /// Get or set a reference to the collection of properties to show in the parent PropertyGrid. - public List PropertyDescriptors { - get { return m_PropertyDescriptors; } - set { m_PropertyDescriptors = value; } - } + /// + /// Get or set a reference to the collection of properties to show in the parent PropertyGrid + /// + public List PropertyDescriptors { get; set; } = new List(); - #region ICustomTypeDescriptor Members - public PropertyDescriptorCollection GetProperties(Attribute[] attributes) { + #region ICustomTypeDescriptor Members + public PropertyDescriptorCollection GetProperties(Attribute[] attributes) + { return GetProperties(); } - public PropertyDescriptorCollection GetProperties() { - return new PropertyDescriptorCollection(m_PropertyDescriptors.ToArray(),true); + public PropertyDescriptorCollection GetProperties() + { + return new PropertyDescriptorCollection(PropertyDescriptors.ToArray(), true); } - /// GetAttributes. + /// + /// GetAttributes + /// /// AttributeCollection - public AttributeCollection GetAttributes() { - return TypeDescriptor.GetAttributes(m_SelectedObject,true); - } - /// Get Class Name. - /// String - public String GetClassName() { - return TypeDescriptor.GetClassName(m_SelectedObject,true); - } - /// GetComponentName. - /// String - public String GetComponentName() { - return TypeDescriptor.GetComponentName(m_SelectedObject,true); + public AttributeCollection GetAttributes() + { + return TypeDescriptor.GetAttributes(SelectedObject, true); } - /// GetConverter. + /// + /// Get Class Name + /// + /// String + public string GetClassName() + { + return TypeDescriptor.GetClassName(SelectedObject, true); + } + + /// + /// GetComponentName + /// + /// String + public string GetComponentName() + { + return TypeDescriptor.GetComponentName(SelectedObject, true); + } + + /// + /// GetConverter + /// /// TypeConverter - public TypeConverter GetConverter() { - return TypeDescriptor.GetConverter(m_SelectedObject,true); + public TypeConverter GetConverter() + { + return TypeDescriptor.GetConverter(SelectedObject, true); } - /// GetDefaultEvent. + /// + /// GetDefaultEvent + /// /// EventDescriptor - public EventDescriptor GetDefaultEvent() { - return TypeDescriptor.GetDefaultEvent(m_SelectedObject,true); + public EventDescriptor GetDefaultEvent() + { + return TypeDescriptor.GetDefaultEvent(SelectedObject, true); } - /// GetDefaultProperty. + /// + /// GetDefaultProperty + /// /// PropertyDescriptor - public PropertyDescriptor GetDefaultProperty() { - return TypeDescriptor.GetDefaultProperty(m_SelectedObject,true); + public PropertyDescriptor GetDefaultProperty() + { + return TypeDescriptor.GetDefaultProperty(SelectedObject, true); } - /// GetEditor. + /// + /// GetEditor + /// /// editorBaseType /// object - public object GetEditor(Type editorBaseType) { - return TypeDescriptor.GetEditor(this,editorBaseType,true); + public object GetEditor(Type editorBaseType) + { + return TypeDescriptor.GetEditor(this,editorBaseType, true); } - public EventDescriptorCollection GetEvents(Attribute[] attributes) { - return TypeDescriptor.GetEvents(m_SelectedObject,attributes,true); + public EventDescriptorCollection GetEvents(Attribute[] attributes) + { + return TypeDescriptor.GetEvents(SelectedObject, attributes, true); } - public EventDescriptorCollection GetEvents() { - return TypeDescriptor.GetEvents(m_SelectedObject,true); + public EventDescriptorCollection GetEvents() + { + return TypeDescriptor.GetEvents(SelectedObject, true); } - public object GetPropertyOwner(PropertyDescriptor pd) { - return m_SelectedObject; + public object GetPropertyOwner(PropertyDescriptor pd) + { + return SelectedObject; } - #endregion - } } diff --git a/mRemoteV1/UI/Controls/IPTextBox.cs b/mRemoteV1/UI/Controls/IPTextBox.cs index bde3f5f54..7dad5a666 100644 --- a/mRemoteV1/UI/Controls/IPTextBox.cs +++ b/mRemoteV1/UI/Controls/IPTextBox.cs @@ -29,9 +29,8 @@ namespace mRemoteNG.UI.Controls /** Sets and Gets the tooltiptext on toolTip1 */ public string ToolTipText { - get - { return toolTip1.GetToolTip(Octet1); } - set + get => toolTip1.GetToolTip(Octet1); + set { toolTip1.SetToolTip(Octet1,value); toolTip1.SetToolTip(Octet2,value); @@ -46,12 +45,8 @@ namespace mRemoteNG.UI.Controls /** Set or Get the string that represents the value in the box */ public override string Text { - get - { - return Octet1.Text + @"." + Octet2.Text + @"." + Octet3.Text + @"." + Octet4.Text; - - } - set + get => Octet1.Text + @"." + Octet2.Text + @"." + Octet3.Text + @"." + Octet4.Text; + set { if (!string.IsNullOrEmpty(value)) { @@ -85,8 +80,7 @@ namespace mRemoteNG.UI.Controls } private void ApplyTheme() - { - if (Tools.DesignModeTest.IsInDesignMode(this)) return; + { if (Themes.ThemeManager.getInstance().ThemingActive) panel1.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); } @@ -246,7 +240,7 @@ namespace mRemoteNG.UI.Controls if(theValue >=0 && theValue <= 255) return true; - MessageBox.Show("Must Be Between 0 and 255","Out Of Range"); + MessageBox.Show(Language.strIPRange,Language.strOutOfRange); return false; } catch diff --git a/mRemoteV1/UI/Controls/MultiSshToolStrip.cs b/mRemoteV1/UI/Controls/MultiSshToolStrip.cs index c1c47dcaa..8edd94784 100644 --- a/mRemoteV1/UI/Controls/MultiSshToolStrip.cs +++ b/mRemoteV1/UI/Controls/MultiSshToolStrip.cs @@ -1,5 +1,6 @@ using System.ComponentModel; using System.Windows.Forms; +using mRemoteNG.Themes; using mRemoteNG.Tools; namespace mRemoteNG.UI.Controls @@ -10,12 +11,16 @@ namespace mRemoteNG.UI.Controls private ToolStripLabel _lblMultiSsh; private ToolStripTextBox _txtMultiSsh; private MultiSSHController _multiSshController; + private ThemeManager _themeManager; - public MultiSshToolStrip() + public MultiSshToolStrip() { InitializeComponent(); - _multiSshController = new MultiSSHController(_txtMultiSsh); + _themeManager = ThemeManager.getInstance(); + _themeManager.ThemeChanged += ApplyTheme; + ApplyTheme(); + _multiSshController = new MultiSSHController(_txtMultiSsh); } private void InitializeComponent() @@ -43,7 +48,14 @@ namespace mRemoteNG.UI.Controls ResumeLayout(true); } - protected override void Dispose(bool disposing) + private void ApplyTheme() + { + if (!_themeManager.ThemingActive) return; + _txtMultiSsh.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); + _txtMultiSsh.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); + } + + protected override void Dispose(bool disposing) { if (disposing) { diff --git a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs index 7fa60fa37..029b13c19 100644 --- a/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs +++ b/mRemoteV1/UI/Controls/QuickConnectToolStrip.cs @@ -5,6 +5,7 @@ using System.Windows.Forms; using mRemoteNG.App; using mRemoteNG.Connection; using mRemoteNG.Connection.Protocol; +using mRemoteNG.Container; using mRemoteNG.Themes; using mRemoteNG.Tools; @@ -232,10 +233,19 @@ namespace mRemoteNG.UI.Controls private void ConnectionsMenuItem_MouseUp(object sender, MouseEventArgs e) { if (e.Button != MouseButtons.Left) return; - var tag = ((ToolStripMenuItem)sender).Tag as ConnectionInfo; - if (tag != null) + var menuItem = (ToolStripMenuItem) sender; + + // While we can connect to a whole folder at once, it is + // probably not the expected behavior when navigating through + // a nested menu. Just return + var containerInfo = menuItem.Tag as ContainerInfo; + if (containerInfo != null) + return; + + var connectionInfo = menuItem.Tag as ConnectionInfo; + if (connectionInfo != null) { - ConnectionInitiator.OpenConnection(tag); + ConnectionInitiator.OpenConnection(connectionInfo); } } #endregion diff --git a/mRemoteV1/UI/DialogFactory.cs b/mRemoteV1/UI/DialogFactory.cs index 7192acf22..6ffbf1adc 100644 --- a/mRemoteV1/UI/DialogFactory.cs +++ b/mRemoteV1/UI/DialogFactory.cs @@ -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 + @"|*.*" }; } + + /// + /// Creates and shows a dialog to either create a new connections file, load a different one, + /// exit, or optionally cancel the operation. + /// + /// + /// + /// + public static void ShowLoadConnectionsFailedDialog(string connectionFileName, string messageText, bool showCancelButton) + { + var commandButtons = new List + { + 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); + } + } + } + + /// + /// 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! + /// + public static SaveFileDialog ConnectionsSaveAsDialog() + { + return new SaveFileDialog + { + CheckPathExists = true, + InitialDirectory = ConnectionsFileInfo.DefaultConnectionsPath, + FileName = ConnectionsFileInfo.DefaultConnectionsFile, + OverwritePrompt = true, + Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*" + }; + } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/ExportForm.Designer.cs b/mRemoteV1/UI/Forms/ExportForm.Designer.cs index 5cb23e2e2..b1a51586f 100644 --- a/mRemoteV1/UI/Forms/ExportForm.Designer.cs +++ b/mRemoteV1/UI/Forms/ExportForm.Designer.cs @@ -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"; diff --git a/mRemoteV1/UI/Forms/ExportForm.cs b/mRemoteV1/UI/Forms/ExportForm.cs index 8b2e8a78c..7daedde4a 100644 --- a/mRemoteV1/UI/Forms/ExportForm.cs +++ b/mRemoteV1/UI/Forms/ExportForm.cs @@ -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 diff --git a/mRemoteV1/UI/Forms/Input/input.cs b/mRemoteV1/UI/Forms/Input/input.cs index 67c842fd8..6df973c99 100644 --- a/mRemoteV1/UI/Forms/Input/input.cs +++ b/mRemoteV1/UI/Forms/Input/input.cs @@ -28,13 +28,13 @@ namespace mRemoteNG.UI.Forms.Input textBox.Anchor = textBox.Anchor | AnchorStyles.Right; textBox.SetBounds(12, 36, 372, 20); - buttonOk.Text = "OK"; + buttonOk.Text = Language.strButtonOK; buttonOk.DialogResult = DialogResult.OK; buttonOk.FlatStyle = FlatStyle.Flat; buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; buttonOk.SetBounds(228, 72, 75, 23); - buttonCancel.Text = "Cancel"; + buttonCancel.Text = Language.strButtonCancel; buttonCancel.DialogResult = DialogResult.Cancel; buttonCancel.FlatStyle = FlatStyle.Flat; buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; diff --git a/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.Designer.cs index 6696dcc22..4a6a50180 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.Designer.cs @@ -2,7 +2,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class AdvancedPage : OptionsPage + public sealed partial class AdvancedPage : OptionsPage { //UserControl overrides dispose to clean up the component list. [System.Diagnostics.DebuggerNonUserCode()] diff --git a/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs b/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs index 9dfc5d1a6..23937f1f8 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AdvancedPage.cs @@ -9,19 +9,19 @@ using mRemoteNG.Tools; namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class AdvancedPage + public sealed partial class AdvancedPage { public AdvancedPage() { InitializeComponent(); - base.ApplyTheme(); + ApplyTheme(); } #region Public Methods public override string PageName { - get { return Language.strTabAdvanced; } + get => Language.strTabAdvanced; set { } } @@ -32,7 +32,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages lblSeconds.Text = Language.strLabelSeconds; lblMaximumPuttyWaitTime.Text = Language.strLabelPuttyTimeout; chkAutomaticReconnect.Text = Language.strCheckboxAutomaticReconnect; - chkLoadBalanceInfoUseUtf8.Text = Language.LoadBalanceInfoUseUtf8; + chkLoadBalanceInfoUseUtf8.Text = Language.strLoadBalanceInfoUseUtf8; lblConfigurePuttySessions.Text = Language.strLabelPuttySessionsConfig; btnLaunchPutty.Text = Language.strButtonLaunchPutty; btnBrowseCustomPuttyPath.Text = Language.strButtonBrowse; @@ -108,16 +108,14 @@ namespace mRemoteNG.UI.Forms.OptionsPages { using (var openFileDialog = new OpenFileDialog()) { - openFileDialog.Filter = $"{Language.strFilterApplication}|*.exe|{Language.strFilterAll}|*.*"; + openFileDialog.Filter = $@"{Language.strFilterApplication}|*.exe|{Language.strFilterAll}|*.*"; openFileDialog.FileName = Path.GetFileName(GeneralAppInfo.PuttyPath); openFileDialog.CheckFileExists = true; openFileDialog.Multiselect = false; - if (openFileDialog.ShowDialog() == DialogResult.OK) - { - txtCustomPuttyPath.Text = openFileDialog.FileName; - SetPuttyLaunchButtonEnabled(); - } + if (openFileDialog.ShowDialog() != DialogResult.OK) return; + txtCustomPuttyPath.Text = openFileDialog.FileName; + SetPuttyLaunchButtonEnabled(); } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.Designer.cs index edd7ce7c7..6e550f441 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.Designer.cs @@ -3,7 +3,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class AppearancePage : OptionsPage + public sealed partial class AppearancePage : OptionsPage { //UserControl overrides dispose to clean up the component list. diff --git a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs index e16e516f6..5dae889c1 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/AppearancePage.cs @@ -5,17 +5,17 @@ using mRemoteNG.Tools; namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class AppearancePage + public sealed partial class AppearancePage { public AppearancePage() { InitializeComponent(); - base.ApplyTheme(); + ApplyTheme(); } public override string PageName { - get { return Language.strTabAppearance; } + get => Language.strTabAppearance; set { } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.Designer.cs index aacd20ce5..7f38b188c 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.Designer.cs @@ -3,7 +3,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class ConnectionsPage : OptionsPage + public sealed partial class ConnectionsPage : OptionsPage { //UserControl overrides dispose to clean up the component list. @@ -85,20 +85,20 @@ namespace mRemoteNG.UI.Forms.OptionsPages // // lblRDPConTimeout // - this.lblRDPConTimeout.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.lblRDPConTimeout.Location = new System.Drawing.Point(3, 6); + this.lblRDPConTimeout.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblRDPConTimeout.Location = new System.Drawing.Point(3, 0); this.lblRDPConTimeout.Name = "lblRDPConTimeout"; - this.lblRDPConTimeout.Size = new System.Drawing.Size(137, 13); + this.lblRDPConTimeout.Size = new System.Drawing.Size(261, 26); this.lblRDPConTimeout.TabIndex = 0; this.lblRDPConTimeout.Text = "RDP Connection Timeout"; this.lblRDPConTimeout.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // lblRdpReconnectionCount // - this.lblRdpReconnectionCount.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.lblRdpReconnectionCount.Location = new System.Drawing.Point(3, 6); + this.lblRdpReconnectionCount.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblRdpReconnectionCount.Location = new System.Drawing.Point(3, 0); this.lblRdpReconnectionCount.Name = "lblRdpReconnectionCount"; - this.lblRdpReconnectionCount.Size = new System.Drawing.Size(139, 13); + this.lblRdpReconnectionCount.Size = new System.Drawing.Size(261, 26); this.lblRdpReconnectionCount.TabIndex = 0; this.lblRdpReconnectionCount.Text = "RDP Reconnection Count"; this.lblRdpReconnectionCount.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; @@ -156,10 +156,10 @@ namespace mRemoteNG.UI.Forms.OptionsPages // // lblAutoSave1 // - this.lblAutoSave1.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.lblAutoSave1.Location = new System.Drawing.Point(3, 6); + this.lblAutoSave1.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblAutoSave1.Location = new System.Drawing.Point(3, 0); this.lblAutoSave1.Name = "lblAutoSave1"; - this.lblAutoSave1.Size = new System.Drawing.Size(261, 13); + this.lblAutoSave1.Size = new System.Drawing.Size(261, 26); this.lblAutoSave1.TabIndex = 0; this.lblAutoSave1.Text = "Auto Save in Minutes (0 means disabled)"; this.lblAutoSave1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; diff --git a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs index 302c2b434..a4ac76d2a 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ConnectionsPage.cs @@ -3,19 +3,19 @@ using mRemoteNG.Config; namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class ConnectionsPage + public sealed partial class ConnectionsPage { - private FrmMain _frmMain = FrmMain.Default; + private readonly FrmMain _frmMain = FrmMain.Default; public ConnectionsPage() { InitializeComponent(); - base.ApplyTheme(); + ApplyTheme(); } public override string PageName { - get { return Language.strConnections; } + get => Language.strConnections; set { } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.Designer.cs index 416050ab1..0d06f197f 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.Designer.cs @@ -1,6 +1,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - partial class CredentialsPage + sealed partial class CredentialsPage { /// /// Required designer variable. diff --git a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs index 64c91c46e..27b5e608a 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs @@ -4,16 +4,16 @@ using mRemoteNG.Security.SymmetricEncryption; namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class CredentialsPage : OptionsPage + public sealed partial class CredentialsPage : OptionsPage { public CredentialsPage() { InitializeComponent(); - base.ApplyTheme(); + ApplyTheme(); } public override string PageName { - get { return Language.Credentials; } + get => Language.Credentials; set { } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.Designer.cs index d183d8ff9..1d13b356e 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.Designer.cs @@ -3,7 +3,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class NotificationsPage : OptionsPage + public sealed partial class NotificationsPage : OptionsPage { //UserControl overrides dispose to clean up the component list. diff --git a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs index 477abbaeb..34e7d46f4 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/NotificationsPage.cs @@ -5,17 +5,17 @@ using mRemoteNG.App; namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class NotificationsPage + public sealed partial class NotificationsPage { public NotificationsPage() { InitializeComponent(); - base.ApplyTheme(); + ApplyTheme(); } public override string PageName { - get { return Language.strMenuNotifications; } + get => Language.strMenuNotifications; set { } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs index 1014d96c2..63357fd18 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/OptionsPage.cs @@ -9,25 +9,17 @@ namespace mRemoteNG.UI.Forms.OptionsPages protected OptionsPage() { //InitializeComponent(); - if (!Tools.DesignModeTest.IsInDesignMode(this)) - Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; - + Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; } #region Public Properties - [Browsable(false)]public virtual string PageName {get; set;} + // ReSharper disable once UnusedAutoPropertyAccessor.Global + [Browsable(false)]public virtual string PageName {get; set;} - public virtual Icon PageIcon {get; set;} - public virtual Image IconImage{ - get - { - if (PageIcon != null) - return PageIcon.ToBitmap(); - return null; - } - } + public virtual Icon PageIcon {get; protected set;} + public virtual Image IconImage => PageIcon?.ToBitmap(); - #endregion + #endregion #region Public Methods public virtual void ApplyLanguage() @@ -51,26 +43,26 @@ namespace mRemoteNG.UI.Forms.OptionsPages } #endregion + /* private void InitializeComponent() { - this.SuspendLayout(); + SuspendLayout(); // // OptionsPage // - this.Name = "OptionsPage"; - this.Size = new System.Drawing.Size(610, 489); - this.ResumeLayout(false); + Name = "OptionsPage"; + Size = new Size(610, 489); + ResumeLayout(false); } + */ - public virtual void ApplyTheme() + protected virtual void ApplyTheme() { - if (Themes.ThemeManager.getInstance().ThemingActive) - { - BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - Invalidate(); - } + if (!Themes.ThemeManager.getInstance().ThemingActive) return; + BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + Invalidate(); } } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.Designer.cs index f2e16032d..796e82e75 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.Designer.cs @@ -1,6 +1,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - partial class SecurityPage + sealed partial class SecurityPage { /// /// Required designer variable. diff --git a/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs b/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs index 0dce2d07b..b5e2c57e2 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/SecurityPage.cs @@ -4,20 +4,20 @@ using mRemoteNG.Security; namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class SecurityPage : OptionsPage + public sealed partial class SecurityPage : OptionsPage { public SecurityPage() { InitializeComponent(); PopulateEncryptionEngineDropDown(); PopulateBlockCipherDropDown(); - base.ApplyTheme(); + ApplyTheme(); } [Browsable(false)] public override string PageName { - get { return Language.strTabSecurity; } + get => Language.strTabSecurity; set { } } @@ -28,6 +28,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages labelBlockCipher.Text = Language.strEncryptionBlockCipherMode; labelEncryptionEngine.Text = Language.strEncryptionEngine; labelKdfIterations.Text = Language.strEncryptionKeyDerivationIterations; + groupAdvancedSecurityOptions.Text = Language.strAdvancedSecurityOptions; } public override void LoadSettings() diff --git a/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.Designer.cs index f1a1654fd..bfc4c758d 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.Designer.cs @@ -3,7 +3,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class SqlServerPage : OptionsPage + public sealed partial class SqlServerPage : OptionsPage { //UserControl overrides dispose to clean up the component list. diff --git a/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs b/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs index 4be316f22..ad59e290d 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs @@ -7,20 +7,20 @@ using mRemoteNG.Security.SymmetricEncryption; namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class SqlServerPage + public sealed partial class SqlServerPage { private readonly SqlDatabaseConnectionTester _databaseConnectionTester; public SqlServerPage() { InitializeComponent(); - base.ApplyTheme(); + ApplyTheme(); _databaseConnectionTester = new SqlDatabaseConnectionTester(); } public override string PageName { - get { return Language.strSQLServer.TrimEnd(':'); } + get => Language.strSQLServer.TrimEnd(':'); set { } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.Designer.cs index d12491cc1..7cbe6aebe 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.Designer.cs @@ -3,7 +3,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class StartupExitPage : OptionsPage + public sealed partial class StartupExitPage : OptionsPage { //UserControl overrides dispose to clean up the component list. diff --git a/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs b/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs index 88c1bee30..b3389990f 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/StartupExitPage.cs @@ -2,17 +2,17 @@ using System; namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class StartupExitPage + public sealed partial class StartupExitPage { public StartupExitPage() { InitializeComponent(); - base.ApplyTheme(); + ApplyTheme(); } public override string PageName { - get { return Language.strStartupExit; } + get => Language.strStartupExit; set { } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs index a5b974f94..1969b466d 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.Designer.cs @@ -3,7 +3,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class TabsPanelsPage : OptionsPage + public sealed partial class TabsPanelsPage : OptionsPage { //UserControl overrides dispose to clean up the component list. @@ -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; + } } diff --git a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs index 566c38a6b..24a5e22ba 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/TabsPanelsPage.cs @@ -1,16 +1,16 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class TabsPanelsPage + public sealed partial class TabsPanelsPage { public TabsPanelsPage() { InitializeComponent(); - base.ApplyTheme(); + ApplyTheme(); } public override string PageName { - get { return Language.strTabsAndPanels.Replace("&&", "&"); } + get => Language.strTabsAndPanels.Replace("&&", "&"); set { } } @@ -25,6 +25,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() @@ -38,6 +40,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() @@ -53,8 +58,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(); + } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs index 77c7ec0b5..0dd4f5321 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/ThemePage.cs @@ -1,9 +1,7 @@ using System; -using System.ComponentModel; using System.Windows.Forms; using mRemoteNG.Themes; using System.Linq; -using System.Drawing; using System.Collections.Generic; using BrightIdeasSoftware; @@ -24,18 +22,17 @@ namespace mRemoteNG.UI.Forms.OptionsPages { InitializeComponent(); - if (!Tools.DesignModeTest.IsInDesignMode(this)) - { - _themeManager = ThemeManager.getInstance(); - _themeManager.ThemeChanged += ApplyTheme; - _oriTheme = _themeManager.ActiveTheme; - _oriActiveTheming = _themeManager.ThemingActive; - } + _themeManager = ThemeManager.getInstance(); + if (!_themeManager.ThemingActive) return; + _themeManager = ThemeManager.getInstance(); + _themeManager.ThemeChanged += ApplyTheme; + _oriTheme = _themeManager.ActiveTheme; + _oriActiveTheming = _themeManager.ThemingActive; } public override string PageName { - get { return Language.strOptionsTabTheme; } + get => Language.strOptionsTabTheme; set { } } @@ -51,12 +48,9 @@ namespace mRemoteNG.UI.Forms.OptionsPages private new void ApplyTheme() { - if (Tools.DesignModeTest.IsInDesignMode(this)) + if (!_themeManager.ThemingActive) return; - if (Themes.ThemeManager.getInstance().ThemingActive) - { - base.ApplyTheme(); - } + base.ApplyTheme(); } public override void LoadSettings() @@ -67,6 +61,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages btnThemeDelete.Enabled = false; //Load the list of themes cboTheme.Items.Clear(); + // ReSharper disable once CoVariantArrayConversion cboTheme.Items.AddRange(_themeManager.LoadThemes().OrderBy(x => x.Name).ToArray()); cboTheme.SelectedItem = _themeManager.ActiveTheme; cboTheme_SelectionChangeCommitted(this, new EventArgs()); @@ -82,23 +77,23 @@ namespace mRemoteNG.UI.Forms.OptionsPages { themeEnableCombo.Checked = false; cboTheme.Enabled = false; + // reset to the default theme when disabling theme support + _themeManager.ActiveTheme = _themeManager.DefaultTheme; } } private void ListPalette_FormatCell(object sender, FormatCellEventArgs e) { - if (e.ColumnIndex == this.ColorCol.Index) - { - PseudoKeyColor colorElem = (PseudoKeyColor)e.Model; - e.SubItem.BackColor = colorElem.Value; - } + if (e.ColumnIndex != ColorCol.Index) return; + var colorElem = (PseudoKeyColor)e.Model; + e.SubItem.BackColor = colorElem.Value; } public override void SaveSettings() { base.SaveSettings(); - foreach(ThemeInfo updatedTheme in modifiedThemes) + foreach(var updatedTheme in modifiedThemes) { _themeManager.updateTheme(updatedTheme); } @@ -122,26 +117,18 @@ namespace mRemoteNG.UI.Forms.OptionsPages { btnThemeNew.Enabled = false; btnThemeDelete.Enabled = false; - if (_themeManager.ThemingActive) - { - _themeManager.ActiveTheme = (ThemeInfo)cboTheme.SelectedItem; - listPalette.ClearObjects(); - if (_themeManager.ActiveTheme.IsExtendable && _themeManager.ThemingActive) - { - btnThemeNew.Enabled = true; - listPalette.ClearObjects(); - listPalette.Enabled = false; - ColorMeList(); - if (!_themeManager.ActiveTheme.IsThemeBase) - { - listPalette.Enabled = true; - btnThemeDelete.Enabled = true; - listPalette.CellClick += ListPalette_CellClick; - - } - } - } - + if (!_themeManager.ThemingActive) return; + _themeManager.ActiveTheme = (ThemeInfo)cboTheme.SelectedItem; + listPalette.ClearObjects(); + if (!_themeManager.ActiveTheme.IsExtendable || !_themeManager.ThemingActive) return; + btnThemeNew.Enabled = true; + listPalette.ClearObjects(); + listPalette.Enabled = false; + ColorMeList(); + if (_themeManager.ActiveTheme.IsThemeBase) return; + listPalette.Enabled = true; + btnThemeDelete.Enabled = true; + listPalette.CellClick += ListPalette_CellClick; } @@ -155,63 +142,59 @@ namespace mRemoteNG.UI.Forms.OptionsPages private void ListPalette_CellClick(object sender, CellClickEventArgs e) { - PseudoKeyColor colorElem = (PseudoKeyColor)e.Model; + var colorElem = (PseudoKeyColor)e.Model; - ColorDialog colorDlg = new ColorDialog(); - colorDlg.AllowFullOpen = true; - colorDlg.FullOpen = true; - colorDlg.AnyColor = true; - colorDlg.SolidColorOnly = false; - colorDlg.Color = colorElem.Value; - - if (colorDlg.ShowDialog() == DialogResult.OK) + var colorDlg = new ColorDialog { - modifiedThemes.Add(_themeManager.ActiveTheme); - _themeManager.ActiveTheme.ExtendedPalette.replaceColor(colorElem.Key, colorDlg.Color); - colorElem.Value = colorDlg.Color; - listPalette.RefreshObject(e.Model); - _themeManager.refreshUI(); - } + AllowFullOpen = true, + FullOpen = true, + AnyColor = true, + SolidColorOnly = false, + Color = colorElem.Value + }; + + if (colorDlg.ShowDialog() != DialogResult.OK) return; + modifiedThemes.Add(_themeManager.ActiveTheme); + _themeManager.ActiveTheme.ExtendedPalette.replaceColor(colorElem.Key, colorDlg.Color); + colorElem.Value = colorDlg.Color; + listPalette.RefreshObject(e.Model); + _themeManager.refreshUI(); } private void ColorMeList() { - foreach (KeyValuePair colorElem in _themeManager.ActiveTheme.ExtendedPalette.ExtColorPalette) + foreach (var colorElem in _themeManager.ActiveTheme.ExtendedPalette.ExtColorPalette) listPalette.AddObject(new PseudoKeyColor(colorElem.Key, colorElem.Value)); } private void btnThemeNew_Click(object sender, EventArgs e) { - String name = _themeManager.ActiveTheme.Name; - DialogResult res = Input.input.InputBox(Language.strOptionsThemeNewThemeCaption, Language.strOptionsThemeNewThemeText, ref name); - if (res == DialogResult.OK) + var name = _themeManager.ActiveTheme.Name; + var res = Input.input.InputBox(Language.strOptionsThemeNewThemeCaption, Language.strOptionsThemeNewThemeText, ref name); + if (res != DialogResult.OK) return; + if (_themeManager.isThemeNameOk(name)) { - if (_themeManager.isThemeNameOk(name)) - { - ThemeInfo addedTheme = _themeManager.addTheme(_themeManager.ActiveTheme, name); - _themeManager.ActiveTheme = addedTheme; - LoadSettings(); - } - else - { - TaskDialog.CTaskDialog.ShowTaskDialogBox(this, Language.strErrors, Language.strOptionsThemeNewThemeError, "", "", "", "", "", "", TaskDialog.ETaskDialogButtons.Ok, TaskDialog.ESysIcons.Error, TaskDialog.ESysIcons.Information, 0); - } + var addedTheme = _themeManager.addTheme(_themeManager.ActiveTheme, name); + _themeManager.ActiveTheme = addedTheme; + LoadSettings(); + } + else + { + TaskDialog.CTaskDialog.ShowTaskDialogBox(this, Language.strErrors, Language.strOptionsThemeNewThemeError, "", "", "", "", "", "", TaskDialog.ETaskDialogButtons.Ok, TaskDialog.ESysIcons.Error, TaskDialog.ESysIcons.Information, 0); } } private void btnThemeDelete_Click(object sender, EventArgs e) { - DialogResult res = TaskDialog.CTaskDialog.ShowTaskDialogBox(this, Language.strWarnings , Language.strOptionsThemeDeleteConfirmation, "", "", "", "", "", "", TaskDialog.ETaskDialogButtons.YesNo, TaskDialog.ESysIcons.Question, TaskDialog.ESysIcons.Information, 0); + var res = TaskDialog.CTaskDialog.ShowTaskDialogBox(this, Language.strWarnings , Language.strOptionsThemeDeleteConfirmation, "", "", "", "", "", "", TaskDialog.ETaskDialogButtons.YesNo, TaskDialog.ESysIcons.Question, TaskDialog.ESysIcons.Information, 0); - if (res == DialogResult.Yes) - { - if (modifiedThemes.Contains(_themeManager.ActiveTheme)) - modifiedThemes.Remove(_themeManager.ActiveTheme); - _themeManager.deleteTheme(_themeManager.ActiveTheme); - LoadSettings(); - } + if (res != DialogResult.Yes) return; + if (modifiedThemes.Contains(_themeManager.ActiveTheme)) + modifiedThemes.Remove(_themeManager.ActiveTheme); + _themeManager.deleteTheme(_themeManager.ActiveTheme); + LoadSettings(); } #endregion diff --git a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.Designer.cs b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.Designer.cs index af0207c93..8cec079e4 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.Designer.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.Designer.cs @@ -2,7 +2,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class UpdatesPage : OptionsPage + public sealed partial class UpdatesPage : OptionsPage { //UserControl overrides dispose to clean up the component list. diff --git a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs index 63bc94ca0..4a4de03cb 100644 --- a/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs +++ b/mRemoteV1/UI/Forms/OptionsPages/UpdatesPage.cs @@ -10,7 +10,7 @@ using mRemoteNG.UI.TaskDialog; namespace mRemoteNG.UI.Forms.OptionsPages { - public partial class UpdatesPage + public sealed partial class UpdatesPage { #region Private Fields @@ -21,14 +21,14 @@ namespace mRemoteNG.UI.Forms.OptionsPages public UpdatesPage() { InitializeComponent(); - base.ApplyTheme(); + ApplyTheme(); } #region Public Methods public override string PageName { - get { return Language.strTabUpdates; } + get => Language.strTabUpdates; set { } } diff --git a/mRemoteV1/UI/Forms/PasswordForm.cs b/mRemoteV1/UI/Forms/PasswordForm.cs index 04f678352..9aafa1dbb 100644 --- a/mRemoteV1/UI/Forms/PasswordForm.cs +++ b/mRemoteV1/UI/Forms/PasswordForm.cs @@ -2,6 +2,7 @@ using System; using System.Security; using System.Windows.Forms; using mRemoteNG.Security; +using mRemoteNG.Tools; namespace mRemoteNG.UI.Forms { @@ -10,21 +11,40 @@ namespace mRemoteNG.UI.Forms private readonly string _passwordName; private SecureString _password = new SecureString(); - private bool Verify { get; } + /// + /// Puts the dialog into the New Password mode. An extra + /// password box is shown which must match the first password + /// to continue. + /// + private bool NewPasswordMode { get; } - public PasswordForm(string passwordName = null, bool verify = true) + /// + /// Creates a new password form for entering or setting a password. + /// + /// + /// + /// Puts the dialog into the New Password mode. An extra + /// password box is shown which must match the first password + /// to continue. + /// + public PasswordForm(string passwordName = null, bool newPasswordMode = true) { InitializeComponent(); _passwordName = passwordName; - Verify = verify; + NewPasswordMode = newPasswordMode; } - public SecureString GetKey() + /// + /// Dispaly a dialog box requesting that the user + /// enter their password. + /// + /// + public Optional GetKey() { var dialog = ShowDialog(); return dialog == DialogResult.OK ? _password - : new SecureString(); + : Optional.Empty; } #region Event Handlers @@ -32,7 +52,7 @@ namespace mRemoteNG.UI.Forms { ApplyLanguage(); - if (Verify) return; + if (NewPasswordMode) return; Height = Height - (txtVerify.Top - txtPassword.Top); lblVerify.Visible = false; txtVerify.Visible = false; @@ -43,7 +63,7 @@ namespace mRemoteNG.UI.Forms _password = txtPassword.Text.ConvertToSecureString(); txtPassword.Text = ""; txtVerify.Text = ""; - if (Verify) return; + if (NewPasswordMode) return; Height = Height + (txtVerify.Top - txtPassword.Top); } @@ -54,12 +74,12 @@ namespace mRemoteNG.UI.Forms } private void btnOK_Click(object sender, EventArgs e) - { - if (Verify && VerifyPassword()) - DialogResult = DialogResult.OK; - else - DialogResult = DialogResult.OK; - } + { + if (NewPasswordMode) + VerifyNewPassword(); + + DialogResult = DialogResult.OK; + } private void txtPassword_TextChanged(object sender, EventArgs e) { @@ -78,7 +98,7 @@ namespace mRemoteNG.UI.Forms btnOK.Text = Language.strButtonOK; } - private bool VerifyPassword() + private bool VerifyNewPassword() { if (txtPassword.Text.Length >= 3) { diff --git a/mRemoteV1/UI/Forms/frmChoosePanel.Designer.cs b/mRemoteV1/UI/Forms/frmChoosePanel.Designer.cs index 083ad1ba5..66d789eaa 100644 --- a/mRemoteV1/UI/Forms/frmChoosePanel.Designer.cs +++ b/mRemoteV1/UI/Forms/frmChoosePanel.Designer.cs @@ -29,25 +29,26 @@ namespace mRemoteNG.UI.Forms //Do not modify it using the code editor. [System.Diagnostics.DebuggerStepThrough()]private void InitializeComponent() { - this.cbPanels = new Controls.Base.NGComboBox(); - this.btnOK = new Controls.Base.NGButton(); - this.lblDescription = new Controls.Base.NGLabel(); - this.btnNew = new Controls.Base.NGButton(); - this.btnCancel = new Controls.Base.NGButton(); + this.cbPanels = new mRemoteNG.UI.Controls.Base.NGComboBox(); + this.btnOK = new mRemoteNG.UI.Controls.Base.NGButton(); + this.lblDescription = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.btnNew = new mRemoteNG.UI.Controls.Base.NGButton(); this.SuspendLayout(); // // cbPanels // + this.cbPanels._mice = mRemoteNG.UI.Controls.Base.NGComboBox.MouseState.HOVER; this.cbPanels.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbPanels.FormattingEnabled = true; - this.cbPanels.Location = new System.Drawing.Point(79, 42); + this.cbPanels.Location = new System.Drawing.Point(12, 42); this.cbPanels.Name = "cbPanels"; - this.cbPanels.Size = new System.Drawing.Size(157, 21); + this.cbPanels.Size = new System.Drawing.Size(224, 21); this.cbPanels.TabIndex = 10; // // btnOK // - this.btnOK.Location = new System.Drawing.Point(92, 73); + this.btnOK._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; + this.btnOK.Location = new System.Drawing.Point(167, 72); this.btnOK.Name = "btnOK"; this.btnOK.Size = new System.Drawing.Size(69, 23); this.btnOK.TabIndex = 20; @@ -66,9 +67,10 @@ namespace mRemoteNG.UI.Forms // // btnNew // + this.btnNew._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnNew.Image = global::mRemoteNG.Resources.Panel_Add; this.btnNew.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; - this.btnNew.Location = new System.Drawing.Point(10, 38); + this.btnNew.Location = new System.Drawing.Point(101, 70); this.btnNew.Name = "btnNew"; this.btnNew.Size = new System.Drawing.Size(60, 27); this.btnNew.TabIndex = 40; @@ -77,27 +79,14 @@ namespace mRemoteNG.UI.Forms this.btnNew.UseVisualStyleBackColor = true; this.btnNew.Click += new System.EventHandler(this.btnNew_Click); // - // btnCancel - // - this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.btnCancel.Location = new System.Drawing.Point(167, 73); - this.btnCancel.Name = "btnCancel"; - this.btnCancel.Size = new System.Drawing.Size(69, 23); - this.btnCancel.TabIndex = 30; - this.btnCancel.Text = global::mRemoteNG.Language.strButtonCancel; - this.btnCancel.UseVisualStyleBackColor = true; - this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); - // // frmChoosePanel // this.AcceptButton = this.btnOK; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.CancelButton = this.btnCancel; this.ClientSize = new System.Drawing.Size(245, 107); this.Controls.Add(this.lblDescription); this.Controls.Add(this.btnNew); - this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnOK); this.Controls.Add(this.cbPanels); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; @@ -116,6 +105,5 @@ namespace mRemoteNG.UI.Forms internal Controls.Base.NGButton btnOK; internal Controls.Base.NGLabel lblDescription; internal Controls.Base.NGButton btnNew; - internal Controls.Base.NGButton btnCancel; } } diff --git a/mRemoteV1/UI/Forms/frmChoosePanel.cs b/mRemoteV1/UI/Forms/frmChoosePanel.cs index 4b5cd36e8..cb545a8d1 100644 --- a/mRemoteV1/UI/Forms/frmChoosePanel.cs +++ b/mRemoteV1/UI/Forms/frmChoosePanel.cs @@ -16,21 +16,15 @@ namespace mRemoteNG.UI.Forms } public string Panel { - get - { - return cbPanels.SelectedItem.ToString(); - } - set - { - cbPanels.SelectedItem = value; - } - } + get => cbPanels.SelectedItem.ToString(); + set => cbPanels.SelectedItem = value; + } private void frmChoosePanel_Load(object sender, System.EventArgs e) { ApplyLanguage(); - - AddAvailablePanels(); + ApplyTheme(); + AddAvailablePanels(); } private void ApplyLanguage() @@ -38,15 +32,23 @@ namespace mRemoteNG.UI.Forms btnOK.Text = Language.strButtonOK; lblDescription.Text = Language.strLabelSelectPanel; btnNew.Text = Language.strButtonNew; - btnCancel.Text = Language.strButtonCancel; Text = Language.strTitleSelectPanel; } - - private void AddAvailablePanels() + + private void ApplyTheme() + { + if (!Themes.ThemeManager.getInstance().ThemingActive) return; + BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + lblDescription.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + lblDescription.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + } + + private void AddAvailablePanels() { cbPanels.Items.Clear(); - for (int i = 0; i <= Runtime.WindowList.Count - 1; i++) + for (var i = 0; i <= Runtime.WindowList.Count - 1; i++) { cbPanels.Items.Add(Runtime.WindowList[i].Text.Replace("&&", "&")); } @@ -67,24 +69,17 @@ namespace mRemoteNG.UI.Forms private void btnNew_Click(object sender, System.EventArgs e) { var pnlName = Language.strNewPanel; - - if (input.InputBox(Language.strNewPanel, Language.strPanelName + ":", ref pnlName) == DialogResult.OK && !string.IsNullOrEmpty(pnlName)) - { - _panelAdder.AddPanel(pnlName); - AddAvailablePanels(); - cbPanels.SelectedItem = pnlName; - cbPanels.Focus(); - } + + if (input.InputBox(Language.strNewPanel, Language.strPanelName + ":", ref pnlName) != DialogResult.OK || string.IsNullOrEmpty(pnlName)) return; + _panelAdder.AddPanel(pnlName); + AddAvailablePanels(); + cbPanels.SelectedItem = pnlName; + cbPanels.Focus(); } private void btnOK_Click(object sender, System.EventArgs e) { DialogResult = DialogResult.OK; } - - private void btnCancel_Click(object sender, System.EventArgs e) - { - DialogResult = DialogResult.Cancel; - } } } diff --git a/mRemoteV1/UI/Forms/frmMain.Designer.cs b/mRemoteV1/UI/Forms/frmMain.Designer.cs index a8072f647..deba6344b 100644 --- a/mRemoteV1/UI/Forms/frmMain.Designer.cs +++ b/mRemoteV1/UI/Forms/frmMain.Designer.cs @@ -26,224 +26,201 @@ namespace mRemoteNG.UI.Forms [System.Diagnostics.DebuggerStepThrough()] private void InitializeComponent() { - this.components = new System.ComponentModel.Container(); - mRemoteNG.Connection.ConnectionInitiator connectionInitiator1 = new mRemoteNG.Connection.ConnectionInitiator(); - this.pnlDock = new WeifenLuo.WinFormsUI.Docking.DockPanel(); - this.msMain = new System.Windows.Forms.MenuStrip(); - this.mainFileMenu1 = new mRemoteNG.UI.Menu.MainFileMenu(); - this.viewMenu1 = new mRemoteNG.UI.Menu.ViewMenu(); - this.toolsMenu1 = new mRemoteNG.UI.Menu.ToolsMenu(); - this.helpMenu1 = new mRemoteNG.UI.Menu.HelpMenu(); - this.mMenFile = new System.Windows.Forms.ToolStripMenuItem(); - this.mMenView = new System.Windows.Forms.ToolStripMenuItem(); - this.mMenTools = new System.Windows.Forms.ToolStripMenuItem(); - this.mMenInfo = new System.Windows.Forms.ToolStripMenuItem(); - this.mMenSep3 = new System.Windows.Forms.ToolStripSeparator(); - this.tsContainer = new System.Windows.Forms.ToolStripContainer(); - this._externalToolsToolStrip = new mRemoteNG.UI.Controls.ExternalToolsToolStrip(); - this._quickConnectToolStrip = new mRemoteNG.UI.Controls.QuickConnectToolStrip(); - this._multiSshToolStrip = new mRemoteNG.UI.Controls.MultiSshToolStrip(); - this.tmrAutoSave = new System.Windows.Forms.Timer(this.components); - this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components); - this.msMain.SuspendLayout(); - this.tsContainer.ContentPanel.SuspendLayout(); - this.tsContainer.TopToolStripPanel.SuspendLayout(); - this.tsContainer.SuspendLayout(); - this.SuspendLayout(); - // - // pnlDock - // - this.pnlDock.Dock = System.Windows.Forms.DockStyle.Fill; - this.pnlDock.DockBackColor = System.Drawing.SystemColors.Control; - this.pnlDock.DockLeftPortion = 230D; - this.pnlDock.DockRightPortion = 230D; - this.pnlDock.DocumentStyle = WeifenLuo.WinFormsUI.Docking.DocumentStyle.DockingSdi; - this.pnlDock.Location = new System.Drawing.Point(0, 0); - this.pnlDock.Name = "pnlDock"; - this.pnlDock.Size = new System.Drawing.Size(966, 473); - this.pnlDock.TabIndex = 13; - this.pnlDock.ActiveDocumentChanged += new System.EventHandler(this.pnlDock_ActiveDocumentChanged); - // - // msMain - // - this.msMain.Dock = System.Windows.Forms.DockStyle.None; - this.msMain.GripMargin = new System.Windows.Forms.Padding(0); - this.msMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.mainFileMenu1, - this.viewMenu1, - this.toolsMenu1, - this.helpMenu1}); - this.msMain.Location = new System.Drawing.Point(367, 25); - this.msMain.Name = "msMain"; - this.msMain.Padding = new System.Windows.Forms.Padding(2, 2, 0, 2); - this.msMain.Size = new System.Drawing.Size(268, 24); - this.msMain.Stretch = false; - this.msMain.TabIndex = 16; - this.msMain.Text = "Main Toolbar"; - // - // mainFileMenu1 - // - this.mainFileMenu1.ConnectionInitiator = null; - this.mainFileMenu1.Name = "mMenFile"; - this.mainFileMenu1.Size = new System.Drawing.Size(37, 20); - this.mainFileMenu1.Text = "&File"; - this.mainFileMenu1.TreeWindow = null; - this.mainFileMenu1.DropDownOpening += new System.EventHandler(this.mainFileMenu1_DropDownOpening); - // - // viewMenu1 - // - this.viewMenu1.FullscreenHandler = null; - this.viewMenu1.MainForm = null; - this.viewMenu1.Name = "mMenView"; - this.viewMenu1.Size = new System.Drawing.Size(44, 20); - this.viewMenu1.Text = "&View"; - this.viewMenu1.TsExternalTools = null; - this.viewMenu1.TsQuickConnect = null; - this.viewMenu1.DropDownOpening += new System.EventHandler(this.ViewMenu_Opening); - // - // toolsMenu1 - // - this.toolsMenu1.CredentialProviderCatalog = null; - this.toolsMenu1.MainForm = null; - this.toolsMenu1.Name = "mMenTools"; - this.toolsMenu1.Size = new System.Drawing.Size(47, 20); - this.toolsMenu1.Text = "&Tools"; - // - // helpMenu1 - // - this.helpMenu1.Name = "mMenInfo"; - this.helpMenu1.Size = new System.Drawing.Size(44, 20); - this.helpMenu1.Text = "&Help"; - this.helpMenu1.TextDirection = System.Windows.Forms.ToolStripTextDirection.Horizontal; - // - // mMenFile - // - this.mMenFile.Name = "mMenFile"; - this.mMenFile.Size = new System.Drawing.Size(32, 19); - // - // mMenView - // - this.mMenView.Name = "mMenView"; - this.mMenView.Size = new System.Drawing.Size(32, 19); - // - // mMenTools - // - this.mMenTools.Name = "mMenTools"; - this.mMenTools.Size = new System.Drawing.Size(32, 19); - // - // mMenInfo - // - this.mMenInfo.Name = "mMenInfo"; - this.mMenInfo.Size = new System.Drawing.Size(32, 19); - // - // mMenSep3 - // - this.mMenSep3.Name = "mMenSep3"; - this.mMenSep3.Size = new System.Drawing.Size(211, 6); - // - // tsContainer - // - // - // tsContainer.ContentPanel - // - this.tsContainer.ContentPanel.Controls.Add(this.pnlDock); - this.tsContainer.ContentPanel.Size = new System.Drawing.Size(966, 473); - this.tsContainer.Dock = System.Windows.Forms.DockStyle.Fill; - this.tsContainer.Location = new System.Drawing.Point(0, 0); - this.tsContainer.Name = "tsContainer"; - this.tsContainer.Size = new System.Drawing.Size(966, 523); - this.tsContainer.TabIndex = 17; - this.tsContainer.Text = "ToolStripContainer1"; - // - // tsContainer.TopToolStripPanel - // - this.tsContainer.TopToolStripPanel.Controls.Add(this.msMain); - this.tsContainer.TopToolStripPanel.Controls.Add(this._externalToolsToolStrip); - this.tsContainer.TopToolStripPanel.Controls.Add(this._quickConnectToolStrip); - this.tsContainer.TopToolStripPanel.Controls.Add(this._multiSshToolStrip); - // - // _externalToolsToolStrip - // - this._externalToolsToolStrip.BackColor = System.Drawing.SystemColors.Control; - this._externalToolsToolStrip.Dock = System.Windows.Forms.DockStyle.None; - this._externalToolsToolStrip.ForeColor = System.Drawing.SystemColors.ControlText; - this._externalToolsToolStrip.Location = new System.Drawing.Point(39, 0); - this._externalToolsToolStrip.MaximumSize = new System.Drawing.Size(0, 25); - this._externalToolsToolStrip.Name = "_externalToolsToolStrip"; - this._externalToolsToolStrip.Size = new System.Drawing.Size(111, 25); - this._externalToolsToolStrip.TabIndex = 17; - // - // _quickConnectToolStrip - // - this._quickConnectToolStrip.BackColor = System.Drawing.SystemColors.Control; - this._quickConnectToolStrip.ConnectionInitiator = connectionInitiator1; - this._quickConnectToolStrip.Dock = System.Windows.Forms.DockStyle.None; - this._quickConnectToolStrip.ForeColor = System.Drawing.SystemColors.ControlText; - this._quickConnectToolStrip.Location = new System.Drawing.Point(3, 25); - this._quickConnectToolStrip.MaximumSize = new System.Drawing.Size(0, 25); - this._quickConnectToolStrip.Name = "_quickConnectToolStrip"; - this._quickConnectToolStrip.Size = new System.Drawing.Size(364, 25); - this._quickConnectToolStrip.TabIndex = 18; - // - // tsMultiSSH - // - this._multiSshToolStrip.ImageScalingSize = new System.Drawing.Size(20, 20); - this._multiSshToolStrip.Location = new System.Drawing.Point(_quickConnectToolStrip.Location.X + _quickConnectToolStrip.Width + 1, 0); - this._multiSshToolStrip.MinimumSize = new System.Drawing.Size(300, 0); - this._multiSshToolStrip.Name = "_multiSshToolStrip"; - this._multiSshToolStrip.Size = new System.Drawing.Size(430, 25); - this._multiSshToolStrip.TabIndex = 0; - this._multiSshToolStrip.Dock = System.Windows.Forms.DockStyle.Right; - // - // tmrAutoSave - // - this.tmrAutoSave.Interval = 10000; - this.tmrAutoSave.Tick += new System.EventHandler(this.tmrAutoSave_Tick); - // - // vsToolStripExtender - // - this.vsToolStripExtender.DefaultRenderer = null; - // - // FrmMain - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(966, 523); - this.Controls.Add(this.tsContainer); - this.Icon = global::mRemoteNG.Resources.mRemote_Icon; - this.MainMenuStrip = this.msMain; - this.Name = "FrmMain"; - this.Opacity = 0D; - this.Text = "mRemoteNG"; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmMain_FormClosing); - this.Load += new System.EventHandler(this.frmMain_Load); - this.Shown += new System.EventHandler(this.frmMain_Shown); - this.ResizeBegin += new System.EventHandler(this.frmMain_ResizeBegin); - this.ResizeEnd += new System.EventHandler(this.frmMain_ResizeEnd); - this.Resize += new System.EventHandler(this.frmMain_Resize); - this.msMain.ResumeLayout(false); - this.msMain.PerformLayout(); - this.tsContainer.ContentPanel.ResumeLayout(false); - this.tsContainer.TopToolStripPanel.ResumeLayout(false); - this.tsContainer.TopToolStripPanel.PerformLayout(); - this.tsContainer.ResumeLayout(false); - this.tsContainer.PerformLayout(); - this.ResumeLayout(false); + this.components = new System.ComponentModel.Container(); + mRemoteNG.Connection.ConnectionInitiator connectionInitiator1 = new mRemoteNG.Connection.ConnectionInitiator(); + this.pnlDock = new WeifenLuo.WinFormsUI.Docking.DockPanel(); + this.msMain = new System.Windows.Forms.MenuStrip(); + this.fileMenu = new mRemoteNG.UI.Menu.MainFileMenu(); + this.viewMenu = new mRemoteNG.UI.Menu.ViewMenu(); + this.toolsMenu = new mRemoteNG.UI.Menu.ToolsMenu(); + this.helpMenu = new mRemoteNG.UI.Menu.HelpMenu(); + this.mMenSep3 = new System.Windows.Forms.ToolStripSeparator(); + this.tsContainer = new System.Windows.Forms.ToolStripContainer(); + this._quickConnectToolStrip = new mRemoteNG.UI.Controls.QuickConnectToolStrip(); + this._multiSshToolStrip = new mRemoteNG.UI.Controls.MultiSshToolStrip(); + this._externalToolsToolStrip = new mRemoteNG.UI.Controls.ExternalToolsToolStrip(); + this.tmrAutoSave = new System.Windows.Forms.Timer(this.components); + this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components); + this.msMain.SuspendLayout(); + this.tsContainer.ContentPanel.SuspendLayout(); + this.tsContainer.TopToolStripPanel.SuspendLayout(); + this.tsContainer.SuspendLayout(); + this.SuspendLayout(); + // + // pnlDock + // + this.pnlDock.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlDock.DockBackColor = System.Drawing.SystemColors.Control; + this.pnlDock.DockLeftPortion = 230D; + this.pnlDock.DockRightPortion = 230D; + this.pnlDock.DocumentStyle = WeifenLuo.WinFormsUI.Docking.DocumentStyle.DockingSdi; + this.pnlDock.Location = new System.Drawing.Point(0, 0); + this.pnlDock.Name = "pnlDock"; + this.pnlDock.Size = new System.Drawing.Size(1129, 472); + this.pnlDock.TabIndex = 13; + this.pnlDock.ActiveDocumentChanged += new System.EventHandler(this.pnlDock_ActiveDocumentChanged); + // + // msMain + // + this.msMain.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.msMain.Dock = System.Windows.Forms.DockStyle.None; + this.msMain.GripMargin = new System.Windows.Forms.Padding(0); + this.msMain.GripStyle = System.Windows.Forms.ToolStripGripStyle.Visible; + this.msMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileMenu, + this.viewMenu, + this.toolsMenu, + this.helpMenu}); + this.msMain.Location = new System.Drawing.Point(3, 50); + this.msMain.Name = "msMain"; + this.msMain.Padding = new System.Windows.Forms.Padding(2, 2, 0, 2); + this.msMain.Size = new System.Drawing.Size(176, 24); + this.msMain.Stretch = false; + this.msMain.TabIndex = 0; + this.msMain.Text = "Main Toolbar"; + // + // fileMenu + // + this.fileMenu.ConnectionInitiator = null; + this.fileMenu.Name = "mMenFile"; + this.fileMenu.Size = new System.Drawing.Size(37, 20); + this.fileMenu.Text = Language.strMenuFile; + this.fileMenu.TreeWindow = null; + this.fileMenu.DropDownOpening += new System.EventHandler(this.mainFileMenu1_DropDownOpening); + // + // viewMenu + // + this.viewMenu.FullscreenHandler = null; + this.viewMenu.MainForm = null; + this.viewMenu.Name = "mMenView"; + this.viewMenu.Size = new System.Drawing.Size(44, 20); + this.viewMenu.Text = Language.strMenuView; + this.viewMenu.TsExternalTools = null; + this.viewMenu.TsMultiSsh = null; + this.viewMenu.TsQuickConnect = null; + this.viewMenu.DropDownOpening += new System.EventHandler(this.ViewMenu_Opening); + // + // toolsMenu + // + this.toolsMenu.CredentialProviderCatalog = null; + this.toolsMenu.MainForm = null; + this.toolsMenu.Name = "mMenTools"; + this.toolsMenu.Size = new System.Drawing.Size(47, 20); + this.toolsMenu.Text = Language.strMenuTools; + // + // helpMenu + // + this.helpMenu.Name = "mMenInfo"; + this.helpMenu.Size = new System.Drawing.Size(44, 20); + this.helpMenu.Text = Language.strMenuHelp; + this.helpMenu.TextDirection = System.Windows.Forms.ToolStripTextDirection.Horizontal; + // + // mMenSep3 + // + this.mMenSep3.Name = "mMenSep3"; + this.mMenSep3.Size = new System.Drawing.Size(211, 6); + // + // tsContainer + // + // + // tsContainer.ContentPanel + // + this.tsContainer.ContentPanel.Controls.Add(this.pnlDock); + this.tsContainer.ContentPanel.Size = new System.Drawing.Size(1129, 472); + this.tsContainer.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsContainer.Location = new System.Drawing.Point(0, 0); + this.tsContainer.Name = "tsContainer"; + this.tsContainer.Size = new System.Drawing.Size(1129, 571); + this.tsContainer.TabIndex = 17; + this.tsContainer.Text = "ToolStripContainer1"; + // + // tsContainer.TopToolStripPanel + // + this.tsContainer.TopToolStripPanel.Controls.Add(this._quickConnectToolStrip); + this.tsContainer.TopToolStripPanel.Controls.Add(this._multiSshToolStrip); + this.tsContainer.TopToolStripPanel.Controls.Add(this.msMain); + this.tsContainer.TopToolStripPanel.Controls.Add(this._externalToolsToolStrip); + // + // _quickConnectToolStrip + // + this._quickConnectToolStrip.BackColor = System.Drawing.SystemColors.Control; + this._quickConnectToolStrip.ConnectionInitiator = connectionInitiator1; + this._quickConnectToolStrip.Dock = System.Windows.Forms.DockStyle.None; + this._quickConnectToolStrip.ForeColor = System.Drawing.SystemColors.ControlText; + this._quickConnectToolStrip.Location = new System.Drawing.Point(3, 0); + this._quickConnectToolStrip.MaximumSize = new System.Drawing.Size(0, 25); + this._quickConnectToolStrip.Name = "_quickConnectToolStrip"; + this._quickConnectToolStrip.Size = new System.Drawing.Size(364, 25); + this._quickConnectToolStrip.TabIndex = 18; + // + // _multiSshToolStrip + // + this._multiSshToolStrip.Dock = System.Windows.Forms.DockStyle.None; + this._multiSshToolStrip.ImageScalingSize = new System.Drawing.Size(20, 20); + this._multiSshToolStrip.Location = new System.Drawing.Point(3, 25); + this._multiSshToolStrip.MinimumSize = new System.Drawing.Size(300, 0); + this._multiSshToolStrip.Name = "_multiSshToolStrip"; + this._multiSshToolStrip.Size = new System.Drawing.Size(376, 25); + this._multiSshToolStrip.TabIndex = 1; + // + // _externalToolsToolStrip + // + this._externalToolsToolStrip.BackColor = System.Drawing.SystemColors.Control; + this._externalToolsToolStrip.Dock = System.Windows.Forms.DockStyle.None; + this._externalToolsToolStrip.ForeColor = System.Drawing.SystemColors.ControlText; + this._externalToolsToolStrip.Location = new System.Drawing.Point(39, 74); + this._externalToolsToolStrip.MaximumSize = new System.Drawing.Size(0, 25); + this._externalToolsToolStrip.Name = "_externalToolsToolStrip"; + this._externalToolsToolStrip.Size = new System.Drawing.Size(111, 25); + this._externalToolsToolStrip.TabIndex = 17; + // + // tmrAutoSave + // + this.tmrAutoSave.Interval = 10000; + this.tmrAutoSave.Tick += new System.EventHandler(this.tmrAutoSave_Tick); + // + // vsToolStripExtender + // + this.vsToolStripExtender.DefaultRenderer = null; + // + // FrmMain + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1129, 571); + this.Controls.Add(this.tsContainer); + this.Icon = global::mRemoteNG.Resources.mRemote_Icon; + this.MainMenuStrip = this.msMain; + this.MinimumSize = new System.Drawing.Size(400, 400); + this.Name = "FrmMain"; + this.Opacity = 0D; + this.Text = "mRemoteNG"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmMain_FormClosing); + this.Load += new System.EventHandler(this.frmMain_Load); + this.Shown += new System.EventHandler(this.frmMain_Shown); + this.ResizeBegin += new System.EventHandler(this.frmMain_ResizeBegin); + this.ResizeEnd += new System.EventHandler(this.frmMain_ResizeEnd); + this.Resize += new System.EventHandler(this.frmMain_Resize); + this.msMain.ResumeLayout(false); + this.msMain.PerformLayout(); + this.tsContainer.ContentPanel.ResumeLayout(false); + this.tsContainer.TopToolStripPanel.ResumeLayout(false); + this.tsContainer.TopToolStripPanel.PerformLayout(); + this.tsContainer.ResumeLayout(false); + this.tsContainer.PerformLayout(); + this.ResumeLayout(false); + } internal WeifenLuo.WinFormsUI.Docking.DockPanel pnlDock; internal System.Windows.Forms.MenuStrip msMain; - internal System.Windows.Forms.ToolStripMenuItem mMenFile; - internal System.Windows.Forms.ToolStripMenuItem mMenView; - internal System.Windows.Forms.ToolStripMenuItem mMenTools; - internal System.Windows.Forms.ToolStripMenuItem mMenInfo; internal System.Windows.Forms.ToolStripContainer tsContainer; internal System.Windows.Forms.Timer tmrAutoSave; internal System.Windows.Forms.ToolStripSeparator mMenSep3; private System.ComponentModel.IContainer components; - private Menu.MainFileMenu mainFileMenu1; - private Menu.ViewMenu viewMenu1; - private Menu.ToolsMenu toolsMenu1; - private Menu.HelpMenu helpMenu1; + private Menu.MainFileMenu fileMenu; + private Menu.ViewMenu viewMenu; + private Menu.ToolsMenu toolsMenu; + private Menu.HelpMenu helpMenu; internal mRemoteNG.UI.Controls.QuickConnectToolStrip _quickConnectToolStrip; internal mRemoteNG.UI.Controls.ExternalToolsToolStrip _externalToolsToolStrip; internal mRemoteNG.UI.Controls.MultiSshToolStrip _multiSshToolStrip; diff --git a/mRemoteV1/UI/Forms/frmMain.cs b/mRemoteV1/UI/Forms/frmMain.cs index 00b192b69..4be80b354 100644 --- a/mRemoteV1/UI/Forms/frmMain.cs +++ b/mRemoteV1/UI/Forms/frmMain.cs @@ -14,6 +14,7 @@ using mRemoteNG.App.Info; using mRemoteNG.App.Initialization; using mRemoteNG.Config; using mRemoteNG.Config.Connections; +using mRemoteNG.Config.DataProviders; using mRemoteNG.Config.Putty; using mRemoteNG.Config.Settings; using mRemoteNG.Connection; @@ -22,6 +23,7 @@ using mRemoteNG.Messages.MessageWriters; using mRemoteNG.Themes; using mRemoteNG.Tools; using mRemoteNG.UI.Menu; +using mRemoteNG.UI.Panels; using mRemoteNG.UI.TaskDialog; using mRemoteNG.UI.Window; using WeifenLuo.WinFormsUI.Docking; @@ -30,7 +32,7 @@ using WeifenLuo.WinFormsUI.Docking; namespace mRemoteNG.UI.Forms { - public partial class FrmMain + public partial class FrmMain { public static FrmMain Default { get; } = new FrmMain(); @@ -45,6 +47,7 @@ namespace mRemoteNG.UI.Forms private ConnectionInfo _selectedConnection; private readonly IList _messageWriters = new List(); private readonly ThemeManager _themeManager; + private readonly FileBackupPruner _backupPruner = new FileBackupPruner(); internal FullscreenHandler Fullscreen { get; set; } @@ -60,15 +63,11 @@ namespace mRemoteNG.UI.Forms //Theming support _themeManager = ThemeManager.getInstance(); vsToolStripExtender.DefaultRenderer = _toolStripProfessionalRenderer; - SetSchema(); + ApplyTheme(); _screenSystemMenu = new ScreenSelectionSystemMenu(this); } - static FrmMain() - { - } - #region Properties public FormWindowState PreviousWindowState { get; set; } @@ -76,8 +75,8 @@ namespace mRemoteNG.UI.Forms public bool AreWeUsingSqlServerForSavingConnections { - get { return _usingSqlServer; } - set + get => _usingSqlServer; + set { if (_usingSqlServer == value) { @@ -90,8 +89,8 @@ namespace mRemoteNG.UI.Forms public string ConnectionsFileName { - get { return _connectionsFileName; } - set + get => _connectionsFileName; + set { if (_connectionsFileName == value) { @@ -104,8 +103,8 @@ namespace mRemoteNG.UI.Forms public bool ShowFullPathInTitle { - get { return _showFullPathInTitle; } - set + get => _showFullPathInTitle; + set { if (_showFullPathInTitle == value) { @@ -118,8 +117,8 @@ namespace mRemoteNG.UI.Forms public ConnectionInfo SelectedConnection { - get { return _selectedConnection; } - set + get => _selectedConnection; + set { if (_selectedConnection == value) { @@ -140,11 +139,12 @@ namespace mRemoteNG.UI.Forms Startup.Instance.InitializeProgram(messageCollector); - SetMenuDependencies(); - - var settingsLoader = new SettingsLoader(this, messageCollector, _quickConnectToolStrip, _externalToolsToolStrip); + msMain.Location = Point.Empty; + var settingsLoader = new SettingsLoader(this, messageCollector, _quickConnectToolStrip, _externalToolsToolStrip, _multiSshToolStrip, msMain); settingsLoader.LoadSettings(); + SetMenuDependencies(); + var uiLoader = new DockPanelLayoutLoader(this, messageCollector); uiLoader.LoadPanelsFromXml(); @@ -161,6 +161,7 @@ namespace mRemoteNG.UI.Forms SetDefaultLayout(); Runtime.ConnectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded; + Runtime.ConnectionsService.ConnectionsSaved += ConnectionsServiceOnConnectionsSaved; var credsAndConsSetup = new CredsAndConsSetup(); credsAndConsSetup.LoadCredsAndCons(); @@ -174,11 +175,31 @@ namespace mRemoteNG.UI.Forms _screenSystemMenu.BuildScreenList(); SystemEvents.DisplaySettingsChanged += _screenSystemMenu.OnDisplayChanged; + ApplyLanguage(); Opacity = 1; + //Fix missing general panel at the first run + if (Settings.Default.CreateEmptyPanelOnStartUp) + { + var panelName = !string.IsNullOrEmpty(Settings.Default.StartUpPanelName) + ? Settings.Default.StartUpPanelName + : Language.strNewPanel; + + var panelAdder = new PanelAdder(); + if (!panelAdder.DoesPanelExist(panelName)) + panelAdder.AddPanel(panelName); + } } - private void OnApplicationSettingChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) + private void ApplyLanguage() + { + fileMenu.ApplyLanguage(); + viewMenu.ApplyLanguage(); + toolsMenu.ApplyLanguage(); + helpMenu.ApplyLanguage(); + } + + private void OnApplicationSettingChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) { if (propertyChangedEventArgs.PropertyName != nameof(Settings.LockToolbars)) return; @@ -188,7 +209,7 @@ namespace mRemoteNG.UI.Forms private void LockToolbarPositions(bool shouldBeLocked) { - var toolbars = new ToolStrip[] { _quickConnectToolStrip, _multiSshToolStrip, _externalToolsToolStrip }; + var toolbars = new ToolStrip[] { _quickConnectToolStrip, _multiSshToolStrip, _externalToolsToolStrip, msMain }; foreach (var toolbar in toolbars) { toolbar.GripStyle = shouldBeLocked @@ -197,49 +218,68 @@ namespace mRemoteNG.UI.Forms } } - private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs) + private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs) { UpdateWindowTitle(); } + private void ConnectionsServiceOnConnectionsSaved(object sender, ConnectionsSavedEventArgs connectionsSavedEventArgs) + { + if (connectionsSavedEventArgs.UsingDatabase) + return; + + _backupPruner.PruneBackupFiles(connectionsSavedEventArgs.ConnectionFileName, Settings.Default.BackupFileKeepCount); + } + private void SetMenuDependencies() { var connectionInitiator = new ConnectionInitiator(); - mainFileMenu1.TreeWindow = Windows.TreeForm; - mainFileMenu1.ConnectionInitiator = connectionInitiator; + fileMenu.TreeWindow = Windows.TreeForm; + fileMenu.ConnectionInitiator = connectionInitiator; - viewMenu1.TsExternalTools = _externalToolsToolStrip; - viewMenu1.TsQuickConnect = _quickConnectToolStrip; - viewMenu1.TsMultiSsh = _multiSshToolStrip; - viewMenu1.FullscreenHandler = Fullscreen; - viewMenu1.MainForm = this; + viewMenu.TsExternalTools = _externalToolsToolStrip; + viewMenu.TsQuickConnect = _quickConnectToolStrip; + viewMenu.TsMultiSsh = _multiSshToolStrip; + viewMenu.FullscreenHandler = Fullscreen; + viewMenu.MainForm = this; - toolsMenu1.MainForm = this; - toolsMenu1.CredentialProviderCatalog = Runtime.CredentialProviderCatalog; + toolsMenu.MainForm = this; + toolsMenu.CredentialProviderCatalog = Runtime.CredentialProviderCatalog; _quickConnectToolStrip.ConnectionInitiator = connectionInitiator; } //Theming support - private void SetSchema() - { - if (_themeManager.ThemingActive) - { - // Persist settings when rebuilding UI - this.pnlDock.Theme = _themeManager.ActiveTheme.Theme; - ApplyTheme(); - } - } private void ApplyTheme() { - if(_themeManager.ThemingActive) - { + if (!_themeManager.ThemingActive) return; + + try + { + // this will always throw when turning themes on from + // the options menu. + pnlDock.Theme = _themeManager.ActiveTheme.Theme; + } + catch (Exception) + { + // intentionally ignore exception + } + + // Persist settings when rebuilding UI + try + { vsToolStripExtender.SetStyle(msMain, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - vsToolStripExtender.SetStyle(_quickConnectToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - vsToolStripExtender.SetStyle(_externalToolsToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - vsToolStripExtender.SetStyle(_multiSshToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - tsContainer.TopToolStripPanel.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("CommandBarMenuDefault_Background"); - } + vsToolStripExtender.SetStyle(_quickConnectToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); + vsToolStripExtender.SetStyle(_externalToolsToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); + vsToolStripExtender.SetStyle(_multiSshToolStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); + tsContainer.TopToolStripPanel.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("CommandBarMenuDefault_Background"); + BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("Error applying theme", ex, MessageClass.WarningMsg); + } } private void frmMain_Shown(object sender, EventArgs e) @@ -315,7 +355,7 @@ namespace mRemoteNG.UI.Forms } } - Shutdown.Cleanup(_quickConnectToolStrip, _externalToolsToolStrip, this); + Shutdown.Cleanup(_quickConnectToolStrip, _externalToolsToolStrip, _multiSshToolStrip, this); IsClosing = true; @@ -392,17 +432,28 @@ namespace mRemoteNG.UI.Forms var controlThatWasClicked = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition)); if (controlThatWasClicked != null) { - if (controlThatWasClicked.CanSelect || controlThatWasClicked is MenuStrip || - controlThatWasClicked is ToolStrip || controlThatWasClicked is Crownwood.Magic.Controls.TabControl || - controlThatWasClicked is Crownwood.Magic.Controls.InertButton) + if (controlThatWasClicked is TreeView || + controlThatWasClicked is ComboBox || + controlThatWasClicked is TextBox) + { + controlThatWasClicked.Focus(); + } + else if (controlThatWasClicked.CanSelect || + controlThatWasClicked is MenuStrip || + controlThatWasClicked is ToolStrip || + controlThatWasClicked is Crownwood.Magic.Controls.TabControl || + controlThatWasClicked is Crownwood.Magic.Controls.InertButton) { // Simulate a mouse event since one wasn't generated by Windows - MouseClickSimulator.Click(controlThatWasClicked, MousePosition); + SimulateClick(controlThatWasClicked); + controlThatWasClicked.Focus(); + } + else + { + // This handles activations from clicks that did not start a size/move operation + ActivateConnection(); } } - - // This handles activations from clicks that did not start a size/move operation - ActivateConnection(); } break; case NativeMethods.WM_WINDOWPOSCHANGED: @@ -437,7 +488,17 @@ namespace mRemoteNG.UI.Forms base.WndProc(ref m); } - + + private void SimulateClick(Control control) + { + var clientMousePosition = control.PointToClient(MousePosition); + var temp_wLow = clientMousePosition.X; + var temp_wHigh = clientMousePosition.Y; + NativeMethods.SendMessage(control.Handle, NativeMethods.WM_LBUTTONDOWN, (IntPtr)NativeMethods.MK_LBUTTON, (IntPtr)NativeMethods.MAKELPARAM(ref temp_wLow, ref temp_wHigh)); + clientMousePosition.X = temp_wLow; + clientMousePosition.Y = temp_wHigh; + } + private void ActivateConnection() { var w = pnlDock.ActiveDocument as ConnectionWindow; @@ -567,10 +628,8 @@ namespace mRemoteNG.UI.Forms Windows.TreeForm.Show(pnlDock, DockState.DockLeft); Windows.ConfigForm.Show(pnlDock); Windows.ConfigForm.DockTo(Windows.TreeForm.Pane, DockStyle.Bottom, -1); - Windows.ErrorsForm.Show(pnlDock, DockState.Document); - - Windows.ErrorsForm.Hide(); - Windows.ScreenshotForm.Hide(); + Windows.ErrorsForm.Show( pnlDock, DockState.DockBottomAutoHide ); + Windows.ScreenshotForm.Hide(); pnlDock.Visible = true; } @@ -580,25 +639,19 @@ namespace mRemoteNG.UI.Forms public delegate void ClipboardchangeEventHandler(); public static event ClipboardchangeEventHandler ClipboardChanged { - add - { - _clipboardChangedEvent = (ClipboardchangeEventHandler)Delegate.Combine(_clipboardChangedEvent, value); - } - remove - { - _clipboardChangedEvent = (ClipboardchangeEventHandler)Delegate.Remove(_clipboardChangedEvent, value); - } + add => _clipboardChangedEvent = (ClipboardchangeEventHandler)Delegate.Combine(_clipboardChangedEvent, value); + remove => _clipboardChangedEvent = (ClipboardchangeEventHandler)Delegate.Remove(_clipboardChangedEvent, value); } #endregion private void ViewMenu_Opening(object sender, EventArgs e) { - viewMenu1.mMenView_DropDownOpening(sender, e); + viewMenu.mMenView_DropDownOpening(sender, e); } private void mainFileMenu1_DropDownOpening(object sender, EventArgs e) { - mainFileMenu1.mMenFile_DropDownOpening(sender, e); + fileMenu.mMenFile_DropDownOpening(sender, e); } } } \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/frmMain.resx b/mRemoteV1/UI/Forms/frmMain.resx index 023400c50..f7a980287 100644 --- a/mRemoteV1/UI/Forms/frmMain.resx +++ b/mRemoteV1/UI/Forms/frmMain.resx @@ -118,21 +118,21 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 535, 17 - - - 357, 17 + 688, 17 - 177, 17 + 17, 17 - 17, 17 + 197, 17 + + + 510, 17 - 630, 17 + 783, 17 - 17, 17 + 350, 17 \ No newline at end of file diff --git a/mRemoteV1/UI/Forms/frmOptions.cs b/mRemoteV1/UI/Forms/frmOptions.cs index cb46aeb64..a613469f7 100644 --- a/mRemoteV1/UI/Forms/frmOptions.cs +++ b/mRemoteV1/UI/Forms/frmOptions.cs @@ -40,15 +40,14 @@ namespace mRemoteNG.UI.Forms } private void ApplyTheme() { - if(Themes.ThemeManager.getInstance().ThemingActive) - { - BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - } + if (!Themes.ThemeManager.getInstance().ThemingActive) return; + BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } private void ApplyLanguage() { + Text = Language.strOptionsPageTitle; foreach (var optionPage in _pages.Values) { optionPage.ApplyLanguage(); @@ -92,8 +91,8 @@ namespace mRemoteNG.UI.Forms private void SetInitiallyActivatedPage() { - bool isSet = false; - for (int i = 0; i < lstOptionPages.Items.Count; i++) + var isSet = false; + for (var i = 0; i < lstOptionPages.Items.Count; i++) { if (!lstOptionPages.Items[i].Text.Equals(_pageName)) continue; lstOptionPages.Items[i].Selected = true; @@ -117,7 +116,7 @@ namespace mRemoteNG.UI.Forms } - private void LstOptionPages_SelectedIndexChanged(object sender, System.EventArgs e) + private void LstOptionPages_SelectedIndexChanged(object sender, EventArgs e) { pnlMain.Controls.Clear(); diff --git a/mRemoteV1/UI/Menu/HelpMenu.cs b/mRemoteV1/UI/Menu/HelpMenu.cs index 64bd1df78..c343c08c7 100644 --- a/mRemoteV1/UI/Menu/HelpMenu.cs +++ b/mRemoteV1/UI/Menu/HelpMenu.cs @@ -129,6 +129,18 @@ namespace mRemoteNG.UI.Menu _mMenInfoAbout.Click += mMenInfoAbout_Click; } + public void ApplyLanguage() + { + Text = Language.strMenuHelp; + _mMenInfoHelp.Text = Language.strMenuHelpContents; + _mMenInfoWebsite.Text = Language.strMenuWebsite; + _mMenInfoDonate.Text = Language.strMenuDonate; + _mMenInfoForum.Text = Language.strMenuSupportForum; + _mMenInfoBugReport.Text = Language.strMenuReportBug; + _mMenToolsUpdate.Text = Language.strMenuCheckForUpdates; + _mMenInfoAbout.Text = Language.strMenuAbout; + } + #region Info private void mMenToolsUpdate_Click(object sender, EventArgs e) { diff --git a/mRemoteV1/UI/Menu/MainFileMenu.cs b/mRemoteV1/UI/Menu/MainFileMenu.cs index 9a95be158..85e08c88c 100644 --- a/mRemoteV1/UI/Menu/MainFileMenu.cs +++ b/mRemoteV1/UI/Menu/MainFileMenu.cs @@ -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; @@ -96,6 +95,7 @@ namespace mRemoteNG.UI.Menu Size = new System.Drawing.Size(37, 20); Text = Language.strMenuFile; //DropDownOpening += mMenFile_DropDownOpening; + DropDownClosed += OnDropDownClosed; // // mMenFileNewConnection // @@ -167,7 +167,7 @@ namespace mRemoteNG.UI.Menu _mMenFileDelete.Image = Resources.Delete; _mMenFileDelete.Name = "mMenFileDelete"; _mMenFileDelete.Size = new System.Drawing.Size(281, 22); - _mMenFileDelete.Text = "Delete..."; + _mMenFileDelete.Text = Language.strDelete; _mMenFileDelete.Click += mMenFileDelete_Click; // // mMenFileRename @@ -175,7 +175,7 @@ namespace mRemoteNG.UI.Menu _mMenFileRename.Image = Resources.Rename; _mMenFileRename.Name = "mMenFileRename"; _mMenFileRename.Size = new System.Drawing.Size(281, 22); - _mMenFileRename.Text = "Rename"; + _mMenFileRename.Text = Language.strRename; _mMenFileRename.Click += mMenFileRename_Click; // // mMenFileDuplicate @@ -183,7 +183,7 @@ namespace mRemoteNG.UI.Menu _mMenFileDuplicate.Image = Resources.page_copy; _mMenFileDuplicate.Name = "mMenFileDuplicate"; _mMenFileDuplicate.Size = new System.Drawing.Size(281, 22); - _mMenFileDuplicate.Text = "Duplicate"; + _mMenFileDuplicate.Text = Language.strDuplicate; _mMenFileDuplicate.Click += mMenFileDuplicate_Click; // // mMenFileSep4 @@ -196,7 +196,7 @@ namespace mRemoteNG.UI.Menu _mMenReconnectAll.Image = Resources.Refresh; _mMenReconnectAll.Name = "mMenReconnectAll"; _mMenReconnectAll.Size = new System.Drawing.Size(281, 22); - _mMenReconnectAll.Text = "Reconnect All Connections"; + _mMenReconnectAll.Text = Language.strReconnectAllConnections; _mMenReconnectAll.Click += mMenReconnectAll_Click; // // mMenFileSep3 @@ -257,6 +257,23 @@ namespace mRemoteNG.UI.Menu _mMenFileExit.Click += mMenFileExit_Click; } + public void ApplyLanguage() + { + Text = Language.strMenuFile; + _mMenFileNewConnection.Text = Language.strNewConnection; + _mMenFileNewFolder.Text = Language.strNewFolder; + _mMenFileNew.Text = Language.strMenuNewConnectionFile; + _mMenFileLoad.Text = Language.strMenuOpenConnectionFile; + _mMenFileSave.Text = Language.strMenuSaveConnectionFile; + _mMenFileSaveAs.Text = Language.strMenuSaveConnectionFileAs; + _mMenFileImport.Text = Language.strImportMenuItem; + _mMenFileImportFromFile.Text = Language.strImportFromFileMenuItem; + _mMenFileImportFromActiveDirectory.Text = Language.strImportAD; + _mMenFileImportFromPortScan.Text = Language.strImportPortScan; + _mMenFileExport.Text = Language.strExportToFileMenuItem; + _mMenFileExit.Text = Language.strMenuExit; + } + #region File internal void mMenFile_DropDownOpening(object sender, EventArgs e) { @@ -328,6 +345,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(); @@ -340,13 +367,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; + } - Runtime.ConnectionsService.NewConnectionsFile(saveFileDialog.FileName); + Runtime.ConnectionsService.NewConnectionsFile(saveFileDialog.FileName); + } } private void mMenFileLoad_Click(object sender, EventArgs e) @@ -375,15 +404,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(FrmMain.Default) != DialogResult.OK) return; var newFileName = saveFileDialog.FileName; Runtime.ConnectionsService.SaveConnections(Runtime.ConnectionsService.ConnectionTreeModel, false, new SaveFilter(), newFileName); @@ -476,18 +501,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 } } \ No newline at end of file diff --git a/mRemoteV1/UI/Menu/ToolsMenu.cs b/mRemoteV1/UI/Menu/ToolsMenu.cs index 174fed0af..69627dddf 100644 --- a/mRemoteV1/UI/Menu/ToolsMenu.cs +++ b/mRemoteV1/UI/Menu/ToolsMenu.cs @@ -61,7 +61,7 @@ namespace mRemoteNG.UI.Menu _mMenToolsUvncsc.Image = Resources.UVNC_SC; _mMenToolsUvncsc.Name = "mMenToolsUVNCSC"; _mMenToolsUvncsc.Size = new System.Drawing.Size(184, 22); - _mMenToolsUvncsc.Text = "UltraVNC SingleClick"; + _mMenToolsUvncsc.Text = Language.strUltraVNCSingleClick; _mMenToolsUvncsc.Visible = false; _mMenToolsUvncsc.Click += mMenToolsUVNCSC_Click; // @@ -103,6 +103,16 @@ namespace mRemoteNG.UI.Menu _mMenToolsOptions.Click += mMenToolsOptions_Click; } + public void ApplyLanguage() + { + Text = Language.strMenuTools; + _mMenToolsSshTransfer.Text = Language.strMenuSSHFileTransfer; + _mMenToolsExternalApps.Text = Language.strMenuExternalTools; + _mMenToolsPortScan.Text = Language.strMenuPortScan; + _mMenToolsComponentsCheck.Text = Language.strComponentsCheck; + _mMenToolsOptions.Text = Language.strMenuOptions; + } + #region Tools private void mMenToolsSSHTransfer_Click(object sender, EventArgs e) { diff --git a/mRemoteV1/UI/Menu/ViewMenu.cs b/mRemoteV1/UI/Menu/ViewMenu.cs index 26325f056..43945783f 100644 --- a/mRemoteV1/UI/Menu/ViewMenu.cs +++ b/mRemoteV1/UI/Menu/ViewMenu.cs @@ -41,7 +41,6 @@ namespace mRemoteNG.UI.Menu public ViewMenu() { Initialize(); - ApplyLanguage(); _panelAdder = new PanelAdder(); } @@ -98,7 +97,7 @@ namespace mRemoteNG.UI.Menu _mMenViewAddConnectionPanel.Image = Resources.Panel_Add; _mMenViewAddConnectionPanel.Name = "mMenViewAddConnectionPanel"; _mMenViewAddConnectionPanel.Size = new System.Drawing.Size(228, 22); - _mMenViewAddConnectionPanel.Text = "Add Connection Panel"; + _mMenViewAddConnectionPanel.Text = Language.strMenuAddConnectionPanel; _mMenViewAddConnectionPanel.Click += mMenViewAddConnectionPanel_Click; // // mMenViewConnectionPanels @@ -106,7 +105,7 @@ namespace mRemoteNG.UI.Menu _mMenViewConnectionPanels.Image = Resources.Panels; _mMenViewConnectionPanels.Name = "mMenViewConnectionPanels"; _mMenViewConnectionPanels.Size = new System.Drawing.Size(228, 22); - _mMenViewConnectionPanels.Text = "Connection Panels"; + _mMenViewConnectionPanels.Text = Language.strMenuConnectionPanels; // // mMenViewSep1 // @@ -120,7 +119,7 @@ namespace mRemoteNG.UI.Menu _mMenViewConnections.Image = Resources.Root; _mMenViewConnections.Name = "mMenViewConnections"; _mMenViewConnections.Size = new System.Drawing.Size(228, 22); - _mMenViewConnections.Text = "Connections"; + _mMenViewConnections.Text = Language.strMenuConnections; _mMenViewConnections.Click += mMenViewConnections_Click; // // mMenViewConfig @@ -130,7 +129,7 @@ namespace mRemoteNG.UI.Menu _mMenViewConfig.Image = Resources.cog; _mMenViewConfig.Name = "mMenViewConfig"; _mMenViewConfig.Size = new System.Drawing.Size(228, 22); - _mMenViewConfig.Text = "Config"; + _mMenViewConfig.Text = Language.strMenuConfig; _mMenViewConfig.Click += mMenViewConfig_Click; // // mMenViewErrorsAndInfos @@ -140,7 +139,7 @@ namespace mRemoteNG.UI.Menu _mMenViewErrorsAndInfos.Image = Resources.ErrorsAndInfos; _mMenViewErrorsAndInfos.Name = "mMenViewErrorsAndInfos"; _mMenViewErrorsAndInfos.Size = new System.Drawing.Size(228, 22); - _mMenViewErrorsAndInfos.Text = "Errors and Infos"; + _mMenViewErrorsAndInfos.Text = Language.strMenuNotifications; _mMenViewErrorsAndInfos.Click += mMenViewErrorsAndInfos_Click; // // mMenViewScreenshotManager @@ -148,7 +147,7 @@ namespace mRemoteNG.UI.Menu _mMenViewScreenshotManager.Image = Resources.Screenshot; _mMenViewScreenshotManager.Name = "mMenViewScreenshotManager"; _mMenViewScreenshotManager.Size = new System.Drawing.Size(228, 22); - _mMenViewScreenshotManager.Text = "Screenshot Manager"; + _mMenViewScreenshotManager.Text = Language.strScreenshots; _mMenViewScreenshotManager.Click += mMenViewScreenshotManager_Click; // // ToolStripSeparator1 @@ -164,7 +163,7 @@ namespace mRemoteNG.UI.Menu _mMenViewJumpTo.Image = Resources.JumpTo; _mMenViewJumpTo.Name = "mMenViewJumpTo"; _mMenViewJumpTo.Size = new System.Drawing.Size(228, 22); - _mMenViewJumpTo.Text = "Jump To"; + _mMenViewJumpTo.Text = Language.strMenuJumpTo; // // mMenViewJumpToConnectionsConfig // @@ -173,7 +172,7 @@ namespace mRemoteNG.UI.Menu _mMenViewJumpToConnectionsConfig.ShortcutKeys = ((Keys)(((Keys.Control | Keys.Alt) | Keys.C))); _mMenViewJumpToConnectionsConfig.Size = new System.Drawing.Size(258, 22); - _mMenViewJumpToConnectionsConfig.Text = "Connections && Config"; + _mMenViewJumpToConnectionsConfig.Text = Language.strMenuConnectionsAndConfig; _mMenViewJumpToConnectionsConfig.Click += mMenViewJumpToConnectionsConfig_Click; // // mMenViewJumpToErrorsInfos @@ -183,7 +182,7 @@ namespace mRemoteNG.UI.Menu _mMenViewJumpToErrorsInfos.ShortcutKeys = ((Keys)(((Keys.Control | Keys.Alt) | Keys.E))); _mMenViewJumpToErrorsInfos.Size = new System.Drawing.Size(258, 22); - _mMenViewJumpToErrorsInfos.Text = "Errors && Infos"; + _mMenViewJumpToErrorsInfos.Text = Language.strMenuNotifications; _mMenViewJumpToErrorsInfos.Click += mMenViewJumpToErrorsInfos_Click; // // mMenViewResetLayout @@ -191,7 +190,7 @@ namespace mRemoteNG.UI.Menu _mMenViewResetLayout.Image = Resources.application_side_tree; _mMenViewResetLayout.Name = "mMenViewResetLayout"; _mMenViewResetLayout.Size = new System.Drawing.Size(228, 22); - _mMenViewResetLayout.Text = "Reset Layout"; + _mMenViewResetLayout.Text = Language.strMenuResetLayout; _mMenViewResetLayout.Click += mMenViewResetLayout_Click; // // mMenViewLockToolbars @@ -199,8 +198,8 @@ namespace mRemoteNG.UI.Menu _mMenViewLockToolbars.Image = Resources.application_side_tree; _mMenViewLockToolbars.Name = "mMenViewLockToolbars"; _mMenViewLockToolbars.Size = new System.Drawing.Size(228, 22); - _mMenViewLockToolbars.Text = "Lock Toolbar Positions"; - _mMenViewLockToolbars.Click += mMenViewLockToolbars_Click; + _mMenViewLockToolbars.Text = Language.strMenuLockToolbars; + _mMenViewLockToolbars.Click += mMenViewLockToolbars_Click; // // mMenViewSep2 // @@ -212,7 +211,7 @@ namespace mRemoteNG.UI.Menu _mMenViewQuickConnectToolbar.Image = Resources.Play_Quick; _mMenViewQuickConnectToolbar.Name = "mMenViewQuickConnectToolbar"; _mMenViewQuickConnectToolbar.Size = new System.Drawing.Size(228, 22); - _mMenViewQuickConnectToolbar.Text = "Quick Connect Toolbar"; + _mMenViewQuickConnectToolbar.Text = Language.strMenuQuickConnectToolbar; _mMenViewQuickConnectToolbar.Click += mMenViewQuickConnectToolbar_Click; // // mMenViewExtAppsToolbar @@ -220,7 +219,7 @@ namespace mRemoteNG.UI.Menu _mMenViewExtAppsToolbar.Image = Resources.ExtApp; _mMenViewExtAppsToolbar.Name = "mMenViewExtAppsToolbar"; _mMenViewExtAppsToolbar.Size = new System.Drawing.Size(228, 22); - _mMenViewExtAppsToolbar.Text = "External Applications Toolbar"; + _mMenViewExtAppsToolbar.Text = Language.strMenuExternalToolsToolbar; _mMenViewExtAppsToolbar.Click += mMenViewExtAppsToolbar_Click; // // mMenViewMultiSSHToolbar @@ -228,8 +227,8 @@ namespace mRemoteNG.UI.Menu _mMenViewMultiSshToolbar.Image = Resources.Panels; _mMenViewMultiSshToolbar.Name = "mMenViewMultiSSHToolbar"; _mMenViewMultiSshToolbar.Size = new System.Drawing.Size(279, 26); - _mMenViewMultiSshToolbar.Text = "Multi SSH Toolbar"; - _mMenViewMultiSshToolbar.Click += mMenViewMultiSSHToolbar_Click; + _mMenViewMultiSshToolbar.Text = Language.strMenuMultiSshToolbar; + _mMenViewMultiSshToolbar.Click += mMenViewMultiSSHToolbar_Click; // // mMenViewSep3 // @@ -242,15 +241,16 @@ namespace mRemoteNG.UI.Menu _mMenViewFullscreen.Name = "mMenViewFullscreen"; _mMenViewFullscreen.ShortcutKeys = Keys.F11; _mMenViewFullscreen.Size = new System.Drawing.Size(228, 22); - _mMenViewFullscreen.Text = "Full Screen"; + _mMenViewFullscreen.Text = Language.strMenuFullScreen; _mMenViewFullscreen.Checked = Settings.Default.MainFormKiosk; _mMenViewFullscreen.Click += mMenViewFullscreen_Click; } - private void ApplyLanguage() + public void ApplyLanguage() { + Text = Language.strMenuView; _mMenViewAddConnectionPanel.Text = Language.strMenuAddConnectionPanel; _mMenViewConnectionPanels.Text = Language.strMenuConnectionPanels; _mMenViewConnections.Text = Language.strMenuConnections; @@ -261,8 +261,10 @@ namespace mRemoteNG.UI.Menu _mMenViewJumpToConnectionsConfig.Text = Language.strMenuConnectionsAndConfig; _mMenViewJumpToErrorsInfos.Text = Language.strMenuNotifications; _mMenViewResetLayout.Text = Language.strMenuResetLayout; + _mMenViewLockToolbars.Text = Language.strLockToolbars; _mMenViewQuickConnectToolbar.Text = Language.strMenuQuickConnectToolbar; _mMenViewExtAppsToolbar.Text = Language.strMenuExternalToolsToolbar; + _mMenViewMultiSshToolbar.Text = Language.strMultiSshToolbar; _mMenViewFullscreen.Text = Language.strMenuFullScreen; } @@ -449,4 +451,4 @@ namespace mRemoteNG.UI.Menu } #endregion } -} \ No newline at end of file +} diff --git a/mRemoteV1/UI/Panels/PanelAdder.cs b/mRemoteV1/UI/Panels/PanelAdder.cs index 57b90e683..8d69fde58 100644 --- a/mRemoteV1/UI/Panels/PanelAdder.cs +++ b/mRemoteV1/UI/Panels/PanelAdder.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Linq; using System.Windows.Forms; using mRemoteNG.App; using mRemoteNG.Messages; @@ -30,6 +31,12 @@ namespace mRemoteNG.UI.Panels } } + public bool DoesPanelExist(string panelName) + { + return Runtime.WindowList?.OfType().Any(w => w.TabText == panelName) + ?? false; + } + private static void ShowConnectionWindow(ConnectionWindow connectionForm) { connectionForm.Show(FrmMain.Default.pnlDock, DockState.Document); diff --git a/mRemoteV1/UI/TaskDialog/CommandButton.cs b/mRemoteV1/UI/TaskDialog/CommandButton.cs index 4063b13aa..6c9fc5748 100644 --- a/mRemoteV1/UI/TaskDialog/CommandButton.cs +++ b/mRemoteV1/UI/TaskDialog/CommandButton.cs @@ -130,7 +130,7 @@ namespace mRemoteNG.UI.TaskDialog //-------------------------------------------------------------------------------- protected override void OnPaint(PaintEventArgs e) { - if (Tools.DesignModeTest.IsInDesignMode(this) || !_themeManager.ThemingActive) + if ( !_themeManager.ThemingActive) { base.OnPaint(e); return; diff --git a/mRemoteV1/UI/Window/AboutWindow.cs b/mRemoteV1/UI/Window/AboutWindow.cs index 7689a37fc..30602b73e 100644 --- a/mRemoteV1/UI/Window/AboutWindow.cs +++ b/mRemoteV1/UI/Window/AboutWindow.cs @@ -25,24 +25,22 @@ namespace mRemoteNG.UI.Window internal Controls.Base.NGLabel lblEdition; internal Controls.Base.NGLabel lblCredits; internal Controls.Base.NGTextBox txtCredits; - private Controls.Base.NGTextBox verText; internal Panel pnlTop; private void InitializeComponent() { this.pnlTop = new System.Windows.Forms.Panel(); - this.lblEdition = new Controls.Base.NGLabel(); + this.lblEdition = new mRemoteNG.UI.Controls.Base.NGLabel(); this.pbLogo = new System.Windows.Forms.PictureBox(); this.pnlBottom = new System.Windows.Forms.Panel(); - this.verText = new Controls.Base.NGTextBox(); - this.lblCredits = new Controls.Base.NGLabel(); - this.txtCredits = new Controls.Base.NGTextBox(); - this.txtChangeLog = new Controls.Base.NGTextBox(); - this.lblTitle = new Controls.Base.NGLabel(); - this.lblVersion = new Controls.Base.NGLabel(); - this.lblChangeLog = new Controls.Base.NGLabel(); - this.lblLicense = new Controls.Base.NGLabel(); - this.lblCopyright = new Controls.Base.NGLabel(); + this.lblCredits = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.txtCredits = new mRemoteNG.UI.Controls.Base.NGTextBox(); + this.txtChangeLog = new mRemoteNG.UI.Controls.Base.NGTextBox(); + this.lblTitle = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.lblVersion = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.lblChangeLog = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.lblLicense = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.lblCopyright = new mRemoteNG.UI.Controls.Base.NGLabel(); this.pnlTop.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pbLogo)).BeginInit(); this.pnlBottom.SuspendLayout(); @@ -91,7 +89,6 @@ namespace mRemoteNG.UI.Window | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.pnlBottom.BackColor = System.Drawing.SystemColors.Control; - this.pnlBottom.Controls.Add(this.verText); this.pnlBottom.Controls.Add(this.lblCredits); this.pnlBottom.Controls.Add(this.txtCredits); this.pnlBottom.Controls.Add(this.txtChangeLog); @@ -106,18 +103,6 @@ namespace mRemoteNG.UI.Window this.pnlBottom.Size = new System.Drawing.Size(1121, 559); this.pnlBottom.TabIndex = 1; // - // verText - // - this.verText.BackColor = System.Drawing.SystemColors.Control; - this.verText.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.verText.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.verText.Location = new System.Drawing.Point(69, 51); - this.verText.Name = "verText"; - this.verText.Size = new System.Drawing.Size(147, 20); - this.verText.TabIndex = 12; - this.verText.TabStop = false; - this.verText.Text = "w.x.y.z"; - // // lblCredits // this.lblCredits.AutoSize = true; @@ -275,14 +260,16 @@ namespace mRemoteNG.UI.Window private new void ApplyTheme() { - if (Themes.ThemeManager.getInstance().ThemingActive) - { - base.ApplyTheme(); - pnlBottom.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlBottom.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - pnlTop.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); - pnlTop.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); - } + if (!Themes.ThemeManager.getInstance().ThemingActive) return; + base.ApplyTheme(); + BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlBottom.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlBottom.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlTop.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlTop.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + lblEdition.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + lblEdition.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); } private void ApplyEditions() @@ -329,8 +316,7 @@ namespace mRemoteNG.UI.Window { lblCopyright.Text = GeneralAppInfo.Copyright; - lblVersion.Text = @"Version "; - verText.Text = GeneralAppInfo.ApplicationVersion; + lblVersion.Text = $@"Version {GeneralAppInfo.ApplicationVersion}"; if (File.Exists(GeneralAppInfo.HomePath + "\\CHANGELOG.TXT")) { diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs index 8453cbcf9..eb03c12c3 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.Designer.cs @@ -9,19 +9,20 @@ namespace mRemoteNG.UI.Window #region Windows Form Designer generated code private void InitializeComponent() { - this.btnImport = new Controls.Base.NGButton(); + this.btnImport = new mRemoteNG.UI.Controls.Base.NGButton(); this.txtDomain = new mRemoteNG.UI.Controls.Base.NGTextBox(); this.lblDomain = new mRemoteNG.UI.Controls.Base.NGLabel(); - this.btnChangeDomain = new Controls.Base.NGButton(); + this.btnChangeDomain = new mRemoteNG.UI.Controls.Base.NGButton(); this.ActiveDirectoryTree = new ADTree.ADtree(); - this.btnClose = new Controls.Base.NGButton(); + this.btnClose = new mRemoteNG.UI.Controls.Base.NGButton(); this.chkSubOU = new mRemoteNG.UI.Controls.Base.NGCheckBox(); this.SuspendLayout(); // // btnImport // - this.btnImport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnImport.Location = new System.Drawing.Point(362, 338); + this.btnImport._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; + this.btnImport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnImport.Location = new System.Drawing.Point(12, 346); this.btnImport.Name = "btnImport"; this.btnImport.Size = new System.Drawing.Size(75, 23); this.btnImport.TabIndex = 4; @@ -35,7 +36,7 @@ namespace mRemoteNG.UI.Window | System.Windows.Forms.AnchorStyles.Right))); this.txtDomain.Location = new System.Drawing.Point(12, 25); this.txtDomain.Name = "txtDomain"; - this.txtDomain.Size = new System.Drawing.Size(425, 22); + this.txtDomain.Size = new System.Drawing.Size(406, 22); this.txtDomain.TabIndex = 1; this.txtDomain.KeyDown += new System.Windows.Forms.KeyEventHandler(this.txtDomain_KeyDown); // @@ -50,10 +51,11 @@ namespace mRemoteNG.UI.Window // // btnChangeDomain // + this.btnChangeDomain._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnChangeDomain.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnChangeDomain.Location = new System.Drawing.Point(443, 23); + this.btnChangeDomain.Location = new System.Drawing.Point(424, 25); this.btnChangeDomain.Name = "btnChangeDomain"; - this.btnChangeDomain.Size = new System.Drawing.Size(75, 23); + this.btnChangeDomain.Size = new System.Drawing.Size(99, 23); this.btnChangeDomain.TabIndex = 2; this.btnChangeDomain.Text = "Change"; this.btnChangeDomain.UseVisualStyleBackColor = true; @@ -71,16 +73,17 @@ namespace mRemoteNG.UI.Window this.ActiveDirectoryTree.Margin = new System.Windows.Forms.Padding(4); this.ActiveDirectoryTree.Name = "ActiveDirectoryTree"; this.ActiveDirectoryTree.SelectedNode = null; - this.ActiveDirectoryTree.Size = new System.Drawing.Size(506, 280); + this.ActiveDirectoryTree.Size = new System.Drawing.Size(510, 271); this.ActiveDirectoryTree.TabIndex = 3; this.ActiveDirectoryTree.ADPathChanged += new ADTree.ADtree.ADPathChangedEventHandler(this.ActiveDirectoryTree_ADPathChanged); // // btnClose // + this.btnClose._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnClose.Location = new System.Drawing.Point(444, 337); + this.btnClose.Location = new System.Drawing.Point(447, 330); this.btnClose.Name = "btnClose"; - this.btnClose.Size = new System.Drawing.Size(75, 23); + this.btnClose.Size = new System.Drawing.Size(75, 39); this.btnClose.TabIndex = 5; this.btnClose.Text = "Close"; this.btnClose.UseVisualStyleBackColor = true; @@ -88,8 +91,10 @@ namespace mRemoteNG.UI.Window // // chkSubOU // - this.chkSubOU.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.chkSubOU.Location = new System.Drawing.Point(248, 342); + this.chkSubOU._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER; + this.chkSubOU.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkSubOU.AutoSize = true; + this.chkSubOU.Location = new System.Drawing.Point(12, 330); this.chkSubOU.Name = "chkSubOU"; this.chkSubOU.Size = new System.Drawing.Size(108, 17); this.chkSubOU.TabIndex = 6; @@ -100,7 +105,7 @@ namespace mRemoteNG.UI.Window // this.AcceptButton = this.btnImport; this.BackColor = System.Drawing.SystemColors.Control; - this.ClientSize = new System.Drawing.Size(530, 373); + this.ClientSize = new System.Drawing.Size(534, 381); this.Controls.Add(this.chkSubOU); this.Controls.Add(this.btnClose); this.Controls.Add(this.ActiveDirectoryTree); diff --git a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs index 4e21ae3be..df27f667e 100644 --- a/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs +++ b/mRemoteV1/UI/Window/ActiveDirectoryImportWindow.cs @@ -9,9 +9,7 @@ namespace mRemoteNG.UI.Window { public partial class ActiveDirectoryImportWindow { - private string CurrentDomain; - - #region Constructors + private string _currentDomain; public ActiveDirectoryImportWindow() { @@ -19,12 +17,10 @@ namespace mRemoteNG.UI.Window FontOverrider.FontOverride(this); WindowType = WindowType.ActiveDirectoryImport; DockPnl = new DockContent(); - CurrentDomain = Environment.UserDomainName; + _currentDomain = Environment.UserDomainName; ApplyTheme(); } - #endregion - private new void ApplyTheme() { base.ApplyTheme(); @@ -38,8 +34,8 @@ namespace mRemoteNG.UI.Window private void ADImport_Load(object sender, EventArgs e) { ApplyLanguage(); - txtDomain.Text = CurrentDomain; - ActiveDirectoryTree.Domain = CurrentDomain; + txtDomain.Text = _currentDomain; + ActiveDirectoryTree.Domain = _currentDomain; EnableDisableImportButton(); // Domain doesn't refresh on load, so it defaults to DOMAIN without this... @@ -89,13 +85,15 @@ namespace mRemoteNG.UI.Window { btnImport.Text = Language.strButtonImport; lblDomain.Text = Language.strLabelDomain; + chkSubOU.Text = Language.strImportSubOUs; btnChangeDomain.Text = Language.strButtonChange; + btnClose.Text = Language.strButtonClose; } private void ChangeDomain() { - CurrentDomain = txtDomain.Text; - ActiveDirectoryTree.Domain = CurrentDomain; + _currentDomain = txtDomain.Text; + ActiveDirectoryTree.Domain = _currentDomain; ActiveDirectoryTree.Refresh(); } diff --git a/mRemoteV1/UI/Window/BaseWindow.cs b/mRemoteV1/UI/Window/BaseWindow.cs index 7eabc1f98..fdf19d9dd 100644 --- a/mRemoteV1/UI/Window/BaseWindow.cs +++ b/mRemoteV1/UI/Window/BaseWindow.cs @@ -30,8 +30,7 @@ namespace mRemoteNG.UI.Window #endregion internal new void ApplyTheme() - { - if (Tools.DesignModeTest.IsInDesignMode(this)) return; + { _themeManager = ThemeManager.getInstance(); if (!_themeManager.ThemingActive) return; BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); diff --git a/mRemoteV1/UI/Window/ComponentsCheckWindow.cs b/mRemoteV1/UI/Window/ComponentsCheckWindow.cs index 71852152d..1e357f139 100644 --- a/mRemoteV1/UI/Window/ComponentsCheckWindow.cs +++ b/mRemoteV1/UI/Window/ComponentsCheckWindow.cs @@ -399,6 +399,8 @@ namespace mRemoteNG.UI.Window WindowType = WindowType.ComponentsCheck; DockPnl = new DockContent(); InitializeComponent(); + FontOverrider.FontOverride(this); + Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme; } #endregion @@ -406,6 +408,7 @@ namespace mRemoteNG.UI.Window private void ComponentsCheck_Load(object sender, EventArgs e) { ApplyLanguage(); + ApplyTheme(); chkAlwaysShow.Checked = Settings.Default.StartupComponentsCheck; CheckComponents(); } @@ -418,6 +421,24 @@ namespace mRemoteNG.UI.Window btnCheckAgain.Text = Language.strCcCheckAgain; } + private new void ApplyTheme() + { + if (!Themes.ThemeManager.getInstance().ThemingActive) return; + base.ApplyTheme(); + pnlCheck1.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCheck1.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlCheck2.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCheck2.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlCheck3.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCheck3.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlCheck4.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCheck4.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlCheck5.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlCheck5.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + pnlChecks.BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background"); + pnlChecks.ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground"); + } + private void btnCheckAgain_Click(object sender, EventArgs e) { CheckComponents(); diff --git a/mRemoteV1/UI/Window/ConfigWindow.cs b/mRemoteV1/UI/Window/ConfigWindow.cs index 0dd85518a..eb3f2ca5a 100644 --- a/mRemoteV1/UI/Window/ConfigWindow.cs +++ b/mRemoteV1/UI/Window/ConfigWindow.cs @@ -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; @@ -265,6 +265,11 @@ namespace mRemoteNG.UI.Window _btnShowInheritance.Checked = false; } } + + /// + /// A list of properties being shown for the current object. + /// + public IEnumerable VisibleObjectProperties => _pGrid.VisibleProperties; #endregion #region Constructors @@ -701,7 +706,6 @@ namespace mRemoteNG.UI.Window UpdateRootInfoNode(e); UpdateInheritanceNode(); ShowHideGridItems(); - Runtime.ConnectionsService.SaveConnectionsAsync(); } catch (Exception ex) { @@ -745,29 +749,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(Runtime.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(Runtime.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 = ""; } } @@ -819,6 +826,7 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); strHide.Add("RedirectPrinters"); + strHide.Add("RedirectClipboard"); strHide.Add("RedirectSmartCards"); strHide.Add("RedirectSound"); strHide.Add("RenderingEngine"); @@ -925,7 +933,8 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); strHide.Add("RedirectPrinters"); - strHide.Add("RedirectSmartCards"); + strHide.Add("RedirectClipboard"); + strHide.Add("RedirectSmartCards"); strHide.Add("RedirectSound"); strHide.Add("RenderingEngine"); strHide.Add("Resolution"); @@ -970,7 +979,8 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); strHide.Add("RedirectPrinters"); - strHide.Add("RedirectSmartCards"); + strHide.Add("RedirectClipboard"); + strHide.Add("RedirectSmartCards"); strHide.Add("RedirectSound"); strHide.Add("RenderingEngine"); strHide.Add("Resolution"); @@ -1014,7 +1024,8 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); strHide.Add("RedirectPrinters"); - strHide.Add("RedirectSmartCards"); + strHide.Add("RedirectClipboard"); + strHide.Add("RedirectSmartCards"); strHide.Add("RedirectSound"); strHide.Add("RenderingEngine"); strHide.Add("Resolution"); @@ -1059,7 +1070,8 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); strHide.Add("RedirectPrinters"); - strHide.Add("RedirectSmartCards"); + strHide.Add("RedirectClipboard"); + strHide.Add("RedirectSmartCards"); strHide.Add("RedirectSound"); strHide.Add("RenderingEngine"); strHide.Add("Resolution"); @@ -1105,7 +1117,8 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); strHide.Add("RedirectPrinters"); - strHide.Add("RedirectSmartCards"); + strHide.Add("RedirectClipboard"); + strHide.Add("RedirectSmartCards"); strHide.Add("RedirectSound"); strHide.Add("RenderingEngine"); strHide.Add("Resolution"); @@ -1151,7 +1164,8 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); strHide.Add("RedirectPrinters"); - strHide.Add("RedirectSmartCards"); + strHide.Add("RedirectClipboard"); + strHide.Add("RedirectSmartCards"); strHide.Add("RedirectSound"); strHide.Add("RenderingEngine"); strHide.Add("Resolution"); @@ -1173,49 +1187,6 @@ namespace mRemoteNG.UI.Window strHide.Add("SoundQuality"); break; case ProtocolType.HTTP: - strHide.Add("CacheBitmaps"); - strHide.Add("Colors"); - strHide.Add("DisplayThemes"); - strHide.Add("DisplayWallpaper"); - strHide.Add("EnableFontSmoothing"); - strHide.Add("EnableDesktopComposition"); - strHide.Add("Domain"); - strHide.Add("ExtApp"); - strHide.Add("ICAEncryptionStrength"); - strHide.Add("PuttySession"); - strHide.Add("RDGatewayDomain"); - strHide.Add("RDGatewayHostname"); - strHide.Add("RDGatewayPassword"); - strHide.Add("RDGatewayUsageMethod"); - strHide.Add("RDGatewayUseConnectionCredentials"); - strHide.Add("RDGatewayUsername"); - strHide.Add("RDPAuthenticationLevel"); - strHide.Add("RDPMinutesToIdleTimeout"); - strHide.Add("RDPAlertIdleTimeout"); - strHide.Add("LoadBalanceInfo"); - strHide.Add("RedirectDiskDrives"); - strHide.Add("RedirectKeys"); - strHide.Add("RedirectPorts"); - strHide.Add("RedirectPrinters"); - strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound"); - strHide.Add("Resolution"); - strHide.Add("AutomaticResize"); - strHide.Add("UseConsoleSession"); - strHide.Add("UseCredSsp"); - strHide.Add("VNCAuthMode"); - strHide.Add("VNCColors"); - strHide.Add("VNCCompression"); - strHide.Add("VNCEncoding"); - strHide.Add("VNCProxyIP"); - strHide.Add("VNCProxyPassword"); - strHide.Add("VNCProxyPort"); - strHide.Add("VNCProxyType"); - strHide.Add("VNCProxyUsername"); - strHide.Add("VNCSmartSizeMode"); - strHide.Add("VNCViewOnly"); - strHide.Add("SoundQuality"); - break; case ProtocolType.HTTPS: strHide.Add("CacheBitmaps"); strHide.Add("Colors"); @@ -1241,8 +1212,10 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); strHide.Add("RedirectPrinters"); - strHide.Add("RedirectSmartCards"); - strHide.Add("RedirectSound;Resolution"); + strHide.Add("RedirectClipboard"); + strHide.Add("RedirectSmartCards"); + strHide.Add("RedirectSound"); + strHide.Add("Resolution"); strHide.Add("AutomaticResize"); strHide.Add("UseConsoleSession"); strHide.Add("UseCredSsp"); @@ -1259,6 +1232,7 @@ namespace mRemoteNG.UI.Window strHide.Add("VNCViewOnly"); strHide.Add("SoundQuality"); break; + case ProtocolType.ICA: strHide.Add("DisplayThemes"); strHide.Add("DisplayWallpaper"); @@ -1281,7 +1255,8 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); strHide.Add("RedirectPrinters"); - strHide.Add("RedirectSmartCards"); + strHide.Add("RedirectClipboard"); + strHide.Add("RedirectSmartCards"); strHide.Add("RedirectSound"); strHide.Add("RenderingEngine"); strHide.Add("AutomaticResize"); @@ -1323,7 +1298,8 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectKeys"); strHide.Add("RedirectPorts"); strHide.Add("RedirectPrinters"); - strHide.Add("RedirectSmartCards"); + strHide.Add("RedirectClipboard"); + strHide.Add("RedirectSmartCards"); strHide.Add("RedirectSound"); strHide.Add("RenderingEngine"); strHide.Add("Resolution"); @@ -1381,6 +1357,8 @@ namespace mRemoteNG.UI.Window strHide.Add("RedirectPorts"); if (conI.Inheritance.RedirectPrinters) strHide.Add("RedirectPrinters"); + if (conI.Inheritance.RedirectClipboard) + strHide.Add("RedirectClipboard"); if (conI.Inheritance.RedirectSmartCards) strHide.Add("RedirectSmartCards"); if (conI.Inheritance.RedirectSound) diff --git a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs index 0fbe2e5ca..cb42408ae 100644 --- a/mRemoteV1/UI/Window/ConnectionTreeWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionTreeWindow.cs @@ -2,24 +2,24 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; +using System.Linq; using System.Windows.Forms; using mRemoteNG.App; using mRemoteNG.Config.Connections; using mRemoteNG.Connection; using mRemoteNG.Themes; using mRemoteNG.Tree; +using mRemoteNG.Tree.Root; using mRemoteNG.UI.Controls; using WeifenLuo.WinFormsUI.Docking; // ReSharper disable ArrangeAccessorOwnerBody namespace mRemoteNG.UI.Window { - public partial class ConnectionTreeWindow + public partial class ConnectionTreeWindow { - private readonly ConnectionContextMenu _contextMenu; private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator(); private ThemeManager _themeManager; - private readonly ConnectionTreeSearchTextFilter _connectionTreeSearchTextFilter = new ConnectionTreeSearchTextFilter(); public ConnectionInfo SelectedNode => olvConnections.SelectedNode; @@ -38,17 +38,24 @@ namespace mRemoteNG.UI.Window WindowType = WindowType.Tree; DockPnl = panel; InitializeComponent(); - _contextMenu = new ConnectionContextMenu(olvConnections); - olvConnections.ContextMenuStrip = _contextMenu; SetMenuEventHandlers(); SetConnectionTreeEventHandlers(); - Settings.Default.PropertyChanged += (sender, args) => SetConnectionTreeEventHandlers(); - olvConnections.ModelFilter = _connectionTreeSearchTextFilter; + Settings.Default.PropertyChanged += OnAppSettingsChanged; } - + private void OnAppSettingsChanged(object o, PropertyChangedEventArgs propertyChangedEventArgs) + { + if (propertyChangedEventArgs.PropertyName == nameof(Settings.UseFilterSearch)) + { + ConnectionTree.UseFiltering = Settings.Default.UseFilterSearch; + ApplyFiltering(); + } - #region Form Stuff + SetConnectionTreeEventHandlers(); + } + + + #region Form Stuff private void Tree_Load(object sender, EventArgs e) { ApplyLanguage(); @@ -82,7 +89,7 @@ namespace mRemoteNG.UI.Window { if (!_themeManager.ThemingActive) return; vsToolStripExtender.SetStyle(msMain, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); - vsToolStripExtender.SetStyle(_contextMenu, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); + vsToolStripExtender.SetStyle(olvConnections.ContextMenuStrip, _themeManager.ActiveTheme.Version, _themeManager.ActiveTheme.Theme); //Treelistview need to be manually themed olvConnections.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TreeView_Background"); olvConnections.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TreeView_Foreground"); @@ -100,8 +107,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(); @@ -150,7 +155,15 @@ namespace mRemoteNG.UI.Window private void ConnectionsServiceOnConnectionsLoaded(object o, ConnectionsLoadedEventArgs connectionsLoadedEventArgs) { + if (olvConnections.InvokeRequired) + { + olvConnections.Invoke(() => ConnectionsServiceOnConnectionsLoaded(o, connectionsLoadedEventArgs)); + return; + } + olvConnections.ConnectionTreeModel = connectionsLoadedEventArgs.NewConnectionTreeModel; + olvConnections.SelectedObject = connectionsLoadedEventArgs.NewConnectionTreeModel.RootNodes + .OfType().FirstOrDefault(); } #endregion @@ -177,24 +190,6 @@ namespace mRemoteNG.UI.Window { olvConnections.AddFolder(); } - - private void tvConnections_BeforeLabelEdit(object sender, LabelEditEventArgs e) - { - _contextMenu.DisableShortcutKeys(); - } - - private void tvConnections_AfterLabelEdit(object sender, LabelEditEventArgs e) - { - try - { - _contextMenu.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 +238,27 @@ 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.RemoveFilter(); + return; + } + olvConnections.ApplyFilter(txtSearch.Text); + } + else + { + if (txtSearch.Text == "") return; + olvConnections.NodeSearcher?.SearchByName(txtSearch.Text); + JumpToNode(olvConnections.NodeSearcher?.CurrentMatch); + } } private void JumpToNode(ConnectionInfo connectionInfo) diff --git a/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs b/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs index 08a0ef4ab..8e097cbc0 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.Designer.cs @@ -18,6 +18,8 @@ namespace mRemoteNG.UI.Window private ToolStripMenuItem cmenTabRenameTab; private ToolStripMenuItem cmenTabDuplicateTab; private ToolStripMenuItem cmenTabDisconnect; + private ToolStripMenuItem cmenTabDisconnectOthers; + private ToolStripMenuItem cmenTabDisconnectOthersRight; private ToolStripMenuItem cmenTabSmartSize; private ToolStripMenuItem cmenTabSendSpecialKeysCtrlAltDel; private ToolStripMenuItem cmenTabSendSpecialKeysCtrlEsc; @@ -53,6 +55,8 @@ namespace mRemoteNG.UI.Window cmenTabDuplicateTab = new ToolStripMenuItem(); cmenTabReconnect = new ToolStripMenuItem(); cmenTabDisconnect = new ToolStripMenuItem(); + cmenTabDisconnectOthers = new ToolStripMenuItem(); + cmenTabDisconnectOthersRight = new ToolStripMenuItem(); cmenTabPuttySettings = new ToolStripMenuItem(); cmenTab.SuspendLayout(); SuspendLayout(); @@ -91,7 +95,9 @@ namespace mRemoteNG.UI.Window cmenTabRenameTab, cmenTabDuplicateTab, cmenTabReconnect, - cmenTabDisconnect + cmenTabDisconnect, + cmenTabDisconnectOthers, + cmenTabDisconnectOthersRight }); cmenTab.Name = "cmenTab"; cmenTab.RenderMode = ToolStripRenderMode.Professional; @@ -214,6 +220,20 @@ namespace mRemoteNG.UI.Window cmenTabDisconnect.Size = new Size(201, 22); cmenTabDisconnect.Text = @"Disconnect"; // + //cmenTabDisconnectOthers + // + cmenTabDisconnectOthers.Image = Resources.Pause; + cmenTabDisconnectOthers.Name = "cmenTabDisconnectOthers"; + cmenTabDisconnectOthers.Size = new Size(201, 22); + cmenTabDisconnectOthers.Text = @"Disconnect Other Tabs"; + // + //cmenTabDisconnectOthersRight + // + cmenTabDisconnectOthersRight.Image = Resources.Pause; + cmenTabDisconnectOthersRight.Name = "cmenTabDisconnectOthersRight"; + cmenTabDisconnectOthersRight.Size = new Size(201, 22); + cmenTabDisconnectOthersRight.Text = @"Disconnect Tabs To The Right"; + // //cmenTabPuttySettings // cmenTabPuttySettings.Name = "cmenTabPuttySettings"; diff --git a/mRemoteV1/UI/Window/ConnectionWindow.cs b/mRemoteV1/UI/Window/ConnectionWindow.cs index ef2de66a1..135ebc7d4 100644 --- a/mRemoteV1/UI/Window/ConnectionWindow.cs +++ b/mRemoteV1/UI/Window/ConnectionWindow.cs @@ -92,6 +92,8 @@ namespace mRemoteNG.UI.Window cmenTabDuplicateTab.Click += (sender, args) => DuplicateTab(); cmenTabReconnect.Click += (sender, args) => Reconnect(); cmenTabDisconnect.Click += (sender, args) => CloseTabMenu(); + cmenTabDisconnectOthers.Click += (sender, args) => CloseOtherTabs(); + cmenTabDisconnectOthersRight.Click += (sender, args) => CloseOtherTabsToTheRight(); cmenTabPuttySettings.Click += (sender, args) => ShowPuttySettingsDialog(); } @@ -234,6 +236,8 @@ namespace mRemoteNG.UI.Window cmenTabDuplicateTab.Text = Language.strMenuDuplicateTab; cmenTabReconnect.Text = Language.strMenuReconnect; cmenTabDisconnect.Text = Language.strMenuDisconnect; + cmenTabDisconnectOthers.Text = Language.strMenuDisconnectOthers; + cmenTabDisconnectOthersRight.Text = Language.strMenuDisconnectOthersRight; cmenTabPuttySettings.Text = Language.strPuttySettings; } @@ -661,6 +665,92 @@ namespace mRemoteNG.UI.Window } } + private void CloseOtherTabs() + { + try + { + if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple) + { + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionOthersInstruction, TabController.SelectedTab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + if (CTaskDialog.VerificationChecked) + { + Settings.Default.ConfirmCloseConnection--; + } + if (result == DialogResult.No) + { + return; + } + } + foreach (TabPage tab in TabController.TabPages) + { + if (TabController.TabPages.IndexOf(tab) != TabController.TabPages.IndexOf(TabController.SelectedTab)) + { + if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) + { + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, tab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + if (CTaskDialog.VerificationChecked) + { + Settings.Default.ConfirmCloseConnection--; + } + if (result == DialogResult.No) + { + continue; + } + } + var interfaceControl = tab.Tag as InterfaceControl; + interfaceControl?.Protocol.Close(); + } + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); + } + } + + private void CloseOtherTabsToTheRight() + { + try + { + if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.Multiple) + { + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionRightInstruction, TabController.SelectedTab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + if (CTaskDialog.VerificationChecked) + { + Settings.Default.ConfirmCloseConnection--; + } + if (result == DialogResult.No) + { + return; + } + } + foreach (TabPage tab in TabController.TabPages) + { + if (TabController.TabPages.IndexOf(tab) > TabController.TabPages.IndexOf(TabController.SelectedTab)) + { + if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) + { + var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName, string.Format(Language.strConfirmCloseConnectionMainInstruction, tab.Title), "", "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.YesNo, ESysIcons.Question, ESysIcons.Question); + if (CTaskDialog.VerificationChecked) + { + Settings.Default.ConfirmCloseConnection--; + } + if (result == DialogResult.No) + { + continue; + } + } + var interfaceControl = tab.Tag as InterfaceControl; + interfaceControl?.Protocol.Close(); + } + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage("CloseTabMenu (UI.Window.ConnectionWindow) failed", ex); + } + } + private void DuplicateTab() { try @@ -727,6 +817,9 @@ namespace mRemoteNG.UI.Window private delegate void CloseTabDelegate(TabPage tabToBeClosed); private void CloseTab(TabPage tabToBeClosed) { + if (tabToBeClosed.Disposing || tabToBeClosed.IsDisposed) + return; + if (TabController.InvokeRequired) { CloseTabDelegate s = CloseTab; diff --git a/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs b/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs index 463e840f2..a379657d4 100644 --- a/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs +++ b/mRemoteV1/UI/Window/ErrorAndInfoWindow.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using System.Collections; +using System.Globalization; using System.Windows.Forms; using System.Text; using WeifenLuo.WinFormsUI.Docking; @@ -14,7 +15,7 @@ namespace mRemoteNG.UI.Window public partial class ErrorAndInfoWindow : BaseWindow { private ControlLayout _layout = ControlLayout.Vertical; - private ThemeManager _themeManager; + private readonly ThemeManager _themeManager; public DockContent PreviousActiveForm { get; set; } @@ -53,11 +54,9 @@ namespace mRemoteNG.UI.Window #region Private Methods private new void ApplyTheme() { - if(_themeManager.ThemingActive) - { - lvErrorCollector.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); - lvErrorCollector.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); - } + if (!_themeManager.ThemingActive) return; + lvErrorCollector.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background"); + lvErrorCollector.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground"); } @@ -224,7 +223,7 @@ namespace mRemoteNG.UI.Window break; } - lblMsgDate.Text = eMsg.Date.ToString(); + lblMsgDate.Text = eMsg.Date.ToString(CultureInfo.InvariantCulture); txtMsgText.Text = eMsg.Text; } catch (Exception ex) @@ -291,7 +290,7 @@ namespace mRemoteNG.UI.Window } stringBuilder.AppendLine(message.Class.ToString()); - stringBuilder.AppendLine(message.Date.ToString()); + stringBuilder.AppendLine(message.Date.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine(message.Text); stringBuilder.AppendLine("----------"); } @@ -339,8 +338,8 @@ namespace mRemoteNG.UI.Window } } #endregion - - public enum ControlLayout + + private enum ControlLayout { Vertical = 0, Horizontal = 1 diff --git a/mRemoteV1/UI/Window/ExternalToolsWindow.Designer.cs b/mRemoteV1/UI/Window/ExternalToolsWindow.Designer.cs index 99aee3cbc..4eeb70497 100644 --- a/mRemoteV1/UI/Window/ExternalToolsWindow.Designer.cs +++ b/mRemoteV1/UI/Window/ExternalToolsWindow.Designer.cs @@ -274,7 +274,7 @@ namespace mRemoteNG.UI.Window // this.ShowOnToolbarCheckBox._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER; this.ShowOnToolbarCheckBox.AutoSize = true; - this.ShowOnToolbarCheckBox.Location = new System.Drawing.Point(306, 158); + this.ShowOnToolbarCheckBox.Location = new System.Drawing.Point(369, 158); this.ShowOnToolbarCheckBox.Name = "ShowOnToolbarCheckBox"; this.ShowOnToolbarCheckBox.Size = new System.Drawing.Size(113, 17); this.ShowOnToolbarCheckBox.TabIndex = 10; @@ -330,7 +330,7 @@ namespace mRemoteNG.UI.Window // this.TryToIntegrateCheckBox._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER; this.TryToIntegrateCheckBox.AutoSize = true; - this.TryToIntegrateCheckBox.Location = new System.Drawing.Point(306, 135); + this.TryToIntegrateCheckBox.Location = new System.Drawing.Point(369, 135); this.TryToIntegrateCheckBox.Name = "TryToIntegrateCheckBox"; this.TryToIntegrateCheckBox.Size = new System.Drawing.Size(103, 17); this.TryToIntegrateCheckBox.TabIndex = 8; diff --git a/mRemoteV1/UI/Window/ExternalToolsWindow.cs b/mRemoteV1/UI/Window/ExternalToolsWindow.cs index ea343b76c..968bcedf0 100644 --- a/mRemoteV1/UI/Window/ExternalToolsWindow.cs +++ b/mRemoteV1/UI/Window/ExternalToolsWindow.cs @@ -45,26 +45,34 @@ namespace mRemoteNG.UI.Window TabText = Language.strMenuExternalTools; NewToolToolstripButton.Text = Language.strButtonNew; - DeleteToolToolstripButton.Text = Language.strOptionsKeyboardButtonDelete; + DeleteToolToolstripButton.Text = Language.strOptionsThemeButtonDelete; LaunchToolToolstripButton.Text = Language.strButtonLaunch; DisplayNameColumnHeader.Text = Language.strColumnDisplayName; FilenameColumnHeader.Text = Language.strColumnFilename; ArgumentsColumnHeader.Text = Language.strColumnArguments; - WaitForExitColumnHeader.Text = Language.strColumnWaitForExit; - TryToIntegrateCheckBox.Text = Language.strTryIntegrate; + WorkingDirColumnHeader.Text = Language.strWorkingDirColumnHeader; + WaitForExitColumnHeader.Text = Language.strColumnWaitForExit; + TryToIntegrateColumnHeader.Text = Language.strTryToIntegrateColumnHeader; + RunElevateHeader.Text = Language.strRunElevateHeader; + ShowOnToolbarColumnHeader.Text = Language.strShowOnToolbarColumnHeader; + + TryToIntegrateCheckBox.Text = Language.strTryIntegrate; ShowOnToolbarCheckBox.Text = Language.strShowOnToolbar; + RunElevatedCheckBox.Text = Language.strRunElevated; - PropertiesGroupBox.Text = Language.strGroupboxExternalToolProperties; + PropertiesGroupBox.Text = Language.strGroupboxExternalToolProperties; DisplayNameLabel.Text = Language.strLabelDisplayName; FilenameLabel.Text = Language.strLabelFilename; ArgumentsLabel.Text = Language.strLabelArguments; - OptionsLabel.Text = Language.strLabelOptions; + WorkingDirLabel.Text = Language.srtWorkingDirectory; + OptionsLabel.Text = Language.strLabelOptions; + WaitForExitCheckBox.Text = Language.strCheckboxWaitForExit; BrowseButton.Text = Language.strButtonBrowse; - - NewToolMenuItem.Text = Language.strMenuNewExternalTool; + BrowseWorkingDir.Text = Language.strButtonBrowse; + NewToolMenuItem.Text = Language.strMenuNewExternalTool; DeleteToolMenuItem.Text = Language.strMenuDeleteExternalTool; LaunchToolMenuItem.Text = Language.strMenuLaunchExternalTool; } @@ -126,6 +134,19 @@ namespace mRemoteNG.UI.Window RunElevatedCheckBox.Checked = selectedTool?.RunElevated ?? false; WaitForExitCheckBox.Enabled = !TryToIntegrateCheckBox.Checked; } + + private void UpdateToolstipControls() + { + _currentlySelectedExternalTools.Clear(); + _currentlySelectedExternalTools.AddRange(ToolsListObjView.SelectedObjects.OfType()); + PropertiesGroupBox.Enabled = _currentlySelectedExternalTools.Count == 1; + + var atleastOneToolSelected = _currentlySelectedExternalTools.Count > 0; + DeleteToolMenuItem.Enabled = atleastOneToolSelected; + DeleteToolToolstripButton.Enabled = atleastOneToolSelected; + LaunchToolMenuItem.Enabled = atleastOneToolSelected; + LaunchToolToolstripButton.Enabled = atleastOneToolSelected; + } #endregion #region Event Handlers @@ -185,6 +206,8 @@ namespace mRemoteNG.UI.Window ToolsListObjView.SelectedIndex = oldSelectedIndex <= maxIndex ? oldSelectedIndex : maxIndex; + + UpdateToolstipControls(); } catch (Exception ex) { @@ -201,15 +224,7 @@ namespace mRemoteNG.UI.Window { try { - _currentlySelectedExternalTools.Clear(); - _currentlySelectedExternalTools.AddRange(ToolsListObjView.SelectedObjects.OfType()); - PropertiesGroupBox.Enabled = _currentlySelectedExternalTools.Count == 1; - - var atleastOneToolSelected = _currentlySelectedExternalTools.Count > 0; - DeleteToolMenuItem.Enabled = atleastOneToolSelected; - DeleteToolToolstripButton.Enabled = atleastOneToolSelected; - LaunchToolMenuItem.Enabled = atleastOneToolSelected; - LaunchToolToolstripButton.Enabled = atleastOneToolSelected; + UpdateToolstipControls(); } catch (Exception ex) { diff --git a/mRemoteV1/UI/Window/HelpWindow.cs b/mRemoteV1/UI/Window/HelpWindow.cs index 1d961b978..6310223cb 100644 --- a/mRemoteV1/UI/Window/HelpWindow.cs +++ b/mRemoteV1/UI/Window/HelpWindow.cs @@ -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; diff --git a/mRemoteV1/UI/Window/PortScanWindow.Designer.cs b/mRemoteV1/UI/Window/PortScanWindow.Designer.cs index d9ef1c120..465fd1834 100644 --- a/mRemoteV1/UI/Window/PortScanWindow.Designer.cs +++ b/mRemoteV1/UI/Window/PortScanWindow.Designer.cs @@ -26,7 +26,7 @@ namespace mRemoteNG.UI.Window internal Controls.Base.NGProgressBar prgBar; internal Controls.Base.NGLabel lblOnlyImport; internal Controls.Base.NGComboBox cbProtocol; - internal System.Windows.Forms.Panel pnlPorts; + internal System.Windows.Forms.Panel pnlScan; internal Controls.Base.NGNumericUpDown portEnd; internal Controls.Base.NGNumericUpDown portStart; internal Controls.Base.NGLabel Label2; @@ -42,7 +42,7 @@ namespace mRemoteNG.UI.Window this.ipEnd = new mRemoteNG.UI.Controls.IPTextBox(); this.lblStartIP = new mRemoteNG.UI.Controls.Base.NGLabel(); this.lblEndIP = new mRemoteNG.UI.Controls.Base.NGLabel(); - this.btnScan = new Controls.Base.NGButton(); + this.btnScan = new mRemoteNG.UI.Controls.Base.NGButton(); this.olvHosts = new mRemoteNG.UI.Controls.Base.NGListView(); this.resultsMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.importHTTPToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -52,8 +52,8 @@ namespace mRemoteNG.UI.Window this.importSSH2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.importTelnetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.importVNCToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.btnImport = new Controls.Base.NGButton(); - this.cbProtocol = new Controls.Base.NGComboBox(); + this.btnImport = new mRemoteNG.UI.Controls.Base.NGButton(); + this.cbProtocol = new mRemoteNG.UI.Controls.Base.NGComboBox(); this.lblOnlyImport = new mRemoteNG.UI.Controls.Base.NGLabel(); this.clmHost = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); this.clmSSH = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); @@ -66,15 +66,18 @@ namespace mRemoteNG.UI.Window this.clmOpenPorts = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); this.clmClosedPorts = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); this.prgBar = new mRemoteNG.UI.Controls.Base.NGProgressBar(); - this.pnlPorts = new System.Windows.Forms.Panel(); - this.portEnd = new Controls.Base.NGNumericUpDown(); - this.portStart = new Controls.Base.NGNumericUpDown(); + this.pnlScan = new System.Windows.Forms.Panel(); + this.numericSelectorTimeout = new mRemoteNG.UI.Controls.Base.NGNumericUpDown(); + this.lblTimeout = new System.Windows.Forms.Label(); + this.portEnd = new mRemoteNG.UI.Controls.Base.NGNumericUpDown(); + this.portStart = new mRemoteNG.UI.Controls.Base.NGNumericUpDown(); this.Label2 = new mRemoteNG.UI.Controls.Base.NGLabel(); this.Label1 = new mRemoteNG.UI.Controls.Base.NGLabel(); this.pnlImport = new System.Windows.Forms.Panel(); ((System.ComponentModel.ISupportInitialize)(this.olvHosts)).BeginInit(); this.resultsMenuStrip.SuspendLayout(); - this.pnlPorts.SuspendLayout(); + this.pnlScan.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numericSelectorTimeout)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.portEnd)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.portStart)).BeginInit(); this.pnlImport.SuspendLayout(); @@ -82,24 +85,24 @@ namespace mRemoteNG.UI.Window // // ipStart // - this.ipStart.Location = new System.Drawing.Point(12, 25); + 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 // - this.ipEnd.Location = new System.Drawing.Point(148, 25); + 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 // this.lblStartIP.AutoSize = true; - this.lblStartIP.Location = new System.Drawing.Point(12, 7); + this.lblStartIP.Location = new System.Drawing.Point(3, 5); this.lblStartIP.Name = "lblStartIP"; this.lblStartIP.Size = new System.Drawing.Size(46, 13); this.lblStartIP.TabIndex = 0; @@ -108,7 +111,7 @@ namespace mRemoteNG.UI.Window // lblEndIP // this.lblEndIP.AutoSize = true; - this.lblEndIP.Location = new System.Drawing.Point(148, 7); + this.lblEndIP.Location = new System.Drawing.Point(152, 5); this.lblEndIP.Name = "lblEndIP"; this.lblEndIP.Size = new System.Drawing.Size(42, 13); this.lblEndIP.TabIndex = 5; @@ -116,13 +119,14 @@ namespace mRemoteNG.UI.Window // // btnScan // + this.btnScan._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnScan.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnScan.Image = global::mRemoteNG.Resources.Search; this.btnScan.ImageAlign = System.Drawing.ContentAlignment.MiddleRight; - this.btnScan.Location = new System.Drawing.Point(597, 12); + this.btnScan.Location = new System.Drawing.Point(769, 5); this.btnScan.Name = "btnScan"; - this.btnScan.Size = new System.Drawing.Size(95, 55); - this.btnScan.TabIndex = 20; + this.btnScan.Size = new System.Drawing.Size(110, 55); + this.btnScan.TabIndex = 6; this.btnScan.Text = "&Scan"; this.btnScan.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; this.btnScan.UseVisualStyleBackColor = true; @@ -135,6 +139,8 @@ namespace mRemoteNG.UI.Window | System.Windows.Forms.AnchorStyles.Right))); this.olvHosts.CellEditUseWholeCell = false; this.olvHosts.ContextMenuStrip = this.resultsMenuStrip; + this.olvHosts.Cursor = System.Windows.Forms.Cursors.Default; + this.olvHosts.DecorateLines = true; this.olvHosts.FullRowSelect = true; this.olvHosts.GridLines = true; this.olvHosts.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; @@ -142,7 +148,7 @@ namespace mRemoteNG.UI.Window this.olvHosts.Location = new System.Drawing.Point(12, 73); this.olvHosts.Name = "olvHosts"; this.olvHosts.ShowGroups = false; - this.olvHosts.Size = new System.Drawing.Size(680, 290); + this.olvHosts.Size = new System.Drawing.Size(883, 290); this.olvHosts.TabIndex = 26; this.olvHosts.UseCompatibleStateImageBehavior = false; this.olvHosts.View = System.Windows.Forms.View.Details; @@ -211,17 +217,19 @@ namespace mRemoteNG.UI.Window // // btnImport // + this.btnImport._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnImport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnImport.Location = new System.Drawing.Point(594, 3); + this.btnImport.Location = new System.Drawing.Point(800, 5); this.btnImport.Name = "btnImport"; - this.btnImport.Size = new System.Drawing.Size(75, 31); - this.btnImport.TabIndex = 101; + this.btnImport.Size = new System.Drawing.Size(80, 40); + this.btnImport.TabIndex = 8; this.btnImport.Text = "&Import"; this.btnImport.UseVisualStyleBackColor = true; this.btnImport.Click += new System.EventHandler(this.btnImport_Click); // // cbProtocol // + this.cbProtocol._mice = mRemoteNG.UI.Controls.Base.NGComboBox.MouseState.HOVER; this.cbProtocol.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.cbProtocol.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbProtocol.FormattingEnabled = true; @@ -233,16 +241,16 @@ namespace mRemoteNG.UI.Window "Rlogin", "RDP", "VNC"}); - this.cbProtocol.Location = new System.Drawing.Point(157, 6); + 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 // this.lblOnlyImport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.lblOnlyImport.AutoSize = true; - this.lblOnlyImport.Location = new System.Drawing.Point(5, 13); + this.lblOnlyImport.Location = new System.Drawing.Point(2, 5); this.lblOnlyImport.Name = "lblOnlyImport"; this.lblOnlyImport.Size = new System.Drawing.Size(104, 13); this.lblOnlyImport.TabIndex = 1; @@ -315,26 +323,57 @@ namespace mRemoteNG.UI.Window // this.prgBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.prgBar.Location = new System.Drawing.Point(12, 50); + this.prgBar.Location = new System.Drawing.Point(5, 45); this.prgBar.Name = "prgBar"; - this.prgBar.Size = new System.Drawing.Size(571, 16); + this.prgBar.Size = new System.Drawing.Size(760, 15); this.prgBar.Step = 1; this.prgBar.TabIndex = 28; // - // pnlPorts + // pnlScan // - this.pnlPorts.Controls.Add(this.portEnd); - this.pnlPorts.Controls.Add(this.portStart); - this.pnlPorts.Controls.Add(this.Label2); - this.pnlPorts.Controls.Add(this.Label1); - this.pnlPorts.Location = new System.Drawing.Point(284, 7); - this.pnlPorts.Name = "pnlPorts"; - this.pnlPorts.Size = new System.Drawing.Size(307, 38); - this.pnlPorts.TabIndex = 18; + this.pnlScan.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.pnlScan.Controls.Add(this.numericSelectorTimeout); + this.pnlScan.Controls.Add(this.lblTimeout); + this.pnlScan.Controls.Add(this.portEnd); + this.pnlScan.Controls.Add(this.portStart); + this.pnlScan.Controls.Add(this.prgBar); + this.pnlScan.Controls.Add(this.Label2); + this.pnlScan.Controls.Add(this.lblStartIP); + this.pnlScan.Controls.Add(this.lblEndIP); + this.pnlScan.Controls.Add(this.ipStart); + this.pnlScan.Controls.Add(this.btnScan); + this.pnlScan.Controls.Add(this.Label1); + this.pnlScan.Controls.Add(this.ipEnd); + this.pnlScan.Location = new System.Drawing.Point(12, 5); + this.pnlScan.Name = "pnlScan"; + this.pnlScan.Size = new System.Drawing.Size(883, 65); + this.pnlScan.TabIndex = 18; + // + // numericSelectorTimeout + // + this.numericSelectorTimeout.Location = new System.Drawing.Point(600, 17); + this.numericSelectorTimeout.Maximum = new decimal(new int[] { + 2147482, + 0, + 0, + 0}); + this.numericSelectorTimeout.Name = "numericSelectorTimeout"; + this.numericSelectorTimeout.Size = new System.Drawing.Size(67, 22); + this.numericSelectorTimeout.TabIndex = 5; + // + // lblTimeout + // + this.lblTimeout.AutoSize = true; + this.lblTimeout.Location = new System.Drawing.Point(597, 1); + this.lblTimeout.Name = "lblTimeout"; + this.lblTimeout.Size = new System.Drawing.Size(102, 13); + this.lblTimeout.TabIndex = 16; + this.lblTimeout.Text = "Timeout (seconds):"; // // portEnd // - this.portEnd.Location = new System.Drawing.Point(232, 12); + this.portEnd.Location = new System.Drawing.Point(490, 17); this.portEnd.Maximum = new decimal(new int[] { 65535, 0, @@ -342,12 +381,12 @@ 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 // - this.portStart.Location = new System.Drawing.Point(79, 12); + this.portStart.Location = new System.Drawing.Point(375, 17); this.portStart.Maximum = new decimal(new int[] { 65535, 0, @@ -355,13 +394,13 @@ 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 // this.Label2.AutoSize = true; - this.Label2.Location = new System.Drawing.Point(162, 16); + this.Label2.Location = new System.Drawing.Point(487, 1); this.Label2.Name = "Label2"; this.Label2.Size = new System.Drawing.Size(54, 13); this.Label2.TabIndex = 10; @@ -370,7 +409,7 @@ namespace mRemoteNG.UI.Window // Label1 // this.Label1.AutoSize = true; - this.Label1.Location = new System.Drawing.Point(3, 17); + this.Label1.Location = new System.Drawing.Point(372, 1); this.Label1.Name = "Label1"; this.Label1.Size = new System.Drawing.Size(58, 13); this.Label1.TabIndex = 0; @@ -383,40 +422,36 @@ namespace mRemoteNG.UI.Window this.pnlImport.Controls.Add(this.btnImport); this.pnlImport.Controls.Add(this.lblOnlyImport); this.pnlImport.Controls.Add(this.cbProtocol); - this.pnlImport.Location = new System.Drawing.Point(12, 369); + this.pnlImport.Location = new System.Drawing.Point(12, 364); this.pnlImport.Name = "pnlImport"; - this.pnlImport.Size = new System.Drawing.Size(680, 40); + this.pnlImport.Size = new System.Drawing.Size(883, 50); this.pnlImport.TabIndex = 102; // // PortScanWindow // this.AcceptButton = this.btnImport; - this.ClientSize = new System.Drawing.Size(704, 421); + this.AutoScroll = true; + this.ClientSize = new System.Drawing.Size(908, 421); this.Controls.Add(this.pnlImport); this.Controls.Add(this.olvHosts); - this.Controls.Add(this.pnlPorts); - this.Controls.Add(this.prgBar); - this.Controls.Add(this.btnScan); - this.Controls.Add(this.lblEndIP); - this.Controls.Add(this.lblStartIP); - this.Controls.Add(this.ipEnd); - this.Controls.Add(this.ipStart); + this.Controls.Add(this.pnlScan); this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MinimumSize = new System.Drawing.Size(924, 460); this.Name = "PortScanWindow"; this.TabText = "Port Scan"; this.Text = "Port Scan"; this.Load += new System.EventHandler(this.PortScan_Load); ((System.ComponentModel.ISupportInitialize)(this.olvHosts)).EndInit(); this.resultsMenuStrip.ResumeLayout(false); - this.pnlPorts.ResumeLayout(false); - this.pnlPorts.PerformLayout(); + this.pnlScan.ResumeLayout(false); + this.pnlScan.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numericSelectorTimeout)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.portEnd)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.portStart)).EndInit(); this.pnlImport.ResumeLayout(false); this.pnlImport.PerformLayout(); this.ResumeLayout(false); - this.PerformLayout(); } internal System.Windows.Forms.Panel pnlImport; @@ -431,5 +466,7 @@ namespace mRemoteNG.UI.Window private System.Windows.Forms.ToolStripMenuItem importSSH2ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem importTelnetToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem importVNCToolStripMenuItem; - } + private System.Windows.Forms.Label lblTimeout; + private Controls.Base.NGNumericUpDown numericSelectorTimeout; + } } diff --git a/mRemoteV1/UI/Window/PortScanWindow.cs b/mRemoteV1/UI/Window/PortScanWindow.cs index d8cdced92..28eae3ea0 100644 --- a/mRemoteV1/UI/Window/PortScanWindow.cs +++ b/mRemoteV1/UI/Window/PortScanWindow.cs @@ -1,17 +1,18 @@ 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; -using static mRemoteNG.Tools.MiscTools; namespace mRemoteNG.UI.Window { - public partial class PortScanWindow + public partial class PortScanWindow { #region Constructors public PortScanWindow() @@ -90,6 +91,7 @@ namespace mRemoteNG.UI.Window olvHosts.Columns.AddRange(new[]{clmHost, clmSSH, clmTelnet, clmHTTP, clmHTTPS, clmRlogin, clmRDP, clmVNC, clmOpenPorts, clmClosedPorts}); ShowImportControls(true); cbProtocol.SelectedIndex = 0; + numericSelectorTimeout.Value = 5; } catch (Exception ex) { @@ -122,16 +124,14 @@ namespace mRemoteNG.UI.Window else { Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, Language.strCannotStartPortScan); - } + } } } private void btnImport_Click(object sender, EventArgs e) { - ProtocolType protocol = (ProtocolType)StringToEnum(typeof(ProtocolType), Convert.ToString(cbProtocol.SelectedItem)); + ProtocolType protocol = (ProtocolType)Enum.Parse(typeof(ProtocolType), Convert.ToString(cbProtocol.SelectedItem), true); importSelectedHosts(protocol); - DialogResult = DialogResult.OK; - Close(); } #endregion @@ -147,13 +147,14 @@ namespace mRemoteNG.UI.Window clmClosedPorts.Text = Language.strClosedPorts; Label2.Text = $"{Language.strEndPort}:"; Label1.Text = $"{Language.strStartPort}:"; + lblTimeout.Text = $"{Language.strTimeoutInSeconds}"; TabText = Language.strMenuPortScan; Text = Language.strMenuPortScan; } private void ShowImportControls(bool controlsVisible) { - pnlPorts.Visible = controlsVisible; + pnlScan.Visible = controlsVisible; pnlImport.Visible = controlsVisible; if (controlsVisible) { @@ -176,7 +177,7 @@ namespace mRemoteNG.UI.Window System.Net.IPAddress ipAddressStart = System.Net.IPAddress.Parse(ipStart.Text); System.Net.IPAddress ipAddressEnd = System.Net.IPAddress.Parse(ipEnd.Text); - _portScanner = new PortScanner(ipAddressStart, ipAddressEnd, (int) portStart.Value, (int) portEnd.Value); + _portScanner = new PortScanner(ipAddressStart, ipAddressEnd, (int) portStart.Value, (int) portEnd.Value, ((int)numericSelectorTimeout.Value)*1000); _portScanner.BeginHostScan += PortScanner_BeginHostScan; _portScanner.HostScanned += PortScanner_HostScanned; @@ -256,10 +257,29 @@ namespace mRemoteNG.UI.Window return; } - var selectedTreeNodeAsContainer = Windows.TreeForm.SelectedNode as ContainerInfo ?? Windows.TreeForm.SelectedNode.Parent; - Import.ImportFromPortScan(hosts, protocol, selectedTreeNodeAsContainer); + var destinationContainer = GetDestinationContainerForImportedHosts(); + Import.ImportFromPortScan(hosts, protocol, destinationContainer); } + /// + /// Determines where the imported hosts will be placed + /// in the connection tree. + /// + private ContainerInfo GetDestinationContainerForImportedHosts() + { + var selectedNode = Windows.TreeForm.SelectedNode + ?? Windows.TreeForm.ConnectionTree.ConnectionTreeModel.RootNodes.OfType().First(); + + // if a putty node is selected, place imported connections in the root connection node + if (selectedNode is RootPuttySessionsNodeInfo || selectedNode is PuttySessionInfo) + selectedNode = Windows.TreeForm.ConnectionTree.ConnectionTreeModel.RootNodes.OfType().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); diff --git a/mRemoteV1/UI/Window/UpdateWindow.Designer.cs b/mRemoteV1/UI/Window/UpdateWindow.Designer.cs index 8a9f34a19..6a8d2f241 100644 --- a/mRemoteV1/UI/Window/UpdateWindow.Designer.cs +++ b/mRemoteV1/UI/Window/UpdateWindow.Designer.cs @@ -20,17 +20,17 @@ namespace mRemoteNG.UI.Window private void InitializeComponent() { - this.btnCheckForUpdate = new Controls.Base.NGButton(); + this.btnCheckForUpdate = new mRemoteNG.UI.Controls.Base.NGButton(); this.pnlUpdate = new System.Windows.Forms.Panel(); - this.lblChangeLogLabel = new Controls.Base.NGLabel(); - this.btnDownload = new Controls.Base.NGButton(); - this.prgbDownload = new Controls.Base.NGProgressBar(); - this.txtChangeLog = new Controls.Base.NGTextBox(); - this.lblStatus = new Controls.Base.NGLabel(); - this.lblLatestVersionLabel = new Controls.Base.NGLabel(); - this.lblInstalledVersionLabel = new Controls.Base.NGLabel(); - this.lblLatestVersion = new Controls.Base.NGLabel(); - this.lblInstalledVersion = new Controls.Base.NGLabel(); + this.lblChangeLogLabel = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.btnDownload = new mRemoteNG.UI.Controls.Base.NGButton(); + this.prgbDownload = new mRemoteNG.UI.Controls.Base.NGProgressBar(); + this.txtChangeLog = new mRemoteNG.UI.Controls.Base.NGTextBox(); + this.lblStatus = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.lblLatestVersionLabel = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.lblInstalledVersionLabel = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.lblLatestVersion = new mRemoteNG.UI.Controls.Base.NGLabel(); + this.lblInstalledVersion = new mRemoteNG.UI.Controls.Base.NGLabel(); this.pbUpdateImage = new System.Windows.Forms.PictureBox(); this.pnlUpdate.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pbUpdateImage)).BeginInit(); @@ -38,6 +38,7 @@ namespace mRemoteNG.UI.Window // // btnCheckForUpdate // + this.btnCheckForUpdate._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnCheckForUpdate.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btnCheckForUpdate.Location = new System.Drawing.Point(16, 104); this.btnCheckForUpdate.Name = "btnCheckForUpdate"; @@ -74,11 +75,12 @@ namespace mRemoteNG.UI.Window // // btnDownload // + this.btnDownload._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER; this.btnDownload.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnDownload.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btnDownload.Location = new System.Drawing.Point(0, 216); this.btnDownload.Name = "btnDownload"; - this.btnDownload.Size = new System.Drawing.Size(144, 32); + this.btnDownload.Size = new System.Drawing.Size(224, 32); this.btnDownload.TabIndex = 2; this.btnDownload.Text = "Download and Install"; this.btnDownload.UseVisualStyleBackColor = true; @@ -88,9 +90,9 @@ namespace mRemoteNG.UI.Window // this.prgbDownload.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.prgbDownload.Location = new System.Drawing.Point(160, 224); + this.prgbDownload.Location = new System.Drawing.Point(230, 224); this.prgbDownload.Name = "prgbDownload"; - this.prgbDownload.Size = new System.Drawing.Size(542, 23); + this.prgbDownload.Size = new System.Drawing.Size(472, 23); this.prgbDownload.TabIndex = 3; this.prgbDownload.Visible = false; // diff --git a/mRemoteV1/app.config b/mRemoteV1/app.config index 48862e673..eaaf2d11c 100644 --- a/mRemoteV1/app.config +++ b/mRemoteV1/app.config @@ -170,6 +170,9 @@ False + + False + False @@ -275,6 +278,9 @@ False + + False + False @@ -666,7 +672,7 @@ - + General True @@ -683,125 +689,24 @@ False + + 0, 0 + + + + + + False + + + False + + + General + - - - /TreeView/Background/Background/@Source - - - /TreeView/Background/Foreground/@Source - - - /TreeView/SelectedItemActive/Background/@Source - - - /TreeView/SelectedItemActive/Foreground/@Source - - - /TreeView/SelectedItemInactive/Background/@Source - - - /TreeView/SelectedItemInactive/Foreground/@Source - - - /Cider/ListBackground/Background/@Source - - - /Cider/ListItem/Foreground/@Source - - - /Cider/ListItem/Background/@Source - - - /Cider/ListItemBorder/Background/@Source - - - /Cider/ListHeader/Background/@Source - - - /Cider/ListHeader/Foreground/@Source - - - /Cider/ListItemSelectedBorder/Background/@Source - - - /Cider/ListItemSelected/Foreground/@Source - - - /Cider/ListItemSelected/Background/@Source - - - /Cider/ListItemDisabled/Foreground/@Source - - - /Cider/ListItemDisabled/Background/@Source - - - /Cider/ListItemDisabledBorder/Background/@Source - - - /CommonControls/Button/Background/@Source - - - /CommonControls/Button/Foreground/@Source - - - /CommonControls/ButtonBorder/Background/@Source - - - /CommonControls/ButtonPressed/Background/@Source - - - /CommonControls/ButtonPressed/Foreground/@Source - - - /CommonControls/ButtonHover/Background/@Source - - - /CommonControls/ButtonHover/Foreground/@Source - - - /TextEditorTextMarkerItems/compilerwarning/Background/@Source - - - /TextEditorTextMarkerItems/compilerwarning/Foreground/@Source - - - /TextEditorTextMarkerItems/compilererror/Background/@Source - - - /TextEditorTextMarkerItems/compilererror/Foreground/@Source - - - /CommonControls/TextBoxBackground/Background/@Source - - - /CommonControls/TextBoxText/Background/@Source - - - /CommonControls/TextBoxBorder/Background/@Source - - - /CommonControls/TextBoxBorderDisabled/Background/@Source - - - /CommonControls/TextBoxBorderFocused/Background/@Source - - - /CommonControls/TextBoxBackgroundDisabled/Background/@Source - - - /CommonControls/TextBoxTextDisabled/Background/@Source - - - /CommonControls/TextBoxBackgroundFocused/Background/@Source - - - /CommonControls/TextBoxTextFocused/Background/@Source - - https://mremoteng.org/ diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index 302e1567d..7dbcdbb86 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -23,7 +23,7 @@ Off B249710A6BB08171F8E75082CF2355AE2890911A mRemoteV1_TemporaryKey.pfx - true + false false v4.6 @@ -41,7 +41,7 @@ false true 1 - 1.64.0.%2a + 1.64.0.1 false true true @@ -157,7 +157,9 @@ + + @@ -166,14 +168,15 @@ - + + - + @@ -186,17 +189,17 @@ - - - + + + - + - + @@ -209,7 +212,7 @@ - + @@ -311,8 +314,8 @@ - + @@ -320,10 +323,13 @@ - + + + + @@ -963,9 +969,10 @@ Designer - + Designer - + Always + Designer @@ -1555,24 +1562,26 @@ powershell.exe -ExecutionPolicy Bypass -File "%25psScriptsDir%25\postbuild_mremo false - false + true true bin\Release\ 1591,660,661 - none + full x86 AllRules.ruleset 1 false false + + - false + true true bin\Release Portable\ PORTABLE 1591,660,661 - none + full x86 false MinimumRecommendedRules.ruleset @@ -1591,6 +1600,9 @@ powershell.exe -ExecutionPolicy Bypass -File "%25psScriptsDir%25\postbuild_mremo MinimumRecommendedRules.ruleset false + + LocalIntranet +