Compare commits

..

120 Commits

Author SHA1 Message Date
David Sparer
9b38308ad1 set date for rc1 build in changelog 2017-01-27 15:28:36 -07:00
Sean Kaim
afcdf96e5c changelog / credits update 2017-01-27 17:13:50 -05:00
David Sparer
3e40b08525 Merge pull request #348 from countchappy/develop
RDP Minutes to Idle Timeout - users cant enter invalid timeout values
2017-01-27 14:58:05 -07:00
countchappy
237cf037be RDP Minutes to Idle Timeout - Update 5
Incorrect values entered in the Minutes to Idle Timout setting will be
corrected to fit in the range of 0-240, rather than be truncated.
2017-01-27 14:56:40 -05:00
Sean Kaim
2445c74638 code clean up and minor refactoring 2017-01-25 17:50:10 -05:00
Sean Kaim
6a69ed48a9 Merge pull request #372 from mRemoteNG/serialize_connectioninfo_id
Serialize connectioninfo ID
2017-01-25 17:01:29 -05:00
David Sparer
217693937f connectioninfo id is now serialized to the confCons file 2017-01-25 14:02:20 -07:00
Sean Kaim
22300577cf Merge pull request #371 from jcefoli/develop
Quick fix for #369 (Reset Layout Ignores Notification Pane)
2017-01-25 15:06:39 -05:00
Joe Cefoli
6a07f4e731 Quick fix for #369 2017-01-25 14:02:16 -05:00
David Sparer
63ace60dcc Merge pull request #367 from mRemoteNG/295_default_con_values_not_saved
resolved issue where saving default con properties would fail
2017-01-25 09:58:50 -07:00
David Sparer
601951582d resolved issue where saving default con properties would fail
enum, int, bool -> string was throwing an exception. now using a simpler strategy for type conversion
resolves #295
2017-01-25 09:54:54 -07:00
Sean Kaim
9250dde5b0 Merge pull request #364 from mRemoteNG/176_scheduled_updates
1.76 scheduled updates to 1.75
2017-01-24 20:04:47 -05:00
Sean Kaim
29ca72d8ca Change log update 2017-01-24 20:03:20 -05:00
Sean Kaim
87c89a0de5 reformat code 2017-01-24 19:55:18 -05:00
Sean Kaim
73f72e39d3 Fix incorrect cast & code clean up
Fixes #362
2017-01-24 19:49:22 -05:00
Sean Kaim
e00ba62606 Refactored Tools.Controls.cs
Fixes #363
2017-01-24 17:52:15 -05:00
Sean Kaim
48d53cecce Rename Tab dialog - populate original name
Fixes #258
2017-01-24 17:36:41 -05:00
David Sparer
e0fd81e938 resolved bug when clicking in blank space in the connection tree 2017-01-23 15:32:06 -07:00
Sean Kaim
04f6f4f9cf Make version selectable/copyable
fixes #360

Also update copyright year since it's 2017 now...
2017-01-23 12:59:29 -05:00
David Sparer
25d1e0a74d Merge pull request #352 from mRemoteNG/299_better_testing_of_connection_tree
Refactor connection tree to be more testable
2017-01-18 09:03:26 -07:00
David Sparer
cbd9d16e4c simplified the connection tree refresh method.
the complexity of trying to add refresh optimizations was causing bugs. i will need to find a new way of reducing flicker
2017-01-17 15:31:40 -07:00
David Sparer
cb708b3217 resolved bug where some context menu hot keys would not work after opening the menu on the root node 2017-01-17 13:45:25 -07:00
David Sparer
4e5a22a7e8 resolved a minor bug where creating a new node would screw up the selected node in the tree
We were trying to do multiselection when it is currently not supported by our implementation.
2017-01-17 09:47:00 -07:00
Sean Kaim
3722db93c6 Merge pull request #349 from jogleasonjr/patch-1
Fix typo in README.MD
2017-01-16 17:56:59 -05:00
John Gleason
b43331dc27 Fix typo in README.MD 2017-01-16 15:20:07 -06:00
countchappy
80c6ce81e1 RDP Minutes to Idle Timeout - Update 4
Added an option to alert if disconnected due to inactivity.
2017-01-16 15:14:27 -05:00
David Sparer
1a776359c4 added test for folder expander 2017-01-14 11:44:09 -07:00
David Sparer
113e4035e5 refactored the deletion confirmer to make it testable 2017-01-14 11:14:30 -07:00
David Sparer
a03095ab8e refactored the node deletion confirmer to be interface-based. this will lead to improved testability 2017-01-14 10:38:11 -07:00
David Sparer
d03f830622 added null test for the composite click handler 2017-01-14 10:36:54 -07:00
David Sparer
9b42dc9f10 Refactored some click handlers and created a test for it
During testing I realized that the double and single click handlers were exactly the same thing, so i combined them into the composite click handler.
2017-01-14 10:11:22 -07:00
David Sparer
fd7adf3c64 added some more tests 2017-01-13 17:43:06 -07:00
David Sparer
d0b7e72f15 Merge pull request #342 from countchappy/develop
RDP Optional Minutes to Idle Timeout
2017-01-13 17:05:25 -07:00
countchappy
5a61c6b7df RDP Minutes to Idle Timeout - Update 3.1 2017-01-13 18:49:39 -05:00
countchappy
c897eae04e RDP Minutes to Idle Timeout - Update 3
Fixed name and description not showing up in the config window.
2017-01-13 18:08:36 -05:00
countchappy
c33095cd0e RDP Minutes to Idle Timeout - Update 2.1
Fixed my goof!
2017-01-13 17:11:07 -05:00
David Sparer
05d8b7983a reorganized some test files and added tests for null args 2017-01-13 12:12:22 -07:00
countchappy
166d9f7133 RDP Minutes to Idle Timeout - Update 2
Added null conditional operator to prevent throwing a null reference
error for beta users.
2017-01-13 13:41:19 -05:00
David Sparer
2ce31f35cc more file organizing 2017-01-13 10:54:39 -07:00
David Sparer
ce5d0cefe3 organized some files 2017-01-13 10:41:28 -07:00
David Sparer
6cc668fe83 added more tests for connectiontree delegates 2017-01-12 15:30:30 -07:00
David Sparer
ac0aa8daf4 added a method to the IConnectionTree interface to make testing another class possible 2017-01-12 15:20:32 -07:00
David Sparer
16b094be44 we no longer need the extensions now that we are subclassing TreeListView 2017-01-12 15:16:55 -07:00
David Sparer
b3e6fd7b96 created test for another tree handler 2017-01-12 15:09:24 -07:00
David Sparer
893d5d92f3 made all relevant classes use IConnectionTree 2017-01-12 15:09:05 -07:00
David Sparer
77add0b39d added an interface for iconnectiontree. this kind of hacky and really just exists to make the tests work. this indicates we have some coupling on ConnectionTree that shouldn't be there.. 2017-01-12 15:08:12 -07:00
David Sparer
b4f8ab0a49 moved a call to settings further up in the abstraction level to make testing easier 2017-01-12 14:13:35 -07:00
David Sparer
1d46c44c21 added tests for another click handler 2017-01-12 13:57:44 -07:00
David Sparer
12da35f875 made the rest of the connectioninitiator functions non-static 2017-01-12 13:57:15 -07:00
David Sparer
8970a15d4e added tests for one of the click handlers 2017-01-12 13:33:12 -07:00
David Sparer
82217478d9 made one of the methods for the connectioninitiator non-static (they should eventually all be non-static).
This change was made to making testing easier (make connectioninitiator mockable)
2017-01-12 13:31:29 -07:00
David Sparer
4c792308bb moved all click-actions for the tree to separate classes to make them easily composable
this has the nice effect of also pushing any calls to the settings class outside the classes that are actualy doing work, making them much easier to test in isolation
2017-01-12 12:47:23 -07:00
David Sparer
978d94a2cd resolved issue with unit test. we could not select a tree object without that object being visible 2017-01-12 11:12:18 -07:00
David Sparer
b195d89b76 moved a few more functions closer to their call site 2017-01-12 11:02:11 -07:00
David Sparer
875888a341 moved a method closer to its call site 2017-01-12 10:51:05 -07:00
David Sparer
6631a13d20 cleanup 2017-01-12 10:31:50 -07:00
David Sparer
28728fe29f moved some connectiontree post setup actions into their own classes. post setup actions are now managed by a composite 2017-01-12 10:29:30 -07:00
David Sparer
aa954cbea9 minor cleanup 2017-01-12 09:24:59 -07:00
David Sparer
dae339f494 moved the image getter delegate code into its imagelist since the img names have to match up. seems like a better division of responsibility 2017-01-12 09:17:34 -07:00
David Sparer
5bcb59f876 moved the setup of the tree image list to its own class 2017-01-12 08:59:34 -07:00
David Sparer
9132592fd7 moved the setup of the name column to its own class 2017-01-12 08:58:52 -07:00
Sean Kaim
ca592fac77 update change log 2017-01-11 17:56:37 -05:00
Sean Kaim
ea657824c2 Streamlined non-integrated IntApp connections
This seems to fix #325
2017-01-11 17:49:37 -05:00
Sean Kaim
99e7072e27 code clean up
relates to #325
2017-01-11 17:01:08 -05:00
David Sparer
ad32f4a0a3 Merge branch 'develop' into 299_better_testing_of_connection_tree 2017-01-11 15:00:44 -07:00
David Sparer
b9cdd0996d moved click handling responsibility out of the connectiontreewindow and into the context menu class 2017-01-11 14:58:29 -07:00
Sean Kaim
e92a76f95b "return ;" annoyed me...
And I did a find and replace in the solution instead of the one file I
was working on... So I'm going with it...
2017-01-11 16:56:14 -05:00
countchappy
10d152342f RDP Minutes to Idle Timeout - Update 1
Fixed some language file stuff.
2017-01-11 16:44:53 -05:00
countchappy
7e4b0635b2 RDP Minutes To Idle Timeout
Allows users to configure a number of minutes until the session will
automatically disconnect if left idle.
2017-01-11 15:23:43 -05:00
Sean Kaim
eec17f10d5 update changelog 2017-01-10 10:54:03 -05:00
Sean Kaim
ac9d5dfa95 code clean up 2017-01-10 10:51:34 -05:00
Sean Kaim
4c2b3738c2 Don't attempt to connect to folders
Fixes #334
2017-01-10 10:46:34 -05:00
Sean Kaim
6f29183b45 code clean up and logging / exception handling 2017-01-09 11:32:04 -05:00
Sean Kaim
dd65c9c588 update changelog 2017-01-06 12:53:56 -05:00
Sean Kaim
cb8bb05627 Merge pull request #329 from mRemoteNG/release_channels
Add Release channels
2017-01-06 12:32:05 -05:00
David Sparer
256f6d8fdd extracted and renamed some methods 2017-01-06 10:15:33 -07:00
Sean Kaim
a88fdddecb allow all tests to pass regardless of build type 2017-01-06 11:58:00 -05:00
Sean Kaim
fd5e3e24df Run tests from local resources 2017-01-06 11:16:02 -05:00
Sean Kaim
244d27427d update some log messages 2017-01-05 14:30:24 -05:00
Sean Kaim
55c42a3cca Merge remote-tracking branch 'refs/remotes/origin/develop' into release_channels 2017-01-05 11:21:46 -05:00
Sean Kaim
3c9cfbdf92 log exception messages only 2017-01-05 11:13:43 -05:00
Sean Kaim
46dd58d26e External Tool/Connection - code clean up & logging
Relates to #325
2017-01-05 11:05:59 -05:00
Sean Kaim
051dd2e567 Add Beta and Dev tests 2017-01-04 11:15:51 -05:00
Sean Kaim
17ccf40082 re-add version check & adjust CPU target for tests
fixed compliler warning regarding architecture mismatch.
2017-01-04 10:47:23 -05:00
Sean Kaim
0f2b61694d Merge remote-tracking branch 'refs/remotes/origin/develop' into release_channels 2017-01-04 09:15:22 -05:00
Sean Kaim
0aed66df47 fix build & test failure 2017-01-03 18:17:03 -05:00
Sean Kaim
94a6e9a886 code clean up around startup / frmMain
Slightly related to #298
2016-12-22 10:01:20 -05:00
Sean Kaim
355f48b6ba We want only Valid info! 2016-12-16 17:29:03 -05:00
Sean Kaim
d1a6526c22 Added functional UpdateStableChannel test
It's working! It's working!
2016-12-16 17:27:57 -05:00
Sean Kaim
975a308647 reworking code to better test & code cleanup 2016-12-15 17:44:55 -05:00
Sean Kaim
5138eaeb68 Merge remote-tracking branch 'refs/remotes/origin/develop' into release_channels 2016-12-15 15:02:30 -05:00
David Sparer
45dfaa1b21 removed unused code 2016-12-13 13:11:50 -07:00
David Sparer
715f92f3d5 removed unnecessary code 2016-12-13 13:07:52 -07:00
Sean Kaim
8d5a765040 pass importSubOU option in to recursive calls
Fixes remaining problems reported in #211
2016-12-13 14:22:39 -05:00
Sean Kaim
34fa6b158b load the default domain when opening the form
Related to #311
2016-12-13 13:34:44 -05:00
David Sparer
78c1f6b8e3 Fixed bug where we could not drop between items (rearrange) 2016-12-13 10:28:38 -07:00
David Sparer
adccb91106 removed unnecessary code 2016-12-13 10:06:50 -07:00
David Sparer
1e213dfff7 resolved issue with deleting the last folder in the tree 2016-12-13 09:58:24 -07:00
David Sparer
d469fa1d40 Made the deletion confirmation functionality plugable to make testing easier 2016-12-13 09:51:18 -07:00
David Sparer
737db469ba Fixed test name 2016-12-13 09:27:32 -07:00
David Sparer
a44a33d508 minor cleanup 2016-12-13 09:16:05 -07:00
David Sparer
a518d41c78 updated connection tree window tests 2016-12-13 09:07:21 -07:00
David Sparer
d5360c6568 Completed splitting the connection tree from the connection tree window 2016-12-13 09:00:38 -07:00
Sean Kaim
d468107311 Load users default/current domain
Fixes #311

Caused by 97a0e2413e

Some code clean up as well...
2016-12-13 10:50:36 -05:00
Sean Kaim
3f65e1bfa0 add tests for update channels
Some code clean up as well...
2016-12-13 10:31:16 -05:00
David Sparer
a22758f5cd organized code into regions to help prepare for later refactoring 2016-12-09 12:57:26 -07:00
David Sparer
88b5b9d1e7 began moving connectiontree functions out of the code for the window and into its own class.
this will improve testability and reduce class complexity
2016-12-07 15:07:15 -07:00
Sean Kaim
e38f7c880e code clean up
Added some log messages for #298
2016-12-06 19:13:09 -05:00
David Sparer
6367b58994 began adding unit tests for the connectiontree ui 2016-12-06 15:28:56 -07:00
David Sparer
5a54b5ee64 Merge pull request #292 from ForensicITGuy/develop
Added code and screenshots for Quick Connect help files
2016-12-06 08:36:00 -07:00
ForensicITGuy
002e41f418 Added Quick Connect screenshots into project. Modified folder name and HTML code to include spaces as observed in the other screenshot folders. Set to track content and copy if newer in output. 2016-12-06 01:04:52 -06:00
David Sparer
f7787c748a Added multiple build badges based on update channel to readme.md 2016-12-03 11:17:41 -07:00
David Sparer
f9b18b45a4 updated the jenkins build badge to point to the sanitized url. added a title to readme.md 2016-12-03 10:46:20 -07:00
David Sparer
8966f44272 resolved issue with Jenkins not being about the build PRs 2016-12-02 16:49:49 -07:00
Tony M Lambert
3dbcbae61f Added code for Quick Connect documentation
Added HTML code to document Quick Connect functionality
2016-12-02 15:49:04 -06:00
Sean Kaim
24508abe7a rename channels 2016-12-02 16:41:37 -05:00
Tony M Lambert
27f8f2542e Added screenshots for Quickconnect documentation 2016-12-02 15:25:05 -06:00
Sean Kaim
44ee3ceec8 User Selectable Release Channels
Final = Final
Beta = Beta & RC
Pre-Release = Alpha, Beta & RC
2016-12-02 14:57:49 -05:00
Sean Kaim
b08112aec0 Load Ext Tools - add logging
Relates to #291 & #236
2016-12-02 12:20:02 -05:00
Sean Kaim
9d2bbda2b9 ExtTools code clean up
Relates to #291 & #236
2016-12-02 12:11:46 -05:00
118 changed files with 3601 additions and 2064 deletions

View File

@@ -1,14 +1,49 @@
1.75 Beta 3 (2016-12-01):
Fixes:
------
#289: Install fails during update process (only affects v1.75 beta 1 - v1.75 beta 2)
1.75 RC1 (2017-01-27):
Known Issue:
------------
Portable build MD5 check will fail when updating from 1.75 Beta 1 to newer versions.
Features/Enhancements:
----------------------
Added Release Channels to the update check functionality allowing users to select one of 3 release channels for updates: Stable, Beta, Dev
#360: Help -> About, Version # is now selectable/copyable
#221: RDP: Optional disconnect after X number of minutes of inactivity
Fixes:
------
#369: Reset Layout Option Does Not Reset Notification Pane
#362: Invalid cast exception when using the Notification Area Icon minimize/restore
#334: Quick Connect displays warning when clicking on a folder
#325: When using a connection with an external app, results in opening the same external app continuously
#311: Import from Active Directory does not use machine's domain by default
#258: Rename Tab dialog - populate original name in dialog (1.72 functionality)
#211, #267: Recursive AD Import wasn't fully functional
General Changes:
----------------
The usual general code clean up and refactoring
#325: Code clean up and additional logging for External Tools based connections
#298: Code clean up and additional logging around application startup
#291, #236: External Tools code clean up and additional logging
1.75 Beta 3 (2016-12-01):
Known Issue:
------------
Portable build MD5 check will fail when updating from 1.75 Beta 1 to newer versions.
Fixes:
------
#289: Install fails during update process (only affects v1.75 beta 1 - v1.75 beta 2)
1.75 Beta 2 (2016-12-01):
Features/Enhancements:
@@ -21,7 +56,7 @@ Fixes:
------
#254: Component check window position issues and uncaught exception
#260: Crash when attempting to load fully encrypted confCons v2.5
#261: Double clicking folder in treeview doesnt expand it in 1.75 beta1
#261: Double clicking folder in treeview doesn't expand it in 1.75 beta1
#271: Install package is not using the last installation path
#278: Silent installs not detecting prerequisites
@@ -65,7 +100,7 @@ Fixes:
MR-965, MR-871, MR-629: Error 264 on RDP Connect attempt - Added timeout value to Tools -> Options -> Connections
MR-946: Remove old/insecure SharpSSH and related components. Replace with SSH.NET for File Transfer Functionality
MR-896: Added prerequisite installer check for KB2574819. Prevents "Class not registered" errors when opening RDP connections.
PR-130: Fix Scan button width to fit russian translation
PR-130: Fix Scan button width to fit Russian translation
@@ -73,7 +108,7 @@ PR-130: Fix Scan button width to fit russian translation
General Changes:
----------------
Updated GeckoFx pacakge
Updated GeckoFx package
Updated DockPanelSuite library to 2.10 Final
Japanese translation updated
MR-942: Refactored code relating to loading the connections file
@@ -148,7 +183,7 @@ Port Scan is now Asynchronous (and is significantly faster)
Fixes:
------
MR-874: Added work-around to installer to ignore installation prerequisites
MR-884: Slow startup in some scnearios checking authenticode certificate
MR-884: Slow startup in some scenarios checking authenticode certificate
MR-872: Crash in External Tools when arguments aren't quoted
MR-854: crashes when right clicking on connection tab
MR-852: Option "Allow only a single instance of the application" non-functional
@@ -289,7 +324,7 @@ Fixed issue MR-398 - Full Screen mode doesn't correctly make use of available sp
Fixed issue MR-402 - scrollbar touch moves putty window
Fixed issue MR-406 - Items disappear from External Tools toolbar when accessing External Tools panel
Fixed issue MR-410 - Unhandled exception when clicking New button under Theme
Fixed issue MR-413 - Can't use aplication
Fixed issue MR-413 - Can't use application
Fixed new connections having a globe icon.
Fixed the category names in the themes tab of the options dialog on Windows XP not showing correctly.
Fixed PuTTY saved sessions with spaces or special characters not being listed.

View File

@@ -8,9 +8,12 @@ Sean Kaim (github.com/kmscode)
Thanks for the awesome new website!
Bennett Blodinger (github.com/benwa)
Joe Cefoli (github.com/jcefoli)
countchappy (github.com/countchappy)
Tony Lambert
Past Contributors
=================

6
Jenkinsfile vendored
View File

