Martin Prikryl %!s(int64=11) %!d(string=hai) anos
pai
achega
ef8921a3ca
Modificáronse 70 ficheiros con 744 adicións e 455 borrados
  1. 47 74
      dotnet/Session.cs
  2. 3 1
      dotnet/internal/ExeSessionProcess.cs
  3. 32 0
      dotnet/internal/Tools.cs
  4. 3 3
      dotnet/properties/AssemblyInfo.cs
  5. 0 2
      libs/openssl/ssl/s23_pkt.c
  6. 0 40
      libs/openssl/ssl/ssl.h
  7. 1 1
      source/Console.cbproj
  8. 1 1
      source/DragExt.cbproj
  9. 2 2
      source/DragExt64.rc
  10. 2 2
      source/WinSCP.cbproj
  11. 7 0
      source/core/Configuration.cpp
  12. 3 0
      source/core/Configuration.h
  13. 8 0
      source/core/FileOperationProgress.cpp
  14. 1 0
      source/core/FileOperationProgress.h
  15. 26 1
      source/core/FtpFileSystem.cpp
  16. 2 0
      source/core/Interface.h
  17. 4 0
      source/core/ScpFileSystem.cpp
  18. 77 55
      source/core/Script.cpp
  19. 2 1
      source/core/Script.h
  20. 12 2
      source/core/SecureShell.cpp
  21. 16 63
      source/core/SessionData.cpp
  22. 1 0
      source/core/SessionData.h
  23. 18 5
      source/core/SessionInfo.cpp
  24. 1 0
      source/core/SessionInfo.h
  25. 4 0
      source/core/SftpFileSystem.cpp
  26. 11 1
      source/core/Terminal.cpp
  27. 1 0
      source/core/Terminal.h
  28. 13 12
      source/core/WebDAVFileSystem.cpp
  29. 1 1
      source/core/WebDAVFileSystem.h
  30. 1 0
      source/filezilla/AsyncProxySocketLayer.cpp
  31. 18 12
      source/filezilla/ControlSocket.cpp
  32. 1 0
      source/filezilla/FileZillaOpt.h
  33. 6 0
      source/filezilla/FtpControlSocket.cpp
  34. 3 0
      source/filezilla/TransferSocket.cpp
  35. 1 1
      source/forms/Custom.cpp
  36. 29 27
      source/forms/CustomScpExplorer.cpp
  37. 3 1
      source/forms/CustomScpExplorer.h
  38. 15 0
      source/forms/EditorPreferences.cpp
  39. 1 0
      source/forms/EditorPreferences.h
  40. 1 5
      source/forms/FileSystemInfo.cpp
  41. 5 1
      source/forms/MessageDlg.cpp
  42. 4 0
      source/forms/Preferences.cpp
  43. 15 5
      source/forms/Preferences.dfm
  44. 1 0
      source/forms/Preferences.h
  45. 2 8
      source/forms/Progress.cpp
  46. 0 1
      source/forms/Progress.h
  47. 2 2
      source/forms/Properties.cpp
  48. 2 2
      source/forms/SynchronizeChecklist.dfm
  49. 12 6
      source/packages/filemng/BaseUtils.pas
  50. 6 2
      source/resource/Propagation.rc
  51. 7 6
      source/resource/TextsCore.h
  52. 2 1
      source/resource/TextsCore1.rc
  53. 19 10
      source/resource/TextsCore2.rc
  54. 3 0
      source/resource/TextsFileZilla.h
  55. 5 0
      source/resource/TextsFileZilla.rc
  56. 6 2
      source/resource/TextsWin.h
  57. 5 1
      source/resource/TextsWin1.rc
  58. 9 5
      source/resource/TextsWin2.rc
  59. 95 40
      source/windows/ConsoleRunner.cpp
  60. 1 1
      source/windows/Setup.cpp
  61. 1 2
      source/windows/TerminalManager.cpp
  62. 18 6
      source/windows/Tools.cpp
  63. 26 5
      source/windows/UserInterface.cpp
  64. 2 2
      source/windows/VCLCommon.cpp
  65. 1 0
      source/windows/VCLCommon.h
  66. 29 1
      source/windows/WinConfiguration.cpp
  67. 2 0
      source/windows/WinConfiguration.h
  68. 35 0
      source/windows/WinInterface.cpp
  69. 6 2
      source/windows/WinInterface.h
  70. 45 31
      source/windows/WinMain.cpp

+ 47 - 74
dotnet/Session.cs

@@ -103,6 +103,7 @@ namespace WinSCP
                 _defaultConfiguration = true;
                 _logUnique = 0;
                 _guardProcessWithJob = true;
+                RawConfiguration = new Dictionary<string, string>();
             }
         }
 
@@ -259,7 +260,7 @@ namespace WinSCP
             {
                 CheckOpened();
 
-                WriteCommand(string.Format(CultureInfo.InvariantCulture, "ls -- \"{0}\"", ArgumentEscape(IncludeTrailingSlash(path))));
+                WriteCommand(string.Format(CultureInfo.InvariantCulture, "ls -- \"{0}\"", Tools.ArgumentEscape(IncludeTrailingSlash(path))));
 
                 RemoteDirectoryInfo result = new RemoteDirectoryInfo();
 
@@ -324,7 +325,7 @@ namespace WinSCP
                     string.Format(CultureInfo.InvariantCulture,
                         "put {0} {1} -- \"{2}\" \"{3}\"",
                         BooleanSwitch(remove, "delete"), options.ToSwitches(),
-                        ArgumentEscape(localPath), ArgumentEscape(remotePath)));
+                        Tools.ArgumentEscape(localPath), Tools.ArgumentEscape(remotePath)));
 
                 TransferOperationResult result = new TransferOperationResult();
 
@@ -339,16 +340,13 @@ namespace WinSCP
                     {
                         if (groupReader.IsNonEmptyElement(TransferEventArgs.UploadTag))
                         {
-                            if (args != null)
-                            {
-                                result.AddTransfer(args);
-                                RaiseFileTransferredEvent(args);
-                            }
+                            AddTransfer(result, args);
                             args = TransferEventArgs.Read(groupReader);
                             mkdir = false;
                         }
                         else if (groupReader.IsNonEmptyElement(TransferEventArgs.MkDirTag))
                         {
+                            AddTransfer(result, args);
                             args = null;
                             mkdir = true;
                             // For now, silently ignoring results (even errors)
@@ -378,17 +376,22 @@ namespace WinSCP
                         }
                     }
 
-                    if (args != null)
-                    {
-                        result.AddTransfer(args);
-                        RaiseFileTransferredEvent(args);
-                    }
+                    AddTransfer(result, args);
                 }
 
                 return result;
             }
         }
 
+        private void AddTransfer(TransferOperationResult result, TransferEventArgs args)
+        {
+            if (args != null)
+            {
+                result.AddTransfer(args);
+                RaiseFileTransferredEvent(args);
+            }
+        }
+
         public TransferOperationResult GetFiles(string remotePath, string localPath, bool remove = false, TransferOptions options = null)
         {
             using (Logger.CreateCallstackAndLock())
@@ -403,7 +406,7 @@ namespace WinSCP
                 WriteCommand(
                     string.Format(CultureInfo.InvariantCulture, "get {0} {1} -- \"{2}\" \"{3}\"",
                         BooleanSwitch(remove, "delete"), options.ToSwitches(),
-                        ArgumentEscape(remotePath), ArgumentEscape(localPath)));
+                        Tools.ArgumentEscape(remotePath), Tools.ArgumentEscape(localPath)));
 
                 TransferOperationResult result = new TransferOperationResult();
 
@@ -417,11 +420,7 @@ namespace WinSCP
                     {
                         if (groupReader.IsNonEmptyElement(TransferEventArgs.DownloadTag))
                         {
-                            if (args != null)
-                            {
-                                result.AddTransfer(args);
-                                RaiseFileTransferredEvent(args);
-                            }
+                            AddTransfer(result, args);
                             args = TransferEventArgs.Read(groupReader);
                         }
                         else if (groupReader.IsNonEmptyElement(RemovalEventArgs.Tag))
@@ -434,11 +433,7 @@ namespace WinSCP
                         }
                     }
 
-                    if (args != null)
-                    {
-                        result.AddTransfer(args);
-                        RaiseFileTransferredEvent(args);
-                    }
+                    AddTransfer(result, args);
                 }
 
                 return result;
@@ -451,7 +446,7 @@ namespace WinSCP
             {
                 CheckOpened();
 
-                WriteCommand(string.Format(CultureInfo.InvariantCulture, "rm -- \"{0}\"", ArgumentEscape(path)));
+                WriteCommand(string.Format(CultureInfo.InvariantCulture, "rm -- \"{0}\"", Tools.ArgumentEscape(path)));
 
                 RemovalOperationResult result = new RemovalOperationResult();
 
@@ -543,7 +538,7 @@ namespace WinSCP
                         BooleanSwitch(mirror, "mirror"),
                         options.ToSwitches(),
                         criteriaName,
-                        ArgumentEscape(localPath), ArgumentEscape(remotePath)));
+                        Tools.ArgumentEscape(localPath), Tools.ArgumentEscape(remotePath)));
 
                 return ReadSynchronizeDirectories();
             }
@@ -568,10 +563,7 @@ namespace WinSCP
                         if ((transferWillBeUpload = groupReader.IsNonEmptyElement(TransferEventArgs.UploadTag)) ||
                             groupReader.IsNonEmptyElement(TransferEventArgs.DownloadTag))
                         {
-                            if (transfer != null)
-                            {
-                                AddSynchronizationTransfer(result, transferIsUpload, transfer);
-                            }
+                            AddSynchronizationTransfer(result, transferIsUpload, transfer);
                             transfer = TransferEventArgs.Read(groupReader);
                             transferIsUpload = transferWillBeUpload;
                         }
@@ -597,10 +589,7 @@ namespace WinSCP
                         }
                     }
 
-                    if (transfer != null)
-                    {
-                        AddSynchronizationTransfer(result, transferIsUpload, transfer);
-                    }
+                    AddSynchronizationTransfer(result, transferIsUpload, transfer);
                 }
                 return result;
             }
@@ -678,7 +667,7 @@ namespace WinSCP
             {
                 CheckOpened();
 
-                WriteCommand(string.Format(CultureInfo.InvariantCulture, "mkdir \"{0}\"", ArgumentEscape(path)));
+                WriteCommand(string.Format(CultureInfo.InvariantCulture, "mkdir \"{0}\"", Tools.ArgumentEscape(path)));
 
                 using (ElementLogReader groupReader = _reader.WaitForGroupAndCreateLogReader())
                 using (ElementLogReader mkdirReader = groupReader.WaitForNonEmptyElementAndCreateLogReader(TransferEventArgs.MkDirTag, LogReadFlags.ThrowFailures))
@@ -695,7 +684,7 @@ namespace WinSCP
             {
                 CheckOpened();
 
-                WriteCommand(string.Format(CultureInfo.InvariantCulture, "mv \"{0}\" \"{1}\"", ArgumentEscape(sourcePath), ArgumentEscape(targetPath)));
+                WriteCommand(string.Format(CultureInfo.InvariantCulture, "mv \"{0}\" \"{1}\"", Tools.ArgumentEscape(sourcePath), Tools.ArgumentEscape(targetPath)));
 
                 using (ElementLogReader groupReader = _reader.WaitForGroupAndCreateLogReader())
                 using (ElementLogReader mvReader = groupReader.WaitForNonEmptyElementAndCreateLogReader("mv", LogReadFlags.ThrowFailures))
@@ -720,6 +709,11 @@ namespace WinSCP
             return path + mask;
         }
 
+        public void AddRawConfiguration(string setting, string value)
+        {
+            RawConfiguration.Add(setting, value);
+        }
+
         [ComRegisterFunction]
         private static void ComRegister(Type t)
         {
@@ -777,15 +771,18 @@ namespace WinSCP
 
         private void AddSynchronizationTransfer(SynchronizationResult result, bool transferIsUpload, TransferEventArgs transfer)
         {
-            if (transferIsUpload)
+            if (transfer != null)
             {
-                result.AddUpload(transfer);
-            }
-            else
-            {
-                result.AddDownload(transfer);
+                if (transferIsUpload)
+                {
+                    result.AddUpload(transfer);
+                }
+                else
+                {
+                    result.AddDownload(transfer);
+                }
+                RaiseFileTransferredEvent(transfer);
             }
-            RaiseFileTransferredEvent(transfer);
         }
 
         private static string IncludeTrailingSlash(string path)
@@ -977,26 +974,16 @@ namespace WinSCP
 
                 string arguments = SessionOptionsToOpenSwitches(sessionOptions);
 
-                if (sessionOptions.RawSettings.Count > 0)
-                {
-                    if (!string.IsNullOrEmpty(arguments))
-                    {
-                        arguments += " ";
-                    }
-                    arguments += "-rawsettings";
-                    foreach (KeyValuePair<string, string> rawSetting in sessionOptions.RawSettings)
-                    {
-                        arguments += string.Format(CultureInfo.InvariantCulture, " {0}=\"{1}\"", rawSetting.Key, ArgumentEscape(rawSetting.Value));
-                    }
-                }
+                Tools.AddRawParameters(ref arguments, sessionOptions.RawSettings, "-rawsettings");
 
                 if (!string.IsNullOrEmpty(arguments))
                 {
-                    arguments += " ";
+                    arguments = " " + arguments;
                 }
 
-                command = "open " + arguments + "\"" + ArgumentEscape(url) + "\"";
-                log = "open " + arguments + "\"" + ArgumentEscape(logUrl) + "\"";
+                // Switches should (and particularly the -rawsettings MUST) come after the URL
+                command = "open \"" + Tools.ArgumentEscape(url) + "\"" + arguments;
+                log = "open \"" + Tools.ArgumentEscape(logUrl) + "\"" + arguments;
             }
         }
 
@@ -1109,7 +1096,7 @@ namespace WinSCP
         {
             using (Logger.CreateCallstack())
             {
-                WriteCommand(string.Format(CultureInfo.InvariantCulture, "stat -- \"{0}\"", ArgumentEscape(path)));
+                WriteCommand(string.Format(CultureInfo.InvariantCulture, "stat -- \"{0}\"", Tools.ArgumentEscape(path)));
 
                 RemoteFileInfo fileInfo = new RemoteFileInfo();
 
@@ -1149,7 +1136,7 @@ namespace WinSCP
 
         internal static string FormatSwitch(string key, string value)
         {
-            return string.Format(CultureInfo.InvariantCulture, "-{0}=\"{1}\"", key, ArgumentEscape(value));
+            return string.Format(CultureInfo.InvariantCulture, "-{0}=\"{1}\"", key, Tools.ArgumentEscape(value));
         }
 
         internal static string FormatSwitch(string key, int value)
@@ -1162,21 +1149,6 @@ namespace WinSCP
             return FormatSwitch(key, (value ? 1 : 0));
         }
 
-        internal static string ArgumentEscape(string value)
-        {
-            int i = 0;
-            while (i < value.Length)
-            {
-                if (value[i] == '"')
-                {
-                    value = value.Insert(i, "\"");
-                    ++i;
-                }
-                ++i;
-            }
-            return value;
-        }
-
         private static string UriEscape(string s)
         {
             return Uri.EscapeDataString(s);
@@ -1647,6 +1619,7 @@ namespace WinSCP
         internal Logger Logger { get; private set; }
         internal bool GuardProcessWithJobInternal { get { return _guardProcessWithJob; } set { CheckNotOpened(); _guardProcessWithJob = value; } }
         internal bool TestHandlesClosedInternal { get; set; }
+        internal Dictionary<string, string> RawConfiguration { get; private set; }
 
         private ExeSessionProcess _process;
         private DateTime _lastOutput;

+ 3 - 1
dotnet/internal/ExeSessionProcess.cs

@@ -74,6 +74,8 @@ namespace WinSCP
                     xmlLogSwitch + "/xmlgroups /nointeractiveinput " + assemblyVersionSwitch +
                     configSwitch + logSwitch + _session.AdditionalExecutableArguments;
 
+                Tools.AddRawParameters(ref arguments, _session.RawConfiguration, "/rawconfig");
+
                 _process = new Process();
                 _process.StartInfo.FileName = executablePath;
                 _process.StartInfo.WorkingDirectory = Path.GetDirectoryName(executablePath);
@@ -90,7 +92,7 @@ namespace WinSCP
 
         private static string LogPathEscape(string path)
         {
-            return Session.ArgumentEscape(path).Replace("!", "!!");
+            return Tools.ArgumentEscape(path).Replace("!", "!!");
         }
 
         public void Abort()

+ 32 - 0
dotnet/internal/Tools.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Globalization;
 
 namespace WinSCP
@@ -18,5 +19,36 @@ namespace WinSCP
         {
             return TimeSpan.FromMilliseconds(value);
         }
+
+        public static string ArgumentEscape(string value)
+        {
+            int i = 0;
+            while (i < value.Length)
+            {
+                if (value[i] == '"')
+                {
+                    value = value.Insert(i, "\"");
+                    ++i;
+                }
+                ++i;
+            }
+            return value;
+        }
+
+        public static void AddRawParameters(ref string arguments, Dictionary<string, string> parameters, string switchName)
+        {
+            if (parameters.Count > 0)
+            {
+                if (!string.IsNullOrEmpty(arguments))
+                {
+                    arguments += " ";
+                }
+                arguments += switchName;
+                foreach (KeyValuePair<string, string> rawSetting in parameters)
+                {
+                    arguments += string.Format(CultureInfo.InvariantCulture, " {0}=\"{1}\"", rawSetting.Key, ArgumentEscape(rawSetting.Value));
+                }
+            }
+        }
     }
 }

