From da6bbf65f0cb8b60149713c3c763bc508fab7499 Mon Sep 17 00:00:00 2001 From: integratorbit Date: Tue, 21 Mar 2023 14:31:15 -0300 Subject: [PATCH] Improve Disk Drive Redirection --- mRemoteNG/App/Export.cs | 2 +- ...vConnectionsDeserializerMremotengFormat.cs | 8 +- ...CsvConnectionsSerializerMremotengFormat.cs | 8 +- .../MsSql/DataTableDeserializer.cs | 4 +- .../Xml/XmlConnectionNodeSerializer28.cs | 327 ++++++++++++++++++ .../Xml/XmlConnectionsDeserializer.cs | 18 +- .../RemoteDesktopConnectionDeserializer.cs | 2 +- ...oteDesktopConnectionManagerDeserializer.cs | 2 +- .../Versioning/SqlDatabaseVersionVerifier.cs | 1 + .../Versioning/SqlVersion29To30Upgrader.cs | 88 +++++ .../Connection/AbstractConnectionRecord.cs | 17 +- mRemoteNG/Connection/ConnectionInfo.cs | 3 +- .../Connection/ConnectionInfoInheritance.cs | 6 + .../Connection/Protocol/RDP/RDPDiskDrives.cs | 20 ++ .../Connection/Protocol/RDP/RdpProtocol6.cs | 43 ++- mRemoteNG/Language/Language.Designer.cs | 54 +++ mRemoteNG/Language/Language.resx | 18 + mRemoteNG/Properties/Settings.Designer.cs | 23 +- mRemoteNG/Schemas/mremoteng_confcons_v2_8.xsd | 193 +++++++++++ .../ConnectionInfoPropertyGrid.cs | 5 + mRemoteNG/mRemoteNG.csproj | 3 + ...emoteDesktopConnectionDeserializerTests.cs | 2 +- ...topConnectionManager27DeserializerTests.cs | 2 +- ...sktopConnectionManagerDeserializerTests.cs | 2 +- .../AbstractConnectionInfoDataTests.cs | 2 +- 25 files changed, 830 insertions(+), 23 deletions(-) create mode 100644 mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer28.cs create mode 100644 mRemoteNG/Config/Serializers/Versioning/SqlVersion29To30Upgrader.cs create mode 100644 mRemoteNG/Connection/Protocol/RDP/RDPDiskDrives.cs create mode 100644 mRemoteNG/Schemas/mremoteng_confcons_v2_8.xsd diff --git a/mRemoteNG/App/Export.cs b/mRemoteNG/App/Export.cs index ced906c4..ecf935b8 100644 --- a/mRemoteNG/App/Export.cs +++ b/mRemoteNG/App/Export.cs @@ -83,7 +83,7 @@ namespace mRemoteNG.App case SaveFormat.mRXML: var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build(); var rootNode = exportTarget.GetRootParent() as RootNodeInfo; - var connectionNodeSerializer = new XmlConnectionNodeSerializer27( + var connectionNodeSerializer = new XmlConnectionNodeSerializer28( cryptographyProvider, rootNode?.PasswordString .ConvertToSecureString() ?? diff --git a/mRemoteNG/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs b/mRemoteNG/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs index f6fe3bc3..a3a269a2 100644 --- a/mRemoteNG/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs +++ b/mRemoteNG/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs @@ -350,7 +350,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv if (headers.Contains("RedirectDiskDrives")) { - if (bool.TryParse(connectionCsv[headers.IndexOf("RedirectDiskDrives")], out bool value)) + if (Enum.TryParse(connectionCsv[headers.IndexOf("RedirectDiskDrives")], out RDPDiskDrives value)) connectionRecord.RedirectDiskDrives = value; } @@ -611,6 +611,12 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRedirectDiskDrives")], out bool value)) connectionRecord.Inheritance.RedirectDiskDrives = value; } + + if (headers.Contains("InheritRedirectDiskDrivesCustom")) + { + if (bool.TryParse(connectionCsv[headers.IndexOf("InheritRedirectDiskDrivesCustom")], out bool value)) + connectionRecord.Inheritance.RedirectDiskDrivesCustom = value; + } if (headers.Contains("InheritRedirectKeys")) { diff --git a/mRemoteNG/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs b/mRemoteNG/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs index e12341b6..ee56c475 100644 --- a/mRemoteNG/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs +++ b/mRemoteNG/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs @@ -18,7 +18,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv private readonly SaveFilter _saveFilter; private readonly ICredentialRepositoryList _credentialRepositoryList; - public Version Version { get; } = new Version(2, 7); + public Version Version { get; } = new Version(2, 8); public CsvConnectionsSerializerMremotengFormat(SaveFilter saveFilter, ICredentialRepositoryList credentialRepositoryList) @@ -60,7 +60,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv sb.Append("Hostname;Port;VmId;Protocol;SSHTunnelConnectionName;OpeningCommand;SSHOptions;PuttySession;ConnectToConsole;UseCredSsp;UseRestrictedAdmin;UseRCG;UseVmId;UseEnhancedMode;RenderingEngine;RDPAuthenticationLevel;" + "LoadBalanceInfo;Colors;Resolution;AutomaticResize;DisplayWallpaper;DisplayThemes;EnableFontSmoothing;EnableDesktopComposition;DisableFullWindowDrag;DisableMenuAnimations;DisableCursorShadow;DisableCursorBlinking;" + - "CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectClipboard;RedirectSmartCards;RedirectSound;RedirectKeys;" + + "CacheBitmaps;RedirectDiskDrives;RedirectDiskDrivesCustomRedirectPorts;RedirectPrinters;RedirectClipboard;RedirectSmartCards;RedirectSound;RedirectKeys;" + "PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;Favorite;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;" + "VNCProxyPort;VNCProxyUsername;VNCProxyPassword;VNCColors;VNCSmartSizeMode;VNCViewOnly;RDGatewayUsageMethod;RDGatewayHostname;" + "RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;RDGatewayExternalCredentialProvider;RDGatewayUserViaAPI;RedirectAudioCapture;RdpVersion;RDPStartProgram;RDPStartProgramWorkDir;UserViaAPI;EC2InstanceId;EC2Region;ExternalCredentialProvider;ExternalAddressProvider;"); @@ -68,7 +68,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv if (_saveFilter.SaveInheritance) sb.Append("InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;" + "InheritEnableFontSmoothing;InheritEnableDesktopComposition;InheritDisableFullWindowDrag;InheritDisableMenuAnimations;InheritDisableCursorShadow;InheritDisableCursorBlinking;InheritDomain;InheritIcon;InheritPanel;InheritPassword;InheritPort;" + - "InheritProtocol;InheritSSHTunnelConnectionName;InheritOpeningCommand;InheritSSHOptions;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;" + + "InheritProtocol;InheritSSHTunnelConnectionName;InheritOpeningCommand;InheritSSHOptions;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectDiskDrivesCustom;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;" + "InheritRedirectClipboard;InheritRedirectSmartCards;InheritRedirectSound;InheritResolution;InheritAutomaticResize;" + "InheritUseConsoleSession;InheritUseCredSsp;InheritUseRestrictedAdmin;InheritUseRCG;InheritUseVmId;InheritUseEnhancedMode;InheritVmId;InheritRenderingEngine;InheritUsername;" + "InheritRDPAuthenticationLevel;InheritLoadBalanceInfo;InheritPreExtApp;InheritPostExtApp;InheritMacAddress;InheritUserField;" + @@ -147,6 +147,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv .Append(FormatForCsv(con.DisableCursorBlinking)) .Append(FormatForCsv(con.CacheBitmaps)) .Append(FormatForCsv(con.RedirectDiskDrives)) + .Append(FormatForCsv(con.RedirectDiskDrivesCustom)) .Append(FormatForCsv(con.RedirectPorts)) .Append(FormatForCsv(con.RedirectPrinters)) .Append(FormatForCsv(con.RedirectClipboard)) @@ -215,6 +216,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv .Append(FormatForCsv(con.Inheritance.SSHOptions)) .Append(FormatForCsv(con.Inheritance.PuttySession)) .Append(FormatForCsv(con.Inheritance.RedirectDiskDrives)) + .Append(FormatForCsv(con.Inheritance.RedirectDiskDrivesCustom)) .Append(FormatForCsv(con.Inheritance.RedirectKeys)) .Append(FormatForCsv(con.Inheritance.RedirectPorts)) .Append(FormatForCsv(con.Inheritance.RedirectPrinters)) diff --git a/mRemoteNG/Config/Serializers/ConnectionSerializers/MsSql/DataTableDeserializer.cs b/mRemoteNG/Config/Serializers/ConnectionSerializers/MsSql/DataTableDeserializer.cs index b40c210a..5f29a2ef 100644 --- a/mRemoteNG/Config/Serializers/ConnectionSerializers/MsSql/DataTableDeserializer.cs +++ b/mRemoteNG/Config/Serializers/ConnectionSerializers/MsSql/DataTableDeserializer.cs @@ -124,7 +124,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql connectionInfo.DisableCursorShadow = (bool)dataRow["DisableCursorShadow"]; connectionInfo.DisableCursorBlinking = (bool)dataRow["DisableCursorBlinking"]; connectionInfo.CacheBitmaps = (bool)dataRow["CacheBitmaps"]; - connectionInfo.RedirectDiskDrives = (bool)dataRow["RedirectDiskDrives"]; + connectionInfo.RedirectDiskDrives = (RDPDiskDrives)Enum.Parse(typeof(RDPDiskDrives), (string)dataRow["RedirectDiskDrives"]); + connectionInfo.RedirectDiskDrivesCustom = (string)dataRow["RedirectDiskDrivesCustom"]; connectionInfo.RedirectPorts = (bool)dataRow["RedirectPorts"]; connectionInfo.RedirectPrinters = (bool)dataRow["RedirectPrinters"]; connectionInfo.RedirectClipboard = (bool)dataRow["RedirectClipboard"]; @@ -189,6 +190,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql connectionInfo.Inheritance.SSHOptions = (bool)dataRow["InheritSSHOptions"]; connectionInfo.Inheritance.PuttySession = (bool)dataRow["InheritPuttySession"]; connectionInfo.Inheritance.RedirectDiskDrives = (bool)dataRow["InheritRedirectDiskDrives"]; + connectionInfo.Inheritance.RedirectDiskDrivesCustom = (bool)dataRow["InheritRedirectDiskDrivesCustom"]; connectionInfo.Inheritance.RedirectKeys = (bool)dataRow["InheritRedirectKeys"]; connectionInfo.Inheritance.RedirectPorts = (bool)dataRow["InheritRedirectPorts"]; connectionInfo.Inheritance.RedirectPrinters = (bool)dataRow["InheritRedirectPrinters"]; diff --git a/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer28.cs b/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer28.cs new file mode 100644 index 00000000..f073a515 --- /dev/null +++ b/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer28.cs @@ -0,0 +1,327 @@ +using System; +using System.Runtime.Versioning; +using System.Security; +using System.Xml.Linq; +using mRemoteNG.App; +using mRemoteNG.Connection; +using mRemoteNG.Container; +using mRemoteNG.Security; + +namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml +{ + // ReSharper disable once InconsistentNaming + [SupportedOSPlatform("windows")] + public class XmlConnectionNodeSerializer28 : ISerializer + { + private readonly ICryptographyProvider _cryptographyProvider; + private readonly SecureString _encryptionKey; + private readonly SaveFilter _saveFilter; + + public Version Version { get; } = new Version(2, 8); + + public XmlConnectionNodeSerializer28(ICryptographyProvider cryptographyProvider, + SecureString encryptionKey, + SaveFilter saveFilter) + { + if (cryptographyProvider == null) + throw new ArgumentNullException(nameof(cryptographyProvider)); + if (encryptionKey == null) + throw new ArgumentNullException(nameof(encryptionKey)); + if (saveFilter == null) + throw new ArgumentNullException(nameof(saveFilter)); + + _cryptographyProvider = cryptographyProvider; + _encryptionKey = encryptionKey; + _saveFilter = saveFilter; + } + + public XElement Serialize(ConnectionInfo connectionInfo) + { + var element = new XElement(XName.Get("Node", "")); + SetElementAttributes(element, connectionInfo); + SetInheritanceAttributes(element, connectionInfo); + return element; + } + + private void SetElementAttributes(XContainer element, ConnectionInfo connectionInfo) + { + var nodeAsContainer = connectionInfo as ContainerInfo; + element.Add(new XAttribute("Name", connectionInfo.Name)); + element.Add(new XAttribute("VmId", connectionInfo.VmId)); + element.Add(new XAttribute("UseVmId", connectionInfo.UseVmId)); + element.Add(new XAttribute("UseEnhancedMode", connectionInfo.UseVmId)); + element.Add(new XAttribute("Type", connectionInfo.GetTreeNodeType().ToString())); + if (nodeAsContainer != null) + element.Add(new XAttribute("Expanded", nodeAsContainer.IsExpanded.ToString().ToLowerInvariant())); + element.Add(new XAttribute("Descr", connectionInfo.Description)); + element.Add(new XAttribute("Icon", connectionInfo.Icon)); + element.Add(new XAttribute("Panel", connectionInfo.Panel)); + element.Add(new XAttribute("Id", connectionInfo.ConstantID)); + + if (!Runtime.UseCredentialManager) + { + element.Add(_saveFilter.SaveUsername + ? new XAttribute("Username", connectionInfo.Username) + : new XAttribute("Username", "")); + + element.Add(_saveFilter.SaveDomain + ? new XAttribute("Domain", connectionInfo.Domain) + : new XAttribute("Domain", "")); + + if (_saveFilter.SavePassword && !connectionInfo.Inheritance.Password) + element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey))); + else + element.Add(new XAttribute("Password", "")); + } + + element.Add(new XAttribute("Hostname", connectionInfo.Hostname)); + element.Add(new XAttribute("Protocol", connectionInfo.Protocol)); + element.Add(new XAttribute("RdpVersion", connectionInfo.RdpVersion.ToString().ToLowerInvariant())); + element.Add(new XAttribute("SSHTunnelConnectionName", connectionInfo.SSHTunnelConnectionName)); + element.Add(new XAttribute("OpeningCommand", connectionInfo.OpeningCommand)); + element.Add(new XAttribute("SSHOptions", connectionInfo.SSHOptions)); + element.Add(new XAttribute("PuttySession", connectionInfo.PuttySession)); + element.Add(new XAttribute("Port", connectionInfo.Port)); + element.Add(new XAttribute("ConnectToConsole", connectionInfo.UseConsoleSession.ToString().ToLowerInvariant())); + element.Add(new XAttribute("UseCredSsp", connectionInfo.UseCredSsp.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RenderingEngine", connectionInfo.RenderingEngine)); + element.Add(new XAttribute("RDPAuthenticationLevel", connectionInfo.RDPAuthenticationLevel)); + element.Add(new XAttribute("RDPMinutesToIdleTimeout", connectionInfo.RDPMinutesToIdleTimeout)); + element.Add(new XAttribute("RDPAlertIdleTimeout", connectionInfo.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); + element.Add(new XAttribute("LoadBalanceInfo", connectionInfo.LoadBalanceInfo)); + element.Add(new XAttribute("Colors", connectionInfo.Colors)); + element.Add(new XAttribute("Resolution", connectionInfo.Resolution)); + element.Add(new XAttribute("AutomaticResize", connectionInfo.AutomaticResize.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisplayWallpaper", connectionInfo.DisplayWallpaper.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisplayThemes", connectionInfo.DisplayThemes.ToString().ToLowerInvariant())); + element.Add(new XAttribute("EnableFontSmoothing", connectionInfo.EnableFontSmoothing.ToString().ToLowerInvariant())); + element.Add(new XAttribute("EnableDesktopComposition", connectionInfo.EnableDesktopComposition.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisableFullWindowDrag", connectionInfo.DisableFullWindowDrag.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisableMenuAnimations", connectionInfo.DisableMenuAnimations.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisableCursorShadow", connectionInfo.DisableCursorShadow.ToString().ToLowerInvariant())); + element.Add(new XAttribute("DisableCursorBlinking", connectionInfo.DisableCursorBlinking.ToString().ToLowerInvariant())); + element.Add(new XAttribute("CacheBitmaps", connectionInfo.CacheBitmaps.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectDiskDrives", connectionInfo.RedirectDiskDrives)); + element.Add(new XAttribute("RedirectDiskDrivesCustom", connectionInfo.RedirectDiskDrivesCustom)); + element.Add(new XAttribute("RedirectPorts", connectionInfo.RedirectPorts.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectPrinters", connectionInfo.RedirectPrinters.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectClipboard", connectionInfo.RedirectClipboard.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectSmartCards", connectionInfo.RedirectSmartCards.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectSound", connectionInfo.RedirectSound.ToString())); + element.Add(new XAttribute("SoundQuality", connectionInfo.SoundQuality.ToString())); + element.Add(new XAttribute("RedirectAudioCapture", connectionInfo.RedirectAudioCapture.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RedirectKeys", connectionInfo.RedirectKeys.ToString().ToLowerInvariant())); + element.Add(new XAttribute("Connected", (connectionInfo.OpenConnections.Count > 0).ToString().ToLowerInvariant())); + element.Add(new XAttribute("PreExtApp", connectionInfo.PreExtApp)); + element.Add(new XAttribute("PostExtApp", connectionInfo.PostExtApp)); + element.Add(new XAttribute("MacAddress", connectionInfo.MacAddress)); + element.Add(new XAttribute("UserField", connectionInfo.UserField)); + element.Add(new XAttribute("Favorite", connectionInfo.Favorite)); + element.Add(new XAttribute("ExtApp", connectionInfo.ExtApp)); + element.Add(new XAttribute("StartProgram", connectionInfo.RDPStartProgram)); + element.Add(new XAttribute("StartProgramWorkDir", connectionInfo.RDPStartProgramWorkDir)); + element.Add(new XAttribute("VNCCompression", connectionInfo.VNCCompression)); + element.Add(new XAttribute("VNCEncoding", connectionInfo.VNCEncoding)); + element.Add(new XAttribute("VNCAuthMode", connectionInfo.VNCAuthMode)); + element.Add(new XAttribute("VNCProxyType", connectionInfo.VNCProxyType)); + element.Add(new XAttribute("VNCProxyIP", connectionInfo.VNCProxyIP)); + element.Add(new XAttribute("VNCProxyPort", connectionInfo.VNCProxyPort)); + + element.Add(_saveFilter.SaveUsername + ? new XAttribute("VNCProxyUsername", connectionInfo.VNCProxyUsername) + : new XAttribute("VNCProxyUsername", "")); + + element.Add(_saveFilter.SavePassword + ? new XAttribute("VNCProxyPassword", _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey)) + : new XAttribute("VNCProxyPassword", "")); + + element.Add(new XAttribute("VNCColors", connectionInfo.VNCColors)); + element.Add(new XAttribute("VNCSmartSizeMode", connectionInfo.VNCSmartSizeMode)); + element.Add(new XAttribute("VNCViewOnly", connectionInfo.VNCViewOnly.ToString().ToLowerInvariant())); + element.Add(new XAttribute("RDGatewayUsageMethod", connectionInfo.RDGatewayUsageMethod)); + element.Add(new XAttribute("RDGatewayHostname", connectionInfo.RDGatewayHostname)); + element.Add(new XAttribute("RDGatewayUseConnectionCredentials", connectionInfo.RDGatewayUseConnectionCredentials)); + element.Add(new XAttribute("RDGatewayExternalCredentialProvider", connectionInfo.RDGatewayExternalCredentialProvider)); + element.Add(new XAttribute("RDGatewayUserViaAPI", connectionInfo.RDGatewayUserViaAPI)); + + element.Add(_saveFilter.SaveUsername + ? new XAttribute("RDGatewayUsername", connectionInfo.RDGatewayUsername) + : new XAttribute("RDGatewayUsername", "")); + + element.Add(_saveFilter.SavePassword + ? new XAttribute("RDGatewayPassword", _cryptographyProvider.Encrypt(connectionInfo.RDGatewayPassword, _encryptionKey)) + : new XAttribute("RDGatewayPassword", "")); + + element.Add(_saveFilter.SaveDomain + ? new XAttribute("RDGatewayDomain", connectionInfo.RDGatewayDomain) + : new XAttribute("RDGatewayDomain", "")); + + element.Add(new XAttribute("UseRCG", connectionInfo.UseRCG)); + element.Add(new XAttribute("UseRestrictedAdmin", connectionInfo.UseRestrictedAdmin)); + + element.Add(new XAttribute("UserViaAPI", connectionInfo.UserViaAPI)); + element.Add(new XAttribute("EC2InstanceId", connectionInfo.EC2InstanceId)); + element.Add(new XAttribute("EC2Region", connectionInfo.EC2Region)); + element.Add(new XAttribute("ExternalCredentialProvider", connectionInfo.ExternalCredentialProvider)); + element.Add(new XAttribute("ExternalAddressProvider", connectionInfo.ExternalAddressProvider)); + } + + private void SetInheritanceAttributes(XContainer element, IInheritable connectionInfo) + { + if (_saveFilter.SaveInheritance) + { + var inheritance = connectionInfo.Inheritance; + + if (inheritance.CacheBitmaps) + element.Add(new XAttribute("InheritCacheBitmaps", inheritance.CacheBitmaps.ToString().ToLowerInvariant())); + if (inheritance.Colors) + element.Add(new XAttribute("InheritColors", inheritance.Colors.ToString().ToLowerInvariant())); + if (inheritance.Description) + element.Add(new XAttribute("InheritDescription", inheritance.Description.ToString().ToLowerInvariant())); + if (inheritance.DisplayThemes) + element.Add(new XAttribute("InheritDisplayThemes", inheritance.DisplayThemes.ToString().ToLowerInvariant())); + if (inheritance.DisplayWallpaper) + element.Add(new XAttribute("InheritDisplayWallpaper", inheritance.DisplayWallpaper.ToString().ToLowerInvariant())); + if (inheritance.EnableFontSmoothing) + element.Add(new XAttribute("InheritEnableFontSmoothing", inheritance.EnableFontSmoothing.ToString().ToLowerInvariant())); + if (inheritance.EnableDesktopComposition) + element.Add(new XAttribute("InheritEnableDesktopComposition", inheritance.EnableDesktopComposition.ToString().ToLowerInvariant())); + if (inheritance.DisableFullWindowDrag) + element.Add(new XAttribute("InheritDisableFullWindowDrag", inheritance.DisableFullWindowDrag.ToString().ToLowerInvariant())); + if (inheritance.DisableMenuAnimations) + element.Add(new XAttribute("InheritDisableMenuAnimations", inheritance.DisableMenuAnimations.ToString().ToLowerInvariant())); + if (inheritance.DisableCursorShadow) + element.Add(new XAttribute("InheritDisableCursorShadow", inheritance.DisableCursorShadow.ToString().ToLowerInvariant())); + if (inheritance.DisableCursorBlinking) + element.Add(new XAttribute("InheritDisableCursorBlinking", inheritance.DisableCursorBlinking.ToString().ToLowerInvariant())); + if (inheritance.Domain) + element.Add(new XAttribute("InheritDomain", inheritance.Domain.ToString().ToLowerInvariant())); + if (inheritance.Icon) + element.Add(new XAttribute("InheritIcon", inheritance.Icon.ToString().ToLowerInvariant())); + if (inheritance.Panel) + element.Add(new XAttribute("InheritPanel", inheritance.Panel.ToString().ToLowerInvariant())); + if (inheritance.Password) + element.Add(new XAttribute("InheritPassword", inheritance.Password.ToString().ToLowerInvariant())); + if (inheritance.Port) + element.Add(new XAttribute("InheritPort", inheritance.Port.ToString().ToLowerInvariant())); + if (inheritance.Protocol) + element.Add(new XAttribute("InheritProtocol", inheritance.Protocol.ToString().ToLowerInvariant())); + if (inheritance.RdpVersion) + element.Add(new XAttribute("InheritRdpVersion", inheritance.RdpVersion.ToString().ToLowerInvariant())); + if (inheritance.SSHTunnelConnectionName) + element.Add(new XAttribute("InheritSSHTunnelConnectionName", inheritance.SSHTunnelConnectionName.ToString().ToLowerInvariant())); + if (inheritance.OpeningCommand) + element.Add(new XAttribute("InheritOpeningCommand", inheritance.OpeningCommand.ToString().ToLowerInvariant())); + if (inheritance.SSHOptions) + element.Add(new XAttribute("InheritSSHOptions", inheritance.SSHOptions.ToString().ToLowerInvariant())); + if (inheritance.PuttySession) + element.Add(new XAttribute("InheritPuttySession", inheritance.PuttySession.ToString().ToLowerInvariant())); + if (inheritance.RedirectDiskDrives) + element.Add(new XAttribute("InheritRedirectDiskDrives", inheritance.RedirectDiskDrives.ToString().ToLowerInvariant())); + if (inheritance.RedirectDiskDrivesCustom) + element.Add(new XAttribute("InheritRedirectDiskDrivesCustom", inheritance.RedirectDiskDrivesCustom.ToString().ToLowerInvariant())); + if (inheritance.RedirectKeys) + element.Add(new XAttribute("InheritRedirectKeys", inheritance.RedirectKeys.ToString().ToLowerInvariant())); + if (inheritance.RedirectPorts) + element.Add(new XAttribute("InheritRedirectPorts", inheritance.RedirectPorts.ToString().ToLowerInvariant())); + if (inheritance.RedirectPrinters) + element.Add(new XAttribute("InheritRedirectPrinters", inheritance.RedirectPrinters.ToString().ToLowerInvariant())); + if (inheritance.RedirectClipboard) + element.Add(new XAttribute("InheritRedirectClipboard", inheritance.RedirectClipboard.ToString().ToLowerInvariant())); + if (inheritance.RedirectSmartCards) + element.Add(new XAttribute("InheritRedirectSmartCards", inheritance.RedirectSmartCards.ToString().ToLowerInvariant())); + if (inheritance.RedirectSound) + element.Add(new XAttribute("InheritRedirectSound", inheritance.RedirectSound.ToString().ToLowerInvariant())); + if (inheritance.SoundQuality) + element.Add(new XAttribute("InheritSoundQuality", inheritance.SoundQuality.ToString().ToLowerInvariant())); + if (inheritance.RedirectAudioCapture) + element.Add(new XAttribute("InheritRedirectAudioCapture", inheritance.RedirectAudioCapture.ToString().ToLowerInvariant())); + if (inheritance.Resolution) + element.Add(new XAttribute("InheritResolution", inheritance.Resolution.ToString().ToLowerInvariant())); + if (inheritance.AutomaticResize) + element.Add(new XAttribute("InheritAutomaticResize", inheritance.AutomaticResize.ToString().ToLowerInvariant())); + if (inheritance.UseConsoleSession) + element.Add(new XAttribute("InheritUseConsoleSession", inheritance.UseConsoleSession.ToString().ToLowerInvariant())); + if (inheritance.UseCredSsp) + element.Add(new XAttribute("InheritUseCredSsp", inheritance.UseCredSsp.ToString().ToLowerInvariant())); + if (inheritance.RenderingEngine) + element.Add(new XAttribute("InheritRenderingEngine", inheritance.RenderingEngine.ToString().ToLowerInvariant())); + if (inheritance.Username) + element.Add(new XAttribute("InheritUsername", inheritance.Username.ToString().ToLowerInvariant())); + if (inheritance.RDPAuthenticationLevel) + element.Add(new XAttribute("InheritRDPAuthenticationLevel", inheritance.RDPAuthenticationLevel.ToString().ToLowerInvariant())); + if (inheritance.RDPMinutesToIdleTimeout) + element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", inheritance.RDPMinutesToIdleTimeout.ToString().ToLowerInvariant())); + if (inheritance.RDPAlertIdleTimeout) + element.Add(new XAttribute("InheritRDPAlertIdleTimeout", inheritance.RDPAlertIdleTimeout.ToString().ToLowerInvariant())); + if (inheritance.LoadBalanceInfo) + element.Add(new XAttribute("InheritLoadBalanceInfo", inheritance.LoadBalanceInfo.ToString().ToLowerInvariant())); + if (inheritance.PreExtApp) + element.Add(new XAttribute("InheritPreExtApp", inheritance.PreExtApp.ToString().ToLowerInvariant())); + if (inheritance.PostExtApp) + element.Add(new XAttribute("InheritPostExtApp", inheritance.PostExtApp.ToString().ToLowerInvariant())); + if (inheritance.MacAddress) + element.Add(new XAttribute("InheritMacAddress", inheritance.MacAddress.ToString().ToLowerInvariant())); + if (inheritance.UserField) + element.Add(new XAttribute("InheritUserField", inheritance.UserField.ToString().ToLowerInvariant())); + if (inheritance.Favorite) + element.Add(new XAttribute("InheritFavorite", inheritance.Favorite.ToString().ToLowerInvariant())); + if (inheritance.ExtApp) + element.Add(new XAttribute("InheritExtApp", inheritance.ExtApp.ToString().ToLowerInvariant())); + if (inheritance.VNCCompression) + element.Add(new XAttribute("InheritVNCCompression", inheritance.VNCCompression.ToString().ToLowerInvariant())); + if (inheritance.VNCEncoding) + element.Add(new XAttribute("InheritVNCEncoding", inheritance.VNCEncoding.ToString().ToLowerInvariant())); + if (inheritance.VNCAuthMode) + element.Add(new XAttribute("InheritVNCAuthMode", inheritance.VNCAuthMode.ToString().ToLowerInvariant())); + if (inheritance.VNCProxyType) + element.Add(new XAttribute("InheritVNCProxyType", inheritance.VNCProxyType.ToString().ToLowerInvariant())); + if (inheritance.VNCProxyIP) + element.Add(new XAttribute("InheritVNCProxyIP", inheritance.VNCProxyIP.ToString().ToLowerInvariant())); + if (inheritance.VNCProxyPort) + element.Add(new XAttribute("InheritVNCProxyPort", inheritance.VNCProxyPort.ToString().ToLowerInvariant())); + if (inheritance.VNCProxyUsername) + element.Add(new XAttribute("InheritVNCProxyUsername", inheritance.VNCProxyUsername.ToString().ToLowerInvariant())); + if (inheritance.VNCProxyPassword) + element.Add(new XAttribute("InheritVNCProxyPassword", inheritance.VNCProxyPassword.ToString().ToLowerInvariant())); + if (inheritance.VNCColors) + element.Add(new XAttribute("InheritVNCColors", inheritance.VNCColors.ToString().ToLowerInvariant())); + if (inheritance.VNCSmartSizeMode) + element.Add(new XAttribute("InheritVNCSmartSizeMode", inheritance.VNCSmartSizeMode.ToString().ToLowerInvariant())); + if (inheritance.VNCViewOnly) + element.Add(new XAttribute("InheritVNCViewOnly", inheritance.VNCViewOnly.ToString().ToLowerInvariant())); + if (inheritance.RDGatewayUsageMethod) + element.Add(new XAttribute("InheritRDGatewayUsageMethod", inheritance.RDGatewayUsageMethod.ToString().ToLowerInvariant())); + if (inheritance.RDGatewayHostname) + element.Add(new XAttribute("InheritRDGatewayHostname", inheritance.RDGatewayHostname.ToString().ToLowerInvariant())); + if (inheritance.RDGatewayUseConnectionCredentials) + element.Add(new XAttribute("InheritRDGatewayUseConnectionCredentials", inheritance.RDGatewayUseConnectionCredentials.ToString().ToLowerInvariant())); + if (inheritance.RDGatewayUsername) + element.Add(new XAttribute("InheritRDGatewayUsername", inheritance.RDGatewayUsername.ToString().ToLowerInvariant())); + if (inheritance.RDGatewayPassword) + element.Add(new XAttribute("InheritRDGatewayPassword", inheritance.RDGatewayPassword.ToString().ToLowerInvariant())); + if (inheritance.RDGatewayDomain) + element.Add(new XAttribute("InheritRDGatewayDomain", inheritance.RDGatewayDomain.ToString().ToLowerInvariant())); + if (inheritance.RDGatewayExternalCredentialProvider) + element.Add(new XAttribute("InheritRDGatewayExternalCredentialProvider", inheritance.RDGatewayExternalCredentialProvider.ToString().ToLowerInvariant())); + if (inheritance.RDGatewayUserViaAPI) + element.Add(new XAttribute("InheritRDGatewayUserViaAPI", inheritance.RDGatewayUserViaAPI.ToString().ToLowerInvariant())); + + if (inheritance.VmId) + element.Add(new XAttribute("InheritVmId", inheritance.VmId.ToString().ToLowerInvariant())); + if (inheritance.UseVmId) + element.Add(new XAttribute("InheritUseVmId", inheritance.UseVmId.ToString().ToLowerInvariant())); + if (inheritance.UseEnhancedMode) + element.Add(new XAttribute("InheritUseEnhancedMode", inheritance.UseEnhancedMode.ToString().ToLowerInvariant())); + if (inheritance.ExternalCredentialProvider) + element.Add(new XAttribute("InheritExternalCredentialProvider", inheritance.ExternalCredentialProvider.ToString().ToLowerInvariant())); + if (inheritance.UserViaAPI) + element.Add(new XAttribute("InheritUserViaAPI", inheritance.UserViaAPI.ToString().ToLowerInvariant())); + if (inheritance.UseRCG) + element.Add(new XAttribute("InheritUseRCG", inheritance.UseRCG.ToString().ToLowerInvariant())); + if (inheritance.UseRestrictedAdmin) + element.Add(new XAttribute("InheritUseRestrictedAdmin", inheritance.UseRestrictedAdmin.ToString().ToLowerInvariant())); + } + } + } +} \ No newline at end of file diff --git a/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs b/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs index 717364fc..02341604 100644 --- a/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs +++ b/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs @@ -291,14 +291,13 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml if (_confVersion >= 0.5) { - connectionInfo.RedirectDiskDrives = xmlnode.GetAttributeAsBool("RedirectDiskDrives"); connectionInfo.RedirectPrinters = xmlnode.GetAttributeAsBool("RedirectPrinters"); connectionInfo.RedirectPorts = xmlnode.GetAttributeAsBool("RedirectPorts"); connectionInfo.RedirectSmartCards = xmlnode.GetAttributeAsBool("RedirectSmartCards"); } else { - connectionInfo.RedirectDiskDrives = false; + connectionInfo.RedirectDiskDrives = RDPDiskDrives.None; connectionInfo.RedirectPrinters = false; connectionInfo.RedirectPorts = false; connectionInfo.RedirectSmartCards = false; @@ -570,6 +569,21 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml connectionInfo.Inheritance.RDGatewayExternalCredentialProvider = xmlnode.GetAttributeAsBool("InheritRDGatewayExternalCredentialProvider"); connectionInfo.Inheritance.RDGatewayUserViaAPI = xmlnode.GetAttributeAsBool("InheritRDGatewayUserViaAPI"); } + if (_confVersion >= 2.8) + { + connectionInfo.RedirectDiskDrives = xmlnode.GetAttributeAsEnum("RedirectDiskDrives"); + connectionInfo.RedirectDiskDrivesCustom = xmlnode.GetAttributeAsString("RedirectDiskDrivesCustom"); + connectionInfo.Inheritance.RedirectDiskDrivesCustom = xmlnode.GetAttributeAsBool("InheritRedirectDiskDrivesCustom"); + } + else if (_confVersion >= 0.5) + { + // used to be boolean + bool tmpRedirect = xmlnode.GetAttributeAsBool("RedirectDiskDrives"); + if (tmpRedirect) + connectionInfo.RedirectDiskDrives = RDPDiskDrives.Local; + else + connectionInfo.RedirectDiskDrives = RDPDiskDrives.None; + } } catch (Exception ex) { diff --git a/mRemoteNG/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs b/mRemoteNG/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs index 3fbd5e3d..6b05f91b 100644 --- a/mRemoteNG/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs +++ b/mRemoteNG/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs @@ -105,7 +105,7 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers connectionInfo.RedirectSmartCards = value == "1"; break; case "redirectdrives": - connectionInfo.RedirectDiskDrives = value == "1"; + connectionInfo.RedirectDiskDrives = (value == "1" ? RDPDiskDrives.Local : RDPDiskDrives.None); break; case "redirectcomports": connectionInfo.RedirectPorts = value == "1"; diff --git a/mRemoteNG/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs b/mRemoteNG/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs index bc427c1c..45af0013 100644 --- a/mRemoteNG/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs +++ b/mRemoteNG/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs @@ -294,7 +294,7 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers // ./redirectClipboard if (bool.TryParse(localResourcesNode?.SelectSingleNode("./redirectDrives")?.InnerText, out var redirectDisks)) - connectionInfo.RedirectDiskDrives = redirectDisks; + connectionInfo.RedirectDiskDrives = redirectDisks ? RDPDiskDrives.Local : RDPDiskDrives.None; if (bool.TryParse(localResourcesNode?.SelectSingleNode("./redirectPorts")?.InnerText, out var redirectPorts)) connectionInfo.RedirectPorts = redirectPorts; diff --git a/mRemoteNG/Config/Serializers/Versioning/SqlDatabaseVersionVerifier.cs b/mRemoteNG/Config/Serializers/Versioning/SqlDatabaseVersionVerifier.cs index e16a6a4b..085ff27d 100644 --- a/mRemoteNG/Config/Serializers/Versioning/SqlDatabaseVersionVerifier.cs +++ b/mRemoteNG/Config/Serializers/Versioning/SqlDatabaseVersionVerifier.cs @@ -44,6 +44,7 @@ namespace mRemoteNG.Config.Serializers.Versioning new SqlVersion26To27Upgrader(_databaseConnector), new SqlVersion27To28Upgrader(_databaseConnector), new SqlVersion28To29Upgrader(_databaseConnector), + new SqlVersion29To30Upgrader(_databaseConnector), }; foreach (var upgrader in dbUpgraders) diff --git a/mRemoteNG/Config/Serializers/Versioning/SqlVersion29To30Upgrader.cs b/mRemoteNG/Config/Serializers/Versioning/SqlVersion29To30Upgrader.cs new file mode 100644 index 00000000..1606da28 --- /dev/null +++ b/mRemoteNG/Config/Serializers/Versioning/SqlVersion29To30Upgrader.cs @@ -0,0 +1,88 @@ +using mRemoteNG.App; +using mRemoteNG.Config.DatabaseConnectors; +using mRemoteNG.Messages; +using System; +using System.Data.Common; +using System.Runtime.Versioning; + +namespace mRemoteNG.Config.Serializers.Versioning +{ + [SupportedOSPlatform("windows")] + public class SqlVersion29To30Upgrader : IVersionUpgrader + { + private readonly Version version = new Version(3, 0); + private readonly IDatabaseConnector _databaseConnector; + + public SqlVersion29To30Upgrader(IDatabaseConnector databaseConnector) + { + _databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector)); + } + + public bool CanUpgrade(Version currentVersion) + { + return currentVersion == new Version(2, 9) || + // Support upgrading during dev revisions, 2.9.1, 2.9.2, etc... + (currentVersion <= new Version(3, 0) && + currentVersion < version); + } + + public Version Upgrade() + { + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, + $"Upgrading database to version {version}."); + + // MYSQL + const string mySqlAlter = @" +ALTER TABLE tblCons ALTER COLUMN `RedirectDiskDrives` varchar(32) DEFAULT NULL; +ALTER TABLE tblCons ADD COLUMN `RedirectDiskDrivesCustom` varchar(32) DEFAULT NULL; +ALTER TABLE tblCons ADD COLUMN `InheritRedirectDiskDrivesCustom` tinyint(1) NOT NULL; +"; + + const string mySqlUpdate = @"UPDATE tblRoot SET ConfVersion=?;"; + + // MS-SQL + const string msSqlAlter = @" +ALTER TABLE tblCons ALTER COLUMN RedirectDiskDrives varchar(32) DEFAULT NULL; +ALTER TABLE tblCons ADD RedirectDiskDrivesCustom varchar(32) DEFAULT NULL; +ALTER TABLE tblCons ADD InheritRedirectDiskDrivesCustom bit NOT NULL; +"; + + const string msSqlUpdate = @"UPDATE tblRoot SET ConfVersion=@confVersion;"; + + using (var sqlTran = _databaseConnector.DbConnection().BeginTransaction(System.Data.IsolationLevel.Serializable)) + { + DbCommand dbCommand; + if (_databaseConnector.GetType() == typeof(MSSqlDatabaseConnector)) + { + dbCommand = _databaseConnector.DbCommand(msSqlAlter); + dbCommand.Transaction = sqlTran; + dbCommand.ExecuteNonQuery(); + dbCommand = _databaseConnector.DbCommand(msSqlUpdate); + dbCommand.Transaction = sqlTran; + } + else if (_databaseConnector.GetType() == typeof(MySqlDatabaseConnector)) + { + dbCommand = _databaseConnector.DbCommand(mySqlAlter); + dbCommand.Transaction = sqlTran; + dbCommand.ExecuteNonQuery(); + dbCommand = _databaseConnector.DbCommand(mySqlUpdate); + dbCommand.Transaction = sqlTran; + } + else + { + throw new Exception("Unknown database back-end"); + } + var pConfVersion = dbCommand.CreateParameter(); + pConfVersion.ParameterName = "confVersion"; + pConfVersion.Value = version.ToString(); + pConfVersion.DbType = System.Data.DbType.String; + pConfVersion.Direction = System.Data.ParameterDirection.Input; + dbCommand.Parameters.Add(pConfVersion); + + dbCommand.ExecuteNonQuery(); + sqlTran.Commit(); + } + return version; + } + } +} \ No newline at end of file diff --git a/mRemoteNG/Connection/AbstractConnectionRecord.cs b/mRemoteNG/Connection/AbstractConnectionRecord.cs index 30d3234c..3a733539 100644 --- a/mRemoteNG/Connection/AbstractConnectionRecord.cs +++ b/mRemoteNG/Connection/AbstractConnectionRecord.cs @@ -76,7 +76,8 @@ namespace mRemoteNG.Connection private bool _disableCursorBlinking; private bool _redirectKeys; - private bool _redirectDiskDrives; + private RDPDiskDrives _redirectDiskDrives; + private string _redirectDiskDrivesCustom; private bool _redirectPrinters; private bool _redirectClipboard; private bool _redirectPorts; @@ -713,14 +714,24 @@ namespace mRemoteNG.Connection [LocalizedAttributes.LocalizedCategory(nameof(Language.Redirect), 6), LocalizedAttributes.LocalizedDisplayName(nameof(Language.DiskDrives)), LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionRedirectDrives)), - TypeConverter(typeof(MiscTools.YesNoTypeConverter)), + TypeConverter(typeof(MiscTools.EnumTypeConverter)), AttributeUsedInProtocol(ProtocolType.RDP)] - public bool RedirectDiskDrives + public RDPDiskDrives RedirectDiskDrives { get => GetPropertyValue("RedirectDiskDrives", _redirectDiskDrives); set => SetField(ref _redirectDiskDrives, value, "RedirectDiskDrives"); } + [LocalizedAttributes.LocalizedCategory(nameof(Language.Redirect), 6), + LocalizedAttributes.LocalizedDisplayName(nameof(Language.RedirectDiskDrivesCustom)), + LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionRedirectDiskDrivesCustom)), + AttributeUsedInProtocol(ProtocolType.RDP)] + public string RedirectDiskDrivesCustom + { + get => GetPropertyValue("RedirectDiskDrivesCustom", _redirectDiskDrivesCustom); + set => SetField(ref _redirectDiskDrivesCustom, value, "RedirectDiskDrivesCustom"); + } + [LocalizedAttributes.LocalizedCategory(nameof(Language.Redirect), 6), LocalizedAttributes.LocalizedDisplayName(nameof(Language.Printers)), LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionRedirectPrinters)), diff --git a/mRemoteNG/Connection/ConnectionInfo.cs b/mRemoteNG/Connection/ConnectionInfo.cs index 8d09d487..45a81708 100644 --- a/mRemoteNG/Connection/ConnectionInfo.cs +++ b/mRemoteNG/Connection/ConnectionInfo.cs @@ -356,7 +356,8 @@ namespace mRemoteNG.Connection private void SetRedirectDefaults() { RedirectKeys = Settings.Default.ConDefaultRedirectKeys; - RedirectDiskDrives = Settings.Default.ConDefaultRedirectDiskDrives; + RedirectDiskDrives = (RDPDiskDrives)Enum.Parse(typeof(RDPDiskDrives), Settings.Default.ConDefaultRedirectDiskDrives); + RedirectDiskDrivesCustom = Settings.Default.ConDefaultRedirectDiskDrivesCustom; RedirectPrinters = Settings.Default.ConDefaultRedirectPrinters; RedirectClipboard = Settings.Default.ConDefaultRedirectClipboard; RedirectPorts = Settings.Default.ConDefaultRedirectPorts; diff --git a/mRemoteNG/Connection/ConnectionInfoInheritance.cs b/mRemoteNG/Connection/ConnectionInfoInheritance.cs index 0ee451cc..617f28d5 100644 --- a/mRemoteNG/Connection/ConnectionInfoInheritance.cs +++ b/mRemoteNG/Connection/ConnectionInfoInheritance.cs @@ -363,6 +363,12 @@ namespace mRemoteNG.Connection TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool RedirectDiskDrives { get; set; } + [LocalizedAttributes.LocalizedCategory(nameof(Language.Redirect), 7), + LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.RedirectDiskDrivesCustom)), + LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.PropertyDescriptionRedirectDiskDrivesCustom)), + TypeConverter(typeof(MiscTools.YesNoTypeConverter))] + public bool RedirectDiskDrivesCustom { get; set; } + [LocalizedAttributes.LocalizedCategory(nameof(Language.Redirect), 7), LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.Printers)), LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.PropertyDescriptionRedirectPrinters)), diff --git a/mRemoteNG/Connection/Protocol/RDP/RDPDiskDrives.cs b/mRemoteNG/Connection/Protocol/RDP/RDPDiskDrives.cs new file mode 100644 index 00000000..40ae8286 --- /dev/null +++ b/mRemoteNG/Connection/Protocol/RDP/RDPDiskDrives.cs @@ -0,0 +1,20 @@ +using mRemoteNG.Tools; +using mRemoteNG.Resources.Language; + +namespace mRemoteNG.Connection.Protocol.RDP +{ + public enum RDPDiskDrives + { + [LocalizedAttributes.LocalizedDescription(nameof(Language.RdpDrivesNone))] + None, + + [LocalizedAttributes.LocalizedDescription(nameof(Language.RdpDrivesLocal))] + Local, + + [LocalizedAttributes.LocalizedDescription(nameof(Language.RdpDrivesAll))] + All, + + [LocalizedAttributes.LocalizedDescription(nameof(Language.RdpDrivesCustom))] + Custom + } +} \ No newline at end of file diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol6.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol6.cs index 90f8e0cf..103f1cf8 100644 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol6.cs +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol6.cs @@ -18,6 +18,7 @@ using mRemoteNG.Resources.Language; using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; using System.DirectoryServices.ActiveDirectory; using System.Runtime.Versioning; +using System.IO; namespace mRemoteNG.Connection.Protocol.RDP { @@ -643,7 +644,7 @@ namespace mRemoteNG.Connection.Protocol.RDP { try { - _rdpClient.AdvancedSettings2.RedirectDrives = connectionInfo.RedirectDiskDrives; + SetDriveRedirection(); _rdpClient.AdvancedSettings2.RedirectPorts = connectionInfo.RedirectPorts; _rdpClient.AdvancedSettings2.RedirectPrinters = connectionInfo.RedirectPrinters; _rdpClient.AdvancedSettings2.RedirectSmartCards = connectionInfo.RedirectSmartCards; @@ -656,6 +657,46 @@ namespace mRemoteNG.Connection.Protocol.RDP } } + private void SetDriveRedirection() + { + if (RDPDiskDrives.None == connectionInfo.RedirectDiskDrives) + _rdpClient.AdvancedSettings2.RedirectDrives = false; + else if (RDPDiskDrives.All == connectionInfo.RedirectDiskDrives) + _rdpClient.AdvancedSettings2.RedirectDrives = true; + else if (RDPDiskDrives.Custom == connectionInfo.RedirectDiskDrives) + { + var rdpNS5 = (IMsRdpClientNonScriptable5)((AxHost)Control).GetOcx(); + for (uint i = 0; i < rdpNS5.DriveCollection.DriveCount; i++) + { + IMsRdpDrive drive = rdpNS5.DriveCollection.DriveByIndex[i]; + drive.RedirectionState = connectionInfo.RedirectDiskDrivesCustom.Contains(drive.Name.Substring(0, 1)); + } + } + else + { + // Local Drives + var rdpNS5 = (IMsRdpClientNonScriptable5)((AxHost)Control).GetOcx(); + for (uint i = 0; i < rdpNS5.DriveCollection.DriveCount; i++) + { + IMsRdpDrive drive = rdpNS5.DriveCollection.DriveByIndex[i]; + drive.RedirectionState = IsLocal(drive); + } + } + } + + private bool IsLocal(IMsRdpDrive drive) + { + DriveInfo[] myDrives = DriveInfo.GetDrives(); + foreach (DriveInfo myDrive in myDrives) + { + if (myDrive.Name.Substring(0, 1).Equals(drive.Name.Substring(0,1))) + { + return myDrive.DriveType == DriveType.Fixed; + } + } + return false; + } + private void SetPerformanceFlags() { try diff --git a/mRemoteNG/Language/Language.Designer.cs b/mRemoteNG/Language/Language.Designer.cs index 512419a1..8733b2f0 100644 --- a/mRemoteNG/Language/Language.Designer.cs +++ b/mRemoteNG/Language/Language.Designer.cs @@ -4126,6 +4126,15 @@ namespace mRemoteNG.Resources.Language { } /// + /// Looks up a localized string similar to Enter custom drives to redirect: C,D,X. + /// + internal static string PropertyDescriptionRedirectDiskDrivesCustom { + get { + return ResourceManager.GetString("PropertyDescriptionRedirectDiskDrivesCustom", resourceCulture); + } + } + + /// /// Looks up a localized string similar to Select whether local disk drives should be shown on the remote host.. /// internal static string PropertyDescriptionRedirectDrives { @@ -4756,6 +4765,42 @@ namespace mRemoteNG.Resources.Language { } } + /// + /// Looks up a localized string similar to All. + /// + internal static string RdpDrivesAll { + get { + return ResourceManager.GetString("RdpDrivesAll", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom. + /// + internal static string RdpDrivesCustom { + get { + return ResourceManager.GetString("RdpDrivesCustom", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Local. + /// + internal static string RdpDrivesLocal { + get { + return ResourceManager.GetString("RdpDrivesLocal", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to None. + /// + internal static string RdpDrivesNone { + get { + return ResourceManager.GetString("RdpDrivesNone", resourceCulture); + } + } + /// /// Looks up a localized string similar to Internal error code 1.. /// @@ -5179,6 +5224,15 @@ namespace mRemoteNG.Resources.Language { } } + /// + /// Looks up a localized string similar to Custom Drives. + /// + internal static string RedirectDiskDrivesCustom { + get { + return ResourceManager.GetString("RedirectDiskDrivesCustom", resourceCulture); + } + } + /// /// Looks up a localized string similar to Disk Drives. /// diff --git a/mRemoteNG/Language/Language.resx b/mRemoteNG/Language/Language.resx index 55d6dd04..6e9c76e8 100644 --- a/mRemoteNG/Language/Language.resx +++ b/mRemoteNG/Language/Language.resx @@ -2316,4 +2316,22 @@ Nightly Channel includes Alphas, Betas & Release Candidates. Automatically try to reconnect when disconnected from server (RDP && ICA only) + + Enter custom drives to redirect: C,D,X + + + All + + + Custom + + + Local + + + None + + + Custom Drives + \ No newline at end of file diff --git a/mRemoteNG/Properties/Settings.Designer.cs b/mRemoteNG/Properties/Settings.Designer.cs index 272e6d86..2f7241eb 100644 --- a/mRemoteNG/Properties/Settings.Designer.cs +++ b/mRemoteNG/Properties/Settings.Designer.cs @@ -169,16 +169,31 @@ namespace mRemoteNG.Properties { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("False")] - public bool ConDefaultRedirectDiskDrives { + [global::System.Configuration.DefaultSettingValueAttribute("Local")] + public string ConDefaultRedirectDiskDrives { get { - return ((bool)(this["ConDefaultRedirectDiskDrives"])); + return ((string)(this["ConDefaultRedirectDiskDrives"])); } set { this["ConDefaultRedirectDiskDrives"] = value; } } - + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ConDefaultRedirectDiskDrivesCustom + { + get + { + return ((string)(this["ConDefaultRedirectDiskDrivesCustom"])); + } + set + { + this["ConDefaultRedirectDiskDrivesCustom"] = value; + } + } + [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] diff --git a/mRemoteNG/Schemas/mremoteng_confcons_v2_8.xsd b/mRemoteNG/Schemas/mremoteng_confcons_v2_8.xsd new file mode 100644 index 00000000..0b8a9ece --- /dev/null +++ b/mRemoteNG/Schemas/mremoteng_confcons_v2_8.xsd @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mRemoteNG/UI/Controls/ConnectionInfoPropertyGrid/ConnectionInfoPropertyGrid.cs b/mRemoteNG/UI/Controls/ConnectionInfoPropertyGrid/ConnectionInfoPropertyGrid.cs index 0b86819c..3757bf14 100644 --- a/mRemoteNG/UI/Controls/ConnectionInfoPropertyGrid/ConnectionInfoPropertyGrid.cs +++ b/mRemoteNG/UI/Controls/ConnectionInfoPropertyGrid/ConnectionInfoPropertyGrid.cs @@ -290,6 +290,11 @@ namespace mRemoteNG.UI.Controls.ConnectionInfoPropertyGrid strHide.Add(nameof(AbstractConnectionRecord.AutomaticResize)); } + if (SelectedConnectionInfo.RedirectDiskDrives != RDPDiskDrives.Custom) + { + strHide.Add(nameof(AbstractConnectionRecord.RedirectDiskDrivesCustom)); + } + if (SelectedConnectionInfo.RedirectSound != RDPSounds.BringToThisComputer) { strHide.Add(nameof(AbstractConnectionRecord.SoundQuality)); diff --git a/mRemoteNG/mRemoteNG.csproj b/mRemoteNG/mRemoteNG.csproj index 692bf5c6..65eb2648 100644 --- a/mRemoteNG/mRemoteNG.csproj +++ b/mRemoteNG/mRemoteNG.csproj @@ -447,6 +447,9 @@ Always + + Always + Always diff --git a/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializerTests.cs b/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializerTests.cs index f5731a3e..ef62c6e5 100644 --- a/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializerTests.cs +++ b/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializerTests.cs @@ -27,7 +27,7 @@ namespace mRemoteNGTests.Config.Serializers.MiscSerializers private const bool ExpectedFontSmoothing = true; private const bool ExpectedDesktopComposition = true; private const bool ExpectedSmartcardRedirection = true; - private const bool ExpectedDriveRedirection = true; + private const RDPDiskDrives ExpectedDriveRedirection = RDPDiskDrives.Local; private const bool ExpectedPortRedirection = true; private const bool ExpectedPrinterRedirection = true; private const RDPSounds ExpectedSoundRedirection = RDPSounds.BringToThisComputer; diff --git a/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManager27DeserializerTests.cs b/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManager27DeserializerTests.cs index 62b1ff97..d532df98 100644 --- a/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManager27DeserializerTests.cs +++ b/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManager27DeserializerTests.cs @@ -35,7 +35,7 @@ namespace mRemoteNGTests.Config.Serializers.MiscSerializers private const RDPSounds ExpectedAudioRedirection = RDPSounds.DoNotPlay; private const bool ExpectedKeyRedirection = true; private const bool ExpectedSmartcardRedirection = true; - private const bool ExpectedDriveRedirection = true; + private const RDPDiskDrives ExpectedDriveRedirection = RDPDiskDrives.Local; private const bool ExpectedPortRedirection = true; private const bool ExpectedPrinterRedirection = true; private const AuthenticationLevel ExpectedAuthLevel = AuthenticationLevel.WarnOnFailedAuth; diff --git a/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializerTests.cs b/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializerTests.cs index dd2362f6..7cdb07d5 100644 --- a/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializerTests.cs +++ b/mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializerTests.cs @@ -33,7 +33,7 @@ namespace mRemoteNGTests.Config.Serializers.MiscSerializers private const RDPSounds ExpectedAudioRedirection = RDPSounds.DoNotPlay; private const bool ExpectedKeyRedirection = true; private const bool ExpectedSmartcardRedirection = true; - private const bool ExpectedDriveRedirection = true; + private const RDPDiskDrives ExpectedDriveRedirection = RDPDiskDrives.Local; private const bool ExpectedPortRedirection = true; private const bool ExpectedPrinterRedirection = true; private const AuthenticationLevel ExpectedAuthLevel = AuthenticationLevel.AuthRequired; diff --git a/mRemoteNGTests/Connection/AbstractConnectionInfoDataTests.cs b/mRemoteNGTests/Connection/AbstractConnectionInfoDataTests.cs index 7c816cce..29c5850f 100644 --- a/mRemoteNGTests/Connection/AbstractConnectionInfoDataTests.cs +++ b/mRemoteNGTests/Connection/AbstractConnectionInfoDataTests.cs @@ -344,7 +344,7 @@ namespace mRemoteNGTests.Connection { var wasCalled = false; _testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true; - _testAbstractConnectionInfoData.RedirectDiskDrives = true; + _testAbstractConnectionInfoData.RedirectDiskDrives = RDPDiskDrives.Local; Assert.That(wasCalled, Is.True); }