@@ -5,11 +5,7 @@ node('windows') {
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow"
stage 'Checkout Branch'
checkout([
$class: 'GitSCM',
branches: scm.branches,
userRemoteConfigs: scm.userRemoteConfigs
])
checkout scm
stage 'Restore NuGet Packages'
def nugetPath = "C:\\nuget.exe"

View File

@@ -1,16 +1,20 @@
# Welcome to the mRemoteNG project!
[![Twitter Follow](https://img.shields.io/twitter/follow/mRemoteNG.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=mRemoteNG)
[![Join the chat at https://gitter.im/mRemoteNG/PublicChat/](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mRemoteNG/PublicChat)
[![PayPal](https://img.shields.io/badge/%24-PayPal-blue.svg)](https://www.paypal.me/DavidSparer)
[![Build Status](http://ec2-52-39-111-114.us-west-2.compute.amazonaws.com:8080/buildStatus/icon?job=mRemoteNG/mRemoteNG/develop)](http://ec2-52-39-111-114.us-west-2.compute.amazonaws.com:8080/job/mRemoteNG/job/mRemoteNG/job/develop/)
[![Issues In Progress](https://badge.waffle.io/mRemoteNG/mRemoteNG.png?label=In%20Progress&title=In%20Progress)](https://waffle.io/mRemoteNG/mRemoteNG)
[![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.74/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.74)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/529/badge)](https://bestpractices.coreinfrastructure.org/projects/529)
[![Issues In Progress](https://badge.waffle.io/mRemoteNG/mRemoteNG.png?label=In%20Progress&title=In%20Progress)](https://waffle.io/mRemoteNG/mRemoteNG)
| Update Channel | Build Status | Downloads |
| ---------------|--------------|-----------|
| Stable | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/master)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/master/) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.74/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.74) |
| Beta | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/beta_channel)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/beta_channel/) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75Beta3/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75Beta3) |
| Development | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/develop)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/develop/) | - |
mRemoteNG is the next generation of mRemote, a full-featured, multi-tab remote connections manager.
@@ -36,8 +40,8 @@ https://support.microsoft.com/en-us/kb/2923545
Windows 8+ support RDP version 8+ out of the box.
RDP versions are backwards compatible, so an mRemoteNG client running on Windows 10 can connection successfully to a Windows 2003 host (for example).
RDP versions are backwards compatible, so an mRemoteNG client running on Windows 10 can connect successfully to a Windows 2003 host (for example).
[![Developed with ReSharper](https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/.github/icon_ReSharper.png)](https://www.jetbrains.com/resharper/)
[![Developed with ReSharper](https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/.github/icon_ReSharper.png)](https://www.jetbrains.com/resharper/)

View File

@@ -0,0 +1,84 @@
using System;
using mRemoteNG.App.Info;
using mRemoteNG.App.Update;
using mRemoteNGTests.Properties;
using NUnit.Framework;
namespace mRemoteNGTests.App
{
[TestFixture]
public class UpdaterTests
{
[Test]
public void UpdateStableChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.update);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
[Test]
public void UpdateBetaChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.beta_update);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
[Test]
public void UpdateDevChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.dev_update);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
[Test]
public void UpdateStablePortableChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.update_portable);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
[Test]
public void UpdateBetaPortableChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.beta_update_portable);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
[Test]
public void UpdateDevPortableChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.dev_update_portable);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
}
}

View File

@@ -1,4 +1,5 @@
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using NUnit.Framework;
@@ -30,5 +31,43 @@ namespace mRemoteNGTests.Connection
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
Assert.That(saveTarget.Domain, Is.EqualTo(_testDomain));
}
[Test]
public void CanSaveEnumValuesToString()
{
const ProtocolType targetProtocol = ProtocolType.RAW;
var saveTarget = new AllStringPropertySaveTarget();
DefaultConnectionInfo.Instance.Protocol = targetProtocol;
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
Assert.That(saveTarget.Protocol, Is.EqualTo(targetProtocol.ToString()));
}
[Test]
public void CanSaveIntegerValuesToString()
{
const int targetValue = 123;
var saveTarget = new AllStringPropertySaveTarget();
DefaultConnectionInfo.Instance.RDPMinutesToIdleTimeout = targetValue;
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
Assert.That(saveTarget.RDPMinutesToIdleTimeout, Is.EqualTo(targetValue.ToString()));
}
[Test]
public void CanSaveStringValuesToString()
{
const string targetName = "hello";
var saveTarget = new AllStringPropertySaveTarget();
DefaultConnectionInfo.Instance.Username = targetName;
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
Assert.That(saveTarget.Username, Is.EqualTo(targetName));
}
private class AllStringPropertySaveTarget
{
public string Username { get; set; }
public string Protocol { get; set; }
public string RDPMinutesToIdleTimeout { get; set; }
}
}
}

View File