+ 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
 [assembly: Guid("a0b93468-d98a-4845-a234-8076229ad93f")]
 
-[assembly: AssemblyVersion("1.2.2.0")]
-[assembly: AssemblyFileVersion("1.2.2.0")]
-[assembly: AssemblyInformationalVersionAttribute("5.6.2.0")]
+[assembly: AssemblyVersion("1.2.3.0")]
+[assembly: AssemblyFileVersion("1.2.3.0")]
+[assembly: AssemblyInformationalVersionAttribute("5.6.3.0")]
 
 [assembly: CLSCompliant(true)]
 

+ 0 - 2
libs/openssl/ssl/s23_pkt.c

@@ -81,7 +81,6 @@ int ssl23_write_bytes(SSL *s)
 			s->init_num=num;
 			return(i);
 			}
-			SSL_TRACE_BYTES(s, &(buf[tot]),i, "write: ");
 		s->rwstate=SSL_NOTHING;
 		if (i == num) return(tot+i);
 
@@ -108,7 +107,6 @@ int ssl23_read_bytes(SSL *s, int n)
 			if (j <= 0)
 				return(j);
 			s->rwstate=SSL_NOTHING;
-			SSL_TRACE_BYTES(s, (char *)&(p[s->packet_length]),j, "read: ");
 			s->packet_length+=j;
 			if (s->packet_length >= (unsigned int)n)
 				return(s->packet_length);

+ 0 - 40
libs/openssl/ssl/ssl.h

@@ -2599,46 +2599,6 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_X509_LIB					 268
 #define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS		 269
 
-#if 0
-
-#define SSL_TRACE(s, str) \
-	{ \
-	void (*ssl_trace_cb)(const SSL *ssl,int type,int val)=NULL; \
-	if ((s)->info_callback != NULL) \
-		ssl_trace_cb=(s)->info_callback; \
-	else if ((s)->ctx->info_callback != NULL) \
-		ssl_trace_cb=(s)->ctx->info_callback; \
-	if (ssl_trace_cb != NULL) \
-		{ \
-		char* ssl_trace_buf = CRYPTO_malloc((strlen(__FILE__) + strlen(__FUNC__) + strlen(str) + 100), __FILE__, __LINE__); \
-		sprintf(ssl_trace_buf, "[%s:%s:%d] %s", __FILE__, __FUNC__, __LINE__, str); \
-		ssl_trace_cb((s),SSL_CB_LOOP,(int)ssl_trace_buf); \
-		} \
-	}
-
-#define SSL_TRACE_BYTES(s, data, len, prefix) \
-	{ \
-	if (((s)->info_callback != NULL) || ((s)->ctx->info_callback != NULL)) \
-		{ \
-		char* ssl_trace_bytes_buf = OPENSSL_malloc(strlen(prefix) + ((len)*3) + 100); \
-		int ssl_trace_i; \
-		strcpy(ssl_trace_bytes_buf, (prefix)); \
-		for (ssl_trace_i = 0; ssl_trace_i < (len); ssl_trace_i++) \
-			{ \
-			sprintf(ssl_trace_bytes_buf + strlen(ssl_trace_bytes_buf), "%2.2x ", (unsigned char)((data)[ssl_trace_i])); \
-			} \
-		SSL_TRACE((s),ssl_trace_bytes_buf); \
-		OPENSSL_free(ssl_trace_bytes_buf); \
-		} \
-	}
-
-#else
-
-#define SSL_TRACE(s, str)
-#define SSL_TRACE_BYTES(s, data, len, prefix)
-
-#endif
-
 #ifdef  __cplusplus
 }
 #endif

+ 1 - 1
source/Console.cbproj

@@ -65,7 +65,7 @@
 			<ProjectType>CppConsoleApplication</ProjectType>
 			<SanitizedProjectName>Console</SanitizedProjectName>
 			<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-2014 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.6.2.0;ReleaseType=beta;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-2014 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.6.3.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>4</VerInfo_MajorVer>
 			<VerInfo_MinorVer>1</VerInfo_MinorVer>

+ 1 - 1
source/DragExt.cbproj

@@ -66,7 +66,7 @@
 			<SanitizedProjectName>DragExt</SanitizedProjectName>
 			<VerInfo_DLL>true</VerInfo_DLL>
 			<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-2014 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.6.2.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP (32-bit);FileVersion=1.2.1.0;InternalName=dragext32;LegalCopyright=(c) 2000-2014 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.6.3.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
 			<VerInfo_Release>1</VerInfo_Release>

+ 2 - 2
source/DragExt64.rc

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

+ 2 - 2
source/WinSCP.cbproj

@@ -83,11 +83,11 @@
 			<SanitizedProjectName>WinSCP</SanitizedProjectName>
 			<UsingDelphiRTL>true</UsingDelphiRTL>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP and SCP client;FileVersion=5.6.2.0;InternalName=winscp;LegalCopyright=(c) 2000-2014 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.6.2.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP and SCP client;FileVersion=5.6.3.0;InternalName=winscp;LegalCopyright=(c) 2000-2014 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.6.3.0;ReleaseType=beta;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>5</VerInfo_MajorVer>
 			<VerInfo_MinorVer>6</VerInfo_MinorVer>
-			<VerInfo_Release>2</VerInfo_Release>
+			<VerInfo_Release>3</VerInfo_Release>
 		</PropertyGroup>
 	<PropertyGroup Condition="'$(Base_Win32)'!=''">
 			<Defines>IDE;STRICT;$(Defines)</Defines>

+ 7 - 0
source/core/Configuration.cpp

@@ -90,6 +90,7 @@ void __fastcall TConfiguration::Default()
   FLogFileName = DefaultLogFileName;
   FPermanentLogFileName = FLogFileName;
   FLogFileAppend = true;
+  FLogSensitive = false;
   FLogWindowLines = 100;
   FLogProtocol = 0;
   UpdateActualLogProtocol();
@@ -197,6 +198,7 @@ UnicodeString __fastcall TConfiguration::PropertyToKey(const UnicodeString & Pro
     KEYEX(Bool,  PermanentLogging, L"Logging"); \
     KEYEX(String,PermanentLogFileName, L"LogFileName"); \
     KEY(Bool,    LogFileAppend); \
+    KEY(Bool,    LogSensitive); \
     KEY(Integer, LogWindowLines); \
     KEY(Integer, LogProtocol); \
     KEYEX(Bool,  PermanentLogActions, L"LogActions"); \
@@ -1254,6 +1256,11 @@ void __fastcall TConfiguration::SetLogFileAppend(bool value)
   SET_CONFIG_PROPERTY(LogFileAppend);
 }
 //---------------------------------------------------------------------
+void __fastcall TConfiguration::SetLogSensitive(bool value)
+{
+  SET_CONFIG_PROPERTY(LogSensitive);
+}
+//---------------------------------------------------------------------
 void __fastcall TConfiguration::SetLogWindowLines(int value)
 {
   SET_CONFIG_PROPERTY(LogWindowLines);

+ 3 - 0
source/core/Configuration.h

@@ -31,6 +31,7 @@ private:
   UnicodeString FPermanentLogFileName;
   int FLogWindowLines;
   bool FLogFileAppend;
+  bool FLogSensitive;
   int FLogProtocol;
   int FActualLogProtocol;
   bool FLogActions;
@@ -87,6 +88,7 @@ private:
   void __fastcall SetLogWindowComplete(bool value);
   bool __fastcall GetLogWindowComplete();
   void __fastcall SetLogFileAppend(bool value);
+  void __fastcall SetLogSensitive(bool value);
   void __fastcall SetLogProtocol(int value);
   void __fastcall SetLogActions(bool value);
   void __fastcall SetActionsLogFileName(UnicodeString value);
@@ -217,6 +219,7 @@ public:
   __property UnicodeString LogFileName  = { read=FLogFileName, write=SetLogFileName };
   __property bool LogToFile  = { read=GetLogToFile };
   __property bool LogFileAppend  = { read=FLogFileAppend, write=SetLogFileAppend };
+  __property bool LogSensitive  = { read=FLogSensitive, write=SetLogSensitive };
   __property int LogProtocol  = { read=FLogProtocol, write=SetLogProtocol };
   __property int ActualLogProtocol  = { read=FActualLogProtocol };
   __property bool LogActions  = { read=FLogActions, write=SetLogActions };

+ 8 - 0
source/core/FileOperationProgress.cpp

@@ -30,6 +30,14 @@ __fastcall TFileOperationProgressType::~TFileOperationProgressType()
   assert(!Suspended || FReset);
 }
 //---------------------------------------------------------------------------
+void __fastcall TFileOperationProgressType::AssignButKeepSuspendState(const TFileOperationProgressType & Other)
+{
+  TValueRestorer<unsigned int> SuspendTimeRestorer(FSuspendTime);
+  TValueRestorer<bool> SuspendedRestorer(Suspended);
+
+  *this = Other;
+}
+//---------------------------------------------------------------------------
 void __fastcall TFileOperationProgressType::Clear()
 {
   FileName = L"";

+ 1 - 0
source/core/FileOperationProgress.h

@@ -85,6 +85,7 @@ public:
   __fastcall TFileOperationProgressType(
     TFileOperationProgressEvent AOnProgress, TFileOperationFinished AOnFinished);
   __fastcall ~TFileOperationProgressType();
+  void __fastcall AssignButKeepSuspendState(const TFileOperationProgressType & Other);
   void __fastcall AddLocallyUsed(__int64 ASize);
   void __fastcall AddTransfered(__int64 ASize, bool AddToTotals = true);
   void __fastcall AddResumed(__int64 ASize);

+ 26 - 1
source/core/FtpFileSystem.cpp

@@ -625,6 +625,14 @@ void __fastcall TFTPFileSystem::CollectUsage()
   {
     FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPPureFTPd");
   }
+  // 220 Titan FTP Server 10.47.1892 Ready.
+  // ...
+  // SYST
+  // 215 UNIX Type: L8
+  else if (ContainsText(FWelcomeMessage, "Titan FTP Server"))
+  {
+    FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPTitan");
+  }
   else
   {
     FTerminal->Configuration->Usage->Inc(L"OpenedSessionsFTPOther");
@@ -1362,6 +1370,8 @@ void __fastcall TFTPFileSystem::Sink(const UnicodeString FileName,
       }
       FILE_OPERATION_LOOP_END(FMTLOAD(CANT_SET_ATTRS, (DestFullName)));
     }
+
+    FTerminal->LogFileDone(OperationProgress);
   }
 
   if (FLAGSET(Params, cpDelete))
@@ -1605,6 +1615,8 @@ void __fastcall TFTPFileSystem::Source(const UnicodeString FileName,
     {
       TTouchSessionAction TouchAction(FTerminal->ActionLog, DestFullName, Modification);
     }
+
+    FTerminal->LogFileDone(OperationProgress);
   }
 
   /* TODO : Delete also read-only files. */
@@ -2571,6 +2583,10 @@ int __fastcall TFTPFileSystem::GetOptionVal(int OptionID) const
       Result = FFileTransferRemoveBOM ? TRUE : FALSE;
       break;
 
+    case OPTION_MPEXT_LOG_SENSITIVE:
+      Result = FTerminal->Configuration->LogSensitive ? TRUE : FALSE;
+      break;
+
     default:
       FAIL;
       Result = FALSE;
@@ -2636,7 +2652,13 @@ void __fastcall TFTPFileSystem::DiscardMessages()
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::WaitForMessages()
 {
-  unsigned int Result = WaitForSingleObject(FQueueEvent, INFINITE);
+  unsigned int Result;
+  do
+  {
+    Result = WaitForSingleObject(FQueueEvent, GUIUpdateInterval);
+    ProcessGUI();
+  } while (Result == WAIT_TIMEOUT);
+
   if (Result != WAIT_OBJECT_0)
   {
     FTerminal->FatalError(NULL, FMTLOAD(INTERNAL_ERROR, (L"ftp#1", IntToStr(int(Result)))));
@@ -3149,6 +3171,9 @@ bool __fastcall TFTPFileSystem::HandleStatus(const wchar_t * AStatus, int Type)
     case TFileZillaIntf::LOG_COMMAND:
       if (Status == L"SYST")
       {
+        // not to trigger the assert in HandleReplyStatus,
+        // when SYST command is used by the user
+        FSystem = "";
         FLastCommand = SYST;
       }
       else if (Status == L"FEAT")

+ 2 - 0
source/core/Interface.h

@@ -15,6 +15,8 @@ UnicodeString __fastcall GetCompanyRegistryKey();
 UnicodeString __fastcall GetRegistryKey();
 void * __fastcall BusyStart();
 void __fastcall BusyEnd(void * Token);
+const unsigned int GUIUpdateInterval = 200;
+bool __fastcall ProcessGUI(bool Force = false);
 UnicodeString __fastcall AppNameString();
 UnicodeString __fastcall SshVersionString();
 void __fastcall CopyToClipboard(UnicodeString Text);

+ 4 - 0
source/core/ScpFileSystem.cpp

@@ -1934,6 +1934,8 @@ void __fastcall TSCPFileSystem::SCPSource(const UnicodeString FileName,
         TChmodSessionAction(FTerminal->ActionLog, AbsoluteFileName,
           Rights);
       }
+
+      FTerminal->LogFileDone(OperationProgress);
     }
   }
   __finally
@@ -2626,6 +2628,8 @@ void __fastcall TSCPFileSystem::SCPSink(const UnicodeString TargetDir,
             }
             FILE_OPERATION_LOOP_END(FMTLOAD(CANT_SET_ATTRS, (DestFileName)));
           }
+
+          FTerminal->LogFileDone(OperationProgress);
         }
       }
     }

+ 77 - 55
source/core/Script.cpp

@@ -352,13 +352,13 @@ void __fastcall TScript::Init()
   FCommands->Register(L"!", 0, SCRIPT_CALL_HELP2, &CallProc, 1, -1, false);
   FCommands->Register(L"pwd", SCRIPT_PWD_DESC, SCRIPT_PWD_HELP, &PwdProc, 0, 0, false);
   FCommands->Register(L"cd", SCRIPT_CD_DESC, SCRIPT_CD_HELP, &CdProc, 0, 1, false);
