Martin Prikryl 10 years ago
parent
commit
4acedf8030
83 changed files with 929 additions and 758 deletions
  1. 0 4
      deployment/winscpsetup.iss
  2. 2 1
      dotnet/Session.cs
  3. 11 2
      dotnet/internal/ExeSessionProcess.cs
  4. 17 3
      dotnet/internal/Logger.cs
  5. 3 3
      dotnet/properties/AssemblyInfo.cs
  6. 14 14
      libs/neon/src/ne_request.c
  7. 2 3
      libs/neon/src/ne_request.h
  8. 4 4
      libs/openssl/crypto/buildinf.h
  9. 1 1
      libs/openssl/crypto/cversion.c
  10. 1 1
      libs/openssl/crypto/ecdsa/ecs_vrf.c
  11. 3 3
      libs/openssl/crypto/opensslv.h
  12. 2 59
      libs/openssl/crypto/rand/rand_win.c
  13. 1 1
      libs/openssl/crypto/x509v3/v3_ncons.c
  14. 3 1
      libs/openssl/e_os.h
  15. 1 1
      source/Console.cbproj
  16. 1 1
      source/DragExt.cbproj
  17. 3 3
      source/DragExt64.rc
  18. 2 3
      source/WinSCP.cbproj
  19. 103 89
      source/components/UnixDirView.cpp
  20. 27 5
      source/core/Configuration.cpp
  21. 6 0
      source/core/Configuration.h
  22. 54 13
      source/core/FtpFileSystem.cpp
  23. 1 0
      source/core/FtpFileSystem.h
  24. 3 0
      source/core/Interface.h
  25. 28 16
      source/core/NamedObjs.cpp
  26. 3 2
      source/core/NamedObjs.h
  27. 43 2
      source/core/Option.cpp
  28. 8 1
      source/core/Option.h
  29. 50 13
      source/core/Script.cpp
  30. 1 0
      source/core/Script.h
  31. 11 0
      source/core/SecureShell.cpp
  32. 23 1
      source/core/SessionData.cpp
  33. 2 1
      source/core/SessionData.h
  34. 43 9
      source/core/SessionInfo.cpp
  35. 2 0
      source/core/SessionInfo.h
  36. 3 2
      source/core/SftpFileSystem.cpp
  37. 15 17
      source/core/WebDAVFileSystem.cpp
  38. 0 2
      source/core/WebDAVFileSystem.h
  39. 14 1
      source/dragext/DragExt.cpp
  40. 6 13
      source/filezilla/ApiLog.cpp
  41. 0 1
      source/filezilla/ApiLog.h
  42. 1 1
      source/filezilla/AsyncSslSocketLayer.cpp
  43. 11 0
      source/filezilla/ControlSocket.cpp
  44. 1 0
      source/filezilla/ControlSocket.h
  45. 4 3
      source/filezilla/FileZillaApi.h
  46. 3 2
      source/filezilla/FileZillaIntf.h
  47. 22 24
      source/filezilla/FtpControlSocket.cpp
  48. 19 23
      source/filezilla/FtpListResult.cpp
  49. 1 1
      source/filezilla/FtpListResult.h
  50. 36 25
      source/filezilla/TransferSocket.cpp
  51. 1 0
      source/filezilla/TransferSocket.h
  52. 39 16
      source/forms/About.cpp
  53. 2 2
      source/forms/About.h
  54. 1 1
      source/forms/Custom.cpp
  55. 24 3
      source/forms/CustomScpExplorer.cpp
  56. 7 7
      source/forms/Editor.dfm
  57. 6 6
      source/forms/GenerateUrl.dfm
  58. 14 0
      source/forms/LocationProfiles.cpp
  59. 1 0
      source/forms/LocationProfiles.h
  60. 33 35
      source/forms/MessageDlg.cpp
  61. 14 0
      source/forms/OpenDirectory.cpp
  62. 1 0
      source/forms/OpenDirectory.h
  63. 7 5
      source/forms/ScpCommander.cpp
  64. 4 4
      source/forms/ScpCommander.dfm
  65. 3 3
      source/forms/ScpExplorer.dfm
  66. 5 2
      source/packages/dragndrop/DragDrop.pas
  67. 5 2
      source/packages/filemng/CustomDirView.pas
  68. 73 283
      source/packages/filemng/DirView.pas
  69. 5 0
      source/putty/windows/WINNET.C
  70. 1 1
      source/resource/Propagation.rc
  71. 2 0
      source/resource/TextsFileZilla.h
  72. 2 0
      source/resource/TextsFileZilla.rc
  73. 1 0
      source/resource/TextsWin.h
  74. 1 0
      source/resource/TextsWin1.rc
  75. 3 3
      source/resource/TextsWin2.rc
  76. 2 0
      source/windows/ConsoleRunner.cpp
  77. 12 7
      source/windows/GUITools.cpp
  78. 1 0
      source/windows/GUITools.h
  79. 5 0
      source/windows/UserInterface.cpp
  80. 1 1
      source/windows/WinConfiguration.cpp
  81. 9 1
      source/windows/WinInterface.cpp
  82. 27 1
      source/windows/WinMain.cpp
  83. 2 0
      source/windows/WinSCP.exe.manifest

+ 0 - 4
deployment/winscpsetup.iss

@@ -1030,10 +1030,6 @@ begin
   if CurPageID = wpLicense then
   if CurPageID = wpLicense then
   begin
   begin
     WizardForm.NextButton.Caption := ExpandConstant('{cm:AcceptButton}')
     WizardForm.NextButton.Caption := ExpandConstant('{cm:AcceptButton}')
-  end
-    else
-  begin
-    WizardForm.NextButton.Caption := SetupMessage(msgButtonNext);
   end;
   end;
 
 
   if CurPageID = wpSelectDir then
   if CurPageID = wpSelectDir then

+ 2 - 1
dotnet/Session.cs

@@ -50,6 +50,7 @@ namespace WinSCP
         public TimeSpan ReconnectTime { get { return _reconnectTime; } set { CheckNotOpened(); _reconnectTime = value; } }
         public TimeSpan ReconnectTime { get { return _reconnectTime; } set { CheckNotOpened(); _reconnectTime = value; } }
         public int ReconnectTimeInMilliseconds { get { return Tools.TimeSpanToMilliseconds(ReconnectTime); } set { ReconnectTime = Tools.MillisecondsToTimeSpan(value); } }
         public int ReconnectTimeInMilliseconds { get { return Tools.TimeSpanToMilliseconds(ReconnectTime); } set { ReconnectTime = Tools.MillisecondsToTimeSpan(value); } }
         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 int DebugLogLevel { get { CheckNotDisposed(); return Logger.LogLevel; } set { CheckNotDisposed(); Logger.LogLevel = 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; } }
         #if DEBUG
         #if DEBUG
@@ -998,7 +999,7 @@ namespace WinSCP
                 string url = head;
                 string url = head;
                 string logUrl = head;
                 string logUrl = head;
 
 