@@ -60,6 +60,32 @@ namespace mRemoteNGTests.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.75.6164.27544
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
///CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
///Checksum: A1E50ACAC4CB8023527E1E7A0E682459
///.
/// </summary>
internal static string beta_update {
get {
return ResourceManager.GetString("beta_update", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.75.6170.27478
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
///Checksum: 1C35EA199F58001BC4EBB164D8B3D11C.
/// </summary>
internal static string beta_update_portable {
get {
return ResourceManager.GetString("beta_update_portable", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
///&lt;Connections Name=&quot;Connections&quot; Export=&quot;False&quot; Protected=&quot;95syzRuZ4mRxpNkZQzoyX8SDpQXLyMq3GncO8o4SyTBoYvn3TAWgn05ZEU2DrjkM&quot; ConfVersion=&quot;2.5&quot;&gt;
@@ -142,6 +168,32 @@ namespace mRemoteNGTests.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.75.6164.27544
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
///CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
///Checksum: A1E50ACAC4CB8023527E1E7A0E682459
///.
/// </summary>
internal static string dev_update {
get {
return ResourceManager.GetString("dev_update", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.75.6170.27478
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
///Checksum: 1C35EA199F58001BC4EBB164D8B3D11C.
/// </summary>
internal static string dev_update_portable {
get {
return ResourceManager.GetString("dev_update_portable", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;
///&lt;!-- ****************************************************************--&gt;
@@ -276,5 +328,30 @@ namespace mRemoteNGTests.Properties {
return ResourceManager.GetString("test_remotedesktopconnection_rdp", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.72.5065.32737
///dURL: http://downloads.mremoteng.org/mRemoteNG-Installer-1.72.exe
///clURL: http://update.mremoteng.org/changes-1.72.txt
///CertificateThumbprint: 1cbd910dbd6e77f26506e7f600736972f700673f
///.
/// </summary>
internal static string update {
get {
return ResourceManager.GetString("update", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.75.6170.27478
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
///Checksum: 1C35EA199F58001BC4EBB164D8B3D11C.
/// </summary>
internal static string update_portable {
get {
return ResourceManager.GetString("update_portable", resourceCulture);
}
}
}
}

View File

@@ -118,6 +118,12 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="beta_update" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\beta-update.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="beta_update_portable" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\beta-update-portable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="confCons_v2_5" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\confCons_v2_5.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
@@ -142,6 +148,12 @@
<data name="confCons_v2_6_passwordis_Password_fullencryption" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\confCons_v2_6_passwordis_Password_fullencryption.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="dev_update" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\dev-update.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="dev_update_portable" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\dev-update-portable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="test_puttyConnectionManager_database" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\test_puttyConnectionManager_database.dat;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16</value>
</data>
@@ -163,4 +175,10 @@
<data name="test_remotedesktopconnection_rdp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\test_remotedesktopconnection.rdp;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16</value>
</data>
<data name="update" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\update.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="update_portable" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\update-portable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
</root>

View File

@@ -0,0 +1,5 @@
Version: 1.75.6170.27478
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: 1C35EA199F58001BC4EBB164D8B3D11C

View File

@@ -0,0 +1,5 @@
Version: 1.75.6164.27544
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: A1E50ACAC4CB8023527E1E7A0E682459

View File

@@ -0,0 +1,5 @@
Version: 1.75.6170.27478
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: 1C35EA199F58001BC4EBB164D8B3D11C

View File

@@ -0,0 +1,5 @@
Version: 1.75.6164.27544
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: A1E50ACAC4CB8023527E1E7A0E682459

View File

@@ -0,0 +1,5 @@
Version: 1.75.6170.27478
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: 1C35EA199F58001BC4EBB164D8B3D11C

View File

@@ -0,0 +1,5 @@
Version: 1.75.6164.27544
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: A1E50ACAC4CB8023527E1E7A0E682459

View File

@@ -0,0 +1,46 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.UI.Controls;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class ExpandNodeClickHandlerTests
{
private ExpandNodeClickHandler _clickHandler;
private IConnectionTree _connectionTree;
[SetUp]
public void Setup()
{
_connectionTree = Substitute.For<IConnectionTree>();
_clickHandler = new ExpandNodeClickHandler(_connectionTree);
}
[Test]
public void TargetedNodeIsExpanded()
{
var folder = new ContainerInfo();
_clickHandler.Execute(folder);
_connectionTree.Received().ToggleExpansion(folder);
}
[Test]
public void NothingHappensWhenConnectionInfoProvided()
{
_clickHandler.Execute(new ConnectionInfo());
_connectionTree.DidNotReceiveWithAnyArgs().ToggleExpansion(new ConnectionInfo());
}
[Test]
public void ExceptionThrownOnConstructorNullArg()
{
// ReSharper disable once ObjectCreationAsStatement
Assert.Throws<ArgumentNullException>(() => new ExpandNodeClickHandler(null));
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class OpenConnectionClickHandlerTests
{
private OpenConnectionClickHandler _clickHandler;
private IConnectionInitiator _connectionInitiator;
[SetUp]
public void Setup()
{
_connectionInitiator = Substitute.For<IConnectionInitiator>();
_clickHandler = new OpenConnectionClickHandler(_connectionInitiator);
}
[Test]
public void ConnectionOpened()
{
var connectionInfo = new ConnectionInfo();
_clickHandler.Execute(connectionInfo);
_connectionInitiator.Received().OpenConnection(connectionInfo);
}
[Test]
public void DoesNothingWhenGivenContainerInfo()
{
_clickHandler.Execute(new ContainerInfo());
_connectionInitiator.DidNotReceiveWithAnyArgs().OpenConnection(new ConnectionInfo());
}
[Test]
public void ExceptionThrownWhenConstructorGivenNullArg()
{
// ReSharper disable once ObjectCreationAsStatement
Assert.Throws<ArgumentNullException>(() => new OpenConnectionClickHandler(null));
}
[Test]
public void ThrowWhenExecuteGivenNullArg()
{
Assert.Throws<ArgumentNullException>(() => _clickHandler.Execute(null));
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class SwitchToConnectionClickHandlerTests
{
private SwitchToConnectionClickHandler _clickHandler;
private IConnectionInitiator _connectionInitiator;
[SetUp]
public void Setup()
{
_connectionInitiator = Substitute.For<IConnectionInitiator>();
_clickHandler = new SwitchToConnectionClickHandler(_connectionInitiator);
}
[Test]
public void SwitchesToConnection()
{
var connectionInfo = new ConnectionInfo();
_clickHandler.Execute(connectionInfo);
_connectionInitiator.Received().SwitchToOpenConnection(connectionInfo);
}
[Test]
public void DoesNothingWhenGivenContainerInfo()
{
_clickHandler.Execute(new ContainerInfo());
_connectionInitiator.DidNotReceiveWithAnyArgs().SwitchToOpenConnection(new ConnectionInfo());
}
[Test]
public void ExceptionThrownWhenConstructorGivenNullArg()
{
// ReSharper disable once ObjectCreationAsStatement
Assert.Throws<ArgumentNullException>(() => new SwitchToConnectionClickHandler(null));
}
[Test]
public void ThrowWhenExecuteGivenNullArg()
{
Assert.Throws<ArgumentNullException>(() => _clickHandler.Execute(null));
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Tree;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class TreeNodeCompositeClickHandlerTests
{
private TreeNodeCompositeClickHandler _clickHandler;
private ConnectionInfo _connectionInfo;
[SetUp]
public void Setup()
{
_clickHandler = new TreeNodeCompositeClickHandler();
_connectionInfo = new ConnectionInfo();
}
[Test]
public void ExecutesAllItsHandlers()
{
var handler1 = Substitute.For<ITreeNodeClickHandler>();
var handler2 = Substitute.For<ITreeNodeClickHandler>();
_clickHandler.ClickHandlers = new[] {handler1, handler2};
_clickHandler.Execute(_connectionInfo);
handler1.Received().Execute(_connectionInfo);
handler2.Received().Execute(_connectionInfo);
}
[Test]
public void ThrowWhenExecuteGivenNullArg()
{
Assert.Throws<ArgumentNullException>(() => _clickHandler.Execute(null));
}
}
}

View File

@@ -0,0 +1,51 @@
using System.Threading;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Controls;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class ConnectionTreeTests
{
private ConnectionTree _connectionTree;
private ConnectionTreeModel _connectionTreeModel;
[SetUp]
public void Setup()
{
_connectionTreeModel = CreateConnectionTreeModel();
_connectionTree = new ConnectionTree
{
PostSetupActions = new IConnectionTreeDelegate[] {new RootNodeExpander()}
};
}
[TearDown]
public void Teardown()
{
_connectionTree.Dispose();
}
[Test, Apartment(ApartmentState.STA)]
public void CanDeleteLastFolderInTheTree()
{
var lastFolder = new ContainerInfo();
_connectionTreeModel.RootNodes[0].AddChild(lastFolder);
_connectionTree.ConnectionTreeModel = _connectionTreeModel;
_connectionTree.SelectObject(lastFolder);
_connectionTree.DeleteSelectedNode();
Assert.That(_connectionTree.GetRootConnectionNode().HasChildren, Is.False);
}
private ConnectionTreeModel CreateConnectionTreeModel()
{
var connectionTreeModel = new ConnectionTreeModel();
connectionTreeModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
return connectionTreeModel;
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Controls;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class PreviousSessionOpenerTests
{
private PreviousSessionOpener _previousSessionOpener;
private IConnectionInitiator _connectionInitiator;
private IConnectionTree _connectionTree;
[SetUp]
public void Setup()
{
_connectionInitiator = Substitute.For<IConnectionInitiator>();
_previousSessionOpener = new PreviousSessionOpener(_connectionInitiator);
_connectionTree = Substitute.For<IConnectionTree>();
_connectionTree.GetRootConnectionNode().Returns(BuildTree());
}
[Test]
public void AllRequestedSessionsAreReopened()
{
_previousSessionOpener.Execute(_connectionTree);
_connectionInitiator.ReceivedWithAnyArgs(2).OpenConnection(new ConnectionInfo());
}
[Test]
public void ExceptionThrownWhenConstructorGivenNullArg()
{
// ReSharper disable once ObjectCreationAsStatement
Assert.Throws<ArgumentNullException>(() => new PreviousSessionOpener(null));
}
private RootNodeInfo BuildTree()
{
var root = new RootNodeInfo(RootNodeType.Connection);
root.AddChild(new ConnectionInfo { PleaseConnect = true });
root.AddChild(new ConnectionInfo());
root.AddChild(new ConnectionInfo { PleaseConnect = true });
return root;
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Linq;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Controls;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class PreviouslyOpenedFolderExpanderTests
{
private PreviouslyOpenedFolderExpander _folderExpander;
private IConnectionTree _connectionTree;
[SetUp]
public void Setup()
{
_folderExpander = new PreviouslyOpenedFolderExpander();
_connectionTree = Substitute.For<IConnectionTree>();
}
[Test]
public void ExpandsAllFoldersThatAreMarkedForExpansion()
{
var connectionTreeModel = GenerateConnectionTreeModel();
_connectionTree.ConnectionTreeModel.Returns(connectionTreeModel);
_connectionTree.GetRootConnectionNode().Returns(connectionTreeModel.RootNodes[0]);
_folderExpander.Execute(_connectionTree);
Assert.That(_connectionTree.ExpandedObjects, Is.EquivalentTo(connectionTreeModel.GetRecursiveChildList().OfType<ContainerInfo>().Where(info => info.IsExpanded)));
}
private ConnectionTreeModel GenerateConnectionTreeModel()
{
var connectionTreeModel = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection) { IsExpanded = true };
var folder1 = new ContainerInfo { IsExpanded = true };
var folder2 = new ContainerInfo();
var con1 = new ConnectionInfo();
root.AddChild(folder1);
folder1.AddChild(folder2);
root.AddChild(con1);
connectionTreeModel.AddRootNode(root);
return connectionTreeModel;
}
}
}

View File

@@ -0,0 +1,47 @@
using System.Windows.Forms;
using mRemoteNG.Connection;
using mRemoteNG.Tree;
using mRemoteNG.UI.Controls;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class SelectedConnectionDeletionConfirmerTests
{
private SelectedConnectionDeletionConfirmer _deletionConfirmer;
private IConnectionTree _connectionTree;
[SetUp]
public void Setup()
{
_connectionTree = Substitute.For<IConnectionTree>();
_connectionTree.SelectedNode.Returns(new ConnectionInfo());
}
[Test]
public void ClickingYesReturnsTrue()
{
_deletionConfirmer = new SelectedConnectionDeletionConfirmer(_connectionTree, MockClickYes);
Assert.That(_deletionConfirmer.Confirm(), Is.True);
}
[Test]
public void ClickingNoReturnsFalse()
{
_deletionConfirmer = new SelectedConnectionDeletionConfirmer(_connectionTree, MockClickNo);
Assert.That(_deletionConfirmer.Confirm(), Is.False);
}
private DialogResult MockClickYes(string promptMessage, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
{
return DialogResult.Yes;
}
private DialogResult MockClickNo(string promptMessage, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
{
return DialogResult.No;
}
}
}

View File

@@ -0,0 +1,32 @@
using System.Threading;
using mRemoteNG.UI.Window;
using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNGTests.UI.Window
{
public class ConnectionTreeWindowTests
{
private ConnectionTreeWindow _connectionTreeWindow;
[SetUp]
public void Setup()
{
_connectionTreeWindow = new ConnectionTreeWindow(new DockContent());
}
[TearDown]
public void Teardown()
{
_connectionTreeWindow.Close();
}
[Test, Apartment(ApartmentState.STA)]
public void CanShowWindow()
{
_connectionTreeWindow.Show();
Assert.That(_connectionTreeWindow.Visible);
}
}
}

View File

@@ -22,7 +22,7 @@
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -31,7 +31,7 @@
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -40,7 +40,7 @@
<OutputPath>bin\x86\Debug Portable\</OutputPath>
<DefineConstants>TRACE;DEBUG;PORTABLE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -49,7 +49,7 @@
<DefineConstants>TRACE;PORTABLE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -101,12 +101,15 @@
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework">
<Private>False</Private>
</Reference>
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="App\LoggerTests.cs" />
<Compile Include="App\UpdaterTests.cs" />
<Compile Include="BinaryFileTests.cs" />
<Compile Include="Config\Serializers\DataTableSerializerTests.cs" />
<Compile Include="Config\Serializers\PortScanDeserializerTests.cs" />
@@ -127,6 +130,7 @@
<Compile Include="Security\KeyDerivation\Pkcs5S2KeyGeneratorTests.cs" />
<Compile Include="Security\SecureStringExtensionsTests.cs" />
<Compile Include="Tools\ExternalToolsArgumentParserTests.cs" />
<Compile Include="Tree\ClickHandlers\TreeNodeCompositeClickHandlerTests.cs" />
<Compile Include="Tree\ConnectionTreeDragAndDropHandlerTests.cs" />
<Compile Include="Tree\ConnectionTreeModelTests.cs" />
<Compile Include="Connection\ConnectionInfoInheritanceTests.cs" />
@@ -146,8 +150,15 @@
<Compile Include="Security\CryptographyProviderFactoryTests.cs" />
<Compile Include="Security\EncryptedSecureStringTests.cs" />
<Compile Include="Security\LegacyRijndaelCryptographyProviderTests.cs" />
<Compile Include="Tree\ConnectionTreeTests.cs" />
<Compile Include="Tree\ClickHandlers\ExpandNodeClickHandlerTests.cs" />
<Compile Include="Tree\NodeSearcherTests.cs" />
<Compile Include="Tree\ClickHandlers\OpenConnectionClickHandlerTests.cs" />
<Compile Include="Tree\PreviouslyOpenedFolderExpanderTests.cs" />
<Compile Include="Tree\PreviousSessionOpenerTests.cs" />
<Compile Include="Tree\RootNodeInfoTests.cs" />
<Compile Include="Tree\ClickHandlers\SwitchToConnectionClickHandlerTests.cs" />
<Compile Include="Tree\SelectedConnectionDeletionConfirmerTests.cs" />
<Compile Include="UI\Controls\TestForm.cs">
<SubType>Form</SubType>
</Compile>
@@ -157,6 +168,7 @@
<Compile Include="UI\Forms\OptionsFormSetupAndTeardown.cs" />
<Compile Include="UI\Forms\PasswordFormTests.cs" />
<Compile Include="UI\WindowListTests.cs" />
<Compile Include="UI\Window\ConnectionTreeWindowTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
@@ -207,6 +219,14 @@
<ItemGroup>
<None Include="Resources\confCons_v2_5_passwordis_Password_fullencryption.xml" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\beta-update-portable.txt" />
<Content Include="Resources\beta-update.txt" />
<Content Include="Resources\dev-update-portable.txt" />
<Content Include="Resources\dev-update.txt" />
<Content Include="Resources\update-portable.txt" />
<Content Include="Resources\update.txt" />
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>

View File

@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tree_005Cclickhandlers/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -8,24 +8,23 @@ using System.Windows.Forms;
namespace mRemoteNG.App
{
public class CompatibilityChecker
public static class CompatibilityChecker
{
public void CheckCompatibility()
public static void CheckCompatibility()
{
CheckFipsPolicy();
CheckLenovoAutoScrollUtility();
}
private void CheckFipsPolicy()
private static void CheckFipsPolicy()
{
if (FipsPolicyEnabledForServer2003() || FipsPolicyEnabledForServer2008AndNewer())
{
MessageBox.Show(frmMain.Default, string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName, GeneralAppInfo.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error));
Environment.Exit(1);
}
Logger.Instance.InfoFormat("Checking FIPS Policy...");
if (!FipsPolicyEnabledForServer2003() && !FipsPolicyEnabledForServer2008AndNewer()) return;
MessageBox.Show(frmMain.Default, string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName, GeneralAppInfo.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error));
Environment.Exit(1);
}
private bool FipsPolicyEnabledForServer2003()
private static bool FipsPolicyEnabledForServer2003()
{
var regKey = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Lsa");
var fipsPolicy = regKey?.GetValue("FIPSAlgorithmPolicy");
@@ -34,7 +33,7 @@ namespace mRemoteNG.App
return (int)fipsPolicy != 0;
}
private bool FipsPolicyEnabledForServer2008AndNewer()
private static bool FipsPolicyEnabledForServer2008AndNewer()
{
var regKey = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Lsa\\FIPSAlgorithmPolicy");
var fipsPolicy = regKey?.GetValue("Enabled");
@@ -43,12 +42,14 @@ namespace mRemoteNG.App
return (int)fipsPolicy != 0;
}
private void CheckLenovoAutoScrollUtility()
private static void CheckLenovoAutoScrollUtility()
{
Logger.Instance.InfoFormat("Checking Lenovo AutoScroll Utility...");
if (!Settings.Default.CompatibilityWarnLenovoAutoScrollUtility)
return;
Process[] proccesses = new Process[] { };
var proccesses = new Process[] { };
try
{
proccesses = Process.GetProcessesByName("virtscrl");
@@ -58,12 +59,10 @@ namespace mRemoteNG.App
Runtime.MessageCollector.AddExceptionMessage("Error in CheckLenovoAutoScrollUtility", ex);
}
if (proccesses.Length > 0)
{
CTaskDialog.MessageBox(Application.ProductName, Language.strCompatibilityProblemDetected, string.Format(Language.strCompatibilityLenovoAutoScrollUtilityDetected, Application.ProductName), "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.Ok, ESysIcons.Warning, ESysIcons.Warning);
if (CTaskDialog.VerificationChecked)
Settings.Default.CompatibilityWarnLenovoAutoScrollUtility = false;
}
if (proccesses.Length <= 0) return;
CTaskDialog.MessageBox(Application.ProductName, Language.strCompatibilityProblemDetected, string.Format(Language.strCompatibilityLenovoAutoScrollUtilityDetected, Application.ProductName), "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.Ok, ESysIcons.Warning, ESysIcons.Warning);
if (CTaskDialog.VerificationChecked)
Settings.Default.CompatibilityWarnLenovoAutoScrollUtility = false;
}
}
}

View File

@@ -34,7 +34,7 @@ namespace mRemoteNG.App
}
if (exportForm.ShowDialog(frmMain.Default) != DialogResult.OK)
return ;
return;
ConnectionInfo exportTarget;
switch (exportForm.Scope)

View File

@@ -11,23 +11,27 @@ namespace mRemoteNG.App.Info
{
public static class GeneralAppInfo
{
public static readonly string UrlHome = "http://www.mremoteng.org/";
public static readonly string UrlDonate = "http://donate.mremoteng.org/";
public static readonly string UrlForum = "http://forum.mremoteng.org/";
public static readonly string UrlBugs = "http://bugs.mremoteng.org/";
public static readonly string ApplicationVersion = Application.ProductVersion;
public const string UrlHome = "http://www.mremoteng.org/";
public const string UrlDonate = "http://donate.mremoteng.org/";
public const string UrlForum = "http://forum.mremoteng.org/";
public const string UrlBugs = "http://bugs.mremoteng.org/";
public static string ApplicationVersion = Application.ProductVersion;
public static readonly string ProductName = Application.ProductName;
public static readonly string Copyright = ((AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyCopyrightAttribute), false)).Copyright;
public static readonly string HomePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
public static string ReportingFilePath = "";
//public static string ReportingFilePath = "";
public static readonly string PuttyPath = HomePath + "\\PuTTYNG.exe";
public static string UserAgent
{
get
{
var details = new List<string>();
details.Add("compatible");
details.Add(OSVersion.Platform == PlatformID.Win32NT ? $"Windows NT {OSVersion.Version.Major}.{OSVersion.Version.Minor}": OSVersion.VersionString);
var details = new List<string>
{
"compatible",
OSVersion.Platform == PlatformID.Win32NT
? $"Windows NT {OSVersion.Version.Major}.{OSVersion.Version.Minor}"
: OSVersion.VersionString
};
if (Is64BitProcess)
{
details.Add("WOW64");

View File

@@ -1,34 +1,72 @@
namespace mRemoteNG.App.Info
using System;
namespace mRemoteNG.App.Info
{
public static class UpdateChannelInfo
{
public static string FileName
public const string STABLE = "Stable";
public const string BETA = "Beta";
public const string DEV = "Development";
/* no #if here since they are used for unit tests as well */
public const string STABLE_PORTABLE = "update-portable.txt";
public const string BETA_PORTABLE = "beta-update-portable.txt";
public const string DEV_PORTABLE = "dev-update-portable.txt";
public const string STABLE_MSI = "update.txt";
public const string BETA_MSI = "beta-update.txt";
public const string DEV_MSI = "dev-update.txt";
public static Uri GetUpdateChannelInfo()
{
var channel = IsValidChannel(Settings.Default.UpdateChannel) ? Settings.Default.UpdateChannel : STABLE;
return GetUpdateTxtUri(channel);
}
private static string GetChannelFileName(string channel)
{
#if PORTABLE
get
{
/* */
/* return PORTABLE update files here */
/* */
#if DEBUG
return "update-portable-debug.txt";
#else
return Settings.Default.UpdateChannel.ToLowerInvariant() == "debug" ? "update-portable-debug.txt" : "update-portable.txt";
#endif
}
switch (channel)
{
case STABLE:
return STABLE_PORTABLE;
case BETA:
return BETA_PORTABLE;
case DEV:
return DEV_PORTABLE;
default:
return STABLE_PORTABLE;
}
#else //NOT portable
get
{
/* */
/* return INSTALLER update files here */
/* */
#if DEBUG
return "update-debug.txt";
#else
return Settings.Default.UpdateChannel.ToLowerInvariant() == "debug" ? "update-debug.txt" : "update.txt";
#endif
}
switch (channel)
{
case STABLE:
return STABLE_MSI;
case BETA:
return BETA_MSI;
case DEV:
return DEV_MSI;
default:
return STABLE_MSI;
}
#endif //endif for PORTABLE
}
private static Uri GetUpdateTxtUri(string channel)
{
return new Uri(new Uri(Settings.Default.UpdateAddress), new Uri(GetChannelFileName(channel), UriKind.Relative));
}
private static bool IsValidChannel(string s)
{
return s.Equals(STABLE) || s.Equals(BETA) || s.Equals(DEV);
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
#pragma warning disable 169
namespace mRemoteNG.App
{
@@ -326,6 +327,11 @@ namespace mRemoteNG.App
/// </summary>
public const int WM_ACTIVATEAPP = 0x1C;
/// <summary>
/// Sent to a window if the mouse causes the cursor to move within a window and mouse input is not captured.
/// </summary>
public const int WM_SETCURSOR = 0x20;
/// <summary>
/// Sent when the cursor is in an inactive window and the user presses a mouse button. The parent window receives this message only if the child window passes it to the DefWindowProc function.
/// </summary>

View File

@@ -33,7 +33,7 @@ namespace mRemoteNG.App
#region Public Properties
public static WindowList WindowList { get; set; }
public static MessageCollector MessageCollector { get; set; }
public static Controls.NotificationAreaIcon NotificationAreaIcon { get; set; }
public static NotificationAreaIcon NotificationAreaIcon { get; set; }
public static bool IsConnectionsFileLoaded { get; set; }
public static RemoteConnectionsSyncronizer RemoteConnectionsSyncronizer { get; set; }
// ReSharper disable once UnusedAutoPropertyAccessor.Local
@@ -42,8 +42,8 @@ namespace mRemoteNG.App
public static SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
public static ConnectionTreeModel ConnectionTreeModel
{
get { return Windows.TreeForm.ConnectionTreeModel; }
set { Windows.TreeForm.ConnectionTreeModel = value; }
get { return Windows.TreeForm.ConnectionTree.ConnectionTreeModel; }
set { Windows.TreeForm.ConnectionTree.ConnectionTreeModel = value; }
}
#endregion
@@ -237,7 +237,7 @@ namespace mRemoteNG.App
// Load config
connectionsLoader.ConnectionFileName = filename;
ConnectionTreeModel = connectionsLoader.LoadConnections(false);
Windows.TreeForm.ConnectionTreeModel = ConnectionTreeModel;
Windows.TreeForm.ConnectionTree.ConnectionTreeModel = ConnectionTreeModel;
}
catch (Exception ex)
{
@@ -274,7 +274,7 @@ namespace mRemoteNG.App
{
if (withDialog)
{
var loadDialog = Controls.ConnectionsLoadDialog();
var loadDialog = ConnectionsLoadDialog();
if (loadDialog.ShowDialog() != DialogResult.OK) return;
connectionsLoader.ConnectionFileName = loadDialog.FileName;
}
@@ -288,7 +288,7 @@ namespace mRemoteNG.App
connectionsLoader.UseDatabase = Settings.Default.UseSQLServer;
ConnectionTreeModel = connectionsLoader.LoadConnections(false);
Windows.TreeForm.ConnectionTreeModel = ConnectionTreeModel;
Windows.TreeForm.ConnectionTree.ConnectionTreeModel = ConnectionTreeModel;
if (Settings.Default.UseSQLServer)
{
@@ -353,6 +353,16 @@ namespace mRemoteNG.App
}
}
private static OpenFileDialog ConnectionsLoadDialog()
{
return new OpenFileDialog
{
CheckFileExists = true,
InitialDirectory = ConnectionsFileInfo.DefaultConnectionsPath,
Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*"
};
}
private static void CreateBackupFile(string fileName)
{
// This intentionally doesn't prune any existing backup files. We just assume the user doesn't want any new ones created.
@@ -593,7 +603,8 @@ namespace mRemoteNG.App
connectionInfo.Protocol = url.StartsWith("https:") ? ProtocolType.HTTPS : ProtocolType.HTTP;
connectionInfo.SetDefaultPort();
connectionInfo.IsQuickConnect = true;
ConnectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
var connectionInitiator = new ConnectionInitiator();
connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
}
public static void GoToWebsite()

View File

@@ -1,11 +1,4 @@
using mRemoteNG.App.Info;
using mRemoteNG.App.Update;
using mRemoteNG.Config.Connections;
using mRemoteNG.Connection;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms;
using System;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
@@ -14,22 +7,26 @@ using System.IO;
using System.Management;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.App.Info;
using mRemoteNG.App.Update;
using mRemoteNG.Config.Connections;
using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Connection;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.UI;
using WeifenLuo.WinFormsUI.Docking;
using mRemoteNG.UI.Forms;
namespace mRemoteNG.App
{
public class Startup
{
private CompatibilityChecker _compatibilityChecker;
private AppUpdater _appUpdate;
public static Startup Instance { get; } = new Startup();
private Startup()
{
_compatibilityChecker = new CompatibilityChecker();
_appUpdate = new AppUpdater();
}
@@ -41,49 +38,31 @@ namespace mRemoteNG.App
{
Debug.Print("---------------------------" + Environment.NewLine + "[START] - " + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture));
LogStartupData();
_compatibilityChecker.CheckCompatibility();
CompatibilityChecker.CheckCompatibility();
ParseCommandLineArgs();
IeBrowserEmulation.Register();
GetConnectionIcons();
DefaultConnectionInfo.Instance.LoadFrom(Settings.Default, (a)=>"ConDefault"+a);
DefaultConnectionInheritance.Instance.LoadFrom(Settings.Default, (a)=>"InhDefault"+a);
DefaultConnectionInfo.Instance.LoadFrom(Settings.Default, a=>"ConDefault"+a);
DefaultConnectionInheritance.Instance.LoadFrom(Settings.Default, a=>"InhDefault"+a);
}
public void SetDefaultLayout()
private static void GetConnectionIcons()
{
frmMain.Default.pnlDock.Visible = false;
frmMain.Default.pnlDock.DockLeftPortion = frmMain.Default.pnlDock.Width * 0.2;
frmMain.Default.pnlDock.DockRightPortion = frmMain.Default.pnlDock.Width * 0.2;
frmMain.Default.pnlDock.DockTopPortion = frmMain.Default.pnlDock.Height * 0.25;
frmMain.Default.pnlDock.DockBottomPortion = frmMain.Default.pnlDock.Height * 0.25;
Windows.TreePanel.Show(frmMain.Default.pnlDock, DockState.DockLeft);
Windows.ConfigPanel.Show(frmMain.Default.pnlDock);
Windows.ConfigPanel.DockTo(Windows.TreePanel.Pane, DockStyle.Bottom, -1);
Windows.ScreenshotForm.Hide();
frmMain.Default.pnlDock.Visible = true;
}
private void GetConnectionIcons()
{
string iPath = GeneralAppInfo.HomePath + "\\Icons\\";
var iPath = GeneralAppInfo.HomePath + "\\Icons\\";
if (Directory.Exists(iPath) == false)
{
return;
}
foreach (string f in Directory.GetFiles(iPath, "*.ico", SearchOption.AllDirectories))
foreach (var f in Directory.GetFiles(iPath, "*.ico", SearchOption.AllDirectories))
{
FileInfo fInfo = new FileInfo(f);
var fInfo = new FileInfo(f);
Array.Resize(ref ConnectionIcon.Icons, ConnectionIcon.Icons.Length + 1);
ConnectionIcon.Icons.SetValue(fInfo.Name.Replace(".ico", ""), ConnectionIcon.Icons.Length - 1);
}
}
private void LogStartupData()
private static void LogStartupData()
{
if (!Settings.Default.WriteLogFile) return;
LogApplicationData();
@@ -93,17 +72,17 @@ namespace mRemoteNG.App
LogCultureData();
}
private void LogSystemData()
private static void LogSystemData()
{
string osData = GetOperatingSystemData();
string architecture = GetArchitectureData();
var osData = GetOperatingSystemData();
var architecture = GetArchitectureData();
Logger.Instance.InfoFormat(string.Join(" ", Array.FindAll(new[] { osData, architecture }, s => !string.IsNullOrEmpty(Convert.ToString(s)))));
}
private string GetOperatingSystemData()
private static string GetOperatingSystemData()
{
string osVersion = string.Empty;
string servicePack = string.Empty;
var osVersion = string.Empty;
var servicePack = string.Empty;
try
{
@@ -118,13 +97,13 @@ namespace mRemoteNG.App
{
Logger.Instance.WarnFormat($"Error retrieving operating system information from WMI. {ex.Message}");
}
string osData = string.Join(" ", new string[] { osVersion, servicePack });
var osData = string.Join(" ", osVersion, servicePack);
return osData;
}
private string GetOSServicePack(string servicePack, ManagementObject managementObject)
private static string GetOSServicePack(string servicePack, ManagementObject managementObject)
{
int servicePackNumber = Convert.ToInt32(managementObject.GetPropertyValue("ServicePackMajorVersion"));
var servicePackNumber = Convert.ToInt32(managementObject.GetPropertyValue("ServicePackMajorVersion"));
if (servicePackNumber != 0)
{
servicePack = $"Service Pack {servicePackNumber}";
@@ -132,15 +111,15 @@ namespace mRemoteNG.App
return servicePack;
}
private string GetArchitectureData()
private static string GetArchitectureData()
{
string architecture = string.Empty;
var architecture = string.Empty;
try
{
foreach (var o in new ManagementObjectSearcher("SELECT * FROM Win32_Processor WHERE DeviceID=\'CPU0\'").Get())
{
var managementObject = (ManagementObject) o;
int addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth"));
var addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth"));
architecture = $"{addressWidth}-bit";
}
}
@@ -151,7 +130,7 @@ namespace mRemoteNG.App
return architecture;
}
private void LogApplicationData()
private static void LogApplicationData()
{
#if !PORTABLE
Logger.Instance.InfoFormat($"{Application.ProductName} {Application.ProductVersion} starting.");
@@ -161,17 +140,17 @@ namespace mRemoteNG.App
#endif
}
private void LogCmdLineArgs()
private static void LogCmdLineArgs()
{
Logger.Instance.InfoFormat($"Command Line: {Environment.GetCommandLineArgs()}");
}
private void LogCLRData()
private static void LogCLRData()
{
Logger.Instance.InfoFormat($"Microsoft .NET CLR {Environment.Version}");
}
private void LogCultureData()
private static void LogCultureData()
{
Logger.Instance.InfoFormat(
$"System Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}");
@@ -197,7 +176,7 @@ namespace mRemoteNG.App
return;
}
DateTime nextUpdateCheck = Convert.ToDateTime(Settings.Default.CheckForUpdatesLastCheck.Add(TimeSpan.FromDays(Convert.ToDouble(Settings.Default.CheckForUpdatesFrequencyDays))));
var nextUpdateCheck = Convert.ToDateTime(Settings.Default.CheckForUpdatesLastCheck.Add(TimeSpan.FromDays(Convert.ToDouble(Settings.Default.CheckForUpdatesFrequencyDays))));
if (!Settings.Default.UpdatePending && DateTime.UtcNow < nextUpdateCheck)
{
return;
@@ -211,7 +190,7 @@ namespace mRemoteNG.App
{
if (frmMain.Default.InvokeRequired)
{
frmMain.Default.Invoke(new AsyncCompletedEventHandler(GetUpdateInfoCompleted), new object[] { sender, e });
frmMain.Default.Invoke(new AsyncCompletedEventHandler(GetUpdateInfoCompleted), sender, e);
return;
}
@@ -225,7 +204,7 @@ namespace mRemoteNG.App
}
if (e.Error != null)
{
throw (e.Error);
throw e.Error;
}
if (_appUpdate.IsUpdateAvailable())
@@ -240,13 +219,13 @@ namespace mRemoteNG.App
}
private void ParseCommandLineArgs()
private static void ParseCommandLineArgs()
{
try
{
CmdArgumentsInterpreter cmd = new CmdArgumentsInterpreter(Environment.GetCommandLineArgs());
var cmd = new CmdArgumentsInterpreter(Environment.GetCommandLineArgs());
string ConsParam = "";
var ConsParam = "";
if (cmd["cons"] != null)
{
ConsParam = "cons";
@@ -256,7 +235,7 @@ namespace mRemoteNG.App
ConsParam = "c";
}
string ResetPosParam = "";
var ResetPosParam = "";
if (cmd["resetpos"] != null)
{
ResetPosParam = "resetpos";
@@ -266,7 +245,7 @@ namespace mRemoteNG.App
ResetPosParam = "rp";
}
string ResetPanelsParam = "";
var ResetPanelsParam = "";
if (cmd["resetpanels"] != null)
{
ResetPanelsParam = "resetpanels";
@@ -276,7 +255,7 @@ namespace mRemoteNG.App
ResetPanelsParam = "rpnl";
}
string ResetToolbarsParam = "";
var ResetToolbarsParam = "";
if (cmd["resettoolbar"] != null)
{
ResetToolbarsParam = "resettoolbar";
@@ -293,7 +272,7 @@ namespace mRemoteNG.App
ResetToolbarsParam = "rtbr";
}
string NoReconnectParam = "";
var NoReconnectParam = "";
if (cmd["noreconnect"] != null)
{
NoReconnectParam = "noreconnect";
@@ -313,7 +292,7 @@ namespace mRemoteNG.App
Settings.Default.CustomConsPath = GeneralAppInfo.HomePath + "\\" + cmd[ConsParam];
return;
}
else if (File.Exists(ConnectionsFileInfo.DefaultConnectionsPath + "\\" + cmd[ConsParam]))
if (File.Exists(ConnectionsFileInfo.DefaultConnectionsPath + "\\" + cmd[ConsParam]))
{
Settings.Default.LoadConsFromCustomLocation = true;
Settings.Default.CustomConsPath = ConnectionsFileInfo.DefaultConnectionsPath + "\\" + cmd[ConsParam];

View File

@@ -9,116 +9,120 @@ using mRemoteNG.Security.SymmetricEncryption;
using System.Security.Cryptography;
#if !PORTABLE
using mRemoteNG.Tools;
#else
using System.Windows.Forms;
#endif
namespace mRemoteNG.App.Update
{
public class AppUpdater
{
private WebProxy _webProxy;
public class AppUpdater
{
private WebProxy _webProxy;
private Thread _getUpdateInfoThread;
private Thread _getChangeLogThread;
#region Public Properties
#region Public Properties
public UpdateInfo CurrentUpdateInfo { get; private set; }
public string ChangeLog { get; private set; }
public string ChangeLog { get; private set; }
public bool IsGetUpdateInfoRunning => _getUpdateInfoThread != null && _getUpdateInfoThread.IsAlive;
public bool IsGetUpdateInfoRunning => _getUpdateInfoThread != null && _getUpdateInfoThread.IsAlive;
private bool IsGetChangeLogRunning => _getChangeLogThread != null && _getChangeLogThread.IsAlive;
private bool IsGetChangeLogRunning => _getChangeLogThread != null && _getChangeLogThread.IsAlive;
public bool IsDownloadUpdateRunning => _downloadUpdateWebClient != null;
public bool IsDownloadUpdateRunning => _downloadUpdateWebClient != null;
#endregion
#region Public Methods
public AppUpdater()
{
SetProxySettings();
}
#endregion
private void SetProxySettings()
{
var shouldWeUseProxy = Settings.Default.UpdateUseProxy;
var proxyAddress = Settings.Default.UpdateProxyAddress;
var port = Settings.Default.UpdateProxyPort;
var useAuthentication = Settings.Default.UpdateProxyUseAuthentication;
var username = Settings.Default.UpdateProxyAuthUser;
#region Public Methods
public AppUpdater()
{
SetProxySettings();
}
private void SetProxySettings()
{
var shouldWeUseProxy = Settings.Default.UpdateUseProxy;
var proxyAddress = Settings.Default.UpdateProxyAddress;
var port = Settings.Default.UpdateProxyPort;
var useAuthentication = Settings.Default.UpdateProxyUseAuthentication;
var username = Settings.Default.UpdateProxyAuthUser;
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
var password = cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, Runtime.EncryptionKey);
var password = cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, Runtime.EncryptionKey);
SetProxySettings(shouldWeUseProxy, proxyAddress, port, useAuthentication, username, password);
}
public void SetProxySettings(bool useProxy, string address, int port, bool useAuthentication, string username, string password)
{
if (useProxy && !string.IsNullOrEmpty(address))
{
_webProxy = port != 0 ? new WebProxy(address, port) : new WebProxy(address);
}
_webProxy.Credentials = useAuthentication ? new NetworkCredential(username, password) : null;
}
else
{
_webProxy = null;
}
}
public bool IsUpdateAvailable()
{
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
return false;
}
return CurrentUpdateInfo.Version > GeneralAppInfo.GetApplicationVersion();
}
public void GetUpdateInfoAsync()
{
if (IsGetUpdateInfoRunning)
{
_getUpdateInfoThread.Abort();
}
_getUpdateInfoThread = new Thread(GetUpdateInfo);
_getUpdateInfoThread.SetApartmentState(ApartmentState.STA);
_getUpdateInfoThread.IsBackground = true;
_getUpdateInfoThread.Start();
}
public void GetChangeLogAsync()
{
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync().");
}
if (IsGetChangeLogRunning)
{
_getChangeLogThread.Abort();
}
_getChangeLogThread = new Thread(GetChangeLog);
_getChangeLogThread.SetApartmentState(ApartmentState.STA);
_getChangeLogThread.IsBackground = true;
_getChangeLogThread.Start();
}
public void DownloadUpdateAsync()
{
if (_downloadUpdateWebClient != null)
{
throw new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress.");
}
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync().");
}
public void SetProxySettings(bool useProxy, string address, int port, bool useAuthentication, string username, string password)
{
if (useProxy && !string.IsNullOrEmpty(address))
{
_webProxy = port != 0 ? new WebProxy(address, port) : new WebProxy(address);
_webProxy.Credentials = useAuthentication ? new NetworkCredential(username, password) : null;
}
else
{
_webProxy = null;
}
}
public bool IsUpdateAvailable()
{
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
return false;
}
return CurrentUpdateInfo.Version > GeneralAppInfo.GetApplicationVersion();
}
public void GetUpdateInfoAsync()
{
if (IsGetUpdateInfoRunning)
{
_getUpdateInfoThread.Abort();
}
_getUpdateInfoThread = new Thread(GetUpdateInfo);
_getUpdateInfoThread.SetApartmentState(ApartmentState.STA);
_getUpdateInfoThread.IsBackground = true;
_getUpdateInfoThread.Start();
}
public void GetChangeLogAsync()
{
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync().");
}
if (IsGetChangeLogRunning)
{
_getChangeLogThread.Abort();
}
_getChangeLogThread = new Thread(GetChangeLog);
_getChangeLogThread.SetApartmentState(ApartmentState.STA);
_getChangeLogThread.IsBackground = true;
_getChangeLogThread.Start();
}
public void DownloadUpdateAsync()
{
if (_downloadUpdateWebClient != null)
{
throw new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress.");
}
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
throw new InvalidOperationException(
"CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync().");
}
#if !PORTABLE
CurrentUpdateInfo.UpdateFilePath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi"));
#else
@@ -138,133 +142,138 @@ namespace mRemoteNG.App.Update
}
#endif
DownloadUpdateWebClient.DownloadFileAsync(CurrentUpdateInfo.DownloadAddress, CurrentUpdateInfo.UpdateFilePath);
}
#endregion
#region Private Properties
private WebClient _downloadUpdateWebClient;
private WebClient DownloadUpdateWebClient
{
get
{
if (_downloadUpdateWebClient != null)
{
return _downloadUpdateWebClient;
}
_downloadUpdateWebClient = CreateWebClient();
_downloadUpdateWebClient.DownloadProgressChanged += DownloadUpdateProgressChanged;
_downloadUpdateWebClient.DownloadFileCompleted += DownloadUpdateCompleted;
return _downloadUpdateWebClient;
}
}
#endregion
#region Private Methods
private WebClient CreateWebClient()
{
var webClient = new WebClient();
webClient.Headers.Add("user-agent", GeneralAppInfo.UserAgent);
webClient.Proxy = _webProxy;
return webClient;
}
private static DownloadStringCompletedEventArgs NewDownloadStringCompletedEventArgs(string result, Exception exception, bool cancelled, object userToken)
{
var type = typeof(DownloadStringCompletedEventArgs);
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
Type[] argumentTypes = {typeof(string), typeof(Exception), typeof(bool), typeof(object)};
var constructor = type.GetConstructor(bindingFlags, null, argumentTypes, null);
object[] arguments = {result, exception, cancelled, userToken};
}
return (DownloadStringCompletedEventArgs)constructor.Invoke(arguments);
}
private DownloadStringCompletedEventArgs DownloadString(Uri address)
{
var webClient = CreateWebClient();
var result = string.Empty;
Exception exception = null;
var cancelled = false;
try
{
result = webClient.DownloadString(address);
}
catch (ThreadAbortException)
{
cancelled = true;
}
catch (Exception ex)
{
exception = ex;
}
return NewDownloadStringCompletedEventArgs(result, exception, cancelled, null);
}
private void GetUpdateInfo()
{
var updateFileUri = new Uri(new Uri(Convert.ToString(Settings.Default.UpdateAddress)), new Uri(UpdateChannelInfo.FileName, UriKind.Relative));
var e = DownloadString(updateFileUri);
if (!e.Cancelled && e.Error == null)
{
CurrentUpdateInfo = UpdateInfo.FromString(e.Result);
#endregion
#region Private Properties
private WebClient _downloadUpdateWebClient;
private WebClient DownloadUpdateWebClient
{
get
{
if (_downloadUpdateWebClient != null)
{
return _downloadUpdateWebClient;
}
_downloadUpdateWebClient = CreateWebClient();
_downloadUpdateWebClient.DownloadProgressChanged += DownloadUpdateProgressChanged;
_downloadUpdateWebClient.DownloadFileCompleted += DownloadUpdateCompleted;
return _downloadUpdateWebClient;
}
}
#endregion
#region Private Methods
private WebClient CreateWebClient()
{
var webClient = new WebClient();
webClient.Headers.Add("user-agent", GeneralAppInfo.UserAgent);
webClient.Proxy = _webProxy;
return webClient;
}
private static DownloadStringCompletedEventArgs NewDownloadStringCompletedEventArgs(string result,
Exception exception, bool cancelled, object userToken)
{
var type = typeof(DownloadStringCompletedEventArgs);
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
Type[] argumentTypes = {typeof(string), typeof(Exception), typeof(bool), typeof(object)};
var constructor = type.GetConstructor(bindingFlags, null, argumentTypes, null);
object[] arguments = {result, exception, cancelled, userToken};
return (DownloadStringCompletedEventArgs) constructor.Invoke(arguments);
}
public DownloadStringCompletedEventArgs DownloadString(Uri address)
{
var webClient = CreateWebClient();
var result = string.Empty;
Exception exception = null;
var cancelled = false;
try
{
result = webClient.DownloadString(address);
}
catch (ThreadAbortException)
{
cancelled = true;
}
catch (Exception ex)
{
exception = ex;
}
return NewDownloadStringCompletedEventArgs(result, exception, cancelled, null);
}
private void GetUpdateInfo()
{
var e = DownloadString(UpdateChannelInfo.GetUpdateChannelInfo());
if (!e.Cancelled && e.Error == null)
{
CurrentUpdateInfo = UpdateInfo.FromString(e.Result);
Settings.Default.CheckForUpdatesLastCheck = DateTime.UtcNow;
if (!Settings.Default.UpdatePending)
{
if (!Settings.Default.UpdatePending)
{
Settings.Default.UpdatePending = IsUpdateAvailable();
}
}
}
}
GetUpdateInfoCompletedEventEvent?.Invoke(this, e);
}
private void GetChangeLog()
{
var e = DownloadString(CurrentUpdateInfo.ChangeLogAddress);
if (!e.Cancelled && e.Error == null)
{
ChangeLog = e.Result;
}
private void GetChangeLog()
{
var e = DownloadString(CurrentUpdateInfo.ChangeLogAddress);
if (!e.Cancelled && e.Error == null)
{
ChangeLog = e.Result;
}
GetChangeLogCompletedEventEvent?.Invoke(this, e);
}
private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
DownloadUpdateProgressChangedEventEvent?.Invoke(sender, e);
}
private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e)
{
var raiseEventArgs = e;
if (!e.Cancelled && e.Error == null)
{
try
{
private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e)
{
var raiseEventArgs = e;
if (!e.Cancelled && e.Error == null)
{
try
{
#if !PORTABLE
var updateAuthenticode = new Authenticode(CurrentUpdateInfo.UpdateFilePath)
{
RequireThumbprintMatch = true,
ThumbprintToMatch = CurrentUpdateInfo.CertificateThumbprint
};
{
RequireThumbprintMatch = true,
ThumbprintToMatch = CurrentUpdateInfo.CertificateThumbprint
};
if (updateAuthenticode.Verify() != Authenticode.StatusValue.Verified)
{
if (updateAuthenticode.Status == Authenticode.StatusValue.UnhandledException)
{
throw (updateAuthenticode.Exception);
}
if (updateAuthenticode.Verify() != Authenticode.StatusValue.Verified)
{
if (updateAuthenticode.Status == Authenticode.StatusValue.UnhandledException)
{
throw updateAuthenticode.Exception;
}
throw (new Exception(updateAuthenticode.StatusMessage));
}
throw new Exception(updateAuthenticode.StatusMessage);
}
#endif
using (var md5 = MD5.Create())
@@ -278,26 +287,29 @@ namespace mRemoteNG.App.Update
}
}
}
catch (Exception ex)
{
raiseEventArgs = new AsyncCompletedEventArgs(ex, false, null);
}
}
if (raiseEventArgs.Cancelled || raiseEventArgs.Error != null)
{
File.Delete(CurrentUpdateInfo.UpdateFilePath);
}
catch (Exception ex)
{
raiseEventArgs = new AsyncCompletedEventArgs(ex, false, null);
}
}
if (raiseEventArgs.Cancelled || raiseEventArgs.Error != null)
{
File.Delete(CurrentUpdateInfo.UpdateFilePath);
}
DownloadUpdateCompletedEventEvent?.Invoke(this, raiseEventArgs);
_downloadUpdateWebClient.Dispose();
_downloadUpdateWebClient = null;
}
#endregion
#region Events
_downloadUpdateWebClient = null;
}
#endregion
#region Events
private AsyncCompletedEventHandler GetUpdateInfoCompletedEventEvent;
public event AsyncCompletedEventHandler GetUpdateInfoCompletedEvent
{
add
@@ -311,6 +323,7 @@ namespace mRemoteNG.App.Update
}
private AsyncCompletedEventHandler GetChangeLogCompletedEventEvent;
public event AsyncCompletedEventHandler GetChangeLogCompletedEvent
{
add
@@ -323,7 +336,8 @@ namespace mRemoteNG.App.Update
}
}
private DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEventEvent;
private DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEventEvent;
public event DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEvent
{
add
@@ -337,6 +351,7 @@ namespace mRemoteNG.App.Update
}
private AsyncCompletedEventHandler DownloadUpdateCompletedEventEvent;
public event AsyncCompletedEventHandler DownloadUpdateCompletedEvent
{
add
@@ -348,6 +363,7 @@ namespace mRemoteNG.App.Update
DownloadUpdateCompletedEventEvent = (AsyncCompletedEventHandler)Delegate.Remove(DownloadUpdateCompletedEventEvent, value);
}
}
#endregion
}
#endregion
}
}

View File

@@ -1,4 +1,5 @@
using System;
// ReSharper disable UnusedAutoPropertyAccessor.Local
namespace mRemoteNG.App.Update
{
@@ -14,7 +15,8 @@ namespace mRemoteNG.App.Update
#if !PORTABLE
public string CertificateThumbprint { get; private set; }
#endif
public string FileName { get; private set; }
// ReSharper disable once MemberCanBePrivate.Global
public string FileName { get; set; }
public string Checksum { get; private set; }
public static UpdateInfo FromString(string input)
@@ -30,16 +32,45 @@ namespace mRemoteNG.App.Update
newInfo.Version = updateFile.GetVersion();
newInfo.DownloadAddress = updateFile.GetUri("dURL");
newInfo.ChangeLogAddress = updateFile.GetUri("clURL");
#if false
newInfo.ImageAddress = updateFile.GetUri("imgURL");
newInfo.ImageLinkAddress = updateFile.GetUri("imgURLLink");
#endif
#if !PORTABLE
newInfo.CertificateThumbprint = updateFile.GetThumbprint();
#endif
newInfo.FileName = updateFile.GetFileName();
newInfo.Checksum = updateFile.GetChecksum();
newInfo.IsValid = true;
newInfo.IsValid = newInfo.CheckIfValid();
}
return newInfo;
}
public bool CheckIfValid()
{
if (string.IsNullOrEmpty(Version.ToString()))
return false;
if(string.IsNullOrEmpty(DownloadAddress.AbsoluteUri))
return false;
if (string.IsNullOrEmpty(ChangeLogAddress.AbsoluteUri))
return false;
#if false
if (string.IsNullOrEmpty(ImageAddress.AbsoluteUri))
return false;
if (string.IsNullOrEmpty(ImageLinkAddress.AbsoluteUri))
return false;
#endif
#if !PORTABLE
if (string.IsNullOrEmpty(CertificateThumbprint))
return false;
#endif
if (string.IsNullOrEmpty(FileName))
return false;
// ReSharper disable once ConvertIfStatementToReturnStatement
if (string.IsNullOrEmpty(Checksum))
return false;
return true;
}
}
}

View File

@@ -89,7 +89,7 @@ namespace mRemoteNG.Config.Connections
if (!VerifyDatabaseVersion(sqlConnector))
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strErrorConnectionListSaveFailed);
return ;
return;
}
var rootTreeNode = Runtime.ConnectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();

View File

@@ -130,7 +130,7 @@ namespace mRemoteNG.Config.Putty
if (_eventWatcher != null)
{
return ;
return;
}
try
@@ -158,7 +158,7 @@ namespace mRemoteNG.Config.Putty
if (_eventWatcher == null)
{
return ;
return;
}
_eventWatcher.EnableRaisingEvents = false;
_eventWatcher.Dispose();
@@ -231,7 +231,7 @@ namespace mRemoteNG.Config.Putty
{
if (!File.Exists(_puttyConfFile))
{
return ;
return;
}
using (var streamReader = new StreamReader(_puttyConfFile))
{
@@ -299,7 +299,7 @@ namespace mRemoteNG.Config.Putty
{
if (!File.Exists(_sessionFile))
{
return ;
return;
}
using (var streamReader = new StreamReader(_sessionFile))
{

View File

@@ -66,7 +66,7 @@ namespace mRemoteNG.Config.Serializers
// check/continue here so we don't create empty connection objects
if(!_importSubOU) continue;
ActiveDirectoryImporter.Import(ldapResult.Path, parentContainer);
ActiveDirectoryImporter.Import(ldapResult.Path, parentContainer, _importSubOU);
continue;
}

View File

@@ -84,6 +84,8 @@ namespace mRemoteNG.Config.Serializers
connectionInfo.RenderingEngine = (HTTPBase.RenderingEngine)Enum.Parse(typeof(HTTPBase.RenderingEngine), (string)dataRow["RenderingEngine"]);
connectionInfo.ICAEncryptionStrength = (ProtocolICA.EncryptionStrength)Enum.Parse(typeof(ProtocolICA.EncryptionStrength), (string)dataRow["ICAEncryptionStrength"]);
connectionInfo.RDPAuthenticationLevel = (ProtocolRDP.AuthenticationLevel)Enum.Parse(typeof(ProtocolRDP.AuthenticationLevel), (string)dataRow["RDPAuthenticationLevel"]);
connectionInfo.RDPMinutesToIdleTimeout = (int)dataRow["RDPMinutesToIdleTimeout"];
connectionInfo.RDPAlertIdleTimeout = (bool)dataRow["RDPAlertIdleTimeout"];
connectionInfo.LoadBalanceInfo = (string)dataRow["LoadBalanceInfo"];
connectionInfo.Colors = (ProtocolRDP.RDPColors)Enum.Parse(typeof(ProtocolRDP.RDPColors) ,(string)dataRow["Colors"]);
connectionInfo.Resolution = (ProtocolRDP.RDPResolutions)Enum.Parse(typeof(ProtocolRDP.RDPResolutions), (string)dataRow["Resolution"]);
@@ -153,6 +155,8 @@ namespace mRemoteNG.Config.Serializers
connectionInfo.Inheritance.Username = (bool)dataRow["InheritUsername"];
connectionInfo.Inheritance.ICAEncryptionStrength = (bool)dataRow["InheritICAEncryptionStrength"];
connectionInfo.Inheritance.RDPAuthenticationLevel = (bool)dataRow["InheritRDPAuthenticationLevel"];
connectionInfo.Inheritance.RDPAlertIdleTimeout = (bool)dataRow["RDPAlertIdleTimeout"];
connectionInfo.Inheritance.RDPMinutesToIdleTimeout = (bool)dataRow["RDPMinutesToIdleTimeout"];
connectionInfo.Inheritance.LoadBalanceInfo = (bool)dataRow["InheritLoadBalanceInfo"];
connectionInfo.Inheritance.PreExtApp = (bool)dataRow["InheritPreExtApp"];
connectionInfo.Inheritance.PostExtApp = (bool)dataRow["InheritPostExtApp"];

View File

@@ -65,6 +65,8 @@ namespace mRemoteNG.Config.Serializers
_dataTable.Columns.Add("RenderingEngine", typeof(string));
_dataTable.Columns.Add("ICAEncryptionStrength", typeof(string));
_dataTable.Columns.Add("RDPAuthenticationLevel", typeof(string));
_dataTable.Columns.Add("RDPMinutesToIdleTimeout", typeof(int));
_dataTable.Columns.Add("RDPAlertIdleTimeout", typeof(bool));
_dataTable.Columns.Add("Colors", typeof(string));
_dataTable.Columns.Add("Resolution", typeof(string));
_dataTable.Columns.Add("DisplayWallpaper", typeof(bool));
@@ -128,6 +130,8 @@ namespace mRemoteNG.Config.Serializers
_dataTable.Columns.Add("InheritRenderingEngine", typeof(bool));
_dataTable.Columns.Add("InheritICAEncryptionStrength", typeof(bool));
_dataTable.Columns.Add("InheritRDPAuthenticationLevel", typeof(bool));
_dataTable.Columns.Add("InheritRDPMinutesToIdleTimeout", typeof(bool));
_dataTable.Columns.Add("InheritRDPAlertIdleTimeout", typeof(bool));
_dataTable.Columns.Add("InheritUsername", typeof(bool));
_dataTable.Columns.Add("InheritPreExtApp", typeof(bool));
_dataTable.Columns.Add("InheritPostExtApp", typeof(bool));
@@ -200,6 +204,8 @@ namespace mRemoteNG.Config.Serializers
dataRow["RenderingEngine"] = connectionInfo.RenderingEngine;
dataRow["ICAEncryptionStrength"] = connectionInfo.ICAEncryptionStrength;
dataRow["RDPAuthenticationLevel"] = connectionInfo.RDPAuthenticationLevel;
//dataRow["RDPMinutesToIdleTimeout"] = connectionInfo.RDPMinutesToIdleTimeout;
//dataRow["RDPAlertIdleTimeout"] = connectionInfo.RDPAlertIdleTimeout;
dataRow["LoadBalanceInfo"] = connectionInfo.LoadBalanceInfo;
dataRow["Colors"] = connectionInfo.Colors;
dataRow["Resolution"] = connectionInfo.Resolution;
@@ -270,6 +276,8 @@ namespace mRemoteNG.Config.Serializers
dataRow["InheritUsername"] = connectionInfo.Inheritance.Username;
dataRow["InheritICAEncryptionStrength"] = connectionInfo.Inheritance.ICAEncryptionStrength;
dataRow["InheritRDPAuthenticationLevel"] = connectionInfo.Inheritance.RDPAuthenticationLevel;
//dataRow["InheritRDPMinutesToIdleTimeout"] = connectionInfo.Inheritance.RDPMinutesToIdleTimeout;
//dataRow["InheritRDPAlertIdleTimeout"] = connectionInfo.Inheritance.RDPAlertIdleTimeout;
dataRow["InheritLoadBalanceInfo"] = connectionInfo.Inheritance.LoadBalanceInfo;
dataRow["InheritPreExtApp"] = connectionInfo.Inheritance.PreExtApp;
dataRow["InheritPostExtApp"] = connectionInfo.Inheritance.PostExtApp;
@@ -325,6 +333,8 @@ namespace mRemoteNG.Config.Serializers
dataRow["InheritUsername"] = false;
dataRow["InheritICAEncryptionStrength"] = false;
dataRow["InheritRDPAuthenticationLevel"] = false;
//dataRow["InheritRDPMinutesToIdleTimeout"] = false;
//dataRow["InheritRDPAlertIdleTimeout"] = false;
dataRow["InheritLoadBalanceInfo"] = false;
dataRow["InheritPreExtApp"] = false;
dataRow["InheritPostExtApp"] = false;

View File

@@ -44,6 +44,7 @@ namespace mRemoteNG.Config.Serializers
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)
@@ -67,6 +68,8 @@ namespace mRemoteNG.Config.Serializers
element.Add(new XAttribute("RenderingEngine", connectionInfo.RenderingEngine));
element.Add(new XAttribute("ICAEncryptionStrength", connectionInfo.ICAEncryptionStrength));
element.Add(new XAttribute("RDPAuthenticationLevel", connectionInfo.RDPAuthenticationLevel));
element.Add(new XAttribute("RDPMinutesToIdleTimeout", connectionInfo.RDPMinutesToIdleTimeout));
element.Add(new XAttribute("RDPAlertIdleTimeout", connectionInfo.RDPAlertIdleTimeout));
element.Add(new XAttribute("LoadBalanceInfo", connectionInfo.LoadBalanceInfo));
element.Add(new XAttribute("Colors", connectionInfo.Colors));
element.Add(new XAttribute("Resolution", connectionInfo.Resolution));
@@ -159,6 +162,8 @@ namespace mRemoteNG.Config.Serializers
element.Add(new XAttribute("InheritUsername", connectionInfo.Inheritance.Username.ToString()));
element.Add(new XAttribute("InheritICAEncryptionStrength", connectionInfo.Inheritance.ICAEncryptionStrength.ToString()));
element.Add(new XAttribute("InheritRDPAuthenticationLevel", connectionInfo.Inheritance.RDPAuthenticationLevel.ToString()));
element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", connectionInfo.Inheritance.RDPMinutesToIdleTimeout.ToString()));
element.Add(new XAttribute("InheritRDPAlertIdleTimeout", connectionInfo.Inheritance.RDPAlertIdleTimeout.ToString()));
element.Add(new XAttribute("InheritLoadBalanceInfo", connectionInfo.Inheritance.LoadBalanceInfo.ToString()));
element.Add(new XAttribute("InheritPreExtApp", connectionInfo.Inheritance.PreExtApp.ToString()));
element.Add(new XAttribute("InheritPostExtApp", connectionInfo.Inheritance.PostExtApp.ToString()));
@@ -214,6 +219,8 @@ namespace mRemoteNG.Config.Serializers
element.Add(new XAttribute("InheritUsername", false.ToString()));
element.Add(new XAttribute("InheritICAEncryptionStrength", false.ToString()));
element.Add(new XAttribute("InheritRDPAuthenticationLevel", false.ToString()));
element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", false.ToString()));
element.Add(new XAttribute("InheritRDPAlertIdleTimeout", false.ToString()));
element.Add(new XAttribute("InheritLoadBalanceInfo", false.ToString()));
element.Add(new XAttribute("InheritPreExtApp", false.ToString()));
element.Add(new XAttribute("InheritPostExtApp", false.ToString()));

View File

@@ -485,8 +485,13 @@ namespace mRemoteNG.Config.Serializers
if (_confVersion >= 2.6)
{
connectionInfo.ConstantID = xmlnode.Attributes["Id"]?.Value ?? connectionInfo.ConstantID;
connectionInfo.SoundQuality = (ProtocolRDP.RDPSoundQuality)Tools.MiscTools.StringToEnum(typeof(ProtocolRDP.RDPSoundQuality), Convert.ToString(xmlnode.Attributes["SoundQuality"].Value));
connectionInfo.Inheritance.SoundQuality = bool.Parse(xmlnode.Attributes["InheritSoundQuality"].Value);
connectionInfo.RDPMinutesToIdleTimeout = Convert.ToInt32(xmlnode.Attributes["RDPMinutesToIdleTimeout"]?.Value ?? "0");
connectionInfo.Inheritance.RDPMinutesToIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPMinutesToIdleTimeout"]?.Value ?? "False");
connectionInfo.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["RDPAlertIdleTimeout"]?.Value ?? "False");
connectionInfo.Inheritance.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPAlertIdleTimeout"]?.Value ?? "False");
}
}
catch (Exception ex)

View File

@@ -20,47 +20,59 @@ namespace mRemoteNG.Config.Settings
public void LoadExternalAppsFromXML()
{
var oldPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\" + GeneralAppInfo.ProductName + "\\" + SettingsFileInfo.ExtAppsFilesName;
var newPath = SettingsFileInfo.SettingsPath + "\\" + SettingsFileInfo.ExtAppsFilesName;
#if !PORTABLE
var oldPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), GeneralAppInfo.ProductName, SettingsFileInfo.ExtAppsFilesName);
#endif
var newPath = Path.Combine(SettingsFileInfo.SettingsPath, SettingsFileInfo.ExtAppsFilesName);
var xDom = new XmlDocument();
if (File.Exists(newPath))
{
Logger.Instance.Info($"Loading External Apps from: {newPath}");
xDom.Load(newPath);
}
#if !PORTABLE
}
else if (File.Exists(oldPath))
{
xDom.Load(oldPath);
Logger.Instance.Info($"Loading External Apps from: {oldPath}");
xDom.Load(oldPath);
}
#endif
}
else
{
Logger.Instance.Warn("Loading External Apps failed: Could not FIND file!");
return;
}
if (xDom.DocumentElement != null)
foreach (XmlElement xEl in xDom.DocumentElement.ChildNodes)
if (xDom.DocumentElement == null)
{
Logger.Instance.Warn("Loading External Apps failed: Could not LOAD file!");
return;
}
foreach (XmlElement xEl in xDom.DocumentElement.ChildNodes)
{
var extA = new ExternalTool
{
var extA = new ExternalTool
{
DisplayName = xEl.Attributes["DisplayName"].Value,
FileName = xEl.Attributes["FileName"].Value,
Arguments = xEl.Attributes["Arguments"].Value
};
DisplayName = xEl.Attributes["DisplayName"].Value,
FileName = xEl.Attributes["FileName"].Value,
Arguments = xEl.Attributes["Arguments"].Value
};
if (xEl.HasAttribute("WaitForExit"))
{
extA.WaitForExit = bool.Parse(xEl.Attributes["WaitForExit"].Value);
}
if (xEl.HasAttribute("TryToIntegrate"))
{
extA.TryIntegrate = bool.Parse(xEl.Attributes["TryToIntegrate"].Value);
}
Runtime.ExternalTools.Add(extA);
if (xEl.HasAttribute("WaitForExit"))
{
extA.WaitForExit = bool.Parse(xEl.Attributes["WaitForExit"].Value);
}
if (xEl.HasAttribute("TryToIntegrate"))
{
extA.TryIntegrate = bool.Parse(xEl.Attributes["TryToIntegrate"].Value);
}
Logger.Instance.Info($"Adding External App: {extA.DisplayName} {extA.FileName} {extA.Arguments}");
Runtime.ExternalTools.Add(extA);
}
_MainForm.SwitchToolBarText(Convert.ToBoolean(mRemoteNG.Settings.Default.ExtAppsTBShowText));
frmMain.Default.AddExternalToolsToToolBar();

View File

@@ -48,7 +48,7 @@ namespace mRemoteNG.Config.Settings
}
else
{
Startup.Instance.SetDefaultLayout();
frmMain.Default.SetDefaultLayout();
}
}
catch (Exception ex)

View File

@@ -9,6 +9,7 @@ using mRemoteNG.Themes;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.App.Info;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms;
@@ -137,14 +138,14 @@ namespace mRemoteNG.Config.Settings
private void SetKioskMode()
{
if (!mRemoteNG.Settings.Default.MainFormKiosk) return;
MainForm.Fullscreen.Value = true;
MainForm._fullscreen.Value = true;
MainForm.mMenViewFullscreen.Checked = true;
}
private static void SetShowSystemTrayIcon()
{
if (mRemoteNG.Settings.Default.ShowSystemTrayIcon)
Runtime.NotificationAreaIcon = new Tools.Controls.NotificationAreaIcon();
Runtime.NotificationAreaIcon = new NotificationAreaIcon();
}
private static void SetPuttyPath()

View File

@@ -36,9 +36,9 @@ namespace mRemoteNG.Config.Settings
mRemoteNG.Settings.Default.MainFormState = with1.WindowState;
if (with1.Fullscreen != null)
if (with1._fullscreen != null)
{
mRemoteNG.Settings.Default.MainFormKiosk = with1.Fullscreen.Value;
mRemoteNG.Settings.Default.MainFormKiosk = with1._fullscreen.Value;
}
mRemoteNG.Settings.Default.FirstStart = false;

View File

@@ -30,6 +30,8 @@ namespace mRemoteNG.Connection
private ProtocolICA.EncryptionStrength _icaEncryption;
private bool _useConsoleSession;
private ProtocolRDP.AuthenticationLevel _rdpAuthenticationLevel;
private int _rdpMinutesToIdleTimeout;
private bool _rdpAlertIdleTimeout;
private string _loadBalanceInfo;
private HTTPBase.RenderingEngine _renderingEngine;
private bool _useCredSsp;
@@ -225,6 +227,30 @@ namespace mRemoteNG.Connection
set { SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel"); }
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDPMinutesToIdleTimeout"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPMinutesToIdleTimeout")]
public virtual int RDPMinutesToIdleTimeout
{
get { return GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout); }
set {
if(value < 0) {
value = 0;
} else if(value > 240) {
value = 240;
}
SetField(ref _rdpMinutesToIdleTimeout, value, "RDPMinutesToIdleTimeout");
}
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDPAlertIdleTimeout"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPAlertIdleTimeout")]
public bool RDPAlertIdleTimeout
{
get { return GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout); }
set { SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout"); }
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameLoadBalanceInfo"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionLoadBalanceInfo")]

View File

@@ -248,6 +248,8 @@ namespace mRemoteNG.Connection
ICAEncryptionStrength = (ProtocolICA.EncryptionStrength) Enum.Parse(typeof(ProtocolICA.EncryptionStrength), Settings.Default.ConDefaultICAEncryptionStrength);
UseConsoleSession = Settings.Default.ConDefaultUseConsoleSession;
RDPAuthenticationLevel = (ProtocolRDP.AuthenticationLevel) Enum.Parse(typeof(ProtocolRDP.AuthenticationLevel), Settings.Default.ConDefaultRDPAuthenticationLevel);
RDPMinutesToIdleTimeout = Settings.Default.ConDefaultRDPMinutesToIdleTimeout;
RDPAlertIdleTimeout = Settings.Default.ConDefaultRDPAlertIdleTimeout;
LoadBalanceInfo = Settings.Default.ConDefaultLoadBalanceInfo;
RenderingEngine = (HTTPBase.RenderingEngine) Enum.Parse(typeof(HTTPBase.RenderingEngine), Settings.Default.ConDefaultRenderingEngine);
UseCredSsp = Settings.Default.ConDefaultUseCredSsp;

View File

@@ -83,9 +83,19 @@ namespace mRemoteNG.Connection
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAuthenticationLevel"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAuthenticationLevel"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RDPAuthenticationLevel {get; set;}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RDPAuthenticationLevel {get; set; }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDPMinutesToIdleTimeout"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDPMinutesToIdleTimeout"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RDPMinutesToIdleTimeout { get; set; }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDPAlertIdleTimeout"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDPAlertIdleTimeout"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool RDPAlertIdleTimeout { get; set; }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameLoadBalanceInfo"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionLoadBalanceInfo"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool LoadBalanceInfo {get; set;}

View File

@@ -12,14 +12,52 @@ using TabPage = Crownwood.Magic.Controls.TabPage;
namespace mRemoteNG.Connection
{
public static class ConnectionInitiator
public class ConnectionInitiator : IConnectionInitiator
{
public static void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None)
public void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None)
{
OpenConnection(containerInfo, force, null);
}
private static void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force, Form conForm)
public void OpenConnection(ConnectionInfo connectionInfo)
{
try
{
OpenConnection(connectionInfo, ConnectionInfo.Force.None);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex);
}
}
public void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force)
{
try
{
OpenConnection(connectionInfo, force, null);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex);
}
}
public bool SwitchToOpenConnection(ConnectionInfo connectionInfo)
{
var interfaceControl = FindConnectionContainer(connectionInfo);
if (interfaceControl == null) return false;
var connectionWindow = (ConnectionWindow)interfaceControl.FindForm();
connectionWindow?.Focus();
var findForm = (ConnectionWindow)interfaceControl.FindForm();
findForm?.Show(frmMain.Default.pnlDock);
var tabPage = (TabPage)interfaceControl.Parent;
tabPage.Selected = true;
return true;
}
#region Private
private void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force, Form conForm)
{
var children = containerInfo.Children;
if (children.Count == 0) return;
@@ -33,31 +71,7 @@ namespace mRemoteNG.Connection
}
}
public static void OpenConnection(ConnectionInfo connectionInfo)
{
try
{
OpenConnection(connectionInfo, ConnectionInfo.Force.None);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionOpenFailed + Environment.NewLine + ex.Message);
}
}
public static void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force)
{
try
{
OpenConnection(connectionInfo, force, null);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionOpenFailed + Environment.NewLine + ex.Message);
}
}
private static void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force, Form conForm)
private void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force, Form conForm)
{
try
{
@@ -104,7 +118,7 @@ namespace mRemoteNG.Connection
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionOpenFailed + Environment.NewLine + ex.Message);
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex);
}
}
@@ -115,19 +129,6 @@ namespace mRemoteNG.Connection
extA?.Start(connectionInfo);
}
public static bool SwitchToOpenConnection(ConnectionInfo nCi)
{
var IC = FindConnectionContainer(nCi);
if (IC == null) return false;
var connectionWindow = (ConnectionWindow)IC.FindForm();
connectionWindow?.Focus();
var findForm = (ConnectionWindow)IC.FindForm();
findForm?.Show(frmMain.Default.pnlDock);
var tabPage = (TabPage)IC.Parent;
tabPage.Selected = true;
return true;
}
private static InterfaceControl FindConnectionContainer(ConnectionInfo connectionInfo)
{
if (connectionInfo.OpenConnections.Count <= 0) return null;
@@ -185,11 +186,15 @@ namespace mRemoteNG.Connection
{
Control connectionContainer = ((ConnectionWindow)connectionForm).AddConnectionTab(connectionInfo);
if (connectionInfo.Protocol == ProtocolType.IntApp)
{
if (Runtime.GetExtAppByName(connectionInfo.ExtApp).Icon != null)
((TabPage)connectionContainer).Icon = Runtime.GetExtAppByName(connectionInfo.ExtApp).Icon;
}
if (connectionInfo.Protocol != ProtocolType.IntApp) return connectionContainer;
var extT = Runtime.GetExtAppByName(connectionInfo.ExtApp);
if(extT == null) return connectionContainer;
if (extT.Icon != null)
((TabPage)connectionContainer).Icon = extT.Icon;
return connectionContainer;
}
@@ -210,10 +215,9 @@ namespace mRemoteNG.Connection
{
newProtocol.InterfaceControl = new InterfaceControl(connectionContainer, newProtocol, connectionInfo);
}
#endregion
#region Event handlers
private static void Prot_Event_Disconnected(object sender, string disconnectedMessage)
{
try
@@ -230,7 +234,7 @@ namespace mRemoteNG.Connection
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.strProtocolEventDisconnectFailed, ex.Message), true);
Runtime.MessageCollector.AddExceptionStackTrace(Language.strProtocolEventDisconnectFailed, ex);
}
}
@@ -240,7 +244,15 @@ namespace mRemoteNG.Connection
{
var Prot = (ProtocolBase)sender;
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnenctionCloseEvent, true);
Runtime.MessageCollector.AddMessage(MessageClass.ReportMsg, string.Format(Language.strConnenctionClosedByUser, Prot.InterfaceControl.Info.Hostname, Prot.InterfaceControl.Info.Protocol.ToString(), Environment.UserName));
string connDetail;
if (Prot.InterfaceControl.Info.Hostname == "" && Prot.InterfaceControl.Info.Protocol == ProtocolType.IntApp)
connDetail = Prot.InterfaceControl.Info.ExtApp;
else if (Prot.InterfaceControl.Info.Hostname != "")
connDetail = Prot.InterfaceControl.Info.Hostname;
else
connDetail = "UNKNOWN";
Runtime.MessageCollector.AddMessage(MessageClass.ReportMsg, string.Format(Language.strConnenctionClosedByUser, connDetail, Prot.InterfaceControl.Info.Protocol, Environment.UserName));
Prot.InterfaceControl.Info.OpenConnections.Remove(Prot);
if (Prot.InterfaceControl.Info.PostExtApp == "") return;
@@ -249,7 +261,7 @@ namespace mRemoteNG.Connection
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnenctionCloseEventFailed + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnenctionCloseEventFailed, ex);
}
}
@@ -273,8 +285,9 @@ namespace mRemoteNG.Connection
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionEventConnectionFailed + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionEventConnectionFailed, ex);
}
}
#endregion
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using mRemoteNG.App;
namespace mRemoteNG.Connection
@@ -39,15 +40,17 @@ namespace mRemoteNG.Connection
var inheritanceProperties = GetProperties(_excludedProperties);
foreach (var property in inheritanceProperties)
{
var propertyFromDestination = typeof(TDestination).GetProperty(propertyNameMutator(property.Name));
var localValue = property.GetValue(Instance, null);
var descriptor = TypeDescriptor.GetProperties(Instance)[property.Name];
var converter = descriptor.Converter;
if (converter != null && converter.CanConvertFrom(localValue.GetType()))
propertyFromDestination.SetValue(destinationInstance, converter.ConvertFrom(localValue), null);
else
propertyFromDestination.SetValue(destinationInstance, localValue, null);
try
{
var propertyFromDestination = typeof(TDestination).GetProperty(propertyNameMutator(property.Name));
var localValue = property.GetValue(Instance, null);
var convertedValue = Convert.ChangeType(localValue, propertyFromDestination.PropertyType);
propertyFromDestination.SetValue(destinationInstance, convertedValue, null);
}
catch (Exception ex)
{
Runtime.MessageCollector?.AddExceptionStackTrace($"Error saving default connectioninfo property {property.Name}", ex);
}
}
}
}