-  FCommands->Register(L"ls", SCRIPT_LS_DESC, SCRIPT_LS_HELP, &LsProc, 0, 1, false);
-  FCommands->Register(L"dir", 0, SCRIPT_LS_HELP, &LsProc, 0, 1, false);
-  FCommands->Register(L"rm", SCRIPT_RM_DESC, SCRIPT_RM_HELP, &RmProc, 1, -1, false);
+  FCommands->Register(L"ls", SCRIPT_LS_DESC, SCRIPT_LS_HELP2, &LsProc, 0, 1, false);
+  FCommands->Register(L"dir", 0, SCRIPT_LS_HELP2, &LsProc, 0, 1, false);
+  FCommands->Register(L"rm", SCRIPT_RM_DESC, SCRIPT_RM_HELP2, &RmProc, 1, -1, false);
   FCommands->Register(L"rmdir", SCRIPT_RMDIR_DESC, SCRIPT_RMDIR_HELP, &RmDirProc, 1, -1, false);
-  FCommands->Register(L"mv", SCRIPT_MV_DESC, SCRIPT_MV_HELP, &MvProc, 2, -1, false);
-  FCommands->Register(L"rename", 0, SCRIPT_MV_HELP, &MvProc, 2, -1, false);
-  FCommands->Register(L"chmod", SCRIPT_CHMOD_DESC, SCRIPT_CHMOD_HELP, &ChModProc, 2, -1, false);
+  FCommands->Register(L"mv", SCRIPT_MV_DESC, SCRIPT_MV_HELP2, &MvProc, 2, -1, false);
+  FCommands->Register(L"rename", 0, SCRIPT_MV_HELP2, &MvProc, 2, -1, false);
+  FCommands->Register(L"chmod", SCRIPT_CHMOD_DESC, SCRIPT_CHMOD_HELP2, &ChModProc, 2, -1, false);
   FCommands->Register(L"ln", SCRIPT_LN_DESC, SCRIPT_LN_HELP, &LnProc, 2, 2, false);
   FCommands->Register(L"symlink", 0, SCRIPT_LN_HELP, &LnProc, 2, 2, false);
   FCommands->Register(L"mkdir", SCRIPT_MKDIR_DESC, SCRIPT_MKDIR_HELP, &MkDirProc, 1, 1, false);
@@ -701,14 +701,7 @@ TStrings * __fastcall TScript::CreateLocalFileList(TScriptProcParams * Parameter
           }
           else
           {
-            int LastError = GetLastError();
-            // System error text for ERROR_FILE_NOT_FOUND is more or less redundant to ours
-            // SCRIPT_MATCH_NO_MATCH. Also the system error does not look nice/user friendly
-            // so avoid using it for this frequent case.
-            if (LastError != ERROR_FILE_NOT_FOUND)
-            {
-              Error = SysErrorMessageForError(LastError);
-            }
+            Error = ListingSysErrorMessage();
           }
         }
 
@@ -731,6 +724,20 @@ TStrings * __fastcall TScript::CreateLocalFileList(TScriptProcParams * Parameter
   return Result;
 }
 //---------------------------------------------------------------------------
+UnicodeString __fastcall TScript::ListingSysErrorMessage()
+{
+  UnicodeString Result;
+  int LastError = GetLastError();
+  // System error text for ERROR_FILE_NOT_FOUND is more or less redundant to ours
+  // SCRIPT_MATCH_NO_MATCH. Also the system error does not look nice/user friendly
+  // so avoid using it for this frequent case.
+  if (LastError != ERROR_FILE_NOT_FOUND)
+  {
+    Result = SysErrorMessageForError(LastError);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall TScript::NoMatch(const UnicodeString & Mask, const UnicodeString & Error)
 {
   UnicodeString Message = FMTLOAD(SCRIPT_MATCH_NO_MATCH, (Mask));
@@ -1088,11 +1095,13 @@ void __fastcall TScript::LsProc(TScriptProcParams * Parameters)
 
   UnicodeString Directory;
   TFileMasks Mask;
+  bool HaveMask = false;
   if (Parameters->ParamCount > 0)
   {
     Directory = Parameters->Param[1];
     UnicodeString MaskStr = UnixExtractFileName(Directory);
-    if (TFileMasks::IsMask(MaskStr))
+    HaveMask = TFileMasks::IsMask(MaskStr);
+    if (HaveMask)
     {
       Mask.SetMask(MaskStr);
       Directory = UnixExtractFilePath(Directory);
@@ -1110,9 +1119,19 @@ void __fastcall TScript::LsProc(TScriptProcParams * Parameters)
   {
     try
     {
-      for (int i = 0; i < FileList->Count; i++)
+      if (FileList->Count > 0)
+      {
+        for (int i = 0; i < FileList->Count; i++)
+        {
+          PrintLine(FileList->Files[i]->ListingStr);
+        }
+      }
+      else
       {
-        PrintLine(FileList->Files[i]->ListingStr);
+        if (HaveMask)
+        {
+          NoMatch(Mask.Masks, UnicodeString());
+        }
       }
     }
     __finally
@@ -1886,7 +1905,7 @@ __fastcall TManagementScript::TManagementScript(TStoredSessionList * StoredSessi
   FCommands->Register(L"session", SCRIPT_SESSION_DESC, SCRIPT_SESSION_HELP, &SessionProc, 0, 1, false);
   FCommands->Register(L"lpwd", SCRIPT_LPWD_DESC, SCRIPT_LPWD_HELP, &LPwdProc, 0, 0, false);
   FCommands->Register(L"lcd", SCRIPT_LCD_DESC, SCRIPT_LCD_HELP, &LCdProc, 1, 1, false);
-  FCommands->Register(L"lls", SCRIPT_LLS_DESC, SCRIPT_LLS_HELP, &LLsProc, 0, 1, false);
+  FCommands->Register(L"lls", SCRIPT_LLS_DESC, SCRIPT_LLS_HELP2, &LLsProc, 0, 1, false);
 }
 //---------------------------------------------------------------------------
 __fastcall TManagementScript::~TManagementScript()
@@ -2237,7 +2256,8 @@ UnicodeString __fastcall TManagementScript::GetLogCmd(const UnicodeString & Full
   const UnicodeString & Command, const UnicodeString & Params)
 {
   UnicodeString Result = FullCommand;
-  if (SameText(FCommands->ResolveCommand(Command), L"open"))
+  if (SameText(FCommands->ResolveCommand(Command), L"open") &&
+      !Configuration->LogSensitive)
   {
     UnicodeString AParams = Params;
     std::unique_ptr<TScriptProcParams> Parameters(new TScriptProcParams(L""));
@@ -2531,54 +2551,56 @@ void __fastcall TManagementScript::LLsProc(TScriptProcParams * Parameters)
   int FindAttrs = faReadOnly | faHidden | faSysFile | faDirectory | faArchive;
   if (FindFirstUnchecked(IncludeTrailingBackslash(Directory) + Mask, FindAttrs, SearchRec) != 0)
   {
-    throw EOSExtException(FMTLOAD(LIST_DIR_ERROR, (Directory)));
+    NoMatch(Mask, ListingSysErrorMessage());
   }
-
-  try
+  else
   {
-    UnicodeString TimeFormat = FixedLenDateTimeFormat(FormatSettings.ShortTimeFormat);
-    UnicodeString DateFormat = FixedLenDateTimeFormat(FormatSettings.ShortDateFormat);
-    int DateLen = 0;
-    int TimeLen = 0;
-    bool First = true;
-
-    do
+    try
     {
-      if (SearchRec.Name != L".")
+      UnicodeString TimeFormat = FixedLenDateTimeFormat(FormatSettings.ShortTimeFormat);
+      UnicodeString DateFormat = FixedLenDateTimeFormat(FormatSettings.ShortDateFormat);
+      int DateLen = 0;
+      int TimeLen = 0;
+      bool First = true;
+
+      do
       {
-        TDateTime DateTime = SearchRec.TimeStamp;
-        UnicodeString TimeStr = FormatDateTime(TimeFormat, DateTime);
-        UnicodeString DateStr = FormatDateTime(DateFormat, DateTime);
-        if (First)
+        if (SearchRec.Name != L".")
         {
-          if (TimeLen < TimeStr.Length())
+          TDateTime DateTime = SearchRec.TimeStamp;
+          UnicodeString TimeStr = FormatDateTime(TimeFormat, DateTime);
+          UnicodeString DateStr = FormatDateTime(DateFormat, DateTime);
+          if (First)
           {
-            TimeLen = TimeStr.Length();
+            if (TimeLen < TimeStr.Length())
+            {
+              TimeLen = TimeStr.Length();
+            }
+            if (DateLen < DateStr.Length())
+            {
+              DateLen = DateStr.Length();
+            }
+            First = false;
           }
-          if (DateLen < DateStr.Length())
+          UnicodeString SizeStr;
+          if (FLAGSET(SearchRec.Attr, faDirectory))
           {
-            DateLen = DateStr.Length();
+            SizeStr = L"<DIR>";
           }
-          First = false;
-        }
-        UnicodeString SizeStr;
-        if (FLAGSET(SearchRec.Attr, faDirectory))
-        {
-          SizeStr = L"<DIR>";
-        }
-        else
-        {
-          SizeStr = FORMAT(L"%14.0n", (double(SearchRec.Size)));
+          else
+          {
+            SizeStr = FORMAT(L"%14.0n", (double(SearchRec.Size)));
+          }
+          PrintLine(FORMAT(L"%-*s  %-*s    %-14s %s", (
+            DateLen, DateStr, TimeLen, TimeStr, SizeStr, SearchRec.Name)));
         }
-        PrintLine(FORMAT(L"%-*s  %-*s    %-14s %s", (
-          DateLen, DateStr, TimeLen, TimeStr, SizeStr, SearchRec.Name)));
       }
+      while (FindNextChecked(SearchRec) == 0);
+    }
+    __finally
+    {
+      FindClose(SearchRec);
     }
-    while (FindNextChecked(SearchRec) == 0);
-  }
-  __finally
-  {
-    FindClose(SearchRec);
   }
 }
 //---------------------------------------------------------------------------

+ 2 - 1
source/core/Script.h

@@ -159,6 +159,8 @@ protected:
   UnicodeString __fastcall SynchronizeFileRecord(
     const UnicodeString & RootDirectory, const TSynchronizeChecklist::TItem * Item,
     bool Local);
+  UnicodeString __fastcall ListingSysErrorMessage();
+  void __fastcall NoMatch(const UnicodeString & Mask, const UnicodeString & Error);
 
 private:
   void __fastcall Init();
@@ -170,7 +172,6 @@ private:
   bool __fastcall HasNonDefaultCopyParams();
   void __fastcall CheckDefaultSynchronizeParams();
   void __fastcall NotSupported();
-  void __fastcall NoMatch(const UnicodeString & Mask, const UnicodeString & Error);
 };
 //---------------------------------------------------------------------------
 typedef void __fastcall (__closure *TScriptInputEvent)(TScript * Script, const UnicodeString Prompt, UnicodeString & Str);

+ 12 - 2
source/core/SecureShell.cpp

@@ -815,7 +815,8 @@ bool __fastcall TSecureShell::PromptUser(bool /*ToServer*/,
 
     if (Result)
     {
-      if ((Prompts->Count >= 1) && FLAGSET(int(Prompts->Objects[0]), pupEcho))
+      if ((Prompts->Count >= 1) &&
+          (FLAGSET(int(Prompts->Objects[0]), pupEcho) || Configuration->LogSensitive))
       {
         LogEvent(FORMAT(L"Response: \"%s\"", (Results->Strings[0])));
       }
@@ -1812,7 +1813,16 @@ bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventR
       {
         Timeout = 0;
       }
-      unsigned int WaitResult = WaitForMultipleObjects(HandleCount + 1, Handles, FALSE, Timeout);
+
+      unsigned int WaitResult;
+      do
+      {
+        unsigned int TimeoutStep = std::min(GUIUpdateInterval, Timeout);
+        Timeout -= TimeoutStep;
+        WaitResult = WaitForMultipleObjects(HandleCount + 1, Handles, FALSE, TimeoutStep);
+        ProcessGUI();
+      } while ((WaitResult == WAIT_TIMEOUT) && (Timeout > 0));
+
       if (WaitResult < WAIT_OBJECT_0 + HandleCount)
       {
         if (handle_got_event(Handles[WaitResult - WAIT_OBJECT_0]))

+ 16 - 63
source/core/SessionData.cpp

@@ -18,7 +18,6 @@
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
-enum TProxyType { pxNone, pxHTTP, pxSocks, pxTelnet }; // 0.53b and older
 const wchar_t * DefaultName = L"Default Settings";
 const wchar_t CipherNames[CIPHER_COUNT][10] = {L"WARN", L"3des", L"blowfish", L"aes", L"des", L"arcfour"};
 const wchar_t KexNames[KEX_COUNT][20] = {L"WARN", L"dh-group1-sha1", L"dh-group14-sha1", L"dh-gex-sha1", L"rsa" };
@@ -77,7 +76,6 @@ void __fastcall TSessionData::Default()
   UserName = L"";
   Password = L"";
   PingInterval = 30;
-  // when changing default, update load/save logic
   PingType = ptOff;
   Timeout = 15;
   TryAgent = true;
@@ -459,7 +457,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool & Rewr
   {
     PingInterval = 30;
   }
-  PingType = static_cast<TPingType>(Storage->ReadInteger(L"PingType", ptOff));
+  PingType = static_cast<TPingType>(Storage->ReadInteger(L"PingType", PingType));
   Timeout = Storage->ReadInteger(L"Timeout", Timeout);
   TryAgent = Storage->ReadBool(L"TryAgent", TryAgent);
   AgentFwd = Storage->ReadBool(L"AgentFwd", AgentFwd);
@@ -523,28 +521,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool & Rewr
   SendBuf = Storage->ReadInteger(L"SendBuf", Storage->ReadInteger("SshSendBuf", SendBuf));
   SshSimple = Storage->ReadBool(L"SshSimple", SshSimple);
 
-  ProxyMethod = (TProxyMethod)Storage->ReadInteger(L"ProxyMethod", -1);
-  if (ProxyMethod < 0)
-  {
-    int ProxyType = Storage->ReadInteger(L"ProxyType", pxNone);
-    int ProxySOCKSVersion;
-    switch (ProxyType) {
-      case pxHTTP:
-        ProxyMethod = pmHTTP;
-        break;
-      case pxTelnet:
-        ProxyMethod = pmTelnet;
-        break;
-      case pxSocks:
-        ProxySOCKSVersion = Storage->ReadInteger(L"ProxySOCKSVersion", 5);
-        ProxyMethod = ProxySOCKSVersion == 5 ? pmSocks5 : pmSocks4;
-        break;
-      default:
-      case pxNone:
-        ProxyMethod = ::pmNone;
-        break;
-    }
-  }
+  ProxyMethod = (TProxyMethod)Storage->ReadInteger(L"ProxyMethod", ProxyMethod);
   ProxyHost = Storage->ReadString(L"ProxyHost", ProxyHost);
   ProxyPort = Storage->ReadInteger(L"ProxyPort", ProxyPort);
   ProxyUsername = Storage->ReadString(L"ProxyUsername", ProxyUsername);
@@ -822,39 +799,6 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
     }
 
     WRITE_DATA(Integer, ProxyMethod);
-    if (PuttyExport)
-    {
-      // support for Putty 0.53b and older
-      int ProxyType;
-      int ProxySOCKSVersion = 5;
-      switch (ProxyMethod) {
-        case pmHTTP:
-          ProxyType = pxHTTP;
-          break;
-        case pmTelnet:
-          ProxyType = pxTelnet;
-          break;
-        case pmSocks5:
-          ProxyType = pxSocks;
-          ProxySOCKSVersion = 5;
-          break;
-        case pmSocks4:
-          ProxyType = pxSocks;
-          ProxySOCKSVersion = 4;
-          break;
-        default:
-        case ::pmNone:
-          ProxyType = pxNone;
-          break;
-      }
-      Storage->WriteInteger(L"ProxyType", ProxyType);
-      Storage->WriteInteger(L"ProxySOCKSVersion", ProxySOCKSVersion);
-    }
-    else
-    {
-      Storage->DeleteValue(L"ProxyType");
-      Storage->DeleteValue(L"ProxySOCKSVersion");
-    }
     WRITE_DATA(String, ProxyHost);
     WRITE_DATA(Integer, ProxyPort);
     WRITE_DATA(String, ProxyUsername);
@@ -1567,6 +1511,7 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
         PortNumber = FtpsImplicitPortNumber;
       }
     }
+    // BACKWARD COMPATIBILITY with 5.5.x
     if (Options->FindSwitch(L"explicitssl"))
     {
       bool Enabled = Options->SwitchValue(L"explicitssl", true);
@@ -1576,9 +1521,13 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
         PortNumber = FtpPortNumber;
       }
     }
-    if (Options->FindSwitch(L"explicittls", Value))
+    if (Options->FindSwitch(L"explicit") ||
+        // BACKWARD COMPATIBILITY with 5.5.x
+        Options->FindSwitch(L"explicittls"))
     {
-      bool Enabled = Options->SwitchValue(L"explicittls", true);
+      UnicodeString SwitchName =
+        Options->FindSwitch(L"explicit") ? L"explicit" : L"explicittls";
+      bool Enabled = Options->SwitchValue(SwitchName, true);
       Ftps = Enabled ? ftpsExplicitTls : ftpsNone;
       if (!PortNumberDefined && Enabled)
       {
@@ -1596,9 +1545,7 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
         if (Options->FindSwitch(L"rawsettings", RawSettings))
         {
           OptionsStorage = new TOptionsStorage(RawSettings);
-
-          bool Dummy;
-          DoLoad(OptionsStorage, Dummy);
+          ApplyRawSettings(OptionsStorage);
         }
       }
       __finally
@@ -1612,6 +1559,12 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
   return true;
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::ApplyRawSettings(THierarchicalStorage * Storage)
+{
+  bool Dummy;
+  DoLoad(Storage, Dummy);
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::ConfigureTunnel(int APortNumber)
 {
   FOrigHostName = HostName;

+ 1 - 0
source/core/SessionData.h

@@ -357,6 +357,7 @@ public:
   void __fastcall Default();
   void __fastcall NonPersistant();
   void __fastcall Load(THierarchicalStorage * Storage);
+  void __fastcall ApplyRawSettings(THierarchicalStorage * Storage);
   void __fastcall ImportFromFilezilla(_di_IXMLNode Node, const UnicodeString & Path);
   void __fastcall Save(THierarchicalStorage * Storage, bool PuttyExport,
     const TSessionData * Default = NULL);

+ 18 - 5
source/core/SessionInfo.cpp

@@ -899,6 +899,18 @@ UnicodeString __fastcall TSessionLog::GetTlsVersionName(TTlsVersion TlsVersion)
   }
 }
 //---------------------------------------------------------------------------
+UnicodeString __fastcall TSessionLog::LogSensitive(const UnicodeString & Str)
+{
+  if (FConfiguration->LogSensitive && !Str.IsEmpty())
+  {
+    return Str;
+  }
+  else
+  {
+    return BooleanToEngStr(!Str.IsEmpty());
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
 {
   TGuard Guard(FCriticalSection);
@@ -945,8 +957,8 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
       ADF(L"Session name: %s (%s)", (Data->SessionName, Data->Source));
       ADF(L"Host name: %s (Port: %d)", (Data->HostNameExpanded, Data->PortNumber));
       ADF(L"User name: %s (Password: %s, Key file: %s)",
-        (Data->UserNameExpanded, BooleanToEngStr(!Data->Password.IsEmpty()),
-         BooleanToEngStr(!Data->PublicKeyFile.IsEmpty())))
+        (Data->UserNameExpanded, LogSensitive(Data->Password),
+         LogSensitive(Data->PublicKeyFile)));
       if (Data->UsesSsh)
       {
         ADF(L"Tunnel: %s", (BooleanToEngStr(Data->Tunnel)));
@@ -954,8 +966,9 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
         {
           ADF(L"Tunnel: Host name: %s (Port: %d)", (Data->TunnelHostName, Data->TunnelPortNumber));
           ADF(L"Tunnel: User name: %s (Password: %s, Key file: %s)",
-            (Data->TunnelUserName, BooleanToEngStr(!Data->TunnelPassword.IsEmpty()),
-             BooleanToEngStr(!Data->TunnelPublicKeyFile.IsEmpty())))
+            (Data->TunnelUserName,
+             LogSensitive(Data->TunnelPassword),
+             LogSensitive(Data->TunnelPublicKeyFile)));
           ADF(L"Tunnel: Local port number: %d", (Data->TunnelLocalPortNumber));
         }
       }
@@ -986,7 +999,7 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
       {
         ADF(L"HostName: %s (Port: %d); Username: %s; Passwd: %s",
           (Data->ProxyHost, Data->ProxyPort,
-           Data->ProxyUsername, BooleanToEngStr(!Data->ProxyPassword.IsEmpty())));
+           Data->ProxyUsername, LogSensitive(Data->ProxyPassword)));
         if (Data->ProxyMethod == pmTelnet)
         {
           ADF(L"Telnet command: %s", (Data->ProxyTelnetCommand));

+ 1 - 0
source/core/SessionInfo.h

@@ -266,6 +266,7 @@ private:
   void __fastcall AddStartupInfo(bool System);
   void __fastcall DoAddStartupInfo(TSessionData * Data);
   UnicodeString __fastcall GetTlsVersionName(TTlsVersion TlsVersion);
+  UnicodeString __fastcall LogSensitive(const UnicodeString & Str);
 };
 //---------------------------------------------------------------------------
 class TActionLog

+ 4 - 0
source/core/SftpFileSystem.cpp

@@ -4835,6 +4835,8 @@ void __fastcall TSFTPFileSystem::SFTPSource(const UnicodeString FileName,
           throw;
         }
       }
+
+      FTerminal->LogFileDone(OperationProgress);
     }
   }
   __finally
@@ -5868,6 +5870,8 @@ void __fastcall TSFTPFileSystem::SFTPSink(const UnicodeString FileName,
           true, true, NULL);
       }
     }
+
+    FTerminal->LogFileDone(OperationProgress);
   }
 
   if (Params & cpDelete)

