Martin Prikryl 12 years ago
parent
commit
2908ab65ca
70 changed files with 1293 additions and 399 deletions
  1. 2 2
      build.bat
  2. 3 3
      deployment/winscpsetup.iss
  3. 4 0
      dotnet/GlobalSuppressions.cs
  4. 14 26
      dotnet/Session.cs
  5. 1 1
      dotnet/WinSCPnet.csproj
  6. 1 1
      dotnet/internal/ConsoleCommStruct.cs
  7. 34 13
      dotnet/internal/ExeSessionProcess.cs
  8. 1 0
      dotnet/internal/SessionLogReader.cs
  9. 28 2
      dotnet/internal/UnsafeNativeMethods.cs
  10. 3 3
      dotnet/properties/AssemblyInfo.cs
  11. 1 1
      source/Console.cbproj
  12. 1 1
      source/DragExt.cbproj
  13. 2 2
      source/DragExt64.rc
  14. 2 1
      source/WinSCP.cbproj
  15. 1 1
      source/components/UnixDirView.cpp
  16. 11 0
      source/core/Common.cpp
  17. 5 3
      source/core/Common.h
  18. 14 9
      source/core/Configuration.cpp
  19. 1 0
      source/core/Configuration.h
  20. 1 0
      source/core/CoreMain.cpp
  21. 13 1
      source/core/FtpFileSystem.cpp
  22. 4 0
      source/core/Interface.h
  23. 1 1
      source/core/PuttyIntf.cpp
  24. 35 27
      source/core/ScpFileSystem.cpp
  25. 6 0
      source/core/ScpFileSystem.h
  26. 12 3
      source/core/SecureShell.cpp
  27. 2 0
      source/core/SecureShell.h
  28. 57 27
      source/core/SessionData.cpp
  29. 8 7
      source/core/SessionData.h
  30. 10 6
      source/core/SessionInfo.cpp
  31. 17 3
      source/core/SftpFileSystem.cpp
  32. 112 16
      source/core/Terminal.cpp
  33. 6 2
      source/core/Terminal.h
  34. 1 2
      source/filezilla/FileZillaIntf.cpp
  35. 2 2
      source/filezilla/FtpControlSocket.cpp
  36. 2 1
      source/filezilla/FtpListResult.cpp
  37. 24 5
      source/forms/Authenticate.cpp
  38. 28 9
      source/forms/Authenticate.dfm
  39. 2 0
      source/forms/Authenticate.h
  40. 11 11
      source/forms/CopyParams.dfm
  41. 22 9
      source/forms/CustomScpExplorer.cpp
  42. 1 0
      source/forms/CustomScpExplorer.dfm
  43. 4 1
      source/forms/FileFind.cpp
  44. 1 1
      source/forms/ImportSessions.cpp
  45. 25 25
      source/forms/LocationProfiles.dfm
  46. 8 2
      source/forms/Login.cpp
  47. 11 8
      source/forms/Login.dfm
  48. 1 1
      source/forms/Login.h
  49. 294 40
      source/forms/MessageDlg.cpp
  50. 4 2
      source/forms/Preferences.cpp
  51. 22 13
      source/forms/Preferences.dfm
  52. 2 1
      source/forms/Preferences.h
  53. 10 5
      source/forms/SynchronizeChecklist.cpp
  54. 19 8
      source/packages/my/NortonLikeListView.pas
  55. 247 13
      source/packages/my/PathLabel.pas
  56. 3 3
      source/resource/TextsCore.h
  57. 4 4
      source/resource/TextsCore1.rc
  58. 2 0
      source/resource/TextsWin.h
  59. 2 0
      source/resource/TextsWin1.rc
  60. 2 1
      source/windows/ConsoleRunner.cpp
  61. 8 14
      source/windows/GUIConfiguration.cpp
  62. 2 3
      source/windows/GUIConfiguration.h
  63. 4 4
      source/windows/GUITools.cpp
  64. 27 8
      source/windows/TerminalManager.cpp
  65. 2 0
      source/windows/TerminalManager.h
  66. 31 24
      source/windows/Tools.cpp
  67. 1 1
      source/windows/UserInterface.cpp
  68. 22 4
      source/windows/VCLCommon.cpp
  69. 9 9
      source/windows/WinConfiguration.cpp
  70. 20 3
      source/windows/WinInterface.cpp

+ 2 - 2
build.bat

@@ -1,6 +1,6 @@
 @echo off
 @echo off
 rem See 'readme' file
 rem See 'readme' file
-set BDS=c:\program files\Embarcadero\RAD Studio\9.0
+set BDS=%ProgramFiles%\Embarcadero\RAD Studio\9.0
 set WITH_DRAGEXT64=0
 set WITH_DRAGEXT64=0
 rem set DRAGEXT64CL=<path to x64 cl.exe>
 rem set DRAGEXT64CL=<path to x64 cl.exe>
 rem set DRAGEXT64INCL=<path to x64 includes>
 rem set DRAGEXT64INCL=<path to x64 includes>
@@ -12,4 +12,4 @@ cd libs
 call buildlibs.bat
 call buildlibs.bat
 
 
 cd ..\source
 cd ..\source
-C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe WinSCP.groupproj /t:clean,%BUILD_TARGET% /p:RELEASE_TYPE=%RELEASE_TYPE%;CONFIG=%BUILD_CONFIG%;INTERM_PATH=.;FINAL_PATH=.
+C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe WinSCP.groupproj /t:%BUILD_TARGET% /p:RELEASE_TYPE=%RELEASE_TYPE%;CONFIG=%BUILD_CONFIG%;INTERM_PATH=.;FINAL_PATH=.

+ 3 - 3
deployment/winscpsetup.iss

@@ -114,6 +114,7 @@ WizardSmallImageFile=compiler:WizModernSmallImage-IS.bmp
 ShowTasksTreeLines=yes
 ShowTasksTreeLines=yes
 PrivilegesRequired=none
 PrivilegesRequired=none
 UsePreviousLanguage=yes
 UsePreviousLanguage=yes
+DisableProgramGroupPage=yes
 MinVersion=0,5.1
 MinVersion=0,5.1
 #ifdef Sign
 #ifdef Sign
 SignTool=sign $f "WinSCP Installer" http://winscp.net/eng/docs/installation
 SignTool=sign $f "WinSCP Installer" http://winscp.net/eng/docs/installation
@@ -1467,10 +1468,9 @@ begin
     { Hide most pages during typical installation }
     { Hide most pages during typical installation }
     (TypicalTypeButton.Checked and
     (TypicalTypeButton.Checked and
      ((PageID = wpSelectDir) or (PageID = wpSelectComponents) or
      ((PageID = wpSelectDir) or (PageID = wpSelectComponents) or
-      (PageID = wpSelectProgramGroup) or (PageID = wpSelectTasks) or
+      (PageID = wpSelectTasks) or
       { Hide Interface page for upgrades only, show for fresh installs }
       { Hide Interface page for upgrades only, show for fresh installs }
-      ((PageID = wpInterface) and Upgrade))) or
-    (IsWin8 and (PageID = wpSelectProgramGroup));
+      ((PageID = wpInterface) and Upgrade)));
 end;
 end;
 
 
 function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo,
 function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo,

+ 4 - 0
dotnet/GlobalSuppressions.cs

@@ -139,3 +139,7 @@ using System.Diagnostics.CodeAnalysis;
 [assembly: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "WinSCP.Logger.#GetProcessStartTime(System.Diagnostics.Process)")]
 [assembly: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "WinSCP.Logger.#GetProcessStartTime(System.Diagnostics.Process)")]
 [assembly: SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "WinSCP.Logger.#GetTotalProcessorTime(System.Diagnostics.Process)")]
 [assembly: SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "WinSCP.Logger.#GetTotalProcessorTime(System.Diagnostics.Process)")]
 [assembly: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "WinSCP.Logger.#GetTotalProcessorTime(System.Diagnostics.Process)")]
 [assembly: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "WinSCP.Logger.#GetTotalProcessorTime(System.Diagnostics.Process)")]
+[assembly: SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Scope = "type", Target = "WinSCP.FileMapAccess")]
+[assembly: SuppressMessage("Microsoft.Security", "CA5122:PInvokesShouldNotBeSafeCriticalFxCopRule", Scope = "member", Target = "WinSCP.UnsafeNativeMethods.#CreateFileMapping(Microsoft.Win32.SafeHandles.SafeFileHandle,System.IntPtr,WinSCP.FileMapProtection,System.Int32,System.Int32,System.String)")]
+[assembly: SuppressMessage("Microsoft.Security", "CA5122:PInvokesShouldNotBeSafeCriticalFxCopRule", Scope = "member", Target = "WinSCP.UnsafeNativeMethods.#MapViewOfFile(Microsoft.Win32.SafeHandles.SafeFileHandle,WinSCP.FileMapAccess,System.UInt32,System.UInt32,System.UIntPtr)")]
+[assembly: SuppressMessage("Microsoft.Interoperability", "CA1404:CallGetLastErrorImmediatelyAfterPInvoke", Scope = "member", Target = "WinSCP.ExeSessionProcess.#InitializeConsole()")]

+ 14 - 26
dotnet/Session.cs

@@ -51,6 +51,7 @@ namespace WinSCP
         public string DebugLogPath { get { CheckNotDisposed(); return Logger.LogPath; } set { CheckNotDisposed(); Logger.LogPath = value; } }
         public string DebugLogPath { get { CheckNotDisposed(); return Logger.LogPath; } set { CheckNotDisposed(); Logger.LogPath = value; } }
         public string SessionLogPath { get { return _sessionLogPath; } set { CheckNotOpened(); _sessionLogPath = value; } }
         public string SessionLogPath { get { return _sessionLogPath; } set { CheckNotOpened(); _sessionLogPath = value; } }
         public string XmlLogPath { get { return _xmlLogPath; } set { CheckNotOpened(); _xmlLogPath = value; } }
         public string XmlLogPath { get { return _xmlLogPath; } set { CheckNotOpened(); _xmlLogPath = value; } }
+        public bool GuardProcessWithJob { get { return _guardProcessWithJob; } set { CheckNotOpened(); _guardProcessWithJob = value; } }
 
 
         public TimeSpan Timeout { get; set; }
         public TimeSpan Timeout { get; set; }
 
 
@@ -97,14 +98,7 @@ namespace WinSCP
                 _disposed = false;
                 _disposed = false;
                 _defaultConfiguration = true;
                 _defaultConfiguration = true;
                 _logUnique = 0;
                 _logUnique = 0;
-            }
-        }
-
-        ~Session()
-        {
-            using (Logger.CreateCallstack())
-            {
-                DoDispose();
+                _guardProcessWithJob = true;
             }
             }
         }
         }
 
 
@@ -112,7 +106,17 @@ namespace WinSCP
         {
         {
             using (Logger.CreateCallstackAndLock())
             using (Logger.CreateCallstackAndLock())
             {
             {
-                DoDispose();
+                _disposed = true;
+
+                Cleanup();
+                Logger.Dispose();
+
+                if (_eventsEvent != null)
+                {
+                    _eventsEvent.Close();
+                    _eventsEvent = null;
+                }
+
                 GC.SuppressFinalize(this);
                 GC.SuppressFinalize(this);
             }
             }
         }
         }
@@ -733,23 +737,6 @@ namespace WinSCP
             return path;
             return path;
         }
         }
 
 
-        private void DoDispose()
-        {
-            using (Logger.CreateCallstack())
-            {
-                _disposed = true;
-
-                Cleanup();
-                Logger.Dispose();
-
-                if (_eventsEvent != null)
-                {
-                    _eventsEvent.Close();
-                    _eventsEvent = null;
-                }
-            }
-        }
-
         private void Cleanup()
         private void Cleanup()
         {
         {
             using (Logger.CreateCallstack())
             using (Logger.CreateCallstack())
@@ -1468,5 +1455,6 @@ namespace WinSCP
         private string _xmlLogPath;
         private string _xmlLogPath;
         private FileTransferProgressEventHandler _fileTransferProgress;
         private FileTransferProgressEventHandler _fileTransferProgress;
         private int _progressHandling;
         private int _progressHandling;
+        private bool _guardProcessWithJob;
     }
     }
 }
 }

+ 1 - 1
dotnet/WinSCPnet.csproj

@@ -9,7 +9,7 @@
     <OutputType>Library</OutputType>
     <OutputType>Library</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <RootNamespace>WinSCP</RootNamespace>
     <RootNamespace>WinSCP</RootNamespace>
-    <AssemblyName>WinSCP</AssemblyName>
+    <AssemblyName>WinSCPnet</AssemblyName>
     <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
     <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
     <FileAlignment>512</FileAlignment>
     <OutputPath>$(FINAL_PATH)\$(Configuration)</OutputPath>
     <OutputPath>$(FINAL_PATH)\$(Configuration)</OutputPath>

+ 1 - 1
dotnet/internal/ConsoleCommStruct.cs

@@ -95,7 +95,7 @@ namespace WinSCP
         {
         {
             _session = session;
             _session = session;
             _fileMapping = fileMapping;
             _fileMapping = fileMapping;
-            _ptr = UnsafeNativeMethods.MapViewOfFile(_fileMapping, 0x1F /*FILE_MAP_ALL_ACCESS*/, 0, 0, UIntPtr.Zero);
+            _ptr = UnsafeNativeMethods.MapViewOfFile(_fileMapping, FileMapAccess.FileMapAllAccess, 0, 0, UIntPtr.Zero);
             _payloadPtr = new IntPtr(_ptr.ToInt64() + 12);
             _payloadPtr = new IntPtr(_ptr.ToInt64() + 12);
             _header = (ConsoleCommHeader)Marshal.PtrToStructure(_ptr, typeof(ConsoleCommHeader));
             _header = (ConsoleCommHeader)Marshal.PtrToStructure(_ptr, typeof(ConsoleCommHeader));
         }
         }

+ 34 - 13
dotnet/internal/ExeSessionProcess.cs

@@ -6,6 +6,7 @@ using System.IO;
 using System.Threading;
 using System.Threading;
 using Microsoft.Win32;
 using Microsoft.Win32;
 using Microsoft.Win32.SafeHandles;
 using Microsoft.Win32.SafeHandles;
+using System.Runtime.InteropServices;
 
 
 namespace WinSCP
 namespace WinSCP
 {
 {
@@ -127,7 +128,11 @@ namespace WinSCP
 
 
                 _logger.WriteLine("Started process {0}", _process.Id);
                 _logger.WriteLine("Started process {0}", _process.Id);
 
 
-                _job.AddProcess(_process.Handle);
+                if (_session.GuardProcessWithJob)
+                {
+                    _job = new Job();
+                    _job.AddProcess(_process.Handle);
+                }
 
 
                 _thread = new Thread(ProcessEvents);
                 _thread = new Thread(ProcessEvents);
                 _thread.IsBackground = true;
                 _thread.IsBackground = true;
@@ -375,8 +380,6 @@ namespace WinSCP
                 Random random = new Random();
                 Random random = new Random();
                 int process = Process.GetCurrentProcess().Id;
                 int process = Process.GetCurrentProcess().Id;
 
 
-                bool uniqEvent;
-
                 do
                 do
                 {
                 {
                     if (attempts > MaxAttempts)
                     if (attempts > MaxAttempts)
@@ -387,20 +390,24 @@ namespace WinSCP
                     int instanceNumber = random.Next(1000);
                     int instanceNumber = random.Next(1000);
 
 
                     _instanceName = string.Format(CultureInfo.InvariantCulture, "_{0}_{1}", process, instanceNumber);
                     _instanceName = string.Format(CultureInfo.InvariantCulture, "_{0}_{1}", process, instanceNumber);
-                    _requestEvent = new EventWaitHandle(false, EventResetMode.AutoReset, ConsoleEventRequest + _instanceName, out uniqEvent);
-                    if (!uniqEvent)
+                    _logger.WriteLine("Trying event {0}", _instanceName);
+                    if (!TryCreateEvent(ConsoleEventRequest + _instanceName, out _requestEvent))
                     {
                     {
+                        _logger.WriteLine("Event {0} is not unique", _instanceName);
                         _requestEvent.Close();
                         _requestEvent.Close();
                         _requestEvent = null;
                         _requestEvent = null;
                     }
                     }
                     else
                     else
                     {
                     {
+                        _logger.WriteLine("Event {0} is unique", _instanceName);
                         _responseEvent = CreateEvent(ConsoleEventResponse + _instanceName);
                         _responseEvent = CreateEvent(ConsoleEventResponse + _instanceName);
                         _cancelEvent = CreateEvent(ConsoleEventCancel + _instanceName);
                         _cancelEvent = CreateEvent(ConsoleEventCancel + _instanceName);
                         string fileMappingName = ConsoleMapping + _instanceName;
                         string fileMappingName = ConsoleMapping + _instanceName;
-                        _fileMapping = UnsafeNativeMethods.CreateFileMapping(
-                            new SafeFileHandle(new IntPtr(-1), true), IntPtr.Zero, 0x04 /*readwrite*/, 0,
-                            ConsoleCommStruct.Size, fileMappingName);
+                        _fileMapping = CreateFileMapping(fileMappingName);
+                        if (Marshal.GetLastWin32Error() == UnsafeNativeMethods.ERROR_ALREADY_EXISTS)
+                        {
+                            throw new SessionLocalException(_session, string.Format(CultureInfo.InvariantCulture, "File mapping {0} already exists", fileMappingName));
+                        }
                         if (_fileMapping.IsInvalid)
                         if (_fileMapping.IsInvalid)
                         {
                         {
                             throw new SessionLocalException(_session, string.Format(CultureInfo.InvariantCulture, "Cannot create file mapping {0}", fileMappingName));
                             throw new SessionLocalException(_session, string.Format(CultureInfo.InvariantCulture, "Cannot create file mapping {0}", fileMappingName));
@@ -408,7 +415,7 @@ namespace WinSCP
                     }
                     }
                     ++attempts;
                     ++attempts;
                 }
                 }
-                while (!uniqEvent);
+                while (_requestEvent == null);
 
 
                 using (ConsoleCommStruct commStruct = AcquireCommStruct())
                 using (ConsoleCommStruct commStruct = AcquireCommStruct())
                 {
                 {
@@ -417,16 +424,30 @@ namespace WinSCP
             }
             }
         }
         }
 
 
+        private static SafeFileHandle CreateFileMapping(string fileMappingName)
+        {
+            return
+                UnsafeNativeMethods.CreateFileMapping(
+                    new SafeFileHandle(new IntPtr(-1), true), IntPtr.Zero, FileMapProtection.PageReadWrite, 0,
+                    ConsoleCommStruct.Size, fileMappingName);
+        }
+
         private ConsoleCommStruct AcquireCommStruct()
         private ConsoleCommStruct AcquireCommStruct()
         {
         {
             return new ConsoleCommStruct(_session, _fileMapping);
             return new ConsoleCommStruct(_session, _fileMapping);
         }
         }
 
 
-        private EventWaitHandle CreateEvent(string name)
+        private static bool TryCreateEvent(string name, out EventWaitHandle ev)
         {
         {
             bool createdNew;
             bool createdNew;
-            EventWaitHandle ev = new EventWaitHandle(false, EventResetMode.AutoReset, name, out createdNew);
-            if (!createdNew)
+            ev = new EventWaitHandle(false, EventResetMode.AutoReset, name, out createdNew);
+            return createdNew;
+        }
+
+        private EventWaitHandle CreateEvent(string name)
+        {
+            EventWaitHandle ev;
+            if (!TryCreateEvent(name, out ev))
             {
             {
                 throw new SessionLocalException(_session, string.Format(CultureInfo.InvariantCulture, "Event {0} already exists", name));
                 throw new SessionLocalException(_session, string.Format(CultureInfo.InvariantCulture, "Event {0} already exists", name));
             }
             }
@@ -637,6 +658,6 @@ namespace WinSCP
         private string _incompleteLine;
         private string _incompleteLine;
         private readonly List<string> _input = new List<string>();
         private readonly List<string> _input = new List<string>();
         private AutoResetEvent _inputEvent = new AutoResetEvent(false);
         private AutoResetEvent _inputEvent = new AutoResetEvent(false);
-        private Job _job = new Job();
+        private Job _job;
     }
     }
 }
 }

+ 1 - 0
dotnet/internal/SessionLogReader.cs

@@ -32,6 +32,7 @@ namespace WinSCP
                 _stream = null;
                 _stream = null;
             }
             }
 
 
+            ((IDisposable)_reader).Dispose();
             _reader = null;
             _reader = null;
         }
         }
 
 

+ 28 - 2
dotnet/internal/UnsafeNativeMethods.cs

@@ -59,13 +59,39 @@ namespace WinSCP
         public UInt32 PeakJobMemoryUsed;
         public UInt32 PeakJobMemoryUsed;
     }
     }
 
 