-                if ((sessionOptions.SecurePassword) != null && (sessionOptions.SecurePassword.Length > 0))
+                if (sessionOptions.SecurePassword != null)
                 {
                 {
                     if (!hasUsername)
                     if (!hasUsername)
                     {
                     {

+ 11 - 2
dotnet/internal/ExeSessionProcess.cs

@@ -495,9 +495,18 @@ namespace WinSCP
         {
         {
             using (_logger.CreateCallstack())
             using (_logger.CreateCallstack())
             {
             {
-                _logger.WriteLine("Waiting for process to exit");
+                int timeout;
 
 
-                if (!_process.WaitForExit(1000))
+                #if DEBUG
+                // in debug build, we expect the winscp.exe to run in tracing mode, being very slow
+                timeout = 10000;
+                #else
+                timeout = 2000;
+                #endif
+
+                _logger.WriteLine("Waiting for process to exit ({0} ms)", timeout);
+
+                if (!_process.WaitForExit(timeout))
                 {
                 {
                     _logger.WriteLine("Killing process");
                     _logger.WriteLine("Killing process");
                     _process.Kill();
                     _process.Kill();

+ 17 - 3
dotnet/internal/Logger.cs

@@ -13,6 +13,7 @@ namespace WinSCP
     internal class Logger : IDisposable
     internal class Logger : IDisposable
     {
     {
         public string LogPath { get { return _logPath; } set { SetLogPath(value); } }
         public string LogPath { get { return _logPath; } set { SetLogPath(value); } }
+        public int LogLevel { get { return _logLevel; } set { SetLogLevel(value); } }
         public bool Logging { get { return (_writter != null) && _writter.BaseStream.CanWrite; } }
         public bool Logging { get { return (_writter != null) && _writter.BaseStream.CanWrite; } }
 
 
         public string GetAssemblyFilePath()
         public string GetAssemblyFilePath()
@@ -156,7 +157,7 @@ namespace WinSCP
 
 
         public void WriteCounters()
         public void WriteCounters()
         {
         {
-            if (Logging)
+            if (Logging && (_logLevel >= 1))
             {
             {
                 try
                 try
                 {
                 {
@@ -178,7 +179,7 @@ namespace WinSCP
 
 
         public void WriteProcesses()
         public void WriteProcesses()
         {
         {
-            if (Logging)
+            if (Logging && (_logLevel >= 1))
             {
             {
                 try
                 try
                 {
                 {
@@ -264,7 +265,10 @@ namespace WinSCP
                         _writter = File.CreateText(_logPath);
                         _writter = File.CreateText(_logPath);
                         _writter.AutoFlush = true;
                         _writter.AutoFlush = true;
                         WriteEnvironmentInfo();
                         WriteEnvironmentInfo();
-                        CreateCounters();
+                        if (_logLevel >= 1)
+                        {
+                            CreateCounters();
+                        }
                     }
                     }
                 }
                 }
             }
             }
@@ -289,11 +293,21 @@ namespace WinSCP
             return new Win32Exception(Marshal.GetLastWin32Error()).Message;
             return new Win32Exception(Marshal.GetLastWin32Error()).Message;
         }
         }
 
 
+        private void SetLogLevel(int value)
+        {
+            if ((value < 0) || (value > 1))
+            {
+                throw new ArgumentOutOfRangeException(string.Format(CultureInfo.CurrentCulture, "Logging level has to be in range 0-1"));
+            }
+            _logLevel = value;
+        }
+
         private StreamWriter _writter;
         private StreamWriter _writter;
         private string _logPath;
         private string _logPath;
         private readonly Dictionary<int, int> _indents = new Dictionary<int, int>();
         private readonly Dictionary<int, int> _indents = new Dictionary<int, int>();
         private readonly object _logLock = new object();
         private readonly object _logLock = new object();
         private readonly Lock _lock = new Lock();
         private readonly Lock _lock = new Lock();
         private List<PerformanceCounter> _performanceCounters = new List<PerformanceCounter>();
         private List<PerformanceCounter> _performanceCounters = new List<PerformanceCounter>();
+        private int _logLevel;
     }
     }
 }
 }

+ 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.2.5.0")]
-[assembly: AssemblyFileVersion("1.2.5.0")]
-[assembly: AssemblyInformationalVersionAttribute("5.6.5.0")]
+[assembly: AssemblyVersion("1.2.6.0")]
+[assembly: AssemblyFileVersion("1.2.6.0")]
+[assembly: AssemblyInformationalVersionAttribute("5.7.0.0")]
 
 
 [assembly: CLSCompliant(true)]
 [assembly: CLSCompliant(true)]
 
 

+ 14 - 14
libs/neon/src/ne_request.c

@@ -94,6 +94,10 @@ struct ne_request_s {
     /* Request body. */
     /* Request body. */
     ne_provide_body body_cb;
     ne_provide_body body_cb;
     void *body_ud;
     void *body_ud;
+    #ifdef WINSCP
+    ne_provide_body body_cb_pre;
+    void *body_ud_pre;
+    #endif
 
 
     /* Request body source: file or buffer (if not callback). */
     /* Request body source: file or buffer (if not callback). */
     union {
     union {
@@ -404,7 +408,11 @@ static int send_request_body(ne_request *req, int retry)
         return NE_ERROR;
         return NE_ERROR;
     }
     }
     
     
-    while ((bytes = req->body_cb(req->body_ud, start, buflen)) > 0) {
+    while (
+        #ifdef WINSCP
+        ((req->body_cb_pre == NULL) || ((bytes = req->body_cb_pre(req->body_ud_pre, start, buflen)) > 0)) &&
+        #endif
+        (bytes = req->body_cb(req->body_ud, start, buflen)) > 0) {
         req->session->status.sr.progress += bytes;
         req->session->status.sr.progress += bytes;
         if (chunked) {
         if (chunked) {
             /* Overwrite the buffer prefix with the appropriate chunk
             /* Overwrite the buffer prefix with the appropriate chunk
@@ -590,20 +598,12 @@ void ne_set_request_body_fd(ne_request *req, int fd,
 
 
 #include <assert.h>
 #include <assert.h>
 
 
-void ne_set_request_body_provider_proxy(ne_request *req,
-    ne_provide_body provider, void * ud,
-    ne_provide_body * prev_provider, void ** prev_ud)
+void ne_set_request_body_provider_pre(ne_request *req,
+    ne_provide_body provider, void *ud)
 {
 {
-    if ((req->body_cb != provider) ||
-        (req->body_ud != ud))
-    {
-        assert(*prev_provider == NULL);
-        assert(*prev_ud == NULL);
-        *prev_provider = req->body_cb;
-        *prev_ud = req->body_ud;
-        req->body_cb = provider;
-        req->body_ud = ud;
-    }
+    assert((req->body_cb_pre == NULL) || (req->body_cb_pre == provider));
+    req->body_cb_pre = provider;
+    req->body_ud_pre = ud;
 }
 }
 
 
 int ne_get_request_body_buffer(ne_request *req, const char **buffer,
 int ne_get_request_body_buffer(ne_request *req, const char **buffer,

+ 2 - 3
libs/neon/src/ne_request.h

@@ -85,9 +85,8 @@ void ne_set_request_body_provider(ne_request *req, ne_off_t length,
                                   ne_provide_body provider, void *userdata);
                                   ne_provide_body provider, void *userdata);
 
 
 #ifdef WINSCP
 #ifdef WINSCP
-void ne_set_request_body_provider_proxy(ne_request *req,
-  ne_provide_body provider, void * ud,
-  ne_provide_body * prev_provider, void ** prev_ud);
+void ne_set_request_body_provider_pre(ne_request *req,
+  ne_provide_body provider, void * ud);
 
 
 int ne_get_request_body_buffer(ne_request *req, const char **buffer,
 int ne_get_request_body_buffer(ne_request *req, const char **buffer,
 			       size_t * size);
 			       size_t * size);

+ 4 - 4
libs/openssl/crypto/buildinf.h

@@ -7,13 +7,13 @@
 #endif
 #endif
 #ifdef MK1MF_PLATFORM_VC_WIN32
 #ifdef MK1MF_PLATFORM_VC_WIN32
   /* auto-generated/updated by util/mk1mf.pl for crypto/cversion.c */
   /* auto-generated/updated by util/mk1mf.pl for crypto/cversion.c */
-  #define CFLAGS "cl  /MD /Ox /O2 /Ob2 -DOPENSSL_THREADS  -DDSO_WIN32  -DOPENSSL_USE_APPLINK -I. -DOPENSSL_NO_RC5 -DOPENSSL_NO_MD2 -DOPENSSL_NO_KRB5 -DOPENSSL_NO_JPAKE -DOPENSSL_NO_STATIC_ENGINE    "
+  #define CFLAGS "compiler: cl  /MD /Ox /O2 /Ob2 -DOPENSSL_THREADS  -DDSO_WIN32  -DOPENSSL_USE_APPLINK -I. -DOPENSSL_NO_RC5 -DOPENSSL_NO_MD2 -DOPENSSL_NO_KRB5 -DOPENSSL_NO_JPAKE -DOPENSSL_NO_STATIC_ENGINE    "
   #define PLATFORM "VC-WIN32"
   #define PLATFORM "VC-WIN32"
-  #define DATE "Fri Jan  9 11:28:31 2015"
+  #define DATE "Wed Jan 28 13:03:40 2015"
 #endif
 #endif
 #ifdef MK1MF_PLATFORM_BC_NT
 #ifdef MK1MF_PLATFORM_BC_NT
   /* auto-generated/updated by util/mk1mf.pl for crypto/cversion.c */
   /* auto-generated/updated by util/mk1mf.pl for crypto/cversion.c */
-  #define CFLAGS "bcc32 -DWIN32_LEAN_AND_MEAN -q -w-ccc -w-rch -w-pia -w-aus -w-par -w-inl  -c -tWC -tWM -DOPENSSL_SYSNAME_WIN32 -DL_ENDIAN -DDSO_WIN32 -D_stricmp=stricmp -D_strnicmp=strnicmp -D_timeb=timeb -D_ftime=ftime -O2 -ff -fp -DBN_ASM -DMD5_ASM -DSHA1_ASM -DRMD160_ASM -DOPENSSL_NO_RC5 -DOPENSSL_NO_MD2 -DOPENSSL_NO_KRB5 -DOPENSSL_NO_JPAKE -DOPENSSL_NO_DYNAMIC_ENGINE    "
+  #define CFLAGS "compiler: bcc32 -DWIN32_LEAN_AND_MEAN -q -w-ccc -w-rch -w-pia -w-aus -w-par -w-inl  -c -tWC -tWM -DOPENSSL_SYSNAME_WIN32 -DL_ENDIAN -DDSO_WIN32 -D_stricmp=stricmp -D_strnicmp=strnicmp -D_timeb=timeb -D_ftime=ftime -O2 -ff -fp -DBN_ASM -DMD5_ASM -DSHA1_ASM -DRMD160_ASM -DOPENSSL_NO_RC5 -DOPENSSL_NO_MD2 -DOPENSSL_NO_KRB5 -DOPENSSL_NO_JPAKE -DOPENSSL_NO_DYNAMIC_ENGINE    "
   #define PLATFORM "BC-NT"
   #define PLATFORM "BC-NT"
-  #define DATE "Fri Jan  9 11:28:31 2015"
+  #define DATE "Wed Jan 28 13:03:40 2015"
 #endif
 #endif

+ 1 - 1
libs/openssl/crypto/cversion.c

@@ -77,7 +77,7 @@ const char *SSLeay_version(int t)
 	if (t == SSLEAY_CFLAGS)
 	if (t == SSLEAY_CFLAGS)
 		{
 		{
 #ifdef CFLAGS
 #ifdef CFLAGS
-		return(CFLAGS); // MPEXT
+		return(CFLAGS);
 #else
 #else
 		return("compiler: information not available");
 		return("compiler: information not available");
 #endif
 #endif

+ 1 - 1
libs/openssl/crypto/ecdsa/ecs_vrf.c

@@ -57,7 +57,7 @@
  */
  */
 
 
 #include "ecs_locl.h"
 #include "ecs_locl.h"
-#include "cryptlib.h"
+#include <string.h>
 #ifndef OPENSSL_NO_ENGINE
 #ifndef OPENSSL_NO_ENGINE
 #include <openssl/engine.h>
 #include <openssl/engine.h>
 #endif
 #endif

+ 3 - 3
libs/openssl/crypto/opensslv.h

@@ -29,11 +29,11 @@ extern "C" {
  * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
  * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
  *  major minor fix final patch/beta)
  *  major minor fix final patch/beta)
  */
  */
-#define OPENSSL_VERSION_NUMBER	0x100010bfL
+#define OPENSSL_VERSION_NUMBER	0x100010cfL
 #ifdef OPENSSL_FIPS
 #ifdef OPENSSL_FIPS
-#define OPENSSL_VERSION_TEXT	"OpenSSL 1.0.1k-fips 8 Jan 2015"
+#define OPENSSL_VERSION_TEXT	"OpenSSL 1.0.1l-fips 15 Jan 2015"
 #else
 #else
-#define OPENSSL_VERSION_TEXT	"OpenSSL 1.0.1k 8 Jan 2015"
+#define OPENSSL_VERSION_TEXT	"OpenSSL 1.0.1l 15 Jan 2015"
 #endif
 #endif
 #define OPENSSL_VERSION_PTEXT	" part of " OPENSSL_VERSION_TEXT
 #define OPENSSL_VERSION_PTEXT	" part of " OPENSSL_VERSION_TEXT
 
 

+ 2 - 59
libs/openssl/crypto/rand/rand_win.c

@@ -196,12 +196,6 @@ int RAND_poll(void)
 	DWORD w;
 	DWORD w;
 	int good = 0;
 	int good = 0;
 
 
-	/* Determine the OS version we are on so we can turn off things 
-	 * that do not work properly.
-	 */
-        OSVERSIONINFO osverinfo ;
-        osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
-        GetVersionEx( &osverinfo ) ;
 
 
 #if defined(OPENSSL_SYS_WINCE)
 #if defined(OPENSSL_SYS_WINCE)
 # if defined(_WIN32_WCE) && _WIN32_WCE>=300
 # if defined(_WIN32_WCE) && _WIN32_WCE>=300
@@ -281,56 +275,6 @@ int RAND_poll(void)
          * at random times on Windows 2000.  Reported by Jeffrey Altman.  
          * at random times on Windows 2000.  Reported by Jeffrey Altman.  
          * Only use it on NT.
          * Only use it on NT.
 	 */
 	 */
-	/* Wolfgang Marczy <[email protected]> reports that
-	 * the RegQueryValueEx call below can hang on NT4.0 (SP6).
-	 * So we don't use this at all for now. */
-#if 0
-        if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
-		osverinfo.dwMajorVersion < 5)
-		{
-		/* Read Performance Statistics from NT/2000 registry
-		 * The size of the performance data can vary from call
-		 * to call so we must guess the size of the buffer to use
-		 * and increase its size if we get an ERROR_MORE_DATA
-		 * return instead of ERROR_SUCCESS.
-		 */
-		LONG   rc=ERROR_MORE_DATA;
-		char * buf=NULL;
-		DWORD bufsz=0;
-		DWORD length;
-
-		while (rc == ERROR_MORE_DATA)
-			{
-			buf = realloc(buf,bufsz+8192);
-			if (!buf)
-				break;
-			bufsz += 8192;
-
-			length = bufsz;
-			rc = RegQueryValueEx(HKEY_PERFORMANCE_DATA, TEXT("Global"),
-				NULL, NULL, buf, &length);
-			}
-		if (rc == ERROR_SUCCESS)
-			{
-                        /* For entropy count assume only least significant
-			 * byte of each DWORD is random.
-			 */
-			RAND_add(&length, sizeof(length), 0);
-			RAND_add(buf, length, length / 4.0);
-
-			/* Close the Registry Key to allow Windows to cleanup/close
-			 * the open handle
-			 * Note: The 'HKEY_PERFORMANCE_DATA' key is implicitly opened
-			 *       when the RegQueryValueEx above is done.  However, if
-			 *       it is not explicitly closed, it can cause disk
-			 *       partition manipulation problems.
-			 */
-			RegCloseKey(HKEY_PERFORMANCE_DATA);
-			}
-		if (buf)
-			free(buf);
-		}
-#endif
 
 
 	if (advapi)
 	if (advapi)
 		{
 		{
@@ -383,7 +327,7 @@ int RAND_poll(void)
         if (advapi)
         if (advapi)
 		FreeLibrary(advapi);
 		FreeLibrary(advapi);
 
 
-	if ((osverinfo.dwPlatformId != VER_PLATFORM_WIN32_NT ||
+	if ((!check_winnt() ||
 	     !OPENSSL_isservice()) &&
 	     !OPENSSL_isservice()) &&
 	    (user = LoadLibrary(TEXT("USER32.DLL"))))
 	    (user = LoadLibrary(TEXT("USER32.DLL"))))
 		{
 		{
@@ -407,8 +351,7 @@ int RAND_poll(void)
 			 * on NT4 even though it exists in SP3 (or SP6) and
 			 * on NT4 even though it exists in SP3 (or SP6) and
 			 * higher.
 			 * higher.
 			 */
 			 */
-			if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
-				osverinfo.dwMajorVersion < 5)
+			if (check_winnt() && !check_win_minplat(5))
 				cursor = 0;
 				cursor = 0;
 			}
 			}
 		if (cursor)
 		if (cursor)

+ 1 - 1
libs/openssl/crypto/x509v3/v3_ncons.c

@@ -401,7 +401,7 @@ static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base)
 	if (dns->length > base->length)
 	if (dns->length > base->length)
 		{
 		{
 		dnsptr += dns->length - base->length;
 		dnsptr += dns->length - base->length;
-		if (dnsptr[-1] != '.')
+		if (*baseptr != '.' && dnsptr[-1] != '.')
 			return X509_V_ERR_PERMITTED_VIOLATION;
 			return X509_V_ERR_PERMITTED_VIOLATION;
 		}
 		}
 
 

+ 3 - 1
libs/openssl/e_os.h

@@ -368,11 +368,13 @@ static __inline unsigned int _strlen31(const char *str)
 #    define DEFAULT_HOME  "C:"
 #    define DEFAULT_HOME  "C:"
 #  endif
 #  endif
 
 
-/* Avoid Windows 8 SDK GetVersion deprecated problems */
+/* Avoid Visual Studio 13 GetVersion deprecated problems */
 #if defined(_MSC_VER) && _MSC_VER>=1800
 #if defined(_MSC_VER) && _MSC_VER>=1800
 #  define check_winnt() (1)
 #  define check_winnt() (1)
+#  define check_win_minplat(x) (1)
 #else
 #else
 #  define check_winnt() (GetVersion() < 0x80000000)
 #  define check_winnt() (GetVersion() < 0x80000000)
+#  define check_win_minplat(x) (LOBYTE(LOWORD(GetVersion())) >= (x))
 #endif
 #endif
 
 
 #else /* The non-microsoft world */
 #else /* The non-microsoft world */

+ 1 - 1
source/Console.cbproj

@@ -65,7 +65,7 @@
 			<ProjectType>CppConsoleApplication</ProjectType>
 			<ProjectType>CppConsoleApplication</ProjectType>
 			<SanitizedProjectName>Console</SanitizedProjectName>
 			<SanitizedProjectName>Console</SanitizedProjectName>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.1.0.0;InternalName=console;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.6.5.0;ReleaseType=RC;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.1.0.0;InternalName=console;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.7.0.0;ReleaseType=stable;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>
 			<VerInfo_MinorVer>1</VerInfo_MinorVer>
 			<VerInfo_MinorVer>1</VerInfo_MinorVer>

+ 1 - 1
source/DragExt.cbproj

@@ -66,7 +66,7 @@
 			<SanitizedProjectName>DragExt</SanitizedProjectName>
 			<SanitizedProjectName>DragExt</SanitizedProjectName>
 			<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-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.6.5.0;ReleaseType=RC;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-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.7.0.0;ReleaseType=stable;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>

+ 3 - 3
source/DragExt64.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
 1 VERSIONINFO
 FILEVERSION 1,2,1,0
 FILEVERSION 1,2,1,0
-PRODUCTVERSION 5,6,5,0
+PRODUCTVERSION 5,7,0,0
 FILEOS 0x4
 FILEOS 0x4
 FILETYPE 0x2
 FILETYPE 0x2
 {
 {
@@ -16,8 +16,8 @@ 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.6.5.0\0"
-            VALUE "ReleaseType", "RC\0"
+            VALUE "ProductVersion", "5.7.0.0\0"
+            VALUE "ReleaseType", "stable\0"
             VALUE "WWW", "http://winscp.net/\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
         }
     }
     }

+ 2 - 3
source/WinSCP.cbproj

@@ -83,11 +83,10 @@
 			<SanitizedProjectName>WinSCP</SanitizedProjectName>
 			<SanitizedProjectName>WinSCP</SanitizedProjectName>
 			<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.6.5.0;InternalName=winscp;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.6.5.0;ReleaseType=RC;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP and SCP client;FileVersion=5.7.0.0;InternalName=winscp;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.7.0.0;ReleaseType=stable;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>6</VerInfo_MinorVer>
-			<VerInfo_Release>5</VerInfo_Release>
+			<VerInfo_MinorVer>7</VerInfo_MinorVer>
 		</PropertyGroup>
 		</PropertyGroup>
 	<PropertyGroup Condition="'$(Base_Win32)'!=''">
 	<PropertyGroup Condition="'$(Base_Win32)'!=''">
 			<Defines>IDE;STRICT;$(Defines)</Defines>
 			<Defines>IDE;STRICT;$(Defines)</Defines>

+ 103 - 89
source/components/UnixDirView.cpp

@@ -39,81 +39,6 @@ namespace Unixdirview
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-#ifndef DESIGN_ONLY
-#define RFILE(N) ((TRemoteFile *)(Item ## N->Data))
-int __stdcall CompareDirectories(TListItem *Item1, TListItem *Item2)
-{
-  // Because CompareDirectories is called from each other compare functions
-  // it's sufficient to check pointers only here (see below)
-  assert(Item1 && RFILE(1) && Item2 && RFILE(2));
-
-  if (RFILE(1)->IsParentDirectory && !RFILE(2)->IsParentDirectory) return -1;
-    else
-  if (!RFILE(1)->IsParentDirectory && RFILE(2)->IsParentDirectory) return 1;
-    else
-  if (RFILE(1)->IsDirectory && !RFILE(2)->IsDirectory) return -1;
-    else
-  if (!RFILE(1)->IsDirectory && RFILE(2)->IsDirectory) return 1;
-    else
-  return 0;
-}
-//---------------------------------------------------------------------------
-int __fastcall CompareExtThenFull(const UnicodeString & Name1, const UnicodeString & Name2)
-{
-  UnicodeString Ext1 = UnixExtractFileExt(Name1);
-  UnicodeString Ext2 = UnixExtractFileExt(Name2);
-  int Result = CompareLogicalText(Ext1, Ext2);
-  if (Result == 0)
-  {
-    Result = CompareLogicalText(Name1, Name2);
-  }
-  return Result;
-}
-//---------------------------------------------------------------------------
-#define DEFINE_COMPARE_FUNC_EX(PROPERTY, NAME, COMPAREFUNCFILE, COMPAREFUNCDIR, FALLBACK) \
-  int __stdcall Compare ## NAME(TListItem *Item1, TListItem *Item2, TUnixDirView *DirView) \
-  { \
-    int Result = CompareDirectories(Item1, Item2); \
-    if (!Result) \
-    { \
-      if (RFILE(1)->IsDirectory) \
-      {  \
-        Result = COMPAREFUNCDIR(RFILE(1)->PROPERTY, RFILE(2)->PROPERTY); \
-      } \
-      else \
-      { \
-        Result = COMPAREFUNCFILE(RFILE(1)->PROPERTY, RFILE(2)->PROPERTY); \
-      } \
-      if (!DirView->UnixColProperties->SortAscending) Result = -Result; \
-      if (Result == 0) \
-      { \
-        Result = FALLBACK(Item1, Item2, DirView); \
-      } \
-    } \
-    return Result; \
-  }
-#define DEFINE_COMPARE_FUNC(PROPERTY, COMPAREFUNC) \
-  DEFINE_COMPARE_FUNC_EX(PROPERTY, PROPERTY, COMPAREFUNC, COMPAREFUNC, CompareItemFileName)
-#define COMPARE_NUMBER(Num1, Num2) ( Num1 < Num2 ? -1 : ( Num1 > Num2 ? 1 : 0) )
-#define COMPARE_DUMMY(X1, X2) 0
-#define COMPARE_ITEM_DUMMY(X1, X2, DV) 0
-#define COMPARE_TOKEN(Token1, Token2) Token1.Compare(Token2)
-//---------------------------------------------------------------------------
-DEFINE_COMPARE_FUNC_EX(FileName, ItemFileName, CompareLogicalText, CompareLogicalText, COMPARE_ITEM_DUMMY);
-DEFINE_COMPARE_FUNC(Size, COMPARE_NUMBER);
-DEFINE_COMPARE_FUNC(Modification, COMPARE_NUMBER);
-DEFINE_COMPARE_FUNC(RightsStr, AnsiCompareText);
-DEFINE_COMPARE_FUNC(Owner, COMPARE_TOKEN);
-DEFINE_COMPARE_FUNC(Group, COMPARE_TOKEN);
-DEFINE_COMPARE_FUNC_EX(Extension, Extension, CompareLogicalText, COMPARE_DUMMY, CompareItemFileName);
-DEFINE_COMPARE_FUNC(LinkTo, CompareLogicalText);
-DEFINE_COMPARE_FUNC_EX(TypeName, TypeName, CompareLogicalText, CompareLogicalText, CompareExtension);
-//---------------------------------------------------------------------------
-#undef DEFINE_COMPARE_FUNC
-#undef COMPARE_NUMBER
-#undef RFILE
-#endif
-//---------------------------------------------------------------------------
 #define HOMEDIRECTORY L""
 #define HOMEDIRECTORY L""
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TUnixDirView::TUnixDirView(TComponent* Owner)
 __fastcall TUnixDirView::TUnixDirView(TComponent* Owner)
@@ -699,26 +624,115 @@ void __fastcall TUnixDirView::SetPath(UnicodeString Value)
 #endif
 #endif
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+#ifndef DESIGN_ONLY
+#define COMPARE_NUMBER(Num1, Num2) ( Num1 < Num2 ? -1 : ( Num1 > Num2 ? 1 : 0) )
+//---------------------------------------------------------------------------
+int __stdcall CompareFile(TListItem * Item1, TListItem * Item2, TUnixDirView * DirView)
+{
+  assert((Item1 != NULL) && (Item2 != NULL));
+  TRemoteFile * File1 = NOT_NULL((TRemoteFile *)(Item1->Data));
+  TRemoteFile * File2 = NOT_NULL((TRemoteFile *)(Item2->Data));
+
+  int Result;
+  if (File1->IsParentDirectory && !File2->IsParentDirectory)
+  {
+    Result = -1;
+  }
+  else if (!File1->IsParentDirectory && File2->IsParentDirectory)
+  {
+    Result = 1;
+  }
+  else if (File1->IsDirectory && !File2->IsDirectory)
+  {
+    Result = -1;
+  }
+  else if (!File1->IsDirectory && File2->IsDirectory)
+  {
+    Result = 1;
+  }
+  else
+  {
+    Result = 0;
+
+    switch (DirView->SortColumn)
+    {
+      case uvName:
+        // fallback
+        break;
+
+      case uvSize:
+        Result = COMPARE_NUMBER(File1->Size, File2->Size);
+        break;
+
+      case uvChanged:
+        Result = COMPARE_NUMBER(File1->Modification, File2->Modification);
+        break;
+
+      case uvRights:
+        Result = AnsiCompareText(File1->RightsStr, File2->RightsStr);
+        break;
+
+      case uvOwner:
+        Result = File1->Owner.Compare(File2->Owner);
+        break;
+
+      case uvGroup:
+        Result = File1->Group.Compare(File2->Group);
+        break;
+
+      case uvExt:
+        // Duplicated in uvType branch
+        if (!File1->IsDirectory)
+        {
+          Result = CompareLogicalText(File1->Extension, File2->Extension);
+        }
+        else
+        {
+          // fallback
+        }
+        break;
+
+      case uvLinkTarget:
+        Result = CompareLogicalText(File1->LinkTo, File2->LinkTo);
+        break;
+
+      case uvType:
+        Result = CompareLogicalText(File1->TypeName, File2->TypeName);
+        // fallback to uvExt
+        if ((Result == 0) && !File1->IsDirectory)
+        {
+          Result = CompareLogicalText(File1->Extension, File2->Extension);
+        }
+        break;
+
+      default:
+        FAIL;
+    }
+
+    if (Result == 0)
+    {
+      Result = CompareLogicalText(File1->FileName, File2->FileName);
+    }
+
+    if (!DirView->UnixColProperties->SortAscending)
+    {
+      Result = -Result;
+    }
+  }
+
+  return Result;
+}
+//---------------------------------------------------------------------------
+#undef COMPARE_NUMBER
+#endif
+//---------------------------------------------------------------------------
 void __fastcall TUnixDirView::SortItems()
 void __fastcall TUnixDirView::SortItems()
 {
 {
 #ifndef DESIGN_ONLY
 #ifndef DESIGN_ONLY
   assert(Terminal);
   assert(Terminal);
   if (HandleAllocated())
   if (HandleAllocated())
   {
   {
-    PFNLVCOMPARE SortProc;
-    switch (SortColumn) {
-      case uvName: SortProc = (PFNLVCOMPARE)CompareItemFileName; break;
-      case uvSize: SortProc = (PFNLVCOMPARE)CompareSize; break;
-      case uvChanged: SortProc = (PFNLVCOMPARE)CompareModification; break;
-      case uvRights: SortProc = (PFNLVCOMPARE)CompareRightsStr; break;
-      case uvOwner: SortProc = (PFNLVCOMPARE)CompareOwner; break;
-      case uvGroup: SortProc = (PFNLVCOMPARE)CompareGroup; break;
-      case uvExt: SortProc = (PFNLVCOMPARE)CompareExtension; break;
-      case uvLinkTarget: SortProc = (PFNLVCOMPARE)CompareLinkTo; break;
-      case uvType: SortProc = (PFNLVCOMPARE)CompareTypeName; break;
-      default: FAIL;
-    }
-    CustomSortItems(SortProc);
+    CustomSortItems(CompareFile);
   }
   }
 #endif
 #endif
 }
 }

+ 27 - 5
source/core/Configuration.cpp

@@ -101,8 +101,10 @@ void __fastcall TConfiguration::Default()
   FPermanentLogFileName = FLogFileName;
   FPermanentLogFileName = FLogFileName;
   FLogFileAppend = true;
   FLogFileAppend = true;
   FLogSensitive = false;
   FLogSensitive = false;
+  FPermanentLogSensitive = FLogSensitive;
   FLogWindowLines = 100;
   FLogWindowLines = 100;
   FLogProtocol = 0;
   FLogProtocol = 0;
+  FPermanentLogProtocol = FLogProtocol;
   UpdateActualLogProtocol();
   UpdateActualLogProtocol();
   FLogActions = false;
   FLogActions = false;
   FPermanentLogActions = false;
   FPermanentLogActions = false;
@@ -208,9 +210,9 @@ UnicodeString __fastcall TConfiguration::PropertyToKey(const UnicodeString & Pro
     KEYEX(Bool,  PermanentLogging, L"Logging"); \
     KEYEX(Bool,  PermanentLogging, L"Logging"); \
     KEYEX(String,PermanentLogFileName, L"LogFileName"); \
     KEYEX(String,PermanentLogFileName, L"LogFileName"); \
     KEY(Bool,    LogFileAppend); \
     KEY(Bool,    LogFileAppend); \
-    KEY(Bool,    LogSensitive); \
+    KEYEX(Bool,  PermanentLogSensitive, L"LogSensitive"); \
     KEY(Integer, LogWindowLines); \
     KEY(Integer, LogWindowLines); \
-    KEY(Integer, LogProtocol); \
+    KEYEX(Integer,PermanentLogProtocol, L"LogProtocol"); \
     KEYEX(Bool,  PermanentLogActions, L"LogActions"); \
     KEYEX(Bool,  PermanentLogActions, L"LogActions"); \
     KEYEX(String,PermanentActionsLogFileName, L"ActionsLogFileName"); \
     KEYEX(String,PermanentActionsLogFileName, L"ActionsLogFileName"); \
   );
   );
@@ -1224,6 +1226,16 @@ void __fastcall TConfiguration::TemporaryActionsLogging(const UnicodeString ALog
   FActionsLogFileName = ALogFileName;
   FActionsLogFileName = ALogFileName;
 }
 }
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
+void __fastcall TConfiguration::TemporaryLogProtocol(int ALogProtocol)
+{
+  FLogProtocol = ALogProtocol;
+}
+//---------------------------------------------------------------------
+void __fastcall TConfiguration::TemporaryLogSensitive(bool ALogSensitive)
+{
+  FLogSensitive = ALogSensitive;
+}
+//---------------------------------------------------------------------
 void __fastcall TConfiguration::SetLogging(bool value)
 void __fastcall TConfiguration::SetLogging(bool value)
 {
 {
   if (Logging != value)
   if (Logging != value)
@@ -1267,8 +1279,13 @@ void __fastcall TConfiguration::UpdateActualLogProtocol()
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 void __fastcall TConfiguration::SetLogProtocol(int value)
 void __fastcall TConfiguration::SetLogProtocol(int value)
 {
 {
-  SET_CONFIG_PROPERTY(LogProtocol);
-  UpdateActualLogProtocol();
+  if (LogProtocol != value)
+  {
+    FPermanentLogProtocol = value;
+    FLogProtocol = value;
+    Changed();
+    UpdateActualLogProtocol();
+  }
 }
 }
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 void __fastcall TConfiguration::SetLogActions(bool value)
 void __fastcall TConfiguration::SetLogActions(bool value)
@@ -1288,7 +1305,12 @@ void __fastcall TConfiguration::SetLogFileAppend(bool value)
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 void __fastcall TConfiguration::SetLogSensitive(bool value)
 void __fastcall TConfiguration::SetLogSensitive(bool value)
 {
 {
-  SET_CONFIG_PROPERTY(LogSensitive);
+  if (LogSensitive != value)
+  {
+    FPermanentLogSensitive = value;
+    FLogSensitive = value;
+    Changed();
+  }
 }
 }
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 void __fastcall TConfiguration::SetLogWindowLines(int value)
 void __fastcall TConfiguration::SetLogWindowLines(int value)

+ 6 - 0
source/core/Configuration.h

@@ -32,7 +32,9 @@ private:
   int FLogWindowLines;
   int FLogWindowLines;
   bool FLogFileAppend;
   bool FLogFileAppend;
   bool FLogSensitive;
   bool FLogSensitive;
+  bool FPermanentLogSensitive;
   int FLogProtocol;
   int FLogProtocol;
+  int FPermanentLogProtocol;
   int FActualLogProtocol;
   int FActualLogProtocol;
   bool FLogActions;
   bool FLogActions;
   bool FPermanentLogActions;
   bool FPermanentLogActions;
@@ -160,6 +162,8 @@ protected:
   __property UnicodeString PermanentLogFileName  = { read=FPermanentLogFileName, write=SetLogFileName };
   __property UnicodeString PermanentLogFileName  = { read=FPermanentLogFileName, write=SetLogFileName };
   __property bool PermanentLogActions  = { read=FPermanentLogActions, write=SetLogActions };
   __property bool PermanentLogActions  = { read=FPermanentLogActions, write=SetLogActions };
   __property UnicodeString PermanentActionsLogFileName  = { read=FPermanentActionsLogFileName, write=SetActionsLogFileName };
   __property UnicodeString PermanentActionsLogFileName  = { read=FPermanentActionsLogFileName, write=SetActionsLogFileName };
+  __property int PermanentLogProtocol  = { read=FPermanentLogProtocol, write=SetLogProtocol };
+  __property bool PermanentLogSensitive  = { read=FPermanentLogSensitive, write=SetLogSensitive };
 
 
 public:
 public:
   __fastcall TConfiguration();
   __fastcall TConfiguration();
@@ -190,6 +194,8 @@ public:
   virtual THierarchicalStorage * CreateScpStorage(bool & SessionList);
   virtual THierarchicalStorage * CreateScpStorage(bool & SessionList);
   void __fastcall TemporaryLogging(const UnicodeString ALogFileName);
   void __fastcall TemporaryLogging(const UnicodeString ALogFileName);
   void __fastcall TemporaryActionsLogging(const UnicodeString ALogFileName);
   void __fastcall TemporaryActionsLogging(const UnicodeString ALogFileName);
+  void __fastcall TemporaryLogProtocol(int ALogProtocol);
+  void __fastcall TemporaryLogSensitive(bool ALogSensitive);
   virtual RawByteString __fastcall EncryptPassword(UnicodeString Password, UnicodeString Key);
   virtual RawByteString __fastcall EncryptPassword(UnicodeString Password, UnicodeString Key);
   virtual UnicodeString __fastcall DecryptPassword(RawByteString Password, UnicodeString Key);
   virtual UnicodeString __fastcall DecryptPassword(RawByteString Password, UnicodeString Key);
   virtual RawByteString __fastcall StronglyRecryptPassword(RawByteString Password, UnicodeString Key);
   virtual RawByteString __fastcall StronglyRecryptPassword(RawByteString Password, UnicodeString Key);

+ 54 - 13
source/core/FtpFileSystem.cpp

@@ -190,7 +190,7 @@ const wchar_t CertificateStorageKey[] = L"FtpsCertificates";
 const UnicodeString SiteCommand(L"SITE");
 const UnicodeString SiteCommand(L"SITE");
 const UnicodeString SymlinkSiteCommand(L"SYMLINK");
 const UnicodeString SymlinkSiteCommand(L"SYMLINK");
 const UnicodeString CopySiteCommand(L"COPY");
 const UnicodeString CopySiteCommand(L"COPY");
-const UnicodeString HashCommand(L"HASH");
+const UnicodeString HashCommand(L"HASH"); // Cerberos + FileZilla servers
 const UnicodeString AvblCommand(L"AVBL");
 const UnicodeString AvblCommand(L"AVBL");
 const UnicodeString XQuotaCommand(L"XQUOTA");
 const UnicodeString XQuotaCommand(L"XQUOTA");
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -252,7 +252,8 @@ __fastcall TFTPFileSystem::TFTPFileSystem(TTerminal * ATerminal):
   FOnCaptureOutput(NULL),
   FOnCaptureOutput(NULL),
   FFileSystemInfoValid(false),
   FFileSystemInfoValid(false),
   FDoListAll(false),
   FDoListAll(false),
-  FServerCapabilities(NULL)
+  FServerCapabilities(NULL),
+  FReadCurrentDirectory(false)
 {
 {
   ResetReply();
   ResetReply();
 
 
@@ -268,11 +269,12 @@ __fastcall TFTPFileSystem::TFTPFileSystem(TTerminal * ATerminal):
 
 
   FChecksumAlgs.reset(new TStringList());
   FChecksumAlgs.reset(new TStringList());
   FChecksumCommands.reset(new TStringList());
   FChecksumCommands.reset(new TStringList());
-  RegisterChecksumAlgCommand(Sha1ChecksumAlg, L"XSHA1");
-  RegisterChecksumAlgCommand(Sha256ChecksumAlg, L"XSHA256");
-  RegisterChecksumAlgCommand(Sha512ChecksumAlg, L"XSHA512");
-  RegisterChecksumAlgCommand(Md5ChecksumAlg, L"XMD5");
-  RegisterChecksumAlgCommand(Crc32ChecksumAlg, L"XCRC");
+  RegisterChecksumAlgCommand(Sha1ChecksumAlg, L"XSHA1"); // e.g. Cerberos FTP
+  RegisterChecksumAlgCommand(Sha256ChecksumAlg, L"XSHA256"); // e.g. Cerberos FTP
+  RegisterChecksumAlgCommand(Sha512ChecksumAlg, L"XSHA512"); // e.g. Cerberos FTP
+  RegisterChecksumAlgCommand(Md5ChecksumAlg, L"XMD5"); // e.g. Cerberos FTP
+  RegisterChecksumAlgCommand(Md5ChecksumAlg, L"MD5"); // e.g. Apache FTP
+  RegisterChecksumAlgCommand(Crc32ChecksumAlg, L"XCRC"); // e.g. Cerberos FTP
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TFTPFileSystem::~TFTPFileSystem()
 __fastcall TFTPFileSystem::~TFTPFileSystem()
@@ -317,7 +319,7 @@ void __fastcall TFTPFileSystem::Open()
   DiscardMessages();
   DiscardMessages();
 
 
   ResetCaches();
   ResetCaches();
-  FCurrentDirectory = L"";
+  FReadCurrentDirectory = true;
   FHomeDirectory = L"";
   FHomeDirectory = L"";
 
 
   TSessionData * Data = FTerminal->SessionData;
   TSessionData * Data = FTerminal->SessionData;
@@ -361,7 +363,7 @@ void __fastcall TFTPFileSystem::Open()
         default:
         default:
         case 0:
         case 0:
         case 1:
         case 1:
-          LogLevel = TFileZillaIntf::LOG_WARNING;
+          LogLevel = TFileZillaIntf::LOG_PROGRESS;
           break;
           break;
 
 
         case 2:
         case 2:
@@ -707,6 +709,23 @@ void __fastcall TFTPFileSystem::CollectUsage()
   {
   {
     FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPComplete");
     FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPComplete");
   }
   }
+  // 220 Core FTP Server Version 1.2, build 567, 64-bit, installed 8 days ago Unregistered
+  // ...
+  // SYST
+  // 215 UNIX Type: L8
+  else if (ContainsText(FWelcomeMessage, L"Core FTP Server"))
+  {
+    FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPCore");
+  }
+  // 220 Service ready for new user.
+  // ..
+  // SYST
+  // 215 UNIX Type: Apache FtpServer
+  // (e.g. brickftp.com)
+  else if (ContainsText(FSystem, L"Apache FtpServer"))
+  {
+    FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPApache");
+  }
   else
   else
   {
   {
     FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPOther");
     FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPOther");
@@ -723,6 +742,7 @@ void __fastcall TFTPFileSystem::Idle()
     if ((FTerminal->SessionData->FtpPingType != ptOff) &&
     if ((FTerminal->SessionData->FtpPingType != ptOff) &&
         (double(Now() - FLastDataSent) > double(FTerminal->SessionData->FtpPingIntervalDT) * 4))
         (double(Now() - FLastDataSent) > double(FTerminal->SessionData->FtpPingIntervalDT) * 4))
     {
     {
+      FTerminal->LogEvent(L"Dummy directory read to keep session alive.");
       FLastDataSent = Now();
       FLastDataSent = Now();
 
 
       TRemoteDirectory * Files = new TRemoteDirectory(FTerminal);
       TRemoteDirectory * Files = new TRemoteDirectory(FTerminal);
@@ -872,12 +892,13 @@ void __fastcall TFTPFileSystem::ChangeDirectory(const UnicodeString ADirectory)
   DoChangeDirectory(Directory);
   DoChangeDirectory(Directory);
 
 
   // make next ReadCurrentDirectory retrieve actual server-side current directory
   // make next ReadCurrentDirectory retrieve actual server-side current directory
-  FCurrentDirectory = L"";
+  FReadCurrentDirectory = true;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::CachedChangeDirectory(const UnicodeString Directory)
 void __fastcall TFTPFileSystem::CachedChangeDirectory(const UnicodeString Directory)
 {
 {
   FCurrentDirectory = UnixExcludeTrailingBackslash(Directory);
   FCurrentDirectory = UnixExcludeTrailingBackslash(Directory);
+  FReadCurrentDirectory = false;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::ChangeFileProperties(const UnicodeString AFileName,
 void __fastcall TFTPFileSystem::ChangeFileProperties(const UnicodeString AFileName,
@@ -959,6 +980,9 @@ bool __fastcall TFTPFileSystem::LoadFilesProperties(TStrings * /*FileList*/)
 UnicodeString __fastcall TFTPFileSystem::DoCalculateFileChecksum(
 UnicodeString __fastcall TFTPFileSystem::DoCalculateFileChecksum(
   bool UsingHashCommand, const UnicodeString & Alg, TRemoteFile * File)
   bool UsingHashCommand, const UnicodeString & Alg, TRemoteFile * File)
 {
 {
+  // Overview of server supporting various hash commands is at:
+  // https://tools.ietf.org/html/draft-ietf-ftpext2-hash-03#appendix-B
+
   UnicodeString CommandName;
   UnicodeString CommandName;
 
 
   if (UsingHashCommand)
   if (UsingHashCommand)
@@ -1034,10 +1058,21 @@ UnicodeString __fastcall TFTPFileSystem::DoCalculateFileChecksum(
       Hash = Range;
       Hash = Range;
     }
     }
   }
   }
-  else // All X<hash> commands
+  else // All hash-specific commands
   {
   {
     // Accepting any 2xx response. Most servers use 213,
     // Accepting any 2xx response. Most servers use 213,
     // but for example WS_FTP uses non-sense code 220 (Service ready for new user)
     // but for example WS_FTP uses non-sense code 220 (Service ready for new user)
+
+    // MD5 response according to a draft-twine-ftpmd5-00 includes a file name
+    // (implemented by Apache FtpServer).
+    // Other commands (X<hash>) return the hash only.
+    ResponseText = ResponseText.Trim();
+    int P = ResponseText.LastDelimiter(L" ");
+    if (P > 0)
+    {
+      ResponseText.Delete(1, P);
+    }
+
     Hash = ResponseText;
     Hash = ResponseText;
   }
   }
 
 
@@ -2172,6 +2207,7 @@ void __fastcall TFTPFileSystem::HomeDirectory()
   // of ChangeDirectory, such as EnsureLocation
   // of ChangeDirectory, such as EnsureLocation
   DoChangeDirectory(FHomeDirectory);
   DoChangeDirectory(FHomeDirectory);
   FCurrentDirectory = FHomeDirectory;
   FCurrentDirectory = FHomeDirectory;
+  FReadCurrentDirectory = false;
   // make sure FZAPI is aware that we changed current working directory
   // make sure FZAPI is aware that we changed current working directory
   FFileZillaIntf->SetCurrentPath(FCurrentDirectory.c_str());
   FFileZillaIntf->SetCurrentPath(FCurrentDirectory.c_str());
 }
 }
@@ -2239,7 +2275,7 @@ void __fastcall TFTPFileSystem::ReadCurrentDirectory()
   // and immediately after call to CWD,
   // and immediately after call to CWD,
   // later our current directory may be not synchronized with FZAPI current
   // later our current directory may be not synchronized with FZAPI current
   // directory anyway, see comments in EnsureLocation
   // directory anyway, see comments in EnsureLocation
-  if (FCurrentDirectory.IsEmpty())
+  if (FReadCurrentDirectory || ALWAYS_FALSE(FCurrentDirectory.IsEmpty()))
   {
   {
     UnicodeString Command = L"PWD";
     UnicodeString Command = L"PWD";
     SendCommand(Command);
     SendCommand(Command);
@@ -2284,6 +2320,7 @@ void __fastcall TFTPFileSystem::ReadCurrentDirectory()
         if (Result)
         if (Result)
         {
         {
           FCurrentDirectory = UnixExcludeTrailingBackslash(Path);
           FCurrentDirectory = UnixExcludeTrailingBackslash(Path);
+          FReadCurrentDirectory = false;
         }
         }
       }
       }
 
 
@@ -3643,7 +3680,7 @@ bool __fastcall TFTPFileSystem::HandleStatus(const wchar_t * AStatus, int Type)
       // by setting dummy one
       // by setting dummy one
       if (Type == TFileZillaIntf::LOG_ERROR)
       if (Type == TFileZillaIntf::LOG_ERROR)
       {
       {
-        if (Status == FTimeoutStatus)
+        if (StartsStr(FTimeoutStatus, Status))
         {
         {
           if (NoFinalLastCode())
           if (NoFinalLastCode())
           {
           {
@@ -3665,6 +3702,10 @@ bool __fastcall TFTPFileSystem::HandleStatus(const wchar_t * AStatus, int Type)
       LogType = llMessage;
       LogType = llMessage;
       break;
       break;
 
 
+    case TFileZillaIntf::LOG_PROGRESS:
+      LogType = llMessage;
+      break;
+
     case TFileZillaIntf::LOG_REPLY:
     case TFileZillaIntf::LOG_REPLY:
       HandleReplyStatus(AStatus);
       HandleReplyStatus(AStatus);
       LogType = llOutput;
       LogType = llOutput;

+ 1 - 0
source/core/FtpFileSystem.h

@@ -237,6 +237,7 @@ private:
   UnicodeString FSystem;
   UnicodeString FSystem;
   TStrings * FFeatures;
   TStrings * FFeatures;
   UnicodeString FCurrentDirectory;
   UnicodeString FCurrentDirectory;
+  bool FReadCurrentDirectory;
   UnicodeString FHomeDirectory;
   UnicodeString FHomeDirectory;
   TRemoteFileList * FFileList;
   TRemoteFileList * FFileList;
   TRemoteFileList * FFileListCache;
   TRemoteFileList * FFileListCache;

+ 3 - 0
source/core/Interface.h

@@ -7,6 +7,8 @@
 #define HELP_NONE ""
 #define HELP_NONE ""
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 TConfiguration * __fastcall CreateConfiguration();
 TConfiguration * __fastcall CreateConfiguration();
+class TOptions;
+TOptions * __fastcall GetGlobalOptions();
 
 
 void __fastcall ShowExtendedException(Exception * E);
 void __fastcall ShowExtendedException(Exception * E);
 bool __fastcall AppendExceptionStackTraceAndForget(TStrings *& MoreMessages);
 bool __fastcall AppendExceptionStackTraceAndForget(TStrings *& MoreMessages);
@@ -16,6 +18,7 @@ UnicodeString __fastcall GetRegistryKey();
 void * __fastcall BusyStart();
 void * __fastcall BusyStart();
 void __fastcall BusyEnd(void * Token);
 void __fastcall BusyEnd(void * Token);
 const unsigned int GUIUpdateInterval = 200;
 const unsigned int GUIUpdateInterval = 200;
+void __fastcall SetNoGUI();
 bool __fastcall ProcessGUI(bool Force = false);
 bool __fastcall ProcessGUI(bool Force = false);
 UnicodeString __fastcall AppNameString();
 UnicodeString __fastcall AppNameString();
 UnicodeString __fastcall SshVersionString();
 UnicodeString __fastcall SshVersionString();

+ 28 - 16
source/core/NamedObjs.cpp

@@ -9,13 +9,7 @@
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 int __fastcall NamedObjectSortProc(void * Item1, void * Item2)
 int __fastcall NamedObjectSortProc(void * Item1, void * Item2)
 {
 {
-  bool HasPrefix1 = ((TNamedObject *)Item1)->Hidden;
-  bool HasPrefix2 = ((TNamedObject *)Item2)->Hidden;
-  if (HasPrefix1 && !HasPrefix2) return -1;
-    else
-  if (!HasPrefix1 && HasPrefix2) return 1;
-    else
-  return CompareLogicalText(((TNamedObject *)Item1)->Name, ((TNamedObject *)Item2)->Name);
+  return static_cast<TNamedObject *>(Item1)->Compare(static_cast<TNamedObject *>(Item2));
 }
 }
 //--- TNamedObject ----------------------------------------------------------
 //--- TNamedObject ----------------------------------------------------------
 __fastcall TNamedObject::TNamedObject(UnicodeString AName)
 __fastcall TNamedObject::TNamedObject(UnicodeString AName)
@@ -29,13 +23,27 @@ void __fastcall TNamedObject::SetName(UnicodeString value)
   FName = value;
   FName = value;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-Integer __fastcall TNamedObject::CompareName(UnicodeString aName,
-  Boolean CaseSensitive)
+int __fastcall TNamedObject::Compare(TNamedObject * Other)
 {
 {
-  if (CaseSensitive)
-    return Name.Compare(aName);
+  int Result;
+  if (Hidden && !Other->Hidden)
+  {
+    Result = -1;
+  }
+  else if (!Hidden && Other->Hidden)
+  {
+    Result = 1;
+  }
   else
   else
-    return Name.CompareIC(aName);
+  {
+    Result = CompareLogicalText(Name, Other->Name);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+bool __fastcall TNamedObject::IsSameName(const UnicodeString & AName)
+{
+  return (Name.CompareIC(AName) == 0);
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TNamedObject::MakeUniqueIn(TNamedObjectList * List)
 void __fastcall TNamedObject::MakeUniqueIn(TNamedObjectList * List)
@@ -101,13 +109,17 @@ void __fastcall TNamedObjectList::Notify(void *Ptr, TListNotification Action)
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-TNamedObject * __fastcall TNamedObjectList::FindByName(UnicodeString Name,
-  Boolean CaseSensitive)
+TNamedObject * __fastcall TNamedObjectList::FindByName(const UnicodeString & Name)
 {
 {
   // this should/can be optimized when list is sorted
   // this should/can be optimized when list is sorted
   for (Integer Index = 0; Index < TObjectList::Count; Index++)
   for (Integer Index = 0; Index < TObjectList::Count; Index++)
-    if (!((TNamedObject *)Items[Index])->CompareName(Name, CaseSensitive))
-      return (TNamedObject *)Items[Index];
+  {
+    TNamedObject * NamedObject = AtObject(Index);
+    if (NamedObject->IsSameName(Name))
+    {
+      return NamedObject;
+    }
+  }
   return NULL;
   return NULL;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------

+ 3 - 2
source/core/NamedObjs.h

@@ -12,7 +12,8 @@ public:
   __property UnicodeString Name = { read = FName, write = SetName };
   __property UnicodeString Name = { read = FName, write = SetName };
   __property bool Hidden = { read = FHidden };
   __property bool Hidden = { read = FHidden };
   __fastcall TNamedObject() {};
   __fastcall TNamedObject() {};
-  Integer __fastcall CompareName(UnicodeString aName, Boolean CaseSensitive = False);
+  bool __fastcall IsSameName(const UnicodeString & Name);
+  virtual int __fastcall Compare(TNamedObject * Other);
   __fastcall TNamedObject(UnicodeString aName);
   __fastcall TNamedObject(UnicodeString aName);
   void __fastcall MakeUniqueIn(TNamedObjectList * List);
   void __fastcall MakeUniqueIn(TNamedObjectList * List);
 private:
 private:
@@ -40,7 +41,7 @@ public:
   __fastcall TNamedObjectList();
   __fastcall TNamedObjectList();
   void __fastcall AlphaSort();
   void __fastcall AlphaSort();
   virtual TNamedObject * __fastcall AtObject(Integer Index);
   virtual TNamedObject * __fastcall AtObject(Integer Index);
-  TNamedObject * __fastcall FindByName(UnicodeString Name, Boolean CaseSensitive = False);
+  TNamedObject * __fastcall FindByName(const UnicodeString & Name);
   __property int Count = { read = GetCount, write = SetCount };
   __property int Count = { read = GetCount, write = SetCount };
   __property int CountIncludingHidden = { read = GetCountIncludingHidden };
   __property int CountIncludingHidden = { read = GetCountIncludingHidden };
 };
 };

+ 43 - 2
source/core/Option.cpp

@@ -10,8 +10,8 @@
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TOptions::TOptions()
 __fastcall TOptions::TOptions()
 {
 {
-  FSwitchMarks = L"-/";
-  FSwitchValueDelimiters = L":=";
+  FSwitchMarks = L"/-";
+  FSwitchValueDelimiters = L"=:";
   FNoMoreSwitches = false;
   FNoMoreSwitches = false;
   FParamCount = 0;
   FParamCount = 0;
 }
 }
@@ -70,6 +70,8 @@ void __fastcall TOptions::Add(UnicodeString Value)
       ++FParamCount;
       ++FParamCount;
     }
     }
   }
   }
+
+  FOriginalOptions = FOptions;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 UnicodeString __fastcall TOptions::GetParam(int Index)
 UnicodeString __fastcall TOptions::GetParam(int Index)
@@ -249,6 +251,18 @@ bool __fastcall TOptions::UnusedSwitch(UnicodeString & Switch)
   return Result;
   return Result;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+bool __fastcall TOptions::WasSwitchAdded(UnicodeString & Switch)
+{
+  bool Result =
+    ALWAYS_TRUE(FOptions.size() > 0) &&
+    (FOptions.back().Type == otSwitch);
+  if (Result)
+  {
+    Switch = FOptions.back().Name;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall TOptions::ParamsProcessed(int ParamsStart, int ParamsCount)
 void __fastcall TOptions::ParamsProcessed(int ParamsStart, int ParamsCount)
 {
 {
   if (ParamsCount > 0)
   if (ParamsCount > 0)
@@ -278,3 +292,30 @@ void __fastcall TOptions::ParamsProcessed(int ParamsStart, int ParamsCount)
     }
     }
   }
   }
 }
 }
+//---------------------------------------------------------------------------
+void __fastcall TOptions::LogOptions(TLogOptionEvent OnLogOption)
+{
+  for (size_t Index = 0; Index < FOriginalOptions.size(); Index++)
+  {
+    const TOption & Option = FOriginalOptions[Index];
+    UnicodeString LogStr;
+    switch (Option.Type)
+    {
+      case otParam:
+        LogStr = FORMAT(L"Parameter: %s", (Option.Value));
+        assert(Option.Name.IsEmpty());
+        break;
+
+      case otSwitch:
+        LogStr =
+          FORMAT(L"Switch:    %s%s%s%s",
+            (FSwitchMarks[1], Option.Name, (Option.Value.IsEmpty() ? UnicodeString() : FSwitchValueDelimiters.SubString(1, 1)), Option.Value));
+        break;
+
+      default:
+        FAIL;
+        break;
+    }
+    OnLogOption(LogStr);
+  }
+}

+ 8 - 1
source/core/Option.h

@@ -6,6 +6,8 @@
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 enum TOptionType { otParam, otSwitch };
 enum TOptionType { otParam, otSwitch };
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+typedef void __fastcall (__closure *TLogOptionEvent)(const UnicodeString & LogStr);
+//---------------------------------------------------------------------------
 class TOptions
 class TOptions
 {
 {
 public:
 public:
@@ -22,6 +24,9 @@ public:
   bool __fastcall SwitchValue(const UnicodeString Switch, bool Default);
   bool __fastcall SwitchValue(const UnicodeString Switch, bool Default);
   bool __fastcall SwitchValue(const UnicodeString Switch, bool Default, bool DefaultOnNonExistence);
   bool __fastcall SwitchValue(const UnicodeString Switch, bool Default, bool DefaultOnNonExistence);
   bool __fastcall UnusedSwitch(UnicodeString & Switch);
   bool __fastcall UnusedSwitch(UnicodeString & Switch);
+  bool __fastcall WasSwitchAdded(UnicodeString & Switch);
+
+  void __fastcall LogOptions(TLogOptionEvent OnEnumOption);
 
 
   __property int ParamCount = { read = FParamCount };
   __property int ParamCount = { read = FParamCount };
   __property UnicodeString Param[int Index] = { read = GetParam };
   __property UnicodeString Param[int Index] = { read = GetParam };
@@ -45,7 +50,9 @@ private:
     bool Used;
     bool Used;
   };
   };
 
 
-  std::vector<TOption> FOptions;
+  typedef std::vector<TOption> TOptionsVector;
+  TOptionsVector FOptions;
+  TOptionsVector FOriginalOptions;
   bool FNoMoreSwitches;
   bool FNoMoreSwitches;
   int FParamCount;
   int FParamCount;
 
 

+ 50 - 13
source/core/Script.cpp

@@ -443,6 +443,11 @@ void __fastcall TScript::Log(TLogLineType Type, AnsiString Str)
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+void __fastcall TScript::LogOption(const UnicodeString & LogStr)
+{
+  Log(llInput, LogStr);
+}
+//---------------------------------------------------------------------------
 void __fastcall TScript::LogPendingLines(TTerminal * ATerminal)
 void __fastcall TScript::LogPendingLines(TTerminal * ATerminal)
 {
 {
   if (IsTerminalLogging(ATerminal) && (FPendingLogLines->Count > 0))
   if (IsTerminalLogging(ATerminal) && (FPendingLogLines->Count > 0))
@@ -487,6 +492,16 @@ void __fastcall TScript::Command(UnicodeString Cmd)
         UnicodeString LogCmd = GetLogCmd(FullCmd, Command, Cmd);
         UnicodeString LogCmd = GetLogCmd(FullCmd, Command, Cmd);
         Log(llInput, LogCmd);
         Log(llInput, LogCmd);
 
 
+        if (Configuration->LogProtocol >= 1)
+        {
+          UnicodeString DummyLogCmd;
+          if (ALWAYS_TRUE(CutToken(LogCmd, DummyLogCmd)))
+          {
+            std::unique_ptr<TScriptProcParams> Parameters(new TScriptProcParams(LogCmd));
+            Parameters->LogOptions(LogOption);
+          }
+        }
+
         if (FEcho)
         if (FEcho)
         {
         {
           PrintLine(LogCmd);
           PrintLine(LogCmd);
@@ -2300,33 +2315,55 @@ UnicodeString __fastcall TManagementScript::GetLogCmd(const UnicodeString & Full
     UnicodeString AParams = Params;
     UnicodeString AParams = Params;
     std::unique_ptr<TScriptProcParams> Parameters(new TScriptProcParams(L""));
     std::unique_ptr<TScriptProcParams> Parameters(new TScriptProcParams(L""));
 
 
-    UnicodeString MaskedParams;
+    UnicodeString Url;
+    UnicodeString MaskedParamsPre;
+    UnicodeString MaskedParamsPost;
+
     UnicodeString Param;
     UnicodeString Param;
     UnicodeString RawParam;
     UnicodeString RawParam;
-    while ((Parameters->ParamCount == 0) && CutToken(AParams, Param, &RawParam))
+    bool AnySensitiveOption = false;
+
+    while (CutToken(AParams, Param, &RawParam))
     {
     {
       Parameters->Add(Param);
       Parameters->Add(Param);
-      if (Parameters->ParamCount == 0)
+      if ((Parameters->ParamCount == 1) && Url.IsEmpty())
       {
       {
+        Url = Param;
+      }
+      else
+      {
+        UnicodeString & MaskedParams = Url.IsEmpty() ? MaskedParamsPre : MaskedParamsPost;
+
+        UnicodeString Switch;
+        if (Parameters->WasSwitchAdded(Switch) &&
+            TSessionData::IsSensitiveOption(Switch))
+        {
+          // We should use something like TProgramParams::FormatSwitch here
+          RawParam = FORMAT(L"-%s=***", (Switch));
+          AnySensitiveOption = true;
+        }
         AddToList(MaskedParams, RawParam, L" ");
         AddToList(MaskedParams, RawParam, L" ");
       }
       }
     }
     }
 
 
-    if (Parameters->ParamCount > 0)
+    if (!Url.IsEmpty() || AnySensitiveOption)
     {
     {
-      UnicodeString Session = Parameters->Param[1];
-
       UnicodeString MaskedUrl;
       UnicodeString MaskedUrl;
       bool DefaultsOnly;
       bool DefaultsOnly;
 
 
-      std::unique_ptr<TSessionData> Data(
-        FStoredSessions->ParseUrl(Session, Parameters.get(), DefaultsOnly, NULL, NULL, &MaskedUrl));
-      if (Session != MaskedUrl)
+      if (!Url.IsEmpty())
+      {
+        std::unique_ptr<TSessionData> Data(
+          FStoredSessions->ParseUrl(Url, Parameters.get(), DefaultsOnly, NULL, NULL, &MaskedUrl));
+      }
+
+      if ((Url != MaskedUrl) || AnySensitiveOption)
       {
       {
-        // todo: quote, if necessary
-        AddToList(MaskedParams, MaskedUrl, L" ");
-        AddToList(MaskedParams, AParams, L" ");
-        Result = Command + L" " + MaskedParams;
+        Result = Command;
+        // AddToList is noop, when respective component is empty
+        AddToList(Result, MaskedParamsPre, L" ");
+        AddToList(Result, MaskedUrl, L" ");
+        AddToList(Result, MaskedParamsPost, L" ");
       }
       }
     }
     }
   }
   }

+ 1 - 0
source/core/Script.h

@@ -173,6 +173,7 @@ private:
   bool __fastcall HasNonDefaultCopyParams();
   bool __fastcall HasNonDefaultCopyParams();
   void __fastcall CheckDefaultSynchronizeParams();
   void __fastcall CheckDefaultSynchronizeParams();
   void __fastcall NotSupported();
   void __fastcall NotSupported();
+  void __fastcall LogOption(const UnicodeString & LogStr);
 };
 };
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 typedef void __fastcall (__closure *TScriptInputEvent)(TScript * Script, const UnicodeString Prompt, UnicodeString & Str);
 typedef void __fastcall (__closure *TScriptInputEvent)(TScript * Script, const UnicodeString Prompt, UnicodeString & Str);

+ 11 - 0
source/core/SecureShell.cpp

@@ -2328,6 +2328,17 @@ void __fastcall TSecureShell::CollectUsage()
   {
   {
     Configuration->Usage->Inc(L"OpenedSessionsSSHComplete");
     Configuration->Usage->Inc(L"OpenedSessionsSSHComplete");
   }
   }
+  // SSH-2.0-CoreFTP-0.3.3
+  else if (ContainsText(FSessionInfo.SshImplementation, L"CoreFTP"))
+  {
+    Configuration->Usage->Inc(L"OpenedSessionsSSHCore");
+  }
+  // SSH-2.0-SSHD-CORE-0.11.0 (value is configurable, this is a default)
+  // (Apache Mina SSHD, e.g. on brickftp.com)
+  else if (ContainsText(FSessionInfo.SshImplementation, L"SSHD-CORE"))
+  {
+    Configuration->Usage->Inc(L"OpenedSessionsSSHApache");
+  }
   else
   else
   {
   {
     Configuration->Usage->Inc(L"OpenedSessionsSSHOther");
     Configuration->Usage->Inc(L"OpenedSessionsSSHOther");

+ 23 - 1
source/core/SessionData.cpp

@@ -52,6 +52,7 @@ const wchar_t UrlParamSeparator = L';';
 const wchar_t UrlParamValueSeparator = L'=';
 const wchar_t UrlParamValueSeparator = L'=';
 const UnicodeString UrlHostKeyParamName(L"fingerprint");
 const UnicodeString UrlHostKeyParamName(L"fingerprint");
 const UnicodeString UrlSaveParamName(L"save");
 const UnicodeString UrlSaveParamName(L"save");
+const UnicodeString PassphraseOption(L"passphrase");
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
 TDateTime __fastcall SecToDateTime(int Sec)
 TDateTime __fastcall SecToDateTime(int Sec)
 {
 {
@@ -69,6 +70,22 @@ _fastcall TSessionData::~TSessionData()
 {
 {
 }
 }
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
+int __fastcall TSessionData::Compare(TNamedObject * Other)
+{
+  int Result;
+  // To avoid using CompareLogicalText on hex names of sessions in workspace.
+  // The session 000A would be sorted before 0001.
+  if (IsWorkspace && NOT_NULL(dynamic_cast<TSessionData *>(Other))->IsWorkspace)
+  {
+    Result = CompareText(Name, Other->Name);
+  }
+  else
+  {
+    Result = TNamedObject::Compare(Other);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::Default()
 void __fastcall TSessionData::Default()
 {
 {
   HostName = L"";
   HostName = L"";
@@ -1228,6 +1245,11 @@ bool __fastcall TSessionData::IsProtocolUrl(
     DoIsProtocolUrl(Url, WinSCPProtocolPrefix + Protocol, ProtocolLen);
     DoIsProtocolUrl(Url, WinSCPProtocolPrefix + Protocol, ProtocolLen);
 }
 }
 //---------------------------------------------------------------------
 //---------------------------------------------------------------------
+bool __fastcall TSessionData::IsSensitiveOption(const UnicodeString & Option)
+{
+  return AnsiSameText(Option, PassphraseOption);
+}
+//---------------------------------------------------------------------
 bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
 bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
   TStoredSessionList * StoredSessions, bool & DefaultsOnly, UnicodeString * FileName,
   TStoredSessionList * StoredSessions, bool & DefaultsOnly, UnicodeString * FileName,
   bool * AProtocolDefined, UnicodeString * MaskedUrl)
   bool * AProtocolDefined, UnicodeString * MaskedUrl)
@@ -1513,7 +1535,7 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
     {
     {
       PublicKeyFile = Value;
       PublicKeyFile = Value;
     }
     }
-    if (Options->FindSwitch(L"passphrase", Value))
+    if (Options->FindSwitch(PassphraseOption, Value))
     {
     {
       Passphrase = Value;
       Passphrase = Value;
     }
     }

+ 2 - 1
source/core/SessionData.h

@@ -205,7 +205,6 @@ private:
   UnicodeString __fastcall GetUserNameExpanded();
   UnicodeString __fastcall GetUserNameExpanded();
   void __fastcall SetPassword(UnicodeString value);
   void __fastcall SetPassword(UnicodeString value);
   UnicodeString __fastcall GetPassword() const;
   UnicodeString __fastcall GetPassword() const;
-  void __fastcall SetPasswordless(bool value);
   void __fastcall SetPingInterval(int value);
   void __fastcall SetPingInterval(int value);
   void __fastcall SetTryAgent(bool value);
   void __fastcall SetTryAgent(bool value);
   void __fastcall SetAgentFwd(bool value);
   void __fastcall SetAgentFwd(bool value);
@@ -382,6 +381,7 @@ public:
   void __fastcall Remove();
   void __fastcall Remove();
   void __fastcall CacheHostKeyIfNotCached();
   void __fastcall CacheHostKeyIfNotCached();
   virtual void __fastcall Assign(TPersistent * Source);
   virtual void __fastcall Assign(TPersistent * Source);
+  virtual int __fastcall Compare(TNamedObject * Other);
   void __fastcall CopyData(TSessionData * Source);
   void __fastcall CopyData(TSessionData * Source);
   void __fastcall CopyDirectoriesStateData(TSessionData * SourceData);
   void __fastcall CopyDirectoriesStateData(TSessionData * SourceData);
   bool __fastcall ParseUrl(UnicodeString Url, TOptions * Options,
   bool __fastcall ParseUrl(UnicodeString Url, TOptions * Options,
@@ -401,6 +401,7 @@ public:
   static UnicodeString __fastcall ExtractLocalName(const UnicodeString & Name);
   static UnicodeString __fastcall ExtractLocalName(const UnicodeString & Name);
   static UnicodeString __fastcall ExtractFolderName(const UnicodeString & Name);
   static UnicodeString __fastcall ExtractFolderName(const UnicodeString & Name);
   static UnicodeString __fastcall ComposePath(const UnicodeString & Path, const UnicodeString & Name);
   static UnicodeString __fastcall ComposePath(const UnicodeString & Path, const UnicodeString & Name);
+  static bool __fastcall IsSensitiveOption(const UnicodeString & Option);
 
 
   __property UnicodeString HostName  = { read=FHostName, write=SetHostName };
   __property UnicodeString HostName  = { read=FHostName, write=SetHostName };
   __property UnicodeString HostNameExpanded  = { read=GetHostNameExpanded };
   __property UnicodeString HostNameExpanded  = { read=GetHostNameExpanded };

+ 43 - 9
source/core/SessionInfo.cpp

@@ -956,6 +956,9 @@ UnicodeString __fastcall TSessionLog::LogSensitive(const UnicodeString & Str)
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+#define ADSTR(S) DoAdd(llMessage, S, DoAddToSelf);
+#define ADF(S, F) ADSTR(FORMAT(S, F));
+//---------------------------------------------------------------------------
 void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
 void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
 {
 {
   TGuard Guard(FCriticalSection);
   TGuard Guard(FCriticalSection);
@@ -963,8 +966,6 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
   BeginUpdate();
   BeginUpdate();
   try
   try
   {
   {
-    #define ADSTR(S) DoAdd(llMessage, S, DoAddToSelf);
-    #define ADF(S, F) ADSTR(FORMAT(S, F));
     if (Data == NULL)
     if (Data == NULL)
     {
     {
       AddSeparator();
       AddSeparator();
@@ -985,10 +986,32 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
       {
       {
         wcscpy(UserName, L"<Failed to retrieve username>");
         wcscpy(UserName, L"<Failed to retrieve username>");
       }
       }
+      UnicodeString LogStr;
+      if (FConfiguration->LogProtocol <= 0)
+      {
+        LogStr = L"Normal";
+      }
+      else if (FConfiguration->LogProtocol == 1)
+      {
+        LogStr = L"Debug 1";
+      }
+      else if (FConfiguration->LogProtocol >= 2)
+      {
+        LogStr = L"Debug 2";
+      }
+      if (FConfiguration->LogSensitive)
+      {
+        LogStr += L", Logging passwords";
+      }
+      ADF(L"Log level: %s", (LogStr));
       ADF(L"Local account: %s", (UserName));
       ADF(L"Local account: %s", (UserName));
       ADF(L"Working directory: %s", (GetCurrentDir()));
       ADF(L"Working directory: %s", (GetCurrentDir()));
       ADF(L"Process ID: %d", (int(GetCurrentProcessId())));
       ADF(L"Process ID: %d", (int(GetCurrentProcessId())));
       ADF(L"Command-line: %s", (CmdLine));
       ADF(L"Command-line: %s", (CmdLine));
+      if (FConfiguration->LogProtocol >= 1)
+      {
+        AddOptions(GetGlobalOptions());
+      }
       ADF(L"Time zone: %s", (GetTimeZoneLogString()));
       ADF(L"Time zone: %s", (GetTimeZoneLogString()));
       if (!AdjustClockForDSTEnabled())
       if (!AdjustClockForDSTEnabled())
       {
       {
@@ -1077,6 +1100,7 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
         }
         }
         ADF(L"Ciphers: %s; Ssh2DES: %s",
         ADF(L"Ciphers: %s; Ssh2DES: %s",
           (Data->CipherList, BooleanToEngStr(Data->Ssh2DES)));
           (Data->CipherList, BooleanToEngStr(Data->Ssh2DES)));
+        ADF(L"KEX: %s", (Data->KexList));
         UnicodeString Bugs;
         UnicodeString Bugs;
         for (int Index = 0; Index < BUG_COUNT; Index++)
         for (int Index = 0; Index < BUG_COUNT; Index++)
         {
         {
@@ -1157,12 +1181,12 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
       UnicodeString TimeInfo;
       UnicodeString TimeInfo;
       if ((Data->FSProtocol == fsSFTP) || (Data->FSProtocol == fsSFTPonly) || (Data->FSProtocol == fsSCPonly) || (Data->FSProtocol == fsWebDAV))
       if ((Data->FSProtocol == fsSFTP) || (Data->FSProtocol == fsSFTPonly) || (Data->FSProtocol == fsSCPonly) || (Data->FSProtocol == fsWebDAV))
       {
       {
-        AddToList(TimeInfo, FORMAT("DST mode: %d", (int(Data->DSTMode))), L";");
+        AddToList(TimeInfo, FORMAT(L"DST mode: %d", (int(Data->DSTMode))), L";");
       }
       }
       if ((Data->FSProtocol == fsSCPonly) || (Data->FSProtocol == fsFTP))
       if ((Data->FSProtocol == fsSCPonly) || (Data->FSProtocol == fsFTP))
       {
       {
         int TimeDifferenceMin = TimeToMinutes(Data->TimeDifference);
         int TimeDifferenceMin = TimeToMinutes(Data->TimeDifference);
-        AddToList(TimeInfo, FORMAT("Timezone offset: %dh %dm", ((TimeDifferenceMin / MinsPerHour), (TimeDifferenceMin % MinsPerHour))), L";");
+        AddToList(TimeInfo, FORMAT(L"Timezone offset: %dh %dm", ((TimeDifferenceMin / MinsPerHour), (TimeDifferenceMin % MinsPerHour))), L";");
       }
       }
       ADSTR(TimeInfo);
       ADSTR(TimeInfo);
 
 
@@ -1174,9 +1198,6 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
 
 
       AddSeparator();
       AddSeparator();
     }
     }
-
-    #undef ADF
-    #undef ADSTR
   }
   }
   __finally
   __finally
   {
   {
@@ -1186,6 +1207,19 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+void __fastcall TSessionLog::AddOption(const UnicodeString & LogStr)
+{
+  ADSTR(LogStr);
+}
+//---------------------------------------------------------------------------
+void __fastcall TSessionLog::AddOptions(TOptions * Options)
+{
+  Options->LogOptions(AddOption);
+}
+//---------------------------------------------------------------------------
+#undef ADF
+#undef ADSTR
+//---------------------------------------------------------------------------
 void __fastcall TSessionLog::AddSeparator()
 void __fastcall TSessionLog::AddSeparator()
 {
 {
   Add(llMessage, L"--------------------------------------------------------------------------");
   Add(llMessage, L"--------------------------------------------------------------------------");
@@ -1422,7 +1456,7 @@ void __fastcall TActionLog::BeginGroup(UnicodeString Name)
   assert(!FInGroup);
   assert(!FInGroup);
   FInGroup = true;
   FInGroup = true;
   assert(FIndent == L"  ");
   assert(FIndent == L"  ");
-  AddIndented(FORMAT("<group name=\"%s\" start=\"%s\">",
+  AddIndented(FORMAT(L"<group name=\"%s\" start=\"%s\">",
     (XmlAttributeEscape(Name), StandardTimestamp())));
     (XmlAttributeEscape(Name), StandardTimestamp())));
   FIndent = L"    ";
   FIndent = L"    ";
 }
 }
@@ -1437,7 +1471,7 @@ void __fastcall TActionLog::EndGroup()
   // so do not try to close the group, if it has not been opened, to avoid recursion
   // so do not try to close the group, if it has not been opened, to avoid recursion
   if (FFile != NULL)
   if (FFile != NULL)
   {
   {
-    AddIndented("</group>");
+    AddIndented(L"</group>");
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------

+ 2 - 0
source/core/SessionInfo.h

@@ -286,6 +286,8 @@ private:
   void __fastcall DoAddStartupInfo(TSessionData * Data);
   void __fastcall DoAddStartupInfo(TSessionData * Data);
   UnicodeString __fastcall GetTlsVersionName(TTlsVersion TlsVersion);
   UnicodeString __fastcall GetTlsVersionName(TTlsVersion TlsVersion);
   UnicodeString __fastcall LogSensitive(const UnicodeString & Str);
   UnicodeString __fastcall LogSensitive(const UnicodeString & Str);
+  void __fastcall AddOption(const UnicodeString & LogStr);
+  void __fastcall AddOptions(TOptions * Options);
 };
 };
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 class TActionLog
 class TActionLog

+ 3 - 2
source/core/SftpFileSystem.cpp

@@ -2008,6 +2008,7 @@ void __fastcall TSFTPFileSystem::Idle()
     if ((FTerminal->SessionData->PingType == ptDummyCommand) &&
     if ((FTerminal->SessionData->PingType == ptDummyCommand) &&
         FSecureShell->Ready)
         FSecureShell->Ready)
     {
     {
+      FTerminal->LogEvent(L"Sending dummy command to keep session alive.");
       TSFTPPacket Packet(SSH_FXP_REALPATH);
       TSFTPPacket Packet(SSH_FXP_REALPATH);
       Packet.AddPathString(L"/", FUtfStrings);
       Packet.AddPathString(L"/", FUtfStrings);
       SendPacketAndReceiveResponse(&Packet, &Packet);
       SendPacketAndReceiveResponse(&Packet, &Packet);
@@ -4554,9 +4555,9 @@ void __fastcall TSFTPFileSystem::SFTPSource(const UnicodeString FileName,
             // if file has all permissions and is small, then it is likely symlink.
             // if file has all permissions and is small, then it is likely symlink.
             // also it is not likely that such a small file (if it is not symlink)
             // also it is not likely that such a small file (if it is not symlink)
             // gets overwritten by large file (that would trigger resumable transfer).
             // gets overwritten by large file (that would trigger resumable transfer).
-            // - Also never do resumable transfer for file owner by other user
+            // - Also never do resumable transfer for file owned by other user
             // as deleting and recreating the file would change ownership.
             // as deleting and recreating the file would change ownership.
-            // This won't for work for SFT-3 (OpenSSH) as it does not provide
+            // This won't for work for SFTP-3 (OpenSSH) as it does not provide
             // owner name (only UID) and we know only logged in user name (not UID)
             // owner name (only UID) and we know only logged in user name (not UID)
             if (File->IsSymLink ||
             if (File->IsSymLink ||
                 ((FVersion < 4) &&
                 ((FVersion < 4) &&

+ 15 - 17
source/core/WebDAVFileSystem.cpp

@@ -181,6 +181,10 @@ void __fastcall NeonInitialize()
   // Even if this fails, we do not want to interrupt WinSCP starting for that.
   // Even if this fails, we do not want to interrupt WinSCP starting for that.
   // We may possibly remember that and fail opening session later.
   // We may possibly remember that and fail opening session later.
   // Anyway, it can hardly fail.
   // Anyway, it can hardly fail.
+  // Though it fails on Wine on Debian VM.
+  // Probably because of ne_sspi_init() as we get this message on stderr:
+  // p11-kit: couldn't load module: /usr/lib/i386-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: /usr/lib/i386-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: cannot open shared object file: No such file or directory
+  // err:winediag:SECUR32_initNTLMSP ntlm_auth was not found or is outdated. Make sure that ntlm_auth >= 3.0.25 is in your path. Usually, you can find it in the winbind package of your distribution.
   ALWAYS_TRUE(ne_sock_init() == 0);
   ALWAYS_TRUE(ne_sock_init() == 0);
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -210,7 +214,6 @@ TWebDAVFileSystem::TWebDAVFileSystem(TTerminal * ATerminal) :
   FNeonSession(NULL),
   FNeonSession(NULL),
   FUploading(false),
   FUploading(false),
   FDownloading(false),
   FDownloading(false),
-  FUploadBodyProvider(NULL),
   FInitialHandshake(false),
   FInitialHandshake(false),
   FIgnoreAuthenticationFailure(iafNo)
   FIgnoreAuthenticationFailure(iafNo)
 {
 {
@@ -525,9 +528,14 @@ void __fastcall TWebDAVFileSystem::CollectUsage()
   {
   {
     FTerminal->Configuration->Usage->Inc(L"OpenedSessionsWebDAVITHit");
     FTerminal->Configuration->Usage->Inc(L"OpenedSessionsWebDAVITHit");
   }
   }
+  // e.g. brickftp.com
+  else if (ContainsText(RemoteSystem, L"nginx"))
+  {
+    FTerminal->Configuration->Usage->Inc(L"OpenedSessionsWebDAVNginx");
+  }
   else
   else
   {
   {
-    // Web also know OpenDrive, Yandex, iFiles (iOS), Swapper (iOS), SafeSync
+    // We also know OpenDrive, Yandex, iFiles (iOS), Swapper (iOS), SafeSync
     FTerminal->Configuration->Usage->Inc(L"OpenedSessionsWebDAVOther");
     FTerminal->Configuration->Usage->Inc(L"OpenedSessionsWebDAVOther");
   }
   }
 }
 }
@@ -1442,8 +1450,6 @@ void __fastcall TWebDAVFileSystem::Source(const UnicodeString FileName,
   }
   }
   __finally
   __finally
   {
   {
-    FUploadBodyProvider = NULL;
-
     if (FD >= 0)
     if (FD >= 0)
     {
     {
       // _close calls CloseHandle internally (even doc states, we should not call CloseHandle),
       // _close calls CloseHandle internally (even doc states, we should not call CloseHandle),
@@ -1675,7 +1681,7 @@ void TWebDAVFileSystem::NeonPreSend(
     // http://lists.manyfish.co.uk/pipermail/neon/2012-April/001452.html
     // http://lists.manyfish.co.uk/pipermail/neon/2012-April/001452.html
     // It's also supported by Oracle server:
     // It's also supported by Oracle server:
     // https://docs.oracle.com/cd/E19146-01/821-1828/gczya/index.html
     // https://docs.oracle.com/cd/E19146-01/821-1828/gczya/index.html
-    // We do not know yet of ay server that fails when the header is used,
+    // We do not know yet of any server that fails when the header is used,
     // so it's added unconditionally.
     // so it's added unconditionally.
     ne_buffer_zappend(Header, "Translate: f\r\n");
     ne_buffer_zappend(Header, "Translate: f\r\n");
   }
   }
@@ -1688,7 +1694,6 @@ void TWebDAVFileSystem::NeonPreSend(
     {
     {
       // all neon request types that use ne_add_request_header
       // all neon request types that use ne_add_request_header
       // use XML content-type, so it's text-based
       // use XML content-type, so it's text-based
-      USEDPARAM(Header);
       assert(ContainsStr(AnsiString(Header->data, Header->used), "Content-Type: " NE_XML_MEDIA_TYPE));
       assert(ContainsStr(AnsiString(Header->data, Header->used), "Content-Type: " NE_XML_MEDIA_TYPE));
       FileSystem->FTerminal->Log->Add(llInput, UnicodeString(UTF8String(Buffer, Size)));
       FileSystem->FTerminal->Log->Add(llInput, UnicodeString(UTF8String(Buffer, Size)));
     }
     }
@@ -1696,14 +1701,8 @@ void TWebDAVFileSystem::NeonPreSend(
 
 
   if (FileSystem->FUploading)
   if (FileSystem->FUploading)
   {
   {
-    // this may get called multiple times per request,
-    // for example when authentication fails
-    ne_set_request_body_provider_proxy(Request,
-      FileSystem->NeonUploadBodyProvider, FileSystem,
-      &FileSystem->FUploadBodyProvider,
-      &FileSystem->FUploadBodyProviderUserData);
-
-    assert(FileSystem->FUploadBodyProvider != NULL);
+    ne_set_request_body_provider_pre(Request,
+      FileSystem->NeonUploadBodyProvider, FileSystem);
   }
   }
 
 
   FileSystem->FResponse = L"";
   FileSystem->FResponse = L"";
@@ -1720,10 +1719,9 @@ int TWebDAVFileSystem::NeonPostSend(ne_request * /*Req*/, void * UserData,
   return NE_OK;
   return NE_OK;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-ssize_t TWebDAVFileSystem::NeonUploadBodyProvider(void * UserData, char * Buffer, size_t BufLen)
+ssize_t TWebDAVFileSystem::NeonUploadBodyProvider(void * UserData, char * /*Buffer*/, size_t /*BufLen*/)
 {
 {
   TWebDAVFileSystem * FileSystem = static_cast<TWebDAVFileSystem *>(UserData);
   TWebDAVFileSystem * FileSystem = static_cast<TWebDAVFileSystem *>(UserData);
-  assert(FileSystem->FUploadBodyProvider != NULL);
   ssize_t Result;
   ssize_t Result;
   if (FileSystem->CancelTransfer())
   if (FileSystem->CancelTransfer())
   {
   {
@@ -1731,7 +1729,7 @@ ssize_t TWebDAVFileSystem::NeonUploadBodyProvider(void * UserData, char * Buffer
   }
   }
   else
   else
   {
   {
-    Result = FileSystem->FUploadBodyProvider(FileSystem->FUploadBodyProviderUserData, Buffer, BufLen);
+    Result = 1;
   }
   }
   return Result;
   return Result;
 }
 }

+ 0 - 2
source/core/WebDAVFileSystem.h

@@ -150,8 +150,6 @@ private:
   ne_session_s * FNeonSession;
   ne_session_s * FNeonSession;
   bool FInitialHandshake;
   bool FInitialHandshake;
   bool FAuthenticationRequested;
   bool FAuthenticationRequested;
-  ne_provide_body FUploadBodyProvider;
-  void * FUploadBodyProviderUserData;
   UnicodeString FResponse;
   UnicodeString FResponse;
   RawByteString FPassword;
   RawByteString FPassword;
   UnicodeString FTlsVersionStr;
   UnicodeString FTlsVersionStr;

+ 14 - 1
source/dragext/DragExt.cpp

@@ -823,7 +823,20 @@ STDMETHODIMP_(UINT) CShellExt::CopyCallback(HWND /*Hwnd*/, UINT Func, UINT /*Fla
   }
   }
   else
   else
   {
   {
-    DEBUG(L"CShellExt::CopyCallback NOT copy nor move");
+    if (!GEnabled)
+    {
+      DEBUG(L"CShellExt::CopyCallback Disabled");
+    }
+    else
+    {
+      wchar_t Buf[1024];
+      wcscpy(Buf, L"CShellExt::CopyCallback NOT copy nor move - X");
+      // This is to avoid using swprintf, what's in a lib,
+      // we do not link yet, in 64-bit build (maybe this changes, once
+      // we switch to BCB build)
+      Buf[wcslen(Buf) - 1] = L'0' + Func;
+      DEBUG(Buf);
+    }
   }
   }
 
 
   DEBUG(L"CShellExt::CopyCallback leave");
   DEBUG(L"CShellExt::CopyCallback leave");

+ 6 - 13
source/filezilla/ApiLog.cpp

@@ -76,7 +76,7 @@ bool CApiLog::LoggingMessageType(int nMessageType) const
 
 
 void CApiLog::LogMessage(int nMessageType, LPCTSTR pMsgFormat, ...) const
 void CApiLog::LogMessage(int nMessageType, LPCTSTR pMsgFormat, ...) const
 {
 {
-	ASSERT(nMessageType>=0 && nMessageType<=8);
+	ASSERT(nMessageType>=FZ_LOG_STATUS && nMessageType<=FZ_LOG_DEBUG);
 	ASSERT(m_hTargetWnd || m_pApiLogParent);
 	ASSERT(m_hTargetWnd || m_pApiLogParent);
 	if (!LoggingMessageType(nMessageType))
 	if (!LoggingMessageType(nMessageType))
 		return;
 		return;
@@ -97,7 +97,7 @@ void CApiLog::LogMessage(int nMessageType, LPCTSTR pMsgFormat, ...) const
 
 
 void CApiLog::LogMessageRaw(int nMessageType, LPCTSTR pMsg) const
 void CApiLog::LogMessageRaw(int nMessageType, LPCTSTR pMsg) const
 {
 {
-	ASSERT(nMessageType>=0 && nMessageType<=8);
+	ASSERT(nMessageType>=FZ_LOG_STATUS && nMessageType<=FZ_LOG_DEBUG);
 	ASSERT(m_hTargetWnd || m_pApiLogParent);
 	ASSERT(m_hTargetWnd || m_pApiLogParent);
 	if (!LoggingMessageType(nMessageType))
 	if (!LoggingMessageType(nMessageType))
 		return;
 		return;
@@ -111,7 +111,7 @@ void CApiLog::LogMessageRaw(int nMessageType, LPCTSTR pMsg) const
 
 
 void CApiLog::LogMessage(int nMessageType, UINT nFormatID, ...) const
 void CApiLog::LogMessage(int nMessageType, UINT nFormatID, ...) const
 {
 {
-	ASSERT(nMessageType>=0 && nMessageType<=8);
+	ASSERT(nMessageType>=FZ_LOG_STATUS && nMessageType<=FZ_LOG_DEBUG);
 	ASSERT(m_hTargetWnd || m_pApiLogParent);
 	ASSERT(m_hTargetWnd || m_pApiLogParent);
 	if (!LoggingMessageType(nMessageType))
 	if (!LoggingMessageType(nMessageType))
 		return;
 		return;
@@ -135,7 +135,7 @@ void CApiLog::LogMessage(int nMessageType, UINT nFormatID, ...) const
 
 
 void CApiLog::LogMessage(CString SourceFile, int nSourceLine, void *pInstance, int nMessageType, LPCTSTR pMsgFormat, ...) const
 void CApiLog::LogMessage(CString SourceFile, int nSourceLine, void *pInstance, int nMessageType, LPCTSTR pMsgFormat, ...) const
 {
 {
-	ASSERT(nMessageType>=4 && nMessageType<=8);
+	ASSERT(nMessageType>=FZ_LOG_LIST && nMessageType<=FZ_LOG_DEBUG);
 	ASSERT(m_hTargetWnd || m_pApiLogParent);
 	ASSERT(m_hTargetWnd || m_pApiLogParent);
 	ASSERT(nSourceLine>0);
 	ASSERT(nSourceLine>0);
 
 
@@ -171,7 +171,7 @@ BOOL CApiLog::PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) con
 
 
 void CApiLog::LogMessageRaw(CString SourceFile, int nSourceLine, void *pInstance, int nMessageType, LPCTSTR pMsg) const
 void CApiLog::LogMessageRaw(CString SourceFile, int nSourceLine, void *pInstance, int nMessageType, LPCTSTR pMsg) const
 {
 {
-	ASSERT(nMessageType>=4 && nMessageType<=8);
+	ASSERT(nMessageType>=FZ_LOG_LIST && FZ_LOG_DEBUG<=FZ_LOG_DEBUG);
 	ASSERT(m_hTargetWnd || m_pApiLogParent);
 	ASSERT(m_hTargetWnd || m_pApiLogParent);
 	ASSERT(nSourceLine>0);
 	ASSERT(nSourceLine>0);
 
 
@@ -240,15 +240,8 @@ BOOL CApiLog::SetDebugLevel(int nDebugLevel)
 {
 {
 	if (m_pApiLogParent)
 	if (m_pApiLogParent)
 		return FALSE;
 		return FALSE;
-	if (nDebugLevel<0 || nDebugLevel>4)
+	if (nDebugLevel<0 || nDebugLevel>5)
 		return FALSE;
 		return FALSE;
 	m_nDebugLevel=nDebugLevel;
 	m_nDebugLevel=nDebugLevel;
 	return TRUE;
 	return TRUE;
 }
 }
-
-int CApiLog::GetDebugLevel()
-{
-	if (m_pApiLogParent)
-		return m_pApiLogParent->m_nDebugLevel;
-	return m_nDebugLevel;
-}

+ 0 - 1
source/filezilla/ApiLog.h

@@ -45,7 +45,6 @@ public:
 	void LogMessageRaw(CString SourceFile, int nSourceLine, void *pInstance, int nMessageType, LPCTSTR pMsg) const;
 	void LogMessageRaw(CString SourceFile, int nSourceLine, void *pInstance, int nMessageType, LPCTSTR pMsg) const;
 
 
 	BOOL SetDebugLevel(int nLogLevel);
 	BOOL SetDebugLevel(int nLogLevel);
-	int GetDebugLevel();
 protected:
 protected:
 #ifdef MPEXT
 #ifdef MPEXT
 	virtual BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) const;
 	virtual BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) const;

+ 1 - 1
source/filezilla/AsyncSslSocketLayer.cpp

@@ -1179,7 +1179,7 @@ void CAsyncSslSocketLayer::apps_ssl_info_callback(const SSL *s, int where, int r
 				{
 				{
 					if (SSL_session_reused(pLayer->m_ssl))
 					if (SSL_session_reused(pLayer->m_ssl))
 					{
 					{
-						pLayer->LogSocketMessage(FZ_LOG_INFO, _T("Session ID reused"));
+						pLayer->LogSocketMessage(FZ_LOG_PROGRESS, _T("Session ID reused"));
 					}
 					}
 					else
 					else
 					{
 					{

+ 11 - 0
source/filezilla/ControlSocket.cpp

@@ -133,6 +133,17 @@ void CControlSocket::ShowStatus(CString status, int type) const
 }
 }
 
 
 
 
+void CControlSocket::ShowTimeoutError(UINT nID) const
+{
+	CString str1;
+	str1.LoadString(IDS_ERRORMSG_TIMEOUT);
+	CString str2;
+	str2.LoadString(nID);
+	CString message;
+	message.Format(L"%s (%s)", str1, str2);
+	ShowStatus(message, FZ_LOG_ERROR);
+}
+
 t_server CControlSocket::GetCurrentServer()
 t_server CControlSocket::GetCurrentServer()
 {
 {
 	return m_CurrentServer;
 	return m_CurrentServer;

+ 1 - 0
source/filezilla/ControlSocket.h

@@ -112,6 +112,7 @@ public:
 	t_server GetCurrentServer();
 	t_server GetCurrentServer();
 	void ShowStatus(UINT nID, int type) const;
 	void ShowStatus(UINT nID, int type) const;
 	void ShowStatus(CString status,int type) const;
 	void ShowStatus(CString status,int type) const;
+	void ShowTimeoutError(UINT nID) const;
 
 
 #ifdef MPEXT
 #ifdef MPEXT
 	virtual bool UsingMlsd() = 0;
 	virtual bool UsingMlsd() = 0;

+ 4 - 3
source/filezilla/FileZillaApi.h

@@ -285,11 +285,12 @@ public:
 #define FZ_LOG_COMMAND 2
 #define FZ_LOG_COMMAND 2
 #define FZ_LOG_REPLY 3
 #define FZ_LOG_REPLY 3
 #define FZ_LOG_LIST 4
 #define FZ_LOG_LIST 4
-//By calling CFileZillaApi::SetDebugLevel, the aplication can enable loggint of the following messages:
+//By calling CFileZillaApi::SetDebugLevel, the aplication can enable logging of the following messages:
 #define FZ_LOG_APIERROR 5
 #define FZ_LOG_APIERROR 5
 #define FZ_LOG_WARNING 6
 #define FZ_LOG_WARNING 6
-#define FZ_LOG_INFO 7
-#define FZ_LOG_DEBUG 8
+#define FZ_LOG_PROGRESS 7
+#define FZ_LOG_INFO 8
+#define FZ_LOG_DEBUG 9
 
 
 class CMainThread;
 class CMainThread;
 class CFileZillaTools;
 class CFileZillaTools;

+ 3 - 2
source/filezilla/FileZillaIntf.h

@@ -102,8 +102,9 @@ public:
     LOG_LIST = 4,
     LOG_LIST = 4,
     LOG_APIERROR = 5,
     LOG_APIERROR = 5,
     LOG_WARNING = 6,
     LOG_WARNING = 6,
-    LOG_INFO = 7,
-    LOG_DEBUG = 8
+    LOG_PROGRESS = 7,
+    LOG_INFO = 8,
+    LOG_DEBUG = 9
   };
   };
 
 
   enum TMessageType
   enum TMessageType

+ 22 - 24
source/filezilla/FtpControlSocket.cpp

@@ -675,7 +675,6 @@ void CFtpControlSocket::LogOnToServer(BOOL bSkipReply /*=FALSE*/)
 	{
 	{
 		#ifdef MPEXT
 		#ifdef MPEXT
 		std::string facts;
 		std::string facts;
-		// this is never true, see comment is DiscardLine
 		if (m_serverCapabilities.GetCapabilityString(mlsd_command, &facts) == yes)
 		if (m_serverCapabilities.GetCapabilityString(mlsd_command, &facts) == yes)
 		{
 		{
 			ftp_capabilities_t cap = m_serverCapabilities.GetCapabilityString(opts_mlst_command);
 			ftp_capabilities_t cap = m_serverCapabilities.GetCapabilityString(opts_mlst_command);
@@ -722,14 +721,14 @@ void CFtpControlSocket::LogOnToServer(BOOL bSkipReply /*=FALSE*/)
 					if (!strcmp(fact.c_str(), "type") ||
 					if (!strcmp(fact.c_str(), "type") ||
 						!strcmp(fact.c_str(), "size") ||
 						!strcmp(fact.c_str(), "size") ||
 						!strcmp(fact.c_str(), "modify") ||
 						!strcmp(fact.c_str(), "modify") ||
+						!strcmp(fact.c_str(), "create") ||
 						!strcmp(fact.c_str(), "perm") ||
 						!strcmp(fact.c_str(), "perm") ||
 						!strcmp(fact.c_str(), "unix.mode") ||
 						!strcmp(fact.c_str(), "unix.mode") ||
 						!strcmp(fact.c_str(), "unix.owner") ||
 						!strcmp(fact.c_str(), "unix.owner") ||
 						!strcmp(fact.c_str(), "unix.user") ||
 						!strcmp(fact.c_str(), "unix.user") ||
 						!strcmp(fact.c_str(), "unix.group") ||
 						!strcmp(fact.c_str(), "unix.group") ||
 						!strcmp(fact.c_str(), "unix.uid") ||
 						!strcmp(fact.c_str(), "unix.uid") ||
-						!strcmp(fact.c_str(), "unix.gid") ||
-						!strcmp(fact.c_str(), "x.hidden"))
+						!strcmp(fact.c_str(), "unix.gid"))
 					{
 					{
 						had_unset |= !enabled;
 						had_unset |= !enabled;
 						opts_facts += fact.c_str();
 						opts_facts += fact.c_str();
@@ -1164,7 +1163,7 @@ void CFtpControlSocket::OnReceive(int nErrorCode)
 		m_MultiLine = "";
 		m_MultiLine = "";
 		CString str;
 		CString str;
 		str.Format(IDS_STATUSMSG_CONNECTEDWITH, m_ServerName);
 		str.Format(IDS_STATUSMSG_CONNECTEDWITH, m_ServerName);
-		ShowStatus(str, FZ_LOG_STATUS);
+		ShowStatus(str, FZ_LOG_PROGRESS);
 		m_pOwner->SetConnected(TRUE);
 		m_pOwner->SetConnected(TRUE);
 	}
 	}
 	char *buffer = new char[BUFFERSIZE];
 	char *buffer = new char[BUFFERSIZE];
@@ -1357,7 +1356,7 @@ void CFtpControlSocket::OnConnect(int nErrorCode)
 				m_pSslLayer ? IDS_STATUSMSG_CONNECTEDWITHSSL :
 				m_pSslLayer ? IDS_STATUSMSG_CONNECTEDWITHSSL :
 #endif
 #endif
 				IDS_STATUSMSG_CONNECTEDWITH, m_ServerName);
 				IDS_STATUSMSG_CONNECTEDWITH, m_ServerName);
-			ShowStatus(str,FZ_LOG_STATUS);
+			ShowStatus(str,FZ_LOG_PROGRESS);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -1569,7 +1568,7 @@ void CFtpControlSocket::CheckForTimeout()
 	CTimeSpan span=CTime::GetCurrentTime()-m_LastRecvTime;
 	CTimeSpan span=CTime::GetCurrentTime()-m_LastRecvTime;
 	if (span.GetTotalSeconds()>=delay)
 	if (span.GetTotalSeconds()>=delay)
 	{
 	{
-		ShowStatus(IDS_ERRORMSG_TIMEOUT, FZ_LOG_ERROR);
+		ShowTimeoutError(IDS_CONTROL_CONNECTION);
 		DoClose();
 		DoClose();
 	}
 	}
 }
 }
@@ -1762,7 +1761,7 @@ void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath pa
 		}
 		}
 		else if (pData->pDirectoryListing && pData->nFinish==1)
 		else if (pData->pDirectoryListing && pData->nFinish==1)
 		{
 		{
-			ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL,FZ_LOG_STATUS);
+			ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL,FZ_LOG_PROGRESS);
 #ifndef MPEXT_NO_CACHE
 #ifndef MPEXT_NO_CACHE
 			CDirectoryCache cache;
 			CDirectoryCache cache;
 			cache.Lock();
 			cache.Lock();
@@ -1837,7 +1836,7 @@ void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath pa
 								}
 								}
 						if (bExact)
 						if (bExact)
 						{
 						{
-							ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_STATUS);
+							ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_PROGRESS);
 							SetDirectoryListing(&dir);
 							SetDirectoryListing(&dir);
 							ResetOperation(FZ_REPLY_OK);
 							ResetOperation(FZ_REPLY_OK);
 							return;
 							return;
@@ -1893,7 +1892,7 @@ void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath pa
 								}
 								}
 						if (bExact)
 						if (bExact)
 						{
 						{
-							ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_STATUS);
+							ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_PROGRESS);
 							SetDirectoryListing(&dir);
 							SetDirectoryListing(&dir);
 							ResetOperation(FZ_REPLY_OK);
 							ResetOperation(FZ_REPLY_OK);
 							return;
 							return;
@@ -1943,7 +1942,7 @@ void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath pa
 								}
 								}
 						if (bExact)
 						if (bExact)
 						{
 						{
-							ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_STATUS);
+							ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_PROGRESS);
 							SetDirectoryListing(&dir);
 							SetDirectoryListing(&dir);
 							ResetOperation(FZ_REPLY_OK);
 							ResetOperation(FZ_REPLY_OK);
 							return;
 							return;
@@ -2064,7 +2063,7 @@ void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath pa
 		case LIST_LIST:
 		case LIST_LIST:
 			if (IsMisleadingListResponse())
 			if (IsMisleadingListResponse())
 			{
 			{
-				ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_STATUS);
+				ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_PROGRESS);
 
 
 				t_directory listing;
 				t_directory listing;
 				listing.server = m_CurrentServer;
 				listing.server = m_CurrentServer;
@@ -2114,7 +2113,7 @@ void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath pa
 		pData->path=path;
 		pData->path=path;
 		pData->subdir=subdir;
 		pData->subdir=subdir;
 		m_Operation.pData=pData;
 		m_Operation.pData=pData;
-		ShowStatus(IDS_STATUSMSG_RETRIEVINGDIRLIST, FZ_LOG_STATUS);
+		ShowStatus(IDS_STATUSMSG_RETRIEVINGDIRLIST, FZ_LOG_PROGRESS);
 		pData->nFinish=-1;
 		pData->nFinish=-1;
 		if (m_pDirectoryListing)
 		if (m_pDirectoryListing)
 		{
 		{
@@ -2168,7 +2167,7 @@ void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath pa
 									}
 									}
 							if (bExact)
 							if (bExact)
 							{
 							{
-								ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL,FZ_LOG_STATUS);
+								ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL,FZ_LOG_PROGRESS);
 								SetDirectoryListing(&dir);
 								SetDirectoryListing(&dir);
 								ResetOperation(FZ_REPLY_OK);
 								ResetOperation(FZ_REPLY_OK);
 								return;
 								return;
@@ -2440,7 +2439,7 @@ void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath pa
 			hostname.Format(L"%s:%d", pData->host, pData->port);
 			hostname.Format(L"%s:%d", pData->host, pData->port);
 			CString str;
 			CString str;
 			str.Format(IDS_STATUSMSG_CONNECTING, hostname);
 			str.Format(IDS_STATUSMSG_CONNECTING, hostname);
-			ShowStatus(str, FZ_LOG_STATUS);
+			ShowStatus(str, FZ_LOG_PROGRESS);
 
 
 			// if PASV create the socket & initiate outbound data channel connection
 			// if PASV create the socket & initiate outbound data channel connection
 			if (!m_pTransferSocket->Connect(pData->host,pData->port))
 			if (!m_pTransferSocket->Connect(pData->host,pData->port))
@@ -3582,7 +3581,7 @@ void CFtpControlSocket::FileTransfer(t_transferfile *transferfile/*=0*/,BOOL bFi
 		case FILETRANSFER_LIST_LIST:
 		case FILETRANSFER_LIST_LIST:
 			if (IsMisleadingListResponse())
 			if (IsMisleadingListResponse())
 			{
 			{
-				ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_STATUS);
+				ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_PROGRESS);
 
 
 				t_directory listing;
 				t_directory listing;
 				listing.server = m_CurrentServer;
 				listing.server = m_CurrentServer;
@@ -5554,6 +5553,7 @@ void CFtpControlSocket::SetFileExistsAction(int nAction, COverwriteRequestData *
 
 
 void CFtpControlSocket::SendKeepAliveCommand()
 void CFtpControlSocket::SendKeepAliveCommand()
 {
 {
+	ShowStatus(L"Sending dummy command to keep session alive.", FZ_LOG_PROGRESS);
 	m_bKeepAliveActive=TRUE;
 	m_bKeepAliveActive=TRUE;
 	//Choose a random command from the list
 	//Choose a random command from the list
 	TCHAR commands[4][7]={_MPT("PWD"),_MPT("REST 0"),_MPT("TYPE A"),_MPT("TYPE I")};
 	TCHAR commands[4][7]={_MPT("PWD"),_MPT("REST 0"),_MPT("TYPE A"),_MPT("TYPE I")};
@@ -6354,14 +6354,12 @@ void CFtpControlSocket::DiscardLine(CStringA line)
 		else if (line.Left(4) == _MPAT("MLST"))
 		else if (line.Left(4) == _MPAT("MLST"))
 		{
 		{
 			USES_CONVERSION;
 			USES_CONVERSION;
-			// This is wrong, the -1 for length does not work with
-			// Mid(), so result is always an empty string.
-			// Consequently CONNECT_FEAT state code in
-			// LogOnToServer() is never triggered
-			// and OPTS MLST command is never sent.
-			// Also using 6 index when there are no facts after
-			// MLST (ftp.drivehq.com) triggers an assertion.
-			m_serverCapabilities.SetCapability(mlsd_command, yes, (LPCSTR)line.Mid(5, -1));
+			std::string facts;
+			if (line.GetLength() > 5)
+			{
+				facts = (LPCSTR)line.Mid(5, line.GetLength() - 5);
+			}
+			m_serverCapabilities.SetCapability(mlsd_command, yes, facts);
 		}
 		}
 		else if (line == _MPAT("MFMT"))
 		else if (line == _MPAT("MFMT"))
 		{
 		{
@@ -6575,7 +6573,7 @@ bool CFtpControlSocket::CheckForcePasvIp(CString & host)
 		default: // auto
 		default: // auto
 			if (!GetPeerName(ahost, tmpPort))
 			if (!GetPeerName(ahost, tmpPort))
 			{
 			{
-				LogMessage(__FILE__, __LINE__, this, FZ_LOG_INFO, _T("Error retrieving server address, cannot test if address is routable"));
+				LogMessage(__FILE__, __LINE__, this, FZ_LOG_PROGRESS, _T("Error retrieving server address, cannot test if address is routable"));
 			}
 			}
 			else if (!IsRoutableAddress(host) && IsRoutableAddress(ahost))
 			else if (!IsRoutableAddress(host) && IsRoutableAddress(ahost))
 			{
 			{

+ 19 - 23
source/filezilla/FtpListResult.cpp

@@ -661,6 +661,9 @@ void CFtpListResult::SendToMessageLog(HWND hWnd, UINT nMsg)
 	curpos = listhead;
 	curpos = listhead;
 	pos=0;
 	pos=0;
 	char *line = GetLine();
 	char *line = GetLine();
+	// Note that FZ_LOG_INFO here is not checked against debug level, as the direct
+	// call to PostMessage bypasses check in LogMessage.
+	// So we get the listing on any logging level, what is actually what we want
 	if (!line)
 	if (!line)
 	{
 	{
 		//Displays a message in the message log
 		//Displays a message in the message log
@@ -1331,6 +1334,8 @@ BOOL CFtpListResult::parseAsMlsd(const char *line, const int linelen, t_director
 		CString factname = facts.Left(pos);
 		CString factname = facts.Left(pos);
 		factname.MakeLower();
 		factname.MakeLower();
 		CString value = facts.Mid(pos + 1, delim - pos - 1);
 		CString value = facts.Mid(pos + 1, delim - pos - 1);
+		// When adding new facts, update filter in CFtpControlSocket::LogOnToServer
+		// (CONNECT_FEAT state)
 		if (factname == _T("type"))
 		if (factname == _T("type"))
 		{
 		{
 			if (!value.CompareNoCase(_T("dir")))
 			if (!value.CompareNoCase(_T("dir")))
@@ -1378,7 +1383,7 @@ BOOL CFtpListResult::parseAsMlsd(const char *line, const int linelen, t_director
 		else if (factname == _T("modify") ||
 		else if (factname == _T("modify") ||
 			(!direntry.date.hasdate && factname == _T("create")))
 			(!direntry.date.hasdate && factname == _T("create")))
 		{
 		{
-			if (!parseMlsdDateTime(value, direntry))
+			if (!parseMlsdDateTime(value, direntry.date))
 				return FALSE;
 				return FALSE;
 		}
 		}
 		else if (factname == _T("perm"))
 		else if (factname == _T("perm"))
@@ -1436,7 +1441,7 @@ BOOL CFtpListResult::parseAsMlsd(const char *line, const int linelen, t_director
 	return TRUE;
 	return TRUE;
 }
 }
 
 
-bool CFtpListResult::parseMlsdDateTime(const CString value, t_directory::t_direntry &direntry) const
+bool CFtpListResult::parseMlsdDateTime(const CString value, t_directory::t_direntry::t_date &date) const
 {
 {
 	if (value.IsEmpty())
 	if (value.IsEmpty())
 		return FALSE;
 		return FALSE;
@@ -1446,35 +1451,26 @@ bool CFtpListResult::parseMlsdDateTime(const CString value, t_directory::t_diren
 	Year=Month=Day=Hours=Minutes=Seconds=0;
 	Year=Month=Day=Hours=Minutes=Seconds=0;
 	if (swscanf((LPCWSTR)value, L"%4d%2d%2d%2d%2d%2d", &Year, &Month, &Day, &Hours, &Minutes, &Seconds) == 6)
 	if (swscanf((LPCWSTR)value, L"%4d%2d%2d%2d%2d%2d", &Year, &Month, &Day, &Hours, &Minutes, &Seconds) == 6)
 	{
 	{
-		direntry.date.hasdate = TRUE;
-		direntry.date.hastime = TRUE;
-		direntry.date.hasseconds = TRUE;
+		date.hasdate = TRUE;
+		date.hastime = TRUE;
+		date.hasseconds = TRUE;
 		result = TRUE;
 		result = TRUE;
 	}
 	}
 	else if (swscanf((LPCWSTR)value, L"%4d%2d%2d", &Year, &Month, &Day) == 3)
 	else if (swscanf((LPCWSTR)value, L"%4d%2d%2d", &Year, &Month, &Day) == 3)
 	{
 	{
-		direntry.date.hasdate = TRUE;
-		direntry.date.hastime = FALSE;
+		date.hasdate = TRUE;
+		date.hastime = FALSE;
 		result = TRUE;
 		result = TRUE;
 	}
 	}
 	if (result)
 	if (result)
 	{
 	{
-		try
-		{
-			direntry.date.year = Year;
-			direntry.date.month = Month;
-			direntry.date.day = Day;
-			direntry.date.hour = Hours;
-			direntry.date.minute = Minutes;
-			direntry.date.second = Seconds;
-			direntry.date.utc = TRUE;
-		}
-		// Does not really seem to ever throw in our version of MFC/ATL
-		catch (CException &)
-		{
-			direntry.date.hasdate = FALSE;
-			direntry.date.hastime = FALSE;
-		}
+		date.year = Year;
+		date.month = Month;
+		date.day = Day;
+		date.hour = Hours;
+		date.minute = Minutes;
+		date.second = Seconds;
+		date.utc = TRUE;
 	}
 	}
 	return result;
 	return result;
 }
 }

+ 1 - 1
source/filezilla/FtpListResult.h

@@ -87,7 +87,7 @@ private:
 	bool parseTime(const char *str, int len, t_directory::t_direntry::t_date &date) const;
 	bool parseTime(const char *str, int len, t_directory::t_direntry::t_date &date) const;
 	bool ParseSize(const char* str, int len, __int64 &size) const;
 	bool ParseSize(const char* str, int len, __int64 &size) const;
 
 
-	bool parseMlsdDateTime(const CString value, t_directory::t_direntry &direntry) const;
+	bool parseMlsdDateTime(const CString value, t_directory::t_direntry::t_date &date) const;
 
 
 	int pos;
 	int pos;
 	struct t_list
 	struct t_list

+ 36 - 25
source/filezilla/TransferSocket.cpp

@@ -367,21 +367,12 @@ void CTransferSocket::OnReceive(int nErrorCode)
 	}
 	}
 }
 }
 
 
-void CTransferSocket::OnAccept(int nErrorCode)
+void CTransferSocket::SetBuffers()
 {
 {
-	LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("OnAccept(%d)"), nErrorCode);
-	m_bListening=FALSE;
-	CAsyncSocketEx tmp;
-	Accept(tmp);
-	SOCKET socket=tmp.Detach();
-	CAsyncSocketEx::Close();
-	
-	Attach(socket);
-
 	/* Set internal socket send buffer
 	/* Set internal socket send buffer
 	 * this should fix the speed problems some users have reported
 	 * this should fix the speed problems some users have reported
 	 */
 	 */
-	DWORD value;
+	DWORD value = 0;
 	int len = sizeof(value);
 	int len = sizeof(value);
 	GetSockOpt(SO_SNDBUF, &value, &len);
 	GetSockOpt(SO_SNDBUF, &value, &len);
 	// MPEXT
 	// MPEXT
@@ -392,6 +383,35 @@ void CTransferSocket::OnAccept(int nErrorCode)
 		SetSockOpt(SO_SNDBUF, &value, sizeof(value));
 		SetSockOpt(SO_SNDBUF, &value, sizeof(value));
 	}
 	}
 
 
+	// For now we increase receive buffer, whenever send buffer is set.
+	// The size is not configurable. The constant taken from FZ.
+	if (sndbuf > 0)
+	{
+		value = 0;
+		len = sizeof(value);
+		GetSockOpt(SO_RCVBUF, &value, &len);
+		int rcvbuf = 4 * 1024 * 1024;
+		if (value < rcvbuf)
+		{
+			value = rcvbuf;
+			SetSockOpt(SO_RCVBUF, &value, sizeof(value));
+		}
+	}
+}
+
+void CTransferSocket::OnAccept(int nErrorCode)
+{
+	LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("OnAccept(%d)"), nErrorCode);
+	m_bListening=FALSE;
+	CAsyncSocketEx tmp;
+	Accept(tmp);
+	SOCKET socket=tmp.Detach();
+	CAsyncSocketEx::Close();
+	
+	Attach(socket);
+
+	SetBuffers();
+
 	if (m_nTransferState == STATE_STARTING)
 	if (m_nTransferState == STATE_STARTING)
 	{
 	{
 		m_nTransferState = STATE_STARTED;	
 		m_nTransferState = STATE_STARTED;	
@@ -462,19 +482,8 @@ void CTransferSocket::OnConnect(int nErrorCode)
 	}
 	}
 	else
 	else
 	{
 	{
-		/* Set internal socket send buffer
-		 * this should fix the speed problems some users have reported
-		 */
-		DWORD value;
-		int len = sizeof(value);
-		GetSockOpt(SO_SNDBUF, &value, &len);
-		// MPEXT
-		int sndbuf = COptions::GetOptionVal(OPTION_MPEXT_SNDBUF);
-		if (value < sndbuf)
-		{
-			value = sndbuf;
-			SetSockOpt(SO_SNDBUF, &value, sizeof(value));
-		}
+		SetBuffers();
+		m_pOwner->ShowStatus(L"Data connection opened", FZ_LOG_INFO);
 	}
 	}
 	if (m_nTransferState == STATE_WAITING)
 	if (m_nTransferState == STATE_WAITING)
 	{
 	{
@@ -535,6 +544,8 @@ void CTransferSocket::OnClose(int nErrorCode)
 		m_nNotifyWaiting |= FD_CLOSE;
 		m_nNotifyWaiting |= FD_CLOSE;
 		return;
 		return;
 	}
 	}
+	
+	m_pOwner->ShowStatus(L"Data connection closed", FZ_LOG_INFO);
 
 
 	OnReceive(0);
 	OnReceive(0);
 	CloseAndEnsureSendClose(0);
 	CloseAndEnsureSendClose(0);
@@ -552,7 +563,7 @@ int CTransferSocket::CheckForTimeout(int delay)
 	CTimeSpan span = CTime::GetCurrentTime()-m_LastActiveTime;
 	CTimeSpan span = CTime::GetCurrentTime()-m_LastActiveTime;
 	if (span.GetTotalSeconds()>=delay)
 	if (span.GetTotalSeconds()>=delay)
 	{
 	{
-		m_pOwner->ShowStatus(IDS_ERRORMSG_TIMEOUT, FZ_LOG_ERROR);
+		m_pOwner->ShowTimeoutError(IDS_DATA_CONNECTION);
 		CloseAndEnsureSendClose(CSMODE_TRANSFERTIMEOUT);
 		CloseAndEnsureSendClose(CSMODE_TRANSFERTIMEOUT);
 		return 2;
 		return 2;
 	}
 	}

+ 1 - 0
source/filezilla/TransferSocket.h

@@ -132,6 +132,7 @@ protected:
 	void EnsureSendClose(int Mode);
 	void EnsureSendClose(int Mode);
 	void CloseOnShutDownOrError(int Mode);
 	void CloseOnShutDownOrError(int Mode);
 	void LogError(int Error);
 	void LogError(int Error);
+	void SetBuffers();
 
 
 	DWORD m_Transfered[SPEED_SECONDS];
 	DWORD m_Transfered[SPEED_SECONDS];
 	bool m_UsedForTransfer[SPEED_SECONDS];
 	bool m_UsedForTransfer[SPEED_SECONDS];

+ 39 - 16
source/forms/About.cpp

@@ -30,14 +30,14 @@
 #pragma resource "*.dfm"
 #pragma resource "*.dfm"
 #endif
 #endif
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-void __fastcall DoAboutDialog(TConfiguration * Configuration,
-  bool AllowLicense, TRegistration * Registration)
+static void __fastcall DoAboutDialog(TConfiguration * Configuration,
+  bool AllowLicense, TRegistration * Registration, bool LoadThirdParty)
 {
 {
   TAboutDialog * AboutDialog = NULL;
   TAboutDialog * AboutDialog = NULL;
   try
   try
   {
   {
     AboutDialog = new TAboutDialog(Application, Configuration, AllowLicense,
     AboutDialog = new TAboutDialog(Application, Configuration, AllowLicense,
-      Registration);
+      Registration, LoadThirdParty);
     AboutDialog->ShowModal();
     AboutDialog->ShowModal();
   }
   }
   __finally
   __finally
@@ -46,8 +46,24 @@ void __fastcall DoAboutDialog(TConfiguration * Configuration,
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+void __fastcall DoAboutDialog(TConfiguration * Configuration,
+  bool AllowLicense, TRegistration * Registration)
+{
+  try
+  {
+    DoAboutDialog(Configuration, AllowLicense, Registration, true);
+  }
+  catch (EOleException & E)
+  {
+    // This happens particularly on Wine that's does not support some
+    // functionality of embedded IE we need.
+    DoAboutDialog(Configuration, AllowLicense, Registration, false);
+  }
+}
+//---------------------------------------------------------------------------
 __fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
 __fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
-  TConfiguration * Configuration, bool AllowLicense, TRegistration * Registration)
+  TConfiguration * Configuration, bool AllowLicense, TRegistration * Registration,
+  bool ALoadThirdParty)
   : TForm(AOwner)
   : TForm(AOwner)
 {
 {
   FConfiguration = Configuration;
   FConfiguration = Configuration;
@@ -123,9 +139,15 @@ __fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
 
 
   LicenseButton->Visible = AllowLicense;
   LicenseButton->Visible = AllowLicense;
 
 
-  FThirdPartyWebBrowser = CreateBrowserViewer(ThirdPartyPanel, L"");
-
   LoadData();
   LoadData();
+  if (ALoadThirdParty)
+  {
+    LoadThirdParty();
+  }
+  else
+  {
+    CreateLabelPanel(ThirdPartyPanel, LoadStr(MESSAGE_DISPLAY_ERROR));
+  }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TAboutDialog::LoadData()
 void __fastcall TAboutDialog::LoadData()
@@ -138,16 +160,17 @@ void __fastcall TAboutDialog::LoadData()
       (Version, FConfiguration->ProductName, FConfiguration->ProductVersion));
       (Version, FConfiguration->ProductName, FConfiguration->ProductVersion));
   }
   }
   VersionLabel->Caption = Version;
   VersionLabel->Caption = Version;
-
-  LoadThirdParty();
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TAboutDialog::LoadThirdParty()
 void __fastcall TAboutDialog::LoadThirdParty()
 {
 {
-  reinterpret_cast<TLabel *>(FThirdPartyWebBrowser)->Color = clBtnFace;
+  TWebBrowserEx * ThirdPartyWebBrowser =
+    CreateBrowserViewer(ThirdPartyPanel, L"");
+
+  reinterpret_cast<TLabel *>(ThirdPartyWebBrowser)->Color = clBtnFace;
 
 
-  FThirdPartyWebBrowser->Navigate(L"about:blank");
-  while (FThirdPartyWebBrowser->ReadyState < ::READYSTATE_INTERACTIVE)
+  ThirdPartyWebBrowser->Navigate(L"about:blank");
+  while (ThirdPartyWebBrowser->ReadyState < ::READYSTATE_INTERACTIVE)
   {
   {
     Application->ProcessMessages();
     Application->ProcessMessages();
   }
   }
@@ -231,7 +254,7 @@ void __fastcall TAboutDialog::LoadThirdParty()
     CreateLink(EXPAT_LICENSE_URL, LoadStr(ABOUT_THIRDPARTY_LICENSE)) + Br +
     CreateLink(EXPAT_LICENSE_URL, LoadStr(ABOUT_THIRDPARTY_LICENSE)) + Br +
     CreateLink(LoadStr(EXPAT_URL)));
     CreateLink(LoadStr(EXPAT_URL)));
 
 
-  AddBrowserLinkHandler(FThirdPartyWebBrowser, EXPAT_LICENSE_URL, ExpatLicenceHandler);
+  AddBrowserLinkHandler(ThirdPartyWebBrowser, EXPAT_LICENSE_URL, ExpatLicenceHandler);
 
 
 #ifndef NO_COMPONENTS
 #ifndef NO_COMPONENTS
 
 
@@ -271,14 +294,14 @@ void __fastcall TAboutDialog::LoadThirdParty()
   ThirdPartyStream->Write(ThirdPartyUTF8.c_str(), ThirdPartyUTF8.Length());
   ThirdPartyStream->Write(ThirdPartyUTF8.c_str(), ThirdPartyUTF8.Length());
   ThirdPartyStream->Seek(0, 0);
   ThirdPartyStream->Seek(0, 0);
 
 
-  // For steam-loaded document, when set only after loading from OnDocumentComplete,
+  // For stream-loaded document, when set only after loading from OnDocumentComplete,
   // browser stops working
   // browser stops working
-  SetBrowserDesignModeOff(FThirdPartyWebBrowser);
+  SetBrowserDesignModeOff(ThirdPartyWebBrowser);
 
 
   TStreamAdapter * ThirdPartyStreamAdapter = new TStreamAdapter(ThirdPartyStream.get(), soReference);
   TStreamAdapter * ThirdPartyStreamAdapter = new TStreamAdapter(ThirdPartyStream.get(), soReference);
   IPersistStreamInit * PersistStreamInit = NULL;
   IPersistStreamInit * PersistStreamInit = NULL;
-  if (ALWAYS_TRUE(FThirdPartyWebBrowser->Document != NULL) &&
-      SUCCEEDED(FThirdPartyWebBrowser->Document->QueryInterface(IID_IPersistStreamInit, (void **)&PersistStreamInit)) &&
+  if (ALWAYS_TRUE(ThirdPartyWebBrowser->Document != NULL) &&
+      SUCCEEDED(ThirdPartyWebBrowser->Document->QueryInterface(IID_IPersistStreamInit, (void **)&PersistStreamInit)) &&
       ALWAYS_TRUE(PersistStreamInit != NULL))
       ALWAYS_TRUE(PersistStreamInit != NULL))
   {
   {
     PersistStreamInit->Load(static_cast<_di_IStream>(*ThirdPartyStreamAdapter));
     PersistStreamInit->Load(static_cast<_di_IStream>(*ThirdPartyStreamAdapter));

+ 2 - 2
source/forms/About.h

@@ -42,7 +42,6 @@ __published:
 private:
 private:
   TConfiguration * FConfiguration;
   TConfiguration * FConfiguration;
   TNotifyEvent FOnRegistrationLink;
   TNotifyEvent FOnRegistrationLink;
-  TWebBrowserEx * FThirdPartyWebBrowser;
 
 
   void __fastcall LoadData();
   void __fastcall LoadData();
   void __fastcall LoadThirdParty();
   void __fastcall LoadThirdParty();
@@ -52,7 +51,8 @@ private:
 
 
 public:
 public:
   virtual __fastcall TAboutDialog(TComponent * AOwner,
   virtual __fastcall TAboutDialog(TComponent * AOwner,
-    TConfiguration * Configuration, bool AllowLicense, TRegistration * Registration);
+    TConfiguration * Configuration, bool AllowLicense, TRegistration * Registration,
+    bool ALoadThirdParty);
 };
 };
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 #endif
 #endif

+ 1 - 1
source/forms/Custom.cpp

@@ -441,7 +441,7 @@ void __fastcall SessionNameValidate(const UnicodeString & Text,
       qtError, qaOK, HELP_NONE);
       qtError, qaOK, HELP_NONE);
     Abort();
     Abort();
   }
   }
-  else if ((Data != NULL) && (Data->CompareName(OriginalName) != 0) &&
+  else if ((Data != NULL) && !Data->IsSameName(OriginalName) &&
     MessageDialog(MainInstructions(FMTLOAD(CONFIRM_OVERWRITE_SESSION, (Text))),
     MessageDialog(MainInstructions(FMTLOAD(CONFIRM_OVERWRITE_SESSION, (Text))),
       qtConfirmation, qaYes | qaNo, HELP_SESSION_SAVE_OVERWRITE) != qaYes)
       qtConfirmation, qaYes | qaNo, HELP_SESSION_SAVE_OVERWRITE) != qaYes)
   {
   {

+ 24 - 3
source/forms/CustomScpExplorer.cpp

@@ -107,6 +107,24 @@ private:
   HANDLE FMutex;
   HANDLE FMutex;
 };
 };
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+class TWindowLock
+{
+public:
+  TWindowLock(TCustomScpExplorerForm * Form) :
+    FForm(Form)
+  {
+    FForm->LockWindow();
+  }
+
+  ~TWindowLock()
+  {
+    FForm->UnlockWindow();
+  }
+
+private:
+  TCustomScpExplorerForm * FForm;
+};
+//---------------------------------------------------------------------------
 struct TTransferOperationParam
 struct TTransferOperationParam
 {
 {
   TTransferOperationParam();
   TTransferOperationParam();
@@ -3498,6 +3516,7 @@ void __fastcall TCustomScpExplorerForm::CreateDirectory(TOperationSide Side)
 
 
   if (DoCreateDirectoryDialog(Name, AProperties, AllowedChanges, SaveSettings))
   if (DoCreateDirectoryDialog(Name, AProperties, AllowedChanges, SaveSettings))
   {
   {
+    TWindowLock Lock(this);
     if (Side == osRemote)
     if (Side == osRemote)
     {
     {
       if (SaveSettings)
       if (SaveSettings)
@@ -3515,6 +3534,7 @@ void __fastcall TCustomScpExplorerForm::CreateDirectory(TOperationSide Side)
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::HomeDirectory(TOperationSide Side)
 void __fastcall TCustomScpExplorerForm::HomeDirectory(TOperationSide Side)
 {
 {
+  TWindowLock Lock(this);
   DirView(Side)->ExecuteHomeDirectory();
   DirView(Side)->ExecuteHomeDirectory();
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -5125,6 +5145,7 @@ void __fastcall TCustomScpExplorerForm::DoOpenDirectoryDialog(
       if (::DoOpenDirectoryDialog(Mode, Side, Name, VisitedDirectories, Terminal,
       if (::DoOpenDirectoryDialog(Mode, Side, Name, VisitedDirectories, Terminal,
             HasDirView[osLocal]))
             HasDirView[osLocal]))
       {
       {
+        TWindowLock Lock(this);
         DirView(Side)->Path = Name;
         DirView(Side)->Path = Name;
       }
       }
     }
     }
@@ -6156,7 +6177,7 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDGiveFeedback(
   DragDropFiles(Sender)->CHCopy = SlippedCopyCursor;
   DragDropFiles(Sender)->CHCopy = SlippedCopyCursor;
   DragDropFiles(Sender)->CHScrollCopy = SlippedCopyCursor;
   DragDropFiles(Sender)->CHScrollCopy = SlippedCopyCursor;
 
 
-  // Remember drop effect so we know (when user dropes files), if we copy or move
+  // Remember drop effect so we know (when user drops files), if we copy or move
   FLastDropEffect = dwEffect;
   FLastDropEffect = dwEffect;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -6764,7 +6785,7 @@ void __fastcall TCustomScpExplorerForm::RemoteFileContolDDChooseEffect(
       {
       {
         bool MoveCapable = FTerminal->IsCapable[fcRemoteMove];
         bool MoveCapable = FTerminal->IsCapable[fcRemoteMove];
         // currently we support copying always (at least via temporary directory);
         // currently we support copying always (at least via temporary directory);
-        // remove associated checks once this all proves stable andworking
+        // remove associated checks once this all proves stable and working
         bool CopyCapable = true;
         bool CopyCapable = true;
         // if we do not support neither of operations, there's no discussion
         // if we do not support neither of operations, there's no discussion
         if (!MoveCapable && !CopyCapable)
         if (!MoveCapable && !CopyCapable)
@@ -8265,6 +8286,6 @@ Boolean __fastcall TCustomScpExplorerForm::AllowedAction(TAction * /*Action*/, T
   // so stop it at least here
   // so stop it at least here
   return
   return
     (Allowed == aaUpdate) ||
     (Allowed == aaUpdate) ||
-    !IsBusy();
+    !NonVisualDataModule->Busy;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------

+ 7 - 7
source/forms/Editor.dfm

@@ -157,19 +157,19 @@ object EditorForm: TEditorForm
     end
     end
     object EditCut: TEditCut
     object EditCut: TEditCut
       Caption = 'Cu&t'
       Caption = 'Cu&t'
-      Hint = 'Cut|Cuts the selection and puts it on the Clipboard'
+      Hint = 'Cut|Cut the selection and put it on the Clipboard'
       ImageIndex = 1
       ImageIndex = 1
       ShortCut = 16472
       ShortCut = 16472
     end
     end
     object EditCopy: TEditCopy
     object EditCopy: TEditCopy
       Caption = '&Copy'
       Caption = '&Copy'
-      Hint = 'Copy|Copies the selection and puts it on the Clipboard'
+      Hint = 'Copy|Copy the selection and put it on the Clipboard'
       ImageIndex = 2
       ImageIndex = 2
       ShortCut = 16451
       ShortCut = 16451
     end
     end
     object EditPaste: TEditPaste
     object EditPaste: TEditPaste
       Caption = '&Paste'
       Caption = '&Paste'
-      Hint = 'Paste|Inserts Clipboard contents'
+      Hint = 'Paste|Insert Clipboard contents'
       ImageIndex = 3
       ImageIndex = 3
       SecondaryShortCuts.Strings = (
       SecondaryShortCuts.Strings = (
         'Shift+Ins'
         'Shift+Ins'
@@ -178,25 +178,25 @@ object EditorForm: TEditorForm
     end
     end
     object EditSelectAll: TEditSelectAll
     object EditSelectAll: TEditSelectAll
       Caption = 'Select &All'
       Caption = 'Select &All'
-      Hint = 'Select All|Selects the entire document'
+      Hint = 'Select All|Select the entire document'
       ImageIndex = 6
       ImageIndex = 6
       ShortCut = 16449
       ShortCut = 16449
     end
     end
     object EditUndo: TEditUndo
     object EditUndo: TEditUndo
       Caption = '&Undo'
       Caption = '&Undo'
-      Hint = 'Undo|Reverts the last action'
+      Hint = 'Undo|Revert the last action'
       ImageIndex = 4
       ImageIndex = 4
       ShortCut = 16474
       ShortCut = 16474
     end
     end
     object EditRedo: TAction
     object EditRedo: TAction
       Caption = 'Re&do'
       Caption = 'Re&do'
-      Hint = 'Redo|Reverts the effects of most recent Undo'
+      Hint = 'Redo|Revert the effects of most recent Undo'
       ImageIndex = 14
       ImageIndex = 14
       ShortCut = 16473
       ShortCut = 16473
     end
     end
     object EditDelete: TEditDelete
     object EditDelete: TEditDelete
       Caption = '&Delete'
       Caption = '&Delete'
-      Hint = 'Delete|Erases the selection'
+      Hint = 'Delete|Erase the selection'
       ImageIndex = 5
       ImageIndex = 5
     end
     end
     object PreferencesAction: TAction
     object PreferencesAction: TAction

+ 6 - 6
source/forms/GenerateUrl.dfm

@@ -29,7 +29,7 @@ object GenerateUrlDialog: TGenerateUrlDialog
       Tag = 1
       Tag = 1
       Left = 11
       Left = 11
       Top = 20
       Top = 20
-      Width = 97
+      Width = 216
       Height = 17
       Height = 17
       Caption = '&User name'
       Caption = '&User name'
       TabOrder = 0
       TabOrder = 0
@@ -39,7 +39,7 @@ object GenerateUrlDialog: TGenerateUrlDialog
       Tag = 2
       Tag = 2
       Left = 235
       Left = 235
       Top = 20
       Top = 20
-      Width = 97
+      Width = 216
       Height = 17
       Height = 17
       HelpType = htKeyword
       HelpType = htKeyword
       HelpKeyword = 'ui_generate_url'
       HelpKeyword = 'ui_generate_url'
@@ -51,7 +51,7 @@ object GenerateUrlDialog: TGenerateUrlDialog
       Tag = 4
       Tag = 4
       Left = 11
       Left = 11
       Top = 43
       Top = 43
-      Width = 97
+      Width = 216
       Height = 17
       Height = 17
       Caption = 'SSH &host Key'
       Caption = 'SSH &host Key'
       TabOrder = 2
       TabOrder = 2
@@ -61,7 +61,7 @@ object GenerateUrlDialog: TGenerateUrlDialog
       Tag = 8
       Tag = 8
       Left = 235
       Left = 235
       Top = 43
       Top = 43
-      Width = 97
+      Width = 216
       Height = 17
       Height = 17
       Caption = 'Initial &directory'
       Caption = 'Initial &directory'
       TabOrder = 3
       TabOrder = 3
@@ -71,7 +71,7 @@ object GenerateUrlDialog: TGenerateUrlDialog
       Tag = 16
       Tag = 16
       Left = 11
       Left = 11
       Top = 66
       Top = 66
-      Width = 97
+      Width = 216
       Height = 17
       Height = 17
       Caption = '&WinSCP-specific'
       Caption = '&WinSCP-specific'
       TabOrder = 4
       TabOrder = 4
@@ -81,7 +81,7 @@ object GenerateUrlDialog: TGenerateUrlDialog
       Tag = 32
       Tag = 32
       Left = 235
       Left = 235
       Top = 66
       Top = 66
-      Width = 97
+      Width = 216
       Height = 17
       Height = 17
       Caption = '&Save extension'
       Caption = '&Save extension'
       TabOrder = 5
       TabOrder = 5

+ 14 - 0
source/forms/LocationProfiles.cpp

@@ -410,6 +410,7 @@ bool __fastcall TLocationProfilesDialog::Execute()
 {
 {
   bool Result;
   bool Result;
   PageControl->ActivePage = GetProfilesSheet();
   PageControl->ActivePage = GetProfilesSheet();
+  FBookmarkSelected = false;
   Result = (ShowModal() == DefaultResult(this));
   Result = (ShowModal() == DefaultResult(this));
   if (Terminal)
   if (Terminal)
   {
   {
@@ -417,6 +418,17 @@ bool __fastcall TLocationProfilesDialog::Execute()
     WinConfiguration->SharedBookmarks = FSharedBookmarkList;
     WinConfiguration->SharedBookmarks = FSharedBookmarkList;
     WinConfiguration->UseSharedBookmarks = (PageControl->ActivePage == SharedProfilesSheet);
     WinConfiguration->UseSharedBookmarks = (PageControl->ActivePage == SharedProfilesSheet);
   }
   }
+  if (Result)
+  {
+    if (FBookmarkSelected)
+    {
+      Configuration->Usage->Inc(L"OpenedBookmark");
+    }
+    else
+    {
+      Configuration->Usage->Inc(L"OpenedPath");
+    }
+  }
   return Result;
   return Result;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -821,6 +833,7 @@ void __fastcall TLocationProfilesDialog::DirectoryEditChange(TObject * /*Sender*
   {
   {
     FindProfile();
     FindProfile();
     UpdateControls();
     UpdateControls();
+    FBookmarkSelected = false;
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -842,6 +855,7 @@ void __fastcall TLocationProfilesDialog::ProfilesViewChange(
     }
     }
     // try to locate the same profile in the other set
     // try to locate the same profile in the other set
     FindProfile();
     FindProfile();
+    FBookmarkSelected = true;
   }
   }
   UpdateControls();
   UpdateControls();
 }
 }

+ 1 - 0
source/forms/LocationProfiles.h

@@ -123,6 +123,7 @@ private:
   TTreeViewScrollOnDragOver * FSessionScrollOnDragOver;
   TTreeViewScrollOnDragOver * FSessionScrollOnDragOver;
   TTreeViewScrollOnDragOver * FSharedScrollOnDragOver;
   TTreeViewScrollOnDragOver * FSharedScrollOnDragOver;
   UnicodeString FSessionKey;
   UnicodeString FSessionKey;
+  bool FBookmarkSelected;
   #ifdef _DEBUG
   #ifdef _DEBUG
   HWND FSessionProfilesViewHandle;
   HWND FSessionProfilesViewHandle;
   HWND FSharedProfilesViewHandle;
   HWND FSharedProfilesViewHandle;

+ 33 - 35
source/forms/MessageDlg.cpp

@@ -983,16 +983,43 @@ TForm * __fastcall TMessageForm::Create(const UnicodeString & Msg,
       ButtonSpacing * (ButtonControls.size() - 1);
       ButtonSpacing * (ButtonControls.size() - 1);
   }
   }
 
 
+  assert((ButtonHeight > 0) && (ButtonWidths > 0));
+
+  TPanel * Panel = new TPanel(Result);
+  Panel->Name = L"Panel";
+  Panel->Parent = Result;
+  Panel->Color = clWindow;
+  Panel->ParentBackground = false;
+  Panel->Anchors = TAnchors() << akLeft << akRight << akTop;
+  Panel->BevelOuter = bvNone;
+  Panel->BevelKind = bkNone;
+  Panel->Caption = L"";
+
   int IconWidth = 0;
   int IconWidth = 0;
+  int IconHeight = 0;
   const wchar_t * IconID = IconIDs[DlgType];
   const wchar_t * IconID = IconIDs[DlgType];
-  bool HasIcon = (IconID != NULL) || !ImageName.IsEmpty();
-  if (HasIcon)
+
+  if ((IconID != NULL) || !ImageName.IsEmpty())
   {
   {
-    IconWidth = 32 + HorzSpacing;
+    TImage * Image = new TImage(Panel);
+    Image->Name = L"Image";
+    Image->Parent = Panel;
+    if (!ImageName.IsEmpty())
+    {
+      LoadResourceImage(Image, ImageName);
+    }
+    else
+    {
+      // Until Windows 8, LoadIcon for IDI_XXX always returns 32x32 image.
+      // Since Windows 8.1, it returns image adjusted for DPI.
+      // For 125%, it's scaled version. For 150%, there's native larger version.
+      Image->Picture->Icon->Handle = LoadIcon(0, IconID);
+    }
+    Image->SetBounds(HorzMargin, VertMargin, Image->Picture->Width, Image->Picture->Height);
+    IconWidth = Image->Width + HorzSpacing;
+    IconHeight = Image->Height;
   }
   }
 
 
-  assert((ButtonHeight > 0) && (ButtonWidths > 0));
-
   int MaxTextWidth = ScaleByTextHeightRunTime(Result, mcMaxDialogWidth);
   int MaxTextWidth = ScaleByTextHeightRunTime(Result, mcMaxDialogWidth);
   // if the dialog would be wide anyway (overwrite confirmation on Windows XP),
   // if the dialog would be wide anyway (overwrite confirmation on Windows XP),
   // to fit the buttons, do not restrict the text
   // to fit the buttons, do not restrict the text
@@ -1001,16 +1028,6 @@ TForm * __fastcall TMessageForm::Create(const UnicodeString & Msg,
     MaxTextWidth = ButtonGroupWidth - IconWidth;
     MaxTextWidth = ButtonGroupWidth - IconWidth;
   }
   }
 
 
-  TPanel * Panel = new TPanel(Result);
-  Panel->Name = L"Panel";
-  Panel->Parent = Result;
-  Panel->Color = clWindow;
-  Panel->ParentBackground = false;
-  Panel->Anchors = TAnchors() << akLeft << akRight << akTop;
-  Panel->BevelOuter = bvNone;
-  Panel->BevelKind = bkNone;
-  Panel->Caption = L"";
-
   UnicodeString BodyMsg = Msg;
   UnicodeString BodyMsg = Msg;
   BodyMsg = RemoveInteractiveMsgTag(BodyMsg);
   BodyMsg = RemoveInteractiveMsgTag(BodyMsg);
   UnicodeString MainMsg;
   UnicodeString MainMsg;
@@ -1119,10 +1136,7 @@ TForm * __fastcall TMessageForm::Create(const UnicodeString & Msg,
 
 
   assert((IconTextWidth > 0) && (IconTextHeight > 0));
   assert((IconTextWidth > 0) && (IconTextHeight > 0));
 
 
-  if (HasIcon && (IconTextHeight < 32))
-  {
-    IconTextHeight = 32;
-  }
+  IconTextHeight = Max(IconTextHeight, IconHeight);
 
 
   int MoreMessageHeight =
   int MoreMessageHeight =
     (HasMoreMessages ?
     (HasMoreMessages ?
@@ -1190,22 +1204,6 @@ TForm * __fastcall TMessageForm::Create(const UnicodeString & Msg,
     Result->Caption = Application->Title;
     Result->Caption = Application->Title;
   }
   }
 
 
-  if ((IconID != NULL) || !ImageName.IsEmpty())
-  {
-    TImage * Image = new TImage(Panel);
-    Image->Name = L"Image";
-    Image->Parent = Panel;
-    if (!ImageName.IsEmpty())
-    {
-      LoadResourceImage(Image, ImageName);
-    }
-    else
-    {
-      Image->Picture->Icon->Handle = LoadIcon(0, IconID);
-    }
-    Image->SetBounds(HorzMargin, VertMargin, 32, 32);
-  }
-
   if (MoreMessagesControl != NULL)
   if (MoreMessagesControl != NULL)
   {
   {
     MoreMessagesControl->SetBounds(
     MoreMessagesControl->SetBounds(

+ 14 - 0
source/forms/OpenDirectory.cpp

@@ -249,6 +249,7 @@ bool __fastcall TOpenDirectoryDialog::Execute()
       AddAsBookmark(PageControl->ActivePage);
       AddAsBookmark(PageControl->ActivePage);
     }
     }
   }
   }
+  FBookmarkSelected = false;
   Result = (ShowModal() == DefaultResult(this));
   Result = (ShowModal() == DefaultResult(this));
   if (Terminal)
   if (Terminal)
   {
   {
@@ -256,6 +257,17 @@ bool __fastcall TOpenDirectoryDialog::Execute()
     WinConfiguration->SharedBookmarks = FSharedBookmarkList;
     WinConfiguration->SharedBookmarks = FSharedBookmarkList;
     WinConfiguration->UseSharedBookmarks = (PageControl->ActivePage == SharedBookmarksSheet);
     WinConfiguration->UseSharedBookmarks = (PageControl->ActivePage == SharedBookmarksSheet);
   }
   }
+  if (Result)
+  {
+    if (FBookmarkSelected)
+    {
+      Configuration->Usage->Inc(L"OpenedBookmark");
+    }
+    else
+    {
+      Configuration->Usage->Inc(L"OpenedPath");
+    }
+  }
   return Result;
   return Result;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -400,6 +412,7 @@ void __fastcall TOpenDirectoryDialog::BookmarkSelected(TObject * Sender)
     Directory = BookmarkDirectory(GetBookmark(BookmarksList, BookmarksList->ItemIndex));
     Directory = BookmarkDirectory(GetBookmark(BookmarksList, BookmarksList->ItemIndex));
   }
   }
   UpdateControls();
   UpdateControls();
+  FBookmarkSelected = true;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TOpenDirectoryDialog::BookmarksListClick(TObject * Sender)
 void __fastcall TOpenDirectoryDialog::BookmarksListClick(TObject * Sender)
@@ -487,6 +500,7 @@ void __fastcall TOpenDirectoryDialog::DirectoryEditChange(TObject * /*Sender*/)
   SelectBookmark(SessionBookmarksList);
   SelectBookmark(SessionBookmarksList);
   SelectBookmark(SharedBookmarksList);
   SelectBookmark(SharedBookmarksList);
   UpdateControls();
   UpdateControls();
+  FBookmarkSelected = false;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TOpenDirectoryDialog::BookmarksListDblClick(TObject * Sender)
 void __fastcall TOpenDirectoryDialog::BookmarksListDblClick(TObject * Sender)

+ 1 - 0
source/forms/OpenDirectory.h

@@ -100,6 +100,7 @@ private:
   bool FAllowSwitch;
   bool FAllowSwitch;
   TListBoxScrollOnDragOver * FSessionScrollOnDragOver;
   TListBoxScrollOnDragOver * FSessionScrollOnDragOver;
   TListBoxScrollOnDragOver * FSharedScrollOnDragOver;
   TListBoxScrollOnDragOver * FSharedScrollOnDragOver;
+  bool FBookmarkSelected;
 
 
   void __fastcall SetDirectory(UnicodeString value);
   void __fastcall SetDirectory(UnicodeString value);
   UnicodeString __fastcall GetDirectory();
   UnicodeString __fastcall GetDirectory();

+ 7 - 5
source/forms/ScpCommander.cpp

@@ -520,6 +520,7 @@ void __fastcall TScpCommanderForm::ConfigurationChanged()
     LocalDirView->Invalidate();
     LocalDirView->Invalidate();
   }
   }
 
 
+  // See also LocalDirViewDDTargetHasDropHandler
   LocalDirView->DragDropFilesEx->ShellExtensions->DropHandler =
   LocalDirView->DragDropFilesEx->ShellExtensions->DropHandler =
     !WinConfiguration->DDExtEnabled;
     !WinConfiguration->DDExtEnabled;
   LocalDriveView->DragDropFilesEx->ShellExtensions->DropHandler =
   LocalDriveView->DragDropFilesEx->ShellExtensions->DropHandler =
@@ -1321,11 +1322,12 @@ bool __fastcall TScpCommanderForm::OpenBookmark(UnicodeString Local, UnicodeStri
 void __fastcall TScpCommanderForm::LocalDirViewDDTargetHasDropHandler(
 void __fastcall TScpCommanderForm::LocalDirViewDDTargetHasDropHandler(
   TObject * /*Sender*/, TListItem * Item, int & /*Effect*/, bool & DropHandler)
   TObject * /*Sender*/, TListItem * Item, int & /*Effect*/, bool & DropHandler)
 {
 {
-  // when drop target is not directory, it is probably file type, which have
-  // associated drop handler (such as ZIP file in WinXP). in this case we
-  // cannot allow downloading when using shellex.
-  // ! this check is duplicated in InternalDDDownload() for non-shellex downloads
-  if ((FDDExtMapFile != NULL) &&
+  // When drop target is not directory, it is probably file type, which have
+  // associated drop handler (such as EXE file). In this case we
+  // cannot allow drop when when using shellex,
+  // as drop handlers are disabled, so drop would error
+  // (see TShellExtension.DropHandler assignment in ConfigurationChanged),
+  if (WinConfiguration->DDExtEnabled &&
       !LocalDirView->ItemIsDirectory(Item))
       !LocalDirView->ItemIsDirectory(Item))
   {
   {
     DropHandler = false;
     DropHandler = false;

+ 4 - 4
source/forms/ScpCommander.dfm

@@ -1022,7 +1022,7 @@ inherited ScpCommanderForm: TScpCommanderForm
           Alignment = taCenter
           Alignment = taCenter
           Framed = False
           Framed = False
           Hint = 'Click to show hidden files'
           Hint = 'Click to show hidden files'
-          MaxSize = 100
+          MaxSize = 120
           Size = 80
           Size = 80
           StretchPriority = 2
           StretchPriority = 2
           Tag = 0
           Tag = 0
@@ -1032,7 +1032,7 @@ inherited ScpCommanderForm: TScpCommanderForm
           Alignment = taCenter
           Alignment = taCenter
           Framed = False
           Framed = False
           Hint = 'Click to modify or clear the filter'
           Hint = 'Click to modify or clear the filter'
-          MaxSize = 100
+          MaxSize = 120
           Size = 80
           Size = 80
           StretchPriority = 2
           StretchPriority = 2
           Tag = 0
           Tag = 0
@@ -1309,7 +1309,7 @@ inherited ScpCommanderForm: TScpCommanderForm
           Alignment = taCenter
           Alignment = taCenter
           Framed = False
           Framed = False
           Hint = 'Click to show hidden files'
           Hint = 'Click to show hidden files'
-          MaxSize = 100
+          MaxSize = 120
           Size = 80
           Size = 80
           StretchPriority = 2
           StretchPriority = 2
           Tag = 0
           Tag = 0
@@ -1319,7 +1319,7 @@ inherited ScpCommanderForm: TScpCommanderForm
           Alignment = taCenter
           Alignment = taCenter
           Framed = False
           Framed = False
           Hint = 'Click to modify or clear the filter'
           Hint = 'Click to modify or clear the filter'
-          MaxSize = 100
+          MaxSize = 120
           Size = 80
           Size = 80
           StretchPriority = 2
           StretchPriority = 2
           Tag = 0
           Tag = 0

+ 3 - 3
source/forms/ScpExplorer.dfm

@@ -953,7 +953,7 @@ inherited ScpExplorerForm: TScpExplorerForm
       Images = GlyphsModule.SessionImages
       Images = GlyphsModule.SessionImages
       Panels = <
       Panels = <
         item
         item
-          Size = 170
+          Size = 130
           StretchPriority = 1
           StretchPriority = 1
           Tag = 0
           Tag = 0
           TextTruncation = twEndEllipsis
           TextTruncation = twEndEllipsis
@@ -961,14 +961,14 @@ inherited ScpExplorerForm: TScpExplorerForm
         item
         item
           Alignment = taCenter
           Alignment = taCenter
           Hint = 'Click to show hidden files'
           Hint = 'Click to show hidden files'
-          Size = 100
+          Size = 120
           Tag = 0
           Tag = 0
           TextTruncation = twEndEllipsis
           TextTruncation = twEndEllipsis
         end
         end
         item
         item
           Alignment = taCenter
           Alignment = taCenter
           Hint = 'Click to modify or clear the filter'
           Hint = 'Click to modify or clear the filter'
-          Size = 100
+          Size = 120
           Tag = 0
           Tag = 0
           TextTruncation = twEndEllipsis
           TextTruncation = twEndEllipsis
         end
         end

+ 5 - 2
source/packages/dragndrop/DragDrop.pas

@@ -902,8 +902,11 @@ begin
           else if dwEffect and DROPEFFECT_Move<>0 then HC:=FOwner.FCHMove
           else if dwEffect and DROPEFFECT_Move<>0 then HC:=FOwner.FCHMove
                else if dwEffect and DROPEFFECT_COPY<>0 then HC:=FOwner.FCHCopy
                else if dwEffect and DROPEFFECT_COPY<>0 then HC:=FOwner.FCHCopy
                          else HC:=DefaultCursor;
                          else HC:=DefaultCursor;
-     if HC=DefaultCursor then Result:=DRAGDROP_S_USEDEFAULTCURSORS
-     else
+     if HC=DefaultCursor then
+     begin
+          Result:=DRAGDROP_S_USEDEFAULTCURSORS
+     end
+         else
      begin
      begin
           Result:=S_Ok;
           Result:=S_Ok;
           Windows.SetCursor(HC);
           Windows.SetCursor(HC);

+ 5 - 2
source/packages/filemng/CustomDirView.pas

@@ -389,7 +389,7 @@ type
     property DimmHiddenFiles: Boolean read FDimmHiddenFiles write SetDimmHiddenFiles default True;
     property DimmHiddenFiles: Boolean read FDimmHiddenFiles write SetDimmHiddenFiles default True;
     property DragDropFilesEx: TCustomizableDragDropFilesEx read FDragDropFilesEx;
     property DragDropFilesEx: TCustomizableDragDropFilesEx read FDragDropFilesEx;
     property FormatSizeBytes: TFormatBytesStyle read FFormatSizeBytes write SetFormatSizeBytes default fbNone;
     property FormatSizeBytes: TFormatBytesStyle read FFormatSizeBytes write SetFormatSizeBytes default fbNone;
-    property WantUseDragImages: Boolean read FWantUseDragImages write FWantUseDragImages default True;
+    property WantUseDragImages: Boolean read FWantUseDragImages write FWantUseDragImages default False;
     property UseDragImages: Boolean read GetUseDragImages stored False;
     property UseDragImages: Boolean read GetUseDragImages stored False;
     property FullDrag default True;
     property FullDrag default True;
     property TargetPopupMenu: Boolean read GetTargetPopupMenu write SetTargetPopupMenu default True;
     property TargetPopupMenu: Boolean read GetTargetPopupMenu write SetTargetPopupMenu default True;
@@ -838,7 +838,7 @@ begin
   FDimmHiddenFiles := True;
   FDimmHiddenFiles := True;
   FShowHiddenFiles := True;
   FShowHiddenFiles := True;
   FFormatSizeBytes := fbNone;
   FFormatSizeBytes := fbNone;
-  FWantUseDragImages := True;
+  FWantUseDragImages := False;
   FAddParentDir := False;
   FAddParentDir := False;
   FullDrag := True;
   FullDrag := True;
   FInvalidNameChars := '\/:*?"<>|';
   FInvalidNameChars := '\/:*?"<>|';
@@ -2222,7 +2222,9 @@ begin
   end;
   end;
 
 
   if Assigned(OnDDQueryContinueDrag) then
   if Assigned(OnDDQueryContinueDrag) then
+  begin
     OnDDQueryContinueDrag(Self, FEscapePressed, grfKeyState, Result);
     OnDDQueryContinueDrag(Self, FEscapePressed, grfKeyState, Result);
+  end;
 
 
   try
   try
     if FEscapePressed then
     if FEscapePressed then
@@ -2549,6 +2551,7 @@ begin
       FDragEnabled := False;
       FDragEnabled := False;
       {Create the dragimage:}
       {Create the dragimage:}
       GlobalDragImageList := DragImageList;
       GlobalDragImageList := DragImageList;
+      // This code is not used anymore
       if UseDragImages and (not AvoidDragImage) then
       if UseDragImages and (not AvoidDragImage) then
       begin
       begin
         ImageListHandle := ListView_CreateDragImage(Handle, FirstItem.Index, Spot);
         ImageListHandle := ListView_CreateDragImage(Handle, FirstItem.Index, Spot);

+ 73 - 283
source/packages/filemng/DirView.pas

@@ -1920,171 +1920,43 @@ begin
   Result := StrCmpLogicalW(PChar(S1), PChar(S2));
   Result := StrCmpLogicalW(PChar(S1), PChar(S2));
 end;
 end;
 
 
-function CompareFileName(I1, I2: TListItem; AOwner: TDirView): Integer; stdcall;
+function CompareFileType(I1, I2: TListItem; P1, P2: PFileRec): Integer;
 var
 var
-  P1, P2: PFileRec;
+  Key1, Key2: string;
 begin
 begin
-  if I1 = I2 then  Result := fEqual
-    else
-  if I1 = nil then Result := fLess
-    else
-  if I2 = nil then Result := fGreater
-    else
+  if P1.Empty then TDirView(I1.ListView).GetDisplayData(I1, False);
+  if P2.Empty then TDirView(I2.ListView).GetDisplayData(I2, False);
+  if P1.IsDirectory then
   begin
   begin
-    P1 := PFileRec(I1.Data);
-    P2 := PFileRec(I2.Data);
-    if P1.isParentDir then
-    begin
-      Result := fLess;
-      Exit;
-    end
-      else
-    if P2.isParentDir then
-    begin
-      Result := fGreater;
-      Exit;
-    end;
-
-    {Directories allways should appear "grouped":}
-    if P1.isDirectory <> P2.isDirectory then
-    begin
-      if P1.isDirectory then
-      begin
-        Result := fLess;
-        Exit;
-      end
-        else
-      begin
-        Result := fGreater;
-        Exit;
-      end;
-    end
-      else Result := CompareLogicalText(P1.DisplayName, P2.DisplayName);
-  end;
-
-  if not AOwner.SortAscending then
-    Result := -Result;
-end; {CompareFileName}
-
-function CompareFileSize(I1, I2: TListItem; AOwner : TDirView): Integer; stdcall;
-var
-  P1, P2: PFileRec;
-begin
-  if I1 = I2 then Result := fEqual
-    else
-  if I1 = nil then Result := fLess
-    else
-  if I2 = nil then Result := fGreater
+    Key1 := P1.TypeName + ' ' + P1.DisplayName;
+    Key2 := P2.TypeName + ' ' + P2.DisplayName;
+  end
     else
     else
   begin
   begin
-    P1 := PFileRec(I1.Data);
-    P2 := PFileRec(I2.Data);
-    if P1.isParentDir then
-    begin
-      Result := fLess;
-      Exit;
-    end
-      else
-    if P2.isParentDir then
-    begin
-      Result := fGreater;
-      Exit;
-    end;
-    {Directories always should appear "grouped":}
-    if P1.isDirectory <> P2.isDirectory then
-    begin
-      if P1.isDirectory then
-      begin
-        Result := fLess;
-        Exit;
-      end
-        else
-      begin
-        Result := fGreater;
-        Exit;
-      end;
-    end
-      else
-    begin
-      if P1.Size < P2.Size then Result := fLess
-        else
-      if P1.Size > P2.Size then Result := fGreater
-        else
-      Result := CompareLogicalText(P1.DisplayName, P2.DisplayName);
-    end;
+    Key1 := P1.TypeName + ' ' + P1.FileExt + ' ' + P1.DisplayName;
+    Key2 := P2.TypeName + ' ' + P2.FileExt + ' ' + P2.DisplayName;
   end;
   end;
-  if not AOwner.SortAscending then
-    Result := -Result;
-end; {CompareFileSize}
+  Result := CompareLogicalText(Key1, Key2);
+end;
 
 
-function CompareFileType(I1, I2: TListItem; AOwner: TDirView): Integer; stdcall;
+function CompareFileTime(P1, P2: PFileRec): Integer;
 var
 var
-  P1, P2: PFileRec;
-  Key1, Key2: string;
+  Time1, Time2: Int64;
 begin
 begin
-  if I1 = I2 then  Result := fEqual
-    else
-  if I1 = nil then Result := fLess
+  Time1 := Int64(P1.FileTime.dwHighDateTime) shl 32 + P1.FileTime.dwLowDateTime;
+  Time2 := Int64(P2.FileTime.dwHighDateTime) shl 32 + P2.FileTime.dwLowDateTime;
+  if Time1 < Time2 then Result := fLess
     else
     else
-  if I2 = nil then Result := fGreater
-    else
-  begin
-    P1 := PFileRec(I1.Data);
-    P2 := PFileRec(I2.Data);
-    if P1.isParentDir then
-    begin
-      Result := fLess;
-      Exit;
-    end
-      else
-    if P2.isParentDir then
-    begin
-      Result := fGreater;
-      Exit;
-    end;
-
-    {Directories allways should appear "grouped":}
-    if P1.isDirectory <> P2.isDirectory then
-    begin
-      if P1.isDirectory then
-      begin
-        Result := fLess;
-        Exit;
-      end
-        else
-      begin
-        Result := fGreater;
-        Exit;
-      end;
-    end
-      else
-    begin
-      if P1.Empty then TDirView(I1.ListView).GetDisplayData(I1, False);
-      if P2.Empty then TDirView(I2.ListView).GetDisplayData(I2, False);
-      if P1.IsDirectory then
-      begin
-        Key1 := P1.TypeName + ' ' + P1.DisplayName;
-        Key2 := P2.TypeName + ' ' + P2.DisplayName;
-      end
-        else
-      begin
-        Key1 := P1.TypeName + ' ' + P1.FileExt + ' ' + P1.DisplayName;
-        Key2 := P2.TypeName + ' ' + P2.FileExt + ' ' + P2.DisplayName;
-      end;
-      Result := CompareLogicalText(Key1, Key2);
-      if Result = 0 then
-        // the fallback is probably pointless for directories as they have the same TypeName
-        Result := CompareLogicalText(P1.DisplayName, P2.DisplayName);
-    end;
-  end;
-  if not AOwner.SortAscending then
-    Result := -Result;
-end; {CompareFileType}
+  if Time1 > Time2 then Result := fGreater
+    else Result := fEqual; // fallback
+end;
 
 
-function CompareFileExt(I1, I2: TListItem; AOwner: TDirView): Integer; stdcall;
+function CompareFile(I1, I2: TListItem; AOwner: TDirView): Integer; stdcall;
 var
 var
+  ConsiderDirection: Boolean;
   P1, P2: PFileRec;
   P1, P2: PFileRec;
 begin
 begin
+  ConsiderDirection := True;
   if I1 = I2 then Result := fEqual
   if I1 = I2 then Result := fEqual
     else
     else
   if I1 = nil then Result := fLess
   if I1 = nil then Result := fLess
@@ -2097,166 +1969,87 @@ begin
     if P1.isParentDir then
     if P1.isParentDir then
     begin
     begin
       Result := fLess;
       Result := fLess;
-      Exit;
+      ConsiderDirection := False;
     end
     end
       else
       else
     if P2.isParentDir then
     if P2.isParentDir then
     begin
     begin
       Result := fGreater;
       Result := fGreater;
-      Exit;
-    end;
-    {Directories allways should appear "grouped":}
-    if P1.isDirectory <> P2.isDirectory then
-    begin
-      if P1.isDirectory then
-      begin
-        Result := fLess;
-        Exit;
-      end
-        else
-      begin
-        Result := fGreater;
-        Exit;
-      end;
+      ConsiderDirection := False;
     end
     end
       else
       else
-    if P1.isDirectory then
-    begin
-      Result := CompareLogicalText(P1.DisplayName, P2.DisplayName);
-    end
-      else
-    begin
-      Result := CompareLogicalText(
-        P1.FileExt + ' ' + P1.DisplayName, P2.FileExt + ' ' + P2.DisplayName);
-    end;
-  end;
-  if not AOwner.SortAscending then
-    Result := -Result;
-end; {CompareFileExt}
-
-function CompareFileAttr(I1, I2: TListItem; AOwner: TDirView): Integer; stdcall;
-var
-  P1, P2: PFileRec;
-begin
-  if I1 = I2 then Result := 0
-    else
-  if I1 = nil then Result := -1
-    else
-  if I2 = nil then Result := 1
-    else
-  begin
-    P1 := PFileRec(I1.Data);
-    P2 := PFileRec(I2.Data);
-    if P1.isParentDir then
-    begin
-      Result := fLess;
-      Exit;
-    end
-      else
-    if P2.isParentDir then
-    begin
-      Result := fGreater;
-      Exit;
-    end;
-    {Directories allways should appear "grouped":}
+    {Directories should always appear "grouped":}
     if P1.isDirectory <> P2.isDirectory then
     if P1.isDirectory <> P2.isDirectory then
     begin
     begin
       if P1.isDirectory then
       if P1.isDirectory then
       begin
       begin
         Result := fLess;
         Result := fLess;
-        Exit;
+        ConsiderDirection := False;
       end
       end
         else
         else
       begin
       begin
         Result := fGreater;
         Result := fGreater;
-        Exit;
+        ConsiderDirection := False;
       end;
       end;
     end
     end
       else
       else
     begin
     begin
-      if P1.Attr < P2.Attr then Result := fLess
-        else
-      if P1.Attr > P2.Attr then Result := fGreater
-        else
-      Result := CompareLogicalText(P1.DisplayName, P2.DisplayName);
-    end;
-  end;
-  if not AOwner.SortAscending then
-    Result := -Result;
-end; {CompareFileAttr}
+      Result := fEqual;
+
+      case AOwner.DirColProperties.SortDirColumn of
+        dvName:
+          ; // fallback
+
+        dvSize:
+          if P1.Size < P2.Size then Result := fLess
+            else
+          if P1.Size > P2.Size then Result := fGreater
+            else ; // fallback
+
+        dvType:
+          Result := CompareFileType(I1, I2, P1, P2);
+
+        dvChanged:
+          Result := CompareFileTime(P1, P2);
+
+        dvAttr:
+          if P1.Attr < P2.Attr then Result := fLess
+            else
+          if P1.Attr > P2.Attr then Result := fGreater
+            else ; // fallback
+
+        dvExt:
+          if not P1.isDirectory then
+          begin
+            Result := CompareLogicalText(
+              P1.FileExt + ' ' + P1.DisplayName, P2.FileExt + ' ' + P2.DisplayName);
+          end
+            else ; //fallback
 
 
-function CompareFileTime(I1, I2: TListItem; AOwner: TDirView): Integer; stdcall;
-var
-  Time1, Time2: Int64;
-  P1, P2: PFileRec;
-begin
-  if I1 = I2 then Result := fEqual
-    else
-  if I1 = nil then Result := fLess
-    else
-  if I2 = nil then Result := fGreater
-    else
-  begin
-    P1 := PFileRec(I1.Data);
-    P2 := PFileRec(I2.Data);
-    if P1.isParentDir then
-    begin
-      Result := fLess;
-      Exit;
-    end
-      else
-    if P2.isParentDir then
-    begin
-      Result := fGreater;
-      Exit;
-    end;
-    {Directories allways should appear "grouped":}
-    if P1.isDirectory <> P2.isDirectory then
-    begin
-      if P1.isDirectory then
-      begin
-        Result := fLess;
-        Exit;
-      end
         else
         else
+          ; // fallback
+      end;
+
+      if Result = fEqual then
       begin
       begin
-        Result := fGreater;
-        Exit;
+        Result := CompareLogicalText(P1.DisplayName, P2.DisplayName)
       end;
       end;
-    end
-      else
-    begin
-      Time1 := Int64(P1.FileTime.dwHighDateTime) shl 32 + P1.FileTime.dwLowDateTime;
-      Time2 := Int64(P2.FileTime.dwHighDateTime) shl 32 + P2.FileTime.dwLowDateTime;
-      if Time1 < Time2 then Result := fLess
-        else
-      if Time1 > Time2 then Result := fGreater
-        else
-      Result := CompareFileName(I1, I2, AOwner);
     end;
     end;
   end;
   end;
-  if not AOwner.SortAscending then
+
+  if ConsiderDirection and (not AOwner.SortAscending) then
+  begin
     Result := -Result;
     Result := -Result;
-end; {CompareFileTime}
+  end;
+end;
 
 
 procedure TDirView.SortItems;
 procedure TDirView.SortItems;
-var
-  SortProc: TLVCompare;
 begin
 begin
   if HandleAllocated then
   if HandleAllocated then
   begin
   begin
     StopIconUpdateThread;
     StopIconUpdateThread;
     try
     try
-      case DirColProperties.SortDirColumn of
-        dvName: SortProc := @CompareFilename;
-        dvSize: SortProc := @CompareFileSize;
-        dvType: SortProc := @CompareFileType;
-        dvChanged: SortProc := @CompareFileTime;
-        dvAttr: SortProc := @CompareFileAttr;
-        dvExt: SortProc := @CompareFileExt;
-        else SortProc := @CompareFilename;
-      end;
-      CustomSortItems(Pointer(@SortProc));
+      CustomSortItems(@CompareFile);
     finally
     finally
       if (not Loading) and FUseIconUpdateThread then
       if (not Loading) and FUseIconUpdateThread then
         StartIconUpdateThread;
         StartIconUpdateThread;
@@ -3193,8 +2986,8 @@ begin
   if Assigned(FDriveView) then
   if Assigned(FDriveView) then
   begin
   begin
     // When a change is detected while menu is popped up
     // When a change is detected while menu is popped up
-    // it loses focus (or somethins similar)
-    // preventing it from handling sussequent click.
+    // it loses focus (or something similar)
+    // preventing it from handling subsequent click.
     // This typically happens when right-dragging from remote to local panel,
     // This typically happens when right-dragging from remote to local panel,
     // what causes temp directory being created+deleted.
     // what causes temp directory being created+deleted.
     // This is HACK, we should implement some uniform watch disabling/enabling
     // This is HACK, we should implement some uniform watch disabling/enabling
@@ -3223,15 +3016,12 @@ end;
 procedure TDirView.DDDropHandlerSucceeded(Sender: TObject; grfKeyState: Longint;
 procedure TDirView.DDDropHandlerSucceeded(Sender: TObject; grfKeyState: Longint;
   Point: TPoint; dwEffect: Longint);
   Point: TPoint; dwEffect: Longint);
 begin
 begin
+  // Not sure why is this here. There's no "disable" counterparty.
   if not WatchThreadActive then
   if not WatchThreadActive then
   begin
   begin
     FChangeTimer.Interval := FChangeInterval;
     FChangeTimer.Interval := FChangeInterval;
     FChangeTimer.Enabled  := True;
     FChangeTimer.Enabled  := True;
   end;
   end;
-  if Assigned(FDriveView) then
-  begin
-    TDriveView(FDriveView).ResumeChangeTimer;
-  end;
 
 
   inherited;
   inherited;
 end;
 end;

+ 5 - 0
source/putty/windows/WINNET.C

@@ -990,7 +990,12 @@ static DWORD try_connect(Actual_Socket sock,
 
 
     if (sndbuf > 0)
     if (sndbuf > 0)
     {
     {
+	int rcvbuf = 4 * 1024 * 1024;
 	p_setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *) &sndbuf, sizeof(sndbuf));
 	p_setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *) &sndbuf, sizeof(sndbuf));
+
+	// For now we increase receive buffer, whenever send buffer is set.
+	// The size is not configurable. The constant taken from FZ.
+	p_setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*) &rcvbuf, sizeof(rcvbuf));
     }
     }
 
 
     /*
     /*

+ 1 - 1
source/resource/Propagation.rc

@@ -2,7 +2,7 @@ STRINGTABLE
 BEGIN
 BEGIN
   DESCRIPTION_45_LETTERS, "Free SFTP, WebDAV and FTP client for Windows"
   DESCRIPTION_45_LETTERS, "Free SFTP, WebDAV and FTP client for Windows"
   DESCRIPTION_80_LETTERS, "WinSCP is a popular free SFTP, SCP, WebDAV and FTP client for Windows."
   DESCRIPTION_80_LETTERS, "WinSCP is a popular free SFTP, SCP, WebDAV and FTP client for Windows."
-  DESCRIPTION_250_LETTERS, "WinSCP, a popular free SFTP and FTP client for Windows, copies files between a local and remote computer. It supports also FTPS, SCP and WebDAV. It offers easy to use GUI for all common file operations and a powerfull automation with .NET assembly."
+  DESCRIPTION_250_LETTERS, "WinSCP, a popular free SFTP and FTP client for Windows, copies files between a local and remote computer. It supports also FTPS, SCP and WebDAV. It offers easy to use GUI for all common file operations and a powerful automation with .NET assembly."
   DESCRIPTION_450_LETTERS, "WinSCP is a popular free SFTP and FTP client for Windows, a powerful tool that will improve your productivity. WinSCP can copy files between a local and remote computer using FTP, FTPS, SCP, SFTP or WebDAV. WinSCP offers an easy to use GUI for all common operations with files and directories. Power users can automate WinSCP using .NET assembly. WinSCP documentation is at http://winscp.net/. WinSCP is available in English and many other languages."
   DESCRIPTION_450_LETTERS, "WinSCP is a popular free SFTP and FTP client for Windows, a powerful tool that will improve your productivity. WinSCP can copy files between a local and remote computer using FTP, FTPS, SCP, SFTP or WebDAV. WinSCP offers an easy to use GUI for all common operations with files and directories. Power users can automate WinSCP using .NET assembly. WinSCP documentation is at http://winscp.net/. WinSCP is available in English and many other languages."
   // "English" shall be replaced by translation language
   // "English" shall be replaced by translation language
   DESCRIPTION_2000_LETTERS, "WinSCP is a popular free SFTP and FTP client for Windows. Moreover, WinSCP is a powerful multi-functional tool that will improve your productivity. WinSCP can copy files between a local and remote computer using multiple protocols: FTP, FTPS, SCP, SFTP or WebDAV. On the one hand, WinSCP offers an easy to use graphical user interface; you can choose between Windows Explorer look and tabbed twin-panel interface like Norton commander. On the other hand, advanced users can automate WinSCP functionality using .NET assembly or simple batch file scripting. You will use WinSCP for all common operations with files. You can start editing a file directly from WinSCP, either using WinSCP internal text editor or using integration with your favorite external text editor. WinSCP operations are not limited to individual files; WinSCP offers several ways to synchronize your remote and local directories. After connecting to a site you can choose to store site information for repeated access, WinSCP can even share site settings with another popular open source tool PuTTY. WinSCP integrates also with Pageant (PuTTY authentication agent) for full support of public key authentication with SSH. Admins love WinSCP support for portable operation using a configuration file instead of registry entries, suitable for operation from removable media. A comprehensive WinSCP documentation is freely accessible at http://winscp.net/. This site hosts also a very active user forum for support and feature requests. WinSCP is available in English and many other languages. WinSCP is an open source software distributed free of charge under the terms of the GNU General Public License (GPL)."
   DESCRIPTION_2000_LETTERS, "WinSCP is a popular free SFTP and FTP client for Windows. Moreover, WinSCP is a powerful multi-functional tool that will improve your productivity. WinSCP can copy files between a local and remote computer using multiple protocols: FTP, FTPS, SCP, SFTP or WebDAV. On the one hand, WinSCP offers an easy to use graphical user interface; you can choose between Windows Explorer look and tabbed twin-panel interface like Norton commander. On the other hand, advanced users can automate WinSCP functionality using .NET assembly or simple batch file scripting. You will use WinSCP for all common operations with files. You can start editing a file directly from WinSCP, either using WinSCP internal text editor or using integration with your favorite external text editor. WinSCP operations are not limited to individual files; WinSCP offers several ways to synchronize your remote and local directories. After connecting to a site you can choose to store site information for repeated access, WinSCP can even share site settings with another popular open source tool PuTTY. WinSCP integrates also with Pageant (PuTTY authentication agent) for full support of public key authentication with SSH. Admins love WinSCP support for portable operation using a configuration file instead of registry entries, suitable for operation from removable media. A comprehensive WinSCP documentation is freely accessible at http://winscp.net/. This site hosts also a very active user forum for support and feature requests. WinSCP is available in English and many other languages. WinSCP is an open source software distributed free of charge under the terms of the GNU General Public License (GPL)."

+ 2 - 0
source/resource/TextsFileZilla.h

@@ -658,6 +658,8 @@
 #define IDS_OPTIONSCAPTION_FONTNAME     3104
 #define IDS_OPTIONSCAPTION_FONTNAME     3104
 #endif
 #endif
 #define IDS_PROXY_CONNECTED             3201
 #define IDS_PROXY_CONNECTED             3201
+#define IDS_CONTROL_CONNECTION          3202
+#define IDS_DATA_CONNECTION             3203
 #if 0
 #if 0
 #define ID_CANCELBUTTON                 32768
 #define ID_CANCELBUTTON                 32768
 #define ID_COPYTOSITEMANAGER            32769
 #define ID_COPYTOSITEMANAGER            32769

+ 2 - 0
source/resource/TextsFileZilla.rc

@@ -85,4 +85,6 @@ END
 STRINGTABLE
 STRINGTABLE
 BEGIN
 BEGIN
   IDS_PROXY_CONNECTED, "Connection with proxy established, performing handshake..."
   IDS_PROXY_CONNECTED, "Connection with proxy established, performing handshake..."
+  IDS_CONTROL_CONNECTION, "control connection"
+  IDS_DATA_CONNECTION, "data connection"
 END
 END

+ 1 - 0
source/resource/TextsWin.h

@@ -224,6 +224,7 @@
 #define MESSAGE_LOADING         1536
 #define MESSAGE_LOADING         1536
 #define NEW_VERSION_CLICK       1537
 #define NEW_VERSION_CLICK       1537
 #define DIRECTORY_READING_AND_RESOLVING_PROGRESS 1538
 #define DIRECTORY_READING_AND_RESOLVING_PROGRESS 1538
+#define MESSAGE_DISPLAY_ERROR   1539
 
 
 #define WIN_FORMS_STRINGS       1600
 #define WIN_FORMS_STRINGS       1600
 #define LOG_NOLOG               1601
 #define LOG_NOLOG               1601

+ 1 - 0
source/resource/TextsWin1.rc

@@ -226,6 +226,7 @@ BEGIN
         MESSAGE_LOADING, "Loading..."
         MESSAGE_LOADING, "Loading..."
         NEW_VERSION_CLICK, "%s\n\nClick here, to see what is new."
         NEW_VERSION_CLICK, "%s\n\nClick here, to see what is new."
         DIRECTORY_READING_AND_RESOLVING_PROGRESS, "%d Resolving links and Reading directory"
         DIRECTORY_READING_AND_RESOLVING_PROGRESS, "%d Resolving links and Reading directory"
+        MESSAGE_DISPLAY_ERROR, "Cannot display"
 
 
         WIN_FORMS_STRINGS, "WIN_FORMS_STRINGS"
         WIN_FORMS_STRINGS, "WIN_FORMS_STRINGS"
         LOG_NOLOG, "No session log."
         LOG_NOLOG, "No session log."

+ 3 - 3
source/resource/TextsWin2.rc

@@ -25,14 +25,14 @@ BEGIN
 "G:%APP% [mysession] /synchronize [local_dir] [remote_dir] [/defaults]\n"
 "G:%APP% [mysession] /synchronize [local_dir] [remote_dir] [/defaults]\n"
 "G:%APP% [mysession] /keepuptodate [local_dir] [remote_dir] [/defaults]\n"
 "G:%APP% [mysession] /keepuptodate [local_dir] [remote_dir] [/defaults]\n"
 "G:%APP% [mysession] [/privatekey=<key>] [/hostkey=<fingerprint>]\n"
 "G:%APP% [mysession] [/privatekey=<key>] [/hostkey=<fingerprint>]\n"
-"G:%APP% [mysession] [/passive[=on|off]] /implicit|explicit\n"
+"G:%APP% [mysession] [/passive[=on|off]] [/implicit|explicit]\n"
 "G:%APP% [mysession] [/timeout=<sec>]\n"
 "G:%APP% [mysession] [/timeout=<sec>]\n"
-"G:%APP% [mysession] [/rawsettings setting1=value1 settings2=value2 ...]\n"
+"G:%APP% [mysession] [/rawsettings setting1=value1 setting2=value2 ...]\n"
 "G:%APP% [/console] [/script=file] [/command command1...] [/parameter param1...]\n"
 "G:%APP% [/console] [/script=file] [/command command1...] [/parameter param1...]\n"
 "C:%APP% [/script=file] [/command command1...] [/parameter param1...]\n"
 "C:%APP% [/script=file] [/command command1...] [/parameter param1...]\n"
 "B:%APP% [/ini=<inifile>] [/log=<logfile>] [/xmllog=<logfile> [/xmlgroups]]\n"
 "B:%APP% [/ini=<inifile>] [/log=<logfile>] [/xmllog=<logfile> [/xmlgroups]]\n"
 "B:%APP% [/rawconfig config1=value1 config2=value2 ...]\n"
 "B:%APP% [/rawconfig config1=value1 config2=value2 ...]\n"
-"B:%APP% [/batchsettings <site_mask> setting1=value1 setting2=value2 ...]\n"
+"B:%APP% /batchsettings <site_mask> setting1=value1 setting2=value2 ...\n"
 "G:%APP% /update\n"
 "G:%APP% /update\n"
 "B:%APP% /help\n"
 "B:%APP% /help\n"
 "\n"
 "\n"

+ 2 - 0
source/windows/ConsoleRunner.cpp

@@ -2104,6 +2104,8 @@ int __fastcall Console(TConsoleMode Mode)
       Console = new TNullConsole();
       Console = new TNullConsole();
     }
     }
 
 
+    SetNoGUI();
+
     if (Mode == cmHelp)
     if (Mode == cmHelp)
     {
     {
       Configuration->Usage->Inc(L"UsageShown");
       Configuration->Usage->Inc(L"UsageShown");

+ 12 - 7
source/windows/GUITools.cpp

@@ -646,6 +646,17 @@ void __fastcall TBrowserViewer::BeforeNavigate2(
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+TPanel * __fastcall CreateLabelPanel(TPanel * Parent, const UnicodeString & Label)
+{
+  TPanel * Result = new TPanel(Parent);
+  Result->Parent = Parent;
+  Result->BevelOuter = bvNone;
+  Result->BevelInner = bvNone; // default
+  Result->Align = alClient;
+  Result->Caption = Label;
+  return Result;
+}
+//---------------------------------------------------------------------------
 TWebBrowserEx * __fastcall CreateBrowserViewer(TPanel * Parent, const UnicodeString & LoadingLabel)
 TWebBrowserEx * __fastcall CreateBrowserViewer(TPanel * Parent, const UnicodeString & LoadingLabel)
 {
 {
   TBrowserViewer * Result = new TBrowserViewer(Parent);
   TBrowserViewer * Result = new TBrowserViewer(Parent);
@@ -655,13 +666,7 @@ TWebBrowserEx * __fastcall CreateBrowserViewer(TPanel * Parent, const UnicodeStr
   Result->Align = alClient;
   Result->Align = alClient;
   Result->ControlBorder = cbNone;
   Result->ControlBorder = cbNone;
 
 
-  TPanel * LoadingPanel = new TPanel(Parent);
-  LoadingPanel->Parent = Parent;
-  LoadingPanel->BevelOuter = bvNone;
-  LoadingPanel->BevelInner = bvNone; // default
-  LoadingPanel->Align = alClient;
-  LoadingPanel->Caption = LoadingLabel;
-  Result->LoadingPanel = LoadingPanel;
+  Result->LoadingPanel = CreateLabelPanel(Parent, LoadingLabel);
 
 
   return Result;
   return Result;
 }
 }

+ 1 - 0
source/windows/GUITools.h

@@ -42,6 +42,7 @@ typedef int __fastcall (*TCalculateWidth)(UnicodeString Text, void * Arg);
 void __fastcall ApplyTabs(
 void __fastcall ApplyTabs(
   UnicodeString & Text, wchar_t Padding,
   UnicodeString & Text, wchar_t Padding,
   TCalculateWidth CalculateWidth, void * CalculateWidthArg);
   TCalculateWidth CalculateWidth, void * CalculateWidthArg);
+TPanel * __fastcall CreateLabelPanel(TPanel * Parent, const UnicodeString & Label);
 namespace Webbrowserex
 namespace Webbrowserex
 {
 {
   class TWebBrowserEx;
   class TWebBrowserEx;

+ 5 - 0
source/windows/UserInterface.cpp

@@ -63,6 +63,11 @@ TConfiguration * __fastcall CreateConfiguration()
   return WinConfiguration;
   return WinConfiguration;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+TOptions * __fastcall GetGlobalOptions()
+{
+  return TProgramParams::Instance();
+}
+//---------------------------------------------------------------------------
 TCustomScpExplorerForm * __fastcall CreateScpExplorer()
 TCustomScpExplorerForm * __fastcall CreateScpExplorer()
 {
 {
   TCustomScpExplorerForm * ScpExplorer;
   TCustomScpExplorerForm * ScpExplorer;

+ 1 - 1
source/windows/WinConfiguration.cpp

@@ -61,7 +61,7 @@ bool __fastcall TEditorData::DecideExternalEditorText(UnicodeString ExternalEdit
 {
 {
   bool Result = false;
   bool Result = false;
   // By default we use default transfer mode (binary),
   // By default we use default transfer mode (binary),
-  // as all reasonable 3rd party editors suppose all EOS styles.
+  // as all reasonable 3rd party editors support all EOL styles.
   // A notable exception is Windows Notepad, so here's an exception for it.
   // A notable exception is Windows Notepad, so here's an exception for it.
 
 
   ReformatFileNameCommand(ExternalEditor);
   ReformatFileNameCommand(ExternalEditor);

+ 9 - 1
source/windows/WinInterface.cpp

@@ -677,12 +677,20 @@ void __fastcall BusyEnd(void * Token)
 static DWORD MainThread = 0;
 static DWORD MainThread = 0;
 static TDateTime LastGUIUpdate = 0;
 static TDateTime LastGUIUpdate = 0;
 static double GUIUpdateIntervalFrac = static_cast<double>(OneSecond/1000*GUIUpdateInterval);  // 1/5 sec
 static double GUIUpdateIntervalFrac = static_cast<double>(OneSecond/1000*GUIUpdateInterval);  // 1/5 sec
+static bool NoGUI = false;
+//---------------------------------------------------------------------------
+void __fastcall SetNoGUI()
+{
+  NoGUI = true;
+}
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 bool __fastcall ProcessGUI(bool Force)
 bool __fastcall ProcessGUI(bool Force)
 {
 {
   assert(MainThread != 0);
   assert(MainThread != 0);
   bool Result = false;
   bool Result = false;
-  if (MainThread == GetCurrentThreadId())
+  // Calling ProcessMessages in Azure WebJob causes access violation in VCL.
+  // As we do not really need to call it in scripting/.NET, just skip it.
+  if ((MainThread == GetCurrentThreadId()) && !NoGUI)
   {
   {
     TDateTime N = Now();
     TDateTime N = Now();
     if (Force ||
     if (Force ||

+ 27 - 1
source/windows/WinMain.cpp

@@ -502,6 +502,33 @@ int __fastcall Execute()
     Configuration->Usage->Inc(L"ConsoleDotNet");
     Configuration->Usage->Inc(L"ConsoleDotNet");
   }
   }
 
 
+  UnicodeString SwitchValue;
+  if (Params->FindSwitch(L"loglevel", SwitchValue))
+  {
+    int StarPos = SwitchValue.Pos(L"*");
+    if (StarPos > 0)
+    {
+      bool LogSensitive = true;
+      SwitchValue.Delete(StarPos, 1);
+
+      if ((StarPos <= SwitchValue.Length()) &&
+          (SwitchValue[StarPos] == L'-'))
+      {
+        LogSensitive = false;
+        SwitchValue.Delete(StarPos, 1);
+      }
+
+      SwitchValue = SwitchValue.Trim();
+
+      Configuration->TemporaryLogSensitive(LogSensitive);
+    }
+    int LogProtocol;
+    if (!SwitchValue.IsEmpty() && TryStrToInt(SwitchValue, LogProtocol) && (LogProtocol >= 0))
+    {
+      Configuration->TemporaryLogProtocol(LogProtocol);
+    }
+  }
+
   TConsoleMode Mode = cmNone;
   TConsoleMode Mode = cmNone;
   if (Params->FindSwitch(L"help") || Params->FindSwitch(L"h") || Params->FindSwitch(L"?"))
   if (Params->FindSwitch(L"help") || Params->FindSwitch(L"h") || Params->FindSwitch(L"?"))
   {
   {
@@ -559,7 +586,6 @@ int __fastcall Execute()
       }
       }
     }
     }
 
 
-    UnicodeString SwitchValue;
     if (Params->FindSwitch(L"UninstallCleanup"))
     if (Params->FindSwitch(L"UninstallCleanup"))
     {
     {
       MaintenanceTask();
       MaintenanceTask();

+ 2 - 0
source/windows/WinSCP.exe.manifest

@@ -40,6 +40,8 @@
             <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
             <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
             <!-- Windows 8.1 -->
             <!-- Windows 8.1 -->
             <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
             <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+            <!-- Windows 10 -->
+            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
         </application>
         </application>
     </compatibility>
     </compatibility>
     <asmv3:application>
     <asmv3:application>