+ 11 - 1
source/core/Terminal.cpp

@@ -82,7 +82,8 @@ __fastcall TLoopDetector::TLoopDetector()
 //---------------------------------------------------------------------------
 void __fastcall TLoopDetector::RecordVisitedDirectory(const UnicodeString & Directory)
 {
-  FVisitedDirectories->Add(ExcludeTrailingBackslash(Directory));
+  UnicodeString VisitedDirectory = ExcludeTrailingBackslash(Directory);
+  FVisitedDirectories->Add(VisitedDirectory);
 }
 //---------------------------------------------------------------------------
 bool __fastcall TLoopDetector::IsUnvisitedDirectory(const TRemoteFile * File)
@@ -2589,6 +2590,15 @@ void __fastcall TTerminal::LogFileDetails(const UnicodeString & FileName, TDateT
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TTerminal::LogFileDone(TFileOperationProgressType * OperationProgress)
+{
+  // optimization
+  if (Log->Logging)
+  {
+    LogEvent(FORMAT("Transfer done: '%s' [%s]", (OperationProgress->FullFileName, IntToStr(OperationProgress->TransferedSize))));
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminal::CustomReadDirectory(TRemoteFileList * FileList)
 {
   assert(FileList);

+ 1 - 0
source/core/Terminal.h

@@ -363,6 +363,7 @@ protected:
   void __fastcall LogRemoteFile(TRemoteFile * File);
   UnicodeString __fastcall FormatFileDetailsForLog(const UnicodeString & FileName, TDateTime Modification, __int64 Size);
   void __fastcall LogFileDetails(const UnicodeString & FileName, TDateTime Modification, __int64 Size);
+  void __fastcall LogFileDone(TFileOperationProgressType * OperationProgress);
   virtual TTerminal * __fastcall GetPasswordSource();
   void __fastcall DoEndTransaction(bool Inform);
   bool  __fastcall VerifyCertificate(

+ 13 - 12
source/core/WebDAVFileSystem.cpp

@@ -230,6 +230,7 @@ void __fastcall TWebDAVFileSystem::Open()
   FCurrentDirectory = L"";
   FHasTrailingSlash = true;
   FStoredPasswordTried = false;
+  FTlsVersionStr = L"";
 
   TSessionData * Data = FTerminal->SessionData;
 
@@ -511,10 +512,9 @@ bool __fastcall TWebDAVFileSystem::GetActive()
 //---------------------------------------------------------------------------
 void __fastcall TWebDAVFileSystem::CollectUsage()
 {
-  UnicodeString TlsVersionStr = GetTlsVersionStr();
-  if (!TlsVersionStr.IsEmpty())
+  if (!FTlsVersionStr.IsEmpty())
   {
-    FTerminal->CollectTlsUsage(TlsVersionStr);
+    FTerminal->CollectTlsUsage(FTlsVersionStr);
   }
 }
 //---------------------------------------------------------------------------
@@ -1426,6 +1426,8 @@ void __fastcall TWebDAVFileSystem::Source(const UnicodeString FileName,
           throw;
         }
       }
+
+      FTerminal->LogFileDone(OperationProgress);
     }
   }
   __finally
@@ -2028,6 +2030,8 @@ void __fastcall TWebDAVFileSystem::Sink(const UnicodeString FileName,
       }
       FILE_OPERATION_LOOP_END(FMTLOAD(CANT_SET_ATTRS, (DestFullName)));
     }
+
+    FTerminal->LogFileDone(OperationProgress);
   }
 
   if (FLAGSET(Params, cpDelete))
@@ -2208,23 +2212,20 @@ bool TWebDAVFileSystem::VerifyCertificate(const TWebDAVCertificateData & Data)
   return Result;
 }
 //------------------------------------------------------------------------------
-UnicodeString __fastcall TWebDAVFileSystem::GetTlsVersionStr()
-{
-  return StrFromNeon(ne_ssl_get_version(FNeonSession));
-}
-//------------------------------------------------------------------------------
 void __fastcall TWebDAVFileSystem::CollectTLSSessionInfo()
 {
-  // see also TFTPFileSystem::Open()
-  UnicodeString TlsVersionStr = GetTlsVersionStr();
-  AddToList(FSessionInfo.SecurityProtocolName, TlsVersionStr, L", ");
+  // See also TFTPFileSystem::Open().
+  // Have to cache the value as the connection (the neon HTTP session, not "our" session)
+  // can be closed as the time we need it in CollectUsage().
+  FTlsVersionStr = StrFromNeon(ne_ssl_get_version(FNeonSession));
+  AddToList(FSessionInfo.SecurityProtocolName, FTlsVersionStr, L", ");
 
   UnicodeString Cipher = StrFromNeon(ne_ssl_get_cipher(FNeonSession));
   FSessionInfo.CSCipher = Cipher;
   FSessionInfo.SCCipher = Cipher;
 
   // see CAsyncSslSocketLayer::PrintSessionInfo()
-  FTerminal->LogEvent(FORMAT("Using %s, cipher %s", (TlsVersionStr, Cipher)));
+  FTerminal->LogEvent(FORMAT(L"Using %s, cipher %s", (FTlsVersionStr, Cipher)));
 }
 //------------------------------------------------------------------------------
 // A neon-session callback to validate the SSL certificate when the CA

+ 1 - 1
source/core/WebDAVFileSystem.h

@@ -154,6 +154,7 @@ private:
   void * FUploadBodyProviderUserData;
   UnicodeString FResponse;
   RawByteString FPassword;
+  UnicodeString FTlsVersionStr;
   enum TIgnoreAuthenticationFailure { iafNo, iafWaiting, iafPasswordFailed } FIgnoreAuthenticationFailure;
 
   void __fastcall CustomReadFile(UnicodeString FileName,
@@ -172,7 +173,6 @@ private:
   int __fastcall RenameFileInternal(const UnicodeString & FileName, const UnicodeString & NewName);
   bool __fastcall IsValidRedirect(int NeonStatus, UnicodeString & Path);
   UnicodeString __fastcall DirectoryPath(UnicodeString Path);
-  UnicodeString __fastcall GetTlsVersionStr();
 };
 //------------------------------------------------------------------------------
 void __fastcall NeonInitialize();

+ 1 - 0
source/filezilla/AsyncProxySocketLayer.cpp

@@ -911,6 +911,7 @@ void CAsyncProxySocketLayer::OnConnect(int nErrorCode)
 			return;
 		ASSERT(m_ProxyData.nProxyType!=PROXYTYPE_NOPROXY);
 		ClearBuffer();