+    [Flags]
+    internal enum FileMapProtection : uint
+    {
+        PageReadonly = 0x02,
+        PageReadWrite = 0x04,
+        PageWriteCopy = 0x08,
+        PageExecuteRead = 0x20,
+        PageExecuteReadWrite = 0x40,
+        SectionCommit = 0x8000000,
+        SectionImage = 0x1000000,
+        SectionNoCache = 0x10000000,
+        SectionReserve = 0x4000000,
+    }
+
+    [Flags]
+    public enum FileMapAccess : int
+    {
+        FileMapCopy = 0x0001,
+        FileMapWrite = 0x0002,
+        FileMapRead = 0x0004,
+        FileMapAllAccess = 0x001f,
+        FileMapExecute = 0x0020,
+    }
+    
     internal static class UnsafeNativeMethods
     internal static class UnsafeNativeMethods
     {
     {
+        public const int ERROR_ALREADY_EXISTS = 183;
+        
         [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
         [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
-        public static extern SafeFileHandle CreateFileMapping(SafeFileHandle hFile, IntPtr lpAttributes, int fProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, string lpName);
+        public static extern SafeFileHandle CreateFileMapping(SafeFileHandle hFile, IntPtr lpAttributes, FileMapProtection fProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, string lpName);
 
 
         [DllImport("kernel32", SetLastError = true, ExactSpelling = true)]
         [DllImport("kernel32", SetLastError = true, ExactSpelling = true)]
-        public static extern IntPtr MapViewOfFile(SafeFileHandle handle, int dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumberOfBytesToMap);
+        public static extern IntPtr MapViewOfFile(SafeFileHandle handle, FileMapAccess dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumberOfBytesToMap);
 
 
         [DllImport("kernel32", ExactSpelling = true)]
         [DllImport("kernel32", ExactSpelling = true)]
         [return: MarshalAs(UnmanagedType.Bool)]
         [return: MarshalAs(UnmanagedType.Bool)]

+ 3 - 3
dotnet/properties/AssemblyInfo.cs

@@ -19,9 +19,9 @@ using System.Runtime.InteropServices;
 // The following GUID is for the ID of the typelib if this project is exposed to COM
 // The following GUID is for the ID of the typelib if this project is exposed to COM
 [assembly: Guid("a0b93468-d98a-4845-a234-8076229ad93f")]
 [assembly: Guid("a0b93468-d98a-4845-a234-8076229ad93f")]
 
 
-[assembly: AssemblyVersion("1.1.0.0")]
-[assembly: AssemblyFileVersion("1.1.0.0")]
-[assembly: AssemblyInformationalVersionAttribute("5.2.0.0")]
+[assembly: AssemblyVersion("1.1.1.0")]
+[assembly: AssemblyFileVersion("1.1.1.0")]
+[assembly: AssemblyInformationalVersionAttribute("5.2.1.0")]
 
 
 [assembly: CLSCompliant(true)]
 [assembly: CLSCompliant(true)]
 
 

+ 1 - 1
source/Console.cbproj

@@ -41,7 +41,7 @@
 			<PackageImports>rtl.bpi;$(PackageImports)</PackageImports>
 			<PackageImports>rtl.bpi;$(PackageImports)</PackageImports>
 			<ProjectType>CppConsoleApplication</ProjectType>
 			<ProjectType>CppConsoleApplication</ProjectType>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.0.0.0;InternalName=console;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.2.0.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.0.0.0;InternalName=console;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.2.1.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>4</VerInfo_MajorVer>
 			<VerInfo_MajorVer>4</VerInfo_MajorVer>
 		</PropertyGroup>
 		</PropertyGroup>

+ 1 - 1
source/DragExt.cbproj

@@ -42,7 +42,7 @@
 			<ProjectType>CppDynamicLibrary</ProjectType>
 			<ProjectType>CppDynamicLibrary</ProjectType>
 			<VerInfo_DLL>true</VerInfo_DLL>
 			<VerInfo_DLL>true</VerInfo_DLL>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP (32-bit);FileVersion=1.2.1.0;InternalName=dragext32;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.2.0.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP (32-bit);FileVersion=1.2.1.0;InternalName=dragext32;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.2.1.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
 			<VerInfo_Release>1</VerInfo_Release>
 			<VerInfo_Release>1</VerInfo_Release>

+ 2 - 2
source/DragExt64.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
 1 VERSIONINFO
 FILEVERSION 1,2,1,0
 FILEVERSION 1,2,1,0
-PRODUCTVERSION 5,2,0,0
+PRODUCTVERSION 5,2,1,0
 FILEOS 0x4
 FILEOS 0x4
 FILETYPE 0x2
 FILETYPE 0x2
 {
 {
@@ -16,7 +16,7 @@ FILETYPE 0x2
             VALUE "LegalTrademarks", "\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext64.dll\0"
             VALUE "OriginalFilename", "dragext64.dll\0"
             VALUE "ProductName", "WinSCP\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "5.2.0.0\0"
+            VALUE "ProductVersion", "5.2.1.0\0"
             VALUE "ReleaseType", "beta\0"
             VALUE "ReleaseType", "beta\0"
             VALUE "WWW", "http://winscp.net/\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
         }

+ 2 - 1
source/WinSCP.cbproj

@@ -51,10 +51,11 @@
 			<ProjectType>CppVCLApplication</ProjectType>
 			<ProjectType>CppVCLApplication</ProjectType>
 			<UsingDelphiRTL>true</UsingDelphiRTL>
 			<UsingDelphiRTL>true</UsingDelphiRTL>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP and SCP client;FileVersion=5.2.0.0;InternalName=winscp;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.2.0.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP and SCP client;FileVersion=5.2.1.0;InternalName=winscp;LegalCopyright=(c) 2000-2013 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.2.1.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>5</VerInfo_MajorVer>
 			<VerInfo_MajorVer>5</VerInfo_MajorVer>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
+			<VerInfo_Release>1</VerInfo_Release>
 		</PropertyGroup>
 		</PropertyGroup>
 		<PropertyGroup Condition="'$(Cfg_1)'!=''">
 		<PropertyGroup Condition="'$(Cfg_1)'!=''">
 			<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
 			<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>

+ 1 - 1
source/components/UnixDirView.cpp

@@ -398,7 +398,7 @@ void __fastcall TUnixDirView::LoadFiles()
           // this is out of date
           // this is out of date
           // (missing columns and does not update then file properties are loaded)
           // (missing columns and does not update then file properties are loaded)
           Item->ImageIndex = File->IconIndex;
           Item->ImageIndex = File->IconIndex;
-          Item->SubItems->Add((!File->IsDirectory ? FormatFloat(L"#,##0", File->Size) : UnicodeString()));
+          Item->SubItems->Add(!File->IsDirectory ? FormatBytes(File->Size, FormatSizeBytes, FormatSizeBytes) : UnicodeString());
           Item->SubItems->Add(File->UserModificationStr);
           Item->SubItems->Add(File->UserModificationStr);
           Item->SubItems->Add(File->RightsStr);
           Item->SubItems->Add(File->RightsStr);
           Item->SubItems->Add(File->Owner.DisplayText);
           Item->SubItems->Add(File->Owner.DisplayText);

+ 11 - 0
source/core/Common.cpp

@@ -1884,5 +1884,16 @@ bool __fastcall IsDirectoryWriteable(const UnicodeString & Path)
   return Result;
   return Result;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+UnicodeString __fastcall FormatNumber(__int64 Number)
+{
+  return FormatFloat(L"#,##0", Number);
+}
+//---------------------------------------------------------------------------
+// simple alternative to FormatBytes
+UnicodeString __fastcall FormatSize(__int64 Size)
+{
+  return FormatNumber(Size);
+}
+//---------------------------------------------------------------------------
 // Suppress warning about unused constants in DateUtils.hpp
 // Suppress warning about unused constants in DateUtils.hpp
 #pragma warn -8080
 #pragma warn -8080

+ 5 - 3
source/core/Common.h

@@ -95,6 +95,8 @@ LCID __fastcall GetDefaultLCID();
 UnicodeString __fastcall DefaultEncodingName();
 UnicodeString __fastcall DefaultEncodingName();
 UnicodeString __fastcall WindowsProductName();
 UnicodeString __fastcall WindowsProductName();
 bool __fastcall IsDirectoryWriteable(const UnicodeString & Path);
 bool __fastcall IsDirectoryWriteable(const UnicodeString & Path);
+UnicodeString __fastcall FormatNumber(__int64 Size);
+UnicodeString __fastcall FormatSize(__int64 Size);
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 typedef void __fastcall (__closure* TProcessLocalFileEvent)
 typedef void __fastcall (__closure* TProcessLocalFileEvent)
   (const UnicodeString FileName, const TSearchRec Rec, void * Param);
   (const UnicodeString FileName, const TSearchRec Rec, void * Param);
@@ -175,9 +177,9 @@ private:
 #else
 #else
 #define CHECK(p) { bool __CHECK_RESULT__ = (p); assert(__CHECK_RESULT__); }
 #define CHECK(p) { bool __CHECK_RESULT__ = (p); assert(__CHECK_RESULT__); }
 #define FAIL assert(false)
 #define FAIL assert(false)
-#define ALWAYS_TRUE(p) DoAlwaysTrue(p, TEXT(#p), TEXT(__FILE__), __LINE__)
-#define ALWAYS_FALSE(p) DoAlwaysFalse(p, TEXT(#p), TEXT(__FILE__), __LINE__)
-#define NOT_NULL(P) DoCheckNotNull(P, TEXT(#P), TEXT(__FILE__), __LINE__)
+#define ALWAYS_TRUE(p) p
+#define ALWAYS_FALSE(p) p
+#define NOT_NULL(P) P
 #endif
 #endif
 #define USEDPARAM(p) ((&p) == (&p))
 #define USEDPARAM(p) ((&p) == (&p))
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------

+ 14 - 9
source/core/Configuration.cpp

@@ -126,11 +126,16 @@ THierarchicalStorage * TConfiguration::CreateScpStorage(bool /*SessionList*/)
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-#define LASTELEM(ELEM) \
-  ELEM.SubString(ELEM.LastDelimiter(L".>")+1, ELEM.Length() - ELEM.LastDelimiter(L".>"))
+UnicodeString __fastcall TConfiguration::PropertyToKey(const UnicodeString & Property)
+{
+  // no longer useful
+  int P = Property.LastDelimiter(L".>");
+  return Property.SubString(P + 1, Property.Length() - P);
+}
+//---------------------------------------------------------------------------
 #define BLOCK(KEY, CANCREATE, BLOCK) \
 #define BLOCK(KEY, CANCREATE, BLOCK) \
   if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
   if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
-#define KEY(TYPE, VAR) KEYEX(TYPE, VAR, VAR)
+#define KEY(TYPE, VAR) KEYEX(TYPE, VAR, PropertyToKey(TEXT(#VAR)))
 #define REGCONFIG(CANCREATE) \
 #define REGCONFIG(CANCREATE) \
   BLOCK(L"Interface", CANCREATE, \
   BLOCK(L"Interface", CANCREATE, \
     KEY(String,   RandomSeedFile); \
     KEY(String,   RandomSeedFile); \
@@ -151,18 +156,18 @@ THierarchicalStorage * TConfiguration::CreateScpStorage(bool /*SessionList*/)
     KEY(Bool,     CollectUsage); \
     KEY(Bool,     CollectUsage); \
   ); \
   ); \
   BLOCK(L"Logging", CANCREATE, \
   BLOCK(L"Logging", CANCREATE, \
-    KEYEX(Bool,  PermanentLogging, Logging); \
-    KEYEX(String,PermanentLogFileName, LogFileName); \
+    KEYEX(Bool,  PermanentLogging, L"Logging"); \
+    KEYEX(String,PermanentLogFileName, L"LogFileName"); \
     KEY(Bool,    LogFileAppend); \
     KEY(Bool,    LogFileAppend); \
     KEY(Integer, LogWindowLines); \
     KEY(Integer, LogWindowLines); \
     KEY(Integer, LogProtocol); \
     KEY(Integer, LogProtocol); \
-    KEYEX(Bool,  PermanentLogActions, LogActions); \
-    KEYEX(String,PermanentActionsLogFileName, ActionsLogFileName); \
+    KEYEX(Bool,  PermanentLogActions, L"LogActions"); \
+    KEYEX(String,PermanentActionsLogFileName, L"ActionsLogFileName"); \
   );
   );
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TConfiguration::SaveData(THierarchicalStorage * Storage, bool /*All*/)
 void __fastcall TConfiguration::SaveData(THierarchicalStorage * Storage, bool /*All*/)
 {
 {
-  #define KEYEX(TYPE, VAR, NAME) Storage->Write ## TYPE(LASTELEM(UnicodeString(TEXT(#NAME))), VAR)
+  #define KEYEX(TYPE, VAR, NAME) Storage->Write ## TYPE(NAME, VAR)
   REGCONFIG(true);
   REGCONFIG(true);
   #undef KEYEX
   #undef KEYEX
 
 
@@ -272,7 +277,7 @@ void __fastcall TConfiguration::Import(const UnicodeString & FileName)
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TConfiguration::LoadData(THierarchicalStorage * Storage)
 void __fastcall TConfiguration::LoadData(THierarchicalStorage * Storage)
 {
 {
-  #define KEYEX(TYPE, VAR, NAME) VAR = Storage->Read ## TYPE(LASTELEM(UnicodeString(TEXT(#NAME))), VAR)
+  #define KEYEX(TYPE, VAR, NAME) VAR = Storage->Read ## TYPE(NAME, VAR)
   #pragma warn -eas
   #pragma warn -eas
   REGCONFIG(false);
   REGCONFIG(false);
   #pragma warn +eas
   #pragma warn +eas

+ 1 - 0
source/core/Configuration.h

@@ -131,6 +131,7 @@ protected:
   virtual void __fastcall Saved();
   virtual void __fastcall Saved();
   void __fastcall CleanupRegistry(UnicodeString CleanupSubKey);
   void __fastcall CleanupRegistry(UnicodeString CleanupSubKey);
   UnicodeString __fastcall BannerHash(const UnicodeString & Banner);
   UnicodeString __fastcall BannerHash(const UnicodeString & Banner);
+  static UnicodeString __fastcall PropertyToKey(const UnicodeString & Property);
 
 
   virtual bool __fastcall GetConfirmOverwriting();
   virtual bool __fastcall GetConfirmOverwriting();
   virtual void __fastcall SetConfirmOverwriting(bool value);
   virtual void __fastcall SetConfirmOverwriting(bool value);

+ 1 - 0
source/core/CoreMain.cpp

@@ -21,6 +21,7 @@ TStoredSessionList * StoredSessions = NULL;
 TQueryButtonAlias::TQueryButtonAlias()
 TQueryButtonAlias::TQueryButtonAlias()
 {
 {
   OnClick = NULL;
   OnClick = NULL;
+  GroupWith = -1;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 TQueryParams::TQueryParams(unsigned int AParams, UnicodeString AHelpKeyword)
 TQueryParams::TQueryParams(unsigned int AParams, UnicodeString AHelpKeyword)

+ 13 - 1
source/core/FtpFileSystem.cpp

@@ -804,13 +804,25 @@ bool __fastcall TFTPFileSystem::ConfirmOverwrite(UnicodeString & FileName,
     {
     {
       Answers |= qaRetry;
       Answers |= qaRetry;
     }
     }
-    TQueryButtonAlias Aliases[3];
+    TQueryButtonAlias Aliases[5];
     Aliases[0].Button = qaRetry;
     Aliases[0].Button = qaRetry;
     Aliases[0].Alias = LoadStr(RESUME_BUTTON);
     Aliases[0].Alias = LoadStr(RESUME_BUTTON);
+    Aliases[0].GroupWith = qaNo;
+    Aliases[0].GrouppedShiftState = TShiftState() << ssAlt;
     Aliases[1].Button = qaAll;
     Aliases[1].Button = qaAll;
     Aliases[1].Alias = LoadStr(YES_TO_NEWER_BUTTON);
     Aliases[1].Alias = LoadStr(YES_TO_NEWER_BUTTON);
+    Aliases[1].GroupWith = qaYes;
+    Aliases[1].GrouppedShiftState = TShiftState() << ssCtrl;
     Aliases[2].Button = qaIgnore;
     Aliases[2].Button = qaIgnore;
     Aliases[2].Alias = LoadStr(RENAME_BUTTON);
     Aliases[2].Alias = LoadStr(RENAME_BUTTON);
+    Aliases[2].GroupWith = qaNo;
+    Aliases[2].GrouppedShiftState = TShiftState() << ssCtrl;
+    Aliases[3].Button = qaYesToAll;
+    Aliases[3].GroupWith = qaYes;
+    Aliases[3].GrouppedShiftState = TShiftState() << ssShift;
+    Aliases[4].Button = qaNoToAll;
+    Aliases[4].GroupWith = qaNo;
+    Aliases[4].GrouppedShiftState = TShiftState() << ssShift;
     TQueryParams QueryParams(qpNeverAskAgainCheck);
     TQueryParams QueryParams(qpNeverAskAgainCheck);
     QueryParams.Aliases = Aliases;
     QueryParams.Aliases = Aliases;
     QueryParams.AliasesCount = LENOF(Aliases);
     QueryParams.AliasesCount = LENOF(Aliases);

+ 4 - 0
source/core/Interface.h

@@ -46,6 +46,8 @@ struct TQueryButtonAlias
   unsigned int Button;
   unsigned int Button;
   UnicodeString Alias;
   UnicodeString Alias;
   TNotifyEvent OnClick;
   TNotifyEvent OnClick;
+  int GroupWith;
+  TShiftState GrouppedShiftState;
 };
 };
 
 
 typedef void __fastcall (__closure *TQueryParamsTimerEvent)(unsigned int & Result);
 typedef void __fastcall (__closure *TQueryParamsTimerEvent)(unsigned int & Result);
@@ -82,6 +84,8 @@ enum TPromptKind
   pkNewPassword
   pkNewPassword
 };
 };
 
 
+enum TPromptUserParam { pupEcho = 0x01, pupRemember = 0x02 };
+
 bool __fastcall IsAuthenticationPrompt(TPromptKind Kind);
 bool __fastcall IsAuthenticationPrompt(TPromptKind Kind);
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 typedef void __fastcall (__closure *TFileFoundEvent)
 typedef void __fastcall (__closure *TFileFoundEvent)

+ 1 - 1
source/core/PuttyIntf.cpp

@@ -128,7 +128,7 @@ int get_userpass_input(prompts_t * p, unsigned char * /*in*/, int /*inlen*/)
     for (int Index = 0; Index < int(p->n_prompts); Index++)
     for (int Index = 0; Index < int(p->n_prompts); Index++)
     {
     {
       prompt_t * Prompt = p->prompts[Index];
       prompt_t * Prompt = p->prompts[Index];
-      Prompts->AddObject(Prompt->prompt, (TObject *)Prompt->echo);
+      Prompts->AddObject(Prompt->prompt, (TObject *)(FLAGMASK(Prompt->echo, pupEcho)));
       Results->AddObject(L"", (TObject *)Prompt->result_len);
       Results->AddObject(L"", (TObject *)Prompt->result_len);
     }
     }
 
 

+ 35 - 27
source/core/ScpFileSystem.cpp

@@ -1276,6 +1276,36 @@ void __fastcall TSCPFileSystem::SpaceAvailable(const UnicodeString Path,
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 // transfer protocol
 // transfer protocol
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+unsigned int __fastcall TSCPFileSystem::ConfirmOverwrite(
+  UnicodeString & FileName, TOperationSide Side,
+  const TOverwriteFileParams * FileParams, const TCopyParamType * CopyParam,
+  int Params, TFileOperationProgressType * OperationProgress)
+{
+  TQueryButtonAlias Aliases[3];
+  Aliases[0].Button = qaAll;
+  Aliases[0].Alias = LoadStr(YES_TO_NEWER_BUTTON);
+  Aliases[0].GroupWith = qaYes;
+  Aliases[0].GrouppedShiftState = TShiftState() << ssCtrl;
+  Aliases[1].Button = qaYesToAll;
+  Aliases[1].GroupWith = qaYes;
+  Aliases[1].GrouppedShiftState = TShiftState() << ssShift;
+  Aliases[2].Button = qaNoToAll;
+  Aliases[2].GroupWith = qaNo;
+  Aliases[2].GrouppedShiftState = TShiftState() << ssShift;
+  TQueryParams QueryParams(qpNeverAskAgainCheck);
+  QueryParams.Aliases = Aliases;
+  QueryParams.AliasesCount = LENOF(Aliases);
+  unsigned int Answer;
+  SUSPEND_OPERATION
+  (
+    Answer = FTerminal->ConfirmFileOverwrite(
+      FileName, FileParams,
+      qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll | qaAll,
+      &QueryParams, Side, CopyParam, Params, OperationProgress);
+  );
+  return Answer;
+}
+//---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::SCPResponse(bool * GotLastLine)
 void __fastcall TSCPFileSystem::SCPResponse(bool * GotLastLine)
 {
 {
   // Taken from scp.c response() and modified
   // Taken from scp.c response() and modified
@@ -1434,19 +1464,8 @@ void __fastcall TSCPFileSystem::CopyToRemote(TStrings * FilesToCopy,
             FileParams.DestSize = File->Size;
             FileParams.DestSize = File->Size;
             FileParams.DestTimestamp = File->Modification;
             FileParams.DestTimestamp = File->Modification;
 
 
-            TQueryButtonAlias Aliases[1];
-            Aliases[0].Button = qaAll;
-            Aliases[0].Alias = LoadStr(YES_TO_NEWER_BUTTON);
-            TQueryParams QueryParams(qpNeverAskAgainCheck);
-            QueryParams.Aliases = Aliases;
-            QueryParams.AliasesCount = LENOF(Aliases);
-            SUSPEND_OPERATION
-            (
-              Answer = FTerminal->ConfirmFileOverwrite(
-                FileNameOnly, &FileParams,
-                qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll | qaAll,
-                &QueryParams, osRemote, CopyParam, Params, OperationProgress);
-            );
+            Answer = ConfirmOverwrite(FileNameOnly, osRemote,
+              &FileParams, CopyParam, Params, OperationProgress);
           }
           }
 
 
           switch (Answer)
           switch (Answer)
@@ -2331,20 +2350,9 @@ void __fastcall TSCPFileSystem::SCPSink(const UnicodeString TargetDir,
                   FileParams.DestTimestamp = UnixToDateTime(MTime,
                   FileParams.DestTimestamp = UnixToDateTime(MTime,
                     FTerminal->SessionData->DSTMode);
                     FTerminal->SessionData->DSTMode);
 
 
-                  TQueryButtonAlias Aliases[1];
-                  Aliases[0].Button = qaAll;
-                  Aliases[0].Alias = LoadStr(YES_TO_NEWER_BUTTON);
-                  TQueryParams QueryParams(qpNeverAskAgainCheck);
-                  QueryParams.Aliases = Aliases;
-                  QueryParams.AliasesCount = LENOF(Aliases);
-
-                  unsigned int Answer;
-                  SUSPEND_OPERATION (
-                    Answer = FTerminal->ConfirmFileOverwrite(
-                      OperationProgress->FileName, &FileParams,
-                      qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll | qaAll,
-                      &QueryParams, osLocal, CopyParam, Params, OperationProgress);
-                  );
+                  unsigned int Answer =
+                    ConfirmOverwrite(OperationProgress->FileName, osLocal,
+                      &FileParams, CopyParam, Params, OperationProgress);
 
 
                   switch (Answer)
                   switch (Answer)
                   {
                   {

+ 6 - 0
source/core/ScpFileSystem.h

@@ -3,9 +3,11 @@
 #define ScpFileSystemH
 #define ScpFileSystemH
 
 
 #include <FileSystems.h>
 #include <FileSystems.h>
+#include <CopyParam.h>
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 class TCommandSet;
 class TCommandSet;
 class TSecureShell;
 class TSecureShell;
+struct TOverwriteFileParams;
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 class TSCPFileSystem : public TCustomFileSystem
 class TSCPFileSystem : public TCustomFileSystem
 {
 {
@@ -122,6 +124,10 @@ private:
   void __fastcall CaptureOutput(const UnicodeString & AddedLine, bool StdError);
   void __fastcall CaptureOutput(const UnicodeString & AddedLine, bool StdError);
   void __fastcall ChangeFileToken(const UnicodeString & DelimitedName,
   void __fastcall ChangeFileToken(const UnicodeString & DelimitedName,
     const TRemoteToken & Token, TFSCommand Cmd, const UnicodeString & RecursiveStr);
     const TRemoteToken & Token, TFSCommand Cmd, const UnicodeString & RecursiveStr);
+  unsigned int __fastcall ConfirmOverwrite(
+    UnicodeString & FileName, TOperationSide Side,
+    const TOverwriteFileParams * FileParams, const TCopyParamType * CopyParam,
+    int Params, TFileOperationProgressType * OperationProgress);
 
 
   static bool __fastcall RemoveLastLine(UnicodeString & Line,
   static bool __fastcall RemoveLastLine(UnicodeString & Line,
     int & ReturnCode, UnicodeString LastLine = L"");
     int & ReturnCode, UnicodeString LastLine = L"");

+ 12 - 3
source/core/SecureShell.cpp

@@ -60,6 +60,7 @@ __fastcall TSecureShell::TSecureShell(TSessionUI* UI,
   FSocketEvent = CreateEvent(NULL, false, false, NULL);
   FSocketEvent = CreateEvent(NULL, false, false, NULL);
   FFrozen = false;
   FFrozen = false;
   FSimple = false;
   FSimple = false;
+  FCollectPrivateKeyUsage = false;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TSecureShell::~TSecureShell()
 __fastcall TSecureShell::~TSecureShell()
@@ -664,7 +665,7 @@ bool __fastcall TSecureShell::PromptUser(bool /*ToServer*/,
   {
   {
     if (FSessionData->AuthKIPassword && !FSessionData->Password.IsEmpty() &&
     if (FSessionData->AuthKIPassword && !FSessionData->Password.IsEmpty() &&
         !FStoredPasswordTriedForKI && (Prompts->Count == 1) &&
         !FStoredPasswordTriedForKI && (Prompts->Count == 1) &&
-        !bool(Prompts->Objects[0]))
+        FLAGCLEAR(int(Prompts->Objects[0]), pupEcho))
     {
     {
       LogEvent(L"Using stored password.");
       LogEvent(L"Using stored password.");
       FUI->Information(LoadStr(AUTH_PASSWORD), false);
       FUI->Information(LoadStr(AUTH_PASSWORD), false);
@@ -1152,9 +1153,12 @@ int __fastcall TSecureShell::TranslateAuthenticationMessage(UnicodeString & Mess
 
 
   int Result = TranslatePuttyMessage(Translation, LENOF(Translation), Message);
   int Result = TranslatePuttyMessage(Translation, LENOF(Translation), Message);
 
 
-  if ((Result == 2) || (Result == 3) || (Result == 4))
+  if (FCollectPrivateKeyUsage &&
+      ((Result == 2) || (Result == 3) || (Result == 4)))
   {
   {
-    Configuration->Usage->Inc(L"OpenedSessionsPrivateKey");
+    Configuration->Usage->Inc(L"OpenedSessionsPrivateKey2");
+    // once only
+    FCollectPrivateKeyUsage = false;
   }
   }
 
 
   return Result;
   return Result;
@@ -2032,3 +2036,8 @@ bool __fastcall TSecureShell::GetReady()
 {
 {
   return FOpened && (FWaiting == 0);
   return FOpened && (FWaiting == 0);
 }
 }
+//---------------------------------------------------------------------------
+void __fastcall TSecureShell::EnableUsage()
+{
+  FCollectPrivateKeyUsage = true;
+}

+ 2 - 0
source/core/SecureShell.h

@@ -46,6 +46,7 @@ private:
   int FWaiting;
   int FWaiting;
   bool FSimple;
   bool FSimple;
   bool FNoConnectionResponse;
   bool FNoConnectionResponse;
+  bool FCollectPrivateKeyUsage;
 
 
   unsigned PendLen;
   unsigned PendLen;
   unsigned PendSize;
   unsigned PendSize;
@@ -128,6 +129,7 @@ public:
   unsigned long __fastcall MaxPacketSize();
   unsigned long __fastcall MaxPacketSize();
   void __fastcall ClearStdError();
   void __fastcall ClearStdError();
   bool __fastcall GetStoredCredentialsTried();
   bool __fastcall GetStoredCredentialsTried();
+  void __fastcall EnableUsage();
 
 
   void __fastcall RegisterReceiveHandler(TNotifyEvent Handler);
   void __fastcall RegisterReceiveHandler(TNotifyEvent Handler);
   void __fastcall UnregisterReceiveHandler(TNotifyEvent Handler);
   void __fastcall UnregisterReceiveHandler(TNotifyEvent Handler);

+ 57 - 27
source/core/SessionData.cpp

@@ -32,10 +32,12 @@ const int FtpPortNumber = 21;
 const int FtpsImplicitPortNumber = 990;
 const int FtpsImplicitPortNumber = 990;
 const int HTTPPortNumber = 80;
 const int HTTPPortNumber = 80;
 const int HTTPSPortNumber = 443;
 const int HTTPSPortNumber = 443;
+const int TelnetPortNumber = 23;
 const int DefaultSendBuf = 262144;
 const int DefaultSendBuf = 262144;
-const UnicodeString AnonymousUserName("anonymous");
-const UnicodeString AnonymousPassword("[email protected]");
-
+const UnicodeString AnonymousUserName(L"anonymous");
+const UnicodeString AnonymousPassword(L"[email protected]");
+const UnicodeString PuttySshProtocol(L"ssh");
+const UnicodeString PuttyTelnetProtocol(L"telnet");
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 TDateTime __fastcall SecToDateTime(int Sec)
 TDateTime __fastcall SecToDateTime(int Sec)
 {
 {
@@ -86,7 +88,7 @@ void __fastcall TSessionData::Default()
     Kex[Index] = DefaultKexList[Index];
     Kex[Index] = DefaultKexList[Index];
   }
   }
   PublicKeyFile = L"";
   PublicKeyFile = L"";
-  FProtocol = ptSSH;
+  FPuttyProtocol = PuttySshProtocol;
   TcpNoDelay = true;
   TcpNoDelay = true;
   SendBuf = DefaultSendBuf;
   SendBuf = DefaultSendBuf;
   SshSimple = true;
   SshSimple = true;
@@ -547,6 +549,8 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool & Rewr
 
 
   Color = Storage->ReadInteger(L"Color", Color);
   Color = Storage->ReadInteger(L"Color", Color);
 
 
+  PuttyProtocol = Storage->ReadString(L"Protocol", PuttyProtocol);
+
   Tunnel = Storage->ReadBool(L"Tunnel", Tunnel);
   Tunnel = Storage->ReadBool(L"Tunnel", Tunnel);
   TunnelPortNumber = Storage->ReadInteger(L"TunnelPortNumber", TunnelPortNumber);
   TunnelPortNumber = Storage->ReadInteger(L"TunnelPortNumber", TunnelPortNumber);
   TunnelUserName = Storage->ReadString(L"TunnelUserName", TunnelUserName);
   TunnelUserName = Storage->ReadString(L"TunnelUserName", TunnelUserName);
@@ -818,6 +822,11 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
     Storage->DeleteValue(L"BuggyMAC");
     Storage->DeleteValue(L"BuggyMAC");
     Storage->DeleteValue(L"AliasGroupList");
     Storage->DeleteValue(L"AliasGroupList");
 
 
+    if (PuttyExport)
+    {
+      WRITE_DATA_EX(String, L"Protocol", PuttyProtocol, );
+    }
+
     if (!PuttyExport)
     if (!PuttyExport)
     {
     {
       WRITE_DATA(String, SftpServer);
       WRITE_DATA(String, SftpServer);
@@ -897,9 +906,9 @@ int __fastcall TSessionData::ReadXmlNode(_di_IXMLNode Node, const UnicodeString
   return Result;
   return Result;
 }
 }
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
-void __fastcall TSessionData::ImportFromFilezilla(_di_IXMLNode Node)
+void __fastcall TSessionData::ImportFromFilezilla(_di_IXMLNode Node, const UnicodeString & Path)
 {
 {
-  Name = ReadXmlNode(Node, L"Name", Name);
+  Name = UnixIncludeTrailingBackslash(Path) + ReadXmlNode(Node, L"Name", Name);
   HostName = ReadXmlNode(Node, L"Host", HostName);
   HostName = ReadXmlNode(Node, L"Host", HostName);
   PortNumber = ReadXmlNode(Node, L"Port", PortNumber);
   PortNumber = ReadXmlNode(Node, L"Port", PortNumber);
 
 
@@ -928,7 +937,7 @@ void __fastcall TSessionData::ImportFromFilezilla(_di_IXMLNode Node)
   }
   }
 
 
   // LogonType enum
   // LogonType enum
-  int LogonType = ReadXmlNode(Node, L"LogonType", 0);
+  int LogonType = ReadXmlNode(Node, L"Logontype", 0);
   if (LogonType == 0) // ANONYMOUS
   if (LogonType == 0) // ANONYMOUS
   {
   {
     UserName = AnonymousUserName;
     UserName = AnonymousUserName;
@@ -1059,13 +1068,13 @@ UnicodeString __fastcall TSessionData::GetSource()
   switch (FSource)
   switch (FSource)
   {
   {
     case ::ssNone:
     case ::ssNone:
-      return L"Ad-Hoc session";
+      return L"Ad-Hoc site";
 
 
     case ssStored:
     case ssStored:
-      return L"Stored session";
+      return L"Site";
 
 
     case ssStoredModified:
     case ssStoredModified:
-      return L"Modified stored session";
+      return L"Modified site";
 
 
     default:
     default:
       assert(false);
       assert(false);
@@ -1789,11 +1798,6 @@ void __fastcall TSessionData::SetTimeout(int value)
   SET_SESSION_PROPERTY(Timeout);
   SET_SESSION_PROPERTY(Timeout);
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-void __fastcall TSessionData::SetProtocol(TProtocol value)
-{
-  SET_SESSION_PROPERTY(Protocol);
-}
-//---------------------------------------------------------------------------
 void __fastcall TSessionData::SetFSProtocol(TFSProtocol value)
 void __fastcall TSessionData::SetFSProtocol(TFSProtocol value)
 {
 {
   SET_SESSION_PROPERTY(FSProtocol);
   SET_SESSION_PROPERTY(FSProtocol);
@@ -1830,6 +1834,11 @@ bool __fastcall TSessionData::GetDefaultShell()
 {
 {
   return Shell.IsEmpty();
   return Shell.IsEmpty();
 }
 }
+//---------------------------------------------------------------------------
+void __fastcall TSessionData::SetPuttyProtocol(UnicodeString value)
+{
+  SET_SESSION_PROPERTY(PuttyProtocol);
+}
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 void __fastcall TSessionData::SetPingIntervalDT(TDateTime value)
 void __fastcall TSessionData::SetPingIntervalDT(TDateTime value)
 {
 {
@@ -2551,6 +2560,37 @@ void __fastcall TStoredSessionList::Saved()
   }
   }
 }
 }
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
+void __fastcall TStoredSessionList::ImportLevelFromFilezilla(_di_IXMLNode Node, const UnicodeString & Path)
+{
+  for (int Index = 0; Index < Node->ChildNodes->Count; Index++)
+  {
+    _di_IXMLNode ChildNode = Node->ChildNodes->Get(Index);
+    if (ChildNode->NodeName == L"Server")
+    {
+      std::auto_ptr<TSessionData> SessionData(new TSessionData(L""));
+      SessionData->Assign(DefaultSettings);
+      SessionData->ImportFromFilezilla(ChildNode, Path);
+      Add(SessionData.release());
+    }
+    else if (ChildNode->NodeName == L"Folder")
+    {
+      UnicodeString Name;
+
+      for (int Index = 0; Index < ChildNode->ChildNodes->Count; Index++)
+      {
+        _di_IXMLNode PossibleTextMode = ChildNode->ChildNodes->Get(Index);
+        if (PossibleTextMode->NodeType == ntText)
+        {
+          UnicodeString NodeValue = PossibleTextMode->NodeValue;
+          AddToList(Name, NodeValue.Trim(), L" ");
+        }
+      }
+
+      ImportLevelFromFilezilla(ChildNode, UnixIncludeTrailingBackslash(Path) + Name.Trim());
+    }
+  }
+}
+//---------------------------------------------------------------------
 void __fastcall TStoredSessionList::ImportFromFilezilla(const UnicodeString FileName)
 void __fastcall TStoredSessionList::ImportFromFilezilla(const UnicodeString FileName)
 {
 {
   const _di_IXMLDocument Document = interface_cast<Xmlintf::IXMLDocument>(new TXMLDocument(NULL));
   const _di_IXMLDocument Document = interface_cast<Xmlintf::IXMLDocument>(new TXMLDocument(NULL));
@@ -2561,17 +2601,7 @@ void __fastcall TStoredSessionList::ImportFromFilezilla(const UnicodeString File
     _di_IXMLNode ServersNode = FileZilla3Node->ChildNodes->FindNode(L"Servers");
     _di_IXMLNode ServersNode = FileZilla3Node->ChildNodes->FindNode(L"Servers");
     if (ServersNode != NULL)
     if (ServersNode != NULL)
     {
     {
-      for (int Index = 0; Index < ServersNode->ChildNodes->Count; Index++)
-      {
-        _di_IXMLNode ChildNode = ServersNode->ChildNodes->Get(Index);
-        if (ChildNode->NodeName == L"Server")
-        {
-          std::auto_ptr<TSessionData> SessionData(new TSessionData(L""));
-          SessionData->Assign(DefaultSettings);
-          SessionData->ImportFromFilezilla(ChildNode);
-          Add(SessionData.release());
-        }
-      }
+      ImportLevelFromFilezilla(ServersNode, L"");
     }
     }
   }
   }
 }
 }
@@ -2623,7 +2653,7 @@ void __fastcall TStoredSessionList::SelectSessionsToImport
   for (int Index = 0; Index < Count; Index++)
   for (int Index = 0; Index < Count; Index++)
   {
   {
     Sessions[Index]->Selected =
     Sessions[Index]->Selected =
-      (!SSHOnly || (Sessions[Index]->Protocol == ptSSH)) &&
+      (!SSHOnly || (Sessions[Index]->PuttyProtocol == PuttySshProtocol)) &&
       !Dest->FindByName(Sessions[Index]->Name);
       !Dest->FindByName(Sessions[Index]->Name);
   }
   }
 }
 }

+ 8 - 7
source/core/SessionData.h

@@ -15,8 +15,6 @@
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 enum TCipher { cipWarn, cip3DES, cipBlowfish, cipAES, cipDES, cipArcfour };
 enum TCipher { cipWarn, cip3DES, cipBlowfish, cipAES, cipDES, cipArcfour };
 #define CIPHER_COUNT (cipArcfour+1)
 #define CIPHER_COUNT (cipArcfour+1)
-enum TProtocol { ptRaw, ptTelnet, ptRLogin, ptSSH };
-#define PROTOCOL_COUNT (ptSSH+1)
 // explicit values to skip obsoleted fsExternalSSH, fsExternalSFTP
 // explicit values to skip obsoleted fsExternalSSH, fsExternalSFTP
 enum TFSProtocol { fsSCPonly = 0, fsSFTP = 1, fsSFTPonly = 2, fsFTP = 5, fsWebDAV = 6 };
 enum TFSProtocol { fsSCPonly = 0, fsSFTP = 1, fsSFTPonly = 2, fsFTP = 5, fsWebDAV = 6 };
 #define FSPROTOCOL_COUNT (fsWebDAV+1)
 #define FSPROTOCOL_COUNT (fsWebDAV+1)
@@ -36,7 +34,6 @@ enum TSessionSource { ssNone, ssStored, ssStoredModified };
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 extern const wchar_t CipherNames[CIPHER_COUNT][10];
 extern const wchar_t CipherNames[CIPHER_COUNT][10];
 extern const wchar_t KexNames[KEX_COUNT][20];
 extern const wchar_t KexNames[KEX_COUNT][20];
-extern const wchar_t ProtocolNames[PROTOCOL_COUNT][10];
 extern const wchar_t SshProtList[][10];
 extern const wchar_t SshProtList[][10];
 extern const wchar_t ProxyMethodList[][10];
 extern const wchar_t ProxyMethodList[][10];
 extern const TCipher DefaultCipherList[CIPHER_COUNT];
 extern const TCipher DefaultCipherList[CIPHER_COUNT];
@@ -50,6 +47,9 @@ extern const int FtpPortNumber;
 extern const int FtpsImplicitPortNumber;
 extern const int FtpsImplicitPortNumber;
 extern const int HTTPPortNumber;
 extern const int HTTPPortNumber;
 extern const int HTTPSPortNumber;
 extern const int HTTPSPortNumber;
+extern const int TelnetPortNumber;
+extern const UnicodeString PuttySshProtocol;
+extern const UnicodeString PuttyTelnetProtocol;
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 class TStoredSessionList;
 class TStoredSessionList;
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -83,7 +83,7 @@ private:
   bool FClearAliases;
   bool FClearAliases;
   TEOLType FEOLType;
   TEOLType FEOLType;
   UnicodeString FPublicKeyFile;
   UnicodeString FPublicKeyFile;
-  TProtocol FProtocol;
+  UnicodeString FPuttyProtocol;
   TFSProtocol FFSProtocol;
   TFSProtocol FFSProtocol;
   bool FModified;
   bool FModified;
   UnicodeString FLocalDirectory;
   UnicodeString FLocalDirectory;
@@ -194,6 +194,7 @@ private:
   TKex __fastcall GetKex(int Index) const;
   TKex __fastcall GetKex(int Index) const;
   void __fastcall SetPublicKeyFile(UnicodeString value);
   void __fastcall SetPublicKeyFile(UnicodeString value);
 
 
+  void __fastcall SetPuttyProtocol(UnicodeString value);
   bool __fastcall GetCanLogin();
   bool __fastcall GetCanLogin();
   void __fastcall SetPingIntervalDT(TDateTime value);
   void __fastcall SetPingIntervalDT(TDateTime value);
   TDateTime __fastcall GetPingIntervalDT();
   TDateTime __fastcall GetPingIntervalDT();
@@ -204,7 +205,6 @@ private:
   bool __fastcall HasSessionName();
   bool __fastcall HasSessionName();
   UnicodeString __fastcall GetDefaultSessionName();
   UnicodeString __fastcall GetDefaultSessionName();
   UnicodeString __fastcall GetSessionUrl();
   UnicodeString __fastcall GetSessionUrl();
-  void __fastcall SetProtocol(TProtocol value);
   void __fastcall SetFSProtocol(TFSProtocol value);
   void __fastcall SetFSProtocol(TFSProtocol value);
   UnicodeString __fastcall GetFSProtocolStr();
   UnicodeString __fastcall GetFSProtocolStr();
   void __fastcall SetLocalDirectory(UnicodeString value);
   void __fastcall SetLocalDirectory(UnicodeString value);
@@ -322,7 +322,7 @@ public:
   void __fastcall Default();
   void __fastcall Default();
   void __fastcall NonPersistant();
   void __fastcall NonPersistant();
   void __fastcall Load(THierarchicalStorage * Storage);
   void __fastcall Load(THierarchicalStorage * Storage);
-  void __fastcall ImportFromFilezilla(_di_IXMLNode Node);
+  void __fastcall ImportFromFilezilla(_di_IXMLNode Node, const UnicodeString & Path);
   void __fastcall Save(THierarchicalStorage * Storage, bool PuttyExport,
   void __fastcall Save(THierarchicalStorage * Storage, bool PuttyExport,
     const TSessionData * Default = NULL);
     const TSessionData * Default = NULL);
   void __fastcall SaveRecryptedPasswords(THierarchicalStorage * Storage);
   void __fastcall SaveRecryptedPasswords(THierarchicalStorage * Storage);
@@ -367,7 +367,7 @@ public:
   __property TCipher Cipher[int Index] = { read=GetCipher, write=SetCipher };
   __property TCipher Cipher[int Index] = { read=GetCipher, write=SetCipher };
   __property TKex Kex[int Index] = { read=GetKex, write=SetKex };
   __property TKex Kex[int Index] = { read=GetKex, write=SetKex };
   __property UnicodeString PublicKeyFile  = { read=FPublicKeyFile, write=SetPublicKeyFile };
   __property UnicodeString PublicKeyFile  = { read=FPublicKeyFile, write=SetPublicKeyFile };
-  __property TProtocol Protocol  = { read=FProtocol, write=SetProtocol };
+  __property UnicodeString PuttyProtocol  = { read=FPuttyProtocol, write=SetPuttyProtocol };
   __property TFSProtocol FSProtocol  = { read=FFSProtocol, write=SetFSProtocol  };
   __property TFSProtocol FSProtocol  = { read=FFSProtocol, write=SetFSProtocol  };
   __property UnicodeString FSProtocolStr  = { read=GetFSProtocolStr };
   __property UnicodeString FSProtocolStr  = { read=GetFSProtocolStr };
   __property bool Modified  = { read=FModified, write=FModified };
   __property bool Modified  = { read=FModified, write=FModified };
@@ -525,6 +525,7 @@ private:
   bool __fastcall IsFolderOrWorkspace(const UnicodeString & Name, bool Workspace);
   bool __fastcall IsFolderOrWorkspace(const UnicodeString & Name, bool Workspace);
   TSessionData * __fastcall CheckIsInFolderOrWorkspaceAndResolve(
   TSessionData * __fastcall CheckIsInFolderOrWorkspaceAndResolve(
     TSessionData * Data, const UnicodeString & Name);
     TSessionData * Data, const UnicodeString & Name);
+  void __fastcall ImportLevelFromFilezilla(_di_IXMLNode Node, const UnicodeString & Path);
 };
 };
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 UnicodeString GetExpandedLogFileName(UnicodeString LogFileName, TSessionData * SessionData);
 UnicodeString GetExpandedLogFileName(UnicodeString LogFileName, TSessionData * SessionData);

+ 10 - 6
source/core/SessionInfo.cpp

@@ -994,12 +994,6 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
           Bugs += UnicodeString(BugFlags[Data->Bug[(TSshBug)Index]])+(Index<BUG_COUNT-1?L",":L"");
           Bugs += UnicodeString(BugFlags[Data->Bug[(TSshBug)Index]])+(Index<BUG_COUNT-1?L",":L"");
         }
         }
         ADF(L"SSH Bugs: %s", (Bugs));
         ADF(L"SSH Bugs: %s", (Bugs));
-        Bugs = L"";
-        for (int Index = 0; Index < SFTP_BUG_COUNT; Index++)
-        {
-          Bugs += UnicodeString(BugFlags[Data->SFTPBug[(TSftpBug)Index]])+(Index<SFTP_BUG_COUNT-1?L",":L"");
-        }
-        ADF(L"SFTP Bugs: %s", (Bugs));
         ADF(L"Return code variable: %s; Lookup user groups: %s",
         ADF(L"Return code variable: %s; Lookup user groups: %s",
           ((Data->DetectReturnVar ? UnicodeString(L"Autodetect") : Data->ReturnVar),
           ((Data->DetectReturnVar ? UnicodeString(L"Autodetect") : Data->ReturnVar),
            BugFlags[Data->LookupUserGroups]));
            BugFlags[Data->LookupUserGroups]));
@@ -1013,6 +1007,16 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
            BooleanToEngStr(Data->IgnoreLsWarnings),
            BooleanToEngStr(Data->IgnoreLsWarnings),
            BooleanToEngStr(Data->Scp1Compatibility)));
            BooleanToEngStr(Data->Scp1Compatibility)));
       }
       }
+      if (Data->FSProtocol == fsSFTP)
+      {
+        UnicodeString Bugs;
+        for (int Index = 0; Index < SFTP_BUG_COUNT; Index++)
+        {
+          Bugs += UnicodeString(BugFlags[Data->SFTPBug[(TSftpBug)Index]])+(Index<SFTP_BUG_COUNT-1?L",":L"");
+        }
+        ADF(L"SFTP Bugs: %s", (Bugs));
+        ADF(L"SFTP Server: %s", ((Data->SftpServer.IsEmpty()? UnicodeString(L"default") : Data->SftpServer)));
+      }
       if (Data->FSProtocol == fsFTP)
       if (Data->FSProtocol == fsFTP)
       {
       {
         UnicodeString Ftps;
         UnicodeString Ftps;

+ 17 - 3
source/core/SftpFileSystem.cpp

@@ -2136,8 +2136,8 @@ unsigned long __fastcall TSFTPFileSystem::GotStatusPacket(TSFTPPacket * Packet,
     {
     {
       LanguageTag = FORMAT(L" (%s)", (LanguageTag));
       LanguageTag = FORMAT(L" (%s)", (LanguageTag));
     }
     }
-    UnicodeString Error = FMTLOAD(SFTP_ERROR_FORMAT2, (MessageStr,
-      int(Code), LanguageTag, ServerMessage, int(Packet->RequestType)));
+    UnicodeString Error = FMTLOAD(SFTP_ERROR_FORMAT3, (MessageStr,
+      int(Code), LanguageTag, ServerMessage));
     FTerminal->TerminalError(NULL, Error);
     FTerminal->TerminalError(NULL, Error);
     return 0;
     return 0;
   }
   }
@@ -3715,13 +3715,25 @@ void __fastcall TSFTPFileSystem::SFTPConfirmOverwrite(UnicodeString & FileName,
     {
     {
       Answers |= qaRetry;
       Answers |= qaRetry;
     }
     }
-    TQueryButtonAlias Aliases[3];
+    TQueryButtonAlias Aliases[5];
     Aliases[0].Button = qaRetry;
     Aliases[0].Button = qaRetry;
     Aliases[0].Alias = LoadStr(APPEND_BUTTON);
     Aliases[0].Alias = LoadStr(APPEND_BUTTON);
+    Aliases[0].GroupWith = qaNo;
+    Aliases[0].GrouppedShiftState = TShiftState() << ssAlt;
     Aliases[1].Button = qaAll;
     Aliases[1].Button = qaAll;
     Aliases[1].Alias = LoadStr(YES_TO_NEWER_BUTTON);
     Aliases[1].Alias = LoadStr(YES_TO_NEWER_BUTTON);
+    Aliases[1].GroupWith = qaYes;
+    Aliases[1].GrouppedShiftState = TShiftState() << ssCtrl;
     Aliases[2].Button = qaIgnore;
     Aliases[2].Button = qaIgnore;
     Aliases[2].Alias = LoadStr(RENAME_BUTTON);
     Aliases[2].Alias = LoadStr(RENAME_BUTTON);
+    Aliases[2].GroupWith = qaNo;
+    Aliases[2].GrouppedShiftState = TShiftState() << ssCtrl;
+    Aliases[3].Button = qaYesToAll;
+    Aliases[3].GroupWith = qaYes;
+    Aliases[3].GrouppedShiftState = TShiftState() << ssShift;
+    Aliases[4].Button = qaNoToAll;
+    Aliases[4].GroupWith = qaNo;
+    Aliases[4].GrouppedShiftState = TShiftState() << ssShift;
     TQueryParams QueryParams(qpNeverAskAgainCheck);
     TQueryParams QueryParams(qpNeverAskAgainCheck);
     QueryParams.NoBatchAnswers = qaIgnore | qaRetry | qaAll;
     QueryParams.NoBatchAnswers = qaIgnore | qaRetry | qaAll;
     QueryParams.Aliases = Aliases;
     QueryParams.Aliases = Aliases;
@@ -4476,6 +4488,8 @@ int __fastcall TSFTPFileSystem::SFTPOpenRemote(void * AOpenParams, void * /*Para
     {
     {
       if (!OpenParams->Confirmed && (OpenType & SSH_FXF_EXCL) && FTerminal->Active)
       if (!OpenParams->Confirmed && (OpenType & SSH_FXF_EXCL) && FTerminal->Active)
       {
       {
+        FTerminal->LogEvent(FORMAT(L"Cannot create new file \"%s\", checking if it exists already", (OpenParams->RemoteFileName)));
+
         bool ThrowOriginal = false;
         bool ThrowOriginal = false;
 
 
         // When exclusive opening of file fails, try to detect if file exists.
         // When exclusive opening of file fails, try to detect if file exists.

+ 112 - 16
source/core/Terminal.cpp

@@ -508,6 +508,7 @@ __fastcall TTerminal::TTerminal(TSessionData * SessionData,
   FTunnelUI = NULL;
   FTunnelUI = NULL;
   FTunnelOpening = false;
   FTunnelOpening = false;
   FCallbackGuard = NULL;
   FCallbackGuard = NULL;
+  FEnableSecureShellUsage = false;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TTerminal::~TTerminal()
 __fastcall TTerminal::~TTerminal()
@@ -731,6 +732,14 @@ void __fastcall TTerminal::Open()
                 FSecureShell = new TSecureShell(this, FSessionData, Log, Configuration);
                 FSecureShell = new TSecureShell(this, FSessionData, Log, Configuration);
                 try
                 try
                 {
                 {
+                  if (FEnableSecureShellUsage)
+                  {
+                    // only on the first connect,
+                    // this is not ideal as it may prevent usage from being collected,
+                    // e.g. when connection fails on the first try
+                    FSecureShell->EnableUsage();
+                    FEnableSecureShellUsage = false;
+                  }
                   // there will be only one channel in this session
                   // there will be only one channel in this session
                   FSecureShell->Simple = true;
                   FSecureShell->Simple = true;
                   FSecureShell->Open();
                   FSecureShell->Open();
@@ -1015,7 +1024,7 @@ bool __fastcall TTerminal::PromptUser(TSessionData * Data, TPromptKind Kind,
   TStrings * Results = new TStringList;
   TStrings * Results = new TStringList;
   try
   try
   {
   {
-    Prompts->AddObject(Prompt, (TObject *)Echo);
+    Prompts->AddObject(Prompt, (TObject *)(FLAGMASK(Echo, pupEcho)));
     Results->AddObject(Result, (TObject *)MaxLen);
     Results->AddObject(Result, (TObject *)MaxLen);
 
 
     AResult = PromptUser(Data, Kind, Name, Instructions, Prompts, Results);
     AResult = PromptUser(Data, Kind, Name, Instructions, Prompts, Results);
@@ -1045,6 +1054,15 @@ bool __fastcall TTerminal::DoPromptUser(TSessionData * /*Data*/, TPromptKind Kin
 {
 {
   bool AResult = false;
   bool AResult = false;
 
 
+  bool PasswordPrompt =
+    (Prompts->Count == 1) && FLAGCLEAR(int(Prompts->Objects[0]), pupEcho) &&
+    ((Kind == pkPassword) || (Kind == pkPassphrase) || (Kind == pkKeybInteractive) ||
+     (Kind == pkTIS) || (Kind == pkCryptoCard));
+  if (PasswordPrompt && !Configuration->RememberPassword)
+  {
+    Prompts->Objects[0] = (TObject*)(int(Prompts->Objects[0]) | pupRemember);
+  }
+
   if (OnPromptUser != NULL)
   if (OnPromptUser != NULL)
   {
   {
     TCallbackGuard Guard(this);
     TCallbackGuard Guard(this);
@@ -1052,10 +1070,8 @@ bool __fastcall TTerminal::DoPromptUser(TSessionData * /*Data*/, TPromptKind Kin
     Guard.Verify();
     Guard.Verify();
   }
   }
 
 
-  if (AResult && (Configuration->RememberPassword) &&
-      (Prompts->Count == 1) && !bool(Prompts->Objects[0]) &&
-      ((Kind == pkPassword) || (Kind == pkPassphrase) || (Kind == pkKeybInteractive) ||
-       (Kind == pkTIS) || (Kind == pkCryptoCard)))
+  if (AResult && PasswordPrompt &&
+      (Configuration->RememberPassword || FLAGSET(int(Prompts->Objects[0]), pupRemember)))
   {
   {
     RawByteString EncryptedPassword = EncryptPassword(Results->Strings[0]);
     RawByteString EncryptedPassword = EncryptPassword(Results->Strings[0]);
     if (FTunnelOpening)
     if (FTunnelOpening)
@@ -1469,6 +1485,10 @@ void __fastcall TTerminal::ClearCaches()
   {
   {
     FDirectoryChangesCache->Clear();
     FDirectoryChangesCache->Clear();
   }
   }
+  if (FCommandSession != NULL)
+  {
+    FCommandSession->ClearCaches();
+  }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::ClearCachedFileList(const UnicodeString Path,
 void __fastcall TTerminal::ClearCachedFileList(const UnicodeString Path,
@@ -1932,7 +1952,7 @@ bool __fastcall TTerminal::CheckRemoteFile(
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 unsigned int __fastcall TTerminal::ConfirmFileOverwrite(const UnicodeString FileName,
 unsigned int __fastcall TTerminal::ConfirmFileOverwrite(const UnicodeString FileName,
-  const TOverwriteFileParams * FileParams, unsigned int Answers, const TQueryParams * QueryParams,
+  const TOverwriteFileParams * FileParams, unsigned int Answers, TQueryParams * QueryParams,
   TOperationSide Side, const TCopyParamType * CopyParam, int Params, TFileOperationProgressType * OperationProgress,
   TOperationSide Side, const TCopyParamType * CopyParam, int Params, TFileOperationProgressType * OperationProgress,
   UnicodeString Message)
   UnicodeString Message)
 {
 {
@@ -1970,17 +1990,21 @@ unsigned int __fastcall TTerminal::ConfirmFileOverwrite(const UnicodeString File
   {
   {
     if (Message.IsEmpty())
     if (Message.IsEmpty())
     {
     {
-      Message = FMTLOAD((Side == osLocal ? LOCAL_FILE_OVERWRITE :
-        REMOTE_FILE_OVERWRITE), (FileName));
+      Message = FMTLOAD((Side == osLocal ? LOCAL_FILE_OVERWRITE2 :
+        REMOTE_FILE_OVERWRITE2), (FileName, FileName));
     }
     }
     if (FileParams != NULL)
     if (FileParams != NULL)
     {
     {
       Message = FMTLOAD(FILE_OVERWRITE_DETAILS, (Message,
       Message = FMTLOAD(FILE_OVERWRITE_DETAILS, (Message,
-        IntToStr(FileParams->SourceSize),
+        FormatSize(FileParams->SourceSize),
         UserModificationStr(FileParams->SourceTimestamp, FileParams->SourcePrecision),
         UserModificationStr(FileParams->SourceTimestamp, FileParams->SourcePrecision),
-        IntToStr(FileParams->DestSize),
+        FormatSize(FileParams->DestSize),
         UserModificationStr(FileParams->DestTimestamp, FileParams->DestPrecision)));
         UserModificationStr(FileParams->DestTimestamp, FileParams->DestPrecision)));
     }
     }
+    if (ALWAYS_TRUE(QueryParams->HelpKeyword.IsEmpty()))
+    {
+      QueryParams->HelpKeyword = L"ui_overwrite";
+    }
     Result = QueryUser(Message, NULL, Answers, QueryParams);
     Result = QueryUser(Message, NULL, Answers, QueryParams);
     switch (Result)
     switch (Result)
     {
     {
@@ -2378,7 +2402,7 @@ void __fastcall TTerminal::CustomReadDirectory(TRemoteFileList * FileList)
   assert(FFileSystem);
   assert(FFileSystem);
   FFileSystem->ReadDirectory(FileList);
   FFileSystem->ReadDirectory(FileList);
 
 
-  if (Configuration->ActualLogProtocol >= 1)
+  if (Log->Logging)
   {
   {
     for (int Index = 0; Index < FileList->Count; Index++)
     for (int Index = 0; Index < FileList->Count; Index++)
     {
     {
@@ -2945,7 +2969,21 @@ void __fastcall TTerminal::DoCustomCommandOnFile(UnicodeString FileName,
       assert(FCommandSession->FSProtocol == cfsSCP);
       assert(FCommandSession->FSProtocol == cfsSCP);
       LogEvent(L"Executing custom command on command session.");
       LogEvent(L"Executing custom command on command session.");
 
 
-      FCommandSession->CurrentDirectory = CurrentDirectory;
+      if (FCommandSession->CurrentDirectory != CurrentDirectory)
+      {
+        FCommandSession->CurrentDirectory = CurrentDirectory;
+        // We are likely in transaction, so ReadCurrentDirectory won't get called
+        // until transaction ends. But we need to know CurrentDirectory to
+        // expand !/ pattern.
+        // Doing this only, when current directory of the main and secondary shell differs,
+        // what would be the case before the first file in transation.
+        // Otherwise we would be reading pwd before every time as the
+        // CustomCommandOnFile on its own sets FReadCurrentDirectoryPending
+        if (FCommandSession->FReadCurrentDirectoryPending)
+        {
+          FCommandSession->ReadCurrentDirectory();
+        }
+      }
       FCommandSession->FFileSystem->CustomCommandOnFile(FileName, File, Command,
       FCommandSession->FFileSystem->CustomCommandOnFile(FileName, File, Command,
         Params, OutputEvent);
         Params, OutputEvent);
     }
     }
@@ -4048,6 +4086,58 @@ TSynchronizeChecklist * __fastcall TTerminal::SynchronizeCollect(const UnicodeSt
   return Checklist;
   return Checklist;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+static void __fastcall AddFlagName(UnicodeString & ParamsStr, int & Params, int Param, const UnicodeString & Name)
+{
+  if (FLAGSET(Params, Param))
+  {
+    AddToList(ParamsStr, Name, ", ");
+  }
+  Params &= ~Param;
+}
+//---------------------------------------------------------------------------
+UnicodeString __fastcall TTerminal::SynchronizeModeStr(TSynchronizeMode Mode)
+{
+  UnicodeString ModeStr;
+  switch (Mode)
+  {
+    case smRemote:
+      ModeStr = L"Remote";
+      break;
+    case smLocal:
+      ModeStr = L"Local";
+      break;
+    case smBoth:
+      ModeStr = L"Both";
+      break;
+    default:
+      ModeStr = L"Unknown";
+      break;
+  }
+  return ModeStr;
+}
+//---------------------------------------------------------------------------
+UnicodeString __fastcall TTerminal::SynchronizeParamsStr(int Params)
+{
+  UnicodeString ParamsStr;
+  AddFlagName(ParamsStr, Params, spDelete, L"Delete");
+  AddFlagName(ParamsStr, Params, spNoConfirmation, L"NoConfirmation");
+  AddFlagName(ParamsStr, Params, spExistingOnly, L"ExistingOnly");
+  AddFlagName(ParamsStr, Params, spNoRecurse, L"NoRecurse");
+  AddFlagName(ParamsStr, Params, spUseCache, L"UseCache");
+  AddFlagName(ParamsStr, Params, spDelayProgress, L"DelayProgress");
+  AddFlagName(ParamsStr, Params, spPreviewChanges, L"*PreviewChanges"); // GUI only
+  AddFlagName(ParamsStr, Params, spTimestamp, L"Timestamp");
+  AddFlagName(ParamsStr, Params, spNotByTime, L"NotByTime");
+  AddFlagName(ParamsStr, Params, spBySize, L"BySize");
+  AddFlagName(ParamsStr, Params, spSelectedOnly, L"*SelectedOnly"); // GUI only
+  AddFlagName(ParamsStr, Params, spMirror, L"Mirror");
+  if (Params > 0)
+  {
+    AddToList(ParamsStr, FORMAT(L"0x%x", (int(Params))), L", ");
+  }
+  return ParamsStr;
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminal::DoSynchronizeCollectDirectory(const UnicodeString LocalDirectory,
 void __fastcall TTerminal::DoSynchronizeCollectDirectory(const UnicodeString LocalDirectory,
   const UnicodeString RemoteDirectory, TSynchronizeMode Mode,
   const UnicodeString RemoteDirectory, TSynchronizeMode Mode,
   const TCopyParamType * CopyParam, int Params,
   const TCopyParamType * CopyParam, int Params,
@@ -4068,8 +4158,8 @@ void __fastcall TTerminal::DoSynchronizeCollectDirectory(const UnicodeString Loc
   Data.Checklist = Checklist;
   Data.Checklist = Checklist;
 
 
   LogEvent(FORMAT(L"Collecting synchronization list for local directory '%s' and remote directory '%s', "
   LogEvent(FORMAT(L"Collecting synchronization list for local directory '%s' and remote directory '%s', "
-    "mode = %d, params = %d", (LocalDirectory, RemoteDirectory,
-    int(Mode), int(Params))));
+    "mode = %s, params = 0x%x (%s)", (LocalDirectory, RemoteDirectory,
+    SynchronizeModeStr(Mode), int(Params), SynchronizeParamsStr(Params))));
 
 
   if (FLAGCLEAR(Params, spDelayProgress))
   if (FLAGCLEAR(Params, spDelayProgress))
   {
   {
@@ -4504,7 +4594,8 @@ void __fastcall TTerminal::SynchronizeApply(TSynchronizeChecklist * Checklist,
       UnicodeString CurrentRemoteDirectory = ChecklistItem->Remote.Directory;
       UnicodeString CurrentRemoteDirectory = ChecklistItem->Remote.Directory;
 
 
       LogEvent(FORMAT(L"Synchronizing local directory '%s' with remote directory '%s', "
       LogEvent(FORMAT(L"Synchronizing local directory '%s' with remote directory '%s', "
-        "params = %d", (CurrentLocalDirectory, CurrentRemoteDirectory, int(Params))));
+        "params = 0x%x (%s)", (CurrentLocalDirectory, CurrentRemoteDirectory,
+        int(Params), SynchronizeParamsStr(Params))));
 
 
       int Count = 0;
       int Count = 0;
 
 
@@ -5040,6 +5131,11 @@ void __fastcall TTerminal::ReflectSettings()
   // also FTunnelLog ?
   // also FTunnelLog ?
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+void __fastcall TTerminal::EnableUsage()
+{
+  FEnableSecureShellUsage = true;
+}
+//---------------------------------------------------------------------------
 __fastcall TSecondaryTerminal::TSecondaryTerminal(TTerminal * MainTerminal,
 __fastcall TSecondaryTerminal::TSecondaryTerminal(TTerminal * MainTerminal,
   TSessionData * ASessionData, TConfiguration * Configuration, const UnicodeString & Name) :
   TSessionData * ASessionData, TConfiguration * Configuration, const UnicodeString & Name) :
   TTerminal(ASessionData, Configuration),
   TTerminal(ASessionData, Configuration),
@@ -5076,7 +5172,7 @@ bool __fastcall TSecondaryTerminal::DoPromptUser(TSessionData * Data,
 {
 {
   bool AResult = false;
   bool AResult = false;
 
 
-  if ((Prompts->Count == 1) && !bool(Prompts->Objects[0]) &&
+  if ((Prompts->Count == 1) && FLAGCLEAR(int(Prompts->Objects[0]), pupEcho) &&
       ((Kind == pkPassword) || (Kind == pkPassphrase) || (Kind == pkKeybInteractive) ||
       ((Kind == pkPassword) || (Kind == pkPassphrase) || (Kind == pkKeybInteractive) ||
        (Kind == pkTIS) || (Kind == pkCryptoCard)))
        (Kind == pkTIS) || (Kind == pkCryptoCard)))
   {
   {

+ 6 - 2
source/core/Terminal.h

@@ -133,7 +133,7 @@ public:
   static const int spTimestamp = 0x100;
   static const int spTimestamp = 0x100;
   static const int spNotByTime = 0x200; // cannot be combined with spTimestamp and smBoth
   static const int spNotByTime = 0x200; // cannot be combined with spTimestamp and smBoth
   static const int spBySize = 0x400; // cannot be combined with smBoth, has opposite meaning for spTimestamp
   static const int spBySize = 0x400; // cannot be combined with smBoth, has opposite meaning for spTimestamp
-  // 0x800 is reserved for GUI (spSelectedOnly)
+  static const int spSelectedOnly = 0x800; // not used by core
   static const int spMirror = 0x1000;
   static const int spMirror = 0x1000;
 
 
 // for TranslateLockedPath()
 // for TranslateLockedPath()
@@ -199,6 +199,7 @@ private:
   TNotifyEvent FOnClose;
   TNotifyEvent FOnClose;
   TCallbackGuard * FCallbackGuard;
   TCallbackGuard * FCallbackGuard;
   TFindingFileEvent FOnFindingFile;
   TFindingFileEvent FOnFindingFile;
+  bool FEnableSecureShellUsage;
 
 
   void __fastcall CommandError(Exception * E, const UnicodeString Msg);
   void __fastcall CommandError(Exception * E, const UnicodeString Msg);
   unsigned int __fastcall CommandError(Exception * E, const UnicodeString Msg, unsigned int Answers);
   unsigned int __fastcall CommandError(Exception * E, const UnicodeString Msg, unsigned int Answers);
@@ -222,6 +223,8 @@ private:
   UnicodeString __fastcall GetTunnelPassword();
   UnicodeString __fastcall GetTunnelPassword();
   bool __fastcall GetStoredCredentialsTried();
   bool __fastcall GetStoredCredentialsTried();
   inline bool __fastcall InTransaction();
   inline bool __fastcall InTransaction();
+  static UnicodeString __fastcall SynchronizeModeStr(TSynchronizeMode Mode);
+  static UnicodeString __fastcall SynchronizeParamsStr(int Params);
 
 
 protected:
 protected:
   bool FReadCurrentDirectoryPending;
   bool FReadCurrentDirectoryPending;
@@ -286,7 +289,7 @@ protected:
   bool __fastcall CheckRemoteFile(
   bool __fastcall CheckRemoteFile(
     const TCopyParamType * CopyParam, int Params, TFileOperationProgressType * OperationProgress);
     const TCopyParamType * CopyParam, int Params, TFileOperationProgressType * OperationProgress);
   unsigned int __fastcall ConfirmFileOverwrite(const UnicodeString FileName,
   unsigned int __fastcall ConfirmFileOverwrite(const UnicodeString FileName,
-    const TOverwriteFileParams * FileParams, unsigned int Answers, const TQueryParams * QueryParams,
+    const TOverwriteFileParams * FileParams, unsigned int Answers, TQueryParams * QueryParams,
     TOperationSide Side, const TCopyParamType * CopyParam, int Params,
     TOperationSide Side, const TCopyParamType * CopyParam, int Params,
     TFileOperationProgressType * OperationProgress, UnicodeString Message = L"");
     TFileOperationProgressType * OperationProgress, UnicodeString Message = L"");
   void __fastcall DoSynchronizeCollectDirectory(const UnicodeString LocalDirectory,
   void __fastcall DoSynchronizeCollectDirectory(const UnicodeString LocalDirectory,
@@ -444,6 +447,7 @@ public:
   UnicodeString __fastcall PeekCurrentDirectory();
   UnicodeString __fastcall PeekCurrentDirectory();
   void __fastcall FatalAbort();
   void __fastcall FatalAbort();
   void __fastcall ReflectSettings();
   void __fastcall ReflectSettings();
+  void __fastcall EnableUsage();
 
 
   const TSessionInfo & __fastcall GetSessionInfo();
   const TSessionInfo & __fastcall GetSessionInfo();
   const TFileSystemInfo & __fastcall GetFileSystemInfo(bool Retrieve = false);
   const TFileSystemInfo & __fastcall GetFileSystemInfo(bool Retrieve = false);

+ 1 - 2
source/filezilla/FileZillaIntf.cpp

@@ -402,11 +402,10 @@ bool __fastcall TFileZillaIntf::HandleMessage(WPARAM wParam, LPARAM lParam)
         try
         try
         {
         {
             TNeedPassRequestData Data;
             TNeedPassRequestData Data;
-            Data.Password = NULL;
             Data.Password = AData->Password.GetBuffer(AData->Password.GetLength());
             Data.Password = AData->Password.GetBuffer(AData->Password.GetLength());
             Result = HandleAsynchRequestNeedPass(Data, RequestResult);
             Result = HandleAsynchRequestNeedPass(Data, RequestResult);
             AData->Password.ReleaseBuffer(AData->Password.GetLength());
             AData->Password.ReleaseBuffer(AData->Password.GetLength());
-            if (Result)
+            if (Result && (RequestResult == TFileZillaIntf::REPLY_OK))
             {
             {
               AData->Password = Data.Password;
               AData->Password = Data.Password;
               free(Data.Password);
               free(Data.Password);

+ 2 - 2
source/filezilla/FtpControlSocket.cpp

@@ -6219,8 +6219,8 @@ bool CFtpControlSocket::IsRoutableAddress(const CString & host)
 	else if (host.Left(3) == _T("172"))
 	else if (host.Left(3) == _T("172"))
 	{
 	{
 		CString middle = host.Mid(4);
 		CString middle = host.Mid(4);
-		int pos = host.Find(_T("."));
-		long part = atol(T2CA(host.Left(pos)));
+		int pos = middle.Find(_T("."));
+		long part = atol(T2CA(middle.Left(pos)));
 		if ((part >= 16) && (part <= 31))
 		if ((part >= 16) && (part <= 31))
 		{
 		{
 			return false;
 			return false;

+ 2 - 1
source/filezilla/FtpListResult.cpp

@@ -760,7 +760,8 @@ char * CFtpListResult::GetLine()
 
 
 void CFtpListResult::AddLine(t_directory::t_direntry &direntry)
 void CFtpListResult::AddLine(t_directory::t_direntry &direntry)
 {
 {
-	if (m_server.nTimeZoneOffset && direntry.date.hasdate && direntry.date.hastime)
+	if (m_server.nTimeZoneOffset &&
+		direntry.date.hasdate && direntry.date.hastime && !direntry.date.utc)
 	{
 	{
 		SYSTEMTIME st = {0};
 		SYSTEMTIME st = {0};
 		st.wYear = direntry.date.year;
 		st.wYear = direntry.date.year;

+ 24 - 5
source/forms/Authenticate.cpp

@@ -202,7 +202,8 @@ TList * __fastcall TAuthenticateForm::GeneratePrompt(UnicodeString Instructions,
     TLabel * Label = GenerateLabel(Current, Prompts->Strings[Index]);
     TLabel * Label = GenerateLabel(Current, Prompts->Strings[Index]);
     Current += Label->Height + FPromptEditGap;
     Current += Label->Height + FPromptEditGap;
 
 
-    TCustomEdit * Edit = GenerateEdit(Current, bool(Prompts->Objects[Index]),
+    bool Echo = FLAGSET(int(Prompts->Objects[Index]), pupEcho);
+    TCustomEdit * Edit = GenerateEdit(Current, Echo,
       int(Results->Objects[Index]));
       int(Results->Objects[Index]));
     Result->Add(Edit);
     Result->Add(Edit);
     Label->FocusControl = Edit;
     Label->FocusControl = Edit;
@@ -224,19 +225,32 @@ bool __fastcall TAuthenticateForm::PromptUser(TPromptKind Kind, UnicodeString Na
 
 
   try
   try
   {
   {
+    bool ShowSessionRememberPasswordPanel = false;
     bool ShowSavePasswordPanel = false;
     bool ShowSavePasswordPanel = false;
     TSessionData * Data = NULL;
     TSessionData * Data = NULL;
-    if (((Kind == pkPassword) || (Kind == pkTIS) || (Kind == pkCryptoCard) ||
-         (Kind == pkKeybInteractive)) &&
-        (Prompts->Count == 1) && !bool(Prompts->Objects[0]) &&
-        StoredCredentialsTried)
+    bool PasswordPrompt =
+      ((Kind == pkPassword) || (Kind == pkTIS) || (Kind == pkCryptoCard) ||
+       (Kind == pkKeybInteractive)) &&
+      (Prompts->Count == 1) && FLAGCLEAR(int(Prompts->Objects[0]), pupEcho);
+    if (PasswordPrompt && StoredCredentialsTried)
     {
     {
       Data = StoredSessions->FindSame(FSessionData);
       Data = StoredSessions->FindSame(FSessionData);
       ShowSavePasswordPanel = (Data != NULL) && !Data->Password.IsEmpty();
       ShowSavePasswordPanel = (Data != NULL) && !Data->Password.IsEmpty();
     }
     }
+    // do not offer to rememeber password,
+    // if we are offering to save the password to stored session
+    if (!ShowSavePasswordPanel &&
+        (Prompts->Count == 1) &&
+        FLAGSET(int(Prompts->Objects[0]), pupRemember) &&
+        ALWAYS_TRUE(PasswordPrompt))
+    {
+      ShowSessionRememberPasswordPanel = true;
+    }
 
 
     SavePasswordCheck->Checked = false;
     SavePasswordCheck->Checked = false;
     SavePasswordPanel->Visible = ShowSavePasswordPanel;
     SavePasswordPanel->Visible = ShowSavePasswordPanel;
+    SessionRememberPasswordCheck->Checked = false;
+    SessionRememberPasswordPanel->Visible = ShowSessionRememberPasswordPanel;
 
 
     if (PasswordPanel->AutoSize)
     if (PasswordPanel->AutoSize)
     {
     {
@@ -263,12 +277,17 @@ bool __fastcall TAuthenticateForm::PromptUser(TPromptKind Kind, UnicodeString Na
       {
       {
         TCustomEdit * Edit = reinterpret_cast<TCustomEdit *>(Edits->Items[Index]);
         TCustomEdit * Edit = reinterpret_cast<TCustomEdit *>(Edits->Items[Index]);
         Results->Strings[Index] = Edit->Text;
         Results->Strings[Index] = Edit->Text;
+
+        Prompts->Objects[Index] = (TObject *)
+          ((int(Prompts->Objects[Index]) & ~pupRemember) |
+           FLAGMASK(((Index == 0) && SessionRememberPasswordCheck->Checked), pupRemember));
       }
       }
 
 
       if (SavePasswordCheck->Checked)
       if (SavePasswordCheck->Checked)
       {
       {
         assert(Data != NULL);
         assert(Data != NULL);
         assert(Results->Count >= 1);
         assert(Results->Count >= 1);
+        FSessionData->Password = Results->Strings[0];
         Data->Password = Results->Strings[0];
         Data->Password = Results->Strings[0];
         // modified only, explicit
         // modified only, explicit
         StoredSessions->Save(false, true);
         StoredSessions->Save(false, true);

+ 28 - 9
source/forms/Authenticate.dfm

@@ -6,7 +6,7 @@ object AuthenticateForm: TAuthenticateForm
   BorderIcons = [biSystemMenu]
   BorderIcons = [biSystemMenu]
   BorderStyle = bsDialog
   BorderStyle = bsDialog
   Caption = 'AuthenticateForm'
   Caption = 'AuthenticateForm'
-  ClientHeight = 316
+  ClientHeight = 359
   ClientWidth = 375
   ClientWidth = 375
   Color = clBtnFace
   Color = clBtnFace
   Constraints.MinHeight = 200
   Constraints.MinHeight = 200
@@ -26,7 +26,7 @@ object AuthenticateForm: TAuthenticateForm
     Left = 0
     Left = 0
     Top = 0
     Top = 0
     Width = 375
     Width = 375
-    Height = 26
+    Height = 44
     Align = alClient
     Align = alClient
     Columns = <
     Columns = <
       item
       item
@@ -46,9 +46,9 @@ object AuthenticateForm: TAuthenticateForm
   end
   end
   object PasswordPanel: TPanel
   object PasswordPanel: TPanel
     Left = 0
     Left = 0
-    Top = 26
+    Top = 44
     Width = 375
     Width = 375
-    Height = 208
+    Height = 233
     Align = alBottom
     Align = alBottom
     AutoSize = True
     AutoSize = True
     BevelOuter = bvNone
     BevelOuter = bvNone
@@ -122,12 +122,12 @@ object AuthenticateForm: TAuthenticateForm
     end
     end
     object SavePasswordPanel: TPanel
     object SavePasswordPanel: TPanel
       Left = 0
       Left = 0
-      Top = 139
+      Top = 164
       Width = 375
       Width = 375
       Height = 25
       Height = 25
       Align = alTop
       Align = alTop
       BevelOuter = bvNone
       BevelOuter = bvNone
-      TabOrder = 1
+      TabOrder = 2
       object SavePasswordCheck: TCheckBox
       object SavePasswordCheck: TCheckBox
         Left = 14
         Left = 14
         Top = 6
         Top = 6
@@ -141,12 +141,12 @@ object AuthenticateForm: TAuthenticateForm
     end
     end
     object ButtonsPanel: TPanel
     object ButtonsPanel: TPanel
       Left = 0
       Left = 0
-      Top = 164
+      Top = 189
       Width = 375
       Width = 375
       Height = 44
       Height = 44
       Align = alTop
       Align = alTop
       BevelOuter = bvNone
       BevelOuter = bvNone
-      TabOrder = 2
+      TabOrder = 3
       DesignSize = (
       DesignSize = (
         375
         375
         44)
         44)
@@ -181,10 +181,29 @@ object AuthenticateForm: TAuthenticateForm
         OnClick = HelpButtonClick
         OnClick = HelpButtonClick
       end
       end
     end
     end
+    object SessionRememberPasswordPanel: TPanel
+      Left = 0
+      Top = 139
+      Width = 375
+      Height = 25
+      Align = alTop
+      BevelOuter = bvNone
+      TabOrder = 1
+      object SessionRememberPasswordCheck: TCheckBox
+        Left = 14
+        Top = 6
+        Width = 275
+        Height = 17
+        Caption = '&Remember password for this session'
+        Checked = True
+        State = cbChecked
+        TabOrder = 0
+      end
+    end
   end
   end
   object BannerPanel: TPanel
   object BannerPanel: TPanel
     Left = 0
     Left = 0
-    Top = 234
+    Top = 277
     Width = 375
     Width = 375
     Height = 82
     Height = 82
     Align = alBottom
     Align = alBottom

+ 2 - 0
source/forms/Authenticate.h

@@ -33,6 +33,8 @@ __published:
   TLabel *InstructionsLabel;
   TLabel *InstructionsLabel;
   TLabel *PromptLabel2;
   TLabel *PromptLabel2;
   TPasswordEdit *PromptEdit2;
   TPasswordEdit *PromptEdit2;
+  TPanel *SessionRememberPasswordPanel;
+  TCheckBox *SessionRememberPasswordCheck;
   void __fastcall FormShow(TObject *Sender);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall HelpButtonClick(TObject *Sender);
   void __fastcall HelpButtonClick(TObject *Sender);
   void __fastcall FormResize(TObject *Sender);
   void __fastcall FormResize(TObject *Sender);

+ 11 - 11
source/forms/CopyParams.dfm

@@ -308,18 +308,18 @@ object CopyParamsFrame: TCopyParamsFrame
       Caption = '&New and updated files only'
       Caption = '&New and updated files only'
       ParentShowHint = False
       ParentShowHint = False
       ShowHint = True
       ShowHint = True
-      TabOrder = 2
+      TabOrder = 3
       OnClick = ControlChange
       OnClick = ControlChange
     end
     end
-  end
-  object IncludeFileMaskHintText: TStaticText
-    Left = 271
-    Top = 380
-    Width = 54
-    Height = 17
-    Alignment = taCenter
-    Caption = 'mask hints'
-    TabOrder = 6
-    TabStop = True
+    object IncludeFileMaskHintText: TStaticText
+      Left = 263
+      Top = 58
+      Width = 54
+      Height = 17
+      Alignment = taCenter
+      Caption = 'mask hints'
+      TabOrder = 2
+      TabStop = True
+    end
   end
   end
 end
 end

+ 22 - 9
source/forms/CustomScpExplorer.cpp

@@ -2748,7 +2748,7 @@ void __fastcall TCustomScpExplorerForm::ExecutedFileChanged(const UnicodeString
          (Data.SessionName, ExtractFileName(FileName)));
          (Data.SessionName, ExtractFileName(FileName)));
       if (MessageDialog(Message, qtConfirmation, qaOK | qaCancel) == qaOK)
       if (MessageDialog(Message, qtConfirmation, qaOK | qaCancel) == qaOK)
       {
       {
-        TTerminalManager::Instance()->ActiveTerminal = Data.Terminal;
+        TTerminalManager::Instance()->SetActiveTerminalWithAutoReconnect(Data.Terminal);
       }
       }
       else
       else
       {
       {
@@ -3585,7 +3585,7 @@ void __fastcall TCustomScpExplorerForm::Idle()
     {
     {
       if (FRefreshRemoteDirectory)
       if (FRefreshRemoteDirectory)
       {
       {
-        if ((Terminal != NULL) && Terminal->Active)
+        if ((Terminal != NULL) && (Terminal->Status == ssOpened))
         {
         {
           Terminal->RefreshDirectory();
           Terminal->RefreshDirectory();
         }
         }
@@ -3601,7 +3601,7 @@ void __fastcall TCustomScpExplorerForm::Idle()
       {
       {
         TManagedTerminal * ManagedTerminal =
         TManagedTerminal * ManagedTerminal =
           dynamic_cast<TManagedTerminal *>(Terminal);
           dynamic_cast<TManagedTerminal *>(Terminal);
-        if ((ManagedTerminal != NULL) && Terminal->Active &&
+        if ((ManagedTerminal != NULL) && (Terminal->Status == ssOpened) &&
             (Now() - ManagedTerminal->DirectoryLoaded >
             (Now() - ManagedTerminal->DirectoryLoaded >
                WinConfiguration->RefreshRemotePanelInterval))
                WinConfiguration->RefreshRemotePanelInterval))
         {
         {
@@ -5491,19 +5491,28 @@ void __fastcall TCustomScpExplorerForm::ShowExtendedException(
     PopupTrayBalloon(Terminal, L"", qtError, E);
     PopupTrayBalloon(Terminal, L"", qtError, E);
   }
   }
 
 
+  // particularly prevent opening new session from jump list,
+  // while exception is shown
+  NonVisualDataModule->StartBusy();
   try
   try
   {
   {
     ShowExtendedExceptionEx(Terminal, E);
     ShowExtendedExceptionEx(Terminal, E);
   }
   }
   __finally
   __finally
   {
   {
+    NonVisualDataModule->EndBusy();
     FTrayIcon->CancelBalloon();
     FTrayIcon->CancelBalloon();
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::TerminalReady()
 void __fastcall TCustomScpExplorerForm::TerminalReady()
 {
 {
-  UpdateSessionTab(SessionsPageControl->ActivePage);
+  // cannot rely on active page being page for active terminal,
+  // as it can happen that active page is the "new session" page
+  // (e.g. when reconnecting active terminal, while login dialog
+  // invoked from "new session" page is modal)
+  int ActiveTerminalIndex = TTerminalManager::Instance()->ActiveTerminalIndex;
+  UpdateSessionTab(SessionsPageControl->Pages[ActiveTerminalIndex]);
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::InactiveTerminalException(
 void __fastcall TCustomScpExplorerForm::InactiveTerminalException(
@@ -6558,8 +6567,8 @@ UnicodeString __fastcall TCustomScpExplorerForm::FileStatusBarText(
     FMTLOAD(FILE_INFO_FORMAT,
     FMTLOAD(FILE_INFO_FORMAT,
       (FormatBytes(FileInfo.SelectedSize),
       (FormatBytes(FileInfo.SelectedSize),
        FormatBytes(FileInfo.FilesSize),
        FormatBytes(FileInfo.FilesSize),
-       FormatFloat(L"#,##0", FileInfo.SelectedCount),
-       FormatFloat(L"#,##0", FileInfo.FilesCount)));
+       FormatNumber(FileInfo.SelectedCount),
+       FormatNumber(FileInfo.FilesCount)));
 
 
   if ((FileInfo.HiddenCount > 0) || (FileInfo.FilteredCount > 0))
   if ((FileInfo.HiddenCount > 0) || (FileInfo.FilteredCount > 0))
   {
   {
@@ -7739,11 +7748,15 @@ bool __fastcall TCustomScpExplorerForm::HandleMouseWheel(WPARAM WParam, LPARAM L
   {
   {
     TPoint Point(LOWORD(LParam), HIWORD(LParam));
     TPoint Point(LOWORD(LParam), HIWORD(LParam));
     TWinControl * Control = FindVCLWindow(Point);
     TWinControl * Control = FindVCLWindow(Point);
-    TCustomForm * Form = ValidParentForm(Control);
-    Result = (Form == this);
+    Result = (Control != NULL);
     if (Result)
     if (Result)
     {
     {
-      SendMessage(Control->Handle, WM_MOUSEWHEEL, WParam, LParam);
+      TCustomForm * Form = ValidParentForm(Control);
+      Result = (Form == this);
+      if (Result)
+      {
+        SendMessage(Control->Handle, WM_MOUSEWHEEL, WParam, LParam);
+      }
     }
     }
   }
   }
   return Result;
   return Result;

+ 1 - 0
source/forms/CustomScpExplorer.dfm

@@ -106,6 +106,7 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
       OnHistoryChange = DirViewHistoryChange
       OnHistoryChange = DirViewHistoryChange
       OnDisplayProperties = RemoteDirViewDisplayProperties
       OnDisplayProperties = RemoteDirViewDisplayProperties
       OnRead = RemoteDirViewRead
       OnRead = RemoteDirViewRead
+      Items.ItemData = {}
     end
     end
     object RemoteDriveView: TUnixDriveView
     object RemoteDriveView: TUnixDriveView
       Left = 0
       Left = 0

+ 4 - 1
source/forms/FileFind.cpp

@@ -9,6 +9,7 @@
 #include <WinConfiguration.h>
 #include <WinConfiguration.h>
 #include <CoreMain.h>
 #include <CoreMain.h>
 #include <Tools.h>
 #include <Tools.h>
+#include <BaseUtils.hpp>
 #include "FileFind.h"
 #include "FileFind.h"
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma package(smart_init)
@@ -243,7 +244,9 @@ void __fastcall TFileFindDialog::FileFound(TTerminal * /*Terminal*/,
   }
   }
   else
   else
   {
   {
-    Item->SubItems->Add(FormatFloat(L"#,##0", File->Size));
+    Item->SubItems->Add(
+      FormatBytes(File->Size,
+        WinConfiguration->FormatSizeBytes, WinConfiguration->FormatSizeBytes));
   }
   }
   Item->SubItems->Add(UserModificationStr(File->Modification, File->ModificationFmt));
   Item->SubItems->Add(UserModificationStr(File->Modification, File->ModificationFmt));
 
 

+ 1 - 1
source/forms/ImportSessions.cpp

@@ -29,7 +29,7 @@ bool __fastcall DoImportSessionsDialog()
   SessionListsList->Add(PuttyImportSessionList.get());
   SessionListsList->Add(PuttyImportSessionList.get());
   SessionListsList->Add(FilezillaImportSessionList.get());
   SessionListsList->Add(FilezillaImportSessionList.get());
 
 
-  bool ImportKeys = false;
+  bool ImportKeys = true;
   std::auto_ptr<TImportSessionsDialog> ImportSessionsDialog(
   std::auto_ptr<TImportSessionsDialog> ImportSessionsDialog(
     new TImportSessionsDialog(Application, SessionListsList.get()));
     new TImportSessionsDialog(Application, SessionListsList.get()));
 
 

+ 25 - 25
source/forms/LocationProfiles.dfm

@@ -461,7 +461,7 @@ object LocationProfilesDialog: TLocationProfilesDialog
       end
       end
       item
       item
         Background = clWindow
         Background = clWindow
-        Name = 'Closed bookmark folder-stored session folder'
+        Name = 'Opened bookmark folder-stored session folder'
         PngImage.Data = {
         PngImage.Data = {
           89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF
           89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF
           61000000097048597300000EC400000EC401952B0E1B00000A4F694343505068
           61000000097048597300000EC400000EC401952B0E1B00000A4F694343505068
@@ -547,20 +547,23 @@ object LocationProfilesDialog: TLocationProfilesDialog
           058F998FCB860D86EB9E383E3939E23F72FDE9FCA743CF64CF269E17FEA2FECB
           058F998FCB860D86EB9E383E3939E23F72FDE9FCA743CF64CF269E17FEA2FECB
           AE17162F7EF8D5EBD7CED198D1A197F29793BF6D7CA5FDEAC0EB19AFDBC6C2C6
           AE17162F7EF8D5EBD7CED198D1A197F29793BF6D7CA5FDEAC0EB19AFDBC6C2C6
           1EBEC97833315EF456FBEDC177DC771DEFA3DF0F4FE47C207F28FF68F9B1F553
           1EBEC97833315EF456FBEDC177DC771DEFA3DF0F4FE47C207F28FF68F9B1F553
-          D0A7FB93199393FF040398F3FC63332DDB0000010E4944415478DA63FCFFFF3F
-          032580B1A18181C988456E3F906D872677E4DC9F47F640F97FD834C22C66DCDC
-          2C172228C1B3DADA471345C1D12DD719DEBDFC1CE057F378235E0336B5C85DB6
-          F650D21112E34251F0EED53786A33BEE61773603C3319FEA87D63003FEBBFAC8
-          92E4EFDD5B1E33F8563F64841B404EE0A118E05B798624CD9BDB4DD00CC84E65
-          60F87D1D3988C0084A2068A8D8E63927D00CC88C6060F8751FA706748337CF3F
-          8B6640AA1703C39FE7981AFEA3190815DBBCE8329A0189C018F9FB114903B22B
-          B0B860E90D5403EC9C151818FEFDC4125CFF517D00153B74E025AA013EA9E998
-          4EC56A0884B165CE1C14033E01695E52A2F13FC3FF2F7ED58FC07A1829CE8D94
-          1A000054D89AE168C695320000000049454E44AE426082}
+          D0A7FB93199393FF040398F3FC63332DDB000001694944415478DA63FCFFFF3F
+          032580B1A18181C988456E3F906D872677E8DC9F478E40F97F780DD8DC2C1722
+          28C9BFDA3AC00045E2E8860B0CEF5E7C08F0AB79BC11AF019B5AE4AE5AFBEA68
+          0949F0A148BC7BF189E1E8E62BB8F41DF1AB79640B33E0BF6B883649FEDEBDE6
+          2A03D00046B801BE09862419B079C1793403E274182E9F7CC6F0F0D63B061223
+          E515C40B41CA0CA70E7F63B04BD94CB4CEFFFFBE336CEDB67F063640DF4C94E1
+          F3571E066D730506863F6F80EE02B98E114223B391E847B7DF305C3A74771ED8
+          0051090E06157D35061151A0FBFFFFC2A909993EB9E71EC3EBC79FBDC106B0B2
+          3133B8046A3130337E81C42D4C210ECDFFFE3230EC587DF3C7BF1FBF84C10648
+          4A7232A8A8F2026DFF0355C8806400030A0DA2BE7EFFCB70F6E4DB1D7E350F3D
+          C1069839DB3088C92921D904338001C14712BF75E618C3ED0B57337D6B1ECF60
+          DCD42CF71A28264252E431307C67FBF34FC6A3E1C93B468A7323A5060000367C
+          916AA60EF9940000000049454E44AE426082}
       end
       end
       item
       item
         Background = clWindow
         Background = clWindow
-        Name = 'Opened bookmark folder-stored session folder'
+        Name = 'Closed bookmark folder-stored session folder'
         PngImage.Data = {
         PngImage.Data = {
           89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF
           89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF
           61000000097048597300000EC400000EC401952B0E1B00000A4F694343505068
           61000000097048597300000EC400000EC401952B0E1B00000A4F694343505068
@@ -646,19 +649,16 @@ object LocationProfilesDialog: TLocationProfilesDialog
           058F998FCB860D86EB9E383E3939E23F72FDE9FCA743CF64CF269E17FEA2FECB
           058F998FCB860D86EB9E383E3939E23F72FDE9FCA743CF64CF269E17FEA2FECB
           AE17162F7EF8D5EBD7CED198D1A197F29793BF6D7CA5FDEAC0EB19AFDBC6C2C6
           AE17162F7EF8D5EBD7CED198D1A197F29793BF6D7CA5FDEAC0EB19AFDBC6C2C6
           1EBEC97833315EF456FBEDC177DC771DEFA3DF0F4FE47C207F28FF68F9B1F553
           1EBEC97833315EF456FBEDC177DC771DEFA3DF0F4FE47C207F28FF68F9B1F553
-          D0A7FB93199393FF040398F3FC63332DDB000001694944415478DA63FCFFFF3F
-          032580B1A18181C988456E3F906D872677E8DC9F478E40F97F780DD8DC2C1722
-          28C9BFDA3AC00045E2E8860B0CEF5E7C08F0AB79BC11AF019B5AE4AE5AFBEA68
-          0949F0A148BC7BF189E1E8E62BB8F41DF1AB79640B33E0BF6B883649FEDEBDE6
-          2A03D00046B801BE09862419B079C1793403E274182E9F7CC6F0F0D63B061223
-          E515C40B41CA0CA70E7F63B04BD94CB4CEFFFFBE336CEDB67F063640DF4C94E1
-          F3571E066D730506863F6F80EE02B98E114223B391E847B7DF305C3A74771ED8
-          0051090E06157D35061151A0FBFFFFC2A909993EB9E71EC3EBC79FBDC106B0B2
-          3133B8046A3130337E81C42D4C210ECDFFFE3230EC587DF3C7BF1FBF84C10648
-          4A7232A8A8F2026DFF0355C8806400030A0DA2BE7EFFCB70F6E4DB1D7E350F3D
-          C1069839DB3088C92921D904338001C14712BF75E618C3ED0B57337D6B1ECF60
-          DCD42CF71A28264252E431307C67FBF34FC6A3E1C93B468A7323A5060000367C
-          916AA60EF9940000000049454E44AE426082}
+          D0A7FB93199393FF040398F3FC63332DDB0000010E4944415478DA63FCFFFF3F
+          032580B1A18181C988456E3F906D872677E4DC9F47F640F97FD834C22C66DCDC
+          2C172228C1B3DADA471345C1D12DD719DEBDFC1CE057F378235E0336B5C85DB6
+          F650D21112E34251F0EED53786A33BEE61773603C3319FEA87D63003FEBBFAC8
+          92E4EFDD5B1E33F8563F64841B404EE0A118E05B798624CD9BDB4DD00CC84E65
+          60F87D1D3988C0084A2068A8D8E63927D00CC88C6060F8751FA706748337CF3F
+          8B6640AA1703C39FE7981AFEA3190815DBBCE8329A0189C018F9FB114903B22B
+          B0B860E90D5403EC9C151818FEFDC4125CFF517D00153B74E025AA013EA9E998
+          4EC56A0884B165CE1C14033E01695E52A2F13FC3FF2F7ED58FC07A1829CE8D94
+          1A000054D89AE168C695320000000049454E44AE426082}
       end>
       end>
     Left = 232
     Left = 232
     Top = 400
     Top = 400

+ 8 - 2
source/forms/Login.cpp

@@ -1063,7 +1063,7 @@ void __fastcall TLoginDialog::UpdateControls()
       EnableControl(IPvGroup, SshProtocol || FtpProtocol);
       EnableControl(IPvGroup, SshProtocol || FtpProtocol);
       EnableControl(IPAutoButton, IPvGroup->Enabled && SshProtocol);
       EnableControl(IPAutoButton, IPvGroup->Enabled && SshProtocol);
 
 
-      // stored sessions sheet
+      // sites sheet
       EnableControl(SessionTree, SessionTree->Items->Count > 0);
       EnableControl(SessionTree, SessionTree->Items->Count > 0);
       if (SitesIncrementalSearchLabel->Visible != !FSitesIncrementalSearch.IsEmpty())
       if (SitesIncrementalSearchLabel->Visible != !FSitesIncrementalSearch.IsEmpty())
       {
       {
@@ -1234,7 +1234,10 @@ void __fastcall TLoginDialog::UpdateControls()
       EnableControl(UtfCombo, (SftpProtocol || FtpProtocol) && EnvironmentSheet->Enabled);
       EnableControl(UtfCombo, (SftpProtocol || FtpProtocol) && EnvironmentSheet->Enabled);
       EnableControl(UtfLabel, UtfCombo->Enabled);
       EnableControl(UtfLabel, UtfCombo->Enabled);
       // should be enabled for fsSFTP (SCP fallback) too, but it would cause confusion
       // should be enabled for fsSFTP (SCP fallback) too, but it would cause confusion
-      EnableControl(TimeDifferenceEdit, ((FtpProtocol || ScpProtocol) && EnvironmentSheet->Enabled));
+      EnableControl(TimeDifferenceEdit,
+        ((FtpProtocol && (ComboAutoSwitchSave(FtpUseMlsdCombo) == asOff)) ||
+         ScpProtocol) &&
+        EnvironmentSheet->Enabled);
       EnableControl(TimeDifferenceLabel, TimeDifferenceEdit->Enabled);
       EnableControl(TimeDifferenceLabel, TimeDifferenceEdit->Enabled);
       EnableControl(TimeDifferenceHoursLabel, TimeDifferenceEdit->Enabled);
       EnableControl(TimeDifferenceHoursLabel, TimeDifferenceEdit->Enabled);
       EnableControl(TimeDifferenceMinutesEdit, TimeDifferenceEdit->Enabled);
       EnableControl(TimeDifferenceMinutesEdit, TimeDifferenceEdit->Enabled);
@@ -1263,6 +1266,9 @@ void __fastcall TLoginDialog::UpdateControls()
 
 
       // environment/ftp
       // environment/ftp
       FtpSheet->Enabled = Advanced && FtpProtocol;
       FtpSheet->Enabled = Advanced && FtpProtocol;
+      EnableControl(FtpListAllCombo,
+        (ComboAutoSwitchSave(FtpUseMlsdCombo) == asOff));
+      EnableControl(FtpListAllLabel, FtpListAllCombo->Enabled);
       EnableControl(FtpForcePasvIpCombo,
       EnableControl(FtpForcePasvIpCombo,
         FtpPasvModeCheck->Checked &&
         FtpPasvModeCheck->Checked &&
         (IPAutoButton->Checked || IPv4Button->Checked));
         (IPAutoButton->Checked || IPv4Button->Checked));

+ 11 - 8
source/forms/Login.dfm

@@ -355,7 +355,7 @@ object LoginDialog: TLoginDialog
       object SessionListSheet: TTabSheet
       object SessionListSheet: TTabSheet
         Tag = 2
         Tag = 2
         HelpType = htKeyword
         HelpType = htKeyword
-        HelpKeyword = 'ui_login_stored_sessions'
+        HelpKeyword = 'ui_login_sites'
         Caption = 'Sites'
         Caption = 'Sites'
         TabVisible = False
         TabVisible = False
         DesignSize = (
         DesignSize = (
@@ -1173,9 +1173,9 @@ object LoginDialog: TLoginDialog
             Caption = 'Post login &commands:'
             Caption = 'Post login &commands:'
             FocusControl = PostLoginCommandsMemo
             FocusControl = PostLoginCommandsMemo
           end
           end
-          object Label5: TLabel
+          object FtpListAllLabel: TLabel
             Left = 12
             Left = 12
-            Top = 102
+            Top = 126
             Width = 159
             Width = 159
             Height = 13
             Height = 13
             Caption = '&Support for listing of hidden files:'
             Caption = '&Support for listing of hidden files:'
@@ -1183,7 +1183,7 @@ object LoginDialog: TLoginDialog
           end
           end
           object Label24: TLabel
           object Label24: TLabel
             Left = 12
             Left = 12
-            Top = 126
+            Top = 102
             Width = 188
             Width = 188
             Height = 13
             Height = 13
             Caption = 'Use &MLSD command for directory listing'
             Caption = 'Use &MLSD command for directory listing'
@@ -1208,12 +1208,13 @@ object LoginDialog: TLoginDialog
           end
           end
           object FtpListAllCombo: TComboBox
           object FtpListAllCombo: TComboBox
             Left = 272
             Left = 272
-            Top = 97
+            Top = 121
             Width = 61
             Width = 61
             Height = 21
             Height = 21
             Style = csDropDownList
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
             Anchors = [akLeft, akTop, akRight]
-            TabOrder = 1
+            TabOrder = 2
+            OnChange = DataChange
           end
           end
           object FtpForcePasvIpCombo: TComboBox
           object FtpForcePasvIpCombo: TComboBox
             Left = 272
             Left = 272
@@ -1223,15 +1224,17 @@ object LoginDialog: TLoginDialog
             Style = csDropDownList
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
             Anchors = [akLeft, akTop, akRight]
             TabOrder = 3
             TabOrder = 3
+            OnChange = DataChange
           end
           end
           object FtpUseMlsdCombo: TComboBox
           object FtpUseMlsdCombo: TComboBox
             Left = 272
             Left = 272
-            Top = 121
+            Top = 97
             Width = 61
             Width = 61
             Height = 21
             Height = 21
             Style = csDropDownList
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
             Anchors = [akLeft, akTop, akRight]
-            TabOrder = 2
+            TabOrder = 1
+            OnChange = DataChange
           end
           end
         end
         end
       end
       end

+ 1 - 1
source/forms/Login.h

@@ -279,7 +279,7 @@ __published:
   TMemo *PostLoginCommandsMemo;
   TMemo *PostLoginCommandsMemo;
   TLabel *BugMaxPkt2Label;
   TLabel *BugMaxPkt2Label;
   TComboBox *BugMaxPkt2Combo;
   TComboBox *BugMaxPkt2Combo;
-  TLabel *Label5;
+  TLabel *FtpListAllLabel;
   TComboBox *FtpListAllCombo;
   TComboBox *FtpListAllCombo;
   TComboBox *FtpForcePasvIpCombo;
   TComboBox *FtpForcePasvIpCombo;
   TLabel *Label22;
   TLabel *Label22;

+ 294 - 40
source/forms/MessageDlg.cpp

@@ -23,25 +23,34 @@ public:
 
 
 protected:
 protected:
   __fastcall TMessageForm(TComponent * AOwner);
   __fastcall TMessageForm(TComponent * AOwner);
+  virtual __fastcall ~TMessageForm();
 
 
   DYNAMIC void __fastcall KeyDown(Word & Key, TShiftState Shift);
   DYNAMIC void __fastcall KeyDown(Word & Key, TShiftState Shift);
+  DYNAMIC void __fastcall KeyUp(Word & Key, TShiftState Shift);
   UnicodeString __fastcall GetFormText();
   UnicodeString __fastcall GetFormText();
   virtual void __fastcall CreateParams(TCreateParams & Params);
   virtual void __fastcall CreateParams(TCreateParams & Params);
   DYNAMIC void __fastcall DoShow();
   DYNAMIC void __fastcall DoShow();
   virtual void __fastcall Dispatch(void * Message);
   virtual void __fastcall Dispatch(void * Message);
+  void __fastcall MenuItemClick(TObject * Sender);
+  void __fastcall ButtonDropDownClick(TObject * Sender);
+  void __fastcall UpdateForShiftStateTimer(TObject * Sender);
 
 
 private:
 private:
   TLabel * Message;
   TLabel * Message;
   TMemo * MessageMemo;
   TMemo * MessageMemo;
+  TShiftState FShiftState;
+  TTimer * FUpdateForShiftStateTimer;
 
 
   void __fastcall HelpButtonClick(TObject * Sender);
   void __fastcall HelpButtonClick(TObject * Sender);
   void __fastcall CMDialogKey(TWMKeyDown & Message);
   void __fastcall CMDialogKey(TWMKeyDown & Message);
+  void __fastcall UpdateForShiftState();
 };
 };
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TMessageForm::TMessageForm(TComponent * AOwner) : TForm(AOwner, 0)
 __fastcall TMessageForm::TMessageForm(TComponent * AOwner) : TForm(AOwner, 0)
 {
 {
   Message = NULL;
   Message = NULL;
   MessageMemo = NULL;
   MessageMemo = NULL;
+  FUpdateForShiftStateTimer = NULL;
   TNonClientMetrics NonClientMetrics;
   TNonClientMetrics NonClientMetrics;
   NonClientMetrics.cbSize = sizeof(NonClientMetrics);
   NonClientMetrics.cbSize = sizeof(NonClientMetrics);
   if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &NonClientMetrics, 0))
   if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &NonClientMetrics, 0))
@@ -52,6 +61,11 @@ __fastcall TMessageForm::TMessageForm(TComponent * AOwner) : TForm(AOwner, 0)
   UseSystemSettingsPre(this);
   UseSystemSettingsPre(this);
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+__fastcall TMessageForm::~TMessageForm()
+{
+  SAFE_DESTROY(FUpdateForShiftStateTimer);
+}
+//---------------------------------------------------------------------------
 void __fastcall TMessageForm::HelpButtonClick(TObject * /*Sender*/)
 void __fastcall TMessageForm::HelpButtonClick(TObject * /*Sender*/)
 {
 {
   if (HelpKeyword != HELP_NONE)
   if (HelpKeyword != HELP_NONE)
@@ -69,12 +83,91 @@ void __fastcall TMessageForm::HelpButtonClick(TObject * /*Sender*/)
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+void __fastcall TMessageForm::UpdateForShiftState()
+{
+
+  TShiftState ShiftState =
+    KeyboardStateToShiftState() *
+    (TShiftState() << ssShift << ssCtrl << ssAlt);
+
+  if (FShiftState != ShiftState)
+  {
+    FShiftState = ShiftState;
+
+    for (int ComponentIndex = 0; ComponentIndex < ComponentCount - 1; ComponentIndex++)
+    {
+      TButton * Button = dynamic_cast<TButton*>(Components[ComponentIndex]);
+      if ((Button != NULL) && (Button->DropDownMenu != NULL))
+      {
+        TMenuItem * MenuItems = Button->DropDownMenu->Items;
+        for (int ItemIndex = 0; ItemIndex < MenuItems->Count; ItemIndex++)
+        {
+          TMenuItem * Item = MenuItems->Items[ItemIndex];
+          TShiftState GrouppedShiftState(Item->Tag >> 16);
+          if (Item->Enabled &&
+              ((ShiftState.Empty() && Item->Default) ||
+               (!ShiftState.Empty() && (ShiftState == GrouppedShiftState))))
+          {
+            int From = 1;
+            Button->Caption = CopyToChars(Item->Caption, From, L"\t", false);
+            Button->ModalResult = Item->Tag & 0xFFFF;
+            assert(Button->OnClick == NULL);
+            assert(Item->OnClick == MenuItemClick);
+            break;
+          }
+        }
+      }
+    }
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TMessageForm::KeyUp(Word & Key, TShiftState Shift)
+{
+
+  UpdateForShiftState();
+
+  TForm::KeyUp(Key, Shift);
+}
+//---------------------------------------------------------------------------
 void __fastcall TMessageForm::KeyDown(Word & Key, TShiftState Shift)
 void __fastcall TMessageForm::KeyDown(Word & Key, TShiftState Shift)
 {
 {
   if (Shift.Contains(ssCtrl) && (Key == L'C'))
   if (Shift.Contains(ssCtrl) && (Key == L'C'))
   {
   {
     CopyToClipboard(GetFormText());
     CopyToClipboard(GetFormText());
   }
   }
+  else
+  {
+    if (!Shift.Contains(ssCtrl))
+    {
+      for (int ComponentIndex = 0; ComponentIndex < ComponentCount - 1; ComponentIndex++)
+      {
+        TButton * Button = dynamic_cast<TButton*>(Components[ComponentIndex]);
+        if ((Button != NULL) && (Button->DropDownMenu != NULL))
+        {
+          TMenuItem * MenuItems = Button->DropDownMenu->Items;
+          for (int ItemIndex = 0; ItemIndex < MenuItems->Count; ItemIndex++)
+          {
+            TMenuItem * Item = MenuItems->Items[ItemIndex];
+            if (IsAccel(Key, MenuItems->Items[ItemIndex]->Caption))
+            {
+              Item->OnClick(Item);
+              Key = 0;
+              break;
+            }
+          }
+        }
+
+        if (Key == 0)
+        {
+          break;
+        }
+      }
+    }
+
+    UpdateForShiftState();
+
+    TForm::KeyDown(Key, Shift);
+  }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 UnicodeString __fastcall TMessageForm::GetFormText()
 UnicodeString __fastcall TMessageForm::GetFormText()
@@ -113,7 +206,38 @@ void __fastcall TMessageForm::CMDialogKey(TWMKeyDown & Message)
   {
   {
     OnKeyDown(this, Message.CharCode, KeyDataToShiftState(Message.KeyData));
     OnKeyDown(this, Message.CharCode, KeyDataToShiftState(Message.KeyData));
   }
   }
-  TForm::Dispatch(&Message);
+
+  if (Message.CharCode == VK_MENU)
+  {
+    bool AnyButtonWithGrouppedCommandsWithShiftState = false;
+    for (int ComponentIndex = 0; ComponentIndex < ComponentCount - 1; ComponentIndex++)
+    {
+      TButton * Button = dynamic_cast<TButton*>(Components[ComponentIndex]);
+      if ((Button != NULL) && (Button->DropDownMenu != NULL))
+      {
+        // we should check if there are any commands with shift state,
+        // but it's bit overkill
+        AnyButtonWithGrouppedCommandsWithShiftState = true;
+        break;
+      }
+    }
+
+    // this is to make Alt only alter button meaning (if there is any
+    // alternable button) and not popup system menu
+    if (AnyButtonWithGrouppedCommandsWithShiftState)
+    {
+      Message.Result = 1;
+      UpdateForShiftState();
+    }
+    else
+    {
+      TForm::Dispatch(&Message);
+    }
+  }
+  else
+  {
+    TForm::Dispatch(&Message);
+  }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TMessageForm::Dispatch(void * Message)
 void __fastcall TMessageForm::Dispatch(void * Message)
@@ -146,6 +270,32 @@ void __fastcall TMessageForm::DoShow()
   TForm::DoShow();
   TForm::DoShow();
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+void __fastcall TMessageForm::MenuItemClick(TObject * Sender)
+{
+  TMenuItem * Item = NOT_NULL(dynamic_cast<TMenuItem *>(Sender));
+  ModalResult = (Item->Tag & 0xFFFF);
+}
+//---------------------------------------------------------------------------
+void __fastcall TMessageForm::UpdateForShiftStateTimer(TObject * /*Sender*/)
+{
+  // this is needed to reflect shift state, even when we do not have a keyboard
+  // focus, what happens when drop down menu is popped up
+  UpdateForShiftState();
+}
+//---------------------------------------------------------------------------
+void __fastcall TMessageForm::ButtonDropDownClick(TObject * /*Sender*/)
+{
+  // as optimization, do not waste time running timer, unless
+  // user pops up drop down menu. we do not have a way to stop timer, once
+  // it closes, but functionaly is does not matter
+  if (FUpdateForShiftStateTimer == NULL)
+  {
+    FUpdateForShiftStateTimer = new TTimer(this);
+    FUpdateForShiftStateTimer->Interval = 50;
+    FUpdateForShiftStateTimer->OnTimer = UpdateForShiftStateTimer;
+  }
+}
+//---------------------------------------------------------------------------
 const ResourceString * Captions[] = { &_SMsgDlgWarning, &_SMsgDlgError, &_SMsgDlgInformation,
 const ResourceString * Captions[] = { &_SMsgDlgWarning, &_SMsgDlgError, &_SMsgDlgInformation,
   &_SMsgDlgConfirm, NULL };
   &_SMsgDlgConfirm, NULL };
 const wchar_t * IconIDs[] = { IDI_EXCLAMATION, IDI_HAND, IDI_ASTERISK,
 const wchar_t * IconIDs[] = { IDI_EXCLAMATION, IDI_HAND, IDI_ASTERISK,
@@ -154,9 +304,13 @@ const int ButtonCount = 11;
 const UnicodeString ButtonNames[ButtonCount] = {
 const UnicodeString ButtonNames[ButtonCount] = {
   L"Yes", L"No", L"OK", L"Cancel", L"Abort", L"Retry", L"Ignore", L"All", L"NoToAll",
   L"Yes", L"No", L"OK", L"Cancel", L"Abort", L"Retry", L"Ignore", L"All", L"NoToAll",
   L"YesToAll", L"Help" };
   L"YesToAll", L"Help" };
+// Own variant to avoid accelerator conflict with "Abort" button.
+// Note that as of now, ALL_BUTTON is never actually used, because it's always aliased
+ResourceString MsgDlgAll = { NULL, ALL_BUTTON };
+ResourceString MsgDlgYesToAll = { NULL, YES_TO_ALL_BUTTON };
 const ResourceString * ButtonCaptions[ButtonCount] = {
 const ResourceString * ButtonCaptions[ButtonCount] = {
   &_SMsgDlgYes, &_SMsgDlgNo, &_SMsgDlgOK, &_SMsgDlgCancel, &_SMsgDlgAbort,
   &_SMsgDlgYes, &_SMsgDlgNo, &_SMsgDlgOK, &_SMsgDlgCancel, &_SMsgDlgAbort,
-  &_SMsgDlgRetry, &_SMsgDlgIgnore, &_SMsgDlgAll, &_SMsgDlgNoToAll, &_SMsgDlgYesToAll,
+  &_SMsgDlgRetry, &_SMsgDlgIgnore, &MsgDlgAll, &_SMsgDlgNoToAll, &MsgDlgYesToAll,
   &_SMsgDlgHelp };
   &_SMsgDlgHelp };
 extern const int ModalResults[ButtonCount] = {
 extern const int ModalResults[ButtonCount] = {
   mrYes, mrNo, mrOk, mrCancel, mrAbort, mrRetry, mrIgnore, mrAll, mrNoToAll,
   mrYes, mrNo, mrOk, mrCancel, mrAbort, mrRetry, mrIgnore, mrAll, mrNoToAll,
@@ -171,6 +325,22 @@ const int mcButtonSpacing = 4;
 const int mcMoreMessageWidth = 320;
 const int mcMoreMessageWidth = 320;
 const int mcMoreMessageHeight = 80;
 const int mcMoreMessageHeight = 80;
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+static UnicodeString __fastcall GetKeyNameStr(int Key)
+{
+  wchar_t Buf[MAX_PATH];
+  LONG VirtualKey = MapVirtualKey(Key, MAPVK_VK_TO_VSC);
+  VirtualKey <<= 16;
+  if (GetKeyNameText(VirtualKey, Buf, LENOF(Buf)) > 0)
+  {
+    Buf[LENOF(Buf) - 1] = L'\0';
+  }
+  else
+  {
+    Buf[0] = L'\0';
+  }
+  return Buf;
+}
+//---------------------------------------------------------------------------
 TForm * __fastcall TMessageForm::Create(const UnicodeString & Msg,
 TForm * __fastcall TMessageForm::Create(const UnicodeString & Msg,
   TStrings * MoreMessages, TMsgDlgType DlgType, TMsgDlgButtons Buttons,
   TStrings * MoreMessages, TMsgDlgType DlgType, TMsgDlgButtons Buttons,
   TQueryButtonAlias * Aliases, unsigned int AliasesCount,
   TQueryButtonAlias * Aliases, unsigned int AliasesCount,
@@ -228,46 +398,44 @@ TForm * __fastcall TMessageForm::Create(const UnicodeString & Msg,
   int ButtonWidth = MulDiv(mcButtonWidth, DialogUnits.x, 4);
   int ButtonWidth = MulDiv(mcButtonWidth, DialogUnits.x, 4);
   TButton * ButtonControls[ButtonCount + 1];
   TButton * ButtonControls[ButtonCount + 1];
   int ButtonControlsCount = 0;
   int ButtonControlsCount = 0;
+  typedef std::map<unsigned int, TButton *> TAnswerButtons;
+  TAnswerButtons AnswerButtons;
   for (unsigned int B = mbYes; B <= mbHelp; B++)
   for (unsigned int B = mbYes; B <= mbHelp; B++)
   {
   {
     assert(B < ButtonCount);
     assert(B < ButtonCount);
     if (Buttons.Contains(TMsgDlgBtn(B)))
     if (Buttons.Contains(TMsgDlgBtn(B)))
     {
     {
       TextRect = Rect(0,0,0,0);
       TextRect = Rect(0,0,0,0);
-      UnicodeString Caption = LoadResourceString(ButtonCaptions[B]);
-
-      // temporary fix of accelerators (&Abort vs. &All/Yes to &All)
-      // must be removed
-      if (Caption == L"&All")
-      {
-        Caption = L"A&ll";
-      }
-      else if (Caption == L"Yes to &All")
-      {
-        Caption = L"Yes to A&ll";
-      }
+      const ResourceString * CaptionResource = ButtonCaptions[B];
+      UnicodeString Caption = LoadStr(CaptionResource->Identifier);
 
 
       TNotifyEvent OnClick = NULL;
       TNotifyEvent OnClick = NULL;
+      int GroupWith = -1;
+      TShiftState GrouppedShiftState;
       if (Aliases != NULL)
       if (Aliases != NULL)
       {
       {
         for (unsigned int i = 0; i < AliasesCount; i++)
         for (unsigned int i = 0; i < AliasesCount; i++)
         {
         {
           if (B == Aliases[i].Button)
           if (B == Aliases[i].Button)
           {
           {
-            Caption = Aliases[i].Alias;
+            if (!Aliases[i].Alias.IsEmpty())
+            {
+              Caption = Aliases[i].Alias;
+            }
             OnClick = Aliases[i].OnClick;
             OnClick = Aliases[i].OnClick;
+            GroupWith = Aliases[i].GroupWith;
+            GrouppedShiftState = Aliases[i].GrouppedShiftState;
+            assert((OnClick == NULL) || (GrouppedShiftState == TShiftState()));
             break;
             break;
           }
           }
         }
         }
       }
       }
 
 
-      TButton * Button = new TButton(Result);
-
       UnicodeString MeasureCaption = Caption;
       UnicodeString MeasureCaption = Caption;
-      if ((TimeoutButton != NULL) && (B == static_cast<unsigned int>(TimeoutResult)))
+      bool IsTimeoutButton = (TimeoutButton != NULL) && (B == static_cast<unsigned int>(TimeoutResult));
+      if (IsTimeoutButton)
       {
       {
         MeasureCaption = FMTLOAD(TIMEOUT_BUTTON, (MeasureCaption, 99));
         MeasureCaption = FMTLOAD(TIMEOUT_BUTTON, (MeasureCaption, 99));
-        *TimeoutButton = Button;
       }
       }
 
 
       DrawText(Result->Canvas->Handle,
       DrawText(Result->Canvas->Handle,
@@ -275,35 +443,121 @@ TForm * __fastcall TMessageForm::Create(const UnicodeString & Msg,
         &TextRect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE |
         &TextRect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE |
         Result->DrawTextBiDiModeFlagsReadingOnly());
         Result->DrawTextBiDiModeFlagsReadingOnly());
       int CurButtonWidth = TextRect.Right - TextRect.Left + 8;
       int CurButtonWidth = TextRect.Right - TextRect.Left + 8;
-      if (CurButtonWidth > ButtonWidth)
-      {
-        ButtonWidth = CurButtonWidth;
-      }
 
 
-      Button->Name = ButtonNames[TMsgDlgBtn(B)];
-      Button->Parent = Result;
-      Button->Caption = Caption;
-      if (OnClick != NULL)
+      int ModalResult = ModalResults[B];
+
+      // we hope that all grouped-with buttons are for asnwer with greater
+      // value that the answer to be grouped with
+      if (SupportsSplitButton() &&
+          (GroupWith >= 0) && ALWAYS_TRUE(GroupWith < static_cast<int>(B)) &&
+          ALWAYS_TRUE(AnswerButtons.find(GroupWith) != AnswerButtons.end()) &&
+          ALWAYS_TRUE(B != static_cast<unsigned int>(TimeoutResult)) &&
+          ALWAYS_TRUE(B != static_cast<unsigned int>(DefaultButton)) &&
+          ALWAYS_TRUE(B != static_cast<unsigned int>(CancelButton)))
       {
       {
-        Button->OnClick = OnClick;
+        TButton * GroupWithButton = AnswerButtons[GroupWith];
+
+        if (GroupWithButton->DropDownMenu == NULL)
+        {
+          GroupWithButton->Style = TCustomButton::bsSplitButton;
+          GroupWithButton->DropDownMenu = new TPopupMenu(Result);
+          // cannot handle subitems with shift state,
+          // if the button has its own handler
+          // (though it may not be the case still here)
+          assert(GroupWithButton->OnClick == NULL);
+
+          TMenuItem * Item = new TMenuItem(GroupWithButton->DropDownMenu);
+          GroupWithButton->DropDownMenu->Items->Add(Item);
+          GroupWithButton->OnDropDownClick = Result->ButtonDropDownClick;
+
+          Item->Caption = GroupWithButton->Caption;
+          Item->OnClick = Result->MenuItemClick;
+          assert(GroupWithButton->ModalResult <= 0xFFFF);
+          Item->Tag = GroupWithButton->ModalResult;
+          Item->Default = true;
+        }
+
+        TMenuItem * Item = new TMenuItem(GroupWithButton->DropDownMenu);
+        GroupWithButton->DropDownMenu->Items->Add(Item);
+
+        // See ShortCutToText in Vcl.Menus.pas
+        if (GrouppedShiftState == (TShiftState() << ssAlt))
+        {
+          Caption = Caption + L"\t" + GetKeyNameStr(VK_MENU);
+        }
+        else if (GrouppedShiftState == (TShiftState() << ssCtrl))
+        {
+          Caption = Caption + L"\t" + GetKeyNameStr(VK_CONTROL);
+        }
+        else if (GrouppedShiftState == (TShiftState() << ssShift))
+        {
+          Caption = Caption + L"\t" + GetKeyNameStr(VK_SHIFT);
+        }
+        else
+        {
+          // do not support combined shift states yet
+          assert(GrouppedShiftState == TShiftState());
+        }
+
+        Item->Caption = Caption;
+        if (OnClick != NULL)
+        {
+          Item->OnClick = OnClick;
+        }
+        else
+        {
+          Item->OnClick = Result->MenuItemClick;
+          assert((ModalResult <= 0xFFFF) && (GrouppedShiftState.ToInt() <= 0xFFFF));
+          Item->Tag = ModalResult + (GrouppedShiftState.ToInt() << 16);
+        }
+
+        // Hard-coded drop down button width (do not know how to ask for system width).
+        // Also we do not update the max button width for the default groupped
+        // button caption. We just blindly hope that captions of advanced commands
+        // are always longer than the caption of simple default command
+        CurButtonWidth += 15;
       }
       }
       else
       else
       {
       {
-        Button->ModalResult = ModalResults[B];
-        Button->Default = (B == static_cast<unsigned int>(DefaultButton));
-        Button->Cancel = (B == static_cast<unsigned int>(CancelButton));
-      }
-      if (MoreMessages != NULL)
-      {
-        Button->Anchors = TAnchors() << akBottom << akLeft;
+        TButton * Button = new TButton(Result);
+
+        if (IsTimeoutButton)
+        {
+          *TimeoutButton = Button;
+        }
+
+        Button->Name = ButtonNames[TMsgDlgBtn(B)];
+        Button->Parent = Result;
+        Button->Caption = Caption;
+        if (OnClick != NULL)
+        {
+          Button->OnClick = OnClick;
+        }
+        else
+        {
+          Button->ModalResult = ModalResult;
+          Button->Default = (B == static_cast<unsigned int>(DefaultButton));
+          Button->Cancel = (B == static_cast<unsigned int>(CancelButton));
+        }
+        if (MoreMessages != NULL)
+        {
+          Button->Anchors = TAnchors() << akBottom << akLeft;
+        }
+        if (B == mbHelp)
+        {
+          Button->OnClick = Result->HelpButtonClick;
+        }
+
+        ButtonControls[ButtonControlsCount] = Button;
+        ButtonControlsCount++;
+
+        AnswerButtons.insert(TAnswerButtons::value_type(B, Button));
       }
       }
-      if (B == mbHelp)
+
+      if (CurButtonWidth > ButtonWidth)
       {
       {
-        Button->OnClick = Result->HelpButtonClick;
+        ButtonWidth = CurButtonWidth;
       }
       }
-
-      ButtonControls[ButtonControlsCount] = Button;
-      ButtonControlsCount++;
     }
     }
   }
   }
 
 

+ 4 - 2
source/forms/Preferences.cpp

@@ -315,7 +315,6 @@ void __fastcall TPreferencesDialog::LoadConfiguration()
     QueueCheck->Checked = GUIConfiguration->DefaultCopyParam.Queue;
     QueueCheck->Checked = GUIConfiguration->DefaultCopyParam.Queue;
     QueueIndividuallyCheck->Checked = GUIConfiguration->DefaultCopyParam.QueueIndividually;
     QueueIndividuallyCheck->Checked = GUIConfiguration->DefaultCopyParam.QueueIndividually;
     QueueNoConfirmationCheck->Checked = GUIConfiguration->DefaultCopyParam.QueueNoConfirmation;
     QueueNoConfirmationCheck->Checked = GUIConfiguration->DefaultCopyParam.QueueNoConfirmation;
-    RememberPasswordCheck->Checked = GUIConfiguration->QueueRememberPassword;
     if (!GUIConfiguration->QueueKeepDoneItems)
     if (!GUIConfiguration->QueueKeepDoneItems)
     {
     {
       QueueKeepDoneItemsForCombo->ItemIndex = 0;
       QueueKeepDoneItemsForCombo->ItemIndex = 0;
@@ -444,6 +443,7 @@ void __fastcall TPreferencesDialog::LoadConfiguration()
 
 
     // security
     // security
     UseMasterPasswordCheck->Checked = WinConfiguration->UseMasterPassword;
     UseMasterPasswordCheck->Checked = WinConfiguration->UseMasterPassword;
+    SessionRememberPasswordCheck->Checked = GUIConfiguration->SessionRememberPassword;
 
 
     // network
     // network
     RetrieveExternalIpAddressButton->Checked = Configuration->ExternalIpAddress.IsEmpty();
     RetrieveExternalIpAddressButton->Checked = Configuration->ExternalIpAddress.IsEmpty();
@@ -606,7 +606,6 @@ void __fastcall TPreferencesDialog::SaveConfiguration()
     CopyParam.Queue = QueueCheck->Checked;
     CopyParam.Queue = QueueCheck->Checked;
     CopyParam.QueueIndividually = QueueIndividuallyCheck->Checked;
     CopyParam.QueueIndividually = QueueIndividuallyCheck->Checked;
     CopyParam.QueueNoConfirmation = QueueNoConfirmationCheck->Checked;
     CopyParam.QueueNoConfirmation = QueueNoConfirmationCheck->Checked;
-    GUIConfiguration->QueueRememberPassword = RememberPasswordCheck->Checked;
     GUIConfiguration->QueueKeepDoneItems = (QueueKeepDoneItemsForCombo->ItemIndex != 0);
     GUIConfiguration->QueueKeepDoneItems = (QueueKeepDoneItemsForCombo->ItemIndex != 0);
     switch (QueueKeepDoneItemsForCombo->ItemIndex)
     switch (QueueKeepDoneItemsForCombo->ItemIndex)
     {
     {
@@ -744,6 +743,9 @@ void __fastcall TPreferencesDialog::SaveConfiguration()
       (CustomExternalIpAddressButton->Checked ? CustomExternalIpAddressEdit->Text : UnicodeString());
       (CustomExternalIpAddressButton->Checked ? CustomExternalIpAddressEdit->Text : UnicodeString());
     Configuration->TryFtpWhenSshFails = TryFtpWhenSshFailsCheck->Checked;
     Configuration->TryFtpWhenSshFails = TryFtpWhenSshFailsCheck->Checked;
 
 
+    // security
+    GUIConfiguration->SessionRememberPassword = SessionRememberPasswordCheck->Checked;
+
     #undef BOOLPROP
     #undef BOOLPROP
   }
   }
   __finally
   __finally

+ 22 - 13
source/forms/Preferences.dfm

@@ -1186,7 +1186,7 @@ object PreferencesDialog: TPreferencesDialog
           Left = 8
           Left = 8
           Top = 8
           Top = 8
           Width = 357
           Width = 357
-          Height = 222
+          Height = 200
           Anchors = [akLeft, akTop, akRight]
           Anchors = [akLeft, akTop, akRight]
           Caption = 'Background transfers'
           Caption = 'Background transfers'
           TabOrder = 0
           TabOrder = 0
@@ -1200,7 +1200,7 @@ object PreferencesDialog: TPreferencesDialog
           end
           end
           object QueueKeepDoneItemsCheck: TLabel
           object QueueKeepDoneItemsCheck: TLabel
             Left = 16
             Left = 16
-            Top = 194
+            Top = 172
             Width = 198
             Width = 198
             Height = 13
             Height = 13
             Caption = 'Display completed transfers in queue for:'
             Caption = 'Display completed transfers in queue for:'
@@ -1234,14 +1234,6 @@ object PreferencesDialog: TPreferencesDialog
             Caption = 'Transfer on &background by default'
             Caption = 'Transfer on &background by default'
             TabOrder = 2
             TabOrder = 2
           end
           end
-          object RememberPasswordCheck: TCheckBox
-            Left = 16
-            Top = 170
-            Width = 337
-            Height = 17
-            Caption = 'Remember &password of main session for background transfers'
-            TabOrder = 6
-          end
           object QueueNoConfirmationCheck: TCheckBox
           object QueueNoConfirmationCheck: TCheckBox
             Left = 16
             Left = 16
             Top = 122
             Top = 122
@@ -1268,12 +1260,12 @@ object PreferencesDialog: TPreferencesDialog
           end
           end
           object QueueKeepDoneItemsForCombo: TComboBox
           object QueueKeepDoneItemsForCombo: TComboBox
             Left = 248
             Left = 248
-            Top = 191
+            Top = 169
             Width = 97
             Width = 97
             Height = 21
             Height = 21
             Style = csDropDownList
             Style = csDropDownList
             MaxLength = 1
             MaxLength = 1
-            TabOrder = 7
+            TabOrder = 6
             OnChange = ControlChange
             OnChange = ControlChange
             Items.Strings = (
             Items.Strings = (
               'Never'
               'Never'
@@ -1286,7 +1278,7 @@ object PreferencesDialog: TPreferencesDialog
         end
         end
         object QueueViewGroup: TGroupBox
         object QueueViewGroup: TGroupBox
           Left = 8
           Left = 8
-          Top = 236
+          Top = 214
           Width = 357
           Width = 357
           Height = 99
           Height = 99
           Anchors = [akLeft, akTop, akRight]
           Anchors = [akLeft, akTop, akRight]
@@ -2163,6 +2155,23 @@ object PreferencesDialog: TPreferencesDialog
             OnClick = UseMasterPasswordCheckClick
             OnClick = UseMasterPasswordCheckClick
           end
           end
         end
         end
+        object PasswordGroupBox: TGroupBox
+          Left = 8
+          Top = 106
+          Width = 357
+          Height = 56
+          Anchors = [akLeft, akTop, akRight]
+          Caption = 'Session password'
+          TabOrder = 1
+          object SessionRememberPasswordCheck: TCheckBox
+            Left = 17
+            Top = 24
+            Width = 333
+            Height = 17
+            Caption = 'Remember &password for duration of session'
+            TabOrder = 0
+          end
+        end
       end
       end
       object IntegrationAppSheet: TTabSheet
       object IntegrationAppSheet: TTabSheet
         Tag = 18
         Tag = 18

+ 2 - 1
source/forms/Preferences.h

@@ -104,7 +104,6 @@ __published:
   TCheckBox *QueueAutoPopupCheck;
   TCheckBox *QueueAutoPopupCheck;
   TCheckBox *QueueCheck;
   TCheckBox *QueueCheck;
   TCheckBox *DDAllowMoveInitCheck;
   TCheckBox *DDAllowMoveInitCheck;
-  TCheckBox *RememberPasswordCheck;
   TCheckBox *ConfirmResumeCheck;
   TCheckBox *ConfirmResumeCheck;
   TTabSheet *StorageSheet;
   TTabSheet *StorageSheet;
   TGroupBox *StorageGroup;
   TGroupBox *StorageGroup;
@@ -256,6 +255,8 @@ __published:
   TTabSheet *PanelLocalSheet;
   TTabSheet *PanelLocalSheet;
   TGroupBox *LocalPanelGroup;
   TGroupBox *LocalPanelGroup;
   TCheckBox *SystemContextMenuCheck;
   TCheckBox *SystemContextMenuCheck;
+  TGroupBox *PasswordGroupBox;
+  TCheckBox *SessionRememberPasswordCheck;
   void __fastcall FormShow(TObject *Sender);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall ControlChange(TObject *Sender);
   void __fastcall ControlChange(TObject *Sender);
   void __fastcall EditorFontButtonClick(TObject *Sender);
   void __fastcall EditorFontButtonClick(TObject *Sender);

+ 10 - 5
source/forms/SynchronizeChecklist.cpp

@@ -13,7 +13,8 @@
 
 
 #include <VCLCommon.h>
 #include <VCLCommon.h>
 #include <Tools.h>
 #include <Tools.h>
-#include <CustomWinConfiguration.h>
+#include <BaseUtils.hpp>
+#include <WinConfiguration.h>
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 #pragma link "IEListView"
 #pragma link "IEListView"
 #pragma link "NortonLikeListView"
 #pragma link "NortonLikeListView"
@@ -242,7 +243,9 @@ void __fastcall TSynchronizeChecklistDialog::LoadItem(TListItem * Item)
       }
       }
       else
       else
       {
       {
-        Item->SubItems->Add(FormatFloat(L"#,##0", ChecklistItem->Local.Size));
+        Item->SubItems->Add(
+          FormatBytes(ChecklistItem->Local.Size,
+            WinConfiguration->FormatSizeBytes, WinConfiguration->FormatSizeBytes));
       }
       }
       Item->SubItems->Add(UserModificationStr(ChecklistItem->Local.Modification,
       Item->SubItems->Add(UserModificationStr(ChecklistItem->Local.Modification,
         ChecklistItem->Local.ModificationFmt));
         ChecklistItem->Local.ModificationFmt));
@@ -283,7 +286,9 @@ void __fastcall TSynchronizeChecklistDialog::LoadItem(TListItem * Item)
       }
       }
       else
       else
       {
       {
-        Item->SubItems->Add(FormatFloat(L"#,##0", ChecklistItem->Remote.Size));
+        Item->SubItems->Add(
+          FormatBytes(ChecklistItem->Remote.Size,
+            WinConfiguration->FormatSizeBytes, WinConfiguration->FormatSizeBytes));
       }
       }
       Item->SubItems->Add(UserModificationStr(ChecklistItem->Remote.Modification,
       Item->SubItems->Add(UserModificationStr(ChecklistItem->Remote.Modification,
         ChecklistItem->Remote.ModificationFmt));
         ChecklistItem->Remote.ModificationFmt));
@@ -438,8 +443,8 @@ void __fastcall TSynchronizeChecklistDialog::StatusBarDrawPanel(
   if (Possible)
   if (Possible)
   {
   {
     PanelText = FORMAT(LoadStrPart(SYNCHRONIZE_SELECTED_ACTIONS, 1),
     PanelText = FORMAT(LoadStrPart(SYNCHRONIZE_SELECTED_ACTIONS, 1),
-      (FormatFloat(L"#,##0", FChecked[Panel->Index]),
-       FormatFloat(L"#,##0", FTotals[Panel->Index])));
+      (FormatNumber(FChecked[Panel->Index]),
+       FormatNumber(FTotals[Panel->Index])));
   }
   }
   else
   else
   {
   {

+ 19 - 8
source/packages/my/NortonLikeListView.pas

@@ -643,8 +643,13 @@ var
   PLastSelectMethod: TSelectMethod;
   PLastSelectMethod: TSelectMethod;
   PDontUnSelectItem: Boolean;
   PDontUnSelectItem: Boolean;
   PDontSelectItem: Boolean;
   PDontSelectItem: Boolean;
-  AParent: TWinControl;
+  WParam: UINT_PTR;
+  LParam: INT_PTR;
 begin
 begin
+  // This whole is replacement for mere ItemFocused := Item
+  // because that does not reset some internal focused pointer,
+  // causing subsequent Shift-Click selects range from the first item,
+  // not from focused item.
   Item.MakeVisible(False);
   Item.MakeVisible(False);
   if Focused then
   if Focused then
   begin
   begin
@@ -657,13 +662,19 @@ begin
     FDontUnSelectItem := True;
     FDontUnSelectItem := True;
     FFocusingItem := True;
     FFocusingItem := True;
     try
     try
-      AParent := Parent;
-      P := ClientToScreen(P);
-      while AParent.Parent <> nil do
-        AParent := AParent.Parent;
-      P := AParent.ScreenToClient(P);
-      SendMessage(AParent.Handle, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(P.X, P.Y));
-      SendMessage(AParent.Handle, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(P.X, P.Y));
+      // HACK
+      // WM_LBUTTONDOWN enters loop, waiting for WM_LBUTTONUP,
+      // so we have to post it in advance to break the loop immediately
+
+      // Without MK_CONTROL, if there are more items selected,
+      // they won't get unselected on subsequent focus change
+      // (with explorer-style selection).
+      // And it also makes the click the least obtrusive, affecting the focused
+      // file only.
+      WParam := MK_LBUTTON or MK_CONTROL;
+      LParam := MAKELPARAM(P.X, P.Y);
+      PostMessage(Handle, WM_LBUTTONUP, WParam, LParam);
+      SendMessage(Handle, WM_LBUTTONDOWN, WParam, LParam);
     finally
     finally
       FFocusingItem := False;
       FFocusingItem := False;
       FLastSelectMethod := PLastSelectMethod;
       FLastSelectMethod := PLastSelectMethod;

+ 247 - 13
source/packages/my/PathLabel.pas

@@ -29,6 +29,7 @@ type
     FIsActive: Boolean;
     FIsActive: Boolean;
     FMask: string;
     FMask: string;
     FAutoSizeVertical: Boolean;
     FAutoSizeVertical: Boolean;
+    FAutoHotTrackColors: Boolean;
     procedure CMHintShow(var Message: TMessage); message CM_HINTSHOW;
     procedure CMHintShow(var Message: TMessage); message CM_HINTSHOW;
     procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
     procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
     procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
     procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
@@ -39,6 +40,13 @@ type
     procedure SetUnixPath(AUnixPath: Boolean);
     procedure SetUnixPath(AUnixPath: Boolean);
     procedure SetMask(Value: string);
     procedure SetMask(Value: string);
     procedure SetAutoSizeVertical(Value: Boolean);
     procedure SetAutoSizeVertical(Value: Boolean);
+    procedure SetFocusControl(Value: TWinControl);
+    function GetFocusControl: TWinControl;
+    function HotTrackColorsStored(Index: Integer): Boolean;
+    procedure SetAutoHotTrackColors(Value: Boolean);
+    function CalculateAutoHotTrackColor(C: TColor): TColor;
+    procedure CalculateAutoHotTrackColors;
+    function CalculateAutoHotTrackColorComponent(C: Byte; Bright: Boolean): Byte;
   protected
   protected
     procedure AdjustBounds; override;
     procedure AdjustBounds; override;
     procedure Click; override;
     procedure Click; override;
@@ -47,6 +55,7 @@ type
       Operation: TOperation); override;
       Operation: TOperation); override;
     procedure Paint; override;
     procedure Paint; override;
     function IsActive: Boolean;
     function IsActive: Boolean;
+    function TrackingActive: Boolean;
     function HotTrackPath(Path: string): string;
     function HotTrackPath(Path: string): string;
     procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); override;
     procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); override;
     procedure DoPathClick(Path: string); virtual;
     procedure DoPathClick(Path: string); virtual;
@@ -60,7 +69,7 @@ type
     property ActiveTextColor: TColor index 3 read GetColors write SetColors
     property ActiveTextColor: TColor index 3 read GetColors write SetColors
       default clCaptionText;
       default clCaptionText;
     property ActiveHotTrackColor: TColor index 5 read GetColors write SetColors
     property ActiveHotTrackColor: TColor index 5 read GetColors write SetColors
-      default clGradientActiveCaption;
+      stored HotTrackColorsStored;
     property UnixPath: Boolean read FUnixPath write SetUnixPath default False;
     property UnixPath: Boolean read FUnixPath write SetUnixPath default False;
     property IndentHorizontal: Integer read FIndentHorizontal
     property IndentHorizontal: Integer read FIndentHorizontal
       write SetIndentHorizontal default 5;
       write SetIndentHorizontal default 5;
@@ -71,14 +80,15 @@ type
     property InactiveTextColor: TColor index 2 read GetColors write SetColors
     property InactiveTextColor: TColor index 2 read GetColors write SetColors
       default clInactiveCaptionText;
       default clInactiveCaptionText;
     property InactiveHotTrackColor: TColor index 4 read GetColors write SetColors
     property InactiveHotTrackColor: TColor index 4 read GetColors write SetColors
-      default clGradientInactiveCaption;
+      stored HotTrackColorsStored;
     property OnGetStatus: TPathLabelGetStatusEvent read FOnGetStatus write FOnGetStatus;
     property OnGetStatus: TPathLabelGetStatusEvent read FOnGetStatus write FOnGetStatus;
     property OnPathClick: TPathLabelPathClickEvent read FOnPathClick write FOnPathClick;
     property OnPathClick: TPathLabelPathClickEvent read FOnPathClick write FOnPathClick;
     property HotTrack: Boolean read FHotTrack write FHotTrack default False;
     property HotTrack: Boolean read FHotTrack write FHotTrack default False;
     property Mask: string read FMask write SetMask;
     property Mask: string read FMask write SetMask;
     property AutoSizeVertical: Boolean read FAutoSizeVertical write SetAutoSizeVertical default False;
     property AutoSizeVertical: Boolean read FAutoSizeVertical write SetAutoSizeVertical default False;
+    property AutoHotTrackColors: Boolean read FAutoHotTrackColors write SetAutoHotTrackColors default True;
 
 
-    property FocusControl;
+    property FocusControl: TWinControl read GetFocusControl write SetFocusControl;
     property Caption;
     property Caption;
     property Hint stored False;
     property Hint stored False;
     property Align default alTop;
     property Align default alTop;
@@ -100,6 +110,7 @@ type
     property HotTrack;
     property HotTrack;
     property OnGetStatus;
     property OnGetStatus;
     property OnPathClick;
     property OnPathClick;
+    property AutoHotTrackColors;
 
 
     property Align;
     property Align;
     property Alignment;
     property Alignment;
@@ -155,13 +166,12 @@ begin
   FIndentVertical := 1;
   FIndentVertical := 1;
   FUnixPath := False;
   FUnixPath := False;
   FHotTrack := False;
   FHotTrack := False;
+  FAutoHotTrackColors := True;
   FColors[0] := clInactiveCaption;
   FColors[0] := clInactiveCaption;
   FColors[1] := clActiveCaption;
   FColors[1] := clActiveCaption;
   FColors[2] := clInactiveCaptionText;
   FColors[2] := clInactiveCaptionText;
   FColors[3] := clCaptionText;
   FColors[3] := clCaptionText;
-  FColors[4] := clGradientInactiveCaption;
-  FColors[5] := clGradientActiveCaption;
-  UpdateStatus;
+  CalculateAutoHotTrackColors;
 end;
 end;
 
 
 procedure TCustomPathLabel.CMHintShow(var Message: TMessage);
 procedure TCustomPathLabel.CMHintShow(var Message: TMessage);
@@ -234,10 +244,211 @@ begin
   if FColors[Index] <> Value then
   if FColors[Index] <> Value then
   begin
   begin
     FColors[Index] := Value;
     FColors[Index] := Value;
+
+    if (Index = 4) or (Index = 5) then
+      FAutoHotTrackColors := False
+    else
+      CalculateAutoHotTrackColors;
+
     UpdateStatus;
     UpdateStatus;
   end;
   end;
 end; { SetColors }
 end; { SetColors }
 
 
+function TCustomPathLabel.HotTrackColorsStored(Index: Integer): Boolean;
+begin
+  Result := not AutoHotTrackColors;
+end;
+
+procedure TCustomPathLabel.SetAutoHotTrackColors(Value: Boolean);
+begin
+  if AutoHotTrackColors <> Value then
+  begin
+    FAutoHotTrackColors := Value;
+    CalculateAutoHotTrackColors;
+    UpdateStatus;
+  end;
+end;
+
+// taken from PngImageListEditor
+
+const
+  WeightR: single = 0.764706;
+  WeightG: single = 1.52941;
+  WeightB: single = 0.254902;
+
+function ColorDistance(C1, C2: Integer): Single;
+var
+  DR, DG, DB: Integer;
+begin
+  DR := (C1 and $FF) - (C2 and $FF);
+  Result := Sqr(DR * WeightR);
+  DG := (C1 shr 8 and $FF) - (C2 shr 8 and $FF);
+  Result := Result + Sqr(DG * WeightG);
+  DB := (C1 shr 16) - (C2 shr 16);
+  Result := Result + Sqr(DB * WeightB);
+  Result := Sqrt(Result);
+end;
+
+function GetAdjustedThreshold(BkgndIntensity, Threshold: Single): Single;
+begin
+  if BkgndIntensity < 220 then
+    Result := (2 - BkgndIntensity / 220) * Threshold
+  else
+    Result := Threshold;
+end;
+
+function IsContrastEnough(AColor, ABkgndColor: Integer; DoAdjustThreshold: Boolean; Threshold: Single): Boolean;
+begin
+  if DoAdjustThreshold then
+    Threshold := GetAdjustedThreshold(ColorDistance(ABkgndColor, $000000),
+      Threshold);
+  Result := ColorDistance(ABkgndColor, AColor) > Threshold;
+end;
+
+procedure AdjustContrast(var AColor: Integer; ABkgndColor: Integer; Threshold: Single);
+var
+  X, Y, Z: Single;
+  R, G, B: Single;
+  RR, GG, BB: Integer;
+  I1, I2, S, Q, W: Single;
+  DoInvert: Boolean;
+begin
+  I1 := ColorDistance(AColor, $000000);
+  I2 := ColorDistance(ABkgndColor, $000000);
+  Threshold := GetAdjustedThreshold(I2, Threshold);
+
+  if I1 > I2 then
+    DoInvert := I2 < 442 - Threshold
+  else
+    DoInvert := I2 < Threshold;
+
+  X := (ABkgndColor and $FF) * WeightR;
+  Y := (ABkgndColor shr 8 and $FF) * WeightG;
+  Z := (ABkgndColor shr 16) * WeightB;
+
+  R := (AColor and $FF) * WeightR;
+  G := (AColor shr 8 and $FF) * WeightG;
+  B := (AColor shr 16) * WeightB;
+
+  if DoInvert then begin
+    R := 195 - R;
+    G := 390 - G;
+    B := 65 - B;
+    X := 195 - X;
+    Y := 390 - Y;
+    Z := 65 - Z;
+  end;
+
+  S := Sqrt(Sqr(B) + Sqr(G) + Sqr(R));
+  if S < 0.01 then
+    S := 0.01;
+
+  Q := (R * X + G * Y + B * Z) / S;
+
+  X := Q / S * R - X;
+  Y := Q / S * G - Y;
+  Z := Q / S * B - Z;
+
+  W := Sqrt(Sqr(Threshold) - Sqr(X) - Sqr(Y) - Sqr(Z));
+
+  R := (Q - W) * R / S;
+  G := (Q - W) * G / S;
+  B := (Q - W) * B / S;
+
+  if DoInvert then begin
+    R := 195 - R;
+    G := 390 - G;
+    B := 65 - B;
+  end;
+
+  if R < 0 then
+    R := 0
+  else if R > 195 then
+    R := 195;
+  if G < 0 then
+    G := 0
+  else if G > 390 then
+    G := 390;
+  if B < 0 then
+    B := 0
+  else if B > 65 then
+    B := 65;
+
+  RR := Trunc(R * (1 / WeightR) + 0.5);
+  GG := Trunc(G * (1 / WeightG) + 0.5);
+  BB := Trunc(B * (1 / WeightB) + 0.5);
+
+  if RR > $FF then
+    RR := $FF
+  else if RR < 0 then
+    RR := 0;
+  if GG > $FF then
+    GG := $FF
+  else if GG < 0 then
+    GG := 0;
+  if BB > $FF then
+    BB := $FF
+  else if BB < 0 then
+    BB := 0;
+
+  AColor := (BB and $FF) shl 16 or (GG and $FF) shl 8 or (RR and $FF);
+end;
+
+procedure SetContrast(var Color: TColor; BkgndColor: TColor; Threshold: Integer);
+var
+  T: Single;
+begin
+  if Color < 0 then
+    Color := GetSysColor(Color and $FF);
+  if BkgndColor < 0 then
+    BkgndColor := GetSysColor(BkgndColor and $FF);
+  T := Threshold;
+  if not IsContrastEnough(Color, BkgndColor, True, T) then
+    AdjustContrast(Integer(Color), BkgndColor, T);
+end;
+
+function TCustomPathLabel.CalculateAutoHotTrackColorComponent(C: Byte; Bright: Boolean): Byte;
+var
+  Delta: Byte;
+begin
+  Delta := Max(Round(C * 0.3), 80);
+  if Bright then
+    Result := Byte(Max(Integer(C) - Delta, 0))
+  else
+    Result := Byte(Min(C + Delta, 255));
+end;
+
+function TCustomPathLabel.CalculateAutoHotTrackColor(C: TColor): TColor;
+var
+  R, G, B: Byte;
+  Bright: Boolean;
+begin
+  C := ColorToRGB(C);
+
+  R := GetRValue(C);
+  G := GetGValue(C);
+  B := GetBValue(C);
+
+  Bright := (R + G + B) > (256 / 2 * 3);
+
+  R := CalculateAutoHotTrackColorComponent(R, Bright);
+  G := CalculateAutoHotTrackColorComponent(G, Bright);
+  B := CalculateAutoHotTrackColorComponent(B, Bright);
+
+  Result := RGB(R, G, B);
+end;
+
+procedure TCustomPathLabel.CalculateAutoHotTrackColors;
+begin
+  if AutoHotTrackColors then
+  begin
+    FColors[4] := CalculateAutoHotTrackColor(FColors[2]);
+    SetContrast(FColors[4], FColors[0], 50);
+    FColors[5] := CalculateAutoHotTrackColor(FColors[3]);
+    SetContrast(FColors[5], FColors[1], 50);
+  end;
+end;
+
 procedure TCustomPathLabel.SetIndentHorizontal(AIndent: Integer);
 procedure TCustomPathLabel.SetIndentHorizontal(AIndent: Integer);
 begin
 begin
   if FIndentHorizontal <> AIndent then
   if FIndentHorizontal <> AIndent then
@@ -268,6 +479,20 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TCustomPathLabel.GetFocusControl: TWinControl;
+begin
+  Result := inherited FocusControl;
+end;
+
+procedure TCustomPathLabel.SetFocusControl(Value: TWinControl);
+begin
+  if FocusControl <> Value then
+  begin
+    inherited FocusControl := Value;
+    UpdateStatus;
+  end;
+end;
+
 procedure TCustomPathLabel.DoDrawText(var Rect: TRect; Flags: Longint);
 procedure TCustomPathLabel.DoDrawText(var Rect: TRect; Flags: Longint);
 var
 var
   i: Integer;
   i: Integer;
@@ -375,7 +600,8 @@ begin
     if FDisplayHotTrack <> '' then
     if FDisplayHotTrack <> '' then
     begin
     begin
       StandardColor := Canvas.Font.Color;
       StandardColor := Canvas.Font.Color;
-      Canvas.Font.Color := FColors[4 + Integer(FIsActive)];
+      if TrackingActive then
+        Canvas.Font.Color := FColors[4 + Integer(FIsActive)];
       DrawText(Canvas.Handle, PChar(FDisplayHotTrack), Length(FDisplayHotTrack), Rect, Flags);
       DrawText(Canvas.Handle, PChar(FDisplayHotTrack), Length(FDisplayHotTrack), Rect, Flags);
       Canvas.Font.Color := StandardColor;
       Canvas.Font.Color := StandardColor;
       HotTrackOffset := Canvas.TextWidth(FDisplayHotTrack);
       HotTrackOffset := Canvas.TextWidth(FDisplayHotTrack);
@@ -523,14 +749,22 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TCustomPathLabel.TrackingActive: Boolean;
+begin
+  Result := Assigned(FocusControl) or Assigned(OnGetStatus);
+end;
+
 procedure TCustomPathLabel.UpdateStatus;
 procedure TCustomPathLabel.UpdateStatus;
 begin
 begin
-  FIsActive := IsActive;
-  Color := FColors[Integer(FIsActive)];
-  // We don't want to store Font properties in DFM
-  // which would be if Font.Color is set to something else than clWindowText
-  if not (csDesigning in ComponentState) then
-    Font.Color := FColors[2 + Integer(FIsActive)];
+  if TrackingActive then
+  begin
+    FIsActive := IsActive;
+    Color := FColors[Integer(FIsActive)];
+    // We don't want to store Font properties in DFM
+    // which would be if Font.Color is set to something else than clWindowText
+    if not (csDesigning in ComponentState) then
+      Font.Color := FColors[2 + Integer(FIsActive)];
+  end;
 end; { UpdateStatus }
 end; { UpdateStatus }
 
 
 procedure TCustomPathLabel.Notification(AComponent: TComponent;
 procedure TCustomPathLabel.Notification(AComponent: TComponent;

+ 3 - 3
source/resource/TextsCore.h

@@ -98,7 +98,7 @@
 #define SFTP_STATUS_NO_CONNECTION 168
 #define SFTP_STATUS_NO_CONNECTION 168
 #define SFTP_STATUS_CONNECTION_LOST 169
 #define SFTP_STATUS_CONNECTION_LOST 169
 #define SFTP_STATUS_OP_UNSUPPORTED 170
 #define SFTP_STATUS_OP_UNSUPPORTED 170
-#define SFTP_ERROR_FORMAT2      171
+#define SFTP_ERROR_FORMAT3      171
 #define SFTP_STATUS_UNKNOWN     172
 #define SFTP_STATUS_UNKNOWN     172
 #define READ_SYMLINK_ERROR      173
 #define READ_SYMLINK_ERROR      173
 #define EMPTY_DIRECTORY         174
 #define EMPTY_DIRECTORY         174
@@ -232,8 +232,8 @@
 #define APPEND_OR_RESUME        312
 #define APPEND_OR_RESUME        312
 #define FILE_OVERWRITE_DETAILS  313
 #define FILE_OVERWRITE_DETAILS  313
 #define READ_ONLY_OVERWRITE     314
 #define READ_ONLY_OVERWRITE     314
-#define LOCAL_FILE_OVERWRITE    315
-#define REMOTE_FILE_OVERWRITE   316
+#define LOCAL_FILE_OVERWRITE2   315
+#define REMOTE_FILE_OVERWRITE2  316
 #define TIMEOUT_STILL_WAITING3  321
 #define TIMEOUT_STILL_WAITING3  321
 #define KEX_BELOW_TRESHOLD      322
 #define KEX_BELOW_TRESHOLD      322
 #define RECONNECT_BUTTON        323
 #define RECONNECT_BUTTON        323

+ 4 - 4
source/resource/TextsCore1.rc

@@ -69,7 +69,7 @@ BEGIN
   SFTP_STATUS_NO_CONNECTION, "No connection."
   SFTP_STATUS_NO_CONNECTION, "No connection."
   SFTP_STATUS_CONNECTION_LOST, "Connection lost."
   SFTP_STATUS_CONNECTION_LOST, "Connection lost."
   SFTP_STATUS_OP_UNSUPPORTED, "The server does not support the operation."
   SFTP_STATUS_OP_UNSUPPORTED, "The server does not support the operation."
-  SFTP_ERROR_FORMAT2, "%s\nError code: %d\nError message from server%s: %s\nRequest code: %d"
+  SFTP_ERROR_FORMAT3, "%s\nError code: %d\nError message from server%s: %s"
   SFTP_STATUS_UNKNOWN, "Unknown status code."
   SFTP_STATUS_UNKNOWN, "Unknown status code."
   READ_SYMLINK_ERROR, "Error reading symlink '%s'."
   READ_SYMLINK_ERROR, "Error reading symlink '%s'."
   EMPTY_DIRECTORY, "Server returned empty listing for directory '%s'."
   EMPTY_DIRECTORY, "Server returned empty listing for directory '%s'."
@@ -103,7 +103,7 @@ BEGIN
   SCP_INIT_ERROR, "Cannot execute SCP to start transfer. Please make sure that SCP is installed on the server and path to it is included in PATH. You may also try SFTP instead of SCP."
   SCP_INIT_ERROR, "Cannot execute SCP to start transfer. Please make sure that SCP is installed on the server and path to it is included in PATH. You may also try SFTP instead of SCP."
   DUPLICATE_BOOKMARK, "Location Profile with name '%s' already exists."
   DUPLICATE_BOOKMARK, "Location Profile with name '%s' already exists."
   MOVE_FILE_ERROR, "Error moving file '%s' to '%s'."
   MOVE_FILE_ERROR, "Error moving file '%s' to '%s'."
-  SFTP_PACKET_TOO_BIG_INIT_EXPLAIN, "%s\n \nThe error is typically caused by message printed from startup script (like .profile). The message may start with \"%s\"."
+  SFTP_PACKET_TOO_BIG_INIT_EXPLAIN, "%s\n \nThe error is typically caused by message printed from startup script (like .profile). The message may start with %s."
   PRESERVE_TIME_PERM_ERROR, "Upload of file '%s' was successful, but error occurred while setting the permissions and/or timestamp. If the problem persists, turn on 'Ignore permission errors' option."
   PRESERVE_TIME_PERM_ERROR, "Upload of file '%s' was successful, but error occurred while setting the permissions and/or timestamp. If the problem persists, turn on 'Ignore permission errors' option."
   ACCESS_VIOLATION_ERROR2, "Invalid access to memory. Please report the error on WinSCP support forum."
   ACCESS_VIOLATION_ERROR2, "Invalid access to memory. Please report the error on WinSCP support forum."
   SFTP_STATUS_NO_SPACE_ON_FILESYSTEM, "There is no free space on the filesystem."
   SFTP_STATUS_NO_SPACE_ON_FILESYSTEM, "There is no free space on the filesystem."
@@ -197,8 +197,8 @@ BEGIN
   APPEND_OR_RESUME, "Do you want to append file '%s' at the end of existing file? Press 'No' to resume file transfer instead."
   APPEND_OR_RESUME, "Do you want to append file '%s' at the end of existing file? Press 'No' to resume file transfer instead."
   FILE_OVERWRITE_DETAILS, "%s\n \nNew:      \t%s bytes, %s\nExisting: \t%s bytes, %s"
   FILE_OVERWRITE_DETAILS, "%s\n \nNew:      \t%s bytes, %s\nExisting: \t%s bytes, %s"
   READ_ONLY_OVERWRITE, "File '%s' is read-only. Overwrite?"
   READ_ONLY_OVERWRITE, "File '%s' is read-only. Overwrite?"
-  LOCAL_FILE_OVERWRITE, "Local file '%s' already exists. Overwrite?"
-  REMOTE_FILE_OVERWRITE, "Remote file '%s' already exists. Overwrite?"
+  LOCAL_FILE_OVERWRITE2, "Overwrite local file '%s'?\n\nDestination directory already contains file '%s'.\nChoose, if you want to overwrite the file or skip this transfer and keep existing file."
+  REMOTE_FILE_OVERWRITE2, "Overwrite remote file '%s'?\n\nDestination directory already contains file '%s'.\nChoose, if you want to overwrite the file or skip this transfer and keep existing file."
   TIMEOUT_STILL_WAITING3, "Host is not communicating for more than %d seconds. Still waiting...\n\nNote: If the problem repeats, try turning off 'Optimize connection buffer size'."
   TIMEOUT_STILL_WAITING3, "Host is not communicating for more than %d seconds. Still waiting...\n\nNote: If the problem repeats, try turning off 'Optimize connection buffer size'."
   KEX_BELOW_TRESHOLD, "The first key-exchange algorithm supported by the server is %s, which is below the configured warning threshold.\n\nDo you want to continue with this connection?"
   KEX_BELOW_TRESHOLD, "The first key-exchange algorithm supported by the server is %s, which is below the configured warning threshold.\n\nDo you want to continue with this connection?"
   RECONNECT_BUTTON, "&Reconnect"
   RECONNECT_BUTTON, "&Reconnect"

+ 2 - 0
source/resource/TextsWin.h

@@ -118,6 +118,8 @@
 #define EDITOR_AUTO_CONFIG      1356
 #define EDITOR_AUTO_CONFIG      1356
 #define IMPORT_SESSIONS         1357
 #define IMPORT_SESSIONS         1357
 #define IMPORT_CONFIGURATION    1358
 #define IMPORT_CONFIGURATION    1358
+#define ALL_BUTTON              1359
+#define YES_TO_ALL_BUTTON       1360
 
 
 #define WIN_INFORMATION_STRINGS 1400
 #define WIN_INFORMATION_STRINGS 1400
 #define APP_CAPTION             1401
 #define APP_CAPTION             1401

+ 2 - 0
source/resource/TextsWin1.rc

@@ -119,6 +119,8 @@ BEGIN
         CLOSE_SESSIONS_WORKSPACE, "Terminate all sessions and close application without saving a workspace?\n\nPress 'No' to enable automatic saving of the workspace."
         CLOSE_SESSIONS_WORKSPACE, "Terminate all sessions and close application without saving a workspace?\n\nPress 'No' to enable automatic saving of the workspace."
         IMPORT_SESSIONS, "You have stored sessions/sites in %s.\n\nDo you want to import them into WinSCP?\n\n(You can import them anytime later from Login dialog)|PuTTY SSH client|Filezilla FTP client|%s and %s"
         IMPORT_SESSIONS, "You have stored sessions/sites in %s.\n\nDo you want to import them into WinSCP?\n\n(You can import them anytime later from Login dialog)|PuTTY SSH client|Filezilla FTP client|%s and %s"
         IMPORT_CONFIGURATION, "Importing configuration will overwrite all your preferences and sites.\n\nDo you want to continue?"
         IMPORT_CONFIGURATION, "Importing configuration will overwrite all your preferences and sites.\n\nDo you want to continue?"
+        ALL_BUTTON, "A&ll"
+        YES_TO_ALL_BUTTON, "Yes to A&ll"
 
 
         WIN_INFORMATION_STRINGS, "WIN_INFORMATION"
         WIN_INFORMATION_STRINGS, "WIN_INFORMATION"
         APP_CAPTION, "%s - %s"
         APP_CAPTION, "%s - %s"

+ 2 - 1
source/windows/ConsoleRunner.cpp

@@ -1222,7 +1222,8 @@ void __fastcall TConsoleRunner::ScriptTerminalPromptUser(TTerminal * /*Terminal*
     Print(Prompt);
     Print(Prompt);
 
 
     UnicodeString AResult = Results->Strings[Index]; // useless
     UnicodeString AResult = Results->Strings[Index]; // useless
-    Result = DoInput(AResult, bool(Prompts->Objects[Index]), InputTimeout(), true);
+    bool Echo = FLAGSET(int(Prompts->Objects[Index]), pupEcho);
+    Result = DoInput(AResult, Echo, InputTimeout(), true);
     Results->Strings[Index] = AResult;
     Results->Strings[Index] = AResult;
   }
   }
 }
 }

+ 8 - 14
source/windows/GUIConfiguration.cpp

@@ -554,7 +554,7 @@ void __fastcall TGUIConfiguration::Default()
   FQueueKeepDoneItems = true;
   FQueueKeepDoneItems = true;
   FQueueKeepDoneItemsFor = 15;
   FQueueKeepDoneItemsFor = 15;
   FQueueAutoPopup = true;
   FQueueAutoPopup = true;
-  FQueueRememberPassword = false;
+  FSessionRememberPassword = false;
   UnicodeString ProgramsFolder;
   UnicodeString ProgramsFolder;
   SpecialFolderLocation(CSIDL_PROGRAM_FILES, ProgramsFolder);
   SpecialFolderLocation(CSIDL_PROGRAM_FILES, ProgramsFolder);
   FDefaultPuttyPathOnly = IncludeTrailingBackslash(ProgramsFolder) + L"PuTTY\\putty.exe";
   FDefaultPuttyPathOnly = IncludeTrailingBackslash(ProgramsFolder) + L"PuTTY\\putty.exe";
@@ -610,16 +610,10 @@ void __fastcall TGUIConfiguration::UpdateStaticUsage()
   Usage->Set(L"CopyParamsCount", (FCopyParamListDefaults ? 0 : FCopyParamList->Count));
   Usage->Set(L"CopyParamsCount", (FCopyParamListDefaults ? 0 : FCopyParamList->Count));
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-UnicodeString __fastcall TGUIConfiguration::PropertyToKey(const UnicodeString Property)
-{
-  // no longer useful
-  int P = Property.LastDelimiter(L".>");
-  return Property.SubString(P + 1, Property.Length() - P);
-}
-//---------------------------------------------------------------------------
 // duplicated from core\configuration.cpp
 // duplicated from core\configuration.cpp
 #define BLOCK(KEY, CANCREATE, BLOCK) \
 #define BLOCK(KEY, CANCREATE, BLOCK) \
   if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
   if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
+#define KEY(TYPE, VAR) KEYEX(TYPE, VAR, PropertyToKey(TEXT(#VAR)))
 #define REGCONFIG(CANCREATE) \
 #define REGCONFIG(CANCREATE) \
   BLOCK(L"Interface", CANCREATE, \
   BLOCK(L"Interface", CANCREATE, \
     KEY(Bool,     ContinueOnError); \
     KEY(Bool,     ContinueOnError); \
@@ -633,7 +627,7 @@ UnicodeString __fastcall TGUIConfiguration::PropertyToKey(const UnicodeString Pr
     KEY(Integer,  QueueKeepDoneItems); \
     KEY(Integer,  QueueKeepDoneItems); \
     KEY(Integer,  QueueKeepDoneItemsFor); \
     KEY(Integer,  QueueKeepDoneItemsFor); \
     KEY(Bool,     QueueAutoPopup); \
     KEY(Bool,     QueueAutoPopup); \
-    KEY(Bool,     QueueRememberPassword); \
+    KEYEX(Bool,   SessionRememberPassword, L"QueueRememberPassword"); \
     KEY(String,   PuttySession); \
     KEY(String,   PuttySession); \
     KEY(String,   PuttyPath); \
     KEY(String,   PuttyPath); \
     KEY(Bool,     PuttyPassword); \
     KEY(Bool,     PuttyPassword); \
@@ -651,9 +645,9 @@ void __fastcall TGUIConfiguration::SaveData(THierarchicalStorage * Storage, bool
   TConfiguration::SaveData(Storage, All);
   TConfiguration::SaveData(Storage, All);
 
 
   // duplicated from core\configuration.cpp
   // duplicated from core\configuration.cpp
-  #define KEY(TYPE, VAR) Storage->Write ## TYPE(PropertyToKey(TEXT(#VAR)), VAR)
+  #define KEYEX(TYPE, VAR, NAME) Storage->Write ## TYPE(NAME, VAR)
   REGCONFIG(true);
   REGCONFIG(true);
-  #undef KEY
+  #undef KEYEX
 
 
   if (Storage->OpenSubKey(L"Interface\\CopyParam", true, true))
   if (Storage->OpenSubKey(L"Interface\\CopyParam", true, true))
   try
   try
@@ -692,11 +686,11 @@ void __fastcall TGUIConfiguration::LoadData(THierarchicalStorage * Storage)
   TConfiguration::LoadData(Storage);
   TConfiguration::LoadData(Storage);
 
 
   // duplicated from core\configuration.cpp
   // duplicated from core\configuration.cpp
-  #define KEY(TYPE, VAR) VAR = Storage->Read ## TYPE(PropertyToKey(TEXT(#VAR)), VAR)
+  #define KEYEX(TYPE, VAR, NAME) VAR = Storage->Read ## TYPE(NAME, VAR)
   #pragma warn -eas
   #pragma warn -eas
   REGCONFIG(false);
   REGCONFIG(false);
   #pragma warn +eas
   #pragma warn +eas
-  #undef KEY
+  #undef KEYEX
 
 
   if (Storage->OpenSubKey(L"Interface\\CopyParam", false, true))
   if (Storage->OpenSubKey(L"Interface\\CopyParam", false, true))
   try
   try
@@ -1048,7 +1042,7 @@ void __fastcall TGUIConfiguration::SetDefaultCopyParam(const TGUICopyParamType &
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 bool __fastcall TGUIConfiguration::GetRememberPassword()
 bool __fastcall TGUIConfiguration::GetRememberPassword()
 {
 {
-  return QueueRememberPassword || PuttyPassword;
+  return SessionRememberPassword || PuttyPassword;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 const TCopyParamList * __fastcall TGUIConfiguration::GetCopyParamList()
 const TCopyParamList * __fastcall TGUIConfiguration::GetCopyParamList()

+ 2 - 3
source/windows/GUIConfiguration.h

@@ -160,7 +160,7 @@ private:
   int FMaxWatchDirectories;
   int FMaxWatchDirectories;
   TDateTime FIgnoreCancelBeforeFinish;
   TDateTime FIgnoreCancelBeforeFinish;
   bool FQueueAutoPopup;
   bool FQueueAutoPopup;
-  bool FQueueRememberPassword;
+  bool FSessionRememberPassword;
   int FQueueTransfersLimit;
   int FQueueTransfersLimit;
   bool FQueueKeepDoneItems;
   bool FQueueKeepDoneItems;
   int FQueueKeepDoneItemsFor;
   int FQueueKeepDoneItemsFor;
@@ -196,7 +196,6 @@ protected:
   virtual bool __fastcall GetRememberPassword();
   virtual bool __fastcall GetRememberPassword();
   const TCopyParamList * __fastcall GetCopyParamList();
   const TCopyParamList * __fastcall GetCopyParamList();
   void __fastcall SetCopyParamList(const TCopyParamList * value);
   void __fastcall SetCopyParamList(const TCopyParamList * value);
-  static UnicodeString __fastcall PropertyToKey(const UnicodeString Property);
   virtual void __fastcall DefaultLocalized();
   virtual void __fastcall DefaultLocalized();
   int __fastcall GetCopyParamIndex();
   int __fastcall GetCopyParamIndex();
   TGUICopyParamType __fastcall GetCurrentCopyParam();
   TGUICopyParamType __fastcall GetCurrentCopyParam();
@@ -233,7 +232,7 @@ public:
   __property bool QueueKeepDoneItems = { read = FQueueKeepDoneItems, write = SetQueueKeepDoneItems };
   __property bool QueueKeepDoneItems = { read = FQueueKeepDoneItems, write = SetQueueKeepDoneItems };
   __property int QueueKeepDoneItemsFor = { read = FQueueKeepDoneItemsFor, write = SetQueueKeepDoneItemsFor };
   __property int QueueKeepDoneItemsFor = { read = FQueueKeepDoneItemsFor, write = SetQueueKeepDoneItemsFor };
   __property bool QueueAutoPopup = { read = FQueueAutoPopup, write = FQueueAutoPopup };
   __property bool QueueAutoPopup = { read = FQueueAutoPopup, write = FQueueAutoPopup };
-  __property bool QueueRememberPassword = { read = FQueueRememberPassword, write = FQueueRememberPassword };
+  __property bool SessionRememberPassword = { read = FSessionRememberPassword, write = FSessionRememberPassword };
   __property LCID Locale = { read = GetLocale, write = SetLocale };
   __property LCID Locale = { read = GetLocale, write = SetLocale };
   __property LCID LocaleSafe = { read = GetLocale, write = SetLocaleSafe };
   __property LCID LocaleSafe = { read = GetLocale, write = SetLocaleSafe };
   __property TStrings * Locales = { read = GetLocales };
   __property TStrings * Locales = { read = GetLocales };

+ 4 - 4
source/windows/GUITools.cpp

@@ -92,15 +92,15 @@ void __fastcall OpenSessionInPutty(const UnicodeString PuttyPath,
           {
           {
             if (GUIConfiguration->TelnetForFtpInPutty)
             if (GUIConfiguration->TelnetForFtpInPutty)
             {
             {
-              ExportData->Protocol = ptTelnet;
-              ExportData->PortNumber = 23;
+              ExportData->PuttyProtocol = PuttyTelnetProtocol;
+              ExportData->PortNumber = TelnetPortNumber;
               // PuTTY  does not allow -pw for telnet
               // PuTTY  does not allow -pw for telnet
               Password = L"";
               Password = L"";
             }
             }
             else
             else
             {
             {
-              ExportData->Protocol = ptSSH;
-              ExportData->PortNumber = 22;
+              ExportData->PuttyProtocol = PuttySshProtocol;
+              ExportData->PortNumber = SshPortNumber;
             }
             }
           }
           }
 
 

+ 27 - 8
source/windows/TerminalManager.cpp

@@ -403,6 +403,8 @@ bool __fastcall TTerminalManager::ConnectActiveTerminal()
     Configuration->Usage->Inc(L"OpenedSessionsAdvanced");
     Configuration->Usage->Inc(L"OpenedSessionsAdvanced");
   }
   }
 
 
+  ActiveTerminal->EnableUsage();
+
   // add only stored sessions to the jump list,
   // add only stored sessions to the jump list,
   // ad-hoc session cannot be reproduced from just a session name
   // ad-hoc session cannot be reproduced from just a session name
   if (StoredSessions->FindSame(ActiveTerminal->SessionData) != NULL)
   if (StoredSessions->FindSame(ActiveTerminal->SessionData) != NULL)
@@ -588,6 +590,16 @@ void __fastcall TTerminalManager::SetScpExplorer(TCustomScpExplorerForm * value)
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TTerminalManager::SetActiveTerminal(TTerminal * value)
 void __fastcall TTerminalManager::SetActiveTerminal(TTerminal * value)
+{
+  DoSetActiveTerminal(value, false);
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminalManager::SetActiveTerminalWithAutoReconnect(TTerminal * value)
+{
+  DoSetActiveTerminal(value, true);
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminalManager::DoSetActiveTerminal(TTerminal * value, bool AutoReconnect)
 {
 {
   if (ActiveTerminal != value)
   if (ActiveTerminal != value)
   {
   {
@@ -631,16 +643,23 @@ void __fastcall TTerminalManager::SetActiveTerminal(TTerminal * value)
       {
       {
         UnicodeString Message = FTerminationMessages->Strings[Index];
         UnicodeString Message = FTerminationMessages->Strings[Index];
         FTerminationMessages->Strings[Index] = L"";
         FTerminationMessages->Strings[Index] = L"";
-        Exception * E = new ESshFatal(NULL, Message);
-        try
+        if (AutoReconnect)
         {
         {
-          // finally show pending terminal message,
-          // this gives user also possibility to reconnect
-          ActiveTerminal->ShowExtendedException(E);
+          ReconnectActiveTerminal();
         }
         }
-        __finally
+        else
         {
         {
-          delete E;
+          Exception * E = new ESshFatal(NULL, Message);
+          try
+          {
+            // finally show pending terminal message,
+            // this gives user also possibility to reconnect
+            ActiveTerminal->ShowExtendedException(E);
+          }
+          __finally
+          {
+            delete E;
+          }
         }
         }
       }
       }
     }
     }
@@ -947,7 +966,7 @@ void __fastcall TTerminalManager::TerminalPromptUser(
   {
   {
     assert(Instructions.IsEmpty());
     assert(Instructions.IsEmpty());
     assert(Prompts->Count == 1);
     assert(Prompts->Count == 1);
-    assert(bool(Prompts->Objects[0]));
+    assert(FLAGSET(int(Prompts->Objects[0]), pupEcho));
     UnicodeString AResult = Results->Strings[0];
     UnicodeString AResult = Results->Strings[0];
 
 
     TInputDialogInitialize InputDialogInitialize = NULL;
     TInputDialogInitialize InputDialogInitialize = NULL;

+ 2 - 0
source/windows/TerminalManager.h

@@ -52,6 +52,7 @@ public:
   void __fastcall FreeActiveTerminal();
   void __fastcall FreeActiveTerminal();
   void __fastcall CycleTerminals(bool Forward);
   void __fastcall CycleTerminals(bool Forward);
   static void ConnectTerminal(TTerminal * Terminal, bool Reopen);
   static void ConnectTerminal(TTerminal * Terminal, bool Reopen);
+  void __fastcall SetActiveTerminalWithAutoReconnect(TTerminal * value);
   void __fastcall UpdateAppTitle();
   void __fastcall UpdateAppTitle();
   bool __fastcall CanOpenInPutty();
   bool __fastcall CanOpenInPutty();
   void __fastcall OpenInPutty();
   void __fastcall OpenInPutty();
@@ -103,6 +104,7 @@ private:
   void __fastcall CreateLogMemo();
   void __fastcall CreateLogMemo();
   void __fastcall FreeLogMemo();
   void __fastcall FreeLogMemo();
   void __fastcall SetScpExplorer(TCustomScpExplorerForm * value);
   void __fastcall SetScpExplorer(TCustomScpExplorerForm * value);
+  void __fastcall DoSetActiveTerminal(TTerminal * value, bool AutoReconnect);
   void __fastcall SetActiveTerminal(TTerminal * value);
   void __fastcall SetActiveTerminal(TTerminal * value);
   void __fastcall SetLogMemo(TLogMemo * value);
   void __fastcall SetLogMemo(TLogMemo * value);
   void __fastcall UpdateAll();
   void __fastcall UpdateAll();

+ 31 - 24
source/windows/Tools.cpp

@@ -843,13 +843,39 @@ typedef struct {
 
 
 typedef BOOL (*WINHTTPGETDEFAULTPROXYCONFIGURATION)(WINHTTP_PROXY_INFO * pProxyInfo);
 typedef BOOL (*WINHTTPGETDEFAULTPROXYCONFIGURATION)(WINHTTP_PROXY_INFO * pProxyInfo);
 typedef BOOL (*WINHTTPGETIEPROXYCONFIGFORCURRENTUSER)(
 typedef BOOL (*WINHTTPGETIEPROXYCONFIGFORCURRENTUSER)(
-  WINHTTP_CURRENT_USER_IE_PROXY_CONFIG * pProxyConfig);
+  IN OUT WINHTTP_CURRENT_USER_IE_PROXY_CONFIG * pProxyConfig);
+  WINHTTP_CURRENT_USER_IE_PROXY_CONFIG IEProxyInfo;
+static HMODULE WinHTTP = NULL;
+static WINHTTPGETDEFAULTPROXYCONFIGURATION WinHttpGetDefaultProxyConfiguration = NULL;
+static WINHTTPGETIEPROXYCONFIGFORCURRENTUSER WinHttpGetIEProxyConfigForCurrentUser = NULL;
+//---------------------------------------------------------------------------
+static bool __fastcall GetProxyUrlFromIE(UnicodeString & Proxy)
+{
+  bool Result = false;
+  memset(&IEProxyInfo, 0, sizeof(IEProxyInfo));
+  if ((WinHttpGetIEProxyConfigForCurrentUser != NULL) &&
+      WinHttpGetIEProxyConfigForCurrentUser(&IEProxyInfo))
+  {
+    if (IEProxyInfo.lpszProxy != NULL)
+    {
+      Proxy = IEProxyInfo.lpszProxy;
+      GlobalFree(IEProxyInfo.lpszProxy);
+      Result = true;
+    }
+    if (IEProxyInfo.lpszAutoConfigUrl != NULL)
+    {
+      GlobalFree(IEProxyInfo.lpszAutoConfigUrl);
+    }
+    if (IEProxyInfo.lpszProxyBypass != NULL)
+    {
+      GlobalFree(IEProxyInfo.lpszProxyBypass);
+    }
+  }
+  return Result;
+}
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 bool __fastcall AutodetectProxyUrl(UnicodeString & Proxy)
 bool __fastcall AutodetectProxyUrl(UnicodeString & Proxy)
 {
 {
-  static HMODULE WinHTTP = NULL;
-  static WINHTTPGETDEFAULTPROXYCONFIGURATION WinHttpGetDefaultProxyConfiguration = NULL;
-  static WINHTTPGETIEPROXYCONFIGFORCURRENTUSER WinHttpGetIEProxyConfigForCurrentUser = NULL;
 
 
   bool Result = true;
   bool Result = true;
 
 
@@ -921,26 +947,7 @@ bool __fastcall AutodetectProxyUrl(UnicodeString & Proxy)
        WinHttpGetProxyForUrl() */
        WinHttpGetProxyForUrl() */
     if (!Result)
     if (!Result)
     {
     {
-      WINHTTP_CURRENT_USER_IE_PROXY_CONFIG IEProxyInfo;
-      memset(&IEProxyInfo, 0, sizeof(IEProxyInfo));
-      if ((WinHttpGetIEProxyConfigForCurrentUser != NULL) &&
-          WinHttpGetIEProxyConfigForCurrentUser(&IEProxyInfo))
-      {
-        if (IEProxyInfo.lpszProxy != NULL)
-        {
-          Proxy = IEProxyInfo.lpszProxy;
-          GlobalFree(IEProxyInfo.lpszProxy);
-          Result = true;
-        }
-        if (IEProxyInfo.lpszAutoConfigUrl != NULL)
-        {
-          GlobalFree(IEProxyInfo.lpszAutoConfigUrl);
-        }
-        if (IEProxyInfo.lpszProxyBypass != NULL)
-        {
-          GlobalFree(IEProxyInfo.lpszProxyBypass);
-        }
-      }
+      Result = GetProxyUrlFromIE(Proxy);
     }
     }
 
 
     // We can also use WinHttpGetProxyForUrl, but it is lengthy
     // We can also use WinHttpGetProxyForUrl, but it is lengthy

+ 1 - 1
source/windows/UserInterface.cpp

@@ -89,7 +89,7 @@ void __fastcall FlashOnBackground()
   assert(Application);
   assert(Application);
   if (!ForcedOnForeground && !ForegroundTask())
   if (!ForcedOnForeground && !ForegroundTask())
   {
   {
-    FlashWindow(Application->Handle, true);
+    FlashWindow(Application->MainFormHandle, true);
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------

+ 22 - 4
source/windows/VCLCommon.cpp

@@ -572,6 +572,13 @@ TAutoSwitch __fastcall CheckBoxAutoSwitchSave(TCheckBox * CheckBox)
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+static const wchar_t PathWordDelimiters[] = L"\\/ ;,.";
+//---------------------------------------------------------------------------
+static bool IsPathWordDelimiter(wchar_t Ch)
+{
+  return (wcschr(PathWordDelimiters, Ch) != NULL);
+}
+//---------------------------------------------------------------------------
 // Windows algorithm is as follows (tested on W2k):
 // Windows algorithm is as follows (tested on W2k):
 // right:
 // right:
 //   is_delimiter(current)
 //   is_delimiter(current)
@@ -583,17 +590,22 @@ TAutoSwitch __fastcall CheckBoxAutoSwitchSave(TCheckBox * CheckBox)
 //   right(left(current) + 1)
 //   right(left(current) + 1)
 int CALLBACK PathWordBreakProc(wchar_t * Ch, int Current, int Len, int Code)
 int CALLBACK PathWordBreakProc(wchar_t * Ch, int Current, int Len, int Code)
 {
 {
-  wchar_t Delimiters[] = L"\\/ ;,.";
   int Result;
   int Result;
   UnicodeString ACh(Ch, Len);
   UnicodeString ACh(Ch, Len);
   if (Code == WB_ISDELIMITER)
   if (Code == WB_ISDELIMITER)
   {
   {
     // we return negacy of what WinAPI docs says
     // we return negacy of what WinAPI docs says
-    Result = (wcschr(Delimiters, ACh[Current + 1]) == NULL);
+    Result = !IsPathWordDelimiter(ACh[Current + 1]);
   }
   }
   else if (Code == WB_LEFT)
   else if (Code == WB_LEFT)
   {
   {
-    Result = ACh.SubString(1, Current - 1).LastDelimiter(Delimiters);
+    // skip consecutive delimiters
+    while ((Current > 0) &&
+           IsPathWordDelimiter(ACh[Current]))
+    {
+      Current--;
+    }
+    Result = ACh.SubString(1, Current - 1).LastDelimiter(PathWordDelimiters);
   }
   }
   else if (Code == WB_RIGHT)
   else if (Code == WB_RIGHT)
   {
   {
@@ -604,7 +616,7 @@ int CALLBACK PathWordBreakProc(wchar_t * Ch, int Current, int Len, int Code)
     }
     }
     else
     else
     {
     {
-      const wchar_t * P = wcspbrk(ACh.c_str() + Current - 1, Delimiters);
+      const wchar_t * P = wcspbrk(ACh.c_str() + Current - 1, PathWordDelimiters);
       if (P == NULL)
       if (P == NULL)
       {
       {
         Result = Len;
         Result = Len;
@@ -612,6 +624,12 @@ int CALLBACK PathWordBreakProc(wchar_t * Ch, int Current, int Len, int Code)
       else
       else
       {
       {
         Result = P - ACh.c_str() + 1;
         Result = P - ACh.c_str() + 1;
+        // skip consecutive delimiters
+        while ((Result < Len) &&
+               IsPathWordDelimiter(ACh[Result + 1]))
+        {
+          Result++;
+        }
       }
       }
     }
     }
   }
   }

+ 9 - 9
source/windows/WinConfiguration.cpp

@@ -491,7 +491,7 @@ void __fastcall TWinConfiguration::Default()
   FEditor.FindMatchCase = false;
   FEditor.FindMatchCase = false;
   FEditor.FindWholeWord = false;
   FEditor.FindWholeWord = false;
   FEditor.FindDown = true;
   FEditor.FindDown = true;
-  FEditor.TabSize = 7;
+  FEditor.TabSize = 8;
   FEditor.MaxEditors = 500;
   FEditor.MaxEditors = 500;
   FEditor.EarlyClose = 2; // seconds
   FEditor.EarlyClose = 2; // seconds
   FEditor.SDIShellEditor = false;
   FEditor.SDIShellEditor = false;
@@ -759,14 +759,14 @@ THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool SessionList)
   ELEM.SubString(ELEM.LastDelimiter(L".>")+1, ELEM.Length() - ELEM.LastDelimiter(L".>"))
   ELEM.SubString(ELEM.LastDelimiter(L".>")+1, ELEM.Length() - ELEM.LastDelimiter(L".>"))
 #define BLOCK(KEY, CANCREATE, BLOCK) \
 #define BLOCK(KEY, CANCREATE, BLOCK) \
   if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
   if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
-#define KEY(TYPE, VAR) KEYEX(TYPE, VAR, VAR)
+#define KEY(TYPE, VAR) KEYEX(TYPE, VAR, PropertyToKey(TEXT(#VAR)))
 #define REGCONFIG(CANCREATE) \
 #define REGCONFIG(CANCREATE) \
   BLOCK(L"Interface", CANCREATE, \
   BLOCK(L"Interface", CANCREATE, \
-    KEYEX(Integer,DoubleClickAction, CopyOnDoubleClick); \
+    KEYEX(Integer,DoubleClickAction, L"CopyOnDoubleClick"); \
     KEY(Bool,     CopyOnDoubleClickConfirmation); \
     KEY(Bool,     CopyOnDoubleClickConfirmation); \
     KEY(Bool,     DDAllowMove); \
     KEY(Bool,     DDAllowMove); \
     KEY(Bool,     DDAllowMoveInit); \
     KEY(Bool,     DDAllowMoveInit); \
-    KEYEX(Integer, DDTransferConfirmation, DDTransferConfirmation2); \
+    KEYEX(Integer, DDTransferConfirmation, L"DDTransferConfirmation2"); \
     KEY(String,   DDTemporaryDirectory); \
     KEY(String,   DDTemporaryDirectory); \
     KEY(Bool,     DDWarnLackOfTempSpace); \
     KEY(Bool,     DDWarnLackOfTempSpace); \
     KEY(Float,    DDWarnLackOfTempSpaceRatio); \
     KEY(Float,    DDWarnLackOfTempSpaceRatio); \
@@ -885,7 +885,7 @@ THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool SessionList)
     KEY(Bool,    ScpCommander.SessionsTabs); \
     KEY(Bool,    ScpCommander.SessionsTabs); \
     KEY(Bool,    ScpCommander.StatusBar); \
     KEY(Bool,    ScpCommander.StatusBar); \
     KEY(String,  ScpCommander.WindowParams); \
     KEY(String,  ScpCommander.WindowParams); \
-    KEYEX(Integer, ScpCommander.NortonLikeMode, ExplorerStyleSelection); \
+    KEYEX(Integer, ScpCommander.NortonLikeMode, L"ExplorerStyleSelection"); \
     KEY(Bool,    ScpCommander.PreserveLocalDirectory); \
     KEY(Bool,    ScpCommander.PreserveLocalDirectory); \
     KEY(Bool,    ScpCommander.CompareByTime); \
     KEY(Bool,    ScpCommander.CompareByTime); \
     KEY(Bool,    ScpCommander.CompareBySize); \
     KEY(Bool,    ScpCommander.CompareBySize); \
@@ -912,8 +912,8 @@ THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool SessionList)
     KEY(String,  LogWindowParams); \
     KEY(String,  LogWindowParams); \
   ); \
   ); \
   BLOCK(L"Security", CANCREATE, \
   BLOCK(L"Security", CANCREATE, \
-    KEYEX(Bool,  FUseMasterPassword, UseMasterPassword); \
-    KEYEX(String,FMasterPasswordVerifier, MasterPasswordVerifier); \
+    KEYEX(Bool,  FUseMasterPassword, L"UseMasterPassword"); \
+    KEYEX(String,FMasterPasswordVerifier, L"MasterPasswordVerifier"); \
   );
   );
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TWinConfiguration::SaveData(THierarchicalStorage * Storage, bool All)
 void __fastcall TWinConfiguration::SaveData(THierarchicalStorage * Storage, bool All)
@@ -921,7 +921,7 @@ void __fastcall TWinConfiguration::SaveData(THierarchicalStorage * Storage, bool
   TCustomWinConfiguration::SaveData(Storage, All);
   TCustomWinConfiguration::SaveData(Storage, All);
 
 
   // duplicated from core\configuration.cpp
   // duplicated from core\configuration.cpp
-  #define KEYEX(TYPE, VAR, NAME) Storage->Write ## TYPE(LASTELEM(UnicodeString(TEXT(#NAME))), VAR)
+  #define KEYEX(TYPE, VAR, NAME) Storage->Write ## TYPE(NAME, VAR)
   REGCONFIG(true);
   REGCONFIG(true);
   #undef KEYEX
   #undef KEYEX
 
 
@@ -1019,7 +1019,7 @@ void __fastcall TWinConfiguration::LoadData(THierarchicalStorage * Storage)
   TCustomWinConfiguration::LoadData(Storage);
   TCustomWinConfiguration::LoadData(Storage);
 
 
   // duplicated from core\configuration.cpp
   // duplicated from core\configuration.cpp
-  #define KEYEX(TYPE, VAR, NAME) VAR = Storage->Read ## TYPE(LASTELEM(UnicodeString(TEXT(#NAME))), VAR)
+  #define KEYEX(TYPE, VAR, NAME) VAR = Storage->Read ## TYPE(NAME, VAR)
   #pragma warn -eas
   #pragma warn -eas
   REGCONFIG(false);
   REGCONFIG(false);
   #pragma warn +eas
   #pragma warn +eas

+ 20 - 3
source/windows/WinInterface.cpp

@@ -147,10 +147,21 @@ static void __fastcall NeverAskAgainCheckClick(void * /*Data*/, TObject * Sender
   for (int ii = 0; ii < Dialog->ControlCount; ii++)
   for (int ii = 0; ii < Dialog->ControlCount; ii++)
   {
   {
     TButton * Button = dynamic_cast<TButton *>(Dialog->Controls[ii]);
     TButton * Button = dynamic_cast<TButton *>(Dialog->Controls[ii]);
-    if ((Button != NULL) && (Button->ModalResult != mrNone) &&
-        (Button->ModalResult != mrCancel))
+    if (Button != NULL)
     {
     {
-      Button->Enabled = !CheckBox->Checked || (Button->ModalResult == PositiveAnswer);
+      if ((Button->ModalResult != mrNone) && (Button->ModalResult != mrCancel))
+      {
+        Button->Enabled = !CheckBox->Checked || (Button->ModalResult == PositiveAnswer);
+      }
+
+      if (Button->DropDownMenu != NULL)
+      {
+        for (int iii = 0; iii < Button->DropDownMenu->Items->Count; iii++)
+        {
+          TMenuItem * Item = Button->DropDownMenu->Items->Items[iii];
+          Item->Enabled = Item->Default || !CheckBox->Checked;
+        }
+      }
     }
     }
   }
   }
 }
 }
@@ -268,6 +279,12 @@ TForm * __fastcall CreateMessageDialogEx(const UnicodeString Msg,
         Aliases[i].Button = Button;
         Aliases[i].Button = Button;
         Aliases[i].Alias = Params->Aliases[i].Alias;
         Aliases[i].Alias = Params->Aliases[i].Alias;
         Aliases[i].OnClick = Params->Aliases[i].OnClick;
         Aliases[i].OnClick = Params->Aliases[i].OnClick;
+        if (Params->Aliases[i].GroupWith >= 0)
+        {
+          CHECK(MapButton(Params->Aliases[i].GroupWith, Button));
+          Aliases[i].GroupWith = Button;
+        }
+        Aliases[i].GrouppedShiftState = Params->Aliases[i].GrouppedShiftState;
       }
       }
       Dialog = CreateMoreMessageDialog(Msg, MoreMessages, DlgType, Buttons,
       Dialog = CreateMoreMessageDialog(Msg, MoreMessages, DlgType, Buttons,
         Aliases, Params->AliasesCount, TimeoutResult, &TimeoutButton, ImageName);
         Aliases, Params->AliasesCount, TimeoutResult, &TimeoutButton, ImageName);