Compare commits

...

246 Commits

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

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

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

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

View File

@@ -1,3 +1,92 @@
1.77.0 (2018-xx-xx):
Features/Enhancements:
----------------------
#1072: Russian translation improvements
#1016: Chinese (simplified) translation improvements
#928: Add context menu items to 'Close all but this' and 'Close all tabs to the right'
1.76.11 (2018-10-18):
Fixes:
------
#1139: Feature "Reconnect to previously opened sessions" not working
#1136: Putty window not maximized
1.76.10 (2018-10-07):
Fixes:
------
#1124: Enabling themes causes an exception
1.76.9 (2018-10-07):
Fixes:
------
#1117: Duplicate panel created when "Reconnect on Startup" and "Create Empty Panel" settings enabled
#1115: Exception when changing from xml data storage to SQL
#1110: Pressing Delete button during connection rename attempts to delete the connection instead of the text
#1106: Inheritance does not work when parent has C# default type set
#1092: Invalid Cast Exceptions loading default connectioninfo
#1091: Minor themeing issues
#853: Added some additional safety checks and logging to help address RDP crashes
1.76.8 (2018-08-25):
Fixes:
------
#1088: Delete and Launch buttons are not disabled when last external tool deleted
#1087: 'Save connections after every edit' setting not honored
#1082: Connections not given GUID if Id is empty in connection xml
1.76.7 (2018-08-22):
Fixes:
------
#1076: Wrong object selected when duplicating connection then switching between properties and inheritance in config window
#1068: Fixed some toolbar positioning bugs
1.76.6 (2018-08-03):
Fixes:
------
#1062: Entering correct password when starting app does not load connections file
1.76.5 (2018-08-02):
Fixes:
------
#1057: Hitting F2 with no connection node selected caused unhandled exception
#1052: 'Switch to notification panel' feature does not always switch
#1051: Tooltips always displayed regardless of 'Show description tooltips in connection tree' setting
#1050: Config window retains access to previously selected node after loading new connections file
#1045: Config window shows several incorrect properties for HTTPS connections
#1040: Canceling "select panel" form does not cancel
#1039: Set default theme when themes disabled
#1038: Unable to add connection with active filter
#1036: Exception when themes are active and options page closed on Connections then reopened
#1034: Connection context menu not being translated
#1030: Exception thrown if importing from port scan and no tree node is selected
#1020: BackupFileKeepCount setting not limiting backup file count
#1004: Duplicating root or PuTTy node through hotkey causes unhandled exception
#1002: Disabling filtering without clearing keyword leaves filtered state
#1001: Connection tree context menu hotkeys stop working and disappear in some cases
#999: Some hotkeys stop working if File menu was called when PuTTy Saved Sessions was selected
#998: Can sometimes add connection under PuTTY Sessions node
#991: Error when deleting host in filtered view
#971: Portable Settings now apply to any machine they are used on
#961: Connections file overwritten if correct decryption password not provided
#893: Removed unneeded files from build/package
#868: if statement returned the same value
#762: Increased button size to fit locaized text
1.76.4 Alpha 6 (2018-06-03): 1.76.4 Alpha 6 (2018-06-03):
Features/Enhancements: Features/Enhancements:

View File

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

View File

@@ -1,9 +1,13 @@
node('windows') { node('windows') {
def jobDir = pwd() def jobDir = pwd()
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\"" def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools" def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe"
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow" def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.7.0\\tools\\nunit3-console.exe"
def nunitTestAdapterPath = "C:\\Users\\Administrator\\AppData\\Local\\Microsoft\\VisualStudio\\14.0\\Extensions" 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') { stage ('Clean output dir') {
@@ -32,24 +36,24 @@ node('windows') {
withCredentials([file(credentialsId: '9b674d57-6792-48e3-984a-4d1bab2abb64', variable: 'CODE_SIGNING_CERT')]) { 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')]) { withCredentials([usernamePassword(credentialsId: '05b7449b-05c0-490f-8661-236242526e62', passwordVariable: 'MRNG_CERT_PASSWORD', usernameVariable: 'NO_USERNAME')]) {
stage ('Build mRemoteNG (Normal - MSI)') { 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 archiveArtifacts artifacts: "Release\\*.msi", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
} }
stage ('Build mRemoteNG (Portable)') { 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 archiveArtifacts artifacts: "Release\\*.zip", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
} }
} }
} }
stage ('Run Unit Tests (Normal - MSI)') { stage ('Run Unit Tests (Normal - MSI)') {
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release\\mRemoteNGTests.dll\"" bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release\\mRemoteNGTests.dll\" --result=${testResultFileNormal} --x86"
} }
stage ('Run Unit Tests (Portable)') { stage ('Run Unit Tests (Portable)') {
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release Portable\\mRemoteNGTests.dll\"" bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release portable\\mRemoteNGTests.dll\" --result=${testResultFilePortable} --x86"
} }
stage ('Generate UpdateCheck Files') { stage ('Generate UpdateCheck Files') {
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\create_upg_chk_files.ps1\" -TagName \"${env.TagName}\" -UpdateChannel \"${env.UpdateChannel}\"" 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') { stage ('Publish to GitHub') {
withCredentials([string(credentialsId: '5443a369-dbe8-42d3-b4e8-04d0b4e9039a', variable: 'GH_AUTH_TOKEN')]) { withCredentials([string(credentialsId: '5443a369-dbe8-42d3-b4e8-04d0b4e9039a', variable: 'GH_AUTH_TOKEN')]) {
def zipPath = "${jobDir}\\Release\\*.zip" def releaseFolder = "${jobDir}\\Release"
def msiPath = "${jobDir}\\Release\\*.msi"
// because batch files suck at handling newline characters, we have to convert to base64 in groovy and back to text in powershell // 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() 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"
} }
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -3,7 +3,7 @@
License for use and distribution 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. 7-Zip Extra files are under the GNU LGPL license.

View File

@@ -1,6 +1,25 @@
7-Zip Extra history 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 9.35 beta 2014-12-07
------------------------------ ------------------------------
- SFX modules were moved to LZMA SDK package. - 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 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. 7-Zip is free software. Read License.txt for more information about license.

View File

@@ -171,13 +171,27 @@ function Upload-GitHubReleaseAsset {
[string] [string]
[Parameter(Mandatory=$true)] [Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication. # The OAuth2 token to use for authentication.
$AuthToken $AuthToken,
[string]
# A short description label for the asset
$Label = ""
) )
$UploadUri = $UploadUri -replace "(\{[\w,\?]*\})$" $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\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning & "$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\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 & "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName

View File

@@ -43,13 +43,8 @@ param (
[string] [string]
[Parameter(Mandatory=$true)] [Parameter(Mandatory=$true)]
# Path to the zip file to upload with the release # Path to the folder which contains release assets to upload
$ZipFilePath, $ReleaseFolderPath,
[string]
[Parameter(Mandatory=$true)]
#Path to the msi file to upload with the release
$MsiFilePath,
[string] [string]
[Parameter(Mandatory=$true)] [Parameter(Mandatory=$true)]
@@ -70,7 +65,17 @@ if ($DescriptionIsBase64Encoded) {
. "$PSScriptRoot\github_functions.ps1" . "$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 $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 $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 $MsiFilePath -ContentType "application/octet-stream" -AuthToken $AuthToken $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) 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" Write-Output "Removing unnecessary files from Release versions"
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "app.publish") -Recurse -Force Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "app.publish") -Recurse -Force
$filesToDelete = Get-ChildItem -Path $TargetDir -Recurse -Include @( $filesToDelete = Get-ChildItem -Path $TargetDir -Recurse -Include @(
"*.pdb",
"*.publish", "*.publish",
"*.xml", "*.xml",
"*.backup", "*.backup",

View File

@@ -13,13 +13,49 @@ param (
) )
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) =====" 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 # Package Zip
if ($ConfigurationName -match "Release" -and $ConfigurationName -match "Portable") { if ($ConfigurationName -eq "Release Portable") {
Write-Output "Packaging Release Portable ZIP" 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 { else {
Write-Output "We will not zip anything - this isnt a portable release build." 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: pull_requests:
do_not_increment_build_number: true do_not_increment_build_number: true
image: Visual Studio 2017 image: Visual Studio 2017
configuration: configuration:
- Release - Release
- Release Portable - Release Portable
- Release Installer
platform: x86 platform: x86
clone_depth: 1 clone_depth: 1
install: install:
@@ -14,7 +15,14 @@ before_build:
build: build:
project: mRemoteV1.sln project: mRemoteV1.sln
verbosity: normal 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: test:
assemblies: assemblies:
only: 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

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

View File

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

View File

@@ -5,6 +5,7 @@ using mRemoteNG.Connection;
using mRemoteNG.Security; using mRemoteNG.Security;
using mRemoteNG.Tree; using mRemoteNG.Tree;
using mRemoteNGTests.TestHelpers; using mRemoteNGTests.TestHelpers;
using NSubstitute;
using NUnit.Framework; using NUnit.Framework;
namespace mRemoteNGTests.Config.Serializers namespace mRemoteNGTests.Config.Serializers
@@ -18,7 +19,7 @@ namespace mRemoteNGTests.Config.Serializers
{ {
var model = CreateConnectionTreeModel(); var model = CreateConnectionTreeModel();
var dataTable = CreateDataTable(model.RootNodes[0]); var dataTable = CreateDataTable(model.RootNodes[0]);
_deserializer = new DataTableDeserializer(); _deserializer = new DataTableDeserializer(Substitute.For<IConnectionsService>());
var output = _deserializer.Deserialize(dataTable); var output = _deserializer.Deserialize(dataTable);
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(model.GetRecursiveChildList().Count())); Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(model.GetRecursiveChildList().Count()));
} }
@@ -27,7 +28,7 @@ namespace mRemoteNGTests.Config.Serializers
public void WeCanDeserializeASingleEntry() public void WeCanDeserializeASingleEntry()
{ {
var dataTable = CreateDataTable(new ConnectionInfo()); var dataTable = CreateDataTable(new ConnectionInfo());
_deserializer = new DataTableDeserializer(); _deserializer = new DataTableDeserializer(Substitute.For<IConnectionsService>());
var output = _deserializer.Deserialize(dataTable); var output = _deserializer.Deserialize(dataTable);
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(1)); Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(1));
} }

View File

@@ -1,8 +1,9 @@
using mRemoteNG.Connection; using mRemoteNG.Connection;
using mRemoteNG.Container;
using NUnit.Framework; using NUnit.Framework;
using System.Reflection;
using System.Collections; using System.Collections;
using System.Linq; using System.Linq;
using System.Reflection;
namespace mRemoteNGTests.Connection namespace mRemoteNGTests.Connection
{ {
@@ -74,6 +75,22 @@ namespace mRemoteNGTests.Connection
Assert.That(hasEverythingInheritedProperty, Is.False); 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() private bool AllInheritancePropertiesAreTrue()
{ {
var allPropertiesTrue = true; var allPropertiesTrue = true;

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,8 @@
using System.Linq; using System;
using mRemoteNG.Config.Serializers; using System.Linq;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Serializers.Xml; using mRemoteNG.Config.Serializers.Xml;
using mRemoteNG.Connection; using mRemoteNG.Connection;
using mRemoteNG.Container; using mRemoteNG.Container;
@@ -7,6 +10,7 @@ using mRemoteNG.Security;
using mRemoteNG.Security.Factories; using mRemoteNG.Security.Factories;
using mRemoteNG.Tree; using mRemoteNG.Tree;
using mRemoteNG.Tree.Root; using mRemoteNG.Tree.Root;
using NSubstitute;
using NUnit.Framework; using NUnit.Framework;
@@ -29,20 +33,20 @@ namespace mRemoteNGTests.IntegrationTests
_originalModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(), _originalModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
new SaveFilter()); new SaveFilter());
_serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer); _serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer);
var mockWindow = Substitute.For<IWin32Window>();
_deserializer = new XmlConnectionsDeserializer(new ConnectionsService(PuttySessionsManager.Instance, new Import(mockWindow), mockWindow), mockWindow);
} }
[TearDown] [TearDown]
public void Teardown() public void Teardown()
{ {
_serializer = null; _serializer = null;
_deserializer = null;
} }
[Test] [Test]
public void SerializeThenDeserialize() public void SerializeThenDeserialize()
{ {
var serializedContent = _serializer.Serialize(_originalModel); var serializedContent = _serializer.Serialize(_originalModel);
_deserializer = new XmlConnectionsDeserializer();
var deserializedModel = _deserializer.Deserialize(serializedContent); var deserializedModel = _deserializer.Deserialize(serializedContent);
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name); var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name); var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
@@ -54,7 +58,6 @@ namespace mRemoteNGTests.IntegrationTests
{ {
_serializer.UseFullEncryption = true; _serializer.UseFullEncryption = true;
var serializedContent = _serializer.Serialize(_originalModel); var serializedContent = _serializer.Serialize(_originalModel);
_deserializer = new XmlConnectionsDeserializer();
var deserializedModel = _deserializer.Deserialize(serializedContent); var deserializedModel = _deserializer.Deserialize(serializedContent);
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name); var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name); var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
@@ -66,7 +69,6 @@ namespace mRemoteNGTests.IntegrationTests
{ {
var originalConnectionInfo = new ConnectionInfo {Name = "con1", Description = "£°úg¶┬ä" }; var originalConnectionInfo = new ConnectionInfo {Name = "con1", Description = "£°úg¶┬ä" };
var serializedContent = _serializer.Serialize(originalConnectionInfo); var serializedContent = _serializer.Serialize(originalConnectionInfo);
_deserializer = new XmlConnectionsDeserializer();
var deserializedModel = _deserializer.Deserialize(serializedContent); var deserializedModel = _deserializer.Deserialize(serializedContent);
var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name); var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name);
Assert.That(deserializedConnectionInfo.Description, Is.EqualTo(originalConnectionInfo.Description)); Assert.That(deserializedConnectionInfo.Description, Is.EqualTo(originalConnectionInfo.Description));
@@ -84,13 +86,26 @@ namespace mRemoteNGTests.IntegrationTests
new SaveFilter()); new SaveFilter());
_serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer); _serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer);
var serializedContent = _serializer.Serialize(_originalModel); var serializedContent = _serializer.Serialize(_originalModel);
_deserializer = new XmlConnectionsDeserializer();
var deserializedModel = _deserializer.Deserialize(serializedContent); var deserializedModel = _deserializer.Deserialize(serializedContent);
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name); var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name); var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
Assert.That(nodeNamesFromDeserializedModel, Is.EquivalentTo(nodeNamesFromOriginalModel)); 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() private ConnectionTreeModel SetupConnectionTreeModel()
{ {
@@ -127,4 +142,4 @@ namespace mRemoteNGTests.IntegrationTests
return connectionTreeModel; return connectionTreeModel;
} }
} }
} }

View File

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

View File

