Compare commits

...

183 Commits

Author SHA1 Message Date
David Sparer
3ed8e768aa bumped patch version 2018-10-07 09:04:48 -05:00
David Sparer
d362691389 updated build scripts to include debug symbols and normalized github
asset names

cherrypicked from the develop branch
2018-10-07 07:53:31 -05:00
David Sparer
4b7c54d5b5 updated changelog 2018-10-07 07:28:57 -05:00
David Sparer
ec80a5aa70 fixed #1117 2018-09-30 13:19:35 -05:00
David Sparer
0c95f178ca updated changelog 2018-09-30 11:04:03 -05:00
David Sparer
e0405b15df fixes #1110 2018-09-30 11:02:01 -05:00
David Sparer
e029f30acf added a few try/catch blocks around some rdp code. related to #853 2018-09-30 10:44:22 -05:00
David Sparer
44ed836b7c fixed #1115 2018-09-29 12:14:44 -05:00
David Sparer
00401201d1 fixed Spanish translation issue. fixes #1112 2018-09-27 08:23:17 -05:00
David Sparer
20f46bea61 fixes #1106 2018-09-20 15:10:43 -05:00
Sean Kaim
a5d22d287c Fixed #1091 2018-08-28 14:59:07 -04:00
Sean Kaim
793095900b fix #1092
parse enums properly
2018-08-28 09:35:08 -04:00
David Sparer
f10e54e47b bumped assembly version to 1.76.8 2018-08-25 10:31:35 -05:00
David Sparer
704e0c1dc1 updated changelog 2018-08-25 10:29:43 -05:00
David Sparer
0c79a9acde fixes #1088 2018-08-24 14:43:08 -05:00
David Sparer
ebfc2715e7 updated changelog 2018-08-24 13:24:23 -05:00
David Sparer
b0dbc9dc18 only delete reg key value if the value exists 2018-08-24 13:23:52 -05:00
David Sparer
507cdf75a5 fixes #1087 2018-08-24 13:23:02 -05:00
David Sparer
8f8492b0be xml deserializer now gives connections an ID if the ID string in xml is empty
fixes #1082
2018-08-24 10:37:54 -05:00
David Sparer
457e715188 set assembly version to 1.76.7 and set release date in changelog 2018-08-22 10:59:45 -05:00
David Sparer
1724521ebf added some null guards to methods 2018-08-22 07:06:44 -05:00
David Sparer
b0fb3596aa added some safety checks around accessing putty registry settings 2018-08-22 07:06:16 -05:00
David Sparer
fb228d72b1 resolved bug #1076 2018-08-19 11:44:43 -05:00
David Sparer
916361a3be update changelog 2018-08-11 20:03:27 -05:00
David Sparer
408c40f699 fixed a few toolbar location loading edge cases
related to #1068
2018-08-11 10:02:07 -05:00
David Sparer
4173f6d775 swapped direct calls to Monitor with a lock statement and added a few method comments 2018-08-11 06:47:31 -05:00
Sean Kaim
e6f3c22064 code clean up / add'l checks
related to #1061
2018-08-03 10:13:31 -04:00
David Sparer
a013518eac bump assembly version 2018-08-03 08:51:44 -05:00
David Sparer
9c88cacb3d hopefully a fix for #1061 2018-08-03 08:33:51 -05:00
David Sparer
d49bf04b15 fixes #1062 2018-08-03 08:13:39 -05:00
David Sparer
1dbd5dc5bc set 1.76.5 release date in changelog 2018-08-02 18:15:33 -05:00
David Sparer
c103706a54 added test to verify #1057 2018-08-02 17:55:36 -05:00
David Sparer
b0a027df52 updated changelog 2018-08-02 17:49:50 -05:00
David Sparer
868641378a Merge pull request #1055 from mRemoteNG/647_save_symbols
647 save symbols
2018-08-02 16:34:04 -05:00
David Sparer
11baae3107 applying patch provided by Toomix in #1057 and merged in 7dbef77 2018-08-01 07:01:45 -05:00
David Sparer
ed8125042e make portable symbols zip file name easier to distinguish from regular symbols 2018-07-30 17:02:08 -05:00
David Sparer
25b2655d0f log which files are uploaded to github release 2018-07-30 16:55:09 -05:00
David Sparer
145a264154 handle wildcard in github asset upload file path 2018-07-30 16:45:55 -05:00
David Sparer
3e33170ae0 handle non-auto hidden notification panel focusing too 2018-07-30 15:23:59 -05:00
David Sparer
d18bf68f0e fix release tests 2018-07-30 14:12:17 -05:00
David Sparer
368917e108 accidentally left off the variable identifier for msbuild 2018-07-30 11:16:04 -05:00
David Sparer
cdea4c3911 missed a groovy var 2018-07-30 11:02:05 -05:00
David Sparer
b4b9b55bbf updated jenkins publish script to target msbuild15 2018-07-30 10:59:21 -05:00
David Sparer
6092c63df4 fix zipping symbols 2018-07-30 08:03:40 -05:00
David Sparer
fda5132184 zip symbols 2018-07-29 22:22:13 -05:00
Sean Kaim
6a9fb25a18 fixes #868
DialogResult is not currently checked, so it's a minimal/non-impact bug currently. But it's fixed now in case it's used in the future...
2018-07-29 21:30:11 -04:00
Sean Kaim
18d7344690 fixes #762
Increased button size by about 150%
2018-07-29 21:16:19 -04:00
Sean Kaim
ba50cf20a0 update changelog 2018-07-29 21:03:54 -04:00
Sean Kaim
7bd6e126e2 Fix #893
Disabled ClickOnce/Publish wihtin the project options.
2018-07-29 21:02:33 -04:00
Sean Kaim
f7521c81d5 Fixes #1052
and some code clean up
2018-07-29 19:03:21 -04:00
David Sparer
f483a2dc2f replaced Timer implementation with Task async call
fixes #1052
2018-07-29 12:02:41 -05:00
Sean Kaim
9769d5af06 changelog update 2018-07-28 22:31:26 -04:00
Sean Kaim
0a2dc3563e fixes #1040
clicking close would have the same effect. Check return code and don't open the connection unless user input has been provided.
2018-07-28 22:30:06 -04:00
Sean Kaim
e9f0157b2b code clean up 2018-07-28 22:15:11 -04:00
Sean Kaim
e8e566fcdd localization fixes 2018-07-28 22:10:17 -04:00
Sean Kaim
72b7d22cef localization fixes 2018-07-28 22:09:27 -04:00
Sean Kaim
f79da476fd options pages code clean up 2018-07-28 21:59:24 -04:00
Sean Kaim
ef31b7844c Merge pull request #1053 from mRemoteNG/cherry
Cherry picked commits for 1.76
2018-07-28 13:54:34 -04:00
Sean Kaim
f1ed1bf115 appveyor post build tests 2018-07-28 13:11:56 -04:00
Sean Kaim
23ea028965 don't run post build zip in appveyor 2018-07-28 13:11:10 -04:00
Sean Kaim
42046a614f Solution config was building wrong projects 2018-07-28 13:05:37 -04:00
Sean Kaim
36055f56e6 the post publish job in the appveyor.yaml in ps1 form 2018-07-28 13:05:28 -04:00
Sean Kaim
b693cb30fc Trim ConfigurationName 2018-07-28 13:03:27 -04:00
Sean Kaim
20377d4ff5 zip portable directly via powershell
Trying to fix appveyor artifact build
2018-07-28 13:03:16 -04:00
Sean Kaim
570d732b0e latest 7-zip 2018-07-28 13:03:00 -04:00
Sean Kaim
d9d2b1de70 code clean up (convert to expression body) 2018-07-28 13:02:36 -04:00
Sean Kaim
0a7eaaf36f minor code clean up 2018-07-28 13:02:25 -04:00
Sean Kaim
36dd3e496d minor code clean up 2018-07-28 13:02:14 -04:00
Sean Kaim
83fd914d7b code clean up 2018-07-28 13:01:41 -04:00
Sean Kaim
281c6b13fa minor code clean up
* No need to kick off the registry provider here (it's done already in PuttySessionsManager#StartWatcher())

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

IDK... I had a Uri.IsWellFormedUriString test in there to avoid the exception, but it seems unnecessary...
2018-07-28 13:01:06 -04:00
David Sparer
00b7b1221c fixes #1051 2018-07-28 09:03:57 -05:00
David Sparer
56cbf0ff3f fixes #1050 2018-07-28 07:52:57 -05:00
Sean Kaim
f852a4d341 minor code clean up 2018-07-27 17:02:51 -04:00
Sean Kaim
7c8c7d482a frmChoosePanel was not properly themed 2018-07-27 16:58:25 -04:00
Sean Kaim
9e95ae2cb0 code clean up 2018-07-27 16:45:38 -04:00
Sean Kaim
0d2d935f17 set default theme when themes disabled
Fixes #1039
Also some code clean up
2018-07-27 16:04:42 -04:00
Sean Kaim
eeb320a825 more clean up (use .ToString) 2018-07-27 14:50:44 -04:00
Sean Kaim
9452d4dbe3 Theme code clean up 2018-07-27 14:45:07 -04:00
Sean Kaim
03d2387cdd appveyor build for 1.76 branch 2018-07-27 14:44:35 -04:00
Sean Kaim
61b325ccb9 code clean up 2018-07-27 14:26:01 -04:00
Sean Kaim
e57de9a4de localized strings 2018-07-27 14:24:42 -04:00
Sean Kaim
96946f3a1e porting fix for #971 to 1.76 branch 2018-07-27 14:15:23 -04:00
David Sparer
8cd6fb7ae2 updated changelog 2018-07-26 13:40:53 -05:00
David Sparer
a5afa90790 fixes #1045 2018-07-26 13:39:12 -05:00
David Sparer
f634eb8d37 created tests for the config window to ensure property grid items correctly display for certain object types 2018-07-26 13:38:53 -05:00
David Sparer
694b61a67b added a property to expose the list of object properties being shown by the property grid
this will help a lot with testing the property grid/config window
2018-07-26 09:12:47 -05:00
David Sparer
88f0d00a15 minor style cleanup 2018-07-26 08:55:55 -05:00
David Sparer
e31088fd2e ensure that quick connect items always have a panel set, even if the con default Panel setting is empty
related to #802
2018-07-25 14:39:23 -05:00
David Sparer
1d7bb63710 ensure ConDefaultPanel has a default value
related to #802
2018-07-25 14:21:44 -05:00
David Sparer
af1ed5349f updated changelog 2018-07-25 08:08:35 -05:00
David Sparer
9dcf71dc31 new connection tree nodes will survive filtering until they exit edit mode
resolves #1038
2018-07-25 08:05:48 -05:00
David Sparer
8bf9af0ed8 updated changelog 2018-07-24 14:49:33 -05:00
David Sparer
aecfad5871 only access first array item if array has any items
resolves #1036
2018-07-24 14:49:01 -05:00
David Sparer
3edd155898 updated changelog 2018-07-24 12:55:27 -05:00
David Sparer
2c419c0b2e minor cleanup 2018-07-24 12:54:34 -05:00
David Sparer
2fb67e7042 fixed issue where the connection context menu wasn't using translated strings
The ctor for the context menu was being called before we loaded the desired culture, leading to the use of the English default strings. Resolves #1034
2018-07-24 12:54:20 -05:00
David Sparer
29483b2625 attached the file backup pruner to listen to connection file save events
resolves #1020
2018-07-23 12:53:03 -05:00
David Sparer
7fc59e79f3 bumped assembly version in preparation for next alpha release 2018-07-23 12:03:53 -05:00
David Sparer
79b3e21148 updated changelog 2018-07-23 12:02:09 -05:00
David Sparer
ee91117010 renamed function to be a bit more accurate 2018-07-23 11:54:49 -05:00
David Sparer
0548037ff3 added a few method summaries 2018-07-23 11:53:50 -05:00
David Sparer
46002632bb removed duplicate code 2018-07-23 11:52:38 -05:00
David Sparer
9659ac1611 added a dialog to prompt for action when decrypting a connection file fails 2018-07-23 11:51:58 -05:00
David Sparer
bbc497e68d added some quality of life methods to Optional 2018-07-23 08:03:03 -05:00
David Sparer
d7ec7574ad updated changelog 2018-07-20 14:54:42 -05:00
David Sparer
2f476d9e61 fix a null ref exception when importing from port scan without selecting a tree node. resolves #1030 2018-07-20 14:52:12 -05:00
David Sparer
c74f37f0de confirmer should return false if deletion target is null. found during regression testing 2018-07-20 12:31:59 -05:00
David Sparer
d27a62cbfc added some extra null checks in the rdcman importer 2018-07-20 07:26:38 -05:00
David Sparer
8029e491a3 Merge branch 'auto_save_during_sort' into release/v1.76 2018-07-18 14:53:26 -05:00
David Sparer
fe56268421 added a simple system to batch saves in the connection service 2018-07-18 14:53:02 -05:00
David Sparer
2db6fabbe9 reverted 3bdcf65 2018-07-18 14:52:12 -05:00
David Sparer
035e89801a reduce FrmMain minimum size to prevent issues with other system features. resolves #1024 2018-07-17 08:07:10 -05:00
David Sparer
3bdcf655fd suspend tree model events during sort, since this can produce a lot of changes 2018-06-25 15:15:46 -05:00
David Sparer
284755f298 fix tab ordering on port scan page 2018-06-23 09:03:25 -05:00
David Sparer
ad5eed96e7 fixed visual bug when filtering connection tree. resolves #993 2018-06-22 15:09:53 -05:00
David Sparer
431c830ea0 resize connection tree column width when calling expand all. related to #993 2018-06-22 13:56:22 -05:00
David Sparer
da047427a5 fix test 2018-06-21 20:33:32 -05:00
David Sparer
69da1dca5f added some tests of the connection tree duplicate function. related to #1004 2018-06-21 18:04:29 -05:00
David Sparer
cc61501f63 dont attempt to delete selected node if it is not a valid deletion target. resolves #1004 2018-06-21 17:35:42 -05:00
David Sparer
4ced2d3392 accidentally put a few changelog items under the wrong version 2018-06-21 16:51:41 -05:00
David Sparer
7c72bfdf6b connection tree now removes filtering when 'use filtering' option turned off. resolves #1002 2018-06-21 15:33:43 -05:00
David Sparer
b8878e1458 updated changelog 2018-06-21 08:35:29 -05:00
David Sparer
abd40cec1b removed duplicate disable/enable shortcut calls that was causing an issue. resolves #1001 2018-06-21 08:34:26 -05:00
David Sparer
cc18da4f28 updated changelog 2018-06-20 16:43:24 -05:00
David Sparer
1a39039162 reenable all hotkeys once file menu closes. Resolves #999 2018-06-20 16:42:58 -05:00
David Sparer
cf9dd72ea5 dont allow folder/connections to be added to the putty root node in connection tree. Resolves #998 2018-06-20 16:25:08 -05:00
David Sparer
b7cdf81665 ensure putty root node returns correct tree node type. Related to #998 2018-06-20 16:20:51 -05:00
David Sparer
8497a05fd1 resolves #991
fixed bug when deleting connection tree node when in filtered view
2018-06-13 14:34:05 -05:00
David Sparer
7db4eec45c fixed bug where the export screen was using new credential manager code that shouldn't be active yet 2018-06-03 10:45:29 -05:00
David Sparer
cd822b545a random stuff the ui designer regenerated 2018-06-03 10:45:06 -05:00
David Sparer
e872581d3c updated changelog 2018-06-03 09:50:42 -05:00
David Sparer
defe9e094c made opening an empty panel on startup configurable in options 2018-05-31 06:26:43 -05:00
David Sparer
5662735cb8 bumped assembly version for next pre-release 2018-05-25 18:01:32 -05:00
David Sparer
8646dce21b update jenkins build to use newest msbuild (enables c# 7 lang features) 2018-05-20 11:07:43 -05:00
David Sparer
99a3eabbaf updated changelog 2018-05-19 17:00:57 -05:00
David Sparer
c57bd386f2 dont try to connect to folders in quick connect menu. resolves #924 2018-05-19 16:57:34 -05:00
David Sparer
f2a52b03df menu bar can be moved when "lock toolbar position" is turned off. closes #902 2018-05-19 12:57:29 -05:00
David Sparer
860e1ccfaa fix a mismerged language item 2018-05-18 21:33:16 -05:00
David Sparer
49967b38d4 update changelog 2018-05-18 21:32:51 -05:00
David Sparer
36038fff6d fix minor code typo 2018-05-18 20:52:17 -05:00
David Sparer
c5958954b0 apply language later in app startup 2018-05-18 20:45:27 -05:00
David Sparer
d0d63016ca Merge branch 'pr_948_target' into release/v1.76
# Conflicts:
#	mRemoteV1/Resources/Language/Language.resx
#	mRemoteV1/UI/Forms/frmMain.Designer.cs
#	mRemoteV1/UI/Menu/ViewMenu.cs
2018-05-18 20:04:23 -05:00
David Sparer
35f2484adf Merge pull request #948 from farosch/translation
some changes regarding tranlsation
2018-05-18 18:41:06 -05:00
David Sparer
c2cf496ded updated changelog and credits 2018-04-29 12:00:08 -05:00
David Sparer
8a172f02a9 updated changelog and credits for #942 2018-04-19 08:08:44 -05:00
David Sparer
f27935ea61 Merge pull request #942 from sli-pro/develop
Made several strings translatable and added Russian translations
2018-04-19 07:58:16 -05:00
Faryan Rezagholi
043df0aec3 fixed wording 2018-04-14 11:56:01 +02:00
Faryan Rezagholi
63a2e18760 added missing items 2018-04-14 11:56:01 +02:00
Faryan Rezagholi
c3ced7ed03 fix: translations of main file menu items were not loaded 2018-04-14 11:56:01 +02:00
Faryan Rezagholi
f597e14b3d fix group box was not translatable 2018-04-14 11:56:01 +02:00
Faryan Rezagholi
aff4ba9115 fix: set labels dock mode to fill (wasnt displaying longer translated texts) 2018-04-14 11:56:01 +02:00
Faryan Rezagholi
554e0805e3 fix: title of options page was not translatable 2018-04-14 11:56:01 +02:00
Faryan Rezagholi
f4efa74a23 Added missing translation options in viewMenu.cs 2018-04-14 11:56:01 +02:00
Vladimir Semenov
ddc19587fa Edited and added a translation of the Russian language in the forms
- File/import
- File/Import from AD
- File/Export to File
- View/Lock Toolbar position
- View/Mylti SSH toolbar
- Tools/Options/Additionally
Related to question #940.
2018-04-10 13:41:34 +03:00
Vladimir Semenov
5f1232727e Edit and add a translation on the external tools form.
Added and corrected Russian and English translations in the external tools tab.
Adjusted the placement of components on the external tools form so that the text does not overlap during translation.
Related to question #940.
2018-04-10 09:58:59 +03:00
David Sparer
9c373e8f0a Merge pull request #938 from sli-pro/develop
Small visual correction of the forms
2018-04-07 11:25:55 -05:00
David Sparer
83942d788f Merge branch '916_default_properties_not_saving' into develop 2018-04-06 15:05:35 -05:00
David Sparer
73d6fec6f3 updated changelog 2018-04-06 15:05:00 -05:00
David Sparer
a37b5deaa1 finished updating some tests for default inheritance 2018-04-06 15:02:14 -05:00
Vladimir Semenov
3b9de847e7 Small visual correction of the forms
- for the main form set the minimum resolution 1140; 603.
- for the form of port scans, done visual editing of components.
2018-04-06 20:59:15 +03:00
David Sparer
924f1f1e48 improved tests for default connection info 2018-04-05 16:37:22 -05:00
David Sparer
7bdebbe25b Merge pull request #936 from sli-pro/develop
Update Language ru
2018-04-05 15:16:31 -05:00
David Sparer
8f46c25dc9 Merge pull request #935 from marcomsousa/develop
Update Language es
2018-04-05 15:15:04 -05:00
Vladimir Semenov
8bb4a03639 Update Language ru
Fix typos in Russian language
2018-04-05 18:51:47 +03:00
Marco Sousa
7b5bc5e057 Update Language es 2018-04-05 12:39:02 +02:00
David Sparer
35582a5e6a fixed bug with saving and loading default connection info data
updated tests to better cover this feature. related to #916
2018-03-22 16:54:50 -05:00
David Sparer
20340fd31f Merge pull request #913 from mRemoteNG/github-templates
Update .github templates
2018-03-22 07:44:10 -05:00
David Sparer
d6d7664b48 update readme shield 2018-03-14 19:30:25 -05:00
David Sparer
ce97e63876 bump version 2018-03-14 19:17:29 -05:00
David Sparer
378b98ff89 set release date 2018-03-14 19:09:02 -05:00
David Sparer
ce31199e57 updated changelog 2018-03-10 17:55:15 -06:00
David Sparer
227f3b2924 fix csv serialization bug where some empty fields would not be included
related to #911
2018-03-10 17:47:33 -06:00
David Sparer
5076f1354c fix bug where inheritance is incorrectly allowed on nodes under the root node after deserializing 2018-03-10 16:37:54 -06:00
Bennett Blodinger
e5a34388ae Update .github templates
Bumping up the quality of the templates with help from https://www.talater.com/open-source-templates
2018-03-09 09:46:03 -05:00
David Sparer
6a5f65c018 add a bit more documentation to the ps script that creates bulk connections 2018-03-09 08:08:29 -06:00
David Sparer
6d5f41b3d8 forgot to bump the stable branch when 1.75.7012 was released 2018-03-03 09:39:37 -06:00
David Sparer
64f10ead63 bump development channel download shield 2018-03-03 09:31:27 -06:00
David Sparer
575dae446f bump version and update changelog 2018-03-03 09:16:55 -06:00
David Sparer
9b438576f2 deserializing enums now ignores case. resolves #899 2018-02-27 09:48:09 -06:00
David Sparer
cbd32f1a07 added powershell script for creating bulk connections 2018-02-27 08:37:25 -06:00
David Sparer
516182ec40 the xml v2.6 schema must have the export field event if we dont use it. need to bump to v2.7 to get rid of it 2018-02-26 08:11:59 -06:00
David Sparer
4ad3a68d80 readded Export field to xml schema 2018-02-26 07:13:36 -06:00
David Sparer
2f9ba32c07 bump readme for development channel badge 2018-02-25 13:41:32 -06:00
157 changed files with 5067 additions and 2512 deletions

View File

@@ -1,16 +1,30 @@
<!--
Only file GitHub issues for bugs and feature requests. All other topics will be closed.
<!--- Provide a general summary of the issue in the Title above -->
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
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
<!-- Bug -->
|Detail|Value|
|--:|---|
|Operating system | Windows 10 x64 |
|mRemoteNG version| 1.75.7008 |
## Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
<!-- Feature Request -->
<!-- If you file a feature request, please delete the bug section -->
## Steps to Reproduce (for bugs)
<!--- Provide an unambiguous set of steps to reproduce -->
<!--- this bug. Include code to reproduce, if relevant -->
1.
2.
3.
4.
## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
## Your Environment
<!--- Include as many relevant details about the environment you experienced the bug in -->
* Version used:
* Operating System and version (e.g. Windows 10 1709 x64):

View File

@@ -1,4 +1,29 @@
<!--
Please provide as much detail as possible with what your pull request does.
Include a reference to a filed issue if it exists.
-->
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
## Screenshots (if appropriate):
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] 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:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] 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.