+		DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_NOERROR, 0);
 		//Send the initial request
 		if (m_ProxyData.nProxyType==PROXYTYPE_SOCKS4 || m_ProxyData.nProxyType==PROXYTYPE_SOCKS4A)
 		{ //SOCKS4 proxy

+ 18 - 12
source/filezilla/ControlSocket.cpp

@@ -112,19 +112,22 @@ void CControlSocket::ShowStatus(UINT nID, int type) const
 
 void CControlSocket::ShowStatus(CString status, int type) const
 {
-	if ( status.Left(5)==_T("PASS ") )
+	if (!COptions::GetOptionVal(OPTION_MPEXT_LOG_SENSITIVE))
 	{
-		int len=status.GetLength()-5;
-		status=_T("PASS ");
-		for (int i=0;i<len;i++)
-			status+=_MPT("*");
-	}
-	else if ( status.Left(5)==_T("ACCT ") )
-	{
-		int len=status.GetLength()-5;
-		status=_T("ACCT ");
-		for (int i=0;i<len;i++)
-			status+=_MPT("*");
+		if ( status.Left(5)==_T("PASS ") )
+		{
+			int len=status.GetLength()-5;
+			status=_T("PASS ");
+			for (int i=0;i<len;i++)
+				status+=_MPT("*");
+		}
+		else if ( status.Left(5)==_T("ACCT ") )
+		{
+			int len=status.GetLength()-5;
+			status=_T("ACCT ");
+			for (int i=0;i<len;i++)
+				status+=_MPT("*");
+		}
 	}
 	LogMessageRaw(type, (LPCTSTR)status);
 }
@@ -231,6 +234,9 @@ int CControlSocket::OnLayerCallback(std::list<t_callbackMsg>& callbacks)
 			{
 				switch (iter->nParam1)
 				{
+				case PROXYERROR_NOERROR:
+					ShowStatus(IDS_PROXY_CONNECTED, FZ_LOG_STATUS);
+					break;
 				case PROXYERROR_NOCONN:
 					ShowStatus(IDS_ERRORMSG_PROXY_NOCONN, FZ_LOG_ERROR);
 					break;

+ 1 - 0
source/filezilla/FileZillaOpt.h

@@ -166,5 +166,6 @@
 #define OPTION_MPEXT_MAX_TLS_VERSION 1005
 #define OPTION_MPEXT_TRANSFER_ACTIVE_IMMEDIATELY 1006
 #define OPTION_MPEXT_REMOVE_BOM 1007
+#define OPTION_MPEXT_LOG_SENSITIVE 1008
 //---------------------------------------------------------------------------
 #endif // FileZillaOptH

+ 6 - 0
source/filezilla/FtpControlSocket.cpp

@@ -2411,6 +2411,12 @@ void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath pa
 
 		if (pData->bPasv)
 		{
+			CString hostname;
+			hostname.Format(L"%s:%d", pData->host, pData->port);
+			CString str;
+			str.Format(IDS_STATUSMSG_CONNECTING, hostname);
+			ShowStatus(str, FZ_LOG_STATUS);
+
 			// if PASV create the socket & initiate outbound data channel connection
 			if (!m_pTransferSocket->Connect(pData->host,pData->port))
 			{

+ 3 - 0
source/filezilla/TransferSocket.cpp

@@ -1111,6 +1111,9 @@ int CTransferSocket::OnLayerCallback(std::list<t_callbackMsg>& callbacks)
 			{
 				switch (iter->nParam1)
 				{
+				case PROXYERROR_NOERROR:
+					m_pOwner->ShowStatus(IDS_PROXY_CONNECTED, FZ_LOG_STATUS);
+					break;
 				case PROXYERROR_NOCONN:
 					m_pOwner->ShowStatus(IDS_ERRORMSG_PROXY_NOCONN, FZ_LOG_ERROR);
 					break;

+ 1 - 1
source/forms/Custom.cpp

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

+ 29 - 27
source/forms/CustomScpExplorer.cpp

@@ -454,8 +454,7 @@ bool __fastcall TCustomScpExplorerForm::CommandLineFromAnotherInstance(
     UnicodeString SessionName = Params.Param[1];
     std::unique_ptr<TObjectList> DataList(new TObjectList());
     UnicodeString DownloadFile; // unused
-    bool Url; // unused
-    GetLoginData(SessionName, &Params, DataList.get(), DownloadFile, Url);
+    GetLoginData(SessionName, &Params, DataList.get(), DownloadFile);
     if (DataList->Count > 0)
     {
       TTerminalManager * Manager = TTerminalManager::Instance();
@@ -763,6 +762,24 @@ void __fastcall TCustomScpExplorerForm::RefreshQueueItems()
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::SetTaskbarListProgressState(TBPFLAG Flags)
+{
+  FTaskbarList->SetProgressState(GetMainForm()->Handle, Flags);
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::SetTaskbarListProgressValue(TFileOperationProgressType * ProgressData)
+{
+  if (ProgressData->Operation != foCalculateSize)
+  {
+    // implies TBPF_NORMAL
+    FTaskbarList->SetProgressValue(GetMainForm()->Handle, ProgressData->OverallProgress(), 100);
+  }
+  else
+  {
+    SetTaskbarListProgressState(TBPF_INDETERMINATE);
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::SetQueueProgress()
 {
   TTerminalManager::Instance()->QueueStatusUpdated();
@@ -778,29 +795,21 @@ void __fastcall TCustomScpExplorerForm::SetQueueProgress()
             ((ProgressData = FQueueStatus->Items[FQueueStatus->DoneCount]->ProgressData) != NULL) &&
             ProgressData->InProgress)
         {
-          if (ProgressData->Operation != foCalculateSize)
-          {
-            // implies TBPF_NORMAL
-            FTaskbarList->SetProgressValue(Handle, ProgressData->OverallProgress(), 100);
-          }
-          else
-          {
-            FTaskbarList->SetProgressState(Handle, TBPF_INDETERMINATE);
-          }
+          SetTaskbarListProgressValue(ProgressData);
         }
         else
         {
-          FTaskbarList->SetProgressState(Handle, TBPF_NOPROGRESS);
+          SetTaskbarListProgressState(TBPF_NOPROGRESS);
         }
       }
       else
       {
-        FTaskbarList->SetProgressState(Handle, TBPF_INDETERMINATE);
+        SetTaskbarListProgressState(TBPF_INDETERMINATE);
       }
     }
     else
     {
-      FTaskbarList->SetProgressState(Handle, TBPF_NOPROGRESS);
+      SetTaskbarListProgressState(TBPF_NOPROGRESS);
     }
   }
 
@@ -1113,10 +1122,10 @@ void __fastcall TCustomScpExplorerForm::AddQueueItem(
     QueueItem = new TDownloadQueueItem(Terminal, FileList, TargetDirectory,
       &CopyParam, Params, SingleFile);
   }
-  AddQueueItem(Queue, QueueItem);
+  AddQueueItem(Queue, QueueItem, Terminal);
 }
 //---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::AddQueueItem(TTerminalQueue * Queue, TQueueItem * QueueItem)
+void __fastcall TCustomScpExplorerForm::AddQueueItem(TTerminalQueue * Queue, TQueueItem * QueueItem, TTerminal * Terminal)
 {
   if (Queue->IsEmpty)
   {
@@ -1235,7 +1244,7 @@ void __fastcall TCustomScpExplorerForm::FileOperationProgress(
     if (FTaskbarList != NULL)
     {
       // Actually, do not know what hides the progress once the operation finishes
-      FTaskbarList->SetProgressState(Handle, TBPF_NORMAL);
+      SetTaskbarListProgressState(TBPF_NORMAL);
     }
   }
   // operation is finished (or terminated), so we hide progress form
@@ -1261,15 +1270,7 @@ void __fastcall TCustomScpExplorerForm::FileOperationProgress(
     if (FTaskbarList != NULL)
     {
       assert(ProgressData.InProgress);
-      if (ProgressData.Operation != foCalculateSize)
-      {
-        // implies TBPF_NORMAL
-        FTaskbarList->SetProgressValue(Handle, ProgressData.OverallProgress(), 100);
-      }
-      else
-      {
-        FTaskbarList->SetProgressState(Handle, TBPF_INDETERMINATE);
-      }
+      SetTaskbarListProgressValue(&ProgressData);
     }
 
     if (FProgressForm->Cancel > ProgressData.Cancel)
@@ -2725,6 +2726,7 @@ void __fastcall TCustomScpExplorerForm::EditorAutoConfig()
         TEditorData EditorData;
         EditorData.Editor = edExternal;
         EditorData.ExternalEditor = FormatCommand(Executable, L"");
+        EditorData.DecideExternalEditorText();
 
         TEditorList EditorList;
         EditorList = *WinConfiguration->EditorList;
@@ -3027,7 +3029,7 @@ void __fastcall TCustomScpExplorerForm::ExecutedFileChanged(const UnicodeString
     TQueueItem * QueueItem = new TUploadQueueItem(Data->Terminal, FileList,
       Data->RemoteDirectory, &CopyParam, Params, true);
     QueueItem->CompleteEvent = UploadCompleteEvent;
-    AddQueueItem(Data->Queue, QueueItem);
+    AddQueueItem(Data->Queue, QueueItem, Data->Terminal);
   }
   __finally
   {

+ 3 - 1
source/forms/CustomScpExplorer.h

@@ -267,7 +267,7 @@ private:
   void __fastcall AddQueueItem(TTerminalQueue * Queue, TTransferDirection Direction,
     TStrings * FileList, const UnicodeString TargetDirectory,
     const TCopyParamType & CopyParam, int Params);
-  void __fastcall AddQueueItem(TTerminalQueue * Queue, TQueueItem * QueueItem);
+  void __fastcall AddQueueItem(TTerminalQueue * Queue, TQueueItem * QueueItem, TTerminal * Terminal);
   void __fastcall ClearTransferSourceSelection(TTransferDirection Direction);
   void __fastcall SessionsDDDragOver(int KeyState, const TPoint & Point, int & Effect);
   void __fastcall SessionsDDProcessDropped(TObject * Sender, int KeyState, const TPoint & Point, int Effect);
@@ -525,6 +525,8 @@ protected:
   bool __fastcall CanCommandLineFromAnotherInstance();
   void __fastcall SetQueueProgress();
   void __fastcall UpdateQueueLabel();
+  void __fastcall SetTaskbarListProgressState(TBPFLAG Flags);
+  void __fastcall SetTaskbarListProgressValue(TFileOperationProgressType * ProgressData);
   TTerminal * __fastcall GetSessionTabTerminal(TTabSheet * TabSheet);
   bool __fastcall SessionTabSwitched();
   void __fastcall RestoreApp();

+ 15 - 0
source/forms/EditorPreferences.cpp

@@ -90,6 +90,8 @@ void __fastcall TEditorPreferencesDialog::Init(TEditorPreferencesMode Mode, bool
     EditorInternalButton->Visible = false;
     EditorExternalButton->Visible = false;
     EditorOpenButton->Visible = false;
+    DefaultButton->Top = DefaultButton->Top - Shift;
+    DefaultButton->Left = ExternalEditorEdit->Left;
     Shift += ExternalEditorGroup->Top - MaskGroup->Top;
     MaskGroup->Visible = false;
     ExternalEditorGroup->Top = ExternalEditorGroup->Top - Shift;
@@ -175,6 +177,17 @@ void __fastcall TEditorPreferencesDialog::ExternalEditorEditExit(
     FilenameEdit->SetFocus();
     throw;
   }
+
+  DecideExternalEditorText();
+}
+//---------------------------------------------------------------------------
+void __fastcall TEditorPreferencesDialog::DecideExternalEditorText()
+{
+  if (TEditorData::DecideExternalEditorText(ExternalEditorEdit->Text))
+  {
+    ExternalEditorTextCheck->Checked = true;
+    UpdateControls();
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TEditorPreferencesDialog::ExternalEditorBrowseButtonClick(
@@ -183,6 +196,7 @@ void __fastcall TEditorPreferencesDialog::ExternalEditorBrowseButtonClick(
   BrowseForExecutable(ExternalEditorEdit,
     LoadStr(PREFERENCES_SELECT_EXTERNAL_EDITOR),
     LoadStr(EXECUTABLE_FILTER), true, false);
+  DecideExternalEditorText();
 }
 //---------------------------------------------------------------------------
 void __fastcall TEditorPreferencesDialog::HelpButtonClick(TObject * /*Sender*/)
@@ -230,5 +244,6 @@ void __fastcall TEditorPreferencesDialog::DefaultButtonClick(TObject * /*Sender*
   EditorExternalButton->Checked = true;
   ExternalEditorEdit->Text = FSystemExternalEditor;
   UpdateControls();
+  DecideExternalEditorText();
 }
 //---------------------------------------------------------------------------

+ 1 - 0
source/forms/EditorPreferences.h

@@ -45,6 +45,7 @@ public:
 
 private:
   void __fastcall UpdateControls();
+  void __fastcall DecideExternalEditorText();
 
   bool FMayRemote;
   UnicodeString FSystemExternalEditor;

+ 1 - 5
source/forms/FileSystemInfo.cpp

@@ -271,11 +271,7 @@ void __fastcall TFileSystemInfoDialog::CopyClick(TObject * Sender)
 {
   TInstantOperationVisualizer Visualizer;
 
-  TComponent * Item = dynamic_cast<TComponent *>(Sender);
-  assert(Item != NULL);
-  TPopupMenu * PopupMenu = dynamic_cast<TPopupMenu *>(Item->Owner);
-  assert(PopupMenu != NULL);
-  TListView * ListView = dynamic_cast<TListView *>(PopupMenu->PopupComponent);
+  TListView * ListView = dynamic_cast<TListView *>(GetPopupComponent(Sender));
   assert(ListView != NULL);
 
   UnicodeString Text;

+ 5 - 1
source/forms/MessageDlg.cpp

@@ -857,7 +857,11 @@ TForm * __fastcall TMessageForm::Create(const UnicodeString & Msg,
     Result->Font->Assign(Screen->MessageFont);
   }
 
-  Configuration->Usage->Set(L"ThemeMessageFontSize", Result->Font->Size);
+  // Can be possibly nul when error occurs before configuration is created
+  if (Configuration != NULL)
+  {
+    Configuration->Usage->Set(L"ThemeMessageFontSize", Result->Font->Size);
+  }
 
   // make sure we consider sizes of the monitor,
   // that is set in DoFormWindowProc(CM_SHOWINGCHANGED) later.

+ 4 - 0
source/forms/Preferences.cpp

@@ -565,6 +565,7 @@ void __fastcall TPreferencesDialog::LoadConfiguration()
     {
       LogWindowLinesEdit->AsInteger = 500;
     }
+    BOOLPROP(LogSensitive);
 
     EnableActionsLoggingCheck->Checked = Configuration->LogActions;
     ActionsLogFileNameEdit->Text = Configuration->ActionsLogFileName;
@@ -901,6 +902,7 @@ void __fastcall TPreferencesDialog::SaveConfiguration()
     {
       Configuration->LogWindowLines = LogWindowLinesEdit->AsInteger;
     }
+    BOOLPROP(LogSensitive);
 
     Configuration->LogActions = EnableActionsLoggingCheck->Checked;
     Configuration->ActionsLogFileName = ActionsLogFileNameEdit->Text;
@@ -1166,6 +1168,8 @@ void __fastcall TPreferencesDialog::UpdateControls()
     EnableControl(LogWindowLinesEdit, LogWindowLinesButton->Enabled && LogWindowLinesButton->Checked);
     EnableControl(LogWindowLinesText, LogWindowLinesEdit->Enabled);
 
+    EnableControl(LogSensitiveCheck, LogProtocolCombo->Enabled);
+
     EnableControl(ActionsLogFileNameEdit, EnableActionsLoggingCheck->Checked);
     EnableControl(ActionsLogFileNameHintText, ActionsLogFileNameEdit->Enabled);
 

+ 15 - 5
source/forms/Preferences.dfm

@@ -252,13 +252,13 @@ object PreferencesDialog: TPreferencesDialog
           Left = 8
           Top = 8
           Width = 389
-          Height = 190
+          Height = 214
           Anchors = [akLeft, akTop, akRight]
           Caption = 'Session log'
           TabOrder = 0
           DesignSize = (
             389
-            190)
+            214)
           object LogWindowLinesText: TLabel
             Left = 327
             Top = 163
@@ -401,10 +401,20 @@ object PreferencesDialog: TPreferencesDialog
             TabOrder = 0
             OnClick = ControlChange
           end
+          object LogSensitiveCheck: TCheckBox
+            Left = 16
+            Top = 187
+            Width = 359
+            Height = 17
+            Anchors = [akLeft, akTop, akRight]
+            Caption = 'Log passwor&ds and other sensitive information'
+            TabOrder = 10
+            OnClick = ControlChange
+          end
         end
         object ActionsLoggingGroup: TGroupBox
           Left = 8
-          Top = 203
+          Top = 227
           Width = 389
           Height = 86
           Anchors = [akLeft, akTop, akRight]
@@ -971,7 +981,7 @@ object PreferencesDialog: TPreferencesDialog
             Width = 129
             Height = 25
             Caption = 'Select fo&nt...'
-            TabOrder = 0
+            TabOrder = 1
             OnClick = PanelFontButtonClick
           end
           object PanelFontCheck: TCheckBox
@@ -980,7 +990,7 @@ object PreferencesDialog: TPreferencesDialog
             Width = 129
             Height = 17
             Caption = 'Use custom &font'
-            TabOrder = 1
+            TabOrder = 0
             OnClick = ControlChange
           end
         end

+ 1 - 0
source/forms/Preferences.h

@@ -300,6 +300,7 @@ __published:
   TLabel *PanelFontLabel;
   TButton *PanelFontButton;
   TCheckBox *PanelFontCheck;
+  TCheckBox *LogSensitiveCheck;
   void __fastcall FormShow(TObject *Sender);
   void __fastcall ControlChange(TObject *Sender);
   void __fastcall EditorFontButtonClick(TObject *Sender);

+ 2 - 8
source/forms/Progress.cpp

@@ -54,7 +54,6 @@ __fastcall TProgressForm::TProgressForm(TComponent * AOwner, bool AllowMoveToQue
   FMoveToQueue = false;
   FMinimizedByMe = false;
   FUpdateCounter = 0;
-  FLastUpdate = 0;
   FDeleteToRecycleBin = false;
   FReadOnly = false;
   FShowAsModalStorage = NULL;
@@ -354,7 +353,7 @@ void __fastcall TProgressForm::SetProgressData(TFileOperationProgressType & ADat
     InstantUpdate = true;
   }
 
-  FData = AData;
+  FData.AssignButKeepSuspendState(AData);
   FDataGot = true;
   if (!UpdateTimer->Enabled)
   {
@@ -373,13 +372,9 @@ void __fastcall TProgressForm::SetProgressData(TFileOperationProgressType & ADat
     UpdateControls();
     Application->ProcessMessages();
   }
-  static double UpdateInterval = static_cast<double>(OneSecond/5);  // 1/5 sec
-  if ((FUpdateCounter % 5 == 0) ||
-      (double(N) - double(FLastUpdate) > UpdateInterval))
+  if (ProcessGUI(FUpdateCounter % 5 == 0))
   {
-    FLastUpdate = N;
     FUpdateCounter = 0;
-    Application->ProcessMessages();
   }
   FUpdateCounter++;
 
@@ -412,7 +407,6 @@ void __fastcall TProgressForm::FormShow(TObject * /*Sender*/)
   {
     UpdateControls();
   }
-  FLastUpdate = 0;
 }
 //---------------------------------------------------------------------------
 void __fastcall TProgressForm::FormHide(TObject * /*Sender*/)

+ 0 - 1
source/forms/Progress.h

@@ -72,7 +72,6 @@ private:
   bool FAsciiTransferChanged;
   bool FResumeStatusChanged;
   void * FShowAsModalStorage;
-  TDateTime FLastUpdate;
   bool FDeleteToRecycleBin;
   bool FReadOnly;
   unsigned long FCPSLimit;

+ 2 - 2
source/forms/Properties.cpp

@@ -649,11 +649,11 @@ void __fastcall TPropertiesDialog::ChecksumAlgEditChange(TObject * /*Sender*/)
   UpdateControls();
 }
 //---------------------------------------------------------------------------
-void __fastcall TPropertiesDialog::CopyClick(TObject * /*Sender*/)
+void __fastcall TPropertiesDialog::CopyClick(TObject * Sender)
 {
   TInstantOperationVisualizer Visualizer;
 
-  TListView * ListView = dynamic_cast<TListView *>(ListViewMenu->PopupComponent);
+  TListView * ListView = dynamic_cast<TListView *>(GetPopupComponent(Sender));
   assert(ListView != NULL);
 
   int Count = 0;

+ 2 - 2
source/forms/SynchronizeChecklist.dfm

@@ -8,8 +8,6 @@ object SynchronizeChecklistDialog: TSynchronizeChecklistDialog
   ClientHeight = 521
   ClientWidth = 695
   Color = clBtnFace
-  Constraints.MinHeight = 350
-  Constraints.MinWidth = 380
   ParentFont = True
   Icon.Data = {
     0000010001001010000001002000680400001600000028000000100000002000
@@ -61,6 +59,7 @@ object SynchronizeChecklistDialog: TSynchronizeChecklistDialog
     Height = 501
     Align = alRight
     BevelOuter = bvNone
+    Constraints.MinHeight = 350
     TabOrder = 1
     DesignSize = (
       124
@@ -160,6 +159,7 @@ object SynchronizeChecklistDialog: TSynchronizeChecklistDialog
     Height = 501
     Align = alClient
     Checkboxes = True
+    Constraints.MinWidth = 240
     FullDrag = True
     HideSelection = False
     ReadOnly = True

+ 12 - 6
source/packages/filemng/BaseUtils.pas

@@ -186,33 +186,39 @@ end; {ExtractFileNameOnly}
 function FormatBytes(Bytes: Int64; Style: TFormatBytesStyle; UseUnitsForBytes: Boolean): string;
 var
   SizeUnit: string;
-  Value: Extended;
+  Value: Int64;
+  Order: Int64;
+  EValue: Extended;
 begin
   if (Style = fbNone) or ((Style = fbShort) and (Bytes < Int64(100*1024))) then
   begin
-    Value := Bytes;
+    Order := 1;
     if UseUnitsForBytes then
       SizeUnit := SByte;
   end
     else
   if (Style = fbKilobytes) or (Bytes < Int64(100*1024*1024)) then
   begin
-    Value := Bytes / 1024;
+    Order := 1024;
     SizeUnit := SKiloByte;
   end
     else
   if Bytes < Int64(Int64(100)*1024*1024*1024) then
   begin
-    Value := Bytes / (1024*1024);
+    Order := 1024*1024;
     SizeUnit := SMegaByte;
   end
     else
   begin
-    Value := Bytes / Int64(1024*1024*1024);
+    Order := 1024*1024*1024;
     SizeUnit := SGigaByte;
   end;
+  Value := Bytes div Order;
+  if (Bytes mod Order) > 0 then
+    Inc(Value);
 
-  Result := FormatFloat('#,##0', Ceil(Value));
+  EValue := Value;
+  Result := FormatFloat('#,##0', EValue);
   if SizeUnit <> '' then
     Result := Result + ' ' + SizeUnit;
 end;

+ 6 - 2
source/resource/Propagation.rc

@@ -1,7 +1,11 @@
 STRINGTABLE
 BEGIN
-  SHORT_DESCRIPTION, "Free SFTP, FTP, WebDAV and SCP client for Windows"
-  LONG_DESCRIPTION, "WinSCP is an open source free SFTP, FTP, WebDAV and SCP client for Windows. Its main function is secure file transfer between a local and a remote computer. Beyond this, WinSCP offers basic file manager, file synchronization functionality and scripting."
+  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_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_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
+  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."
 
   FUNCTIONS_PROTOCOLS, "Support for SFTP and SCP protocols over SSH, FTP and WebDAV protocol"
   FUNCTIONS_FILE_OPERATION, "All common operations with files"

+ 7 - 6
source/resource/TextsCore.h

@@ -12,14 +12,14 @@
 #define SCRIPT_SESSION_HELP     8
 #define SCRIPT_PWD_HELP         9
 #define SCRIPT_CD_HELP          10
-#define SCRIPT_LS_HELP          11
+#define SCRIPT_LS_HELP2         11
 #define SCRIPT_LPWD_HELP        12
 #define SCRIPT_LCD_HELP         13
-#define SCRIPT_LLS_HELP         14
-#define SCRIPT_RM_HELP          15
+#define SCRIPT_LLS_HELP2        14
+#define SCRIPT_RM_HELP2         15
 #define SCRIPT_RMDIR_HELP       16
-#define SCRIPT_MV_HELP          17
-#define SCRIPT_CHMOD_HELP       18
+#define SCRIPT_MV_HELP2         17
+#define SCRIPT_CHMOD_HELP2      18
 #define SCRIPT_LN_HELP          19
 #define SCRIPT_MKDIR_HELP       20
 #define SCRIPT_GET_HELP7        21
@@ -166,7 +166,7 @@
 #define SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED 240
 #define SFTP_STATUS_DELETE_PENDING 241
 #define SFTP_STATUS_FILE_CORRUPT 242
-#define KEY_TYPE_UNKNOWN        243
+#define KEY_TYPE_UNKNOWN2       243
 #define KEY_TYPE_UNSUPPORTED    244
 #define KEY_TYPE_DIFFERENT_SSH  245
 #define SFTP_OVERWRITE_FILE_ERROR2 246
@@ -235,6 +235,7 @@
 #define SFTP_STATUS_OWNER_INVALID 711
 #define SFTP_STATUS_GROUP_INVALID 712
 #define SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK 713
+#define KEY_TYPE_UNOPENABLE     714
 
 #define CORE_CONFIRMATION_STRINGS 300
 #define CONFIRM_PROLONG_TIMEOUT3 301

+ 2 - 1
source/resource/TextsCore1.rc

@@ -137,7 +137,7 @@ BEGIN
   SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED, "Byte range lock refused."
   SFTP_STATUS_DELETE_PENDING, "An operation was attempted on a file for which a delete operation is pending."
   SFTP_STATUS_FILE_CORRUPT, "The file is corrupt; an filesystem integrity check should be run."
-  KEY_TYPE_UNKNOWN, "File '%s' does not exist or it does not contain private key in known format."
+  KEY_TYPE_UNKNOWN2, "File '%s' does not contain private key in known format."
   KEY_TYPE_UNSUPPORTED, "**Private key file '%s' contains key in %s format. WinSCP supports only PuTTY format.**\n \nYou can use PuTTYgen tool to convert your private key file."
   KEY_TYPE_DIFFERENT_SSH, "Private key file '%s' contains key in %s format. It does not follow your preferred SSH protocol version."
   SFTP_OVERWRITE_FILE_ERROR2, "Cannot overwrite remote file '%s'.$$\n \nPress 'Delete' to delete the file and create new one instead of overwriting it.$$"
@@ -206,6 +206,7 @@ BEGIN
   SFTP_STATUS_OWNER_INVALID, "The name specified can not be assigned as an owner of a file."
   SFTP_STATUS_GROUP_INVALID, "The name specified can not be assigned as the primary group of a file."
   SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK, "The requested operation could not be completed because the specifed byte range lock has not been granted."
+  KEY_TYPE_UNOPENABLE, "Private key file '%s' does not exist or cannot be opened."
 
   CORE_CONFIRMATION_STRINGS, "CORE_CONFIRMATION"
   CONFIRM_PROLONG_TIMEOUT3, "Host is not communicating for %d seconds.\n\nWait for another %0:d seconds?"

+ 19 - 10
source/resource/TextsCore2.rc

@@ -73,8 +73,7 @@ BEGIN
     "                     (FTPS and WebDAVS only)\n"
     "  -passive=on|off    Passive mode (FTP protocol only)\n"
     "  -implicit          Implicit TLS/SSL (FTPS protocol only)\n"
-    "  -explicittls       Explicit TLS (FTPS protocol only)\n"
-    "  -explicitssl       Explicit SSL (FTPS protocol only)\n"
+    "  -explicit          Explicit TLS/SSL (FTPS protocol only)\n"
     "  -rawsettings setting1=value1 setting2=value2 ...\n"
     "                     Configures any site settings using raw format\n"
     "                     as in an INI file\n"
@@ -107,7 +106,7 @@ BEGIN
     "examples:\n"
     "  cd /home/martin\n"
     "  cd\n"
-  SCRIPT_LS_HELP,
+  SCRIPT_LS_HELP2,
     "ls [ <directory> ]/[ <wildcard> ]\n"
     "  Lists the contents of specified remote directory. If directory is \n"
     "  not specified, lists working directory.\n"
@@ -115,6 +114,8 @@ BEGIN
     "  Otherwise, all files are listed.\n"
     "alias:\n"
     "  dir\n"
+    "effective option:\n"
+    "  failonnomatch\n"
     "examples:\n"
     "  ls\n"
     "  ls *.html\n"
@@ -127,21 +128,25 @@ BEGIN
     "  Changes local working directory for all sessions.\n"
     "example:\n"
     "  lcd d:\\\n"
-  SCRIPT_LLS_HELP,
+  SCRIPT_LLS_HELP2,
     "lls [ <directory> ]\\[ <wildcard> ]\n"
     "  Lists the contents of specified local directory. If directory is \n"
     "  not specified, lists working directory.\n"
     "  When wildcard is specified, it is treated as set of files to list.\n"
     "  Otherwise, all files are listed.\n"
+    "effective option:\n"
+    "  failonnomatch\n"
     "examples:\n"
     "  lls\n"
     "  lls *.html\n"
     "  lls d:\\\n"
-  SCRIPT_RM_HELP,
+  SCRIPT_RM_HELP2,
     "rm <file> [ <file2> ... ]\n"
     "  Removes one or more remote files. If remote recycle bin is\n"
     "  configured, moves file to the bin instead of deleting it.\n"
     "  Filename can be replaced with wildcard to select multiple files.\n"
+    "effective option:\n"
+    "  failonnomatch\n"
     "examples:\n"
     "  rm index.html\n"
     "  rm index.html about.html\n"
@@ -152,7 +157,7 @@ BEGIN
     "  configured, moves directory to the bin instead of deleting it.\n"
     "example:\n"
     "  rmdir public_html\n"
-  SCRIPT_MV_HELP,
+  SCRIPT_MV_HELP2,
     "mv <file> [ <file2> ... ] [ <directory>/ ][ <newname> ]\n"
     "  Moves or renames one or more remote files. Destination directory or new\n"
     "  name or both must be specified. Destination directory must end with \n"
@@ -160,17 +165,21 @@ BEGIN
     "  Filename can be replaced with wildcard to select multiple files.\n"
     "alias:\n"
     "  rename\n"
+    "effective option:\n"
+    "  failonnomatch\n"
     "examples:\n"
     "  mv index.html public_html/\n"
     "  mv index.html about.*\n"
     "  mv index.html public_html/about.*\n"
     "  mv public_html/index.html public_html/about.html /home/martin/*.bak\n"
     "  mv *.html /home/backup/*.bak\n"
-  SCRIPT_CHMOD_HELP,
+  SCRIPT_CHMOD_HELP2,
     "chmod <mode> <file> [ <file2> ... ]\n"
     "  Changes permissions of one or more remote files. Mode can be specified\n"
     "  as three or four-digit octal number.\n"
     "  Filename can be replaced with wildcard to select multiple files.\n"
+    "effective option:\n"
+    "  failonnomatch\n"
     "examples:\n"
     "  chmod 644 index.html about.html\n"
     "  chmod 1700 /home/martin/public_html\n"
@@ -213,7 +222,7 @@ BEGIN
     "                   Possible values are 'on', 'off' or threshold\n"
     "  -neweronly       Transfer new and updated files only\n"
     "effective options:\n"
-    "  confirm, reconnecttime\n"
+    "  confirm, failonnomatch, reconnecttime\n"
     "examples:\n"
     "  get index.html\n"
     "  get -delete index.html about.html .\\\n"
@@ -248,7 +257,7 @@ BEGIN
     "                      Possible values are 'on', 'off' or threshold\n"
     "  -neweronly          Transfer new and updated files only\n"
     "effective options:\n"
-    "  confirm, reconnecttime\n"
+    "  confirm, failonnomatch, reconnecttime\n"
     "examples:\n"
     "  put index.html\n"
     "  put -delete index.html about.html ./\n"
@@ -283,7 +292,7 @@ BEGIN
     "  failonnomatch on|off\n"
     "           When 'on', commands fail when file mask matches no files.\n"
     "           When 'off', commands do nothing when file mask matches no files.\n"
-    "           Commands affected: get, put, rm, mv, chmod\n"
+    "           Commands affected: get, put, rm, mv, chmod, ls, lls\n"
     "examples:\n"
     "  option\n"
     "  option batch\n"

+ 3 - 0
source/resource/TextsFileZilla.h

@@ -656,6 +656,9 @@
 #define IDS_DIRINFO_SELECTED_DIRSANDFILEMIN 3102
 #define IDS_QUEUESTATUS_PAUSED          3103
 #define IDS_OPTIONSCAPTION_FONTNAME     3104
+#endif
+#define IDS_PROXY_CONNECTED             3201
+#if 0
 #define ID_CANCELBUTTON                 32768
 #define ID_COPYTOSITEMANAGER            32769
 #define ID_EDIT_EXPORTSETTINGS          32770

+ 5 - 0
source/resource/TextsFileZilla.rc

@@ -81,3 +81,8 @@ BEGIN
   IDS_ERRORMSG_UNKNOWNSSLERROR, "Unknown error in TLS layer"
   IDS_ERRORMSG_SSLCERTIFICATEERROR, "Could not verify TLS certificate"
 END
+
+STRINGTABLE
+BEGIN
+  IDS_PROXY_CONNECTED, "Connection with proxy established, performing handshake..."
+END

+ 6 - 2
source/resource/TextsWin.h

@@ -2,7 +2,7 @@
 #define TextsWinH
 
 #define DND_DOWNLOAD_MOVE_WARNING 1050
-#define USAGE9                  1051
+#define USAGE10                 1051
 
 #define WIN_ERROR_STRINGS       1100
 #define WARN_FATAL_ERROR        1102
@@ -54,7 +54,6 @@
 #define COPY_PARAM_DUPLICATE    1163
 #define CUSTOM_COMMAND_IMPOSSIBLE 1164
 #define EDIT_SESSION_CLOSED_RELOAD 1165
-#define UNSAFE_ACTIONS_DISABLED 1167
 #define DECRYPT_PASSWORD_ERROR  1168
 #define MASTER_PASSWORD_INCORRECT 1169
 #define MASTER_PASSWORD_DIFFERENT 1170
@@ -68,6 +67,11 @@
 #define FILEZILLA_SITE_MANAGER_NOT_FOUND 1178
 #define FILEZILLA_NO_SITES      1179
 #define PUTTY_NO_SITES          1180
+#define BATCH_SET_NO_MASK       1181
+#define BATCH_SET_NO_SETTINGS   1182
+#define BATCH_SET_NOT_CHANGED   1183
+#define BATCH_SET_CHANGED       1184
+#define BATCH_SET_SUMMARY       1185
 
 #define WIN_CONFIRMATION_STRINGS 1300
 #define CONFIRM_OVERWRITE_SESSION 1301

+ 5 - 1
source/resource/TextsWin1.rc

@@ -59,7 +59,6 @@ BEGIN
         CUSTOM_COMMAND_IMPOSSIBLE, "Custom command '%s' cannot be executed right now. Please select files for the command first."
         CUSTOM_COMMAND_AD_HOC_NAME, "Ad Hoc"
         EDIT_SESSION_CLOSED_RELOAD, "Cannot reload file '%s', the session '%s' has been already closed."
-        UNSAFE_ACTIONS_DISABLED, "Automatic actions are disabled when URL address is provided on command-line."
         DECRYPT_PASSWORD_ERROR, "The password cannot be decrypted."
         MASTER_PASSWORD_INCORRECT, "You did not enter the correct current master password."
         MASTER_PASSWORD_DIFFERENT, "New and re-entered master passwords are not the same."
@@ -73,6 +72,11 @@ BEGIN
         FILEZILLA_SITE_MANAGER_NOT_FOUND, "FileZilla site manager file not found (%s)."
         FILEZILLA_NO_SITES, "No sites found in FileZilla site manager file (%s)."
         PUTTY_NO_SITES, "No sites found in PuTTY sites registry key (%s)."
+        BATCH_SET_NO_MASK, "No site mask specified."
+        BATCH_SET_NO_SETTINGS, "No site settings specified."
+        BATCH_SET_NOT_CHANGED, "Not changed"
+        BATCH_SET_CHANGED, "Changed"
+        BATCH_SET_SUMMARY, "Found %d sites, Changed %d sites"
 
         WIN_CONFIRMATION_STRINGS, "WIN_CONFIRMATION"
         CONFIRM_OVERWRITE_SESSION, "Site with name '%s' already exists. Overwrite?"

+ 9 - 5
source/resource/TextsWin2.rc

@@ -13,7 +13,7 @@ BEGIN
 "Hint: To copy files hold down Ctrl key while dragging.\n"
 "\n"
 "Do you still want to move the files?"
-  USAGE9,
+  USAGE10,
 "WinSCP, %s\n"
 "%s\n"
 "\n"
@@ -25,12 +25,14 @@ BEGIN
 "G:%APP% [mysession] /synchronize [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] [/passive[=on|off]] /implicit|explicittls|explicitssl\n"
+"G:%APP% [mysession] [/passive[=on|off]] /implicit|explicit\n"
 "G:%APP% [mysession] [/timeout=<sec>]\n"
 "G:%APP% [mysession] [/rawsettings setting1=value1 settings2=value2 ...]\n"
 "G:%APP% [/console] [/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% [/rawconfig config1=value1 config1=value2 ...]\n"
+"B:%APP% [/batchsettings <site_mask> setting1=value1 setting2=value2 ...]\n"
 "G:%APP% /update\n"
 "B:%APP% /help\n"
 "\n"
@@ -47,6 +49,9 @@ BEGIN
 "B: /command      Executes list of script commands.\n"
 "B: /parameter    Passes list of parameters to script.\n"
 "B: /ini=         Path to configuration INI-file.\n"
+"B: /rawconfig    Configures any settings using raw format as in an INI file.\n"
+"B: /batchsettings Updates settings of sites matching a mask using a raw format\n"
+"B:               as in an INI file.\n"
 "B: /log=         Turns on session logging to file.\n"
 "B: /xmllog=      Turns on XML logging to file.\n"
 "B: /xmlgroups    Group all XML log elements belonging to the same command.\n"
@@ -54,11 +59,10 @@ BEGIN
 "G: /timeout=     Server response timeout.\n"
 "G: /hostkey=     Fingerprint of server host key.\n"
 "G: /passive=     Passive mode (FTP protocol only).\n"
-"G: /rawsettings= Configures any session settings using raw format\n"
+"G: /rawsettings  Configures any session settings using raw format\n"
 "G:               as in an INI file.\n"
 "G: /implicit     Implicit TLS/SSL (FTPS protocol only).\n"
-"G: /explicittls  Explicit TLS (FTPS protocol only).\n"
-"G: /explicitssl  Explicit SSL (FTPS protocol only).\n"
+"G: /explicit     Explicit TLS/SSL (FTPS protocol only).\n"
 "G: /update       Queries application homepage for updates.\n"
 "B: /help         Prints this usage.\n"
 END

+ 95 - 40
source/windows/ConsoleRunner.cpp

@@ -9,6 +9,7 @@
 #include <Terminal.h>
 #include <PuttyTools.h>
 #include <Queue.h>
+#include <HierarchicalStorage.h>
 
 #include <Consts.hpp>
 #include <StrUtils.hpp>
@@ -1973,9 +1974,14 @@ void __fastcall LoadScriptFromFile(UnicodeString FileName, TStrings * Lines)
   Lines->LoadFromFile(FileName);
 }
 //---------------------------------------------------------------------------
+void __fastcall ConsolePrintLine(TConsole * Console, const UnicodeString & Str)
+{
+  Console->Print(Str + L"\n");
+}
+//---------------------------------------------------------------------------
 void __fastcall Usage(TConsole * Console)
 {
-  UnicodeString Usage = LoadStr(USAGE9, 10240);
+  UnicodeString Usage = LoadStr(USAGE10, 10240);
   UnicodeString ExeBaseName = ExtractFileBaseName(Application->ExeName);
   Usage = ReplaceText(Usage, L"%APP%", ExeBaseName);
   UnicodeString Copyright =
@@ -2011,14 +2017,66 @@ void __fastcall Usage(TConsole * Console)
 
     if (Print)
     {
-      Console->Print(Line + L"\n");
+      ConsolePrintLine(Console, Line);
     }
   }
   Console->WaitBeforeExit();
 }
 //---------------------------------------------------------------------------
-int __fastcall Console(bool Help)
+void __fastcall BatchSettings(TConsole * Console, TProgramParams * Params)
 {
+  std::unique_ptr<TStrings> Arguments(new TStringList());
+  if (ALWAYS_TRUE(Params->FindSwitch(L"batchsettings", Arguments.get())))
+  {
+    if (Arguments->Count < 1)
+    {
+      ConsolePrintLine(Console, LoadStr(BATCH_SET_NO_MASK));
+    }
+    else if (Arguments->Count < 2)
+    {
+      ConsolePrintLine(Console, LoadStr(BATCH_SET_NO_SETTINGS));
+    }
+    else
+    {
+      TFileMasks Mask(Arguments->Strings[0]);
+      Arguments->Delete(0);
+
+      std::unique_ptr<TOptionsStorage> OptionsStorage(new TOptionsStorage(Arguments.get()));
+
+      int Matches = 0;
+      int Changes = 0;
+
+      for (int Index = 0; Index < StoredSessions->Count; Index++)
+      {
+        TSessionData * Data = StoredSessions->Sessions[Index];
+        if (!Data->IsWorkspace &&
+            Mask.Matches(Data->Name, false, false))
+        {
+          Matches++;
+          std::unique_ptr<TSessionData> OriginalData(new TSessionData(L""));
+          OriginalData->Assign(Data);
+          Data->ApplyRawSettings(OptionsStorage.get());
+          bool Changed = !OriginalData->IsSame(Data, false);
+          if (Changed)
+          {
+            Changes++;
+          }
+          UnicodeString StateStr = LoadStr(Changed ? BATCH_SET_CHANGED : BATCH_SET_NOT_CHANGED);
+          ConsolePrintLine(Console, FORMAT(L"%s - %s", (Data->Name, StateStr)));
+        }
+      }
+
+      StoredSessions->Save(false, true); // explicit
+      ConsolePrintLine(Console, FMTLOAD(BATCH_SET_SUMMARY, (Matches, Changes)));
+    }
+
+    Console->WaitBeforeExit();
+  }
+}
+//---------------------------------------------------------------------------
+int __fastcall Console(TConsoleMode Mode)
+{
+  assert(Mode != cmNone);
   TProgramParams * Params = TProgramParams::Instance();
   int Result = 0;
   TConsole * Console = NULL;
@@ -2033,7 +2091,7 @@ int __fastcall Console(bool Help)
       Configuration->Usage->Inc(L"ConsoleExternal");
       Console = new TExternalConsole(ConsoleInstance, Params->FindSwitch(L"nointeractiveinput"));
     }
-    else if (Params->FindSwitch(L"Console") || Help)
+    else if (Params->FindSwitch(L"Console") || (Mode != cmScripting))
     {
       Configuration->Usage->Inc(L"ConsoleOwn");
       Console = TOwnConsole::Instance();
@@ -2044,34 +2102,45 @@ int __fastcall Console(bool Help)
       Console = new TNullConsole();
     }
 
-    if (Help)
+    if (Mode == cmHelp)
     {
+      Configuration->Usage->Inc(L"UsageShown");
       Usage(Console);
     }
+    else if (Mode == cmBatchSettings)
+    {
+      if (CheckSafe(Params))
+      {
+        Configuration->Usage->Inc(L"BatchSettings");
+        BatchSettings(Console, Params);
+      }
+    }
     else
     {
       Runner = new TConsoleRunner(Console);
 
       try
       {
-        UnicodeString Value;
-        if (Params->FindSwitch(L"script", Value) && !Value.IsEmpty())
+        if (CheckSafe(Params))
         {
-          Configuration->Usage->Inc(L"ScriptFile");
-          LoadScriptFromFile(Value, ScriptCommands);
-        }
-        Params->FindSwitch(L"command", ScriptCommands);
-        if (ScriptCommands->Count > 0)
-        {
-          Configuration->Usage->Inc(L"ScriptCommands");
-        }
-        Params->FindSwitch(L"parameter", ScriptParameters);
-        if (ScriptParameters->Count > 0)
-        {
-          Configuration->Usage->Inc(L"ScriptParameters");
+          UnicodeString Value;
+          if (Params->FindSwitch(L"script", Value) && !Value.IsEmpty())
+          {
+            Configuration->Usage->Inc(L"ScriptFile");
+            LoadScriptFromFile(Value, ScriptCommands);
+          }
+          Params->FindSwitch(L"command", ScriptCommands);
+          if (ScriptCommands->Count > 0)
+          {
+            Configuration->Usage->Inc(L"ScriptCommands");
+          }
+          Params->FindSwitch(L"parameter", ScriptParameters);
+          if (ScriptParameters->Count > 0)
+          {
+            Configuration->Usage->Inc(L"ScriptParameters");
+          }
         }
 
-        bool Url = false;
         UnicodeString Session;
         if (Params->ParamCount >= 1)
         {
@@ -2079,29 +2148,15 @@ int __fastcall Console(bool Help)
         }
 
         bool DefaultsOnly;
-        delete StoredSessions->ParseUrl(Session, Params, DefaultsOnly,
-          NULL, &Url);
+        delete StoredSessions->ParseUrl(Session, Params, DefaultsOnly);
 
-        if (Url || Params->FindSwitch(L"Unsafe"))
+        UnicodeString LogFile;
+        if (Params->FindSwitch(L"Log", LogFile) && CheckSafe(Params))
         {
-          // prevent any automatic action when URL is provided on
-          // command-line (the check is duplicated in Execute())
-          if ((ScriptCommands->Count > 0) || Params->FindSwitch(L"Log") || Params->FindSwitch(L"XmlLog"))
-          {
-            Console->Print(LoadStr(UNSAFE_ACTIONS_DISABLED) + L"\n");
-          }
-          ScriptCommands->Clear();
-        }
-        else
-        {
-          UnicodeString LogFile;
-          if (Params->FindSwitch(L"Log", LogFile))
-          {
-            Configuration->Usage->Inc(L"ScriptLog");
-            Configuration->TemporaryLogging(LogFile);
-          }
-          CheckXmlLogParam(Params);
+          Configuration->Usage->Inc(L"ScriptLog");
+          Configuration->TemporaryLogging(LogFile);
         }
+        CheckXmlLogParam(Params);
 
         Result = Runner->Run(Session, Params,
           (ScriptCommands->Count > 0 ? ScriptCommands : NULL),

+ 1 - 1
source/windows/Setup.cpp

@@ -370,7 +370,7 @@ static void __fastcall RegisterAsUrlHandler(HKEY RootKey,
       Registry->OpenKey(L"open", true) &&
       Registry->OpenKey(L"command", true))
   {
-    Registry->WriteString(L"", FORMAT(L"\"%s\" /unsafe \"%%1\"", (Application->ExeName)));
+    Registry->WriteString(L"", FORMAT(L"\"%s\" %s \"%%1\"", (Application->ExeName, TProgramParams::FormatSwitch(UNSAFE_SWITCH))));
     Registry->CloseKey();
   }
   else

+ 1 - 2
source/windows/TerminalManager.cpp

@@ -1343,10 +1343,9 @@ void __fastcall TTerminalManager::OpenInPutty()
 void __fastcall TTerminalManager::NewSession(bool /*FromSite*/, const UnicodeString & SessionUrl)
 {
   UnicodeString DownloadFile; // unused
-  bool Url; // unused
   std::unique_ptr<TObjectList> DataList(new TObjectList());
 
-  GetLoginData(SessionUrl, NULL, DataList.get(), DownloadFile, Url);
+  GetLoginData(SessionUrl, NULL, DataList.get(), DownloadFile);
 
   if (DataList->Count > 0)
   {

+ 18 - 6
source/windows/Tools.cpp

@@ -927,9 +927,12 @@ static void __fastcall DoVerifyKey(
   {
     FileName = ExpandEnvironmentVariables(FileName);
     TKeyType Type = KeyType(FileName);
+    // reason _wfopen failed
+    int Error = errno;
     UnicodeString Message;
     UnicodeString HelpKeyword = HELP_LOGIN_KEY_TYPE;
     UnicodeString PuttygenPath;
+    std::unique_ptr<TStrings> MoreMessages;
     bool TryPuttygen = false;
     switch (Type)
     {
@@ -959,18 +962,27 @@ static void __fastcall DoVerifyKey(
           if ((Type == ktSSH1) !=
                 ((SshProt == ssh1only) || (SshProt == ssh1)))
           {
-            Message = FMTLOAD(KEY_TYPE_DIFFERENT_SSH,
-              (FileName, (Type == ktSSH1 ? L"SSH-1" : L"PuTTY SSH-2")));
+            Message =
+              MainInstructions(
+                FMTLOAD(KEY_TYPE_DIFFERENT_SSH,
+                  (FileName, (Type == ktSSH1 ? L"SSH-1" : L"PuTTY SSH-2"))));
           }
         }
         break;
 
+      case ktUnopenable:
+        Message = MainInstructions(FMTLOAD(KEY_TYPE_UNOPENABLE, (FileName)));
+        if (Error != ERROR_SUCCESS)
+        {
+          MoreMessages.reset(TextToStringList(SysErrorMessageForError(Error)));
+        }
+        break;
+
       default:
         FAIL;
         // fallthru
-      case ktUnopenable:
       case ktUnknown:
-        Message = FMTLOAD(KEY_TYPE_UNKNOWN, (FileName));
+        Message = MainInstructions(FMTLOAD(KEY_TYPE_UNKNOWN2, (FileName)));
         break;
     }
 
@@ -979,7 +991,7 @@ static void __fastcall DoVerifyKey(
       if (TryPuttygen)
       {
         Configuration->Usage->Inc(L"PrivateKeyConvertSuggestions");
-        if (MessageDialog(Message, qtConfirmation, qaOK | qaCancel, HelpKeyword) == qaOK)
+        if (MoreMessageDialog(Message, MoreMessages.get(), qtConfirmation, qaOK | qaCancel, HelpKeyword) == qaOK)
         {
           if (!ExecuteShell(PuttygenPath, AddPathQuotes(FileName)))
           {
@@ -991,7 +1003,7 @@ static void __fastcall DoVerifyKey(
       else
       {
         Configuration->Usage->Inc(L"PrivateKeySelectErrors");
-        if (MessageDialog(Message, qtWarning, qaIgnore | qaAbort,
+        if (MoreMessageDialog(Message, MoreMessages.get(), qtWarning, qaIgnore | qaAbort,
              HelpKeyword) == qaAbort)
         {
           Abort();

+ 26 - 5
source/windows/UserInterface.cpp

@@ -44,16 +44,20 @@ TConfiguration * __fastcall CreateConfiguration()
     {
       WinConfiguration->SetNulStorage();
     }
-    else
+    else if (CheckSafe(Params))
     {
       IniFileName = ExpandFileName(ExpandEnvironmentVariables(IniFileName));
       WinConfiguration->IniFileStorageName = IniFileName;
     }
   }
-  std::unique_ptr<TStrings> RawConfig(new TStringList());
-  if (Params->FindSwitch(L"rawconfig", RawConfig.get()))
+
+  if (CheckSafe(Params))
   {
-    WinConfiguration->OptionsStorage = RawConfig.get();
+    std::unique_ptr<TStrings> RawConfig(new TStringList());
+    if (Params->FindSwitch(L"rawconfig", RawConfig.get()))
+    {
+      WinConfiguration->OptionsStorage = RawConfig.get();
+    }
   }
 
   return WinConfiguration;
@@ -1218,7 +1222,9 @@ void __fastcall MessageWithNoHelp(const UnicodeString & Message)
 bool __fastcall CheckXmlLogParam(TProgramParams * Params)
 {
   UnicodeString LogFile;
-  bool Result = Params->FindSwitch(L"XmlLog", LogFile);
+  bool Result =
+    Params->FindSwitch(L"XmlLog", LogFile) &&
+    CheckSafe(Params);
   if (Result)
   {
     Configuration->Usage->Inc(L"ScriptXmlLog");
@@ -1226,3 +1232,18 @@ bool __fastcall CheckXmlLogParam(TProgramParams * Params)
   }
   return Result;
 }
+//---------------------------------------------------------------------------
+bool __fastcall CheckSafe(TProgramParams * Params)
+{
+  // Originally we warned when the test didn't pass,
+  // but it would actually be helping hackers, so let's be silent.
+
+  // Earlier we tested presence of any URL on command-line.
+  // That was added to prevent abusing URL handler in 3.8.2 (2006).
+  // Later in 4.0.4 (2007) an /Unsafe switch was added to URL handler registration.
+  // So by now, we can check for the switch only and
+  // do not limit user from combining URL with say
+  // /rawconfig
+
+  return !Params->FindSwitch(UNSAFE_SWITCH);
+}

+ 2 - 2
source/windows/VCLCommon.cpp

@@ -241,7 +241,7 @@ inline void __fastcall DoFormWindowProc(TCustomForm * Form, TWndMethod WndProc,
 
           // When main form is hidden, no taskbar button for it is shown and
           // this window does not become main window, so there won't be no taskbar
-          // icon created automatically (by VCL). So we force is manually here.
+          // icon created automatically (by VCL). So we force it manually here.
           // This particularly happen for all windows/dialogs of command-line
           // operations (e.g. /synchronize) after CreateScpExplorer() happens.
 
@@ -276,7 +276,7 @@ inline void __fastcall DoFormWindowProc(TCustomForm * Form, TWndMethod WndProc,
     }
 
     // Part of following code (but actually not all, TODO), has to happen
-    // for all windows when VCL main window is hidden (psrticularly the last branch).
+    // for all windows when VCL main window is hidden (particularly the last branch).
     // This is different from above brach, that should happen only for top-level visible window.
     if ((Application->MainForm == Form) ||
         // this particularly happens if error occurs while main

+ 1 - 0
source/windows/VCLCommon.h

@@ -50,6 +50,7 @@ void __fastcall CutFormToDesktop(TForm * Form);
 void __fastcall UpdateFormPosition(TCustomForm * Form, TPosition Position);
 void __fastcall ResizeForm(TCustomForm * Form, int Width, int Height);
 TComponent * __fastcall GetFormOwner();
+TForm * __fastcall GetMainForm();
 void __fastcall SetCorrectFormParent(TForm * Form);
 void __fastcall InvokeHelp(TWinControl * Control);
 void __fastcall SetFormIcons(TForm * Form, const UnicodeString & BigIconName,

+ 29 - 1
source/windows/WinConfiguration.cpp

@@ -27,7 +27,7 @@ __fastcall TEditorData::TEditorData() :
   FileMask(L"*.*"),
   Editor(edInternal),
   ExternalEditor(L""),
-  ExternalEditorText(true),
+  ExternalEditorText(false),
   SDIExternalEditor(false),
   DetectMDIExternalEditor(false)
 {
@@ -57,6 +57,33 @@ bool __fastcall TEditorData::operator==(const TEditorData & rhd) const
 }
 #undef C
 //---------------------------------------------------------------------------
+bool __fastcall TEditorData::DecideExternalEditorText(UnicodeString ExternalEditor)
+{
+  bool Result = false;
+  // By default we use default transfer mode (binary),
+  // as all reasonable 3rd party editors suppose all EOS styles.
+  // A notable exception is Windows Notepad, so here's an exception for it.
+
+  ReformatFileNameCommand(ExternalEditor);
+  UnicodeString ProgramName = ExtractProgramName(ExternalEditor);
+  // We explicitly do not use TEditorPreferences::GetDefaultExternalEditor(),
+  // as we need to expliclty refer to Notepad, even if the default external
+  // editor ever changes
+  if (SameText(ProgramName, "notepad"))
+  {
+    Result = true;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TEditorData::DecideExternalEditorText()
+{
+  if (DecideExternalEditorText(ExternalEditor))
+  {
+    ExternalEditorText = true;
+  }
+}
+//---------------------------------------------------------------------------
 __fastcall TEditorPreferences::TEditorPreferences()
 {
 }
@@ -86,6 +113,7 @@ UnicodeString __fastcall TEditorPreferences::GetDefaultExternalEditor()
 void __fastcall TEditorPreferences::LegacyDefaults()
 {
   FData.ExternalEditor = GetDefaultExternalEditor();
+  FData.DecideExternalEditorText();
 }
 //---------------------------------------------------------------------------
 UnicodeString __fastcall TEditorPreferences::ExtractExternalEditorName() const

+ 2 - 0
source/windows/WinConfiguration.h

@@ -212,6 +212,8 @@ struct TEditorData
   bool DetectMDIExternalEditor;
 
   bool __fastcall operator ==(const TEditorData & rhd) const;
+  void __fastcall DecideExternalEditorText();
+  static bool __fastcall DecideExternalEditorText(UnicodeString ExternalEditor);
 };
 //---------------------------------------------------------------------------
 #undef C

+ 35 - 0
source/windows/WinInterface.cpp

@@ -15,6 +15,7 @@
 #include <VCLCommon.h>
 #include <Glyphs.h>
 #include <PasTools.hpp>
+#include <DateUtils.hpp>
 
 #include "WinInterface.h"
 #include "CustomWinConfiguration.h"
@@ -683,6 +684,29 @@ void __fastcall BusyEnd(void * Token)
   Screen->Cursor = reinterpret_cast<TCursor>(Token);
 }
 //---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+static DWORD MainThread = 0;
+static TDateTime LastGUIUpdate = 0;
+static double GUIUpdateIntervalFrac = static_cast<double>(OneSecond/1000*GUIUpdateInterval);  // 1/5 sec
+//---------------------------------------------------------------------------
+bool __fastcall ProcessGUI(bool Force)
+{
+  assert(MainThread != 0);
+  bool Result = false;
+  if (MainThread == GetCurrentThreadId())
+  {
+    TDateTime N = Now();
+    if (Force ||
+        (double(N) - double(LastGUIUpdate) > GUIUpdateIntervalFrac))
+    {
+      LastGUIUpdate = N;
+      Application->ProcessMessages();
+      Result = true;
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall CopyParamListButton(TButton * Button)
 {
   if (!SupportsSplitButton())
@@ -988,6 +1012,16 @@ void __fastcall MenuPopup(TObject * Sender, const TPoint & MousePos, bool & Hand
   Handled = true;
 }
 //---------------------------------------------------------------------------
+TComponent * __fastcall GetPopupComponent(TObject * Sender)
+{
+  TComponent * Item = dynamic_cast<TComponent *>(Sender);
+  assert(Item != NULL);
+  TPopupMenu * PopupMenu = dynamic_cast<TPopupMenu *>(Item->Owner);
+  assert(PopupMenu != NULL);
+  assert(PopupMenu->PopupComponent != NULL);
+  return PopupMenu->PopupComponent;
+}
+//---------------------------------------------------------------------------
 void __fastcall MenuButton(TButton * Button)
 {
   Button->Images = GlyphsModule->ButtonImages;
@@ -1160,6 +1194,7 @@ void __fastcall WinInitialize()
 
   SetErrorMode(SEM_FAILCRITICALERRORS);
   OnApiPath = ::ApiPath;
+  MainThread = GetCurrentThreadId();
 
 #pragma warn -8111
 #pragma warn .8111

+ 6 - 2
source/windows/WinInterface.h

@@ -28,6 +28,7 @@ const int mpAllowContinueOnError = 0x02;
 #define JUMPLIST_SWITCH L"JumpList"
 #define DESKTOP_SWITCH L"Desktop"
 #define SEND_TO_HOOK_SWITCH L"SendToHook"
+#define UNSAFE_SWITCH L"Unsafe"
 
 struct TMessageParams
 {
@@ -74,6 +75,7 @@ void __fastcall SearchHelp(const UnicodeString & Message);
 void __fastcall MessageWithNoHelp(const UnicodeString & Message);
 
 class TProgramParams;
+bool __fastcall CheckSafe(TProgramParams * Params);
 bool __fastcall CheckXmlLogParam(TProgramParams * Params);
 
 UnicodeString __fastcall GetToolbarsLayoutStr(TComponent * OwnerComponent);
@@ -125,7 +127,7 @@ bool __fastcall DoChangeMasterPasswordDialog(UnicodeString & NewPassword);
 // windows\WinMain.cpp
 int __fastcall Execute();
 void __fastcall GetLoginData(UnicodeString SessionName, TOptions * Options,
-  TObjectList * DataList, UnicodeString & DownloadFile, bool & Url);
+  TObjectList * DataList, UnicodeString & DownloadFile);
 
 // forms\InputDlg.cpp
 struct TInputDialogData
@@ -372,7 +374,8 @@ TForm * __fastcall CreateMoreMessageDialog(const UnicodeString & Msg,
   const UnicodeString & MoreMessagesUrl, TSize MoreMessagesSize);
 
 // windows\Console.cpp
-int __fastcall Console(bool Help);
+enum TConsoleMode { cmNone, cmScripting, cmHelp, cmBatchSettings };
+int __fastcall Console(TConsoleMode Mode);
 
 // forms\EditorPreferences.cpp
 enum TEditorPreferencesMode { epmAdd, epmEdit, epmAdHoc };
@@ -406,6 +409,7 @@ void __fastcall MenuPopup(TPopupMenu * Menu, TRect Rect, TComponent * PopupCompo
 void __fastcall MenuPopup(TPopupMenu * Menu, TButton * Button);
 void __fastcall MenuPopup(TObject * Sender, const TPoint & MousePos, bool & Handled);
 void __fastcall MenuButton(TButton * Button);
+TComponent * __fastcall GetPopupComponent(TObject * Sender);
 TRect __fastcall CalculatePopupRect(TButton * Button);
 TRect __fastcall CalculatePopupRect(TControl * Control, TPoint MousePos);
 

+ 45 - 31
source/windows/WinMain.cpp

@@ -22,7 +22,7 @@
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
 void __fastcall GetLoginData(UnicodeString SessionName, TOptions * Options,
-  TObjectList * DataList, UnicodeString & DownloadFile, bool & Url)
+  TObjectList * DataList, UnicodeString & DownloadFile)
 {
   bool DefaultsOnly = false;
   bool Close = false;
@@ -36,7 +36,7 @@ void __fastcall GetLoginData(UnicodeString SessionName, TOptions * Options,
   {
     TSessionData * SessionData =
       StoredSessions->ParseUrl(SessionName, Options, DefaultsOnly,
-        &DownloadFile, &Url);
+        &DownloadFile);
     DataList->Add(SessionData);
 
     if (DataList->Count == 1)
@@ -502,11 +502,24 @@ int __fastcall Execute()
     Configuration->Usage->Inc(L"ConsoleDotNet");
   }
 
-  bool Help = Params->FindSwitch(L"help") || Params->FindSwitch(L"h") || Params->FindSwitch(L"?");
-  if (Help || Params->FindSwitch(L"Console") || Params->FindSwitch(L"script") ||
+  TConsoleMode Mode = cmNone;
+  if (Params->FindSwitch(L"Console") || Params->FindSwitch(L"script") ||
       Params->FindSwitch(L"command"))
   {
-    return Console(Help);
+    Mode = cmScripting;
+  }
+  else if (Params->FindSwitch(L"help") || Params->FindSwitch(L"h") || Params->FindSwitch(L"?"))
+  {
+    Mode = cmHelp;
+  }
+  else if (Params->FindSwitch(L"batchsettings"))
+  {
+    Mode = cmBatchSettings;
+  }
+
+  if (Mode != cmNone)
+  {
+    return Console(Mode);
   }
 
   TTerminalManager * TerminalManager = NULL;
@@ -561,31 +574,43 @@ int __fastcall Execute()
              Params->FindSwitch(L"RegisterAsUrlHandler")) // BACKWARD COMPATIBILITY
     {
       MaintenanceTask();
-      RegisterForDefaultProtocols();
+      if (CheckSafe(Params))
+      {
+        RegisterForDefaultProtocols();
+      }
     }
     else if (Params->FindSwitch(L"UnregisterForProtocols"))
     {
       MaintenanceTask();
-      UnregisterForProtocols();
+      if (CheckSafe(Params))
+      {
+        UnregisterForProtocols();
+      }
     }
     else if (Params->FindSwitch(L"AddSearchPath"))
     {
       MaintenanceTask();
-      AddSearchPath(ExtractFilePath(Application->ExeName));
+      if (CheckSafe(Params))
+      {
+        AddSearchPath(ExtractFilePath(Application->ExeName));
+      }
     }
     else if (Params->FindSwitch(L"RemoveSearchPath"))
     {
       MaintenanceTask();
-      try
-      {
-        RemoveSearchPath(ExtractFilePath(Application->ExeName));
-      }
-      catch(...)
+      if (CheckSafe(Params))
       {
-        // ignore errors
-        // (RemoveSearchPath is called always on uninstallation,
-        // even if AddSearchPath was not used, so we would get the error
-        // always for non-priviledged user)
+        try
+        {
+          RemoveSearchPath(ExtractFilePath(Application->ExeName));
+        }
+        catch(...)
+        {
+          // ignore errors
+          // (RemoveSearchPath is called always on uninstallation,
+          // even if AddSearchPath was not used, so we would get the error
+          // always for non-priviledged user)
+        }
       }
     }
     else if (Params->FindSwitch(L"ImportSitesIfAny"))
@@ -637,7 +662,7 @@ int __fastcall Execute()
 
       if (!Params->Empty)
       {
-        if (Params->FindSwitch(L"Defaults"))
+        if (Params->FindSwitch(L"Defaults") && CheckSafe(Params))
         {
           UseDefaults = true;
         }
@@ -719,26 +744,15 @@ int __fastcall Execute()
       do
       {
         Retry = false;
-        bool Url = false;
         TObjectList * DataList = new TObjectList();
-        GetLoginData(AutoStartSession, Params, DataList, DownloadFile, Url);
+        GetLoginData(AutoStartSession, Params, DataList, DownloadFile);
         // from now on, we do not support runtime locale change
         GUIConfiguration->CanApplyLocaleImmediately = false;
         try
         {
           if (DataList->Count > 0)
           {
-            if (Url || Params->FindSwitch(L"Unsafe"))
-            {
-              // prevent any automatic action when URL is provided on
-              // command-line (the check is duplicated in Console())
-              if (UseDefaults || Params->FindSwitch(L"Log") || Params->FindSwitch(L"XmlLog"))
-              {
-                MessageDialog(LoadStr(UNSAFE_ACTIONS_DISABLED), qtWarning, qaOK);
-              }
-              UseDefaults = false;
-            }
-            else
+            if (CheckSafe(Params))
             {
               UnicodeString LogFile;
               if (Params->FindSwitch(L"Log", LogFile))