View File

@@ -0,0 +1,15 @@
using mRemoteNG.Container;
namespace mRemoteNG.Connection
{
public interface IConnectionInitiator
{
void OpenConnection(ConnectionInfo connectionInfo);
void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None);
void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force);
bool SwitchToOpenConnection(ConnectionInfo connectionInfo);
}
}

View File

@@ -172,7 +172,7 @@ namespace mRemoteNG.Connection.Protocol.Http
WebBrowser objWebBrowser = wBrowser as WebBrowser;
if (objWebBrowser == null)
{
return ;
return;
}
// This can only be set once the WebBrowser control is shown, it will throw a COM exception otherwise.

View File

@@ -137,7 +137,7 @@ namespace mRemoteNG.Connection.Protocol.ICA
{
if (((int)Force & (int)ConnectionInfo.Force.NoCredentials) == (int)ConnectionInfo.Force.NoCredentials)
{
return ;
return;
}
string _user = _Info.Username;

View File

@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.Messages;
namespace mRemoteNG.Connection.Protocol
@@ -20,41 +21,52 @@ namespace mRemoteNG.Connection.Protocol
#region Public Methods
public override bool Initialize()
{
if (InterfaceControl.Info != null)
{
_externalTool = Runtime.GetExtAppByName(Convert.ToString(InterfaceControl.Info.ExtApp));
_externalTool.ConnectionInfo = InterfaceControl.Info;
}
return base.Initialize();
if (InterfaceControl.Info == null) return base.Initialize();
_externalTool = Runtime.GetExtAppByName(InterfaceControl.Info.ExtApp);
_externalTool.ConnectionInfo = InterfaceControl.Info;
return base.Initialize();
}
public override bool Connect()
{
try
{
if (_externalTool.TryIntegrate == false)
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Attempting to start: {_externalTool.DisplayName}", true);
if (_externalTool.TryIntegrate == false)
{
_externalTool.Start(InterfaceControl.Info);
Close();
return false;
/* Don't call close here... There's nothing for the override to do in this case since
* _process is not created in this scenario. When returning false, ProtocolBase.Close()
* will be called - which is just going to call IntegratedProgram.Close() again anyway...
* Close();
*/
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Assuming no other errors/exceptions occurred immediately before this message regarding {_externalTool.DisplayName}, the next \"closed by user\" message can be ignored", true);
return false;
}
ExternalToolArgumentParser argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo);
_process = new Process();
_process.StartInfo.UseShellExecute = true;
_process.StartInfo.FileName = argParser.ParseArguments(_externalTool.FileName);
_process.StartInfo.Arguments = argParser.ParseArguments(_externalTool.Arguments);
_process.EnableRaisingEvents = true;
_process.Exited += ProcessExited;
var argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo);
_process = new Process
{
StartInfo =
{
UseShellExecute = true,
FileName = argParser.ParseArguments(_externalTool.FileName),
Arguments = argParser.ParseArguments(_externalTool.Arguments)
},
EnableRaisingEvents = true
};
_process.Exited += ProcessExited;
_process.Start();
_process.WaitForInputIdle(Convert.ToInt32(Settings.Default.MaxPuttyWaitTime * 1000));
_process.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
int startTicks = Environment.TickCount;
while (_handle.ToInt32() == 0 & Environment.TickCount < startTicks + (Settings.Default.MaxPuttyWaitTime * 1000))
var startTicks = Environment.TickCount;
while (_handle.ToInt32() == 0 & Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000)
{
_process.Refresh();
if (_process.MainWindowTitle != "Default IME")
@@ -68,10 +80,10 @@ namespace mRemoteNG.Connection.Protocol
}
NativeMethods.SetParent(_handle, InterfaceControl.Handle);
Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, Language.strIntAppStuff, true);
Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, string.Format(Language.strIntAppHandle, _handle.ToString()), true);
Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, string.Format(Language.strIntAppTitle, _process.MainWindowTitle), true);
Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, string.Format(Language.strIntAppParentHandle, InterfaceControl.Parent.Handle.ToString()), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strIntAppStuff, true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppHandle, _handle), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppTitle, _process.MainWindowTitle), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppParentHandle, InterfaceControl.Parent.Handle), true);
Resize(this, new EventArgs());
base.Connect();
@@ -88,15 +100,12 @@ namespace mRemoteNG.Connection.Protocol
{
try
{
if (ConnectionWindow.InTabDrag)
{
return ;
}
if (ConnectionWindow.InTabDrag) return;
NativeMethods.SetForegroundWindow(_handle);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppFocusFailed, ex: ex, logOnly: true);
Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppFocusFailed, ex);
}
}
@@ -104,45 +113,49 @@ namespace mRemoteNG.Connection.Protocol
{
try
{
if (InterfaceControl.Size == Size.Empty)
{
return ;
}
NativeMethods.MoveWindow(_handle, Convert.ToInt32(-SystemInformation.FrameBorderSize.Width), Convert.ToInt32(-(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height)), InterfaceControl.Width + (SystemInformation.FrameBorderSize.Width * 2), InterfaceControl.Height + SystemInformation.CaptionHeight + (SystemInformation.FrameBorderSize.Height * 2), true);
if (InterfaceControl.Size == Size.Empty) return;
NativeMethods.MoveWindow(_handle, -SystemInformation.FrameBorderSize.Width, -(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height), InterfaceControl.Width + SystemInformation.FrameBorderSize.Width * 2, InterfaceControl.Height + SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height * 2, true);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppResizeFailed, ex: ex, logOnly: true);
Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppResizeFailed, ex);
}
}
public override void Close()
{
try
{
if (!_process.HasExited)
{
_process.Kill();
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppKillFailed, ex: ex, logOnly: true);
}
try
{
if (!_process.HasExited)
{
_process.Dispose();
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppDisposeFailed, ex: ex, logOnly: true);
}
base.Close();
/* only attempt this if we have a valid process object
* Non-integated tools will still call base.Close() and don't have a valid process object.
* See Connect() above... This just muddies up the log.
*/
if (_process != null)
{
try
{
if (!_process.HasExited)
{
_process.Kill();
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppKillFailed, ex);
}
try
{
if (!_process.HasExited)
{
_process.Dispose();
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppDisposeFailed, ex);
}
}
base.Close();
}
#endregion