View File

@@ -1,3 +1,99 @@
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:

View File

@@ -23,6 +23,7 @@ github.com/DamianBis
github.com/pfjason
github.com/sirLoaf
github.com/Fyers
Vladimir Semenov (github.com/sli-pro)
Past Contributors
@@ -59,6 +60,8 @@ 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)
Included Source Code

8
Jenkinsfile vendored
View File

@@ -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)') {

View File

@@ -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"
}
}
}

View File

@@ -10,9 +10,9 @@
| Update Channel | Build Status | Downloads |
| ---------------|--------------|-----------|
| 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.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://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.76Alpha2/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76Alpha2) |
| 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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

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

View File

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

View File

@@ -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()

View File

@@ -171,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
}
}

View File

@@ -46,4 +46,5 @@ Format-Table -AutoSize -Wrap -InputObject @{
& "$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 -CertificatePath $CertificatePath
& "$PSScriptRoot\zip_symbols.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
& "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName

View File

@@ -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)

View File

@@ -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",

View File

@@ -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."

View File

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

56
Tools/zip_symbols.ps1 Normal file
View File

@@ -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 ""

View File

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

View File

@@ -19,20 +19,20 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Csv
public class CsvConnectionsDeserializerMremotengFormatTests
{
private CsvConnectionsDeserializerMremotengFormat _deserializer;
private ICredentialRepositoryList _credentialRepositoryList;
private CsvConnectionsSerializerMremotengFormat _serializer;
[SetUp]
public void Setup()
{
_deserializer = new CsvConnectionsDeserializerMremotengFormat();
_credentialRepositoryList = Substitute.For<ICredentialRepositoryList>();
var credentialRepositoryList = Substitute.For<ICredentialRepositoryList>();
_serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), credentialRepositoryList);
}
[TestCaseSource(typeof(DeserializationTestSource), nameof(DeserializationTestSource.ConnectionPropertyTestCases))]
public object ConnectionPropertiesDeserializedCorrectly(string propertyToCheck)
{
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
var csv = serializer.Serialize(GetTestConnection());
var csv = _serializer.Serialize(GetTestConnection());
var deserializedConnections = _deserializer.Deserialize(csv);
var connection = deserializedConnections.GetRecursiveChildList().FirstOrDefault();
var propertyValue = typeof(ConnectionInfo).GetProperty(propertyToCheck)?.GetValue(connection);
@@ -42,10 +42,10 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Csv
[TestCaseSource(typeof(DeserializationTestSource), nameof(DeserializationTestSource.InheritanceTestCases))]
public object InheritancePropertiesDeserializedCorrectly(string propertyToCheck)
{
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
var csv = serializer.Serialize(GetTestConnectionWithAllInherited());
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;
}
@@ -58,8 +58,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Csv
// | |- Con1
// |- Con2
var treeModel = new ConnectionTreeModelBuilder().Build();
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
var csv = serializer.Serialize(treeModel);
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");

View File

@@ -1,7 +1,6 @@
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;
@@ -19,7 +18,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
public void Setup(string confCons, string password)
{
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(password.ConvertToSecureString);
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(() => password.ConvertToSecureString());
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize(confCons);
}

View File

@@ -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;

View File

@@ -43,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()
{

View File

@@ -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<string>();
// 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<PropertyInfo> GetConnectionInfoProperties()
{
return new ConnectionInfo().GetSerializableProperties();
}
}
}

View File