@@ -8,7 +8,7 @@ using mRemoteNG.Connection.Protocol.VNC;
namespace mRemoteNGTests.TestHelpers namespace mRemoteNGTests.TestHelpers
{ {
internal class ConnectionInfoHelpers internal static class ConnectionInfoHelpers
{ {
private static readonly Random _random = new Random(); private static readonly Random _random = new Random();
@@ -128,5 +128,5 @@ namespace mRemoteNGTests.TestHelpers
var values = Enum.GetValues(typeof(T)); var values = Enum.GetValues(typeof(T));
return (T)values.GetValue(_random.Next(values.Length)); return (T)values.GetValue(_random.Next(values.Length));
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,227 @@
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 NSubstitute;
using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
{
public class ConfigWindowGeneralTests
{
private ConfigWindow _configWindow;
[SetUp]
public void Setup()
{
_configWindow = new ConfigWindow(new DockContent(), Substitute.For<IConnectionsService>())
{
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.RedirectClipboard),
nameof(ConnectionInfo.RedirectPorts),
nameof(ConnectionInfo.RedirectSmartCards),
nameof(ConnectionInfo.RedirectSound),
});
break;
case ProtocolType.VNC:
expectedProperties.AddRange(new []
{
nameof(ConnectionInfo.Password),
nameof(ConnectionInfo.Port),
nameof(ConnectionInfo.VNCSmartSizeMode),
nameof(ConnectionInfo.VNCViewOnly),
});
break;
case ProtocolType.SSH1:
case ProtocolType.SSH2:
expectedProperties.AddRange(new []
{
nameof(ConnectionInfo.Username),
nameof(ConnectionInfo.Password),
nameof(ConnectionInfo.Port),
nameof(ConnectionInfo.PuttySession)
});
break;
case ProtocolType.Telnet:
case ProtocolType.Rlogin:
case ProtocolType.RAW:
expectedProperties.AddRange(new[]
{
nameof(ConnectionInfo.Port),
nameof(ConnectionInfo.PuttySession),
});
break;
case ProtocolType.HTTP:
case ProtocolType.HTTPS:
expectedProperties.AddRange(new []
{
nameof(ConnectionInfo.Username),
nameof(ConnectionInfo.Password),
nameof(ConnectionInfo.Port),
nameof(ConnectionInfo.RenderingEngine),
});
break;
case ProtocolType.ICA:
expectedProperties.AddRange(new []
{
nameof(ConnectionInfo.Username),
nameof(ConnectionInfo.Password),
nameof(ConnectionInfo.Domain),
nameof(ConnectionInfo.ICAEncryptionStrength),
nameof(ConnectionInfo.Resolution),
nameof(ConnectionInfo.Colors),
nameof(ConnectionInfo.CacheBitmaps),
});
break;
case ProtocolType.IntApp:
expectedProperties.AddRange(new[]
{
nameof(ConnectionInfo.Username),
nameof(ConnectionInfo.Password),
nameof(ConnectionInfo.Domain),
nameof(ConnectionInfo.Port),
nameof(ConnectionInfo.ExtApp),
});
break;
default:
throw new ArgumentOutOfRangeException(nameof(protocol), protocol, null);
}
return expectedProperties;
}
}
}

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,39 @@
using System.Collections.Generic;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.UI.Window;
using NSubstitute;
using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
{
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(new DockContent(), Substitute.For<IConnectionsService>())
{
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

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

View File

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

View File

@@ -33,16 +33,19 @@ Global
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution 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.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.ActiveCfg = Debug Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.Build.0 = 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.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.ActiveCfg = Debug|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.Build.0 = 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.ActiveCfg = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.Build.0 = Release Portable|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.ActiveCfg = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.Build.0 = 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.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.ActiveCfg = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.Build.0 = 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 {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.ActiveCfg = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.Build.0 = 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.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.ActiveCfg = Debug Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.Build.0 = 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.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.ActiveCfg = Debug|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.Build.0 = 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.ActiveCfg = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.Build.0 = Release Portable|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.ActiveCfg = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.Build.0 = 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.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.ActiveCfg = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.Build.0 = 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.ActiveCfg = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|Any CPU.Build.0 = 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.ActiveCfg = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.Build.0 = 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.ActiveCfg = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.Build.0 = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|x86.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|Any CPU.ActiveCfg = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x86.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.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.Build.0 = 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.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 Portable|x86.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|Any CPU.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 {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 Portable|x86.ActiveCfg = Debug Portable|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|Any CPU.ActiveCfg = Debug|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}.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.ActiveCfg = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.Build.0 = Release Portable|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.ActiveCfg = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.Build.0 = 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 {F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,6 +6,8 @@ using System.Data.SqlClient;
using System.Threading; using System.Threading;
using mRemoteNG.Config.Connections.Multiuser; using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Config.DatabaseConnectors; using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
namespace mRemoteNG.Config.Connections namespace mRemoteNG.Config.Connections
{ {
@@ -13,13 +15,15 @@ namespace mRemoteNG.Config.Connections
{ {
private readonly SqlDatabaseConnector _sqlConnector; private readonly SqlDatabaseConnector _sqlConnector;
private readonly SqlCommand _sqlQuery; private readonly SqlCommand _sqlQuery;
private readonly IConnectionsService _connectionsService;
private DateTime _lastUpdateTime; private DateTime _lastUpdateTime;
private DateTime _lastDatabaseUpdateTime; private DateTime _lastDatabaseUpdateTime;
public SqlConnectionsUpdateChecker(IConnectionsService connectionsService, DatabaseConnectorFactory databaseConnectorFactory)
public SqlConnectionsUpdateChecker()
{ {
_sqlConnector = DatabaseConnectorFactory.SqlDatabaseConnectorFromSettings(); _connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
databaseConnectorFactory.ThrowIfNull(nameof(databaseConnectorFactory));
_sqlConnector = databaseConnectorFactory.SqlDatabaseConnectorFromSettings();
_sqlQuery = new SqlCommand("SELECT * FROM tblUpdate", _sqlConnector.SqlConnection); _sqlQuery = new SqlCommand("SELECT * FROM tblUpdate", _sqlConnector.SqlConnection);
_lastUpdateTime = default(DateTime); _lastUpdateTime = default(DateTime);
_lastDatabaseUpdateTime = default(DateTime); _lastDatabaseUpdateTime = default(DateTime);
@@ -64,7 +68,7 @@ namespace mRemoteNG.Config.Connections
private bool CheckIfIAmTheLastOneUpdated(DateTime lastUpdateInDb) private bool CheckIfIAmTheLastOneUpdated(DateTime lastUpdateInDb)
{ {
DateTime LastSqlUpdateWithoutMilliseconds = new DateTime(Runtime.ConnectionsService.LastSqlUpdate.Ticks - (Runtime.ConnectionsService.LastSqlUpdate.Ticks % TimeSpan.TicksPerSecond), Runtime.ConnectionsService.LastSqlUpdate.Kind); DateTime LastSqlUpdateWithoutMilliseconds = new DateTime(_connectionsService.LastSqlUpdate.Ticks - (_connectionsService.LastSqlUpdate.Ticks % TimeSpan.TicksPerSecond), _connectionsService.LastSqlUpdate.Kind);
return lastUpdateInDb == LastSqlUpdateWithoutMilliseconds; return lastUpdateInDb == LastSqlUpdateWithoutMilliseconds;
} }

View File

@@ -1,15 +1,17 @@
using System; using mRemoteNG.Connection;
using System;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using mRemoteNG.Connection;
namespace mRemoteNG.Config.Connections namespace mRemoteNG.Config.Connections
{ {
public class SaveConnectionsOnEdit public class SaveConnectionsOnEdit
{ {
private readonly ConnectionsService _connectionsService; private readonly IConnectionsService _connectionsService;
public SaveConnectionsOnEdit(ConnectionsService connectionsService) public bool Enabled { get; set; } = true;
public SaveConnectionsOnEdit(IConnectionsService connectionsService)
{ {
if (connectionsService == null) if (connectionsService == null)
throw new ArgumentNullException(nameof(connectionsService)); throw new ArgumentNullException(nameof(connectionsService));
@@ -20,10 +22,9 @@ namespace mRemoteNG.Config.Connections
private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs) private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
{ {
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged; connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged;
connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged; connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel) foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
{ {
oldTree.CollectionChanged -= ConnectionTreeModelOnCollectionChanged; oldTree.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
@@ -45,7 +46,11 @@ namespace mRemoteNG.Config.Connections
{ {
if (!mRemoteNG.Settings.Default.SaveConnectionsAfterEveryEdit) if (!mRemoteNG.Settings.Default.SaveConnectionsAfterEveryEdit)
return; return;
_connectionsService.SaveConnections();
if (!Enabled)
return;
_connectionsService.SaveConnectionsAsync();
} }
} }
} }

View File

@@ -2,20 +2,31 @@
using mRemoteNG.Config.DataProviders; using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers; using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.Versioning; using mRemoteNG.Config.Serializers.Versioning;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
using mRemoteNG.Tree; using mRemoteNG.Tree;
namespace mRemoteNG.Config.Connections namespace mRemoteNG.Config.Connections
{ {
public class SqlConnectionsLoader public class SqlConnectionsLoader
{ {
private readonly DatabaseConnectorFactory _databaseConnectorFactory;
private readonly IConnectionsService _connectionsService;
public SqlConnectionsLoader(DatabaseConnectorFactory databaseConnectorFactory, IConnectionsService connectionsService)
{
_databaseConnectorFactory = databaseConnectorFactory.ThrowIfNull(nameof(databaseConnectorFactory));
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
public ConnectionTreeModel Load() public ConnectionTreeModel Load()
{ {
var connector = DatabaseConnectorFactory.SqlDatabaseConnectorFromSettings(); var connector = _databaseConnectorFactory.SqlDatabaseConnectorFromSettings();
var dataProvider = new SqlDataProvider(connector); var dataProvider = new SqlDataProvider(connector);
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(connector); var databaseVersionVerifier = new SqlDatabaseVersionVerifier(connector);
databaseVersionVerifier.VerifyDatabaseVersion(); databaseVersionVerifier.VerifyDatabaseVersion();
var dataTable = dataProvider.Load(); var dataTable = dataProvider.Load();
var deserializer = new DataTableDeserializer(); var deserializer = new DataTableDeserializer(_connectionsService);
return deserializer.Deserialize(dataTable); return deserializer.Deserialize(dataTable);
} }
} }

View File

@@ -2,13 +2,13 @@
using System.Data.SqlClient; using System.Data.SqlClient;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Security;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.App.Info; using mRemoteNG.App.Info;
using mRemoteNG.Config.DatabaseConnectors; using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.DataProviders; using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers; using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.Versioning; using mRemoteNG.Config.Serializers.Versioning;
using mRemoteNG.Connection;
using mRemoteNG.Container; using mRemoteNG.Container;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Security; using mRemoteNG.Security;
@@ -21,14 +21,15 @@ namespace mRemoteNG.Config.Connections
{ {
public class SqlConnectionsSaver : ISaver<ConnectionTreeModel> public class SqlConnectionsSaver : ISaver<ConnectionTreeModel>
{ {
private SecureString _password = Runtime.EncryptionKey; private readonly IConnectionsService _connectionsService;
private readonly SaveFilter _saveFilter; private readonly SaveFilter _saveFilter;
private readonly DatabaseConnectorFactory _databaseConnectorFactory;
public SqlConnectionsSaver(SaveFilter saveFilter) public SqlConnectionsSaver(SaveFilter saveFilter, IConnectionsService connectionsService, DatabaseConnectorFactory databaseConnectorFactory)
{ {
if (saveFilter == null) _saveFilter = saveFilter.ThrowIfNull(nameof(saveFilter));
throw new ArgumentNullException(nameof(saveFilter)); _databaseConnectorFactory = databaseConnectorFactory.ThrowIfNull(nameof(databaseConnectorFactory));
_saveFilter = saveFilter; _connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
} }
public void Save(ConnectionTreeModel connectionTreeModel) public void Save(ConnectionTreeModel connectionTreeModel)
@@ -40,7 +41,7 @@ namespace mRemoteNG.Config.Connections
} }
using (var sqlConnector = DatabaseConnectorFactory.SqlDatabaseConnectorFromSettings()) using (var sqlConnector = _databaseConnectorFactory.SqlDatabaseConnectorFromSettings())
{ {
sqlConnector.Connect(); sqlConnector.Connect();
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(sqlConnector); var databaseVersionVerifier = new SqlDatabaseVersionVerifier(sqlConnector);
@@ -67,17 +68,17 @@ namespace mRemoteNG.Config.Connections
{ {
if (rootTreeNode.Password) if (rootTreeNode.Password)
{ {
_password = rootTreeNode.PasswordString.ConvertToSecureString(); _connectionsService.EncryptionKey = rootTreeNode.PasswordString.ConvertToSecureString();
strProtected = cryptographyProvider.Encrypt("ThisIsProtected", _password); strProtected = cryptographyProvider.Encrypt("ThisIsProtected", _connectionsService.EncryptionKey);
} }
else else
{ {
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", _password); strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", _connectionsService.EncryptionKey);
} }
} }
else else
{ {
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", _password); strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", _connectionsService.EncryptionKey);
} }
var sqlQuery = new SqlCommand("DELETE FROM tblRoot", sqlDatabaseConnector.SqlConnection); var sqlQuery = new SqlCommand("DELETE FROM tblRoot", sqlDatabaseConnector.SqlConnection);

View File

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

View File

@@ -32,7 +32,7 @@ namespace mRemoteNG.Config.Connections
try try
{ {
var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build(); var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build();
var connectionNodeSerializer = new XmlConnectionNodeSerializer26( var connectionNodeSerializer = new XmlConnectionNodeSerializer27(
cryptographyProvider, cryptographyProvider,
connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(), connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
_saveFilter); _saveFilter);

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,13 @@
using mRemoteNG.Tools;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using mRemoteNG.Tools;
using mRemoteNG.Tree.Root; using mRemoteNG.Tree.Root;
// ReSharper disable ArrangeAccessorOwnerBody // ReSharper disable ArrangeAccessorOwnerBody
namespace mRemoteNG.Config.Putty namespace mRemoteNG.Config.Putty
{ {
public class PuttySessionsManager public class PuttySessionsManager
{ {
public static PuttySessionsManager Instance { get; } = new 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; puttySessionProvider.ThrowIfNull(nameof(puttySessionProvider));
provider.GetSessions();
var rootTreeNode = puttySessionProvider.RootInfo;
puttySessionProvider.GetSessions();
if (!RootPuttySessionsNodes.Contains(rootTreeNode) && rootTreeNode.HasChildren()) if (!RootPuttySessionsNodes.Contains(rootTreeNode) && rootTreeNode.HasChildren())
RootPuttySessionsNodes.Add(rootTreeNode); 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management; using System.Management;
using System.Security.Principal; using System.Security.Principal;
using System.Text; using System.Text;
using System.Web; using System.Web;
using Microsoft.Win32;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Messages;
namespace mRemoteNG.Config.Putty namespace mRemoteNG.Config.Putty
{ {
public class PuttySessionsRegistryProvider : AbstractPuttySessionsProvider public class PuttySessionsRegistryProvider : AbstractPuttySessionsProvider
{ {
private const string PuttySessionsKey = "Software\\SimonTatham\\PuTTY\\Sessions"; private const string PuttySessionsKey = "Software\\SimonTatham\\PuTTY\\Sessions";
private static ManagementEventWatcher _eventWatcher; private static ManagementEventWatcher _eventWatcher;
@@ -39,7 +39,10 @@ namespace mRemoteNG.Config.Putty
} }
public override PuttySessionInfo GetSession(string sessionName) public override PuttySessionInfo GetSession(string sessionName)
{ {
if (string.IsNullOrEmpty(sessionName))
return null;
var sessionsKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey); var sessionsKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey);
var sessionKey = sessionsKey?.OpenSubKey(sessionName); var sessionKey = sessionsKey?.OpenSubKey(sessionName);
if (sessionKey == null) return null; if (sessionKey == null) return null;
@@ -50,10 +53,15 @@ namespace mRemoteNG.Config.Putty
{ {
PuttySession = sessionName, PuttySession = sessionName,
Name = sessionName, Name = sessionName,
Hostname = Convert.ToString(sessionKey.GetValue("HostName")), Hostname = sessionKey.GetValue("HostName")?.ToString() ?? "",
Username = Convert.ToString(sessionKey.GetValue("UserName")) 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()) switch (protocol.ToLowerInvariant())
{ {
case "raw": case "raw":
@@ -65,16 +73,15 @@ namespace mRemoteNG.Config.Putty
case "serial": case "serial":
return null; return null;
case "ssh": case "ssh":
var sshVersionObject = sessionKey.GetValue("SshProt"); int.TryParse(sessionKey.GetValue("SshProt")?.ToString(), out var sshVersion);
if (sshVersionObject != null) /* Per PUTTY.H in PuTTYNG & PuTTYNG Upstream (PuTTY proper currently)
{ * expect 0 for SSH1, 3 for SSH2 ONLY
var sshVersion = Convert.ToInt32(sshVersionObject); * 1 for SSH1 with a 2 fallback
sessionInfo.Protocol = sshVersion >= 2 ? ProtocolType.SSH2 : ProtocolType.SSH1; * 2 for SSH2 with a 1 fallback
} *
else * default to SSH2 if any other value is received
{ */
sessionInfo.Protocol = ProtocolType.SSH2; sessionInfo.Protocol = sshVersion == 1 || sshVersion == 0 ? ProtocolType.SSH1 : ProtocolType.SSH2;
}
break; break;
case "telnet": case "telnet":
sessionInfo.Protocol = ProtocolType.Telnet; sessionInfo.Protocol = ProtocolType.Telnet;
@@ -82,7 +89,12 @@ namespace mRemoteNG.Config.Putty
default: default:
return null; 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; return sessionInfo;
} }

View File

@@ -33,6 +33,7 @@ namespace mRemoteNG.Config.Putty
foreach (var sessionName in Directory.GetFiles(sessionsFolderPath)) foreach (var sessionName in Directory.GetFiles(sessionsFolderPath))
{ {
var sessionFileName = Path.GetFileName(sessionName); var sessionFileName = Path.GetFileName(sessionName);
// ReSharper disable once ConstantConditionalAccessQualifier
sessionNames.Add(raw ? sessionFileName : System.Web.HttpUtility.UrlDecode(sessionFileName?.Replace("+", "%2B"))); sessionNames.Add(raw ? sessionFileName : System.Web.HttpUtility.UrlDecode(sessionFileName?.Replace("+", "%2B")));
} }
@@ -125,9 +126,6 @@ namespace mRemoteNG.Config.Putty
public override void StartWatcher() public override void StartWatcher()
{ {
PuttySessionsRegistryProvider.StartWatcher();
PuttySessionsRegistryProvider.PuttySessionChanged += OnRegistrySessionChanged;
if (_eventWatcher != null) if (_eventWatcher != null)
{ {
return; return;
@@ -136,18 +134,22 @@ namespace mRemoteNG.Config.Putty
try try
{ {
var sessionsFolderPath = GetSessionsFolderPath(); var sessionsFolderPath = GetSessionsFolderPath();
if (Directory.Exists(sessionsFolderPath))
{ if (!Directory.Exists(sessionsFolderPath))
_eventWatcher = new FileSystemWatcher(sessionsFolderPath) {
{ Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"XmingPortablePuttySessions.Watcher.StartWatching() failed: '{sessionsFolderPath}' does not exist.", true);
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite return;
}; }
_eventWatcher.Changed += OnFileSystemEventArrived;
_eventWatcher.Created += OnFileSystemEventArrived; _eventWatcher = new FileSystemWatcher(sessionsFolderPath)
_eventWatcher.Deleted += OnFileSystemEventArrived; {
_eventWatcher.Renamed += OnFileSystemEventArrived; NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite
_eventWatcher.EnableRaisingEvents = true; };
} _eventWatcher.Changed += OnFileSystemEventArrived;
_eventWatcher.Created += OnFileSystemEventArrived;
_eventWatcher.Deleted += OnFileSystemEventArrived;
_eventWatcher.Renamed += OnFileSystemEventArrived;
_eventWatcher.EnableRaisingEvents = true;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -173,7 +175,8 @@ namespace mRemoteNG.Config.Putty
private static string GetPuttyConfPath() private static string GetPuttyConfPath()
{ {
var puttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath ? mRemoteNG.Settings.Default.CustomPuttyPath : App.Info.GeneralAppInfo.PuttyPath; 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() private static string GetSessionsFolderPath()
@@ -200,6 +203,9 @@ namespace mRemoteNG.Config.Putty
private static PuttySessionInfo ModifyRegistrySessionInfo(PuttySessionInfo sessionInfo) private static PuttySessionInfo ModifyRegistrySessionInfo(PuttySessionInfo sessionInfo)
{ {
if (sessionInfo == null)
return null;
sessionInfo.Name = string.Format(RegistrySessionNameFormat, sessionInfo.Name); sessionInfo.Name = string.Format(RegistrySessionNameFormat, sessionInfo.Name);
sessionInfo.PuttySession = string.Format(RegistrySessionNameFormat, sessionInfo.PuttySession); sessionInfo.PuttySession = string.Format(RegistrySessionNameFormat, sessionInfo.PuttySession);
return sessionInfo; return sessionInfo;

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,6 +13,7 @@ using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Container; using mRemoteNG.Container;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Security; using mRemoteNG.Security;
using mRemoteNG.Tools;
using mRemoteNG.Tree; using mRemoteNG.Tree;
using mRemoteNG.Tree.Root; using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
@@ -20,19 +21,23 @@ using mRemoteNG.UI.TaskDialog;
namespace mRemoteNG.Config.Serializers.Xml namespace mRemoteNG.Config.Serializers.Xml
{ {
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel> public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
{ {
private readonly IConnectionsService _connectionsService;
private XmlDocument _xmlDocument; private XmlDocument _xmlDocument;
private double _confVersion; private double _confVersion;
private XmlConnectionsDecryptor _decryptor; private XmlConnectionsDecryptor _decryptor;
private string ConnectionFileName = ""; private string ConnectionFileName = "";
private const double MaxSupportedConfVersion = 2.8; private const double MaxSupportedConfVersion = 2.8;
private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection); private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection);
private readonly IWin32Window _dialogWindowParent;
public Func<SecureString> AuthenticationRequestor { get; set; } public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
public XmlConnectionsDeserializer(Func<SecureString> authenticationRequestor = null) public XmlConnectionsDeserializer(IConnectionsService connectionsService, IWin32Window dialogWindowParent, Func<Optional<SecureString>> authenticationRequestor = null)
{ {
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
_dialogWindowParent = dialogWindowParent.ThrowIfNull(nameof(dialogWindowParent));
AuthenticationRequestor = authenticationRequestor; AuthenticationRequestor = authenticationRequestor;
} }
@@ -47,8 +52,6 @@ namespace mRemoteNG.Config.Serializers.Xml
{ {
LoadXmlConnectionData(xml); LoadXmlConnectionData(xml);
ValidateConnectionFileVersion(); ValidateConnectionFileVersion();
if (!import)
Runtime.ConnectionsService.IsConnectionsFileLoaded = false;
var rootXmlElement = _xmlDocument.DocumentElement; var rootXmlElement = _xmlDocument.DocumentElement;
InitializeRootNode(rootXmlElement); InitializeRootNode(rootXmlElement);
@@ -62,8 +65,6 @@ namespace mRemoteNG.Config.Serializers.Xml
var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value; var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value;
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString())) if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString()))
{ {
mRemoteNG.Settings.Default.LoadConsFromCustomLocation = false;
mRemoteNG.Settings.Default.CustomConsPath = "";
return null; return null;
} }
} }
@@ -81,13 +82,13 @@ namespace mRemoteNG.Config.Serializers.Xml
AddNodesFromXmlRecursive(_xmlDocument.DocumentElement, _rootNodeInfo); AddNodesFromXmlRecursive(_xmlDocument.DocumentElement, _rootNodeInfo);
if (!import) if (!import)
Runtime.ConnectionsService.IsConnectionsFileLoaded = true; _connectionsService.IsConnectionsFileLoaded = true;
return connectionTreeModel; return connectionTreeModel;
} }
catch (Exception ex) catch (Exception ex)
{ {
Runtime.ConnectionsService.IsConnectionsFileLoaded = false; _connectionsService.IsConnectionsFileLoaded = false;
Runtime.MessageCollector.AddExceptionStackTrace(Language.strLoadFromXmlFailed, ex); Runtime.MessageCollector.AddExceptionStackTrace(Language.strLoadFromXmlFailed, ex);
throw; throw;
} }
@@ -117,7 +118,7 @@ namespace mRemoteNG.Config.Serializers.Xml
private void ShowIncompatibleVersionDialogBox() private void ShowIncompatibleVersionDialogBox()
{ {
CTaskDialog.ShowTaskDialogBox( CTaskDialog.ShowTaskDialogBox(
FrmMain.Default, _dialogWindowParent,
Application.ProductName, Application.ProductName,
"Incompatible connection file format", "Incompatible connection file format",
$"The format of this connection file is not supported. Please upgrade to a newer version of {Application.ProductName}.", $"The format of this connection file is not supported. Please upgrade to a newer version of {Application.ProductName}.",
@@ -208,7 +209,9 @@ namespace mRemoteNG.Config.Serializers.Xml
{ {
if (xmlnode.Attributes == null) return null; 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); var connectionInfo = new ConnectionInfo(connectionId);
try try
@@ -286,14 +289,14 @@ namespace mRemoteNG.Config.Serializers.Xml
if (_confVersion >= 0.5) if (_confVersion >= 0.5)
{ {
connectionInfo.RedirectDiskDrives = bool.Parse(xmlnode.Attributes["RedirectDiskDrives"].Value); connectionInfo.RedirectDiskDrives = bool.Parse(xmlnode.Attributes["RedirectDiskDrives"].Value);
connectionInfo.RedirectPrinters = bool.Parse(xmlnode.Attributes["RedirectPrinters"].Value); connectionInfo.RedirectPrinters = bool.Parse(xmlnode.Attributes["RedirectPrinters"].Value);
connectionInfo.RedirectPorts = bool.Parse(xmlnode.Attributes["RedirectPorts"].Value); connectionInfo.RedirectPorts = bool.Parse(xmlnode.Attributes["RedirectPorts"].Value);
connectionInfo.RedirectSmartCards = bool.Parse(xmlnode.Attributes["RedirectSmartCards"].Value); connectionInfo.RedirectSmartCards = bool.Parse(xmlnode.Attributes["RedirectSmartCards"].Value);
} }
else else
{ {
connectionInfo.RedirectDiskDrives = false; connectionInfo.RedirectDiskDrives = false;
connectionInfo.RedirectPrinters = false; connectionInfo.RedirectPrinters = false;
connectionInfo.RedirectPorts = false; connectionInfo.RedirectPorts = false;
connectionInfo.RedirectSmartCards = false; connectionInfo.RedirectSmartCards = false;
} }
@@ -509,6 +512,11 @@ namespace mRemoteNG.Config.Serializers.Xml
connectionInfo.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["RDPAlertIdleTimeout"]?.Value ?? "False"); connectionInfo.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["RDPAlertIdleTimeout"]?.Value ?? "False");
connectionInfo.Inheritance.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPAlertIdleTimeout"]?.Value ?? "False"); connectionInfo.Inheritance.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPAlertIdleTimeout"]?.Value ?? "False");
} }
if(_confVersion >= 2.7)
{
connectionInfo.RedirectClipboard = bool.Parse(xmlnode.Attributes["RedirectClipboard"].Value);
connectionInfo.Inheritance.RedirectClipboard = bool.Parse(xmlnode.Attributes["InheritRedirectClipboard"].Value);
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -10,18 +10,26 @@ using mRemoteNG.Connection.Protocol.ICA;
using mRemoteNG.Connection.Protocol.RDP; using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Connection.Protocol.VNC; using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Container; using mRemoteNG.Container;
using mRemoteNG.Tools;
using mRemoteNG.Tree; using mRemoteNG.Tree;
using mRemoteNG.Tree.Root; using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Serializers namespace mRemoteNG.Config.Serializers
{ {
public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel> public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel>
{ {
public ConnectionTreeModel Deserialize(DataTable table) private readonly IConnectionsService _connectionsService;
public DataTableDeserializer(IConnectionsService connectionsService)
{
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
}
public ConnectionTreeModel Deserialize(DataTable table)
{ {
var connectionList = CreateNodesFromTable(table); var connectionList = CreateNodesFromTable(table);
var connectionTreeModel = CreateNodeHierarchy(connectionList, table); var connectionTreeModel = CreateNodeHierarchy(connectionList, table);
Runtime.ConnectionsService.IsConnectionsFileLoaded = true; _connectionsService.IsConnectionsFileLoaded = true;
return connectionTreeModel; return connectionTreeModel;
} }
@@ -101,6 +109,7 @@ namespace mRemoteNG.Config.Serializers
connectionInfo.RedirectDiskDrives = (bool)dataRow["RedirectDiskDrives"]; connectionInfo.RedirectDiskDrives = (bool)dataRow["RedirectDiskDrives"];
connectionInfo.RedirectPorts = (bool)dataRow["RedirectPorts"]; connectionInfo.RedirectPorts = (bool)dataRow["RedirectPorts"];
connectionInfo.RedirectPrinters = (bool)dataRow["RedirectPrinters"]; connectionInfo.RedirectPrinters = (bool)dataRow["RedirectPrinters"];
connectionInfo.RedirectClipboard = (bool)dataRow["RedirectClipboard"];
connectionInfo.RedirectSmartCards = (bool)dataRow["RedirectSmartCards"]; connectionInfo.RedirectSmartCards = (bool)dataRow["RedirectSmartCards"];
connectionInfo.RedirectSound = (RdpProtocol.RDPSounds)Enum.Parse(typeof(RdpProtocol.RDPSounds), (string)dataRow["RedirectSound"]); connectionInfo.RedirectSound = (RdpProtocol.RDPSounds)Enum.Parse(typeof(RdpProtocol.RDPSounds), (string)dataRow["RedirectSound"]);
connectionInfo.SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), (string)dataRow["SoundQuality"]); connectionInfo.SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), (string)dataRow["SoundQuality"]);
@@ -147,6 +156,7 @@ namespace mRemoteNG.Config.Serializers
connectionInfo.Inheritance.RedirectKeys = (bool)dataRow["InheritRedirectKeys"]; connectionInfo.Inheritance.RedirectKeys = (bool)dataRow["InheritRedirectKeys"];
connectionInfo.Inheritance.RedirectPorts = (bool)dataRow["InheritRedirectPorts"]; connectionInfo.Inheritance.RedirectPorts = (bool)dataRow["InheritRedirectPorts"];
connectionInfo.Inheritance.RedirectPrinters = (bool)dataRow["InheritRedirectPrinters"]; connectionInfo.Inheritance.RedirectPrinters = (bool)dataRow["InheritRedirectPrinters"];
connectionInfo.Inheritance.RedirectClipboard = (bool)dataRow["InheritRedirectClipboard"];
connectionInfo.Inheritance.RedirectSmartCards = (bool)dataRow["InheritRedirectSmartCards"]; connectionInfo.Inheritance.RedirectSmartCards = (bool)dataRow["InheritRedirectSmartCards"];
connectionInfo.Inheritance.RedirectSound = (bool)dataRow["InheritRedirectSound"]; connectionInfo.Inheritance.RedirectSound = (bool)dataRow["InheritRedirectSound"];
connectionInfo.Inheritance.SoundQuality = (bool)dataRow["InheritSoundQuality"]; connectionInfo.Inheritance.SoundQuality = (bool)dataRow["InheritSoundQuality"];

View File

@@ -91,6 +91,7 @@ namespace mRemoteNG.Config.Serializers
dataTable.Columns.Add("RedirectDiskDrives", typeof(bool)); dataTable.Columns.Add("RedirectDiskDrives", typeof(bool));
dataTable.Columns.Add("RedirectPorts", typeof(bool)); dataTable.Columns.Add("RedirectPorts", typeof(bool));
dataTable.Columns.Add("RedirectPrinters", typeof(bool)); dataTable.Columns.Add("RedirectPrinters", typeof(bool));
dataTable.Columns.Add("RedirectClipboard", typeof(bool));
dataTable.Columns.Add("RedirectSmartCards", typeof(bool)); dataTable.Columns.Add("RedirectSmartCards", typeof(bool));
dataTable.Columns.Add("RedirectSound", typeof(string)); dataTable.Columns.Add("RedirectSound", typeof(string));
dataTable.Columns.Add("RedirectKeys", typeof(bool)); dataTable.Columns.Add("RedirectKeys", typeof(bool));
@@ -135,6 +136,7 @@ namespace mRemoteNG.Config.Serializers
dataTable.Columns.Add("InheritRedirectKeys", typeof(bool)); dataTable.Columns.Add("InheritRedirectKeys", typeof(bool));
dataTable.Columns.Add("InheritRedirectPorts", typeof(bool)); dataTable.Columns.Add("InheritRedirectPorts", typeof(bool));
dataTable.Columns.Add("InheritRedirectPrinters", typeof(bool)); dataTable.Columns.Add("InheritRedirectPrinters", typeof(bool));
dataTable.Columns.Add("InheritRedirectClipboard", typeof(bool));
dataTable.Columns.Add("InheritRedirectSmartCards", typeof(bool)); dataTable.Columns.Add("InheritRedirectSmartCards", typeof(bool));
dataTable.Columns.Add("InheritRedirectSound", typeof(bool)); dataTable.Columns.Add("InheritRedirectSound", typeof(bool));
dataTable.Columns.Add("InheritResolution", typeof(bool)); dataTable.Columns.Add("InheritResolution", typeof(bool));
@@ -235,6 +237,7 @@ namespace mRemoteNG.Config.Serializers
dataRow["RedirectDiskDrives"] = connectionInfo.RedirectDiskDrives; dataRow["RedirectDiskDrives"] = connectionInfo.RedirectDiskDrives;
dataRow["RedirectPorts"] = connectionInfo.RedirectPorts; dataRow["RedirectPorts"] = connectionInfo.RedirectPorts;
dataRow["RedirectPrinters"] = connectionInfo.RedirectPrinters; dataRow["RedirectPrinters"] = connectionInfo.RedirectPrinters;
dataRow["RedirectClipboard"] = connectionInfo.RedirectClipboard;
dataRow["RedirectSmartCards"] = connectionInfo.RedirectSmartCards; dataRow["RedirectSmartCards"] = connectionInfo.RedirectSmartCards;
dataRow["RedirectSound"] = connectionInfo.RedirectSound; dataRow["RedirectSound"] = connectionInfo.RedirectSound;
dataRow["SoundQuality"] = connectionInfo.SoundQuality; dataRow["SoundQuality"] = connectionInfo.SoundQuality;
@@ -282,6 +285,7 @@ namespace mRemoteNG.Config.Serializers
dataRow["InheritRedirectKeys"] = connectionInfo.Inheritance.RedirectKeys; dataRow["InheritRedirectKeys"] = connectionInfo.Inheritance.RedirectKeys;
dataRow["InheritRedirectPorts"] = connectionInfo.Inheritance.RedirectPorts; dataRow["InheritRedirectPorts"] = connectionInfo.Inheritance.RedirectPorts;
dataRow["InheritRedirectPrinters"] = connectionInfo.Inheritance.RedirectPrinters; dataRow["InheritRedirectPrinters"] = connectionInfo.Inheritance.RedirectPrinters;
dataRow["InheritRedirectClipboard"] = connectionInfo.Inheritance.RedirectClipboard;
dataRow["InheritRedirectSmartCards"] = connectionInfo.Inheritance.RedirectSmartCards; dataRow["InheritRedirectSmartCards"] = connectionInfo.Inheritance.RedirectSmartCards;
dataRow["InheritRedirectSound"] = connectionInfo.Inheritance.RedirectSound; dataRow["InheritRedirectSound"] = connectionInfo.Inheritance.RedirectSound;
dataRow["InheritSoundQuality"] = connectionInfo.Inheritance.SoundQuality; dataRow["InheritSoundQuality"] = connectionInfo.Inheritance.SoundQuality;
@@ -339,6 +343,7 @@ namespace mRemoteNG.Config.Serializers
dataRow["InheritRedirectKeys"] = false; dataRow["InheritRedirectKeys"] = false;
dataRow["InheritRedirectPorts"] = false; dataRow["InheritRedirectPorts"] = false;
dataRow["InheritRedirectPrinters"] = false; dataRow["InheritRedirectPrinters"] = false;
dataRow["InheritRedirectClipboard"] = false;
dataRow["InheritRedirectSmartCards"] = false; dataRow["InheritRedirectSmartCards"] = false;
dataRow["InheritRedirectSound"] = false; dataRow["InheritRedirectSound"] = false;
dataRow["InheritSoundQuality"] = false; dataRow["InheritSoundQuality"] = false;

View File

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

View File

@@ -1,5 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Xml; using System.Xml;
using mRemoteNG.Connection; using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
@@ -7,8 +9,6 @@ using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Container; using mRemoteNG.Container;
using mRemoteNG.Tree; using mRemoteNG.Tree;
using mRemoteNG.Tree.Root; using mRemoteNG.Tree.Root;
using System.Security.Cryptography;
using System.Text;
namespace mRemoteNG.Config.Serializers namespace mRemoteNG.Config.Serializers
@@ -60,7 +60,7 @@ namespace mRemoteNG.Config.Serializers
} }
else else
{ {
var versionNode = rdcManNode.SelectSingleNode("./version")?.InnerText; var versionNode = rdcManNode?.SelectSingleNode("./version")?.InnerText;
if (versionNode != null) if (versionNode != null)
{ {
var version = new Version(versionNode); var version = new Version(versionNode);
@@ -101,15 +101,16 @@ namespace mRemoteNG.Config.Serializers
{ {
if (_schemaVersion == 1) 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"); containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties");
} }
var newContainer = new ContainerInfo(); var newContainer = new ContainerInfo();
var connectionInfo = ConnectionInfoFromXml(containerPropertiesNode); var connectionInfo = ConnectionInfoFromXml(containerPropertiesNode);
newContainer.CopyFrom(connectionInfo); newContainer.CopyFrom(connectionInfo);
if (_schemaVersion == 3) if (_schemaVersion == 3)
{ {
// Program Verison 2.7 wraps these properties // Program Version 2.7 wraps these properties
containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties"); containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties");
} }
newContainer.Name = containerPropertiesNode?.SelectSingleNode("./name")?.InnerText ?? Language.strNewFolder; newContainer.Name = containerPropertiesNode?.SelectSingleNode("./name")?.InnerText ?? Language.strNewFolder;
@@ -130,20 +131,22 @@ namespace mRemoteNG.Config.Serializers
var propertiesNode = xmlNode.SelectSingleNode("./properties"); var propertiesNode = xmlNode.SelectSingleNode("./properties");
if (_schemaVersion == 1) propertiesNode = xmlNode; // Version 2.2 defines the container name at the root instead if (_schemaVersion == 1) propertiesNode = xmlNode; // Version 2.2 defines the container name at the root instead
connectionInfo.Hostname = propertiesNode.SelectSingleNode("./name")?.InnerText; connectionInfo.Hostname = propertiesNode?.SelectSingleNode("./name")?.InnerText ?? "";
connectionInfo.Name = propertiesNode.SelectSingleNode("./displayName")?.InnerText ?? connectionInfo.Hostname; connectionInfo.Name = propertiesNode?.SelectSingleNode("./displayName")?.InnerText ?? connectionInfo.Hostname;
connectionInfo.Description = propertiesNode.SelectSingleNode("./comment")?.InnerText ?? String.Empty; connectionInfo.Description = propertiesNode?.SelectSingleNode("./comment")?.InnerText ?? string.Empty;
var logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials"); var logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials");
if (logonCredentialsNode?.Attributes?["inherit"].Value == "None") if (logonCredentialsNode?.Attributes?["inherit"]?.Value == "None")
{ {
connectionInfo.Username = logonCredentialsNode.SelectSingleNode("userName")?.InnerText; connectionInfo.Username = logonCredentialsNode.SelectSingleNode("userName")?.InnerText;
var passwordNode = logonCredentialsNode.SelectSingleNode("./password"); var passwordNode = logonCredentialsNode.SelectSingleNode("./password");
if (_schemaVersion == 1) // Version 2.2 allows clear text passwords 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 else
{ {
@@ -160,7 +163,7 @@ namespace mRemoteNG.Config.Serializers
} }
var connectionSettingsNode = xmlNode.SelectSingleNode("./connectionSettings"); 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"); connectionInfo.UseConsoleSession = bool.Parse(connectionSettingsNode.SelectSingleNode("./connectToConsole")?.InnerText ?? "false");
// ./startProgram // ./startProgram
@@ -174,7 +177,7 @@ namespace mRemoteNG.Config.Serializers
} }
var gatewaySettingsNode = xmlNode.SelectSingleNode("./gatewaySettings"); 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.RDGatewayUsageMethod = gatewaySettingsNode.SelectSingleNode("./enabled")?.InnerText == "True" ? RdpProtocol.RDGatewayUsageMethod.Always : RdpProtocol.RDGatewayUsageMethod.Never;
connectionInfo.RDGatewayHostname = gatewaySettingsNode.SelectSingleNode("./hostName")?.InnerText; connectionInfo.RDGatewayHostname = gatewaySettingsNode.SelectSingleNode("./hostName")?.InnerText;
@@ -198,7 +201,7 @@ namespace mRemoteNG.Config.Serializers
} }
var remoteDesktopNode = xmlNode.SelectSingleNode("./remoteDesktop"); var remoteDesktopNode = xmlNode.SelectSingleNode("./remoteDesktop");
if (remoteDesktopNode?.Attributes?["inherit"].Value == "None") if (remoteDesktopNode?.Attributes?["inherit"]?.Value == "None")
{ {
var resolutionString = remoteDesktopNode.SelectSingleNode("./size")?.InnerText.Replace(" ", ""); var resolutionString = remoteDesktopNode.SelectSingleNode("./size")?.InnerText.Replace(" ", "");
try try
@@ -231,7 +234,7 @@ namespace mRemoteNG.Config.Serializers
} }
var localResourcesNode = xmlNode.SelectSingleNode("./localResources"); var localResourcesNode = xmlNode.SelectSingleNode("./localResources");
if (localResourcesNode?.Attributes?["inherit"].Value == "None") if (localResourcesNode?.Attributes?["inherit"]?.Value == "None")
{ {
// ReSharper disable once SwitchStatementMissingSomeCases // ReSharper disable once SwitchStatementMissingSomeCases
switch (localResourcesNode.SelectSingleNode("./audioRedirection")?.InnerText) switch (localResourcesNode.SelectSingleNode("./audioRedirection")?.InnerText)
@@ -271,10 +274,11 @@ namespace mRemoteNG.Config.Serializers
} }
// ./redirectClipboard // ./redirectClipboard
connectionInfo.RedirectDiskDrives = bool.Parse(localResourcesNode.SelectSingleNode("./redirectDrives")?.InnerText ?? "false"); connectionInfo.RedirectDiskDrives = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectDrives")?.InnerText ?? "false");
connectionInfo.RedirectPorts = bool.Parse(localResourcesNode.SelectSingleNode("./redirectPorts")?.InnerText ?? "false"); connectionInfo.RedirectPorts = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectPorts")?.InnerText ?? "false");
connectionInfo.RedirectPrinters = bool.Parse(localResourcesNode.SelectSingleNode("./redirectPrinters")?.InnerText ?? "false"); connectionInfo.RedirectPrinters = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectPrinters")?.InnerText ?? "false");
connectionInfo.RedirectSmartCards = bool.Parse(localResourcesNode.SelectSingleNode("./redirectSmartCards")?.InnerText ?? "false"); connectionInfo.RedirectSmartCards = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectSmartCards")?.InnerText ?? "false");
connectionInfo.RedirectClipboard = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectClipboard")?.InnerText ?? "false");
} }
else else
{ {
@@ -284,10 +288,11 @@ namespace mRemoteNG.Config.Serializers
connectionInfo.Inheritance.RedirectPorts = true; connectionInfo.Inheritance.RedirectPorts = true;
connectionInfo.Inheritance.RedirectPrinters = true; connectionInfo.Inheritance.RedirectPrinters = true;
connectionInfo.Inheritance.RedirectSmartCards = true; connectionInfo.Inheritance.RedirectSmartCards = true;
connectionInfo.Inheritance.RedirectClipboard = true;
} }
var securitySettingsNode = xmlNode.SelectSingleNode("./securitySettings"); var securitySettingsNode = xmlNode.SelectSingleNode("./securitySettings");
if (securitySettingsNode?.Attributes?["inherit"].Value == "None") if (securitySettingsNode?.Attributes?["inherit"]?.Value == "None")
{ {
// ReSharper disable once SwitchStatementMissingSomeCases // ReSharper disable once SwitchStatementMissingSomeCases
switch (securitySettingsNode.SelectSingleNode("./authentication")?.InnerText) switch (securitySettingsNode.SelectSingleNode("./authentication")?.InnerText)
@@ -321,7 +326,7 @@ namespace mRemoteNG.Config.Serializers
private static string DecryptRdcManPassword(string ciphertext) private static string DecryptRdcManPassword(string ciphertext)
{ {
if (string.IsNullOrEmpty(ciphertext)) if (string.IsNullOrEmpty(ciphertext))
return null; return string.Empty;
try try
{ {
@@ -332,7 +337,7 @@ namespace mRemoteNG.Config.Serializers
catch (Exception /*ex*/) catch (Exception /*ex*/)
{ {
//Runtime.MessageCollector.AddExceptionMessage("RemoteDesktopConnectionManager.DecryptPassword() failed.", ex, logOnly: true); //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.Authentication;
using mRemoteNG.Security.Factories; using mRemoteNG.Security.Factories;
using mRemoteNG.Security.SymmetricEncryption; using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using mRemoteNG.Tree.Root; using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Serializers namespace mRemoteNG.Config.Serializers
@@ -13,7 +14,7 @@ namespace mRemoteNG.Config.Serializers
private readonly ICryptographyProvider _cryptographyProvider; private readonly ICryptographyProvider _cryptographyProvider;
private readonly RootNodeInfo _rootNodeInfo; private readonly RootNodeInfo _rootNodeInfo;
public Func<SecureString> AuthenticationRequestor { get; set; } public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
public int KeyDerivationIterations public int KeyDerivationIterations
{ {
@@ -91,16 +92,14 @@ namespace mRemoteNG.Config.Serializers
private bool Authenticate(string cipherText, SecureString password) private bool Authenticate(string cipherText, SecureString password)
{ {
var authenticator = new PasswordAuthenticator(_cryptographyProvider, cipherText) var authenticator = new PasswordAuthenticator(_cryptographyProvider, cipherText, AuthenticationRequestor);
{
AuthenticationRequestor = AuthenticationRequestor
};
var authenticated = authenticator.Authenticate(password); var authenticated = authenticator.Authenticate(password);
if (!authenticated) return authenticated; if (!authenticated)
return false;
_rootNodeInfo.PasswordString = authenticator.LastAuthenticatedPassword.ConvertToUnsecureString(); _rootNodeInfo.PasswordString = authenticator.LastAuthenticatedPassword.ConvertToUnsecureString();
return authenticated; return true;
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,37 +1,37 @@
/// The MIT License (MIT) // The MIT License (MIT)
/// //
/// Copyright(c) crdx // Copyright(c) crdx
/// //
/// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
/// a copy of this software and associated documentation files (the // a copy of this software and associated documentation files (the
/// "Software"), to deal in the Software without restriction, including // "Software"), to deal in the Software without restriction, including
/// without limitation the rights to use, copy, modify, merge, publish, // without limitation the rights to use, copy, modify, merge, publish,
/// distribute, sublicense, and/or sell copies of the Software, and to // distribute, sublicense, and/or sell copies of the Software, and to
/// permit persons to whom the Software is furnished to do so, subject to // permit persons to whom the Software is furnished to do so, subject to
/// the following conditions: // the following conditions:
/// //
/// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
/// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
/// //
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
/// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
/// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
/// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
/// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
/// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
/// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/// //
/// https://raw.githubusercontent.com/crdx/PortableSettingsProvider // https://raw.githubusercontent.com/crdx/PortableSettingsProvider
/// //
using System.Linq;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Configuration; using System.Configuration;
using System.Windows.Forms; using System.Windows.Forms;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Xml; using System.Xml;
using System.IO; using System.IO;
//using mRemoteNG.App;
namespace mRemoteNG.Config.Settings.Providers namespace mRemoteNG.Config.Settings.Providers
{ {
@@ -43,63 +43,34 @@ namespace mRemoteNG.Config.Settings.Providers
private const string _className = "PortableSettingsProvider"; private const string _className = "PortableSettingsProvider";
private XmlDocument _xmlDocument; private XmlDocument _xmlDocument;
private string _filePath private string _filePath => Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? throw new InvalidOperationException(), $"{ApplicationName}.settings");
{
get
{
return Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),
string.Format("{0}.settings", ApplicationName));
}
}
private XmlNode _localSettingsNode private XmlNode _localSettingsNode => GetSettingsNode(_localSettingsNodeName);
{
get
{
XmlNode settingsNode = GetSettingsNode(_localSettingsNodeName);
XmlNode machineNode = settingsNode.SelectSingleNode(Environment.MachineName.ToLowerInvariant());
if (machineNode == null) private XmlNode _globalSettingsNode => GetSettingsNode(_globalSettingsNodeName);
{
machineNode = _rootDocument.CreateElement(Environment.MachineName.ToLowerInvariant());
settingsNode.AppendChild(machineNode);
}
return machineNode; private XmlNode _rootNode => _rootDocument.SelectSingleNode(_rootNodeName);
}
}
private XmlNode _globalSettingsNode
{
get { return GetSettingsNode(_globalSettingsNodeName); }
}
private XmlNode _rootNode
{
get { return _rootDocument.SelectSingleNode(_rootNodeName); }
}
private XmlDocument _rootDocument private XmlDocument _rootDocument
{ {
get get
{ {
if (_xmlDocument == null) if (_xmlDocument != null) return _xmlDocument;
try
{ {
try _xmlDocument = new XmlDocument();
{ _xmlDocument.Load(_filePath);
_xmlDocument = new XmlDocument();
_xmlDocument.Load(_filePath);
}
catch (Exception)
{
}
if (_xmlDocument.SelectSingleNode(_rootNodeName) != null)
return _xmlDocument;
_xmlDocument = GetBlankXmlDocument();
} }
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; return _xmlDocument;
} }
@@ -107,14 +78,11 @@ namespace mRemoteNG.Config.Settings.Providers
public override string ApplicationName public override string ApplicationName
{ {
get { return Path.GetFileNameWithoutExtension(Application.ExecutablePath); } get => Path.GetFileNameWithoutExtension(Application.ExecutablePath);
set { } set { }
} }
public override string Name public override string Name => _className;
{
get { return _className; }
}
public override void Initialize(string name, NameValueCollection config) 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) public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
{ {
SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); var values = new SettingsPropertyValueCollection();
foreach (SettingsProperty property in collection) foreach (SettingsProperty property in collection)
{ {
@@ -158,11 +126,9 @@ namespace mRemoteNG.Config.Settings.Providers
private void SetValue(SettingsPropertyValue propertyValue) private void SetValue(SettingsPropertyValue propertyValue)
{ {
XmlNode targetNode = IsGlobal(propertyValue.Property) var targetNode = IsGlobal(propertyValue.Property) ? _globalSettingsNode : _localSettingsNode;
? _globalSettingsNode
: _localSettingsNode;
XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[@name='{0}']", propertyValue.Name)); var settingNode = targetNode.SelectSingleNode($"setting[@name='{propertyValue.Name}']");
if (settingNode != null) if (settingNode != null)
settingNode.InnerText = propertyValue.SerializedValue.ToString(); settingNode.InnerText = propertyValue.SerializedValue.ToString();
@@ -170,10 +136,10 @@ namespace mRemoteNG.Config.Settings.Providers
{ {
settingNode = _rootDocument.CreateElement("setting"); settingNode = _rootDocument.CreateElement("setting");
XmlAttribute nameAttribute = _rootDocument.CreateAttribute("name"); var nameAttribute = _rootDocument.CreateAttribute("name");
nameAttribute.Value = propertyValue.Name; nameAttribute.Value = propertyValue.Name;
settingNode.Attributes.Append(nameAttribute); settingNode.Attributes?.Append(nameAttribute);
settingNode.InnerText = propertyValue.SerializedValue.ToString(); settingNode.InnerText = propertyValue.SerializedValue.ToString();
targetNode.AppendChild(settingNode); targetNode.AppendChild(settingNode);
@@ -182,8 +148,8 @@ namespace mRemoteNG.Config.Settings.Providers
private string GetValue(SettingsProperty property) private string GetValue(SettingsProperty property)
{ {
XmlNode targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode; var targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode;
XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[@name='{0}']", property.Name)); var settingNode = targetNode.SelectSingleNode($"setting[@name='{property.Name}']");
if (settingNode == null) if (settingNode == null)
return property.DefaultValue != null ? property.DefaultValue.ToString() : string.Empty; return property.DefaultValue != null ? property.DefaultValue.ToString() : string.Empty;
@@ -191,7 +157,7 @@ namespace mRemoteNG.Config.Settings.Providers
return settingNode.InnerText; return settingNode.InnerText;
} }
private bool IsGlobal(SettingsProperty property) private static bool IsGlobal(SettingsProperty property)
{ {
foreach (DictionaryEntry attribute in property.Attributes) foreach (DictionaryEntry attribute in property.Attributes)
{ {
@@ -204,20 +170,18 @@ namespace mRemoteNG.Config.Settings.Providers
private XmlNode GetSettingsNode(string name) private XmlNode GetSettingsNode(string name)
{ {
XmlNode settingsNode = _rootNode.SelectSingleNode(name); var settingsNode = _rootNode.SelectSingleNode(name);
if (settingsNode == null) if (settingsNode != null) return settingsNode;
{ settingsNode = _rootDocument.CreateElement(name);
settingsNode = _rootDocument.CreateElement(name); _rootNode.AppendChild(settingsNode);
_rootNode.AppendChild(settingsNode);
}
return 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.CreateXmlDeclaration("1.0", "utf-8", string.Empty));
blankXmlDocument.AppendChild(blankXmlDocument.CreateElement(_rootNodeName)); blankXmlDocument.AppendChild(blankXmlDocument.CreateElement(_rootNodeName));

View File

@@ -19,11 +19,12 @@ namespace mRemoteNG.Config.Settings
{ {
private readonly ExternalAppsLoader _externalAppsLoader; private readonly ExternalAppsLoader _externalAppsLoader;
private readonly MessageCollector _messageCollector; private readonly MessageCollector _messageCollector;
private readonly MenuStrip _mainMenu;
private readonly QuickConnectToolStrip _quickConnectToolStrip; private readonly QuickConnectToolStrip _quickConnectToolStrip;
private readonly ExternalToolsToolStrip _externalToolsToolStrip; private readonly ExternalToolsToolStrip _externalToolsToolStrip;
private readonly MultiSshToolStrip _multiSshToolStrip; private readonly MultiSshToolStrip _multiSshToolStrip;
private readonly Func<NotificationAreaIcon> _notificationAreaIconBuilder;
private FrmMain MainForm { get; } private readonly FrmMain _frmMain;
public SettingsLoader( public SettingsLoader(
@@ -31,26 +32,20 @@ namespace mRemoteNG.Config.Settings
MessageCollector messageCollector, MessageCollector messageCollector,
QuickConnectToolStrip quickConnectToolStrip, QuickConnectToolStrip quickConnectToolStrip,
ExternalToolsToolStrip externalToolsToolStrip, ExternalToolsToolStrip externalToolsToolStrip,
MultiSshToolStrip multiSshToolStrip) MultiSshToolStrip multiSshToolStrip,
ExternalAppsLoader externalAppsLoader,
Func<NotificationAreaIcon> notificationAreaIconBuilder,
MenuStrip mainMenu)
{ {
if (mainForm == null) _frmMain = mainForm.ThrowIfNull(nameof(mainForm));
throw new ArgumentNullException(nameof(mainForm)); _messageCollector = messageCollector.ThrowIfNull(nameof(messageCollector));
if (messageCollector == null) _quickConnectToolStrip = quickConnectToolStrip.ThrowIfNull(nameof(quickConnectToolStrip));
throw new ArgumentNullException(nameof(messageCollector)); _externalToolsToolStrip = externalToolsToolStrip.ThrowIfNull(nameof(externalToolsToolStrip));
if (quickConnectToolStrip == null) _multiSshToolStrip = multiSshToolStrip.ThrowIfNull(nameof(multiSshToolStrip));
throw new ArgumentNullException(nameof(quickConnectToolStrip)); _externalAppsLoader = externalAppsLoader.ThrowIfNull(nameof(externalAppsLoader));
if (externalToolsToolStrip == null) _notificationAreaIconBuilder = notificationAreaIconBuilder.ThrowIfNull(nameof(notificationAreaIconBuilder));
throw new ArgumentNullException(nameof(externalToolsToolStrip)); _mainMenu = mainMenu.ThrowIfNull(nameof(mainMenu));
if (multiSshToolStrip == null) }
throw new ArgumentNullException(nameof(multiSshToolStrip));
MainForm = mainForm;
_messageCollector = messageCollector;
_quickConnectToolStrip = quickConnectToolStrip;
_externalToolsToolStrip = externalToolsToolStrip;
_multiSshToolStrip = multiSshToolStrip;
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip);
}
#region Public Methods #region Public Methods
public void LoadSettings() public void LoadSettings()
@@ -80,10 +75,10 @@ namespace mRemoteNG.Config.Settings
} }
} }
private static void SetAlwaysShowPanelTabs() private void SetAlwaysShowPanelTabs()
{ {
if (mRemoteNG.Settings.Default.AlwaysShowPanelTabs) if (mRemoteNG.Settings.Default.AlwaysShowPanelTabs)
FrmMain.Default.pnlDock.DocumentStyle = DocumentStyle.DockingWindow; _frmMain.pnlDock.DocumentStyle = DocumentStyle.DockingWindow;
} }
@@ -98,32 +93,32 @@ namespace mRemoteNG.Config.Settings
private void SetApplicationWindowPositionAndSize() private void SetApplicationWindowPositionAndSize()
{ {
MainForm.WindowState = FormWindowState.Normal; _frmMain.WindowState = FormWindowState.Normal;
if (mRemoteNG.Settings.Default.MainFormState == FormWindowState.Normal) if (mRemoteNG.Settings.Default.MainFormState == FormWindowState.Normal)
{ {
if (!mRemoteNG.Settings.Default.MainFormLocation.IsEmpty) if (!mRemoteNG.Settings.Default.MainFormLocation.IsEmpty)
MainForm.Location = mRemoteNG.Settings.Default.MainFormLocation; _frmMain.Location = mRemoteNG.Settings.Default.MainFormLocation;
if (!mRemoteNG.Settings.Default.MainFormSize.IsEmpty) if (!mRemoteNG.Settings.Default.MainFormSize.IsEmpty)
MainForm.Size = mRemoteNG.Settings.Default.MainFormSize; _frmMain.Size = mRemoteNG.Settings.Default.MainFormSize;
} }
else else
{ {
if (!mRemoteNG.Settings.Default.MainFormRestoreLocation.IsEmpty) if (!mRemoteNG.Settings.Default.MainFormRestoreLocation.IsEmpty)
MainForm.Location = mRemoteNG.Settings.Default.MainFormRestoreLocation; _frmMain.Location = mRemoteNG.Settings.Default.MainFormRestoreLocation;
if (!mRemoteNG.Settings.Default.MainFormRestoreSize.IsEmpty) if (!mRemoteNG.Settings.Default.MainFormRestoreSize.IsEmpty)
MainForm.Size = mRemoteNG.Settings.Default.MainFormRestoreSize; _frmMain.Size = mRemoteNG.Settings.Default.MainFormRestoreSize;
} }
if (mRemoteNG.Settings.Default.MainFormState == FormWindowState.Maximized) if (mRemoteNG.Settings.Default.MainFormState == FormWindowState.Maximized)
{ {
MainForm.WindowState = FormWindowState.Maximized; _frmMain.WindowState = FormWindowState.Maximized;
} }
// Make sure the form is visible on the screen // Make sure the form is visible on the screen
const int minHorizontal = 300; const int minHorizontal = 300;
const int minVertical = 150; const int minVertical = 150;
var screenBounds = Screen.FromHandle(MainForm.Handle).Bounds; var screenBounds = Screen.FromHandle(_frmMain.Handle).Bounds;
var newBounds = MainForm.Bounds; var newBounds = _frmMain.Bounds;
if (newBounds.Right < screenBounds.Left + minHorizontal) if (newBounds.Right < screenBounds.Left + minHorizontal)
newBounds.X = screenBounds.Left + minHorizontal - newBounds.Width; newBounds.X = screenBounds.Left + minHorizontal - newBounds.Width;
@@ -134,29 +129,29 @@ namespace mRemoteNG.Config.Settings
if (newBounds.Top > screenBounds.Bottom - minVertical) if (newBounds.Top > screenBounds.Bottom - minVertical)
newBounds.Y = screenBounds.Bottom - minVertical; newBounds.Y = screenBounds.Bottom - minVertical;
MainForm.Location = newBounds.Location; _frmMain.Location = newBounds.Location;
} }
private void SetAutoSave() private void SetAutoSave()
{ {
if (mRemoteNG.Settings.Default.AutoSaveEveryMinutes <= 0) return; if (mRemoteNG.Settings.Default.AutoSaveEveryMinutes <= 0) return;
MainForm.tmrAutoSave.Interval = mRemoteNG.Settings.Default.AutoSaveEveryMinutes * 60000; _frmMain.tmrAutoSave.Interval = mRemoteNG.Settings.Default.AutoSaveEveryMinutes * 60000;
MainForm.tmrAutoSave.Enabled = true; _frmMain.tmrAutoSave.Enabled = true;
} }
private void SetKioskMode() private void SetKioskMode()
{ {
if (!mRemoteNG.Settings.Default.MainFormKiosk) return; if (!mRemoteNG.Settings.Default.MainFormKiosk) return;
MainForm.Fullscreen.Value = true; _frmMain.Fullscreen.Value = true;
} }
private static void SetShowSystemTrayIcon() private void SetShowSystemTrayIcon()
{ {
if (mRemoteNG.Settings.Default.ShowSystemTrayIcon) if (mRemoteNG.Settings.Default.ShowSystemTrayIcon)
Runtime.NotificationAreaIcon = new NotificationAreaIcon(); Runtime.NotificationAreaIcon = _notificationAreaIconBuilder();
} }
private static void SetPuttyPath() private void SetPuttyPath()
{ {
PuttyBase.PuttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath ? mRemoteNG.Settings.Default.CustomPuttyPath : GeneralAppInfo.PuttyPath; PuttyBase.PuttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath ? mRemoteNG.Settings.Default.CustomPuttyPath : GeneralAppInfo.PuttyPath;
} }
@@ -197,6 +192,7 @@ namespace mRemoteNG.Config.Settings
private void LoadToolbarsFromSettings() private void LoadToolbarsFromSettings()
{ {
ResetAllToolbarLocations(); ResetAllToolbarLocations();
AddMainMenuPanel();
AddExternalAppsPanel(); AddExternalAppsPanel();
AddQuickConnectPanel(); AddQuickConnectPanel();
AddMultiSshPanel(); AddMultiSshPanel();
@@ -210,46 +206,64 @@ namespace mRemoteNG.Config.Settings
private void ResetAllToolbarLocations() private void ResetAllToolbarLocations()
{ {
var tempToolStrip = new ToolStripPanel(); var tempToolStrip = new ToolStripPanel();
tempToolStrip.Join(_mainMenu);
tempToolStrip.Join(_quickConnectToolStrip); tempToolStrip.Join(_quickConnectToolStrip);
tempToolStrip.Join(_externalToolsToolStrip); tempToolStrip.Join(_externalToolsToolStrip);
tempToolStrip.Join(_multiSshToolStrip); tempToolStrip.Join(_multiSshToolStrip);
} }
private void AddMainMenuPanel()
{
SetToolstripGripStyle(_mainMenu);
var toolStripPanel = ToolStripPanelFromString("top");
toolStripPanel.Join(_mainMenu, new Point(3, 0));
}
private void AddQuickConnectPanel() private void AddQuickConnectPanel()
{ {
SetToolstripGripStyle(_quickConnectToolStrip);
_quickConnectToolStrip.Visible = mRemoteNG.Settings.Default.QuickyTBVisible;
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.QuickyTBParentDock); var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.QuickyTBParentDock);
toolStripPanel.Join(_quickConnectToolStrip, mRemoteNG.Settings.Default.QuickyTBLocation); toolStripPanel.Join(_quickConnectToolStrip, mRemoteNG.Settings.Default.QuickyTBLocation);
_quickConnectToolStrip.Visible = mRemoteNG.Settings.Default.QuickyTBVisible;
} }
private void AddExternalAppsPanel() private void AddExternalAppsPanel()
{ {
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock); SetToolstripGripStyle(_externalToolsToolStrip);
toolStripPanel.Join(_externalToolsToolStrip, mRemoteNG.Settings.Default.ExtAppsTBLocation);
_externalToolsToolStrip.Visible = mRemoteNG.Settings.Default.ExtAppsTBVisible; _externalToolsToolStrip.Visible = mRemoteNG.Settings.Default.ExtAppsTBVisible;
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock);
toolStripPanel.Join(_externalToolsToolStrip, mRemoteNG.Settings.Default.ExtAppsTBLocation);
} }
private void AddMultiSshPanel() private void AddMultiSshPanel()
{ {
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock); SetToolstripGripStyle(_multiSshToolStrip);
toolStripPanel.Join(_multiSshToolStrip, mRemoteNG.Settings.Default.MultiSshToolbarLocation);
_multiSshToolStrip.Visible = mRemoteNG.Settings.Default.MultiSshToolbarVisible; _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) private ToolStripPanel ToolStripPanelFromString(string panel)
{ {
switch (panel.ToLower()) switch (panel.ToLower())
{ {
case "top": case "top":
return MainForm.tsContainer.TopToolStripPanel; return _frmMain.tsContainer.TopToolStripPanel;
case "bottom": case "bottom":
return MainForm.tsContainer.BottomToolStripPanel; return _frmMain.tsContainer.BottomToolStripPanel;
case "left": case "left":
return MainForm.tsContainer.LeftToolStripPanel; return _frmMain.tsContainer.LeftToolStripPanel;
case "right": case "right":
return MainForm.tsContainer.RightToolStripPanel; return _frmMain.tsContainer.RightToolStripPanel;
default: default:
return MainForm.tsContainer.TopToolStripPanel; return _frmMain.tsContainer.TopToolStripPanel;
} }
} }
@@ -259,4 +273,4 @@ namespace mRemoteNG.Config.Settings
} }
#endregion #endregion
} }
} }

View File

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

View File

@@ -57,6 +57,7 @@ namespace mRemoteNG.Connection
private bool _redirectKeys; private bool _redirectKeys;
private bool _redirectDiskDrives; private bool _redirectDiskDrives;
private bool _redirectPrinters; private bool _redirectPrinters;
private bool _redirectClipboard;
private bool _redirectPorts; private bool _redirectPorts;
private bool _redirectSmartCards; private bool _redirectSmartCards;
private RdpProtocol.RDPSounds _redirectSound; private RdpProtocol.RDPSounds _redirectSound;
@@ -87,8 +88,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionName")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionName")]
public virtual string Name public virtual string Name
{ {
get { return _name; } get => _name;
set { SetField(ref _name, value, "Name"); } set => SetField(ref _name, value, "Name");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
@@ -96,8 +97,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDescription")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDescription")]
public virtual string Description public virtual string Description
{ {
get { return GetPropertyValue("Description", _description); } get => GetPropertyValue("Description", _description);
set { SetField(ref _description, value, "Description"); } set => SetField(ref _description, value, "Description");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
@@ -106,8 +107,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionIcon")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionIcon")]
public virtual string Icon public virtual string Icon
{ {
get { return GetPropertyValue("Icon", _icon); } get => GetPropertyValue("Icon", _icon);
set { SetField(ref _icon, value, "Icon"); } set => SetField(ref _icon, value, "Icon");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"), [LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
@@ -115,8 +116,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPanel")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPanel")]
public virtual string Panel public virtual string Panel
{ {
get { return GetPropertyValue("Panel", _panel); } get => GetPropertyValue("Panel", _panel);
set { SetField(ref _panel, value, "Panel"); } set => SetField(ref _panel, value, "Panel");
} }
#endregion #endregion
@@ -126,8 +127,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAddress")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAddress")]
public virtual string Hostname public virtual string Hostname
{ {
get { return _hostname.Trim(); } get => _hostname.Trim();
set { SetField(ref _hostname, value?.Trim(), "Hostname"); } set => SetField(ref _hostname, value?.Trim(), "Hostname");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2), [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
@@ -135,8 +136,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUsername")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUsername")]
public virtual string Username public virtual string Username
{ {
get { return GetPropertyValue("Username", _username); } get => GetPropertyValue("Username", _username);
set { SetField(ref _username, value?.Trim(), "Username"); } set => SetField(ref _username, value?.Trim(), "Username");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2), [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
@@ -145,8 +146,8 @@ namespace mRemoteNG.Connection
PasswordPropertyText(true)] PasswordPropertyText(true)]
public virtual string Password public virtual string Password
{ {
get { return GetPropertyValue("Password", _password); } get => GetPropertyValue("Password", _password);
set { SetField(ref _password, value, "Password"); } set => SetField(ref _password, value, "Password");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2), [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
@@ -154,8 +155,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDomain")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDomain")]
public string Domain public string Domain
{ {
get { return GetPropertyValue("Domain", _domain).Trim(); } get => GetPropertyValue("Domain", _domain).Trim();
set { SetField(ref _domain, value?.Trim(), "Domain"); } set => SetField(ref _domain, value?.Trim(), "Domain");
} }
#endregion #endregion
@@ -166,8 +167,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public virtual ProtocolType Protocol public virtual ProtocolType Protocol
{ {
get { return GetPropertyValue("Protocol", _protocol); } get => GetPropertyValue("Protocol", _protocol);
set { SetField(ref _protocol, value, "Protocol"); } set => SetField(ref _protocol, value, "Protocol");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -176,8 +177,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(ExternalToolsTypeConverter))] TypeConverter(typeof(ExternalToolsTypeConverter))]
public string ExtApp public string ExtApp
{ {
get { return GetPropertyValue("ExtApp", _extApp); } get => GetPropertyValue("ExtApp", _extApp);
set { SetField(ref _extApp, value, "ExtApp"); } set => SetField(ref _extApp, value, "ExtApp");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -185,8 +186,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPort")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPort")]
public virtual int Port public virtual int Port
{ {
get { return GetPropertyValue("Port", _port); } get => GetPropertyValue("Port", _port);
set { SetField(ref _port, value, "Port"); } set => SetField(ref _port, value, "Port");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -195,8 +196,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(Config.Putty.PuttySessionsManager.SessionList))] TypeConverter(typeof(Config.Putty.PuttySessionsManager.SessionList))]
public virtual string PuttySession public virtual string PuttySession
{ {
get { return GetPropertyValue("PuttySession", _puttySession); } get => GetPropertyValue("PuttySession", _puttySession);
set { SetField(ref _puttySession, value, "PuttySession"); } set => SetField(ref _puttySession, value, "PuttySession");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -205,8 +206,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public IcaProtocol.EncryptionStrength ICAEncryptionStrength public IcaProtocol.EncryptionStrength ICAEncryptionStrength
{ {
get { return GetPropertyValue("ICAEncryptionStrength", _icaEncryption); } get => GetPropertyValue("ICAEncryptionStrength", _icaEncryption);
set { SetField(ref _icaEncryption, value, "ICAEncryptionStrength"); } set => SetField(ref _icaEncryption, value, "ICAEncryptionStrength");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -215,8 +216,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool UseConsoleSession public bool UseConsoleSession
{ {
get { return GetPropertyValue("UseConsoleSession", _useConsoleSession); } get => GetPropertyValue("UseConsoleSession", _useConsoleSession);
set { SetField(ref _useConsoleSession, value, "UseConsoleSession"); } set => SetField(ref _useConsoleSession, value, "UseConsoleSession");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -225,8 +226,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.AuthenticationLevel RDPAuthenticationLevel public RdpProtocol.AuthenticationLevel RDPAuthenticationLevel
{ {
get { return GetPropertyValue("RDPAuthenticationLevel", _rdpAuthenticationLevel); } get => GetPropertyValue("RDPAuthenticationLevel", _rdpAuthenticationLevel);
set { SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel"); } set => SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -234,7 +235,7 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPMinutesToIdleTimeout")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPMinutesToIdleTimeout")]
public virtual int RDPMinutesToIdleTimeout public virtual int RDPMinutesToIdleTimeout
{ {
get { return GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout); } get => GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout);
set { set {
if(value < 0) if(value < 0)
value = 0; value = 0;
@@ -249,8 +250,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPAlertIdleTimeout")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPAlertIdleTimeout")]
public bool RDPAlertIdleTimeout public bool RDPAlertIdleTimeout
{ {
get { return GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout); } get => GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout);
set { SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout"); } set => SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -258,8 +259,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionLoadBalanceInfo")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionLoadBalanceInfo")]
public string LoadBalanceInfo public string LoadBalanceInfo
{ {
get { return GetPropertyValue("LoadBalanceInfo", _loadBalanceInfo).Trim(); } get => GetPropertyValue("LoadBalanceInfo", _loadBalanceInfo).Trim();
set { SetField(ref _loadBalanceInfo, value?.Trim(), "LoadBalanceInfo"); } set => SetField(ref _loadBalanceInfo, value?.Trim(), "LoadBalanceInfo");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -268,8 +269,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public HTTPBase.RenderingEngine RenderingEngine public HTTPBase.RenderingEngine RenderingEngine
{ {
get { return GetPropertyValue("RenderingEngine", _renderingEngine); } get => GetPropertyValue("RenderingEngine", _renderingEngine);
set { SetField(ref _renderingEngine, value, "RenderingEngine"); } set => SetField(ref _renderingEngine, value, "RenderingEngine");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3), [LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
@@ -278,8 +279,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool UseCredSsp public bool UseCredSsp
{ {
get { return GetPropertyValue("UseCredSsp", _useCredSsp); } get => GetPropertyValue("UseCredSsp", _useCredSsp);
set { SetField(ref _useCredSsp, value, "UseCredSsp"); } set => SetField(ref _useCredSsp, value, "UseCredSsp");
} }
#endregion #endregion
@@ -290,8 +291,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDGatewayUsageMethod RDGatewayUsageMethod public RdpProtocol.RDGatewayUsageMethod RDGatewayUsageMethod
{ {
get { return GetPropertyValue("RDGatewayUsageMethod", _rdGatewayUsageMethod); } get => GetPropertyValue("RDGatewayUsageMethod", _rdGatewayUsageMethod);
set { SetField(ref _rdGatewayUsageMethod, value, "RDGatewayUsageMethod"); } set => SetField(ref _rdGatewayUsageMethod, value, "RDGatewayUsageMethod");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
@@ -299,8 +300,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayHostname")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayHostname")]
public string RDGatewayHostname public string RDGatewayHostname
{ {
get { return GetPropertyValue("RDGatewayHostname", _rdGatewayHostname).Trim(); } get => GetPropertyValue("RDGatewayHostname", _rdGatewayHostname).Trim();
set { SetField(ref _rdGatewayHostname, value?.Trim(), "RDGatewayHostname"); } set => SetField(ref _rdGatewayHostname, value?.Trim(), "RDGatewayHostname");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
@@ -309,8 +310,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDGatewayUseConnectionCredentials RDGatewayUseConnectionCredentials public RdpProtocol.RDGatewayUseConnectionCredentials RDGatewayUseConnectionCredentials
{ {
get { return GetPropertyValue("RDGatewayUseConnectionCredentials", _rdGatewayUseConnectionCredentials); } get => GetPropertyValue("RDGatewayUseConnectionCredentials", _rdGatewayUseConnectionCredentials);
set { SetField(ref _rdGatewayUseConnectionCredentials, value, "RDGatewayUseConnectionCredentials"); } set => SetField(ref _rdGatewayUseConnectionCredentials, value, "RDGatewayUseConnectionCredentials");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
@@ -318,8 +319,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUsername")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUsername")]
public string RDGatewayUsername public string RDGatewayUsername
{ {
get { return GetPropertyValue("RDGatewayUsername", _rdGatewayUsername).Trim(); } get => GetPropertyValue("RDGatewayUsername", _rdGatewayUsername).Trim();
set { SetField(ref _rdGatewayUsername, value?.Trim(), "RDGatewayUsername"); } set => SetField(ref _rdGatewayUsername, value?.Trim(), "RDGatewayUsername");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
@@ -328,8 +329,8 @@ namespace mRemoteNG.Connection
PasswordPropertyText(true)] PasswordPropertyText(true)]
public string RDGatewayPassword public string RDGatewayPassword
{ {
get { return GetPropertyValue("RDGatewayPassword", _rdGatewayPassword); } get => GetPropertyValue("RDGatewayPassword", _rdGatewayPassword);
set { SetField(ref _rdGatewayPassword, value, "RDGatewayPassword"); } set => SetField(ref _rdGatewayPassword, value, "RDGatewayPassword");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4), [LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
@@ -337,8 +338,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayDomain")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayDomain")]
public string RDGatewayDomain public string RDGatewayDomain
{ {
get { return GetPropertyValue("RDGatewayDomain", _rdGatewayDomain).Trim(); } get => GetPropertyValue("RDGatewayDomain", _rdGatewayDomain).Trim();
set { SetField(ref _rdGatewayDomain, value?.Trim(), "RDGatewayDomain"); } set => SetField(ref _rdGatewayDomain, value?.Trim(), "RDGatewayDomain");
} }
#endregion #endregion
@@ -349,8 +350,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDPResolutions Resolution public RdpProtocol.RDPResolutions Resolution
{ {
get { return GetPropertyValue("Resolution", _resolution); } get => GetPropertyValue("Resolution", _resolution);
set { SetField(ref _resolution, value, "Resolution"); } set => SetField(ref _resolution, value, "Resolution");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -359,8 +360,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool AutomaticResize public bool AutomaticResize
{ {
get { return GetPropertyValue("AutomaticResize", _automaticResize); } get => GetPropertyValue("AutomaticResize", _automaticResize);
set { SetField(ref _automaticResize, value, "AutomaticResize"); } set => SetField(ref _automaticResize, value, "AutomaticResize");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -369,8 +370,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDPColors Colors public RdpProtocol.RDPColors Colors
{ {
get { return GetPropertyValue("Colors", _colors); } get => GetPropertyValue("Colors", _colors);
set { SetField(ref _colors, value, "Colors"); } set => SetField(ref _colors, value, "Colors");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -379,8 +380,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool CacheBitmaps public bool CacheBitmaps
{ {
get { return GetPropertyValue("CacheBitmaps", _cacheBitmaps); } get => GetPropertyValue("CacheBitmaps", _cacheBitmaps);
set { SetField(ref _cacheBitmaps, value, "CacheBitmaps"); } set => SetField(ref _cacheBitmaps, value, "CacheBitmaps");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -389,8 +390,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool DisplayWallpaper public bool DisplayWallpaper
{ {
get { return GetPropertyValue("DisplayWallpaper", _displayWallpaper); } get => GetPropertyValue("DisplayWallpaper", _displayWallpaper);
set { SetField(ref _displayWallpaper, value, "DisplayWallpaper"); } set => SetField(ref _displayWallpaper, value, "DisplayWallpaper");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -399,8 +400,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool DisplayThemes public bool DisplayThemes
{ {
get { return GetPropertyValue("DisplayThemes", _displayThemes); } get => GetPropertyValue("DisplayThemes", _displayThemes);
set { SetField(ref _displayThemes, value, "DisplayThemes"); } set => SetField(ref _displayThemes, value, "DisplayThemes");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -409,8 +410,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool EnableFontSmoothing public bool EnableFontSmoothing
{ {
get { return GetPropertyValue("EnableFontSmoothing", _enableFontSmoothing); } get => GetPropertyValue("EnableFontSmoothing", _enableFontSmoothing);
set { SetField(ref _enableFontSmoothing, value, "EnableFontSmoothing"); } set => SetField(ref _enableFontSmoothing, value, "EnableFontSmoothing");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -419,8 +420,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool EnableDesktopComposition public bool EnableDesktopComposition
{ {
get { return GetPropertyValue("EnableDesktopComposition", _enableDesktopComposition); } get => GetPropertyValue("EnableDesktopComposition", _enableDesktopComposition);
set { SetField(ref _enableDesktopComposition, value, "EnableDesktopComposition"); } set => SetField(ref _enableDesktopComposition, value, "EnableDesktopComposition");
} }
#endregion #endregion
@@ -431,8 +432,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectKeys public bool RedirectKeys
{ {
get { return GetPropertyValue("RedirectKeys", _redirectKeys); } get => GetPropertyValue("RedirectKeys", _redirectKeys);
set { SetField(ref _redirectKeys, value, "RedirectKeys"); } set => SetField(ref _redirectKeys, value, "RedirectKeys");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -441,8 +442,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectDiskDrives public bool RedirectDiskDrives
{ {
get { return GetPropertyValue("RedirectDiskDrives", _redirectDiskDrives); } get => GetPropertyValue("RedirectDiskDrives", _redirectDiskDrives);
set { SetField(ref _redirectDiskDrives, value, "RedirectDiskDrives"); } set => SetField(ref _redirectDiskDrives, value, "RedirectDiskDrives");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -451,8 +452,18 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectPrinters public bool RedirectPrinters
{ {
get { return GetPropertyValue("RedirectPrinters", _redirectPrinters); } get => GetPropertyValue("RedirectPrinters", _redirectPrinters);
set { SetField(ref _redirectPrinters, value, "RedirectPrinters"); } set => SetField(ref _redirectPrinters, value, "RedirectPrinters");
}
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameRedirectClipboard"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRedirectClipboard"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectClipboard
{
get { return GetPropertyValue("RedirectClipboard", _redirectClipboard); }
set { SetField(ref _redirectClipboard, value, "RedirectClipboard"); }
} }
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -461,8 +472,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectPorts public bool RedirectPorts
{ {
get { return GetPropertyValue("RedirectPorts", _redirectPorts); } get => GetPropertyValue("RedirectPorts", _redirectPorts);
set { SetField(ref _redirectPorts, value, "RedirectPorts"); } set => SetField(ref _redirectPorts, value, "RedirectPorts");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -471,8 +482,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool RedirectSmartCards public bool RedirectSmartCards
{ {
get { return GetPropertyValue("RedirectSmartCards", _redirectSmartCards); } get => GetPropertyValue("RedirectSmartCards", _redirectSmartCards);
set { SetField(ref _redirectSmartCards, value, "RedirectSmartCards"); } set => SetField(ref _redirectSmartCards, value, "RedirectSmartCards");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -481,8 +492,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDPSounds RedirectSound public RdpProtocol.RDPSounds RedirectSound
{ {
get { return GetPropertyValue("RedirectSound", _redirectSound); } get => GetPropertyValue("RedirectSound", _redirectSound);
set { SetField(ref _redirectSound, value, "RedirectSound"); } set => SetField(ref _redirectSound, value, "RedirectSound");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6), [LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
@@ -491,8 +502,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public RdpProtocol.RDPSoundQuality SoundQuality public RdpProtocol.RDPSoundQuality SoundQuality
{ {
get { return GetPropertyValue("SoundQuality", _soundQuality); } get => GetPropertyValue("SoundQuality", _soundQuality);
set { SetField(ref _soundQuality, value, "SoundQuality"); } set => SetField(ref _soundQuality, value, "SoundQuality");
} }
#endregion #endregion
@@ -506,8 +517,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(ExternalToolsTypeConverter))] TypeConverter(typeof(ExternalToolsTypeConverter))]
public virtual string PreExtApp public virtual string PreExtApp
{ {
get { return GetPropertyValue("PreExtApp", _preExtApp); } get => GetPropertyValue("PreExtApp", _preExtApp);
set { SetField(ref _preExtApp, value, "PreExtApp"); } set => SetField(ref _preExtApp, value, "PreExtApp");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -516,8 +527,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(ExternalToolsTypeConverter))] TypeConverter(typeof(ExternalToolsTypeConverter))]
public virtual string PostExtApp public virtual string PostExtApp
{ {
get { return GetPropertyValue("PostExtApp", _postExtApp); } get => GetPropertyValue("PostExtApp", _postExtApp);
set { SetField(ref _postExtApp, value, "PostExtApp"); } set => SetField(ref _postExtApp, value, "PostExtApp");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -525,8 +536,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionMACAddress")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionMACAddress")]
public virtual string MacAddress public virtual string MacAddress
{ {
get { return GetPropertyValue("MacAddress", _macAddress); } get => GetPropertyValue("MacAddress", _macAddress);
set { SetField(ref _macAddress, value, "MacAddress"); } set => SetField(ref _macAddress, value, "MacAddress");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -534,8 +545,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUser1")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUser1")]
public virtual string UserField public virtual string UserField
{ {
get { return GetPropertyValue("UserField", _userField); } get => GetPropertyValue("UserField", _userField);
set { SetField(ref _userField, value, "UserField"); } set => SetField(ref _userField, value, "UserField");
} }
#endregion #endregion
@@ -547,8 +558,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.Compression VNCCompression public ProtocolVNC.Compression VNCCompression
{ {
get { return GetPropertyValue("VNCCompression", _vncCompression); } get => GetPropertyValue("VNCCompression", _vncCompression);
set { SetField(ref _vncCompression, value, "VNCCompression"); } set => SetField(ref _vncCompression, value, "VNCCompression");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -558,8 +569,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.Encoding VNCEncoding public ProtocolVNC.Encoding VNCEncoding
{ {
get { return GetPropertyValue("VNCEncoding", _vncEncoding); } get => GetPropertyValue("VNCEncoding", _vncEncoding);
set { SetField(ref _vncEncoding, value, "VNCEncoding"); } set => SetField(ref _vncEncoding, value, "VNCEncoding");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2), [LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
@@ -569,8 +580,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.AuthMode VNCAuthMode public ProtocolVNC.AuthMode VNCAuthMode
{ {
get { return GetPropertyValue("VNCAuthMode", _vncAuthMode); } get => GetPropertyValue("VNCAuthMode", _vncAuthMode);
set { SetField(ref _vncAuthMode, value, "VNCAuthMode"); } set => SetField(ref _vncAuthMode, value, "VNCAuthMode");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -580,8 +591,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.ProxyType VNCProxyType public ProtocolVNC.ProxyType VNCProxyType
{ {
get { return GetPropertyValue("VNCProxyType", _vncProxyType); } get => GetPropertyValue("VNCProxyType", _vncProxyType);
set { SetField(ref _vncProxyType, value, "VNCProxyType"); } set => SetField(ref _vncProxyType, value, "VNCProxyType");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -590,8 +601,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyAddress")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyAddress")]
public string VNCProxyIP public string VNCProxyIP
{ {
get { return GetPropertyValue("VNCProxyIP", _vncProxyIp); } get => GetPropertyValue("VNCProxyIP", _vncProxyIp);
set { SetField(ref _vncProxyIp, value, "VNCProxyIP"); } set => SetField(ref _vncProxyIp, value, "VNCProxyIP");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -600,8 +611,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyPort")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyPort")]
public int VNCProxyPort public int VNCProxyPort
{ {
get { return GetPropertyValue("VNCProxyPort", _vncProxyPort); } get => GetPropertyValue("VNCProxyPort", _vncProxyPort);
set { SetField(ref _vncProxyPort, value, "VNCProxyPort"); } set => SetField(ref _vncProxyPort, value, "VNCProxyPort");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -610,8 +621,8 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyUsername")] LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyUsername")]
public string VNCProxyUsername public string VNCProxyUsername
{ {
get { return GetPropertyValue("VNCProxyUsername", _vncProxyUsername); } get => GetPropertyValue("VNCProxyUsername", _vncProxyUsername);
set { SetField(ref _vncProxyUsername, value, "VNCProxyUsername"); } set => SetField(ref _vncProxyUsername, value, "VNCProxyUsername");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7), [LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
@@ -621,8 +632,8 @@ namespace mRemoteNG.Connection
PasswordPropertyText(true)] PasswordPropertyText(true)]
public string VNCProxyPassword public string VNCProxyPassword
{ {
get { return GetPropertyValue("VNCProxyPassword", _vncProxyPassword); } get => GetPropertyValue("VNCProxyPassword", _vncProxyPassword);
set { SetField(ref _vncProxyPassword, value, "VNCProxyPassword"); } set => SetField(ref _vncProxyPassword, value, "VNCProxyPassword");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -632,8 +643,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.Colors VNCColors public ProtocolVNC.Colors VNCColors
{ {
get { return GetPropertyValue("VNCColors", _vncColors); } get => GetPropertyValue("VNCColors", _vncColors);
set { SetField(ref _vncColors, value, "VNCColors"); } set => SetField(ref _vncColors, value, "VNCColors");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -642,8 +653,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.EnumTypeConverter))] TypeConverter(typeof(MiscTools.EnumTypeConverter))]
public ProtocolVNC.SmartSizeMode VNCSmartSizeMode public ProtocolVNC.SmartSizeMode VNCSmartSizeMode
{ {
get { return GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode); } get => GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode);
set { SetField(ref _vncSmartSizeMode, value, "VNCSmartSizeMode"); } set => SetField(ref _vncSmartSizeMode, value, "VNCSmartSizeMode");
} }
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5), [LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
@@ -652,8 +663,8 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool VNCViewOnly public bool VNCViewOnly
{ {
get { return GetPropertyValue("VNCViewOnly", _vncViewOnly); } get => GetPropertyValue("VNCViewOnly", _vncViewOnly);
set { SetField(ref _vncViewOnly, value, "VNCViewOnly"); } set => SetField(ref _vncViewOnly, value, "VNCViewOnly");
} }
#endregion #endregion
#endregion #endregion
@@ -665,7 +676,7 @@ namespace mRemoteNG.Connection
protected virtual TPropertyType GetPropertyValue<TPropertyType>(string propertyName, TPropertyType value) 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; public event PropertyChangedEventHandler PropertyChanged;
@@ -674,12 +685,11 @@ namespace mRemoteNG.Connection
PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(args.PropertyName)); 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; field = value;
RaisePropertyChangedEvent(this, new PropertyChangedEventArgs(propertyName)); 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.App;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.Http; using mRemoteNG.Connection.Protocol.Http;
@@ -15,11 +10,16 @@ using mRemoteNG.Connection.Protocol.Telnet;
using mRemoteNG.Connection.Protocol.VNC; using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Container; using mRemoteNG.Container;
using mRemoteNG.Tree; using mRemoteNG.Tree;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
namespace mRemoteNG.Connection namespace mRemoteNG.Connection
{ {
[DefaultProperty("Name")] [DefaultProperty("Name")]
public class ConnectionInfo : AbstractConnectionRecord, IHasParent, IInheritable public class ConnectionInfo : AbstractConnectionRecord, IHasParent, IInheritable
{ {
#region Public Properties #region Public Properties
@@ -78,7 +78,8 @@ namespace mRemoteNG.Connection
var newConnectionInfo = new ConnectionInfo(); var newConnectionInfo = new ConnectionInfo();
newConnectionInfo.CopyFrom(this); newConnectionInfo.CopyFrom(this);
newConnectionInfo.Inheritance = Inheritance.Clone(); newConnectionInfo.Inheritance = Inheritance.Clone();
return newConnectionInfo; newConnectionInfo.Inheritance.Parent = newConnectionInfo;
return newConnectionInfo;
} }
public void CopyFrom(ConnectionInfo sourceConnectionInfo) public void CopyFrom(ConnectionInfo sourceConnectionInfo)
@@ -172,10 +173,11 @@ namespace mRemoteNG.Connection
if (!ShouldThisPropertyBeInherited(propertyName)) if (!ShouldThisPropertyBeInherited(propertyName))
return value; return value;
var inheritedValue = GetInheritedPropertyValue<TPropertyType>(propertyName); var couldGetInheritedValue = TryGetInheritedPropertyValue<TPropertyType>(propertyName, out var inheritedValue);
if (inheritedValue.Equals(default(TPropertyType)))
return value; return couldGetInheritedValue
return inheritedValue; ? inheritedValue
: value;
} }
private bool ShouldThisPropertyBeInherited(string propertyName) private bool ShouldThisPropertyBeInherited(string propertyName)
@@ -196,22 +198,23 @@ namespace mRemoteNG.Connection
return inheritPropertyValue; return inheritPropertyValue;
} }
private TPropertyType GetInheritedPropertyValue<TPropertyType>(string propertyName) private bool TryGetInheritedPropertyValue<TPropertyType>(string propertyName, out TPropertyType inheritedValue)
{ {
try try
{ {
var connectionInfoType = Parent.GetType(); var connectionInfoType = Parent.GetType();
var parentPropertyInfo = connectionInfoType.GetProperty(propertyName); var parentPropertyInfo = connectionInfoType.GetProperty(propertyName);
if (parentPropertyInfo == null) if (parentPropertyInfo == null)
return default(TPropertyType); // shouldn't get here... throw new NullReferenceException($"Could not retrieve property data for property '{propertyName}' on parent node '{Parent?.Name}'");
var parentPropertyValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null);
return parentPropertyValue; inheritedValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null);
return true;
} }
catch (Exception e) catch (Exception e)
{ {
Runtime.MessageCollector.AddExceptionStackTrace($"Error retrieving inherited property '{propertyName}'", e); Runtime.MessageCollector.AddExceptionStackTrace($"Error retrieving inherited property '{propertyName}'", e);
return default(TPropertyType); inheritedValue = default(TPropertyType);
return false;
} }
} }
@@ -310,9 +313,10 @@ namespace mRemoteNG.Connection
RedirectKeys = Settings.Default.ConDefaultRedirectKeys; RedirectKeys = Settings.Default.ConDefaultRedirectKeys;
RedirectDiskDrives = Settings.Default.ConDefaultRedirectDiskDrives; RedirectDiskDrives = Settings.Default.ConDefaultRedirectDiskDrives;
RedirectPrinters = Settings.Default.ConDefaultRedirectPrinters; RedirectPrinters = Settings.Default.ConDefaultRedirectPrinters;
RedirectClipboard = Settings.Default.ConDefaultRedirectClipboard;
RedirectPorts = Settings.Default.ConDefaultRedirectPorts; RedirectPorts = Settings.Default.ConDefaultRedirectPorts;
RedirectSmartCards = Settings.Default.ConDefaultRedirectSmartCards; RedirectSmartCards = Settings.Default.ConDefaultRedirectSmartCards;
RedirectSound = (RdpProtocol.RDPSounds) Enum.Parse(typeof(RdpProtocol.RDPSounds), Settings.Default.ConDefaultRedirectSound); RedirectSound = (RdpProtocol.RDPSounds) Enum.Parse(typeof(RdpProtocol.RDPSounds), Settings.Default.ConDefaultRedirectSound);
SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), Settings.Default.ConDefaultSoundQuality); SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), Settings.Default.ConDefaultSoundQuality);
} }

View File

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

View File

@@ -5,6 +5,8 @@ using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.RDP; using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Container; using mRemoteNG.Container;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.UI;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Panels; using mRemoteNG.UI.Panels;
using mRemoteNG.UI.Window; using mRemoteNG.UI.Window;
@@ -14,8 +16,25 @@ using TabPage = Crownwood.Magic.Controls.TabPage;
namespace mRemoteNG.Connection namespace mRemoteNG.Connection
{ {
public class ConnectionInitiator : IConnectionInitiator public class ConnectionInitiator : IConnectionInitiator
{ {
private readonly PanelAdder _panelAdder = new PanelAdder(); private readonly WindowList _windowList;
private readonly ExternalToolsService _externalToolsService;
private readonly ProtocolFactory _protocolFactory;
private readonly FrmMain _frmMain;
/// <summary>
/// This is a property because we have a circular dependency.
/// </summary>
public PanelAdder Adder { get; set; }
public ConnectionInitiator(WindowList windowList, ExternalToolsService externalToolsService, ProtocolFactory protocolFactory, FrmMain frmMain)
{
_frmMain = frmMain;
_windowList = windowList.ThrowIfNull(nameof(windowList));
_externalToolsService = externalToolsService.ThrowIfNull(nameof(externalToolsService));
_protocolFactory = protocolFactory.ThrowIfNull(nameof(protocolFactory));
}
public void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None) public void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None)
{ {
@@ -53,7 +72,7 @@ namespace mRemoteNG.Connection
var connectionWindow = (ConnectionWindow)interfaceControl.FindForm(); var connectionWindow = (ConnectionWindow)interfaceControl.FindForm();
connectionWindow?.Focus(); connectionWindow?.Focus();
var findForm = (ConnectionWindow)interfaceControl.FindForm(); var findForm = (ConnectionWindow)interfaceControl.FindForm();
findForm?.Show(FrmMain.Default.pnlDock); findForm?.Show(_frmMain.pnlDock);
var tabPage = (TabPage)interfaceControl.Parent; var tabPage = (TabPage)interfaceControl.Parent;
tabPage.Selected = true; tabPage.Selected = true;
return true; return true;
@@ -92,10 +111,10 @@ namespace mRemoteNG.Connection
return; return;
} }
var protocolFactory = new ProtocolFactory(); var newProtocol = _protocolFactory.CreateProtocol(connectionInfo);
var newProtocol = protocolFactory.CreateProtocol(connectionInfo);
var connectionPanel = SetConnectionPanel(connectionInfo, force); var connectionPanel = SetConnectionPanel(connectionInfo, force);
if (string.IsNullOrEmpty(connectionPanel)) return;
var connectionForm = SetConnectionForm(conForm, connectionPanel); var connectionForm = SetConnectionForm(conForm, connectionPanel);
var connectionContainer = SetConnectionContainer(connectionInfo, connectionForm); var connectionContainer = SetConnectionContainer(connectionInfo, connectionForm);
SetConnectionFormEventHandlers(newProtocol, connectionForm); SetConnectionFormEventHandlers(newProtocol, connectionForm);
@@ -117,7 +136,7 @@ namespace mRemoteNG.Connection
} }
connectionInfo.OpenConnections.Add(newProtocol); connectionInfo.OpenConnections.Add(newProtocol);
FrmMain.Default.SelectedConnection = connectionInfo; _frmMain.SelectedConnection = connectionInfo;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -125,19 +144,19 @@ namespace mRemoteNG.Connection
} }
} }
private static void StartPreConnectionExternalApp(ConnectionInfo connectionInfo) private void StartPreConnectionExternalApp(ConnectionInfo connectionInfo)
{ {
if (connectionInfo.PreExtApp == "") return; if (connectionInfo.PreExtApp == "") return;
var extA = Runtime.ExternalToolsService.GetExtAppByName(connectionInfo.PreExtApp); var extA = _externalToolsService.GetExtAppByName(connectionInfo.PreExtApp);
extA?.Start(connectionInfo); extA?.Start(connectionInfo);
} }
private static InterfaceControl FindConnectionContainer(ConnectionInfo connectionInfo) private InterfaceControl FindConnectionContainer(ConnectionInfo connectionInfo)
{ {
if (connectionInfo.OpenConnections.Count <= 0) return null; if (connectionInfo.OpenConnections.Count <= 0) return null;
for (var i = 0; i <= Runtime.WindowList.Count - 1; i++) for (var i = 0; i <= _windowList.Count - 1; i++)
{ {
var window = Runtime.WindowList[i] as ConnectionWindow; var window = _windowList[i] as ConnectionWindow;
var connectionWindow = window; var connectionWindow = window;
if (connectionWindow?.TabController == null) continue; if (connectionWindow?.TabController == null) continue;
foreach (TabPage t in connectionWindow.TabController.TabPages) foreach (TabPage t in connectionWindow.TabController.TabPages)
@@ -153,16 +172,20 @@ namespace mRemoteNG.Connection
return null; return null;
} }
private static string SetConnectionPanel(ConnectionInfo connectionInfo, ConnectionInfo.Force force) private string SetConnectionPanel(ConnectionInfo connectionInfo, ConnectionInfo.Force force)
{ {
var connectionPanel = ""; var connectionPanel = "";
if (connectionInfo.Panel == "" || (force & ConnectionInfo.Force.OverridePanel) == ConnectionInfo.Force.OverridePanel | Settings.Default.AlwaysShowPanelSelectionDlg) if (connectionInfo.Panel == "" || (force & ConnectionInfo.Force.OverridePanel) == ConnectionInfo.Force.OverridePanel | Settings.Default.AlwaysShowPanelSelectionDlg)
{ {
var frmPnl = new frmChoosePanel(); var frmPnl = new frmChoosePanel(Adder, _windowList);
if (frmPnl.ShowDialog() == DialogResult.OK) if (frmPnl.ShowDialog() == DialogResult.OK)
{ {
connectionPanel = frmPnl.Panel; connectionPanel = frmPnl.Panel;
} }
else
{
return null;
}
} }
else else
{ {
@@ -173,24 +196,24 @@ namespace mRemoteNG.Connection
private Form SetConnectionForm(Form conForm, string connectionPanel) private Form SetConnectionForm(Form conForm, string connectionPanel)
{ {
var connectionForm = conForm ?? Runtime.WindowList.FromString(connectionPanel); var connectionForm = conForm ?? _windowList.FromString(connectionPanel);
if (connectionForm == null) if (connectionForm == null)
connectionForm = _panelAdder.AddPanel(connectionPanel); connectionForm = Adder.AddPanel(connectionPanel);
else else
((ConnectionWindow)connectionForm).Show(FrmMain.Default.pnlDock); ((ConnectionWindow)connectionForm).Show(_frmMain.pnlDock);
connectionForm.Focus(); connectionForm.Focus();
return connectionForm; return connectionForm;
} }
private static Control SetConnectionContainer(ConnectionInfo connectionInfo, Form connectionForm) private Control SetConnectionContainer(ConnectionInfo connectionInfo, Form connectionForm)
{ {
Control connectionContainer = ((ConnectionWindow)connectionForm).AddConnectionTab(connectionInfo); Control connectionContainer = ((ConnectionWindow)connectionForm).AddConnectionTab(connectionInfo);
if (connectionInfo.Protocol != ProtocolType.IntApp) return connectionContainer; if (connectionInfo.Protocol != ProtocolType.IntApp) return connectionContainer;
var extT = Runtime.ExternalToolsService.GetExtAppByName(connectionInfo.ExtApp); var extT = _externalToolsService.GetExtAppByName(connectionInfo.ExtApp);
if(extT == null) return connectionContainer; if(extT == null) return connectionContainer;
@@ -205,7 +228,7 @@ namespace mRemoteNG.Connection
newProtocol.Closed += ((ConnectionWindow)connectionForm).Prot_Event_Closed; newProtocol.Closed += ((ConnectionWindow)connectionForm).Prot_Event_Closed;
} }
private static void SetConnectionEventHandlers(ProtocolBase newProtocol) private void SetConnectionEventHandlers(ProtocolBase newProtocol)
{ {
newProtocol.Disconnected += Prot_Event_Disconnected; newProtocol.Disconnected += Prot_Event_Disconnected;
newProtocol.Connected += Prot_Event_Connected; newProtocol.Connected += Prot_Event_Connected;
@@ -246,7 +269,7 @@ namespace mRemoteNG.Connection
} }
} }
private static void Prot_Event_Closed(object sender) private void Prot_Event_Closed(object sender)
{ {
try try
{ {
@@ -264,7 +287,7 @@ namespace mRemoteNG.Connection
prot.InterfaceControl.Info.OpenConnections.Remove(prot); prot.InterfaceControl.Info.OpenConnections.Remove(prot);
if (prot.InterfaceControl.Info.PostExtApp == "") return; if (prot.InterfaceControl.Info.PostExtApp == "") return;
var extA = Runtime.ExternalToolsService.GetExtAppByName(prot.InterfaceControl.Info.PostExtApp); var extA = _externalToolsService.GetExtAppByName(prot.InterfaceControl.Info.PostExtApp);
extA?.Start(prot.InterfaceControl.Info); extA?.Start(prot.InterfaceControl.Info);
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -1,55 +1,62 @@
using System; using System;
using System.IO; using System.IO;
using System.Security;
using System.Threading; using System.Threading;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.App.Info; using mRemoteNG.App.Info;
using mRemoteNG.Config.Connections; using mRemoteNG.Config.Connections;
using mRemoteNG.Config.Connections.Multiuser; using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.Putty; using mRemoteNG.Config.Putty;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
using mRemoteNG.Messages;
using mRemoteNG.Security; using mRemoteNG.Security;
using mRemoteNG.Tools; using mRemoteNG.Tools;
using mRemoteNG.Tree; using mRemoteNG.Tree;
using mRemoteNG.Tree.Root; using mRemoteNG.Tree.Root;
using mRemoteNG.UI;
using mRemoteNG.UI.TaskDialog;
namespace mRemoteNG.Connection namespace mRemoteNG.Connection
{ {
public class ConnectionsService public class ConnectionsService : IConnectionsService
{ {
private static readonly object SaveLock = new object(); private static readonly object SaveLock = new object();
private bool _showDialogWhenLoadingConnections;
private readonly PuttySessionsManager _puttySessionsManager; private readonly PuttySessionsManager _puttySessionsManager;
private readonly Import _import;
private readonly IWin32Window _dialogWindowParent;
private bool _batchingSaves = false;
private bool _saveRequested = false;
private bool _saveAsyncRequested = false;
public bool IsConnectionsFileLoaded { get; set; } public bool IsConnectionsFileLoaded { get; set; }
public bool UsingDatabase { get; private set; } public bool UsingDatabase { get; private set; }
public string ConnectionFileName { get; private set; } public string ConnectionFileName { get; private set; }
public RemoteConnectionsSyncronizer RemoteConnectionsSyncronizer { get; set; } public RemoteConnectionsSyncronizer RemoteConnectionsSyncronizer { get; set; }
public DateTime LastSqlUpdate { get; set; } public DateTime LastSqlUpdate { get; set; }
public SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
// TODO - this is only a property to break up a circular dependency. move to ctor when able
public DatabaseConnectorFactory DatabaseConnectorFactory { get; set; }
public ConnectionTreeModel ConnectionTreeModel { get; private set; } public ConnectionTreeModel ConnectionTreeModel { get; private set; }
//public ConnectionTreeModel ConnectionTreeModel
//{
// get { return Windows.TreeForm.ConnectionTree.ConnectionTreeModel; }
// set { Windows.TreeForm.ConnectionTree.ConnectionTreeModel = value; }
//}
public ConnectionsService(PuttySessionsManager puttySessionsManager) public ConnectionsService(PuttySessionsManager puttySessionsManager, Import import, IWin32Window dialogWindowParent)
{ {
if (puttySessionsManager == null) _puttySessionsManager = puttySessionsManager.ThrowIfNull(nameof(puttySessionsManager));
throw new ArgumentNullException(nameof(puttySessionsManager)); _import = import.ThrowIfNull(nameof(import));
_dialogWindowParent = dialogWindowParent.ThrowIfNull(nameof(dialogWindowParent));
_puttySessionsManager = puttySessionsManager;
} }
public void NewConnectionsFile(string filename) public void NewConnectionsFile(string filename)
{ {
try try
{ {
filename.ThrowIfNullOrEmpty(nameof(filename));
var newConnectionsModel = new ConnectionTreeModel(); var newConnectionsModel = new ConnectionTreeModel();
newConnectionsModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection)); newConnectionsModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename); SaveConnections(newConnectionsModel, false, new SaveFilter(), filename, true);
LoadConnections(false, false, filename); LoadConnections(false, false, filename);
UpdateCustomConsPathSetting(filename);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -79,6 +86,10 @@ namespace mRemoteNG.Connection
{ {
newConnectionInfo.Port = uri.Port; newConnectionInfo.Port = uri.Port;
} }
if (string.IsNullOrEmpty(newConnectionInfo.Panel))
newConnectionInfo.Panel = Language.strGeneral;
newConnectionInfo.IsQuickConnect = true; newConnectionInfo.IsQuickConnect = true;
return newConnectionInfo; return newConnectionInfo;
@@ -97,16 +108,24 @@ namespace mRemoteNG.Connection
/// <param name="useDatabase"></param> /// <param name="useDatabase"></param>
/// <param name="import"></param> /// <param name="import"></param>
/// <param name="connectionFileName"></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 oldConnectionTreeModel = ConnectionTreeModel;
var oldIsUsingDatabaseValue = UsingDatabase; var oldIsUsingDatabaseValue = UsingDatabase;
var newConnectionTreeModel = var newConnectionTreeModel = useDatabase
(useDatabase ? new SqlConnectionsLoader(DatabaseConnectorFactory, this).Load()
? new SqlConnectionsLoader().Load() : new XmlConnectionsLoader(connectionFileName, this, _dialogWindowParent).Load();
: new XmlConnectionsLoader(connectionFileName).Load())
?? new ConnectionTreeModel(); if (newConnectionTreeModel == null)
{
DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed", IsConnectionsFileLoaded, this);
return;
}
IsConnectionsFileLoaded = true;
ConnectionFileName = connectionFileName;
UsingDatabase = useDatabase;
if (!import) if (!import)
{ {
@@ -114,12 +133,35 @@ namespace mRemoteNG.Connection
newConnectionTreeModel.RootNodes.AddRange(_puttySessionsManager.RootPuttySessionsNodes); newConnectionTreeModel.RootNodes.AddRange(_puttySessionsManager.RootPuttySessionsNodes);
} }
IsConnectionsFileLoaded = true;
ConnectionFileName = connectionFileName;
UsingDatabase = useDatabase;
ConnectionTreeModel = newConnectionTreeModel; ConnectionTreeModel = newConnectionTreeModel;
UpdateCustomConsPathSetting(connectionFileName);
RaiseConnectionsLoadedEvent(oldConnectionTreeModel, newConnectionTreeModel, oldIsUsingDatabaseValue, useDatabase, 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> /// <summary>
@@ -128,8 +170,6 @@ namespace mRemoteNG.Connection
/// </summary> /// </summary>
public void SaveConnections() public void SaveConnections()
{ {
if (!IsConnectionsFileLoaded)
return;
SaveConnections(ConnectionTreeModel, UsingDatabase, new SaveFilter(), ConnectionFileName); SaveConnections(ConnectionTreeModel, UsingDatabase, new SaveFilter(), ConnectionFileName);
} }
@@ -141,17 +181,29 @@ namespace mRemoteNG.Connection
/// <param name="useDatabase"></param> /// <param name="useDatabase"></param>
/// <param name="saveFilter"></param> /// <param name="saveFilter"></param>
/// <param name="connectionFileName"></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 try
{ {
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Saving connections...");
RemoteConnectionsSyncronizer?.Disable(); RemoteConnectionsSyncronizer?.Disable();
var previouslyUsingDatabase = UsingDatabase; var previouslyUsingDatabase = UsingDatabase;
if (useDatabase) if (useDatabase)
new SqlConnectionsSaver(saveFilter).Save(connectionTreeModel); new SqlConnectionsSaver(saveFilter, this, DatabaseConnectorFactory).Save(connectionTreeModel);
else else
new XmlConnectionsSaver(connectionFileName, saveFilter).Save(connectionTreeModel); new XmlConnectionsSaver(connectionFileName, saveFilter).Save(connectionTreeModel);
@@ -161,6 +213,7 @@ namespace mRemoteNG.Connection
UsingDatabase = useDatabase; UsingDatabase = useDatabase;
ConnectionFileName = connectionFileName; ConnectionFileName = connectionFileName;
RaiseConnectionsSavedEvent(connectionTreeModel, previouslyUsingDatabase, UsingDatabase, connectionFileName); RaiseConnectionsSavedEvent(connectionTreeModel, previouslyUsingDatabase, UsingDatabase, connectionFileName);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Successfully saved connections");
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -174,6 +227,12 @@ namespace mRemoteNG.Connection
public void SaveConnectionsAsync() public void SaveConnectionsAsync()
{ {
if (_batchingSaves)
{
_saveAsyncRequested = true;
return;
}
var t = new Thread(SaveConnectionsBGd); var t = new Thread(SaveConnectionsBGd);
t.SetApartmentState(ApartmentState.STA); t.SetApartmentState(ApartmentState.STA);
t.Start(); t.Start();
@@ -181,19 +240,175 @@ namespace mRemoteNG.Connection
private void SaveConnectionsBGd() private void SaveConnectionsBGd()
{ {
Monitor.Enter(SaveLock); lock (SaveLock)
SaveConnections(); {
Monitor.Exit(SaveLock); SaveConnections();
}
}
public void LoadConnectionsAsync()
{
_showDialogWhenLoadingConnections = false;
var t = new Thread(LoadConnectionsBGd);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private void LoadConnectionsBGd()
{
LoadConnections(_showDialogWhenLoadingConnections);
}
public void LoadConnections(bool withDialog = false)
{
var connectionFileName = "";
try
{
// disable sql update checking while we are loading updates
RemoteConnectionsSyncronizer?.Disable();
if (!Settings.Default.UseSQLServer)
{
if (withDialog)
{
var loadDialog = DialogFactory.BuildLoadConnectionsDialog();
if (loadDialog.ShowDialog() != DialogResult.OK) return;
connectionFileName = loadDialog.FileName;
}
else
{
connectionFileName = GetStartupConnectionFileName();
}
}
LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
if (Settings.Default.UseSQLServer)
{
LastSqlUpdate = DateTime.Now;
}
else
{
if (connectionFileName == GetDefaultStartupConnectionFileName())
{
Settings.Default.LoadConsFromCustomLocation = false;
}
else
{
Settings.Default.LoadConsFromCustomLocation = true;
Settings.Default.CustomConsPath = connectionFileName;
}
}
// re-enable sql update checking after updates are loaded
RemoteConnectionsSyncronizer?.Enable();
}
catch (Exception ex)
{
if (Settings.Default.UseSQLServer)
{
Runtime.MessageCollector.AddExceptionMessage(Language.strLoadFromSqlFailed, ex);
var commandButtons = string.Join("|", Language.strCommandTryAgain, Language.strCommandOpenConnectionFile, string.Format(Language.strCommandExitProgram, Application.ProductName));
CTaskDialog.ShowCommandBox(Application.ProductName, Language.strLoadFromSqlFailed, Language.strLoadFromSqlFailedContent, MiscTools.GetExceptionMessageRecursive(ex), "", "", commandButtons, false, ESysIcons.Error, ESysIcons.Error);
switch (CTaskDialog.CommandButtonResult)
{
case 0:
LoadConnections(withDialog);
return;
case 1:
Settings.Default.UseSQLServer = false;
LoadConnections(true);
return;
default:
Application.Exit();
return;
}
}
if (ex is FileNotFoundException && !withDialog)
{
Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName), ex, MessageClass.InformationMsg);
string[] commandButtons =
{
Language.ConfigurationCreateNew,
Language.ConfigurationCustomPath,
Language.ConfigurationImportFile,
Language.strMenuExit
};
var answered = false;
while (!answered)
{
try
{
CTaskDialog.ShowTaskDialogBox(
GeneralAppInfo.ProductName,
Language.ConnectionFileNotFound,
"", "", "", "", "",
string.Join(" | ", commandButtons),
ETaskDialogButtons.None,
ESysIcons.Question,
ESysIcons.Question);
switch (CTaskDialog.CommandButtonResult)
{
case 0:
NewConnectionsFile(connectionFileName);
answered = true;
break;
case 1:
LoadConnections(true);
answered = true;
break;
case 2:
NewConnectionsFile(connectionFileName);
_import.ImportFromFile(ConnectionTreeModel.RootNodes[0]);
answered = true;
break;
case 3:
Application.Exit();
answered = true;
break;
}
}
catch (Exception exc)
{
Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName), exc, MessageClass.InformationMsg);
}
}
return;
}
Runtime.MessageCollector.AddExceptionStackTrace(string.Format(Language.strConnectionsFileCouldNotBeLoaded, connectionFileName), ex);
if (connectionFileName != GetStartupConnectionFileName())
{
LoadConnections(withDialog);
}
else
{
MessageBox.Show(_dialogWindowParent,
string.Format(Language.strErrorStartupConnectionFileLoad, Environment.NewLine, Application.ProductName, GetStartupConnectionFileName(), MiscTools.GetExceptionMessageRecursive(ex)),
@"Could not load startup file.", MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.Exit();
}
}
} }
public string GetStartupConnectionFileName() public string GetStartupConnectionFileName()
{ {
return Settings.Default.LoadConsFromCustomLocation == false ? GetDefaultStartupConnectionFileName() : Settings.Default.CustomConsPath; return Settings.Default.LoadConsFromCustomLocation == false
? GetDefaultStartupConnectionFileName()
: Settings.Default.CustomConsPath;
} }
public string GetDefaultStartupConnectionFileName() public string GetDefaultStartupConnectionFileName()
{ {
return Runtime.IsPortableEdition ? GetDefaultStartupConnectionFileNamePortableEdition() : GetDefaultStartupConnectionFileNameNormalEdition(); return Runtime.IsPortableEdition
? GetDefaultStartupConnectionFileNamePortableEdition()
: GetDefaultStartupConnectionFileNameNormalEdition();
} }
private void UpdateCustomConsPathSetting(string filename) private void UpdateCustomConsPathSetting(string filename)

View File

@@ -31,9 +31,14 @@ namespace mRemoteNG.Connection
throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found."); throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found.");
var valueFromSource = propertyFromSource.GetValue(sourceInstance, null); var valueFromSource = propertyFromSource.GetValue(sourceInstance, null);
var value = Convert.ChangeType(valueFromSource, property.PropertyType);
if (property.PropertyType.IsEnum)
{
property.SetValue(Instance, Enum.Parse(property.PropertyType, valueFromSource.ToString()), null);
continue;
}
property.SetValue(Instance, value, null); property.SetValue(Instance, Convert.ChangeType(valueFromSource, property.PropertyType), null);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,6 +16,12 @@ namespace mRemoteNG.Connection.Protocol
{ {
private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID
private bool _isPuttyNg; private bool _isPuttyNg;
private readonly IConnectionsService _connectionsService;
public PuttyBase(IConnectionsService connectionsService)
{
_connectionsService = connectionsService;
}
#region Public Properties #region Public Properties
@@ -99,7 +105,7 @@ namespace mRemoteNG.Connection.Protocol
if (Settings.Default.EmptyCredentials == "custom") if (Settings.Default.EmptyCredentials == "custom")
{ {
var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey); password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, _connectionsService.EncryptionKey);
} }
} }
@@ -199,7 +205,14 @@ namespace mRemoteNG.Connection.Protocol
{ {
return; return;
} }
NativeMethods.MoveWindow(PuttyHandle, -SystemInformation.FrameBorderSize.Width, -(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height), InterfaceControl.Width + SystemInformation.FrameBorderSize.Width * 2, InterfaceControl.Height + SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height * 2, true);
var left = -(SystemInformation.FrameBorderSize.Width + SystemInformation.HorizontalResizeBorderThickness);
var top = -(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height + SystemInformation.VerticalResizeBorderThickness);
var width = InterfaceControl.Width + (SystemInformation.FrameBorderSize.Width + SystemInformation.HorizontalResizeBorderThickness) * 2;
var height = InterfaceControl.Height + SystemInformation.CaptionHeight +
(SystemInformation.FrameBorderSize.Height + SystemInformation.VerticalResizeBorderThickness) * 2;
NativeMethods.MoveWindow(PuttyHandle, left, top, width, height, true);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

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

View File

@@ -30,7 +30,8 @@ namespace mRemoteNG.Connection.Protocol.RDP
private bool _loginComplete; private bool _loginComplete;
private bool _redirectKeys; private bool _redirectKeys;
private bool _alertOnIdleDisconnect; private bool _alertOnIdleDisconnect;
private readonly FrmMain _frmMain = FrmMain.Default; private readonly FrmMain _frmMain;
private readonly IConnectionsService _connectionsService;
#region Properties #region Properties
public bool SmartSize public bool SmartSize
@@ -92,8 +93,10 @@ namespace mRemoteNG.Connection.Protocol.RDP
#endregion #endregion
#region Constructors #region Constructors
public RdpProtocol() public RdpProtocol(FrmMain frmMain, IConnectionsService connectionsService)
{ {
_frmMain = frmMain;
_connectionsService = connectionsService;
Control = new AxMsRdpClient8NotSafeForScripting(); Control = new AxMsRdpClient8NotSafeForScripting();
} }
#endregion #endregion
@@ -316,10 +319,19 @@ namespace mRemoteNG.Connection.Protocol.RDP
return; 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; IMsRdpClient8 msRdpClient8 = _rdpClient;
msRdpClient8.Reconnect((uint)size.Width, (uint)size.Height); 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() private void SetRdGateway()
@@ -444,7 +456,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
if (Settings.Default.DefaultPassword != "") if (Settings.Default.DefaultPassword != "")
{ {
var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
_rdpClient.AdvancedSettings2.ClearTextPassword = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey); _rdpClient.AdvancedSettings2.ClearTextPassword = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, _connectionsService.EncryptionKey);
} }
} }
} }
@@ -543,6 +555,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
_rdpClient.AdvancedSettings2.RedirectPrinters = _connectionInfo.RedirectPrinters; _rdpClient.AdvancedSettings2.RedirectPrinters = _connectionInfo.RedirectPrinters;
_rdpClient.AdvancedSettings2.RedirectSmartCards = _connectionInfo.RedirectSmartCards; _rdpClient.AdvancedSettings2.RedirectSmartCards = _connectionInfo.RedirectSmartCards;
_rdpClient.SecuredSettings2.AudioRedirectionMode = (int)_connectionInfo.RedirectSound; _rdpClient.SecuredSettings2.AudioRedirectionMode = (int)_connectionInfo.RedirectSound;
_rdpClient.AdvancedSettings.DisableRdpdr = _connectionInfo.RedirectClipboard ? 0 : 1;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -916,17 +929,25 @@ namespace mRemoteNG.Connection.Protocol.RDP
#region Reconnect Stuff #region Reconnect Stuff
public void tmrReconnect_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 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) if (ReconnectGroup.ReconnectWhenReady && srvReady)
{ {
tmrReconnect.Enabled = false; tmrReconnect.Enabled = false;
ReconnectGroup.DisposeReconnectGroup(); ReconnectGroup.DisposeReconnectGroup();
//SetProps() //SetProps()
_rdpClient.Connect(); _rdpClient.Connect();
} }
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.AutomaticReconnectError, _connectionInfo.Hostname),
ex, MessageClass.WarningMsg, false);
}
} }
#endregion #endregion
} }

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