View File

@@ -23,12 +23,12 @@ namespace mRemoteNG.Connection.Protocol
#region Public Properties
#region Control
public string Name { get; set; }
private string Name { get; }
protected UI.Window.ConnectionWindow ConnectionWindow
{
get { return _connectionWindow; }
set
private set
{
_connectionWindow = value;
_connectionWindow.ResizeBegin += ResizeBegin;
@@ -61,7 +61,7 @@ namespace mRemoteNG.Connection.Protocol
Name = name;
}
public ProtocolBase()
protected ProtocolBase()
{
}
@@ -78,7 +78,7 @@ namespace mRemoteNG.Connection.Protocol
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t focus Control (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't focus Control (Connection.Protocol.Base)", ex);
}
}
@@ -112,7 +112,7 @@ namespace mRemoteNG.Connection.Protocol
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t SetProps (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't SetProps (Connection.Protocol.Base)", ex);
return false;
}
}
@@ -132,7 +132,7 @@ namespace mRemoteNG.Connection.Protocol
public virtual void Close()
{
Thread t = new Thread(CloseBG);
var t = new Thread(CloseBG);
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
@@ -153,31 +153,31 @@ namespace mRemoteNG.Connection.Protocol
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.WarningMsg, "Could not dispose control, probably form is already closed (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't dispose control, probably form is already closed (Connection.Protocol.Base)", ex);
}
}
if (_interfaceControl != null)
{
try
{
if (_interfaceControl.Parent == null) return;
if (_interfaceControl.Parent.Tag != null)
{
SetTagToNothing();
}
if (_interfaceControl == null) return;
try
{
if (_interfaceControl.Parent == null) return;
if (_interfaceControl.Parent.Tag != null)
{
SetTagToNothing();
}
DisposeInterface();
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.WarningMsg, "Could not set InterfaceControl.Parent.Tag or Dispose Interface, probably form is already closed (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true);
}
}
DisposeInterface();
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't set InterfaceControl.Parent.Tag or Dispose Interface, probably form is already closed (Connection.Protocol.Base)", ex);
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t Close InterfaceControl BG (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't Close InterfaceControl BG (Connection.Protocol.Base)", ex);
}
}
@@ -186,7 +186,7 @@ namespace mRemoteNG.Connection.Protocol
{
if (_interfaceControl.InvokeRequired)
{
DisposeInterfaceCB s = new DisposeInterfaceCB(DisposeInterface);
var s = new DisposeInterfaceCB(DisposeInterface);
_interfaceControl.Invoke(s);
}
else
@@ -200,7 +200,7 @@ namespace mRemoteNG.Connection.Protocol
{
if (_interfaceControl.Parent.InvokeRequired)
{
SetTagToNothingCB s = new SetTagToNothingCB(SetTagToNothing);
var s = new SetTagToNothingCB(SetTagToNothing);
_interfaceControl.Parent.Invoke(s);
}
else
@@ -214,7 +214,7 @@ namespace mRemoteNG.Connection.Protocol
{
if (Control.InvokeRequired)
{
DisposeControlCB s = new DisposeControlCB(DisposeControl);
var s = new DisposeControlCB(DisposeControl);
Control.Invoke(s);
}
else

View File

@@ -30,6 +30,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
private ConnectionInfo _connectionInfo;
private bool _loginComplete;
private bool _redirectKeys;
private bool _alertOnIdleDisconnect;
#endregion
#region Properties
@@ -129,9 +130,12 @@ namespace mRemoteNG.Connection.Protocol.RDP
SetCredentials();
SetResolution();
_rdpClient.FullScreenTitle = _connectionInfo.Name;
//not user changeable
_rdpClient.AdvancedSettings2.GrabFocusOnConnect = true;
_alertOnIdleDisconnect = _connectionInfo.RDPAlertIdleTimeout;
_rdpClient.AdvancedSettings2.MinutesToIdleTimeout = _connectionInfo.RDPMinutesToIdleTimeout;
//not user changeable
_rdpClient.AdvancedSettings2.GrabFocusOnConnect = true;
_rdpClient.AdvancedSettings3.EnableAutoReconnect = true;
_rdpClient.AdvancedSettings3.MaxReconnectAttempts = Settings.Default.RdpReconnectionCount;
_rdpClient.AdvancedSettings2.keepAliveInterval = 60000; //in milliseconds (10,000 = 10 seconds)
@@ -176,8 +180,8 @@ namespace mRemoteNG.Connection.Protocol.RDP
{
_loginComplete = false;
SetEventHandlers();
try
try
{
_rdpClient.Connect();
base.Connect();
@@ -616,7 +620,8 @@ namespace mRemoteNG.Connection.Protocol.RDP
_rdpClient.OnFatalError += RDPEvent_OnFatalError;
_rdpClient.OnDisconnected += RDPEvent_OnDisconnected;
_rdpClient.OnLeaveFullScreenMode += RDPEvent_OnLeaveFullscreenMode;
}
_rdpClient.OnIdleTimeoutNotification += RDPEvent_OnIdleTimeoutNotification;
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetEventHandlersFailed, ex);
@@ -625,7 +630,20 @@ namespace mRemoteNG.Connection.Protocol.RDP
#endregion
#region Private Events & Handlers
private void RDPEvent_OnFatalError(int errorCode)
private void RDPEvent_OnIdleTimeoutNotification()
{
Close(); //Simply close the RDP Session if the idle timeout has been triggered.
if (_alertOnIdleDisconnect)
{
string message = "The " + _connectionInfo.Name + " session was disconnected due to inactivity";
const string caption = "Session Disconnected";
MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
private void RDPEvent_OnFatalError(int errorCode)
{
Event_ErrorOccured(this, Convert.ToString(errorCode));
}

View File

@@ -75,7 +75,7 @@ namespace mRemoteNG.Connection
var puttyProcess = new PuttyProcessController();
if (!puttyProcess.Start())
{
return ;
return;
}
if (puttyProcess.SelectListBoxItem(PuttySession))
{

View File

@@ -116,7 +116,7 @@ namespace mRemoteNG.Messages
return lvItem;
}
public void AddExceptionMessage(string message, Exception ex, MessageClass msgClass = MessageClass.ErrorMsg, bool logOnly = false)
public void AddExceptionMessage(string message, Exception ex, MessageClass msgClass = MessageClass.ErrorMsg, bool logOnly = true)
{
AddMessage(msgClass, message + Environment.NewLine + Tools.MiscTools.GetExceptionMessageRecursive(ex), logOnly);
}
@@ -186,7 +186,7 @@ namespace mRemoteNG.Messages
}
}
delegate void AddToListCB(ListViewItem lvItem);
private delegate void AddToListCB(ListViewItem lvItem);
private void AddToList(ListViewItem lvItem)
{
if (MCForm.lvErrorCollector.InvokeRequired)

View File

@@ -14,7 +14,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("Multi-protocol remote connections manager")]
[assembly: AssemblyCompany("")]
[assembly:AssemblyProduct("mRemoteNG")]
[assembly: AssemblyCopyright("Copyright © 2016 mRemoteNG Dev Team; 2010-2013 Riley McArdle; 2007-2009 Felix Deimel")]
[assembly: AssemblyCopyright("Copyright © 2017 mRemoteNG Dev Team; 2010-2013 Riley McArdle; 2007-2009 Felix Deimel")]
[assembly:AssemblyTrademark("")]
[assembly:ComVisible(false)]

View File

@@ -2099,13 +2099,16 @@ namespace mRemoteNG {
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("release")]
public string UpdateChannel {
get {
return ((string)(this["UpdateChannel"]));
}
set {
this["UpdateChannel"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
@@ -2347,5 +2350,53 @@ namespace mRemoteNG {
this["InhDefaultSoundQuality"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int ConDefaultRDPMinutesToIdleTimeout {
get {
return ((int)(this["ConDefaultRDPMinutesToIdleTimeout"]));
}
set {
this["ConDefaultRDPMinutesToIdleTimeout"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool InhDefaultRDPMinutesToIdleTimeout {
get {
return ((bool)(this["InhDefaultRDPMinutesToIdleTimeout"]));
}
set {
this["InhDefaultRDPMinutesToIdleTimeout"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool ConDefaultRDPAlertIdleTimeout {
get {
return ((bool)(this["ConDefaultRDPAlertIdleTimeout"]));
}
set {
this["ConDefaultRDPAlertIdleTimeout"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool InhDefaultRDPAlertIdleTimeout {
get {
return ((bool)(this["InhDefaultRDPAlertIdleTimeout"]));
}
set {
this["InhDefaultRDPAlertIdleTimeout"] = value;
}
}
}
}

View File

@@ -521,7 +521,7 @@
<Setting Name="IdentifyQuickConnectTabs" Roaming="true" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="UpdateChannel" Type="System.String" Scope="Application">
<Setting Name="UpdateChannel" Type="System.String" Scope="User">
<Value Profile="(Default)">release</Value>
</Setting>
<Setting Name="ThemeName" Type="System.String" Scope="User">
@@ -584,5 +584,17 @@
<Setting Name="InhDefaultSoundQuality" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="ConDefaultRDPMinutesToIdleTimeout" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="InhDefaultRDPMinutesToIdleTimeout" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="ConDefaultRDPAlertIdleTimeout" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="InhDefaultRDPAlertIdleTimeout" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@@ -1,13 +1,60 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Quick Connect</title>
<link href="Main.css" rel="stylesheet" type="text/css" />
</head>
<body>
<p>
Sorry, not yet...</p>
</body>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Quick Connect</title>
<link href="Main.css" rel="stylesheet" type="text/css" />
</head>
<body>
<p>
The Quick Connect functionality of mRemoteNG allows you to quickly connect to a remote host using a variety of network protocols.
</p>
<p class="heading1">
Use Cases
</p>
<p>
The primary use case for Quick Connect is to connect to remote hosts when you already remember the DNS hostname/IP address and the appropriate protocol for the connection.
<br />
<br />
An additional use case is to connect to remote hosts saved as a connection quickly.
</p>
<p class="heading1">
Prerequisites
</p>
<ul>
<li>Knowledge of a DNS host name or IP address</li>
<li>Knowledge of an appropriate protocol to communicate with remote host</li>
</ul>
<p> OR </p>
<ul>
<li>A predefined mRemoteNG connection</li>
</ul>
<p class="heading1">
Using QuickConnect
</p>
<p>
To use Quick Connect, ensure the Quick Connect toolbar is enabled by selecting <b>View</b> and then <b>Quick Connect Toolbar</b>.
<br />
Next, input a DNS host name or IP address into the box labeled "Connect". This box will also save previous entries during your session.
<br />
<img alt="Quick Connect Toolbar" src="Screenshots/Quick Connect/01.png" />
<br />
<br />
<img alt="Quick Connect Toolbar" src="Screenshots/Quick Connect/02.png" />
<br />
<br />
Select the appropriate network protocol by clicking the arrow next to the Connect box.
<br />
<img alt="Quick Connect Toolbar" src="Screenshots/Quick Connect/03.png" />
<br />
<br />
If you wish to use an existing connection, select the globe icon next to the protocol button and select the appropriate connection.
</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -4117,6 +4117,24 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Select whether to receive an alert after the RDP session disconnects due to inactivity.
/// </summary>
internal static string strPropertyDescriptionRDPAlertIdleTimeout {
get {
return ResourceManager.GetString("strPropertyDescriptionRDPAlertIdleTimeout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The number of minutes for the RDP session to sit idle before automatically disconnecting (for no limit use 0).
/// </summary>
internal static string strPropertyDescriptionRDPMinutesToIdleTimeout {
get {
return ResourceManager.GetString("strPropertyDescriptionRDPMinutesToIdleTimeout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Select whether local disk drives should be shown on the remote host..
/// </summary>
@@ -4603,6 +4621,24 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Alert on Idle Disconnect.
/// </summary>
internal static string strPropertyNameRDPAlertIdleTimeout {
get {
return ResourceManager.GetString("strPropertyNameRDPAlertIdleTimeout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Minutes to Idle.
/// </summary>
internal static string strPropertyNameRDPMinutesToIdleTimeout {
get {
return ResourceManager.GetString("strPropertyNameRDPMinutesToIdleTimeout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Disk Drives.
/// </summary>

View File

@@ -2421,4 +2421,16 @@ mRemoteNG will now quit and begin with the installation.</value>
<data name="strDownloadPortable" xml:space="preserve">
<value>Download</value>
</data>
<data name="strPropertyDescriptionRDPMinutesToIdleTimeout" xml:space="preserve">
<value>The number of minutes for the RDP session to sit idle before automatically disconnecting (for no limit use 0)</value>
</data>
<data name="strPropertyNameRDPMinutesToIdleTimeout" xml:space="preserve">
<value>Minutes to Idle</value>
</data>
<data name="strPropertyDescriptionRDPAlertIdleTimeout" xml:space="preserve">
<value>Select whether to receive an alert after the RDP session disconnects due to inactivity</value>
</data>
<data name="strPropertyNameRDPAlertIdleTimeout" xml:space="preserve">
<value>Alert on Idle Disconnect</value>
</data>
</root>

View File

@@ -34,6 +34,7 @@
<xs:attribute name="Descr" type="xs:string" use="required" />
<xs:attribute name="Icon" type="xs:string" use="required" />
<xs:attribute name="Panel" type="xs:string" use="required" />
<xs:attribute name="Id" type="xs:string" use="required" />
<xs:attribute name="Username" type="xs:string" use="required" />
<xs:attribute name="Domain" type="xs:string" use="required" />
<xs:attribute name="Password" type="xs:string" use="required" />
@@ -46,6 +47,8 @@
<xs:attribute name="RenderingEngine" type="xs:string" use="required" />
<xs:attribute name="ICAEncryptionStrength" type="xs:string" use="required" />
<xs:attribute name="RDPAuthenticationLevel" type="xs:string" use="required" />
<xs:attribute name="RDPMinutesToIdleTimeout" type="xs:int" use="required" />
<xs:attribute name="RDPAlertIdleTimeout" type="xs:boolean" use="required" />
<xs:attribute name="LoadBalanceInfo" type="xs:string" use="required" />
<xs:attribute name="Colors" type="xs:string" use="required" />
<xs:attribute name="Resolution" type="xs:string" use="required" />
@@ -114,6 +117,8 @@
<xs:attribute name="InheritUsername" type="xs:boolean" use="optional" />
<xs:attribute name="InheritICAEncryptionStrength" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRDPAuthenticationLevel" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRDPMinutesToIdleTimeout" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRDPAlertIdleTimeout" type="xs:boolean" use="optional" />
<xs:attribute name="InheritLoadBalanceInfo" type="xs:boolean" use="optional" />
<xs:attribute name="InheritPreExtApp" type="xs:boolean" use="optional" />
<xs:attribute name="InheritPostExtApp" type="xs:boolean" use="optional" />

View File

@@ -117,7 +117,7 @@ namespace mRemoteNG.Themes
{
if (_name == value)
{
return ;
return;
}
_name = value;
NotifyPropertyChanged("Name");
@@ -135,7 +135,7 @@ namespace mRemoteNG.Themes
{
if (_windowBackgroundColor == value)
{
return ;
return;
}
_windowBackgroundColor = value;
NotifyPropertyChanged("WindowBackgroundColor");
@@ -152,7 +152,7 @@ namespace mRemoteNG.Themes
{
if (_menuBackgroundColor == value)
{
return ;
return;
}
_menuBackgroundColor = value;
NotifyPropertyChanged("MenuBackgroundColor");
@@ -169,7 +169,7 @@ namespace mRemoteNG.Themes
{
if (_menuTextColor == value)
{
return ;
return;
}
_menuTextColor = value;
NotifyPropertyChanged("MenuTextColor");
@@ -187,7 +187,7 @@ namespace mRemoteNG.Themes
{
if (_toolbarBackgroundColor == value || value.A < 255)
{
return ;
return;
}
_toolbarBackgroundColor = value;
NotifyPropertyChanged("ToolbarBackgroundColor");
@@ -204,7 +204,7 @@ namespace mRemoteNG.Themes
{
if (_toolbarTextColor == value)
{
return ;
return;
}
_toolbarTextColor = value;
NotifyPropertyChanged("ToolbarTextColor");
@@ -223,7 +223,7 @@ namespace mRemoteNG.Themes
{
if (_connectionsPanelBackgroundColor == value || value.A < 255)
{
return ;
return;
}
_connectionsPanelBackgroundColor = value;
NotifyPropertyChanged("ConnectionsPanelBackgroundColor");
@@ -240,7 +240,7 @@ namespace mRemoteNG.Themes
{
if (_connectionsPanelTextColor == value)
{
return ;
return;
}
_connectionsPanelTextColor = value;
NotifyPropertyChanged("ConnectionsPanelTextColor");
@@ -260,7 +260,7 @@ namespace mRemoteNG.Themes
{
if (_connectionsPanelTreeLineColor == value)
{
return ;
return;
}
_connectionsPanelTreeLineColor = value;
NotifyPropertyChanged("ConnectionsPanelTreeLineColor");
@@ -280,7 +280,7 @@ namespace mRemoteNG.Themes
{
if (_searchBoxBackgroundColor == value || value.A < 255)
{
return ;
return;
}
_searchBoxBackgroundColor = value;
NotifyPropertyChanged("SearchBoxBackgroundColor");
@@ -300,7 +300,7 @@ namespace mRemoteNG.Themes
{
if (_searchBoxTextPromptColor == value)
{
return ;
return;
}
_searchBoxTextPromptColor = value;
NotifyPropertyChanged("SearchBoxTextPromptColor");
@@ -320,7 +320,7 @@ namespace mRemoteNG.Themes
{
if (_searchBoxTextColor == value)
{
return ;
return;
}
_searchBoxTextColor = value;
NotifyPropertyChanged("SearchBoxTextColor");
@@ -342,7 +342,7 @@ namespace mRemoteNG.Themes
{
if (_configPanelBackgroundColor == value || value.A < 255)
{
return ;
return;
}
_configPanelBackgroundColor = value;
NotifyPropertyChanged("ConfigPanelBackgroundColor");
@@ -362,7 +362,7 @@ namespace mRemoteNG.Themes
{
if (_configPanelTextColor == value)
{
return ;
return;
}
_configPanelTextColor = value;
NotifyPropertyChanged("ConfigPanelTextColor");
@@ -382,7 +382,7 @@ namespace mRemoteNG.Themes
{
if (_configPanelCategoryTextColor == value)
{
return ;
return;
}
_configPanelCategoryTextColor = value;
NotifyPropertyChanged("ConfigPanelCategoryTextColor");
@@ -402,7 +402,7 @@ namespace mRemoteNG.Themes
{
if (_configPanelHelpBackgroundColor == value || value.A < 255)
{
return ;
return;
}
_configPanelHelpBackgroundColor = value;
NotifyPropertyChanged("ConfigPanelHelpBackgroundColor");
@@ -422,7 +422,7 @@ namespace mRemoteNG.Themes
{
if (_configPanelHelpTextColor == value)
{
return ;
return;
}
_configPanelHelpTextColor = value;
NotifyPropertyChanged("ConfigPanelHelpTextColor");
@@ -442,7 +442,7 @@ namespace mRemoteNG.Themes
{
if (_configPanelGridLineColor == value)
{
return ;
return;
}
_configPanelGridLineColor = value;
NotifyPropertyChanged("ConfigPanelGridLineColor");

View File

@@ -81,7 +81,7 @@ namespace mRemoteNG.Themes
{
if (e.PropertyName == "Name")
{
return ;
return;
}
ThemeChangedEvent?.Invoke();
}

View File

@@ -11,6 +11,7 @@ namespace mRemoteNG.Tools
{
public class ExternalTool
{
private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
#region Public Properties
public string DisplayName { get; set; }
public string FileName { get; set; }
@@ -57,7 +58,7 @@ namespace mRemoteNG.Tools
private void StartExternalProcess()
{
Process process = new Process();
var process = new Process();
SetProcessProperties(process, ConnectionInfo);
process.Start();
@@ -69,7 +70,7 @@ namespace mRemoteNG.Tools
private void SetProcessProperties(Process process, ConnectionInfo startConnectionInfo)
{
ExternalToolArgumentParser argParser = new ExternalToolArgumentParser(startConnectionInfo);
var argParser = new ExternalToolArgumentParser(startConnectionInfo);
process.StartInfo.UseShellExecute = true;
process.StartInfo.FileName = argParser.ParseArguments(FileName);
process.StartInfo.Arguments = argParser.ParseArguments(Arguments);
@@ -79,18 +80,18 @@ namespace mRemoteNG.Tools
{
try
{
ConnectionInfo newConnectionInfo = BuildConnectionInfoForIntegratedApp();
ConnectionInitiator.OpenConnection(newConnectionInfo);
var newConnectionInfo = BuildConnectionInfoForIntegratedApp();
_connectionInitiator.OpenConnection(newConnectionInfo);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(message: "ExternalApp.StartIntegrated() failed.", ex: ex, logOnly: true);
Runtime.MessageCollector.AddExceptionMessage("ExternalApp.StartIntegrated() failed.", ex);
}
}
private ConnectionInfo BuildConnectionInfoForIntegratedApp()
{
ConnectionInfo newConnectionInfo = GetAppropriateInstanceOfConnectionInfo();
var newConnectionInfo = GetAppropriateInstanceOfConnectionInfo();
SetConnectionInfoFields(newConnectionInfo);
return newConnectionInfo;
}

View File

@@ -14,7 +14,7 @@ using static System.String;
namespace mRemoteNG.Tools
{
public class MiscTools
public static class MiscTools
{
public static Icon GetIconFromFile(string FileName)
{
@@ -112,7 +112,7 @@ namespace mRemoteNG.Tools
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Taking Screenshot failed" + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace("Taking Screenshot failed", ex);
}
return null;
@@ -120,7 +120,7 @@ namespace mRemoteNG.Tools
public class EnumTypeConverter : EnumConverter
{
private Type _enumType;
private readonly Type _enumType;
public EnumTypeConverter(Type type) : base(type)
{
@@ -135,8 +135,8 @@ namespace mRemoteNG.Tools
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destType)
{
if (value == null) return null;
var fi = _enumType.GetField(Enum.GetName(_enumType, value: value));
var dna = (DescriptionAttribute) (Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)));
var fi = _enumType.GetField(Enum.GetName(_enumType, value));
var dna = (DescriptionAttribute) Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));
return dna != null ? dna.Description : value.ToString();
}
@@ -150,9 +150,9 @@ namespace mRemoteNG.Tools
{
foreach (var fi in _enumType.GetFields())
{
var dna = (DescriptionAttribute) (Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)));
var dna = (DescriptionAttribute) Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));
if ((dna != null) && ((string) value == dna.Description))
if (dna != null && (string) value == dna.Description)
{
return Enum.Parse(_enumType, fi.Name);
}
@@ -167,12 +167,7 @@ namespace mRemoteNG.Tools
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
@@ -193,7 +188,7 @@ namespace mRemoteNG.Tools
return false;
}
throw (new Exception("Values must be \"Yes\" or \"No\""));
throw new Exception("Values must be \"Yes\" or \"No\"");
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
@@ -220,63 +215,5 @@ namespace mRemoteNG.Tools
return svc;
}
}
public class Fullscreen
{
public Fullscreen(Form handledForm)
{
_handledForm = handledForm;
}
private readonly Form _handledForm;
private FormWindowState _savedWindowState;
private FormBorderStyle _savedBorderStyle;
private Rectangle _savedBounds;
private bool _value;
public bool Value
{
get
{
return _value;
}
set
{
if (_value == value)
{
return ;
}
if (!_value)
{
EnterFullscreen();
}
else
{
ExitFullscreen();
}
_value = value;
}
}
private void EnterFullscreen()
{
_savedBorderStyle = _handledForm.FormBorderStyle;
_savedWindowState = _handledForm.WindowState;
_savedBounds = _handledForm.Bounds;
_handledForm.FormBorderStyle = FormBorderStyle.None;
if (_handledForm.WindowState == FormWindowState.Maximized)
{
_handledForm.WindowState = FormWindowState.Normal;
}
_handledForm.WindowState = FormWindowState.Maximized;
}
private void ExitFullscreen()
{
_handledForm.FormBorderStyle = _savedBorderStyle;
_handledForm.WindowState = _savedWindowState;
_handledForm.Bounds = _savedBounds;
}
}
}
}

View File

@@ -0,0 +1,128 @@
using System;
using System.Linq;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.UI.Forms;
namespace mRemoteNG.Tools
{
public class NotificationAreaIcon
{
private readonly NotifyIcon _nI;
private readonly ContextMenuStrip _cMen;
private readonly ToolStripMenuItem _cMenCons;
private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
public bool Disposed { get; private set; }
public NotificationAreaIcon()
{
try
{
_cMenCons = new ToolStripMenuItem
{
Text = Language.strConnections,
Image = Resources.Root
};
var cMenSep1 = new ToolStripSeparator();
var cMenExit = new ToolStripMenuItem {Text = Language.strMenuExit};
cMenExit.Click += cMenExit_Click;
_cMen = new ContextMenuStrip
{
Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, Convert.ToByte(0)),
RenderMode = ToolStripRenderMode.Professional
};
_cMen.Items.AddRange(new ToolStripItem[] {_cMenCons, cMenSep1, cMenExit});
_nI = new NotifyIcon
{
Text = @"mRemoteNG",
BalloonTipText = @"mRemoteNG",
Icon = Resources.mRemote_Icon,
ContextMenuStrip = _cMen,
Visible = true
};
_nI.MouseClick += nI_MouseClick;
_nI.MouseDoubleClick += nI_MouseDoubleClick;
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("Creating new SysTrayIcon failed", ex);
}
}
public void Dispose()
{
try
{
_nI.Visible = false;
_nI.Dispose();
_cMen.Dispose();
Disposed = true;
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("Disposing SysTrayIcon failed", ex);
}
}
private void nI_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Right) return;
_cMenCons.DropDownItems.Clear();
var menuItemsConverter = new ConnectionsTreeToMenuItemsConverter
{
MouseUpEventHandler = ConMenItem_MouseUp
};
// ReSharper disable once CoVariantArrayConversion
ToolStripItem[] rootMenuItems = menuItemsConverter.CreateToolStripDropDownItems(Runtime.ConnectionTreeModel).ToArray();
_cMenCons.DropDownItems.AddRange(rootMenuItems);
}
private static void nI_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (frmMain.Default.Visible)
HideForm();
else
ShowForm();
}
private static void ShowForm()
{
frmMain.Default.Show();
frmMain.Default.WindowState = frmMain.Default.PreviousWindowState;
if (Settings.Default.ShowSystemTrayIcon) return;
Runtime.NotificationAreaIcon.Dispose();
Runtime.NotificationAreaIcon = null;
}
private static void HideForm()
{
frmMain.Default.Hide();
frmMain.Default.PreviousWindowState = frmMain.Default.WindowState;
}
private void ConMenItem_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
if (!(((ToolStripMenuItem) sender).Tag is ConnectionInfo)) return;
if (frmMain.Default.Visible == false)
ShowForm();
_connectionInitiator.OpenConnection((ConnectionInfo) ((ToolStripMenuItem) sender).Tag);
}
private static void cMenExit_Click(object sender, EventArgs e)
{
Shutdown.Quit();
}
}
}

View File

@@ -83,7 +83,7 @@ namespace mRemoteNG.Tools
public void WaitForExit()
{
if (Process == null || Process.HasExited)
return ;
return;
Process.WaitForExit();
}
#endregion

View File

@@ -1,161 +0,0 @@
using System;
using System.Linq;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.UI.Forms;
namespace mRemoteNG.Tools
{
public class Controls
{
public class NotificationAreaIcon
{
private NotifyIcon _nI;
private ContextMenuStrip _cMen;
private ToolStripMenuItem _cMenCons;
public bool Disposed { get; set; }
public NotificationAreaIcon()
{
try
{
_cMenCons = new ToolStripMenuItem
{
Text = Language.strConnections,
Image = Resources.Root
};
var cMenSep1 = new ToolStripSeparator();
var cMenExit = new ToolStripMenuItem {Text = Language.strMenuExit};
cMenExit.Click += cMenExit_Click;
_cMen = new ContextMenuStrip
{
Font =
new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, Convert.ToByte(0)),
RenderMode = ToolStripRenderMode.Professional
};
_cMen.Items.AddRange(new ToolStripItem[] {_cMenCons, cMenSep1, cMenExit});
_nI = new NotifyIcon
{
Text = "mRemote",
BalloonTipText = "mRemote",
Icon = Resources.mRemote_Icon,
ContextMenuStrip = _cMen,
Visible = true
};
_nI.MouseClick += nI_MouseClick;
_nI.MouseDoubleClick += nI_MouseDoubleClick;
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Creating new SysTrayIcon failed" + Environment.NewLine + ex.Message, true);
}
}
public void Dispose()
{
try
{
_nI.Visible = false;
_nI.Dispose();
_cMen.Dispose();
Disposed = true;
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Disposing SysTrayIcon failed" + Environment.NewLine + ex.Message, true);
}
}
private void nI_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Right) return;
_cMenCons.DropDownItems.Clear();
var menuItemsConverter = new ConnectionsTreeToMenuItemsConverter
{
MouseUpEventHandler = ConMenItem_MouseUp
};
ToolStripItem[] rootMenuItems = menuItemsConverter.CreateToolStripDropDownItems(Runtime.ConnectionTreeModel).ToArray();
_cMenCons.DropDownItems.AddRange(rootMenuItems);
}
private void nI_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (frmMain.Default.Visible)
{
HideForm();
}
else
{
ShowForm();
}
}
private void ShowForm()
{
frmMain.Default.Show();
frmMain.Default.WindowState = frmMain.Default.PreviousWindowState;
if (Settings.Default.ShowSystemTrayIcon) return;
Runtime.NotificationAreaIcon.Dispose();
Runtime.NotificationAreaIcon = null;
}
private void HideForm()
{
frmMain.Default.Hide();
frmMain.Default.PreviousWindowState = frmMain.Default.WindowState;
}
private void ConMenItem_MouseUp(Object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
if (!(((Control) sender).Tag is ConnectionInfo)) return;
if (frmMain.Default.Visible == false)
{
ShowForm();
}
ConnectionInitiator.OpenConnection((ConnectionInfo)((Control)sender).Tag);
}
private void cMenExit_Click(Object sender, EventArgs e)
{
Shutdown.Quit();
}
}
public static SaveFileDialog ConnectionsSaveAsDialog()
{
var saveFileDialog = new SaveFileDialog();
saveFileDialog.CheckPathExists = true;
saveFileDialog.InitialDirectory = App.Info.ConnectionsFileInfo.DefaultConnectionsPath;
saveFileDialog.FileName = App.Info.ConnectionsFileInfo.DefaultConnectionsFile;
saveFileDialog.OverwritePrompt = true;
saveFileDialog.Filter = Language.strFiltermRemoteXML + "|*.xml|" + Language.strFilterAll + "|*.*";
return saveFileDialog;
}
public static OpenFileDialog ConnectionsLoadDialog()
{
var lDlg = new OpenFileDialog
{
CheckFileExists = true,
InitialDirectory = App.Info.ConnectionsFileInfo.DefaultConnectionsPath,
Filter = Language.strFiltermRemoteXML + "|*.xml|" + Language.strFilterAll + "|*.*"
};
return lDlg;
}
}
}

View File

@@ -0,0 +1,11 @@

namespace mRemoteNG.Tree
{
public class AlwaysConfirmYes : IConfirm
{
public bool Confirm()
{
return true;
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.UI.Controls;
namespace mRemoteNG.Tree
{
public class ExpandNodeClickHandler : ITreeNodeClickHandler
{
private readonly IConnectionTree _connectionTree;
public ExpandNodeClickHandler(IConnectionTree connectionTree)
{
if (connectionTree == null)
throw new ArgumentNullException(nameof(connectionTree));
_connectionTree = connectionTree;
}
public void Execute(ConnectionInfo clickedNode)
{
var clickedNodeAsContainer = clickedNode as ContainerInfo;
if (clickedNodeAsContainer == null) return;
_connectionTree.ToggleExpansion(clickedNodeAsContainer);
}
}
}

View File

@@ -0,0 +1,10 @@
using mRemoteNG.Connection;
namespace mRemoteNG.Tree
{
public interface ITreeNodeClickHandler
{
void Execute(ConnectionInfo clickedNode);
}
}

View File

@@ -0,0 +1,26 @@
using System;
using mRemoteNG.Connection;
namespace mRemoteNG.Tree
{
public class OpenConnectionClickHandler : ITreeNodeClickHandler
{
private readonly IConnectionInitiator _connectionInitiator;
public OpenConnectionClickHandler(IConnectionInitiator connectionInitiator)
{
if (connectionInitiator == null)
throw new ArgumentNullException(nameof(connectionInitiator));
_connectionInitiator = connectionInitiator;
}
public void Execute(ConnectionInfo clickedNode)
{
if (clickedNode == null)
throw new ArgumentNullException(nameof(clickedNode));
if (clickedNode.GetTreeNodeType() != TreeNodeType.Connection && clickedNode.GetTreeNodeType() != TreeNodeType.PuttySession) return;
_connectionInitiator.OpenConnection(clickedNode);
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using mRemoteNG.Connection;
namespace mRemoteNG.Tree
{
public class SwitchToConnectionClickHandler : ITreeNodeClickHandler
{
private readonly IConnectionInitiator _connectionInitiator;
public SwitchToConnectionClickHandler(IConnectionInitiator connectionInitiator)
{
if (connectionInitiator == null)
throw new ArgumentNullException(nameof(connectionInitiator));
_connectionInitiator = connectionInitiator;
}
public void Execute(ConnectionInfo clickedNode)
{
if (clickedNode == null)
throw new ArgumentNullException(nameof(clickedNode));
if (clickedNode.GetTreeNodeType() != TreeNodeType.Connection && clickedNode.GetTreeNodeType() != TreeNodeType.PuttySession) return;
_connectionInitiator.SwitchToOpenConnection(clickedNode);
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using mRemoteNG.Connection;
namespace mRemoteNG.Tree
{
public class TreeNodeCompositeClickHandler : ITreeNodeClickHandler
{
public IEnumerable<ITreeNodeClickHandler> ClickHandlers { get; set; } = new ITreeNodeClickHandler[0];
public void Execute(ConnectionInfo clickedNode)
{
if (clickedNode == null)
throw new ArgumentNullException(nameof(clickedNode));
foreach (var handler in ClickHandlers)
{
handler.Execute(clickedNode);
}
}
}
}

View File

@@ -0,0 +1,7 @@
namespace mRemoteNG.Tree
{
public interface IConfirm
{
bool Confirm();
}
}

View File

@@ -1,24 +0,0 @@
using System.Windows.Forms;
using BrightIdeasSoftware;
namespace mRemoteNG.Tree
{
public static class ObjectListViewExtensions
{
public static void Invoke(this Control control, MethodInvoker action)
{
control.Invoke(action);
}
public static void InvokeExpand(this TreeListView control, object model)
{
control.Invoke(() => control.Expand(model));
}
public static void InvokeRebuildAll(this TreeListView control, bool preserveState)
{
control.Invoke(() => control.RebuildAll(preserveState));
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Linq;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.UI.Controls;
namespace mRemoteNG.Tree
{
public class PreviousSessionOpener : IConnectionTreeDelegate
{
private readonly IConnectionInitiator _connectionInitiator;
public PreviousSessionOpener(IConnectionInitiator connectionInitiator)
{
if (connectionInitiator == null)
throw new ArgumentNullException(nameof(connectionInitiator));
_connectionInitiator = connectionInitiator;
}
public void Execute(IConnectionTree connectionTree)
{
var connectionInfoList = connectionTree.GetRootConnectionNode().GetRecursiveChildList().Where(node => !(node is ContainerInfo));
var previouslyOpenedConnections = connectionInfoList.Where(item => item.PleaseConnect);
foreach (var connectionInfo in previouslyOpenedConnections)
{
_connectionInitiator.OpenConnection(connectionInfo);
}
}
}
}

View File

@@ -0,0 +1,19 @@
using System.Linq;
using mRemoteNG.Container;
using mRemoteNG.UI.Controls;
namespace mRemoteNG.Tree
{
public class PreviouslyOpenedFolderExpander : IConnectionTreeDelegate
{
public void Execute(IConnectionTree connectionTree)
{
var rootNode = connectionTree.GetRootConnectionNode();
var containerList = connectionTree.ConnectionTreeModel.GetRecursiveChildList(rootNode).OfType<ContainerInfo>();
var previouslyExpandedNodes = containerList.Where(container => container.IsExpanded);
connectionTree.ExpandedObjects = previouslyExpandedNodes;
connectionTree.InvokeRebuildAll(true);
}
}
}

View File

@@ -0,0 +1,14 @@
using mRemoteNG.UI.Controls;
namespace mRemoteNG.Tree
{
public class RootNodeExpander : IConnectionTreeDelegate
{
public void Execute(IConnectionTree connectionTree)
{
var rootConnectionNode = connectionTree.GetRootConnectionNode();
connectionTree.InvokeExpand(rootConnectionNode);
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Windows.Forms;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.UI.Controls;
namespace mRemoteNG.Tree
{
public class SelectedConnectionDeletionConfirmer : IConfirm
{
private readonly IConnectionTree _connectionTree;
private readonly Func<string, string, MessageBoxButtons, MessageBoxIcon, DialogResult> _confirmationFunc;
public SelectedConnectionDeletionConfirmer(IConnectionTree connectionTree, Func<string, string, MessageBoxButtons, MessageBoxIcon, DialogResult> confirmationFunc)
{
_connectionTree = connectionTree;
_confirmationFunc = confirmationFunc;
}
public bool Confirm()
{
var deletionTarget = _connectionTree.SelectedNode;
var deletionTargetAsContainer = deletionTarget as ContainerInfo;
if (deletionTargetAsContainer != null)
return deletionTargetAsContainer.HasChildren()
? UserConfirmsNonEmptyFolderDeletion(deletionTargetAsContainer)
: UserConfirmsEmptyFolderDeletion(deletionTargetAsContainer);
return UserConfirmsConnectionDeletion(deletionTarget);
}
private bool UserConfirmsEmptyFolderDeletion(AbstractConnectionInfoData deletionTarget)
{
var messagePrompt = string.Format(Language.strConfirmDeleteNodeFolder, deletionTarget.Name);
return PromptUser(messagePrompt);
}
private bool UserConfirmsNonEmptyFolderDeletion(AbstractConnectionInfoData deletionTarget)
{
var messagePrompt = string.Format(Language.strConfirmDeleteNodeFolderNotEmpty, deletionTarget.Name);
return PromptUser(messagePrompt);
}
private bool UserConfirmsConnectionDeletion(AbstractConnectionInfoData deletionTarget)
{
var messagePrompt = string.Format(Language.strConfirmDeleteNodeConnection, deletionTarget.Name);
return PromptUser(messagePrompt);
}
private bool PromptUser(string promptMessage)
{
var msgBoxResponse = _confirmationFunc.Invoke(promptMessage, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
return msgBoxResponse == DialogResult.Yes;
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using mRemoteNG.App;
@@ -6,13 +7,14 @@ using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
// ReSharper disable UnusedParameter.Local
namespace mRemoteNG.UI.Controls
{
internal sealed class ConnectionContextMenu : ContextMenuStrip
public sealed class ConnectionContextMenu : ContextMenuStrip
{
private ToolStripMenuItem _cMenTreeAddConnection;
private ToolStripMenuItem _cMenTreeAddFolder;
@@ -44,14 +46,23 @@ namespace mRemoteNG.UI.Controls
private ToolStripMenuItem _cMenTreeImportFile;
private ToolStripMenuItem _cMenTreeImportActiveDirectory;
private ToolStripMenuItem _cMenTreeImportPortScan;
private readonly ConnectionTree _connectionTree;
private readonly IConnectionInitiator _connectionInitiator;
public ConnectionContextMenu()
public ConnectionContextMenu(ConnectionTree connectionTree)
{
_connectionTree = connectionTree;
_connectionInitiator = new ConnectionInitiator();
InitializeComponent();
ApplyLanguage();
EnableShortcutKeys();
Opening += (sender, args) => AddExternalApps();
Opening += (sender, args) =>
{
AddExternalApps();
ShowHideMenuItems();
};
Closing += (sender, args) => EnableMenuItemsRecursive(Items);
}
private void InitializeComponent()
@@ -384,104 +395,129 @@ namespace mRemoteNG.UI.Controls
_cMenTreeMoveDown.Text = Language.strMoveDown;
}
internal void ShowHideTreeContextMenuItems(ConnectionInfo connectionInfo)
internal void ShowHideMenuItems()
{
if (connectionInfo == null)
if (_connectionTree.SelectedNode == null)
return;
try
{
Enabled = true;
EnableMenuItemsRecursive(Items);
if (connectionInfo is RootPuttySessionsNodeInfo)
if (_connectionTree.SelectedNode is RootPuttySessionsNodeInfo)
{
_cMenTreeAddConnection.Enabled = false;
_cMenTreeAddFolder.Enabled = false;
_cMenTreeConnect.Enabled = false;
_cMenTreeConnectWithOptions.Enabled = false;
_cMenTreeDisconnect.Enabled = false;
_cMenTreeToolsTransferFile.Enabled = false;
_cMenTreeConnectWithOptions.Enabled = false;
_cMenTreeToolsSort.Enabled = false;
_cMenTreeToolsExternalApps.Enabled = false;
_cMenTreeDuplicate.Enabled = false;
_cMenTreeRename.Enabled = true;
_cMenTreeDelete.Enabled = false;
_cMenTreeMoveUp.Enabled = false;
_cMenTreeMoveDown.Enabled = false;
ShowHideMenuItemsForRootPuttyNode();
}
else if (connectionInfo is RootNodeInfo)
else if (_connectionTree.SelectedNode is RootNodeInfo)
{
_cMenTreeConnect.Enabled = false;
_cMenTreeConnectWithOptions.Enabled = false;
_cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false;
_cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false;
_cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Enabled = false;
_cMenTreeDisconnect.Enabled = false;
_cMenTreeToolsTransferFile.Enabled = false;
_cMenTreeToolsExternalApps.Enabled = false;
_cMenTreeDuplicate.Enabled = false;
_cMenTreeDelete.Enabled = false;
_cMenTreeMoveUp.Enabled = false;
_cMenTreeMoveDown.Enabled = false;
ShowHideMenuItemsForRootConnectionNode();
}
else if (connectionInfo is ContainerInfo)
else if (_connectionTree.SelectedNode is ContainerInfo)
{
_cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false;
_cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false;
_cMenTreeDisconnect.Enabled = false;
var openConnections = ((ContainerInfo)connectionInfo).Children.Sum(child => child.OpenConnections.Count);
if (openConnections > 0)
_cMenTreeDisconnect.Enabled = true;
_cMenTreeToolsTransferFile.Enabled = false;
_cMenTreeToolsExternalApps.Enabled = false;
ShowHideMenuItemsForContainer(_connectionTree.SelectedNode);
}
else if (connectionInfo is PuttySessionInfo)
else if (_connectionTree.SelectedNode is PuttySessionInfo)
{
_cMenTreeAddConnection.Enabled = false;
_cMenTreeAddFolder.Enabled = false;
if (connectionInfo.OpenConnections.Count == 0)
_cMenTreeDisconnect.Enabled = false;
if (!(connectionInfo.Protocol == ProtocolType.SSH1 | connectionInfo.Protocol == ProtocolType.SSH2))
_cMenTreeToolsTransferFile.Enabled = false;
_cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false;
_cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false;
_cMenTreeToolsSort.Enabled = false;
_cMenTreeDuplicate.Enabled = false;
_cMenTreeRename.Enabled = false;
_cMenTreeDelete.Enabled = false;
_cMenTreeMoveUp.Enabled = false;
_cMenTreeMoveDown.Enabled = false;
ShowHideMenuItemsForPuttyNode(_connectionTree.SelectedNode);
}
else
{
if (connectionInfo.OpenConnections.Count == 0)
_cMenTreeDisconnect.Enabled = false;
if (!(connectionInfo.Protocol == ProtocolType.SSH1 | connectionInfo.Protocol == ProtocolType.SSH2))
_cMenTreeToolsTransferFile.Enabled = false;
if (!(connectionInfo.Protocol == ProtocolType.RDP | connectionInfo.Protocol == ProtocolType.ICA))
{
_cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false;
_cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false;
}
if (connectionInfo.Protocol == ProtocolType.IntApp)
_cMenTreeConnectWithOptionsNoCredentials.Enabled = false;
ShowHideMenuItemsForConnectionNode(_connectionTree.SelectedNode);
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("ShowHideTreeContextMenuItems (UI.Window.ConnectionTreeWindow) failed", ex);
Runtime.MessageCollector.AddExceptionStackTrace("ShowHideMenuItems (UI.Controls.ConnectionContextMenu) failed", ex);
}
}
internal void ShowHideMenuItemsForRootPuttyNode()
{
_cMenTreeAddConnection.Enabled = false;
_cMenTreeAddFolder.Enabled = false;
_cMenTreeConnect.Enabled = false;
_cMenTreeConnectWithOptions.Enabled = false;
_cMenTreeDisconnect.Enabled = false;
_cMenTreeToolsTransferFile.Enabled = false;
_cMenTreeConnectWithOptions.Enabled = false;
_cMenTreeToolsSort.Enabled = false;
_cMenTreeToolsExternalApps.Enabled = false;
_cMenTreeDuplicate.Enabled = false;
_cMenTreeRename.Enabled = true;
_cMenTreeDelete.Enabled = false;
_cMenTreeMoveUp.Enabled = false;
_cMenTreeMoveDown.Enabled = false;
}
internal void ShowHideMenuItemsForRootConnectionNode()
{
_cMenTreeConnect.Enabled = false;
_cMenTreeConnectWithOptions.Enabled = false;
_cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false;
_cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false;
_cMenTreeConnectWithOptionsChoosePanelBeforeConnecting.Enabled = false;
_cMenTreeDisconnect.Enabled = false;
_cMenTreeToolsTransferFile.Enabled = false;
_cMenTreeToolsExternalApps.Enabled = false;
_cMenTreeDuplicate.Enabled = false;
_cMenTreeDelete.Enabled = false;
_cMenTreeMoveUp.Enabled = false;
_cMenTreeMoveDown.Enabled = false;
}
internal void ShowHideMenuItemsForContainer(ConnectionInfo connectionInfo)
{
_cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false;
_cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false;
_cMenTreeDisconnect.Enabled = false;
var openConnections = ((ContainerInfo)connectionInfo).Children.Sum(child => child.OpenConnections.Count);
if (openConnections > 0)
_cMenTreeDisconnect.Enabled = true;
_cMenTreeToolsTransferFile.Enabled = false;
_cMenTreeToolsExternalApps.Enabled = false;
}
internal void ShowHideMenuItemsForPuttyNode(ConnectionInfo connectionInfo)
{
_cMenTreeAddConnection.Enabled = false;
_cMenTreeAddFolder.Enabled = false;
if (connectionInfo.OpenConnections.Count == 0)
_cMenTreeDisconnect.Enabled = false;
if (!(connectionInfo.Protocol == ProtocolType.SSH1 | connectionInfo.Protocol == ProtocolType.SSH2))
_cMenTreeToolsTransferFile.Enabled = false;
_cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false;
_cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false;
_cMenTreeToolsSort.Enabled = false;
_cMenTreeDuplicate.Enabled = false;
_cMenTreeRename.Enabled = false;
_cMenTreeDelete.Enabled = false;
_cMenTreeMoveUp.Enabled = false;
_cMenTreeMoveDown.Enabled = false;
}
internal void ShowHideMenuItemsForConnectionNode(ConnectionInfo connectionInfo)
{
if (connectionInfo.OpenConnections.Count == 0)
_cMenTreeDisconnect.Enabled = false;
if (!(connectionInfo.Protocol == ProtocolType.SSH1 | connectionInfo.Protocol == ProtocolType.SSH2))
_cMenTreeToolsTransferFile.Enabled = false;
if (!(connectionInfo.Protocol == ProtocolType.RDP | connectionInfo.Protocol == ProtocolType.ICA))
{
_cMenTreeConnectWithOptionsConnectInFullscreen.Enabled = false;
_cMenTreeConnectWithOptionsConnectToConsoleSession.Enabled = false;
}
if (connectionInfo.Protocol == ProtocolType.IntApp)
_cMenTreeConnectWithOptionsNoCredentials.Enabled = false;
}
internal void DisableShortcutKeys()
{
_cMenTreeConnect.ShortcutKeys = Keys.None;
@@ -553,183 +589,218 @@ namespace mRemoteNG.UI.Controls
_cMenTreeToolsExternalApps.DropDownItems.Clear();
}
#region Events
public event EventHandler ConnectClicked;
#region Click handlers
private void OnConnectClicked(object sender, EventArgs e)
{
var handler = ConnectClicked;
handler?.Invoke(this, e);
var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo;
if (selectedNodeAsContainer != null)
_connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.DoNotJump);
else
_connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.DoNotJump);
}
public event EventHandler ConnectToConsoleSessionClicked;
private void OnConnectToConsoleSessionClicked(object sender, EventArgs e)
{
var handler = ConnectToConsoleSessionClicked;
handler?.Invoke(this, e);
var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo;
if (selectedNodeAsContainer != null)
_connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.UseConsoleSession | ConnectionInfo.Force.DoNotJump);
else
_connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.UseConsoleSession | ConnectionInfo.Force.DoNotJump);
}
public event EventHandler DontConnectToConsoleSessionClicked;
private void OnDontConnectToConsoleSessionClicked(object sender, EventArgs e)
{
var handler = DontConnectToConsoleSessionClicked;
handler?.Invoke(this, e);
var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo;
if (selectedNodeAsContainer != null)
_connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.DontUseConsoleSession | ConnectionInfo.Force.DoNotJump);
else
_connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.DontUseConsoleSession | ConnectionInfo.Force.DoNotJump);
}
public event EventHandler ConnectInFullscreenClicked;
private void OnConnectInFullscreenClicked(object sender, EventArgs e)
{
var handler = ConnectInFullscreenClicked;
handler?.Invoke(this, e);
var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo;
if (selectedNodeAsContainer != null)
_connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.Fullscreen | ConnectionInfo.Force.DoNotJump);
else
_connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.Fullscreen | ConnectionInfo.Force.DoNotJump);
}
public event EventHandler ConnectWithNoCredentialsClick;
private void OnConnectWithNoCredentialsClick(object sender, EventArgs e)
{
var handler = ConnectWithNoCredentialsClick;
handler?.Invoke(this, e);
var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo;
if (selectedNodeAsContainer != null)
_connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.NoCredentials);
else
_connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.NoCredentials);
}
public event EventHandler ChoosePanelBeforeConnectingClicked;
private void OnChoosePanelBeforeConnectingClicked(object sender, EventArgs e)
{
var handler = ChoosePanelBeforeConnectingClicked;
handler?.Invoke(this, e);
var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo;
if (selectedNodeAsContainer != null)
_connectionInitiator.OpenConnection(selectedNodeAsContainer, ConnectionInfo.Force.OverridePanel | ConnectionInfo.Force.DoNotJump);
else
_connectionInitiator.OpenConnection(_connectionTree.SelectedNode, ConnectionInfo.Force.OverridePanel | ConnectionInfo.Force.DoNotJump);
}
public event EventHandler DisconnectClicked;
private void OnDisconnectClicked(object sender, EventArgs e)
{
var handler = DisconnectClicked;
handler?.Invoke(this, e);
DisconnectConnection(_connectionTree.SelectedNode);
}
public event EventHandler TransferFileClicked;
public void DisconnectConnection(ConnectionInfo connectionInfo)
{
try
{
if (connectionInfo == null) return;
var nodeAsContainer = connectionInfo as ContainerInfo;
if (nodeAsContainer != null)
{
foreach (var child in nodeAsContainer.Children)
{
for (var i = 0; i <= child.OpenConnections.Count - 1; i++)
{
child.OpenConnections[i].Disconnect();
}
}
}
else
{
for (var i = 0; i <= connectionInfo.OpenConnections.Count - 1; i++)
{
connectionInfo.OpenConnections[i].Disconnect();
}
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("DisconnectConnection (UI.Window.ConnectionTreeWindow) failed", ex);
}
}
private void OnTransferFileClicked(object sender, EventArgs e)
{
var handler = TransferFileClicked;
handler?.Invoke(this, e);
SshTransferFile();
}
public event EventHandler DuplicateClicked;
public void SshTransferFile()
{
try
{
Windows.Show(WindowType.SSHTransfer);
Windows.SshtransferForm.Hostname = _connectionTree.SelectedNode.Hostname;
Windows.SshtransferForm.Username = _connectionTree.SelectedNode.Username;
Windows.SshtransferForm.Password = _connectionTree.SelectedNode.Password;
Windows.SshtransferForm.Port = Convert.ToString(_connectionTree.SelectedNode.Port);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("SSHTransferFile (UI.Window.ConnectionTreeWindow) failed", ex);
}
}
private void OnDuplicateClicked(object sender, EventArgs e)
{
var handler = DuplicateClicked;
handler?.Invoke(this, e);
_connectionTree.DuplicateSelectedNode();
}
public event EventHandler RenameClicked;
private void OnRenameClicked(object sender, EventArgs e)
{
var handler = RenameClicked;
handler?.Invoke(this, e);
_connectionTree.RenameSelectedNode();
}
public event EventHandler DeleteClicked;
private void OnDeleteClicked(object sender, EventArgs e)
{
var handler = DeleteClicked;
handler?.Invoke(this, e);
_connectionTree.DeleteSelectedNode();
}
public event EventHandler ImportFileClicked;
private void OnImportFileClicked(object sender, EventArgs e)
{
var handler = ImportFileClicked;
handler?.Invoke(this, e);
var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo ?? _connectionTree.SelectedNode.Parent;
Import.ImportFromFile(selectedNodeAsContainer);
}
public event EventHandler ImportActiveDirectoryClicked;
private void OnImportActiveDirectoryClicked(object sender, EventArgs e)
{
var handler = ImportActiveDirectoryClicked;
handler?.Invoke(this, e);
Windows.Show(WindowType.ActiveDirectoryImport);
}
public event EventHandler ImportPortScanClicked;
private void OnImportPortScanClicked(object sender, EventArgs e)
{
var handler = ImportPortScanClicked;
handler?.Invoke(this, e);
Windows.Show(WindowType.PortScan);
}
public event EventHandler ExportFileClicked;
private void OnExportFileClicked(object sender, EventArgs e)
{
var handler = ExportFileClicked;
handler?.Invoke(this, e);
Export.ExportToFile(_connectionTree.SelectedNode, Runtime.ConnectionTreeModel);
}
public event EventHandler AddConnectionClicked;
private void OnAddConnectionClicked(object sender, EventArgs e)
{
var handler = AddConnectionClicked;
handler?.Invoke(this, e);
_connectionTree.AddConnection();
Runtime.SaveConnectionsAsync();
}
public event EventHandler AddFolderClicked;
private void OnAddFolderClicked(object sender, EventArgs e)
{
var handler = AddFolderClicked;
handler?.Invoke(this, e);
_connectionTree.AddFolder();
Runtime.SaveConnectionsAsync();
}
public event EventHandler SortAscendingClicked;
private void OnSortAscendingClicked(object sender, EventArgs e)
{
var handler = SortAscendingClicked;
handler?.Invoke(this, e);
SortNodesRecursive(_connectionTree.SelectedNode, ListSortDirection.Ascending);
}
public event EventHandler SortDescendingClicked;
private void OnSortDescendingClicked(object sender, EventArgs e)
{
var handler = SortDescendingClicked;
handler?.Invoke(this, e);
SortNodesRecursive(_connectionTree.SelectedNode, ListSortDirection.Descending);
}
public event EventHandler MoveUpClicked;
private void OnMoveUpClicked(object sender, EventArgs e)
{
var handler = MoveUpClicked;
handler?.Invoke(this, e);
_connectionTree.SelectedNode.Parent.PromoteChild(_connectionTree.SelectedNode);
Runtime.SaveConnectionsAsync();
}
public event EventHandler MoveDownClicked;
private void OnMoveDownClicked(object sender, EventArgs e)
{
var handler = MoveDownClicked;
handler?.Invoke(this, e);
_connectionTree.SelectedNode.Parent.DemoteChild(_connectionTree.SelectedNode);
Runtime.SaveConnectionsAsync();
}
public event EventHandler ExternalToolClicked;
private void OnExternalToolClicked(object sender, EventArgs e)
{
var handler = ExternalToolClicked;
handler?.Invoke(sender, e);
StartExternalApp((ExternalTool)((ToolStripMenuItem)sender).Tag);
}
private void StartExternalApp(ExternalTool externalTool)
{
try
{
if (_connectionTree.SelectedNode.GetTreeNodeType() == TreeNodeType.Connection | _connectionTree.SelectedNode.GetTreeNodeType() == TreeNodeType.PuttySession)
externalTool.Start(_connectionTree.SelectedNode);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("cMenTreeToolsExternalAppsEntry_Click failed (UI.Window.ConnectionTreeWindow)", ex);
}
}
#endregion
private void SortNodesRecursive(ConnectionInfo sortTarget, ListSortDirection sortDirection)
{
if (sortTarget == null)
sortTarget = _connectionTree.GetRootConnectionNode();
var sortTargetAsContainer = sortTarget as ContainerInfo;
if (sortTargetAsContainer != null)
sortTargetAsContainer.SortRecursive(sortDirection);
else
_connectionTree.SelectedNode.Parent.SortRecursive(sortDirection);
Runtime.SaveConnectionsAsync();
}
}
}

View File

@@ -0,0 +1,36 @@
namespace mRemoteNG.UI.Controls
{
partial class ConnectionTree
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@@ -0,0 +1,282 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using BrightIdeasSoftware;
using mRemoteNG.App;
using mRemoteNG.Config.Putty;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
namespace mRemoteNG.UI.Controls
{
public partial class ConnectionTree : TreeListView, IConnectionTree
{
private ConnectionTreeModel _connectionTreeModel;
private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler();
private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance;
public ConnectionInfo SelectedNode => (ConnectionInfo) SelectedObject;
public NodeSearcher NodeSearcher { get; private set; }
public IConfirm NodeDeletionConfirmer { get; set; } = new AlwaysConfirmYes();
public IEnumerable<IConnectionTreeDelegate> PostSetupActions { get; set; } = new IConnectionTreeDelegate[0];
public ITreeNodeClickHandler DoubleClickHandler { get; set; } = new TreeNodeCompositeClickHandler();
public ITreeNodeClickHandler SingleClickHandler { get; set; } = new TreeNodeCompositeClickHandler();
public ConnectionTreeModel ConnectionTreeModel
{
get { return _connectionTreeModel; }
set
{
_connectionTreeModel = value;
PopulateTreeView();
}
}
public ConnectionTree()
{
InitializeComponent();
SetupConnectionTreeView();
}
#region ConnectionTree Setup
private void SetupConnectionTreeView()
{
var imageList = new StatusImageList();
SmallImageList = imageList.GetImageList();
AddColumns(imageList.ImageGetter);
LinkModelToView();
SetupDropSink();
SetEventHandlers();
}
private void AddColumns(ImageGetterDelegate imageGetterDelegate)
{
Columns.Add(new NameColumn(imageGetterDelegate));
}
private void LinkModelToView()
{
CanExpandGetter = item =>
{
var itemAsContainer = item as ContainerInfo;
return itemAsContainer?.Children.Count > 0;
};
ChildrenGetter = item => ((ContainerInfo)item).Children;
}
private void SetupDropSink()
{
DropSink = new SimpleDropSink
{
CanDropBetween = true
};
}
private void SetEventHandlers()
{
Collapsed += (sender, args) =>
{
var container = args.Model as ContainerInfo;
if (container != null)
container.IsExpanded = false;
};
Expanded += (sender, args) =>
{
var container = args.Model as ContainerInfo;
if (container != null)
container.IsExpanded = true;
};
SelectionChanged += tvConnections_AfterSelect;
CellClick += tvConnections_NodeMouseSingleClick;
CellClick += tvConnections_NodeMouseDoubleClick;
CellToolTipShowing += tvConnections_CellToolTipShowing;
ModelCanDrop += _dragAndDropHandler.HandleEvent_ModelCanDrop;
ModelDropped += _dragAndDropHandler.HandleEvent_ModelDropped;
}
private void PopulateTreeView()
{
UnregisterModelUpdateHandlers();
SetObjects(ConnectionTreeModel.RootNodes);
RegisterModelUpdateHandlers();
NodeSearcher = new NodeSearcher(ConnectionTreeModel);
ExecutePostSetupActions();
}
private void RegisterModelUpdateHandlers()
{
_puttySessionsManager.PuttySessionsCollectionChanged += OnPuttySessionsCollectionChanged;
ConnectionTreeModel.CollectionChanged += HandleCollectionChanged;
ConnectionTreeModel.PropertyChanged += HandleCollectionPropertyChanged;
}
private void UnregisterModelUpdateHandlers()
{
_puttySessionsManager.PuttySessionsCollectionChanged -= OnPuttySessionsCollectionChanged;
ConnectionTreeModel.CollectionChanged -= HandleCollectionChanged;
ConnectionTreeModel.PropertyChanged -= HandleCollectionPropertyChanged;
}
private void OnPuttySessionsCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
RefreshObjects(GetRootPuttyNodes().ToList());
}
private void HandleCollectionPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
//TODO for some reason property changed events are getting triggered twice for each changed property. should be just once. cant find source of duplication
var property = propertyChangedEventArgs.PropertyName;
if (property != "Name" && property != "OpenConnections") return;
var senderAsConnectionInfo = sender as ConnectionInfo;
if (senderAsConnectionInfo != null)
RefreshObject(senderAsConnectionInfo);
}
private void ExecutePostSetupActions()
{
foreach (var action in PostSetupActions)
{
action.Execute(this);
}
}
#endregion
#region ConnectionTree Behavior
public RootNodeInfo GetRootConnectionNode()
{
return (RootNodeInfo)Roots.Cast<ConnectionInfo>().First(item => item is RootNodeInfo);
}
public void InvokeExpand(object model)
{
Invoke((MethodInvoker)(() => Expand(model)));
}
public void InvokeRebuildAll(bool preserveState)
{
Invoke((MethodInvoker)(() => RebuildAll(preserveState)));
}
public IEnumerable<RootPuttySessionsNodeInfo> GetRootPuttyNodes()
{
return Objects.OfType<RootPuttySessionsNodeInfo>();
}
public void AddConnection()
{
try
{
AddNode(new ConnectionInfo());
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("UI.Window.Tree.AddConnection() failed.", ex);
}
}
public void AddFolder()
{
try
{
AddNode(new ContainerInfo());
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace(Language.strErrorAddFolderFailed, ex);
}
}
private void AddNode(ConnectionInfo newNode)
{
if (SelectedNode == null) return;
DefaultConnectionInfo.Instance.SaveTo(newNode);
DefaultConnectionInheritance.Instance.SaveTo(newNode.Inheritance);
var selectedContainer = SelectedNode as ContainerInfo;
var parent = selectedContainer ?? SelectedNode?.Parent;
newNode.SetParent(parent);
Expand(parent);
SelectObject(newNode, true);
EnsureModelVisible(newNode);
}
public void DuplicateSelectedNode()
{
var newNode = SelectedNode.Clone();
newNode.Parent.SetChildBelow(newNode, SelectedNode);
Runtime.SaveConnectionsAsync();
}
public void RenameSelectedNode()
{
SelectedItem.BeginEdit();
Runtime.SaveConnectionsAsync();
}
public void DeleteSelectedNode()
{
if (SelectedNode is RootNodeInfo || SelectedNode is PuttySessionInfo) return;
if (!NodeDeletionConfirmer.Confirm()) return;
ConnectionTreeModel.DeleteNode(SelectedNode);
Runtime.SaveConnectionsAsync();
}
private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
RefreshObject(sender);
}
private void tvConnections_AfterSelect(object sender, EventArgs e)
{
try
{
Windows.ConfigForm.SelectedTreeNode = SelectedNode;
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_AfterSelect (UI.Window.ConnectionTreeWindow) failed", ex);
}
}
private void tvConnections_NodeMouseSingleClick(object sender, CellClickEventArgs e)
{
if (e.ClickCount > 1) return;
var clickedNode = e.Model as ConnectionInfo;
if (clickedNode == null) return;
SingleClickHandler.Execute(clickedNode);
}
private void tvConnections_NodeMouseDoubleClick(object sender, CellClickEventArgs e)
{
if (e.ClickCount < 2) return;
var clickedNode = e.Model as ConnectionInfo;
if (clickedNode == null) return;
DoubleClickHandler.Execute(clickedNode);
}
private void tvConnections_CellToolTipShowing(object sender, ToolTipShowingEventArgs e)
{
try
{
var nodeProducingTooltip = (ConnectionInfo)e.Model;
e.Text = nodeProducingTooltip.Description;
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("tvConnections_MouseMove (UI.Window.ConnectionTreeWindow) failed", ex);
}
}
#endregion
}
}

View File

@@ -0,0 +1,25 @@
using System.Collections;
using mRemoteNG.Connection;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
namespace mRemoteNG.UI.Controls
{
public interface IConnectionTree
{
ConnectionTreeModel ConnectionTreeModel { get; set; }
ConnectionInfo SelectedNode { get; }
IEnumerable ExpandedObjects { get; set; }
RootNodeInfo GetRootConnectionNode();
void InvokeExpand(object model);
void InvokeRebuildAll(bool preserveState);
void ToggleExpansion(object model);
}
}

View File

@@ -0,0 +1,8 @@

namespace mRemoteNG.UI.Controls
{
public interface IConnectionTreeDelegate
{
void Execute(IConnectionTree connectionTree);
}
}

View File

@@ -0,0 +1,18 @@
using BrightIdeasSoftware;
using mRemoteNG.Connection;
namespace mRemoteNG.UI.Controls
{
public class NameColumn : OLVColumn
{
public NameColumn(ImageGetterDelegate imageGetterDelegate)
{
AspectName = "Name";
FillsFreeSpace = true;
IsButton = true;
AspectGetter = item => ((ConnectionInfo) item).Name;
ImageGetter = imageGetterDelegate;
}
}
}

View File

@@ -9,7 +9,7 @@ namespace mRemoteNG.UI.Controls
{
public class QuickConnectComboBox : ToolStripComboBox
{
private ComboBox _comboBox;
private readonly ComboBox _comboBox;
private bool _ignoreEnter;
public QuickConnectComboBox()
@@ -53,7 +53,7 @@ namespace mRemoteNG.UI.Controls
// Items can't be removed from the ComboBox while it is dropped down without possibly causing
// an exception so we must close it, delete the item, and then drop it down again. When we
// close it programmatically, the SelectedItem may revert to Nothing, so we must save it first.
object item = _comboBox.SelectedItem;
var item = _comboBox.SelectedItem;
_comboBox.DroppedDown = false;
_comboBox.Items.Remove(item);
_comboBox.SelectedIndex = -1;
@@ -66,29 +66,29 @@ namespace mRemoteNG.UI.Controls
}
}
private void ComboBox_SelectedIndexChanged(Object sender, EventArgs e)
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (!(_comboBox.SelectedItem is HistoryItem))
{
return ;
return;
}
HistoryItem historyItem = (HistoryItem) _comboBox.SelectedItem;
var historyItem = (HistoryItem) _comboBox.SelectedItem;
OnProtocolChanged(new ProtocolChangedEventArgs(historyItem.ConnectionInfo.Protocol));
}
private static void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
{
ComboBox comboBox = sender as ComboBox;
var comboBox = sender as ComboBox;
if (comboBox == null)
{
return ;
return;
}
object drawItem = comboBox.Items[e.Index];
var drawItem = comboBox.Items[e.Index];
string drawString;
if (drawItem is HistoryItem)
{
HistoryItem historyItem = (HistoryItem) drawItem;
var historyItem = (HistoryItem) drawItem;
drawString = historyItem.ToString(true);
}
else
@@ -116,11 +116,8 @@ namespace mRemoteNG.UI.Controls
{
return false;
}
if (ConnectionInfo.Protocol != other.ConnectionInfo.Protocol)
{
return false;
}
return true;
return ConnectionInfo.Protocol == other.ConnectionInfo.Protocol;
}
public override string ToString()
@@ -130,31 +127,25 @@ namespace mRemoteNG.UI.Controls
public string ToString(bool includeProtocol)
{
string port = string.Empty;
var port = string.Empty;
if (ConnectionInfo.Port != ConnectionInfo.GetDefaultPort())
{
port = $":{ConnectionInfo.Port}";
}
if (includeProtocol)
{
return $"{ConnectionInfo.Hostname}{port} ({ConnectionInfo.Protocol})";
}
else
{
return $"{ConnectionInfo.Hostname}{port}";
}
return includeProtocol ? $"{ConnectionInfo.Hostname}{port} ({ConnectionInfo.Protocol})" : $"{ConnectionInfo.Hostname}{port}";
}
}
private bool Exists(HistoryItem searchItem)
{
foreach (object item in _comboBox.Items)
foreach (var item in _comboBox.Items)
{
if (!(item is HistoryItem))
{
continue;
}
HistoryItem historyItem = (HistoryItem) item;
var historyItem = (HistoryItem) item;
if (historyItem.Equals(searchItem))
{
return true;
@@ -167,7 +158,7 @@ namespace mRemoteNG.UI.Controls
{
try
{
HistoryItem historyItem = new HistoryItem {ConnectionInfo = connectionInfo};
var historyItem = new HistoryItem {ConnectionInfo = connectionInfo};
if (!Exists(historyItem))
{
_comboBox.Items.Insert(0, historyItem);
@@ -175,7 +166,7 @@ namespace mRemoteNG.UI.Controls
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(Language.strQuickConnectAddFailed, ex, Messages.MessageClass.ErrorMsg, true);
Runtime.MessageCollector.AddExceptionMessage(Language.strQuickConnectAddFailed, ex);
}
}
@@ -209,7 +200,8 @@ namespace mRemoteNG.UI.Controls
private void OnConnectRequested(ConnectRequestedEventArgs e)
{
ConnectRequestedEvent?.Invoke(this, new ConnectRequestedEventArgs(e.ConnectionString));
// TODO: Any reason to not jsut pass "e"?
ConnectRequestedEvent?.Invoke(this, new ConnectRequestedEventArgs(e.ConnectionString));
}
public class ProtocolChangedEventArgs : EventArgs
@@ -241,6 +233,7 @@ namespace mRemoteNG.UI.Controls
private void OnProtocolChanged(ProtocolChangedEventArgs e)
{
// TODO: Any reason to not jsut pass "e"?
ProtocolChangedEvent?.Invoke(this, new ProtocolChangedEventArgs(e.Protocol));
}
#endregion

View File

@@ -0,0 +1,57 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree.Root;
namespace mRemoteNG.UI.Controls
{
public class StatusImageList
{
public ImageList GetImageList()
{
var imageList = new ImageList
{
ColorDepth = ColorDepth.Depth32Bit,
ImageSize = new Size(16, 16),
TransparentColor = Color.Transparent
};
FillImageList(imageList);
return imageList;
}
public object ImageGetter(object rowObject)
{
if (rowObject is RootPuttySessionsNodeInfo) return "PuttySessions";
if (rowObject is RootNodeInfo) return "Root";
if (rowObject is ContainerInfo) return "Folder";
var connection = rowObject as ConnectionInfo;
if (connection == null) return "";
return connection.OpenConnections.Count > 0 ? "Play" : "Pause";
}
private void FillImageList(ImageList imageList)
{
try
{
imageList.Images.Add(Resources.Root);
imageList.Images.SetKeyName(0, "Root");
imageList.Images.Add(Resources.Folder);
imageList.Images.SetKeyName(1, "Folder");
imageList.Images.Add(Resources.Play);
imageList.Images.SetKeyName(2, "Play");
imageList.Images.Add(Resources.Pause);
imageList.Images.SetKeyName(3, "Pause");
imageList.Images.Add(Resources.PuttySessions);
imageList.Images.SetKeyName(4, "PuttySessions");
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace($"Unable to fill the image list of type {nameof(StatusImageList)}", ex);
}
}
}
}

View File

@@ -22,7 +22,7 @@ namespace mRemoteNG.UI.Controls
{
if (e.CloseReason != ToolStripDropDownCloseReason.AppClicked)
{
return ;
return;
}
Rectangle dropDownButtonBoundsClient = DropDownButtonBounds; // Relative to the ToolStripSplitButton

View File

@@ -205,7 +205,7 @@ namespace mRemoteNG.UI.Forms
SelectFileTypeBasedOnSaveFormat(saveFileDialog);
if (saveFileDialog.ShowDialog(this) != DialogResult.OK)
return ;
return;
txtFileName.Text = saveFileDialog.FileName;
}

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