@@ -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<PropertyInfo> GetInheritanceProperties()
{
return new ConnectionInfoInheritance(new object(), true).GetProperties();
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -1,4 +1,6 @@
using System.Linq;
using System;
using System.Linq;
using System.Xml.Linq;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection;
@@ -29,20 +31,19 @@ namespace mRemoteNGTests.IntegrationTests
_originalModel.RootNodes.OfType<RootNodeInfo>().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);
@@ -54,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);
@@ -66,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));
@@ -84,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()
{

View File

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

View File

@@ -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();
/// <summary>
/// Returns a <see cref="ConnectionInfo"/> object with randomized
/// values in all fields.
/// </summary>
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<RdpProtocol.RDPColors>(),
ICAEncryptionStrength = RandomEnum<IcaProtocol.EncryptionStrength> (),
Protocol = RandomEnum<ProtocolType>(),
RDGatewayUsageMethod = RandomEnum<RdpProtocol.RDGatewayUsageMethod>(),
RDGatewayUseConnectionCredentials = RandomEnum<RdpProtocol.RDGatewayUseConnectionCredentials>(),
RDPAuthenticationLevel = RandomEnum<RdpProtocol.AuthenticationLevel>(),
RedirectSound = RandomEnum<RdpProtocol.RDPSounds>(),
RenderingEngine = RandomEnum<HTTPBase.RenderingEngine>(),
Resolution = RandomEnum<RdpProtocol.RDPResolutions>(),
SoundQuality = RandomEnum<RdpProtocol.RDPSoundQuality>(),
VNCAuthMode = RandomEnum<ProtocolVNC.AuthMode>(),
VNCColors = RandomEnum<ProtocolVNC.Colors>(),
VNCCompression = RandomEnum<ProtocolVNC.Compression>(),
VNCEncoding = RandomEnum<ProtocolVNC.Encoding>(),
VNCProxyType = RandomEnum<ProtocolVNC.ProxyType>(),
VNCSmartSizeMode = RandomEnum<ProtocolVNC.SmartSizeMode>(),
};
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<T>() 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));
}
}
}

View File

@@ -0,0 +1,63 @@
namespace mRemoteNGTests.TestHelpers
{
/// <summary>
/// A ConnectionInfo that has only the serializable properties as string types.
/// Only used for testing.
/// </summary>
internal class SerializableConnectionInfoAllPropertiesOfType<TType>
{
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 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; }
}
}

View File

@@ -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 });

View File

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

View File

@@ -0,0 +1,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());
}
}
}

View File

@@ -0,0 +1,224 @@
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<string> 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<TestCaseData> ConnectionInfoGeneralTestCases()
{
var protocolTypes = typeof(ProtocolType).GetEnumValues().OfType<ProtocolType>();
var testCases = new List<TestCaseData>();
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<string> BuildExpectedConnectionInfoPropertyList(ProtocolType protocol, bool isContainer)
{
var expectedProperties = new List<string>
{
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.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;
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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<string> 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));
}
}
}

View File

@@ -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),
});
}
}
}

View File

@@ -146,6 +146,7 @@
<Compile Include="Connection\ConnectionInfoComparerTests.cs" />
<Compile Include="Connection\Protocol\IntegratedProgramTests.cs" />
<Compile Include="Connection\Protocol\ProtocolListTests.cs" />
<Compile Include="Container\RootNodeInfoTests.cs" />
<Compile Include="Credential\CompositeRepositoryUnlockerTests.cs" />
<Compile Include="Credential\CredentialChangedEventArgsTests.cs" />
<Compile Include="Credential\CredentialDeletionMsgBoxConfirmerTests.cs" />
@@ -169,9 +170,11 @@
<Compile Include="Security\PasswordCreation\PasswordLengthConstraintTests.cs" />
<Compile Include="Security\RandomGeneratorTests.cs" />
<Compile Include="Security\SecureStringExtensionsTests.cs" />
<Compile Include="TestHelpers\ConnectionInfoHelpers.cs" />
<Compile Include="TestHelpers\ConnectionTreeModelBuilder.cs" />
<Compile Include="Security\XmlCryptoProviderBuilderTests.cs" />
<Compile Include="TestHelpers\FileTestHelpers.cs" />
<Compile Include="TestHelpers\SerializableConnectionInfoAllPropertiesOfType.cs" />
<Compile Include="Tools\ExternalToolsArgumentParserTests.cs" />
<Compile Include="Tools\FullyObservableCollectionTests.cs" />
<Compile Include="Tools\OptionalTests.cs" />
@@ -204,6 +207,7 @@
<Compile Include="Tree\RootNodeInfoTests.cs" />
<Compile Include="Tree\ClickHandlers\SwitchToConnectionClickHandlerTests.cs" />
<Compile Include="Tree\SelectedConnectionDeletionConfirmerTests.cs" />
<Compile Include="UI\Controls\ConnectionTreeTests.cs" />
<Compile Include="UI\Controls\PageSequenceTests.cs" />
<Compile Include="UI\Controls\SecureTextBoxTestForm.cs">
<SubType>Form</SubType>
@@ -228,6 +232,10 @@
<Compile Include="UI\Forms\OptionsFormSetupAndTeardown.cs" />
<Compile Include="UI\Forms\PasswordFormTests.cs" />
<Compile Include="UI\WindowListTests.cs" />
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowGeneralTests.cs" />
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowRdpSpecialTests.cs" />
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowSpecialTestsBase.cs" />
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowVncSpecialTests.cs" />
<Compile Include="UI\Window\ConnectionTreeWindowTests.cs" />
</ItemGroup>
<ItemGroup>

View File

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

View File

@@ -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();

View File

@@ -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();

View File

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

View File

@@ -1,15 +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;
using mRemoteNG.Config.Serializers.Xml;
namespace mRemoteNG.Config.Connections
{
public class XmlConnectionsLoader
public class XmlConnectionsLoader
{
private readonly string _connectionFilePath;
@@ -32,7 +31,7 @@ namespace mRemoteNG.Config.Connections
return deserializer.Deserialize(xmlString);
}
private SecureString PromptForPassword()
private Optional<SecureString> PromptForPassword()
{
var password = MiscTools.PasswordDialog("", false);
return password;

View File

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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -48,7 +48,10 @@ namespace mRemoteNG.Config.Serializers.Csv
{
// 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

View File

@@ -16,7 +16,6 @@ namespace mRemoteNG.Config.Serializers.Csv
private readonly SaveFilter _saveFilter;
private readonly ICredentialRepositoryList _credentialRepositoryList;
public CsvConnectionsSerializerMremotengFormat(SaveFilter saveFilter, ICredentialRepositoryList credentialRepositoryList)
{
saveFilter.ThrowIfNull(nameof(saveFilter));
@@ -79,142 +78,134 @@ namespace mRemoteNG.Config.Serializers.Csv
private void SerializeConnectionInfo(ConnectionInfo con, StringBuilder sb)
{
sb.AppendLine();
sb.Append(string.Join(";",
CleanStringForCsv(con.Name),
CleanStringForCsv(con.ConstantID),
CleanStringForCsv(con.Parent?.ConstantID ?? ""),
CleanStringForCsv(con.GetTreeNodeType()),
CleanStringForCsv(con.Description),
CleanStringForCsv(con.Icon),
CleanStringForCsv(con.Panel)))
.Append(";");
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($"{CleanStringForCsv(con.Username)};");
sb.Append(FormatForCsv(con.Username));
if (_saveFilter.SavePassword)
sb.Append($"{CleanStringForCsv(con.Password)};");
sb.Append(FormatForCsv(con.Password));
if (_saveFilter.SaveDomain)
sb.Append($"{CleanStringForCsv(con.Domain)};");
sb.Append(FormatForCsv(con.Domain));
sb.Append(string.Join(";",
CleanStringForCsv(con.Hostname),
CleanStringForCsv(con.Protocol),
CleanStringForCsv(con.PuttySession),
CleanStringForCsv(con.Port),
CleanStringForCsv(con.UseConsoleSession),
CleanStringForCsv(con.UseCredSsp),
CleanStringForCsv(con.RenderingEngine),
CleanStringForCsv(con.ICAEncryptionStrength),
CleanStringForCsv(con.RDPAuthenticationLevel),
CleanStringForCsv(con.LoadBalanceInfo),
CleanStringForCsv(con.Colors),
CleanStringForCsv(con.Resolution),
CleanStringForCsv(con.AutomaticResize),
CleanStringForCsv(con.DisplayWallpaper),
CleanStringForCsv(con.DisplayThemes),
CleanStringForCsv(con.EnableFontSmoothing),
CleanStringForCsv(con.EnableDesktopComposition),
CleanStringForCsv(con.CacheBitmaps),
CleanStringForCsv(con.RedirectDiskDrives),
CleanStringForCsv(con.RedirectPorts),
CleanStringForCsv(con.RedirectPrinters),
CleanStringForCsv(con.RedirectSmartCards),
CleanStringForCsv(con.RedirectSound),
CleanStringForCsv(con.RedirectKeys),
CleanStringForCsv(con.PreExtApp),
CleanStringForCsv(con.PostExtApp),
CleanStringForCsv(con.MacAddress),
CleanStringForCsv(con.UserField),
CleanStringForCsv(con.ExtApp),
CleanStringForCsv(con.VNCCompression),
CleanStringForCsv(con.VNCEncoding),
CleanStringForCsv(con.VNCAuthMode),
CleanStringForCsv(con.VNCProxyType),
CleanStringForCsv(con.VNCProxyIP),
CleanStringForCsv(con.VNCProxyPort),
CleanStringForCsv(con.VNCProxyUsername),
CleanStringForCsv(con.VNCProxyPassword),
CleanStringForCsv(con.VNCColors),
CleanStringForCsv(con.VNCSmartSizeMode),
CleanStringForCsv(con.VNCViewOnly),
CleanStringForCsv(con.RDGatewayUsageMethod),
CleanStringForCsv(con.RDGatewayHostname),
CleanStringForCsv(con.RDGatewayUseConnectionCredentials),
CleanStringForCsv(con.RDGatewayUsername),
CleanStringForCsv(con.RDGatewayPassword),
CleanStringForCsv(con.RDGatewayDomain)))
.Append(";");
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.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(string.Join(";",
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,
con.Inheritance.RDPAlertIdleTimeout,
con.Inheritance.RDPMinutesToIdleTimeout,
con.Inheritance.SoundQuality));
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.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));
}
/// <summary>
/// Remove text that is unsafe for use in CSV files
/// </summary>
/// <param name="text"></param>
private string CleanStringForCsv(object text)
private string FormatForCsv(object value)
{
return text.ToString().Replace(";", "");
var cleanedString = value.ToString().Replace(";", "");
return cleanedString + ";";
}
}
}

View File

@@ -85,7 +85,7 @@ namespace mRemoteNG.Config.Serializers.Xml
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().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()));

View File

@@ -21,7 +21,7 @@ using mRemoteNG.UI.TaskDialog;
namespace mRemoteNG.Config.Serializers.Xml
{
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
{
private XmlDocument _xmlDocument;
private double _confVersion;
@@ -30,9 +30,9 @@ namespace mRemoteNG.Config.Serializers.Xml
private const double MaxSupportedConfVersion = 2.8;
private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection);
public Func<SecureString> AuthenticationRequestor { get; set; }
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
public XmlConnectionsDeserializer(Func<SecureString> authenticationRequestor = null)
public XmlConnectionsDeserializer(Func<Optional<SecureString>> authenticationRequestor = null)
{
AuthenticationRequestor = authenticationRequestor;
}
@@ -48,8 +48,6 @@ namespace mRemoteNG.Config.Serializers.Xml
{
LoadXmlConnectionData(xml);
ValidateConnectionFileVersion();
if (!import)
Runtime.ConnectionsService.IsConnectionsFileLoaded = false;
var rootXmlElement = _xmlDocument.DocumentElement;
InitializeRootNode(rootXmlElement);
@@ -63,8 +61,6 @@ namespace mRemoteNG.Config.Serializers.Xml
var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value;
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString()))
{
mRemoteNG.Settings.Default.LoadConsFromCustomLocation = false;
mRemoteNG.Settings.Default.CustomConsPath = "";
return null;
}
}
@@ -144,10 +140,10 @@ namespace mRemoteNG.Config.Serializers.Xml
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);
@@ -209,7 +205,9 @@ namespace mRemoteNG.Config.Serializers.Xml
{
if (xmlnode.Attributes == null) return null;
var connectionId = xmlnode.Attributes["Id"]?.Value ?? Guid.NewGuid().ToString();
var connectionId = xmlnode.Attributes["Id"]?.Value;
if (string.IsNullOrWhiteSpace(connectionId))
connectionId = Guid.NewGuid().ToString();
var connectionInfo = new ConnectionInfo(connectionId);
try
@@ -301,7 +299,9 @@ namespace mRemoteNG.Config.Serializers.Xml
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);
}
@@ -317,9 +317,9 @@ namespace mRemoteNG.Config.Serializers.Xml
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
{
@@ -395,7 +395,7 @@ namespace mRemoteNG.Config.Serializers.Xml
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;
@@ -405,16 +405,16 @@ namespace mRemoteNG.Config.Serializers.Xml
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);
@@ -431,13 +431,13 @@ namespace mRemoteNG.Config.Serializers.Xml
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);
@@ -458,9 +458,9 @@ namespace mRemoteNG.Config.Serializers.Xml
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;
@@ -501,7 +501,7 @@ namespace mRemoteNG.Config.Serializers.Xml
if (_confVersion >= 2.6)
{
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");

View File

@@ -4,7 +4,7 @@ using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Serializers.Xml
{
public class XmlRootNodeSerializer
public class XmlRootNodeSerializer
{
public XElement SerializeRootNodeInfo(RootNodeInfo rootNodeInfo, ICryptographyProvider cryptographyProvider, bool fullFileEncryption = false)
{
@@ -12,7 +12,8 @@ namespace mRemoteNG.Config.Serializers.Xml
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().ToLowerInvariant()));

View File

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

View File

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

View File

@@ -1,4 +1,6 @@
using System.Configuration;
#if !PORTABLE
using System.Configuration;
#endif
namespace mRemoteNG.Config.Settings.Providers
{

View File

@@ -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));

View File

@@ -19,6 +19,7 @@ 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;
@@ -31,7 +32,8 @@ namespace mRemoteNG.Config.Settings
MessageCollector messageCollector,
QuickConnectToolStrip quickConnectToolStrip,
ExternalToolsToolStrip externalToolsToolStrip,
MultiSshToolStrip multiSshToolStrip)
MultiSshToolStrip multiSshToolStrip,
MenuStrip mainMenu)
{
if (mainForm == null)
throw new ArgumentNullException(nameof(mainForm));
@@ -43,13 +45,16 @@ namespace mRemoteNG.Config.Settings
throw new ArgumentNullException(nameof(externalToolsToolStrip));
if (multiSshToolStrip == null)
throw new ArgumentNullException(nameof(multiSshToolStrip));
if (mainMenu == null)
throw new ArgumentNullException(nameof(mainMenu));
MainForm = mainForm;
_messageCollector = messageCollector;
_quickConnectToolStrip = quickConnectToolStrip;
_externalToolsToolStrip = externalToolsToolStrip;
_multiSshToolStrip = multiSshToolStrip;
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip);
_mainMenu = mainMenu;
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip);
}
#region Public Methods
@@ -197,6 +202,7 @@ namespace mRemoteNG.Config.Settings
private void LoadToolbarsFromSettings()
{
ResetAllToolbarLocations();
AddMainMenuPanel();
AddExternalAppsPanel();
AddQuickConnectPanel();
AddMultiSshPanel();
@@ -210,31 +216,49 @@ namespace mRemoteNG.Config.Settings
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()
{
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock);
toolStripPanel.Join(_multiSshToolStrip, mRemoteNG.Settings.Default.MultiSshToolbarLocation);
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)
{

View File

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

View File

@@ -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;
@@ -15,12 +10,16 @@ using mRemoteNG.Connection.Protocol.Telnet;
using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Container;
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
@@ -79,7 +78,8 @@ namespace mRemoteNG.Connection
var newConnectionInfo = new ConnectionInfo();
newConnectionInfo.CopyFrom(this);
newConnectionInfo.Inheritance = Inheritance.Clone();
return newConnectionInfo;
newConnectionInfo.Inheritance.Parent = newConnectionInfo;
return newConnectionInfo;
}
public void CopyFrom(ConnectionInfo sourceConnectionInfo)
@@ -127,19 +127,22 @@ namespace mRemoteNG.Connection
return filteredProperties;
}
public virtual IEnumerable<PropertyInfo> 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);
}
@@ -170,10 +173,11 @@ namespace mRemoteNG.Connection
if (!ShouldThisPropertyBeInherited(propertyName))
return value;
var inheritedValue = GetInheritedPropertyValue<TPropertyType>(propertyName);
if (inheritedValue.Equals(default(TPropertyType)))
return value;
return inheritedValue;
var couldGetInheritedValue = TryGetInheritedPropertyValue<TPropertyType>(propertyName, out var inheritedValue);
return couldGetInheritedValue
? inheritedValue
: value;
}
private bool ShouldThisPropertyBeInherited(string propertyName)
@@ -194,22 +198,23 @@ namespace mRemoteNG.Connection
return inheritPropertyValue;
}
private TPropertyType GetInheritedPropertyValue<TPropertyType>(string propertyName)
private bool TryGetInheritedPropertyValue<TPropertyType>(string propertyName, out TPropertyType inheritedValue)
{
try
{
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);
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);
return default(TPropertyType);
inheritedValue = default(TPropertyType);
return false;
}
}

View File

@@ -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
{

View File

@@ -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
/// <param name="useDatabase"></param>
/// <param name="import"></param>
/// <param name="connectionFileName"></param>
public ConnectionTreeModel LoadConnections(bool useDatabase, bool import, string connectionFileName)
public void LoadConnections(bool useDatabase, bool import, string connectionFileName)
{
var oldConnectionTreeModel = ConnectionTreeModel;
var oldIsUsingDatabaseValue = UsingDatabase;
var newConnectionTreeModel =
(useDatabase
? 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;
}
/// <summary>
/// When turned on, calls to <see cref="SaveConnections()"/> or
/// <see cref="SaveConnectionsAsync"/> will not immediately execute.
/// Instead, they will be deferred until <see cref="EndBatchingSaves"/>
/// is called.
/// </summary>
public void BeginBatchingSaves()
{
_batchingSaves = true;
}
/// <summary>
/// Immediately executes a single <see cref="SaveConnections()"/> or
/// <see cref="SaveConnectionsAsync"/> if one has been requested
/// since calling <see cref="BeginBatchingSaves"/>.
/// </summary>
public void EndBatchingSaves()
{
_batchingSaves = false;
if (_saveAsyncRequested)
SaveConnectionsAsync();
else if(_saveRequested)
SaveConnections();
}
/// <summary>
@@ -128,8 +163,6 @@ namespace mRemoteNG.Connection
/// </summary>
public void SaveConnections()
{
if (!IsConnectionsFileLoaded)
return;
SaveConnections(ConnectionTreeModel, UsingDatabase, new SaveFilter(), ConnectionFileName);
}
@@ -141,12 +174,24 @@ namespace mRemoteNG.Connection
/// <param name="useDatabase"></param>
/// <param name="saveFilter"></param>
/// <param name="connectionFileName"></param>
public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName)
/// <param name="forceSave">Bypasses safety checks that prevent saving if a connection file isn't loaded.</param>
public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName, bool forceSave = false)
{
if (connectionTreeModel == null) return;
if (connectionTreeModel == null)
return;
if (!forceSave && !IsConnectionsFileLoaded)
return;
if (_batchingSaves)
{
_saveRequested = true;
return;
}
try
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Saving connections...");
RemoteConnectionsSyncronizer?.Disable();
var previouslyUsingDatabase = UsingDatabase;
@@ -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)

View File

@@ -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>(TSource sourceInstance, Func<string, string> 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>(TDestination destinationInstance, Func<string, string> 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)
{

View File

@@ -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()
@@ -916,17 +925,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
}

View File

@@ -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);

View File

@@ -63,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);
@@ -81,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;

View File

@@ -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;
}
}
}

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
@@ -17,6 +17,10 @@
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
<applicationRequestMinimum>
<PermissionSet Unrestricted="true" ID="Custom" SameSite="site" />
<defaultAssemblyRequest permissionSetReference="Custom" />
</applicationRequestMinimum>
</security>
</trustInfo>
</asmv1:assembly>
</asmv1:assembly>

View File

@@ -60,6 +60,24 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to An error occurred while trying to reconnect to RDP host &apos;{0}&apos;.
/// </summary>
internal static string AutomaticReconnectError {
get {
return ResourceManager.GetString("AutomaticReconnectError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An error occurred while trying to change the connection resolution to host &apos;{0}&apos;.
/// </summary>
internal static string ChangeConnectionResolutionError {
get {
return ResourceManager.GetString("ChangeConnectionResolutionError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Create a New Connection File.
/// </summary>
@@ -222,6 +240,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Working directory:.
/// </summary>
internal static string srtWorkingDirectory {
get {
return ResourceManager.GetString("srtWorkingDirectory", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to About.
/// </summary>
@@ -312,6 +339,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to AdvancedSecurityOptions.
/// </summary>
internal static string strAdvancedSecurityOptions {
get {
return ResourceManager.GetString("strAdvancedSecurityOptions", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Allow only a single instance of the application (mRemoteNG restart required).
/// </summary>
@@ -439,7 +475,7 @@ namespace mRemoteNG {
}
/// <summary>
/// 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):.
/// </summary>
internal static string strAutoSaveEvery {
get {
@@ -1628,6 +1664,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Create an empty panel when mRemoteNG starts.
/// </summary>
internal static string strCreateEmptyPanelOnStartUp {
get {
return ResourceManager.GetString("strCreateEmptyPanelOnStartUp", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Credential Editor.
/// </summary>
@@ -1684,6 +1729,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Delete....
/// </summary>
internal static string strDelete {
get {
return ResourceManager.GetString("strDelete", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Detect.
/// </summary>
@@ -2544,7 +2598,7 @@ namespace mRemoteNG {
}
/// <summary>
/// Looks up a localized string similar to An error occurred while importing the file, &quot;{0}&quot;..
/// Looks up a localized string similar to An error occurred while importing the file &quot;{0}&quot;..
/// </summary>
internal static string strImportFileFailedContent {
get {
@@ -2633,6 +2687,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Import sub OUs.
/// </summary>
internal static string strImportSubOUs {
get {
return ResourceManager.GetString("strImportSubOUs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Inactive.
/// </summary>
@@ -2741,6 +2804,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Must Be Between 0 and 255.
/// </summary>
internal static string strIPRange {
get {
return ResourceManager.GetString("strIPRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to CTRL-ALT-DEL.
/// </summary>
@@ -3011,6 +3083,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Use UTF8 encoding for RDP &quot;Load Balance Info&quot; property.
/// </summary>
internal static string strLoadBalanceInfoUseUtf8 {
get {
return ResourceManager.GetString("strLoadBalanceInfoUseUtf8", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Load from SQL failed.
/// </summary>
@@ -3056,6 +3137,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Lock toolbar positions.
/// </summary>
internal static string strLockToolbars {
get {
return ResourceManager.GetString("strLockToolbars", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Log file path.
/// </summary>
@@ -3416,6 +3506,24 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Lock Toolbar Positions.
/// </summary>
internal static string strMenuLockToolbars {
get {
return ResourceManager.GetString("strMenuLockToolbars", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Multi SSH Toolbar.
/// </summary>
internal static string strMenuMultiSshToolbar {
get {
return ResourceManager.GetString("strMenuMultiSshToolbar", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to New Connection File.
/// </summary>
@@ -3812,6 +3920,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Multi SSH toolbar.
/// </summary>
internal static string strMultiSshToolbar {
get {
return ResourceManager.GetString("strMultiSshToolbar", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to My current credentials (Windows logon information).
/// </summary>
@@ -4110,6 +4227,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to mRemoteNG Options.
/// </summary>
internal static string strOptionsPageTitle {
get {
return ResourceManager.GetString("strOptionsPageTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Testing....
/// </summary>
@@ -4174,7 +4300,7 @@ namespace mRemoteNG {
}
/// <summary>
/// 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 &apos;themes&apos; folder.
/// </summary>
internal static string strOptionsThemeErrorNoThemes {
get {
@@ -4218,6 +4344,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Out Of Range.
/// </summary>
internal static string strOutOfRange {
get {
return ResourceManager.GetString("strOutOfRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Panel Name.
/// </summary>
@@ -6147,6 +6282,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Reconnect All Connections.
/// </summary>
internal static string strReconnectAllConnections {
get {
return ResourceManager.GetString("strReconnectAllConnections", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reconnect to previously opened sessions on startup.
/// </summary>
@@ -6210,6 +6354,24 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Run elevated.
/// </summary>
internal static string strRunElevated {
get {
return ResourceManager.GetString("strRunElevated", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Run elevate.
/// </summary>
internal static string strRunElevateHeader {
get {
return ResourceManager.GetString("strRunElevateHeader", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Save.
/// </summary>
@@ -6381,6 +6543,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Show on toolbar column.
/// </summary>
internal static string strShowOnToolbarColumnHeader {
get {
return ResourceManager.GetString("strShowOnToolbarColumnHeader", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Show protocols on tab names.
/// </summary>
@@ -7011,6 +7182,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Timeout (seconds).
/// </summary>
internal static string strTimeoutInSeconds {
get {
return ResourceManager.GetString("strTimeoutInSeconds", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Title.
/// </summary>
@@ -7101,6 +7281,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Try to integrate.
/// </summary>
internal static string strTryToIntegrateColumnHeader {
get {
return ResourceManager.GetString("strTryToIntegrateColumnHeader", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type.
/// </summary>
@@ -7128,6 +7317,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to UltraVNC SingleClick.
/// </summary>
internal static string strUltraVNCSingleClick {
get {
return ResourceManager.GetString("strUltraVNCSingleClick", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Uncheck the properties you want not to be saved!.
/// </summary>
@@ -7471,6 +7669,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Working directory.
/// </summary>
internal static string strWorkingDirColumnHeader {
get {
return ResourceManager.GetString("strWorkingDirColumnHeader", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to XULrunner path:.
/// </summary>
@@ -7507,15 +7714,6 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Timeout (seconds).
/// </summary>
internal static string TimeoutInSeconds {
get {
return ResourceManager.GetString("TimeoutInSeconds", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unlock.
/// </summary>

View File

@@ -151,10 +151,10 @@
<value>Panel Auswahldialog immer anzeigen</value>
</data>
<data name="strAlwaysShowPanelTabs" xml:space="preserve">
<value>Palettenregister immer anzeigen</value>
<value>Panel immer anzeigen</value>
</data>
<data name="strAlwaysShowSysTrayIcon" xml:space="preserve">
<value>System Tray Icon immer anzeigen</value>
<value>Tray Icon immer anzeigen</value>
</data>
<data name="strAskUpdatesCommandAskLater" xml:space="preserve">
<value>Später nochmal fragen</value>
@@ -178,7 +178,7 @@
<value>Automatisch Sitzungsinformationen einholen</value>
</data>
<data name="strAutoSaveEvery" xml:space="preserve">
<value>Automatisch speichern jede:</value>
<value>Automatisch speichern in Minuten (0 bedeutet deaktiviert):</value>
</data>
<data name="strAutoSaveMins" xml:space="preserve">
<value>Minuten (0 bedeutet deaktiviert)</value>
@@ -424,7 +424,7 @@ VncSharp Control Version {0}</value>
<value>Kompatibilitätsproblem entdeckt</value>
</data>
<data name="strComponentsCheck" xml:space="preserve">
<value>Komponentenüberprüfung</value>
<value>Komponenten prüfen</value>
</data>
<data name="strConfigPropertyGridButtonIconClickFailed" xml:space="preserve">
<value>Bild Knopf Ereignis fehlgeschlagen!</value>
@@ -748,7 +748,7 @@ Starte mit neuer Datei.</value>
<value>Quick connect Registerkarten identifizieren, indem das Präfix "Quick:" benutzt wird</value>
</data>
<data name="strImportAD" xml:space="preserve">
<value>Aus Active Directory importieren</value>
<value>Von Active Directory importieren</value>
</data>
<data name="strImportExport" xml:space="preserve">
<value>Importieren/Exportieren</value>
@@ -817,7 +817,7 @@ Starte mit neuer Datei.</value>
<value>Beim Schließen der Verbindungen:</value>
</data>
<data name="strLabelConnect" xml:space="preserve">
<value>&amp;Direkt Verbinden:</value>
<value>&amp;Verbinden:</value>
</data>
<data name="strLabelDisplayName" xml:space="preserve">
<value>Anzeigename</value>
@@ -931,7 +931,7 @@ Starte mit neuer Datei.</value>
<value>Verbindungen</value>
</data>
<data name="strMenuConnectionsAndConfig" xml:space="preserve">
<value>Verbindungen and Konfiguration</value>
<value>Verbindungen und Konfiguration</value>
</data>
<data name="strMenuCopy" xml:space="preserve">
<value>Kopieren</value>
@@ -994,7 +994,7 @@ Starte mit neuer Datei.</value>
<value>&amp;Hilfe</value>
</data>
<data name="strMenuHelpContents" xml:space="preserve">
<value>mRemoteNG Hilfe</value>
<value>Hilfe</value>
</data>
<data name="strMenuJumpTo" xml:space="preserve">
<value>Springe zu</value>
@@ -1003,10 +1003,7 @@ Starte mit neuer Datei.</value>
<value>Starten</value>
</data>
<data name="strMenuNewConnectionFile" xml:space="preserve">
<value>Neue Konfigurationsdatei</value>
</data>
<data name="strMenuNewExternalTool" xml:space="preserve">
<value>Hinzufügen</value>
<value>Neue Verbindungsdatei</value>
</data>
<data name="strMenuNotifications" xml:space="preserve">
<value>Meldungen</value>
@@ -1021,7 +1018,7 @@ Starte mit neuer Datei.</value>
<value>Alle Löschen</value>
</data>
<data name="strMenuOpenConnectionFile" xml:space="preserve">
<value>Konfigurationsdatei öffnen...</value>
<value>Verbindungsdatei öffnen...</value>
</data>
<data name="strMenuOptions" xml:space="preserve">
<value>Optionen</value>
@@ -1033,7 +1030,7 @@ Starte mit neuer Datei.</value>
<value>Port-Scan</value>
</data>
<data name="strMenuQuickConnectToolbar" xml:space="preserve">
<value>Direkt-Verbinden-Symbolleiste</value>
<value>QuickConnect Symbolleiste</value>
</data>
<data name="strMenuReconnect" xml:space="preserve">
<value>Wiederverbinden</value>
@@ -1060,10 +1057,10 @@ Starte mit neuer Datei.</value>
<value>Layout zurücksetzen</value>
</data>
<data name="strMenuSaveConnectionFile" xml:space="preserve">
<value>Konfigurationsdatei speichern</value>
<value>Verbindungsdatei speichern</value>
</data>
<data name="strMenuSaveConnectionFileAs" xml:space="preserve">
<value>Konfigurationsdatei speichern unter...</value>
<value>Verbindungsdatei speichern unter...</value>
</data>
<data name="strMenuScreenshot" xml:space="preserve">
<value>Bildschirmschnappschuss</value>
@@ -1096,7 +1093,7 @@ Starte mit neuer Datei.</value>
<value>Chat starten (VNC)</value>
</data>
<data name="strMenuSupportForum" xml:space="preserve">
<value>Unterstützungs Forum</value>
<value>Forum</value>
</data>
<data name="strMenuTools" xml:space="preserve">
<value>E&amp;xtras</value>
@@ -1566,9 +1563,6 @@ Wenn Sie Fehler feststellen, dann sollten Sie eine neue Verbindungsdatei erstell
<data name="strQuick" xml:space="preserve">
<value>Direkt: {0}</value>
</data>
<data name="strQuickConnect" xml:space="preserve">
<value>Direkt verbinden</value>
</data>
<data name="strQuickConnectAddFailed" xml:space="preserve">
<value>Hinzufügen zur Direktverbindungshistorie fehlgeschlagen!</value>
</data>
@@ -1828,7 +1822,7 @@ Wenn Sie Fehler feststellen, dann sollten Sie eine neue Verbindungsdatei erstell
<value>Anmeldeinformationen im Tab Titel anzeigen</value>
</data>
<data name="strShowProtocolOnTabs" xml:space="preserve">
<value>Protokoll im Tab Titel anzeigen</value>
<value>Protokoll im Titel des Tab anzeigen</value>
</data>
<data name="strSingleClickOnConnectionOpensIt" xml:space="preserve">
<value>Ein einzelner Klick auf eine Verbindung öffnet diese</value>
@@ -2085,9 +2079,6 @@ Wenn Sie Fehler feststellen, dann sollten Sie eine neue Verbindungsdatei erstell
<data name="strUpdateCheckPortableEdition" xml:space="preserve">
<value>mRemoteNG Portable Edition unterstützt derzeit keine automatische Updates.</value>
</data>
<data name="strUpdateDeleteFailed" xml:space="preserve">
<value>Löschen der Aktualisierungsdatei ist gehlgeschlagen!</value>
</data>
<data name="strUpdateDownloadComplete" xml:space="preserve">
<value>Download fertiggestellt!
mRemoteNG wird nun geschlossen und die Installation gestartet.</value>
@@ -2180,6 +2171,402 @@ mRemoteNG wird nun geschlossen und die Installation gestartet.</value>
<value>Ja</value>
</data>
<data name="strMenuReconnectAll" xml:space="preserve">
<value>Wiederverbinden von allen offenen Verbindungen</value>
<value>Wiederverbinden aller offener Verbindungen</value>
</data>
</root>
<data name="strButtonLaunch" xml:space="preserve">
<value>&amp;Starten</value>
</data>
<data name="strCommandOpenConnectionFile" xml:space="preserve">
<value>Eine Verbindungsdatei öffnen</value>
</data>
<data name="strConnectNoCredentials" xml:space="preserve">
<value>Ohne Anmeldedaten verbinden</value>
</data>
<data name="strDontConnectToConsoleSessionMenuItem" xml:space="preserve">
<value>Nicht zu Konsolensitzung verbinden</value>
</data>
<data name="strErrorCouldNotLaunchPutty" xml:space="preserve">
<value>PuTTY konnte nicht gestartet werden</value>
</data>
<data name="strExportEverything" xml:space="preserve">
<value>Export alles</value>
</data>
<data name="strExportFile" xml:space="preserve">
<value>Export Datei</value>
</data>
<data name="strExportProperties" xml:space="preserve">
<value>Export Eigeschaften</value>
</data>
<data name="strFilterAllImportable" xml:space="preserve">
<value>Alle importierbaren Dateien</value>
</data>
<data name="strImportFileFailedMainInstruction" xml:space="preserve">
<value>Import fehlgeschlagen</value>
</data>
<data name="strImportFromFileMenuItem" xml:space="preserve">
<value>Von &amp;Datei importieren</value>
</data>
<data name="strImportLocationContent" xml:space="preserve">
<value>Wo sollen die importierten Objekte platziert werden?</value>
</data>
<data name="strImportLocationMainInstruction" xml:space="preserve">
<value>Import Ziel</value>
</data>
<data name="strOptionsKeyboardButtonDelete" xml:space="preserve">
<value>&amp;Löschen</value>
</data>
<data name="strOptionsKeyboardButtonNew" xml:space="preserve">
<value>&amp;Neu</value>
</data>
<data name="strOptionsKeyboardButtonReset" xml:space="preserve">
<value>&amp;Neu</value>
</data>
<data name="strOptionsKeyboardCommandsNextTab" xml:space="preserve">
<value>Nächster Tab</value>
</data>
<data name="strOptionsKeyboardGroupModifyShortcut" xml:space="preserve">
<value>Vorheriger Tab</value>
</data>
<data name="strOptionsProxyTesting" xml:space="preserve">
<value>Teste...</value>
</data>
<data name="strOptionsTabKeyboard" xml:space="preserve">
<value>Tastatur</value>
</data>
<data name="strUpdateCheckFailedLabel" xml:space="preserve">
<value>Überprüfung fehlgeschlagen</value>
</data>
<data name="strUpdateCheckingLabel" xml:space="preserve">
<value>Prüfe auf Updates...</value>
</data>
<data name="strEncryptionEngine" xml:space="preserve">
<value>Verschlüsselungs-Engine</value>
</data>
<data name="strTabSecurity" xml:space="preserve">
<value>Sicherheit</value>
</data>
<data name="strRDPSoundQualityDynamic" xml:space="preserve">
<value>Dynamisch</value>
</data>
<data name="strRDPSoundQualityHigh" xml:space="preserve">
<value>Hoch</value>
</data>
<data name="strRDPSoundQualityMedium" xml:space="preserve">
<value>Mittel</value>
</data>
<data name="strPropertyNameSoundQuality" xml:space="preserve">
<value>Ton Qualität</value>
</data>
<data name="strUpdatePortableDownloadComplete" xml:space="preserve">
<value>Download abgeschlossen!</value>
</data>
<data name="strRemove" xml:space="preserve">
<value>Entfernen</value>
</data>
<data name="strTitle" xml:space="preserve">
<value>Titel</value>
</data>
<data name="strOpenFile" xml:space="preserve">
<value>Datei öffnen</value>
</data>
<data name="strHttpsInsecureAllowAlways" xml:space="preserve">
<value>Immer erlauben</value>
</data>
<data name="strHttpsInsecureAllowOnce" xml:space="preserve">
<value>Ein Mal erlauben</value>
</data>
<data name="strHttpsInsecureDontAllow" xml:space="preserve">
<value>Nie erlauben</value>
</data>
<data name="IncorrectPassword" xml:space="preserve">
<value>Falsches Passwort</value>
</data>
<data name="Source" xml:space="preserve">
<value>Qualle</value>
</data>
<data name="strBack" xml:space="preserve">
<value>Zurück</value>
</data>
<data name="strCreateAndOpenNewFile" xml:space="preserve">
<value>Erstelle und öffne neue Datei</value>
</data>
<data name="strOpenADifferentFile" xml:space="preserve">
<value>Andere Datei öffnen</value>
</data>
<data name="strCredentialManagerUpgradeDescription" xml:space="preserve">
<value>In v1.76 haben wir ein Berechtigungsverwaltungssystem eingeführt. Diese Funktion erfordert eine erhebliche Änderung bei der Speicherung und Interaktion mit Anmeldeinformationen in mRemoteNG. Sie müssen eine Aktualisierung Ihrer mRemoteNG-Verbindungsdatei durchführen.
Diese Seite führt Sie durch den Prozess der Aktualisierung Ihrer Verbindungsdatei oder gibt Ihnen die Möglichkeit, eine andere Verbindungsdatei zu öffnen, wenn Sie das Upgrade nicht durchführen möchten.</value>
</data>
<data name="ConfigurationCreateNew" xml:space="preserve">
<value>Neue Verbindungsdatei erstellen</value>
</data>
<data name="strCommandExitProgram" xml:space="preserve">
<value>B&amp;eende {0}</value>
</data>
<data name="strCommandTryAgain" xml:space="preserve">
<value>&amp;Nochmal versuchen</value>
</data>
<data name="strExternalToolDefaultName" xml:space="preserve">
<value>Neues externes Programm</value>
</data>
<data name="strLoadFromSqlFailedContent" xml:space="preserve">
<value>Die Verbindungsinformationen konnten nicht vom SQL-Server geladen werden.</value>
</data>
<data name="strOptionsKeyboardCommandsPreviousTab" xml:space="preserve">
<value>Vorheriger Tab</value>
</data>
<data name="strOptionsKeyboardLabelKeyboardShortcuts" xml:space="preserve">
<value>Tataturkürzel</value>
</data>
<data name="strPasswordStatusMustMatch" xml:space="preserve">
<value>Beide Passwörter müssen übereinstimmen</value>
</data>
<data name="strPasswordStatusTooShort" xml:space="preserve">
<value>Das Passwort muss mindestens 3 Zeichen lang sein.</value>
</data>
<data name="strPortScanComplete" xml:space="preserve">
<value>Port-Scan abgeschlossen.</value>
</data>
<data name="strPropertyDescriptionAutomaticResize" xml:space="preserve">
<value>Wählen Sie aus, ob die Größe der Verbindung automatisch angepasst werden soll, wenn die Fenstergröße geändert oder der Vollbildmodus umgeschaltet wird. Benötigt RDC 8.0 oder höher.</value>
</data>
<data name="strPropertyDescriptionLoadBalanceInfo" xml:space="preserve">
<value>Gibt die Lastausgleichsinformationen an, die von Lastenausgleichsroutern verwendet werden, um den besten Server auszuwählen.</value>
</data>
<data name="strPropertyNameLoadBalanceInfo" xml:space="preserve">
<value>Lastausgleichsinfo</value>
</data>
<data name="strTitlePasswordWithName" xml:space="preserve">
<value>Passwort für {0}</value>
</data>
<data name="strRDPOverallConnectionTimeout" xml:space="preserve">
<value>RDP-Verbindungs-Timeout:</value>
</data>
<data name="strNodeAlreadyInFolder" xml:space="preserve">
<value>Dieser Knoten ist bereits im Verzeichnis</value>
</data>
<data name="strNodeCannotDragOnSelf" xml:space="preserve">
<value>Knoten kann nicht auf sich selbst gezogen werden.</value>
</data>
<data name="strNodeCannotDragParentOnChild" xml:space="preserve">
<value>Elternknoten kann nicht auf Kindknoten gezogen werden.</value>
</data>
<data name="strNodeNotDraggable" xml:space="preserve">
<value>Dieser Knoten ist nicht ziehbar.</value>
</data>
<data name="strEncryptionBlockCipherMode" xml:space="preserve">
<value>Block Cipher-Modus</value>
</data>
<data name="strShowTheseMessageTypes" xml:space="preserve">
<value>Zeige diese Nachrichtentypen</value>
</data>
<data name="ConnectionFileNotFound" xml:space="preserve">
<value>Die Verbindungsdatei konnte nicht gefunden werden.</value>
</data>
<data name="ConfigurationImportFile" xml:space="preserve">
<value>Existierende Datei importieren</value>
</data>
<data name="ConnectionSuccessful" xml:space="preserve">
<value>Verbindung erfolgreich</value>
</data>
<data name="DatabaseNotAvailable" xml:space="preserve">
<value>Datenbank '{0}' nicht verfügbar.</value>
</data>
<data name="SaveConnectionsAfterEveryEdit" xml:space="preserve">
<value>Verbindungen nach jeder Änderung speichern</value>
</data>
<data name="FilterSearchMatchesInConnectionTree" xml:space="preserve">
<value>Suchergebnisse in Verbindungen filtern</value>
</data>
<data name="TestConnection" xml:space="preserve">
<value>Teste Verbindung</value>
</data>
<data name="strTimeoutInSeconds" xml:space="preserve">
<value>Time-Out (Sekunden)</value>
</data>
<data name="strOptionsKeyboardButtonResetAll" xml:space="preserve">
<value>&amp;Alles zurücksetzen</value>
</data>
<data name="strPropertyNameAutomaticResize" xml:space="preserve">
<value>Automatische Größenanpassung</value>
</data>
<data name="strPuttySessionSettings" xml:space="preserve">
<value>PuTTY Sitzungseinstellungen</value>
</data>
<data name="strShowOnToolbar" xml:space="preserve">
<value>Auf der Toolbar anzeigen</value>
</data>
<data name="strAccept" xml:space="preserve">
<value>Akzeptieren</value>
</data>
<data name="strCredentialEditor" xml:space="preserve">
<value>Hinzufügen</value>
</data>
<data name="strAssignedCredential" xml:space="preserve">
<value>Zugewiesene Anmeldedaten</value>
</data>
<data name="strHttpsInsecurePromptTitle" xml:space="preserve">
<value>Unsichere Zertifikate erlauben?</value>
</data>
<data name="Unlock" xml:space="preserve">
<value>Entsperren</value>
</data>
<data name="strOptionsThemeEnableTheming" xml:space="preserve">
<value>Themes aktivieren</value>
</data>
<data name="strOptionsThemeNewThemeCaption" xml:space="preserve">
<value>Neuer Thema Name</value>
</data>
<data name="TestingConnection" xml:space="preserve">
<value>Teste Verbindung</value>
</data>
<data name="strExportToFileMenuItem" xml:space="preserve">
<value>In Datei &amp;exportieren...</value>
</data>
<data name="strImportFileFailedContent" xml:space="preserve">
<value>Ein Fehler ist während des Imports der Datei {0} aufgetreten.</value>
</data>
<data name="strMenuLockToolbars" xml:space="preserve">
<value>Symbolleisten sperren</value>
</data>
<data name="strMenuMultiSshToolbar" xml:space="preserve">
<value>Multi-SSH Symbolleiste</value>
</data>
<data name="strAdvancedSecurityOptions" xml:space="preserve">
<value>Erweiterte Sicherheitsoptionen</value>
</data>
<data name="strLogTheseMessageTypes" xml:space="preserve">
<value>Diese Nachrichtentypen protokollieren</value>
</data>
<data name="strOptionsThemeThemeChaangeWarning" xml:space="preserve">
<value>Warnung! Ein Neustart ist notwendig um ein Theme zu deaktivieren oder anzuwenden</value>
</data>
<data name="strOptionsThemeErrorNoThemes" xml:space="preserve">
<value>
Es werden keine Themes geladen, vergewissern Sie sich, dass das standard mremoteNG-Theme im Ordner 'themes' vorhanden ist</value>
</data>
<data name="LoginFailedForUser" xml:space="preserve">
<value>Login fehlgeschlagen für Benutzer '{0}'.</value>
</data>
<data name="strOptionsPageTitle" xml:space="preserve">
<value>mRemoteNG Optionen</value>
</data>
<data name="strImportLocationCommandButtons" xml:space="preserve">
<value>Unter dem Stamm {0} {1} | Unter dem ausgewählten Ordner {0} {2}</value>
</data>
<data name="strMenuNewExternalTool" xml:space="preserve">
<value>Neues externes Tool</value>
</data>
<data name="strMenuSessionRetrieve" xml:space="preserve">
<value>Abrufen</value>
</data>
<data name="strUpdateGetChangeLogFailed" xml:space="preserve">
<value>Das Change-Log konnte nicht herunter geladen werden.</value>
</data>
<data name="strPropertyDescriptionSoundQuality" xml:space="preserve">
<value>Wählen Sie die vom Protokoll bereitgestellte Klangqualität: Dynamisch, Mittel, Hoch</value>
</data>
<data name="strPropertyDescriptionRDPMinutesToIdleTimeout" xml:space="preserve">
<value>Die Anzahl der Minuten, die die RDP-Sitzung im Leerlauf verbleibt, bevor sie automatisch getrennt wird (0 bedeutet kein Limit)</value>
</data>
<data name="strPropertyNameRDPMinutesToIdleTimeout" xml:space="preserve">
<value>Minuten zum Leerlauf</value>
</data>
<data name="strAdd" xml:space="preserve">
<value>Hinzufügen</value>
</data>
<data name="strPropertyDescriptionCredential" xml:space="preserve">
<value>Auswählen welche Anmeldeinformationen für diese Verbindung verwendet werden sollen.</value>
</data>
<data name="strConfirmDeleteCredentialRecord" xml:space="preserve">
<value>Möchten Sie die Anmeldeinformationen {0} wirklich löschen?</value>
</data>
<data name="strFindMatchingCredentialFailed" xml:space="preserve">
<value>
Es konnte kein Anmeldedatensatz mit der ID "{0}" für den Verbindungsdatensatz mit dem Namen "{1}" gefunden werden.</value>
</data>
<data name="strPropertyDescriptionRDPAlertIdleTimeout" xml:space="preserve">
<value>Wählen Sie, ob eine Benachrichtigung empfangen werden soll, nachdem die RDP-Sitzung aufgrund von Inaktivität getrennt wurde</value>
</data>
<data name="strPropertyNameRDPAlertIdleTimeout" xml:space="preserve">
<value>Benachrichtigung bei Leerlauftrennung</value>
</data>
<data name="strPasswordConstainsSpecialCharactersConstraintHint" xml:space="preserve">
<value>Das Passwort muss mindestens {0} der folgenden Zeichen enthalten: {1}</value>
</data>
<data name="strPasswordContainsLowerCaseConstraintHint" xml:space="preserve">
<value>Das Passwort muss mindestens {0} Kleinbuchstaben enthalten</value>
</data>
<data name="strPasswordContainsNumbersConstraint" xml:space="preserve">
<value>Passwort muss mindestens {0} Nummer (n) enthalten</value>
</data>
<data name="strPasswordContainsUpperCaseConstraintHint" xml:space="preserve">
<value>Passwort muss mindestens {0} Großbuchstaben enthalten</value>
</data>
<data name="strPasswordLengthConstraintHint" xml:space="preserve">
<value>
Die Passwortlänge muss zwischen {0} und {1} liegen</value>
</data>
<data name="strChooseLogPath" xml:space="preserve">
<value>
Wählen Sie einen Pfad für die mRemoteNG-Protokolldatei</value>
</data>
<data name="strLogFilePath" xml:space="preserve">
<value>Protokollierungspfad</value>
</data>
<data name="strChoosePath" xml:space="preserve">
<value>Pfad wählen</value>
</data>
<data name="strUseDefault" xml:space="preserve">
<value>Standard verwenden</value>
</data>
<data name="strLogging" xml:space="preserve">
<value>Protokollierung</value>
</data>
<data name="strLogToAppDir" xml:space="preserve">
<value>In das Anwendungsverzeichnis protokollieren</value>
</data>
<data name="strHttpsInsecurePrompt" xml:space="preserve">
<value>Unsicheres Zertifikat für URL zulassen: {0}?</value>
</data>
<data name="RepositoryIsUnlocked" xml:space="preserve">
<value>Das ausgewählte Repository ist entsperrt</value>
</data>
<data name="Unlocking" xml:space="preserve">
<value>Entsperren</value>
</data>
<data name="UnlockCredentialRepository" xml:space="preserve">
<value>Entsperre Credential Repository</value>
</data>
<data name="PromptUnlockCredReposOnStartup" xml:space="preserve">
<value>Auffordern das Credential Repository beim Start zu entsperren</value>
</data>
<data name="strConnectionFilePath" xml:space="preserve">
<value>Verbindungsdateipfad</value>
</data>
<data name="CredentialUnavailable" xml:space="preserve">
<value>Anmeldeinformationen nicht verfügbar</value>
</data>
<data name="strOptionsThemeDeleteConfirmation" xml:space="preserve">
<value>Soll das Theme wirklich gelöscht werden?</value>
</data>
<data name="strOptionsThemeNewThemeError" xml:space="preserve">
<value>Das Theme kann nicht erstellt werden, Name bereits vorhanden oder Sonderzeichen im Namen</value>
</data>
<data name="strOptionsThemeNewThemeText" xml:space="preserve">
<value>Namen des neuen Theme angeben</value>
</data>
<data name="CouldNotFindExternalTool" xml:space="preserve">
<value>Externes Tool mit Namen "{0}" konnte nicht gefunden werden</value>
</data>
<data name="ConfigurationCustomPath" xml:space="preserve">
<value>Eigenen Pfad verwenden</value>
</data>
<data name="ServerNotAccessible" xml:space="preserve">
<value>Server '{0}' nicht erreichbar</value>
</data>
<data name="LoadBalanceInfoUseUtf8" xml:space="preserve">
<value>Verwenden Sie die UTF8-Codierung für die RDP-Eigenschaft "Load Balance Info"</value>
</data>
</root>

View File

@@ -59,7 +59,7 @@
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
@@ -105,17 +105,17 @@
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="strAbout" xml:space="preserve">
<value>Acerca de</value>
@@ -1154,7 +1154,7 @@ Ver el articulo de soporte de Microsoft en http://support.microsoft.com/kb/81183
<value>Sin SmartSize</value>
</data>
<data name="strNoUpdateAvailable" xml:space="preserve">
<value>Sin actualizaciones dosponibles</value>
<value>Sin actualizaciones disponibles</value>
</data>
<data name="strOldConffile" xml:space="preserve">
<value>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
<value>Introduzca su dominio.</value>
</data>
<data name="strPropertyDescriptionEnableDesktopComposition" xml:space="preserve">
<value>Seleccione si emplear composición de escrotorio o no.</value>
<value>Seleccione si emplear composición de escritorio o no.</value>
</data>
<data name="strPropertyDescriptionEnableFontSmoothing" xml:space="preserve">
<value>Seleccione si emplear suavizado de fuentes o no.</value>

View File

@@ -181,7 +181,7 @@
<value>Automatically get session information</value>
</data>
<data name="strAutoSaveEvery" xml:space="preserve">
<value>Auto save every:</value>
<value>Auto save time in minutes (0 means disabled):</value>
</data>
<data name="strAutoSaveMins" xml:space="preserve">
<value>Minutes (0 means disabled)</value>
@@ -836,7 +836,7 @@ See the Microsoft Support article at http://support.microsoft.com/kb/811833 for
<value>Import/Export</value>
</data>
<data name="strImportFileFailedContent" xml:space="preserve">
<value>An error occurred while importing the file, "{0}".</value>
<value>An error occurred while importing the file "{0}".</value>
</data>
<data name="strImportFileFailedMainInstruction" xml:space="preserve">
<value>Import failed</value>
@@ -2584,7 +2584,7 @@ This page will walk you through the process of upgrading your connections file o
<value>Warning: Restart is required to disable the themes or to completely apply a new one</value>
</data>
<data name="strOptionsThemeErrorNoThemes" xml:space="preserve">
<value>No themes are loaded, check that the default mremoteNG themes exist in the slash themes folder</value>
<value>No themes are loaded, check that the default mremoteNG themes exist in the 'themes' folder</value>
</data>
<data name="CouldNotFindExternalTool" xml:space="preserve">
<value>Could not find external tool with name "{0}"</value>
@@ -2631,7 +2631,73 @@ This page will walk you through the process of upgrading your connections file o
<data name="LoadBalanceInfoUseUtf8" xml:space="preserve">
<value>Use UTF8 encoding for RDP "Load Balance Info" property</value>
</data>
<data name="TimeoutInSeconds" xml:space="preserve">
<data name="strTimeoutInSeconds" xml:space="preserve">
<value>Timeout (seconds)</value>
</data>
<data name="srtWorkingDirectory" xml:space="preserve">
<value>Working directory:</value>
</data>
<data name="strRunElevated" xml:space="preserve">
<value>Run elevated</value>
</data>
<data name="strRunElevateHeader" xml:space="preserve">
<value>Run elevate</value>
</data>
<data name="strShowOnToolbarColumnHeader" xml:space="preserve">
<value>Show on toolbar column</value>
</data>
<data name="strTryToIntegrateColumnHeader" xml:space="preserve">
<value>Try to integrate</value>
</data>
<data name="strWorkingDirColumnHeader" xml:space="preserve">
<value>Working directory</value>
</data>
<data name="strLockToolbars" xml:space="preserve">
<value>Lock toolbar positions</value>
</data>
<data name="strMultiSshToolbar" xml:space="preserve">
<value>Multi SSH toolbar</value>
</data>
<data name="strImportSubOUs" xml:space="preserve">
<value>Import sub OUs</value>
</data>
<data name="strMenuLockToolbars" xml:space="preserve">
<value>Lock Toolbar Positions</value>
</data>
<data name="strMenuMultiSshToolbar" xml:space="preserve">
<value>Multi SSH Toolbar</value>
</data>
<data name="strAdvancedSecurityOptions" xml:space="preserve">
<value>AdvancedSecurityOptions</value>
</data>
<data name="strOptionsPageTitle" xml:space="preserve">
<value>mRemoteNG Options</value>
</data>
<data name="strLoadBalanceInfoUseUtf8" xml:space="preserve">
<value>Use UTF8 encoding for RDP "Load Balance Info" property</value>
</data>
<data name="strCreateEmptyPanelOnStartUp" xml:space="preserve">
<value>Create an empty panel when mRemoteNG starts</value>
</data>
<data name="strIPRange" xml:space="preserve">
<value>Must Be Between 0 and 255</value>
</data>
<data name="strOutOfRange" xml:space="preserve">
<value>Out Of Range</value>
</data>
<data name="strDelete" xml:space="preserve">
<value>Delete...</value>
</data>
<data name="strReconnectAllConnections" xml:space="preserve">
<value>Reconnect All Connections</value>
</data>
<data name="strUltraVNCSingleClick" xml:space="preserve">
<value>UltraVNC SingleClick</value>
</data>
<data name="AutomaticReconnectError" xml:space="preserve">
<value>An error occurred while trying to reconnect to RDP host '{0}'</value>
</data>
<data name="ChangeConnectionResolutionError" xml:space="preserve">
<value>An error occurred while trying to change the connection resolution to host '{0}'</value>
</data>
</root>

View File

@@ -187,13 +187,13 @@
<value>Текущая версия</value>
</data>
<data name="strButtonBrowse" xml:space="preserve">
<value>&amp;Обзор ...</value>
<value>&amp;Обзор...</value>
</data>
<data name="strButtonCancel" xml:space="preserve">
<value>&amp;Отменить</value>
</data>
<data name="strButtonChange" xml:space="preserve">
<value>Измененить</value>
<value>Изменить</value>
</data>
<data name="strButtonClose" xml:space="preserve">
<value>&amp;Закрыть</value>
@@ -302,8 +302,8 @@
<value>GeckoFx был найден и установлен правильно.</value>
</data>
<data name="strCcICAFailed" xml:space="preserve">
<value>ICA требуется установленный XenDesktop Online Plugin и зарегистрированная библиотека wfica.ocx. Вы можете скачать клиент здесь: http://www.citrix.com/download/
Если у вас есть установленный XenDesktop Online Plugin и ничего не работает, попробуйте зарегистрировать wfica.ocx вручную.
<value>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/ "</value>
</data>
@@ -319,7 +319,7 @@
Убедитесь, что putty.exe есть в папке с mRemoteNG (по умолчанию: C:\Program Files\mRemoteNG\), или что вы указали правильный путь к исполняемому файлу PuTTY в Инструменты - Опции - Дополнительно - Путь к PuTTY)</value>
</data>
<data name="strCcPuttyOK" xml:space="preserve">
<value>Испольняемый файл PuTTY найден и готов к использованию.</value>
<value>Исполняемый файл PuTTY найден и готов к использованию.</value>
</data>
<data name="strCcRDPFailed" xml:space="preserve">
<value>Для правильной работы RDP необходимо иметь установленный Remote Desktop Connection (Terminal Services Client) 8.0. Вы можете получить его здесь: https://support.microsoft.com/kb/2592687
@@ -418,7 +418,7 @@
<value>Невозможно разобрать аргументы командной строки!</value>
</data>
<data name="strCompatibilityLenovoAutoScrollUtilityDetected" xml:space="preserve">
<value>{0} обнаружено что на этой системе работает утилита Lenovo Auto Scroll. Известно, что эта утилита вызвает проблемы с {0}. Рекомендуется отключить или удалить ее.</value>
<value>{0} обнаружено что на этой системе работает утилита Lenovo Auto Scroll. Известно, что эта утилита вызывает проблемы с {0}. Рекомендуется отключить или удалить ее.</value>
</data>
<data name="strCompatibilityProblemDetected" xml:space="preserve">
<value>Обнаружена проблема совместимости</value>
@@ -569,7 +569,7 @@
<value>Не подключать без проверки</value>
</data>
<data name="strDoubleClickTabClosesIt" xml:space="preserve">
<value>Двойной щелчок для закрытия вкладки</value>
<value>Двойной щелчок для закрытия вкладки</value>
</data>
<data name="strDownloadAndInstall" xml:space="preserve">
<value>Загрузка и установка</value>
@@ -605,7 +605,7 @@
<value>Конечный IP</value>
</data>
<data name="strEndPort" xml:space="preserve">
<value>Конечн. порт</value>
<value>Конечный порт</value>
</data>
<data name="strErrorAddExternalToolsToToolBarFailed" xml:space="preserve">
<value>Ошибка добавления внешнего приложения на Панель (frmMain). {0}</value>
@@ -711,7 +711,7 @@
<value>Соединение</value>
</data>
<data name="strGroupboxExternalToolProperties" xml:space="preserve">
<value>Свройства внешнего инструмента</value>
<value>Свойства внешнего инструмента</value>
</data>
<data name="strGroupboxFiles" xml:space="preserve">
<value>Файлы</value>
@@ -825,7 +825,7 @@
<value>&amp;Подключение:</value>
</data>
<data name="strLabelDisplayName" xml:space="preserve">
<value>Отображаемое имя</value>
<value>Отображаемое имя:</value>
</data>
<data name="strLabelDomain" xml:space="preserve">
<value>Домен:</value>
@@ -855,7 +855,7 @@
<value>Нажмите на эту кнопку для настройки сессий PuTTY:</value>
</data>
<data name="strLabelPuttyTimeout" xml:space="preserve">
<value>Max. PuTTY &amp;&amp; Integrated Ext. Apps wait time:</value>
<value>Максимальное время ожидание PuTTY и внешнего приложения:</value>
</data>
<data name="strLabelReleasedUnderGPL" xml:space="preserve">
<value>Выпущено под лицензией GNU General Public License (GPL)</value>
@@ -897,7 +897,7 @@
<value>Загрузить из XML не удалось!</value>
</data>
<data name="strLocalFile" xml:space="preserve">
<value>Локал. файл</value>
<value>Локальный файл</value>
</data>
<data name="strLocalFileDoesNotExist" xml:space="preserve">
<value>Локальный файл не существует!</value>
@@ -951,10 +951,10 @@
<value>Удалить...</value>
</data>
<data name="strMenuDeleteConnection" xml:space="preserve">
<value>Удалить подключение ...</value>
<value>Удалить подключение...</value>
</data>
<data name="strMenuDeleteExternalTool" xml:space="preserve">
<value>Удалить Внешний инструмент...</value>
<value>Удалить внешний инструмент...</value>
</data>
<data name="strMenuDeleteFolder" xml:space="preserve">
<value>Удалить папку...</value>
@@ -1270,7 +1270,7 @@
<value>Это имя, которое будет отображаться в дереве подключений.</value>
</data>
<data name="strPropertyDescriptionPanel" xml:space="preserve">
<value>Устанавить панель, в которой будет открыто подключение.</value>
<value>Установить панель, в которой будет открыто подключение.</value>
</data>
<data name="strPropertyDescriptionPassword" xml:space="preserve">
<value>Введите пароль.</value>
@@ -1579,7 +1579,7 @@
<value>Ошибка добавления Быстрого подключения!</value>
</data>
<data name="strQuickConnectFailed" xml:space="preserve">
<value>Созданить быстрое подключение не удалось</value>
<value>Создать быстрое подключение не удалось</value>
</data>
<data name="strRadioCloseWarnAll" xml:space="preserve">
<value>Предупреждать при закрытии подключений</value>
@@ -1705,7 +1705,7 @@
<value>Ошибка сессии!</value>
</data>
<data name="strRdpReconnectCount" xml:space="preserve">
<value>К-ство переподключений RDP:</value>
<value>Количество переподключений RDP:</value>
</data>
<data name="strRdpSetAuthenticationLevelFailed" xml:space="preserve">
<value>RDP: Установить уровень проверки подлинности не удалась!</value>
@@ -1768,7 +1768,7 @@
<value>Обновление</value>
</data>
<data name="strRemoteFile" xml:space="preserve">
<value>Удаленн. файл</value>
<value>Удалить файл</value>
</data>
<data name="strRemoveAll" xml:space="preserve">
<value>Удалить все</value>
@@ -1885,7 +1885,7 @@
<value>Фоновая передача по SSH - не удалась!</value>
</data>
<data name="strSSHTranferSuccessful" xml:space="preserve">
<value>Передано успешо!</value>
<value>Передано успешно!</value>
</data>
<data name="strSSHTransferEndFailed" xml:space="preserve">
<value>Передача по SSH завершена с ошибкой (UI.Window.SSHTransfer)!</value>
@@ -1897,7 +1897,7 @@
<value>Начальный IP</value>
</data>
<data name="strStartPort" xml:space="preserve">
<value>Начальн. порт</value>
<value>Начальный порт</value>
</data>
<data name="strStartupExit" xml:space="preserve">
<value>Запуск / Выход</value>
@@ -2080,7 +2080,7 @@
<value>Требуется обновление mRemoteNG</value>
</data>
<data name="strUpdateCheck" xml:space="preserve">
<value>mRemoteNG может периодически подключаться к сайту mRemoteNG для проверки наличия обновлений.</value>
<value>mRemoteNG может периодически подключаться к сайту mRemoteNG для проверки наличия обновлений.</value>
</data>
<data name="strUpdateCheckCompleteFailed" xml:space="preserve">
<value>Не удалось завершить проверку обновлений!</value>
@@ -2191,4 +2191,76 @@ mRemoteNG сейчас прекратит работу и начнет проц
<data name="strMenuReconnectAll" xml:space="preserve">
<value>Переподключить все открытые соединения</value>
</data>
<data name="srtWorkingDirectory" xml:space="preserve">
<value>Рабочий каталог:</value>
</data>
<data name="strButtonLaunch" xml:space="preserve">
<value>Запуск</value>
</data>
<data name="strRunElevated" xml:space="preserve">
<value>Выполнить с повышенными правами</value>
</data>
<data name="strRunElevateHeader" xml:space="preserve">
<value>Выполнить с повышенными правами</value>
</data>
<data name="strShowOnToolbar" xml:space="preserve">
<value>Отобразить на панели инструментов:</value>
</data>
<data name="strShowOnToolbarColumnHeader" xml:space="preserve">
<value>Отобразить на панели инструментов</value>
</data>
<data name="strTryToIntegrateColumnHeader" xml:space="preserve">
<value>Попробовать интегрировать</value>
</data>
<data name="strWorkingDirColumnHeader" xml:space="preserve">
<value>Рабочий каталог</value>
</data>
<data name="strExportToFileMenuItem" xml:space="preserve">
<value>Экспорт в файл...</value>
</data>
<data name="strImportFromFileMenuItem" xml:space="preserve">
<value>Импорт из файла...</value>
</data>
<data name="strImportMenuItem" xml:space="preserve">
<value>Импорт</value>
</data>
<data name="strLockToolbars" xml:space="preserve">
<value>Закрепить позицию панели инструментов</value>
</data>
<data name="strMultiSshToolbar" xml:space="preserve">
<value>Панель инструментов SSH</value>
</data>
<data name="strAssignedCredential" xml:space="preserve">
<value>Назначенные учетные данные</value>
</data>
<data name="strExportEverything" xml:space="preserve">
<value>Экспортировать все</value>
</data>
<data name="strExportFile" xml:space="preserve">
<value>Файл экспорта</value>
</data>
<data name="strExportItems" xml:space="preserve">
<value>Пункт импорта</value>
</data>
<data name="strExportProperties" xml:space="preserve">
<value>Экспорт свойств</value>
</data>
<data name="strExportSelectedConnection" xml:space="preserve">
<value>Экспорт выбранного соединения</value>
</data>
<data name="strExportSelectedFolder" xml:space="preserve">
<value>Экспорт выбранной папки</value>
</data>
<data name="strFileFormatLabel" xml:space="preserve">
<value>Формат файла:</value>
</data>
<data name="strImportSubOUs" xml:space="preserve">
<value>Импорт подразделений</value>
</data>
<data name="strLoadBalanceInfoUseUtf8" xml:space="preserve">
<value>Используйте кодировку UTF8 для свойства RDP "Load Balance Info"</value>
</data>
<data name="strTimeoutInSeconds" xml:space="preserve">
<value>Время ожидания в секундах:</value>
</data>
</root>

View File

@@ -14,6 +14,7 @@
<xs:element name="Node" type="mrng:connectioninfo" />
</xs:sequence>
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="Export" type="xs:boolean" use="required" />
<xs:attribute name="EncryptionEngine" type="xs:string" use="required" />
<xs:attribute name="BlockCipherMode" type="xs:string" use="required" />
<xs:attribute name="KdfIterations" type="xs:int" use="optional" />

View File

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

View File

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

View File

@@ -9,35 +9,14 @@ namespace mRemoteNG.Themes
/// </summary>
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<string, Color> _extendedColors;
private Dictionary<string, Color> _default;
#endregion
#region Constructors
public ExtendedColorPalette()
{
_extendedColors = new Dictionary<string, Color>();
_default = new Dictionary<string, Color>(); // If this is the default palette, it will not have a default-default palette
ExtColorPalette = new Dictionary<string, Color>();
DefaultColorPalette = new Dictionary<string, Color>(); // 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
/// <returns></returns>
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
/// <param name="inColor"></param>
public void addColor(string colorKey,Color inColor)
{
_extendedColors.Add(colorKey, inColor);
ExtColorPalette.Add(colorKey, inColor);
}
@@ -111,33 +89,13 @@ namespace mRemoteNG.Themes
/// <param name="inColor"></param>
public void replaceColor(string colorKey, Color inColor)
{
_extendedColors[colorKey]= inColor;
ExtColorPalette[colorKey]= inColor;
}
public Dictionary<string, Color> DefaultColorPalette
{
get
{
return _default;
}
set
{
_default = value;
}
}
public Dictionary<string, Color> DefaultColorPalette { get; set; }
public Dictionary<string, Color> ExtColorPalette
{
get
{
return _extendedColors;
}
set
{
_extendedColors = value;
}
}
public Dictionary<string, Color> ExtColorPalette { get; set; }
}
}

View File

@@ -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);

View File

@@ -7,6 +7,7 @@ using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.Themes
{
/// <inheritdoc />
/// <summary>
/// Container class for all the color and style elements to define a theme
/// </summary>
@@ -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
}
}

View File

@@ -46,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());
}
@@ -64,80 +60,74 @@ namespace mRemoteNG.Themes
//THe manager precharges all the themes at once
public List<ThemeInfo> LoadThemes()
{
if (themes == null)
if (themes != null) return themes.Values.OfType<ThemeInfo>().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<ThemeInfo>().ToList();
try
{
themes = new Hashtable();
//Load the files in theme folder first, to incluide vstheme light as default
string themePath = App.Info.SettingsFileInfo.ThemeFolder;
if (themePath != null)
//In install mode first time is necesary to copy the themes folder
if (!Directory.Exists(themePath))
{
try
{
//In install mode first time is necesary to copy the themes folder
if (!Directory.Exists(themePath))
{
Directory.CreateDirectory(themePath);
Directory.CreateDirectory(themePath);
}
DirectoryInfo orig = new DirectoryInfo(App.Info.SettingsFileInfo.InstalledThemeFolder);
FileInfo[] files = orig.GetFiles();
foreach (FileInfo file in files)
{
}
var orig = new DirectoryInfo(App.Info.SettingsFileInfo.InstalledThemeFolder);
var files = orig.GetFiles();
foreach (var file in files)
{
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))
{
string[] themeFiles = Directory.GetFiles(themePath, "*.vstheme");
string defaultThemeURL = Directory.GetFiles(themePath, "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);
}
}
//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);
}
}
catch(Exception ex )
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Error loading themes" + Environment.NewLine + ex.Message, true);
}
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<ThemeInfo>().ToList();
}
@@ -149,29 +139,24 @@ namespace mRemoteNG.Themes
/// <returns></returns>
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
@@ -191,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;
}
@@ -206,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")
@@ -223,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

View File

@@ -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
{
/// <summary>
/// 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
/// </summary>
/// <param name="themeInfo"></param>
public static void SaveToXmlFile(ThemeInfo themeToSave,ThemeInfo baseTheme)
/// <summary>
/// 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
/// </summary>
/// <param name="themeToSave"></param>
/// <param name="baseTheme"></param>
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
/// <param name="themeToUpdate"></param>
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
/// <returns></returns>
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);
}
*/
}
}

View File

@@ -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

View File

@@ -34,7 +34,7 @@ namespace mRemoteNG.Tools
}
}
public static SecureString PasswordDialog(string passwordName = null, bool verify = true)
public static Optional<SecureString> PasswordDialog(string passwordName = null, bool verify = true)
{
var passwordForm = new PasswordForm(passwordName, verify);
return passwordForm.GetKey();
@@ -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)
{

View File

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

View File

@@ -30,7 +30,7 @@ namespace mRemoteNG.Tree
RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, rootNode));
}
public IEnumerable<ConnectionInfo> GetRecursiveChildList()
public IReadOnlyList<ConnectionInfo> GetRecursiveChildList()
{
var list = new List<ConnectionInfo>();
foreach (var rootNode in RootNodes)

View File

@@ -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<ConnectionInfo>)_connectionTreeModel.GetRecursiveChildList();
var nodes = _connectionTreeModel.GetRecursiveChildList();
var searchTextLower = searchText.ToLowerInvariant();
foreach (var node in nodes)
{

View File

@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tools;
@@ -65,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);
}
}
}

View File

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

View File

@@ -73,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
{
@@ -129,7 +129,7 @@ namespace mRemoteNG.UI.Controls.Base
}
//Arrow
e.Graphics.DrawString("\u25BC", this.Font, 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);

View File

@@ -10,7 +10,7 @@ namespace mRemoteNG.UI.Controls.Base
{
private ThemeManager _themeManager;
public NGGroupBox() : base()
public NGGroupBox()
{
ThemeManager.getInstance().ThemeChanged += OnCreateControl;
}

View File

@@ -23,10 +23,12 @@ namespace mRemoteNG.UI.Controls.Base
{
base.OnCreateControl();
_themeManager = ThemeManager.getInstance();
if (_themeManager.ThemingActive)
{
Invalidate();
}
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();
}
@@ -38,16 +40,17 @@ namespace mRemoteNG.UI.Controls.Base
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);
}
}

View File

@@ -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,7 +15,7 @@ namespace mRemoteNG.UI.Controls.Base
private NGButton Up;
private NGButton Down;
public NGNumericUpDown() : base()
public NGNumericUpDown()
{
_themeManager = ThemeManager.getInstance();
ThemeManager.getInstance().ThemeChanged += OnCreateControl;
@@ -28,7 +29,8 @@ namespace mRemoteNG.UI.Controls.Base
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
{

View File

@@ -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<RootPuttySessionsNodeInfo> 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);
@@ -278,6 +288,13 @@ namespace mRemoteNG.UI.Controls
public void DuplicateSelectedNode()
{
if (SelectedNode == null)
return;
var selectedNodeType = SelectedNode.GetTreeNodeType();
if (selectedNodeType != TreeNodeType.Connection && selectedNodeType != TreeNodeType.Container)
return;
var newNode = SelectedNode.Clone();
SelectedNode.Parent.AddChildBelow(newNode, SelectedNode);
newNode.Parent.SetChildBelow(newNode, SelectedNode);
@@ -285,8 +302,11 @@ namespace mRemoteNG.UI.Controls
public void RenameSelectedNode()
{
_allowEdit = true;
SelectedItem.BeginEdit();
if (SelectedItem != null)
{
_allowEdit = true;
SelectedItem.BeginEdit();
}
}
public void DeleteSelectedNode()
@@ -301,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();
}
/// <summary>
/// Expands all tree objects and recalculates the
/// column widths.
/// </summary>
public override void ExpandAll()
{
base.ExpandAll();
AutoResizeColumn(Columns[0]);
}
/// <summary>
/// Filters tree items based on the given <see cref="filterText"/>
/// </summary>
/// <param name="filterText">The text to filter by</param>
public void ApplyFilter(string filterText)
{
UseFiltering = true;
_connectionTreeSearchTextFilter.FilterText = filterText;
ModelFilter = _connectionTreeSearchTextFilter;
}
/// <summary>
/// Removes all item filtering from the connection tree
/// </summary>
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
@@ -350,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;
}
@@ -385,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)
@@ -394,4 +480,4 @@ namespace mRemoteNG.UI.Controls
}
#endregion
}
}
}

View File

@@ -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; } = "";
/// <summary>
/// A list of <see cref="ConnectionInfo"/> objects that should
/// always be included in the output, regardless of matching
/// the desired <see cref="FilterText"/>.
/// </summary>
public List<ConnectionInfo> SpecialInclusionList { get; } = new List<ConnectionInfo>();
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) ||

View File

@@ -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
{
/// <summary>
/// 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.
/// </summary>
public partial class FilteredPropertyGrid : PropertyGrid
/// <summary>
/// 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.
/// </summary>
public partial class FilteredPropertyGrid : PropertyGrid
{
/// <summary>Contain a reference to the collection of properties to show in the parent PropertyGrid.</summary>
/// <summary>
/// Contain a reference to the collection of properties to show in the parent PropertyGrid.
/// </summary>
/// <remarks>By default, m_PropertyDescriptors contain all the properties of the object. </remarks>
readonly List<PropertyDescriptor> m_PropertyDescriptors = new List<PropertyDescriptor>();
/// <summary>Contain a reference to the array of properties to display in the PropertyGrid.</summary>
private AttributeCollection m_HiddenAttributes, m_BrowsableAttributes;
/// <summary>Contain references to the arrays of properties or categories to hide.</summary>
private string[] m_BrowsableProperties, m_HiddenProperties;
/// <summary>Contain a reference to the wrapper that contains the object to be displayed into the PropertyGrid.</summary>
private ObjectWrapper m_Wrapper;
readonly List<PropertyDescriptor> _propertyDescriptors = new List<PropertyDescriptor>();
/// <summary>Public constructor.</summary>
public FilteredPropertyGrid() {
/// <summary>
/// Contain a reference to the array of properties to display in the PropertyGrid.
/// </summary>
private AttributeCollection _hiddenAttributes;
private AttributeCollection _browsableAttributes;
/// <summary>
/// Contain references to the arrays of properties or categories to hide.
/// </summary>
private string[] _mBrowsableProperties;
private string[] _mHiddenProperties;
/// <summary>
/// Contain a reference to the wrapper that contains the object to be displayed into the PropertyGrid.
/// </summary>
private ObjectWrapper _mWrapper;
/// <summary>
/// Public constructor.
/// </summary>
public FilteredPropertyGrid()
{
InitializeComponent();
base.SelectedObject = m_Wrapper;
base.SelectedObject = _mWrapper;
}
public new AttributeCollection BrowsableAttributes {
get { return m_BrowsableAttributes; }
/// <summary>
/// A list of all currently properties being shown by the property grid.
/// </summary>
public IEnumerable<string> 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();
}
}
/// <summary>Get or set the categories to hide.</summary>
/// <summary>
/// Get or set the categories to hide.
/// </summary>
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();
}
}
/// <summary>Get or set the properties to show.</summary>
/// <summary>
/// Get or set the properties to show.
/// </summary>
/// <exception cref="ArgumentException">if one or several properties don't exist.</exception>
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();
}
}
/// <summary>Get or set the properties to hide.</summary>
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();
}
}
/// <summary>Overwrite the PropertyGrid.SelectedObject property.</summary>
/// <summary>
/// Overwrite the PropertyGrid.SelectedObject property.
/// </summary>
/// <remarks>The object passed to the base PropertyGrid is the wrapper.</remarks>
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;
}
}
/*
/// <summary>Called when the browsable properties have changed.</summary>
private void OnBrowsablePropertiesChanged() {
if(m_Wrapper == null) return;
}
*/
/// <summary>
/// Build the list of the properties to be displayed in the PropertyGrid, following the filters defined the Browsable and Hidden properties.
/// </summary>
private void RefreshProperties()
{
if(_mWrapper == null)
return;
/// <summary>Build the list of the properties to be displayed in the PropertyGrid, following the filters defined the Browsable and Hidden properties.</summary>
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<PropertyDescriptor>()
.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);
}
}
}
}
/// <summary>Allows to hide a set of properties to the parent PropertyGrid.</summary>
/// <summary>
/// Predicate to determine if a property has a Browsable(false) attribute
/// attatched to it. If so, it should not be shown.
/// </summary>
/// <param name="propertyDescriptor"></param>
/// <returns></returns>
private bool PropertyDoesntHaveBrowsableFalseAttribute(PropertyDescriptor propertyDescriptor)
{
return !propertyDescriptor.Attributes.Contains(new BrowsableAttribute(false));
}
/// <summary>
/// Allows to hide a set of properties to the parent PropertyGrid.
/// </summary>
/// <param name="attribute">A set of attributes that filter the original collection of properties.</param>
/// <remarks>For better performance, include the BrowsableAttribute with true value.</remarks>
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);
}
/// <summary>Add all the properties that match an attribute to the list of properties to be displayed in the PropertyGrid.</summary>
/// <summary>
/// Add all the properties that match an attribute to the list of properties to be displayed in the PropertyGrid.
/// </summary>
/// <param name="attribute">The attribute to be added.</param>
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);
}
/// <summary>Add a property to the list of properties to be displayed in the PropertyGrid.</summary>
/// <summary>
/// Add a property to the list of properties to be displayed in the PropertyGrid.
/// </summary>
/// <param name="property">The property to be added.</param>
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);
}
/// <summary>Allows to hide a property to the parent PropertyGrid.</summary>
/// <summary>
/// Allows to hide a property to the parent PropertyGrid.
/// </summary>
/// <param name="property">The name of the property to be hidden.</param>
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);
}
}
}

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