Martin Prikryl %!s(int64=12) %!d(string=hai) anos
pai
achega
ba4e8b3013
Modificáronse 60 ficheiros con 510 adicións e 305 borrados
  1. BIN=BIN
      deployment/winscpsetup.ico
  2. 1 0
      deployment/winscpsetup.iss
  3. 1 1
      dotnet/properties/AssemblyInfo.cs
  4. 1 1
      source/Console.cbproj
  5. 1 1
      source/DragExt.cbproj
  6. 3 3
      source/DragExt64.rc
  7. 2 3
      source/WinSCP.cbproj
  8. 20 0
      source/core/Common.cpp
  9. 2 0
      source/core/Common.h
  10. 6 3
      source/core/Configuration.cpp
  11. 39 0
      source/core/CoreMain.cpp
  12. 6 6
      source/core/Exceptions.cpp
  13. 11 2
      source/core/FtpFileSystem.cpp
  14. 1 0
      source/core/FtpFileSystem.h
  15. 25 3
      source/core/Interface.h
  16. 16 24
      source/core/ScpFileSystem.cpp
  17. 1 1
      source/core/Script.cpp
  18. 5 3
      source/core/SecureShell.cpp
  19. 3 2
      source/core/SftpFileSystem.cpp
  20. 1 0
      source/core/SftpFileSystem.h
  21. 122 61
      source/core/Terminal.cpp
  22. 4 4
      source/core/Terminal.h
  23. 1 0
      source/core/WebDAVFileSystem.cpp
  24. 1 0
      source/filezilla/FileZillaOpt.h
  25. 2 1
      source/filezilla/TransferSocket.cpp
  26. 9 0
      source/forms/About.cpp
  27. 1 0
      source/forms/About.dfm
  28. 2 0
      source/forms/About.h
  29. 2 1
      source/forms/CopyParams.cpp
  30. 6 6
      source/forms/CopyParams.dfm
  31. 1 0
      source/forms/Custom.cpp
  32. 9 2
      source/forms/CustomScpExplorer.cpp
  33. 2 2
      source/forms/FileFind.cpp
  34. 0 6
      source/forms/FileFind.dfm
  35. 7 0
      source/forms/FileSystemInfo.cpp
  36. 17 17
      source/forms/FileSystemInfo.dfm
  37. 5 0
      source/forms/Login.cpp
  38. 1 0
      source/forms/MessageDlg.cpp
  39. 29 7
      source/forms/Preferences.cpp
  40. 5 4
      source/forms/Preferences.dfm
  41. 0 1
      source/forms/Progress.cpp
  42. 2 0
      source/forms/Properties.cpp
  43. 2 0
      source/forms/Rights.cpp
  44. 2 0
      source/forms/ScpCommander.cpp
  45. 1 1
      source/forms/SiteAdvanced.cpp
  46. 1 0
      source/forms/Synchronize.cpp
  47. 0 6
      source/forms/SynchronizeChecklist.dfm
  48. 1 1
      source/resource/TextsCore1.rc
  49. 1 1
      source/resource/TextsCore2.rc
  50. 1 1
      source/resource/TextsWin1.rc
  51. 1 0
      source/windows/ConsoleRunner.cpp
  52. 15 21
      source/windows/CustomWinConfiguration.cpp
  53. 12 11
      source/windows/Setup.cpp
  54. 3 7
      source/windows/TerminalManager.cpp
  55. 1 0
      source/windows/TerminalManager.h
  56. 12 8
      source/windows/VCLCommon.cpp
  57. 1 2
      source/windows/VCLCommon.h
  58. 48 51
      source/windows/WinConfiguration.cpp
  59. 33 30
      source/windows/WinInterface.cpp
  60. 2 0
      source/windows/WinInterface.h

BIN=BIN
deployment/winscpsetup.ico


+ 1 - 0
deployment/winscpsetup.iss

@@ -118,6 +118,7 @@ PrivilegesRequired=none
 UsePreviousLanguage=yes
 DisableProgramGroupPage=yes
 MinVersion=0,5.1
+SetupIconFile=winscpsetup.ico
 #ifdef Sign
 SignTool=sign $f "WinSCP Installer" http://winscp.net/eng/docs/installation
 #endif

+ 1 - 1
dotnet/properties/AssemblyInfo.cs

@@ -21,7 +21,7 @@ using System.Runtime.InteropServices;
 
 [assembly: AssemblyVersion("1.1.4.0")]
 [assembly: AssemblyFileVersion("1.1.4.0")]
-[assembly: AssemblyInformationalVersionAttribute("5.2.7.0")]
+[assembly: AssemblyInformationalVersionAttribute("5.5.0.0")]
 
 [assembly: CLSCompliant(true)]
 

+ 1 - 1
source/Console.cbproj

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

+ 1 - 1
source/DragExt.cbproj

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

+ 3 - 3
source/DragExt64.rc

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

+ 2 - 3
source/WinSCP.cbproj

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

+ 20 - 0
source/core/Common.cpp

@@ -290,6 +290,26 @@ UnicodeString __fastcall MainInstructions(const UnicodeString & S)
   return MainMsgTag + S + MainMsgTag;
 }
 //---------------------------------------------------------------------------
+UnicodeString __fastcall MainInstructionsFirstParagraph(const UnicodeString & S)
+{
+  // WORKAROUND, we consider it bad practice, the highlighting should better
+  // be localized (but maybe we change our mind later)
+  UnicodeString Result;
+  int Pos = S.Pos(L"\n\n");
+  // we would not be calling this on single paragraph message
+  if (ALWAYS_TRUE(Pos > 0))
+  {
+    Result =
+      MainInstructions(S.SubString(1, Pos - 1)) +
+      S.SubString(Pos, S.Length() - Pos + 1);
+  }
+  else
+  {
+    Result = MainInstructions(S);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 bool ExtractMainInstructions(UnicodeString & S, UnicodeString & MainInstructions)
 {
   bool Result = false;

+ 2 - 0
source/core/Common.h

@@ -46,6 +46,7 @@ UnicodeString DelimitStr(UnicodeString Str, UnicodeString Chars);
 UnicodeString ShellDelimitStr(UnicodeString Str, wchar_t Quote);
 UnicodeString ExceptionLogString(Exception *E);
 UnicodeString __fastcall MainInstructions(const UnicodeString & S);
+UnicodeString __fastcall MainInstructionsFirstParagraph(const UnicodeString & S);
 bool ExtractMainInstructions(UnicodeString & S, UnicodeString & MainInstructions);
 UnicodeString UnformatMessage(UnicodeString S);
 bool IsNumber(const UnicodeString Str);
@@ -180,6 +181,7 @@ private:
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 #include <assert.h>
+#define ACCESS_VIOLATION_TEST { (*((int*)NULL)) = 0; }
 #ifndef _DEBUG
 #undef assert
 #define assert(p)   ((void)0)

+ 6 - 3
source/core/Configuration.cpp

@@ -121,18 +121,20 @@ void __fastcall TConfiguration::UpdateStaticUsage()
 //---------------------------------------------------------------------------
 THierarchicalStorage * TConfiguration::CreateScpStorage(bool /*SessionList*/)
 {
+  THierarchicalStorage * Result;
   if (Storage == stRegistry)
   {
-    return new TRegistryStorage(RegistryStorageKey);
+    Result = new TRegistryStorage(RegistryStorageKey);
   }
   else if (Storage == stNul)
   {
-    return new TIniFileStorage(L"nul");
+    Result = new TIniFileStorage(L"nul");
   }
   else
   {
-    return new TIniFileStorage(IniFileStorageName);
+    Result = new TIniFileStorage(IniFileStorageName);
   }
+  return Result;
 }
 //---------------------------------------------------------------------------
 UnicodeString __fastcall TConfiguration::PropertyToKey(const UnicodeString & Property)
@@ -910,6 +912,7 @@ UnicodeString __fastcall TConfiguration::GetIniFileStorageName(bool ReadingOnly)
       }
     }
 
+    // BACKWARD COMPATIBILITY with 4.x
     if (FVirtualIniFileStorageName.IsEmpty() &&
         TPath::IsDriveRooted(IniPath))
     {

+ 39 - 0
source/core/CoreMain.cpp

@@ -9,6 +9,7 @@
 #include "Configuration.h"
 #include "PuttyIntf.h"
 #include "Cryptography.h"
+#include <DateUtils.hpp>
 #ifndef NO_FILEZILLA
 #include "FileZillaIntf.h"
 #endif
@@ -33,6 +34,7 @@ TQueryParams::TQueryParams(unsigned int AParams, UnicodeString AHelpKeyword)
   TimerEvent = NULL;
   TimerMessage = L"";
   TimerAnswers = 0;
+  TimerQueryType = static_cast<TQueryType>(-1);
   Timeout = 0;
   TimeoutAnswer = 0;
   NoBatchAnswers = 0;
@@ -130,3 +132,40 @@ void CoreMaintenanceTask()
   DontSaveRandomSeed();
 }
 //---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+__fastcall TOperationVisualizer::TOperationVisualizer(bool UseBusyCursor) :
+  FUseBusyCursor(UseBusyCursor)
+{
+  if (FUseBusyCursor)
+  {
+    FToken = BusyStart();
+  }
+}
+//---------------------------------------------------------------------------
+__fastcall TOperationVisualizer::~TOperationVisualizer()
+{
+  if (FUseBusyCursor)
+  {
+    BusyEnd(FToken);
+  }
+}
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+__fastcall TInstantOperationVisualizer::TInstantOperationVisualizer() :
+  FStart(Now())
+{
+}
+//---------------------------------------------------------------------------
+__fastcall TInstantOperationVisualizer::~TInstantOperationVisualizer()
+{
+  TDateTime Time = Now();
+  __int64 Duration = MilliSecondsBetween(Time, FStart);
+  const __int64 MinDuration = 250;
+  if (Duration < MinDuration)
+  {
+    Sleep(static_cast<unsigned int>(MinDuration - Duration));
+  }
+}
+//---------------------------------------------------------------------------
+// WORKAROUND, suppress warning about unused constants in DateUtils.hpp
+#pragma warn -8080

+ 6 - 6
source/core/Exceptions.cpp

@@ -27,7 +27,7 @@ static bool __fastcall WellKnownException(
     {
       throw EAccessViolation(E->Message);
     }
-    Message = LoadStr(ACCESS_VIOLATION_ERROR3);
+    Message = MainInstructions(LoadStr(ACCESS_VIOLATION_ERROR3));
     CounterName = L"AccessViolations";
     Clone.reset(new EAccessViolation(E->Message));
   }
@@ -42,7 +42,7 @@ static bool __fastcall WellKnownException(
     {
       throw EIntError(E->Message);
     }
-    Message = E->Message;
+    Message = MainInstructions(E->Message);
     CounterName = L"InternalExceptions";
     Clone.reset(new EIntError(E->Message));
   }
@@ -52,7 +52,7 @@ static bool __fastcall WellKnownException(
     {
       throw EExternal(E->Message);
     }
-    Message = E->Message;
+    Message = MainInstructions(E->Message);
     CounterName = L"ExternalExceptions";
     Clone.reset(new EExternal(E->Message));
   }
@@ -62,7 +62,7 @@ static bool __fastcall WellKnownException(
     {
       throw EHeapException(E->Message);
     }
-    Message = E->Message;
+    Message = MainInstructions(E->Message);
     CounterName = L"HeapExceptions";
     Clone.reset(new EHeapException(E->Message));
   }
@@ -239,7 +239,7 @@ __fastcall ExtException::ExtException(UnicodeString Msg, Exception* E, UnicodeSt
       {
         FMoreMessages = new TStringList();
       }
-      FMoreMessages->Append(Msg);
+      FMoreMessages->Append(UnformatMessage(Msg));
     }
   }
   FHelpKeyword = MergeHelpKeyword(GetExceptionHelpKeyword(E), HelpKeyword);
@@ -302,7 +302,7 @@ void __fastcall ExtException::AddMoreMessages(Exception* E)
     }
     else if (!Msg.IsEmpty())
     {
-      FMoreMessages->Insert(0, Msg);
+      FMoreMessages->Insert(0, UnformatMessage(Msg));
     }
 
     if (FMoreMessages->Count == 0)

+ 11 - 2
source/core/FtpFileSystem.cpp

@@ -1237,6 +1237,8 @@ void __fastcall TFTPFileSystem::Sink(const UnicodeString FileName,
 
       FFileTransferCPSLimit = OperationProgress->CPSLimit;
       FFileTransferPreserveTime = CopyParam->PreserveTime;
+      // not used for downloads anyway
+      FFileTransferRemoveBOM = CopyParam->RemoveBOM;
       UserData.FileName = DestFileName;
       UserData.Params = Params;
       UserData.AutoResume = FLAGSET(Flags, tfAutoResume);
@@ -1480,6 +1482,7 @@ void __fastcall TFTPFileSystem::Source(const UnicodeString FileName,
       FFileTransferCPSLimit = OperationProgress->CPSLimit;
       // not used for uploads anyway
       FFileTransferPreserveTime = CopyParam->PreserveTime;
+      FFileTransferRemoveBOM = CopyParam->RemoveBOM;
       // not used for uploads, but we get new name (if any) back in this field
       UserData.FileName = DestFileName;
       UserData.Params = Params;
@@ -1763,6 +1766,7 @@ bool __fastcall TFTPFileSystem::IsCapable(int Capability) const
     case fcAnyCommand: // but not fcShellAnyCommand
     case fcRename:
     case fcRemoteMove:
+    case fcRemoveBOMUpload:
       return true;
 
     case fcPreservingTimestampUpload:
@@ -1785,7 +1789,6 @@ bool __fastcall TFTPFileSystem::IsCapable(int Capability) const
     case fcTimestampChanging:
     case fcIgnorePermErrors:
     case fcRemoveCtrlZUpload:
-    case fcRemoveBOMUpload:
       return false;
 
     default:
@@ -2340,6 +2343,10 @@ int __fastcall TFTPFileSystem::GetOptionVal(int OptionID) const
       Result = Data->FtpTransferActiveImmediatelly;
       break;
 
+    case OPTION_MPEXT_REMOVE_BOM:
+      Result = FFileTransferRemoveBOM ? TRUE : FALSE;
+      break;
+
     default:
       assert(false);
       Result = FALSE;
@@ -2687,7 +2694,8 @@ void __fastcall TFTPFileSystem::GotReply(unsigned int Reply, unsigned int Flags,
       if (Error.IsEmpty() && (MoreMessages != NULL))
       {
         assert(MoreMessages->Count > 0);
-        Error = MoreMessages->Strings[0];
+        // bit too generic assigning of main instructions, let's see how it works
+        Error = MainInstructions(MoreMessages->Strings[0]);
         MoreMessages->Delete(0);
       }
 
@@ -3118,6 +3126,7 @@ struct TClipboardHandler
 
   void __fastcall Copy(TObject * /*Sender*/)
   {
+    TInstantOperationVisualizer Visualizer;
     CopyToClipboard(Text);
   }
 };

+ 1 - 0
source/core/FtpFileSystem.h

@@ -231,6 +231,7 @@ private:
   bool FFileTransferCancelled;
   __int64 FFileTransferResumed;
   bool FFileTransferPreserveTime;
+  bool FFileTransferRemoveBOM;
   unsigned long FFileTransferCPSLimit;
   bool FAwaitingProgress;
   TCaptureOutputEvent FOnCaptureOutput;

+ 25 - 3
source/core/Interface.h

@@ -12,7 +12,8 @@ void __fastcall ShowExtendedException(Exception * E);
 
 UnicodeString __fastcall GetCompanyRegistryKey();
 UnicodeString __fastcall GetRegistryKey();
-void __fastcall Busy(bool Start);
+void * __fastcall BusyStart();
+void __fastcall BusyEnd(void * Token);
 UnicodeString __fastcall AppNameString();
 UnicodeString __fastcall SshVersionString();
 void __fastcall CopyToClipboard(UnicodeString Text);
@@ -59,6 +60,7 @@ struct TQueryButtonAlias
 };
 
 typedef void __fastcall (__closure *TQueryParamsTimerEvent)(unsigned int & Result);
+enum TQueryType { qtConfirmation, qtWarning, qtError, qtInformation };
 
 struct TQueryParams
 {
@@ -74,14 +76,13 @@ struct TQueryParams
   TQueryParamsTimerEvent TimerEvent;
   UnicodeString TimerMessage;
   unsigned int TimerAnswers;
+  TQueryType TimerQueryType;
   unsigned int Timeout;
   unsigned int TimeoutAnswer;
   unsigned int NoBatchAnswers;
   UnicodeString HelpKeyword;
 };
 
-enum TQueryType { qtConfirmation, qtWarning, qtError, qtInformation };
-
 enum TPromptKind
 {
   pkPrompt,
@@ -105,4 +106,25 @@ typedef void __fastcall (__closure *TFileFoundEvent)
 typedef void __fastcall (__closure *TFindingFileEvent)
   (TTerminal * Terminal, const UnicodeString Directory, bool & Cancel);
 //---------------------------------------------------------------------------
+class TOperationVisualizer
+{
+public:
+  __fastcall TOperationVisualizer(bool UseBusyCursor = true);
+  __fastcall ~TOperationVisualizer();
+
+private:
+  bool FUseBusyCursor;
+  void * FToken;
+};
+//---------------------------------------------------------------------------
+class TInstantOperationVisualizer : public TOperationVisualizer
+{
+public:
+  __fastcall TInstantOperationVisualizer();
+  __fastcall ~TInstantOperationVisualizer();
+
+private:
+  TDateTime FStart;
+};
+//---------------------------------------------------------------------------
 #endif

+ 16 - 24
source/core/ScpFileSystem.cpp

@@ -646,28 +646,20 @@ void __fastcall TSCPFileSystem::ReadCommandOutput(int Params, const UnicodeStrin
 void __fastcall TSCPFileSystem::ExecCommand(const UnicodeString & Cmd, int Params,
   const UnicodeString & CmdString)
 {
-  if (Params < 0) Params = ecDefault;
-  if (FTerminal->UseBusyCursor)
+  if (Params < 0)
   {
-    Busy(true);
+    Params = ecDefault;
   }
-  try
-  {
-    SendCommand(Cmd);
 
-    int COParams = coWaitForLastLine;
-    if (Params & ecRaiseExcept) COParams |= coRaiseExcept;
-    if (Params & ecIgnoreWarnings) COParams |= coIgnoreWarnings;
-    if (Params & ecReadProgress) COParams |= coReadProgress;
-    ReadCommandOutput(COParams, &CmdString);
-  }
-  __finally
-  {
-    if (FTerminal->UseBusyCursor)
-    {
-      Busy(false);
-    }
-  }
+  TOperationVisualizer Visualizer(FTerminal->UseBusyCursor);
+
+  SendCommand(Cmd);
+
+  int COParams = coWaitForLastLine;
+  if (Params & ecRaiseExcept) COParams |= coRaiseExcept;
+  if (Params & ecIgnoreWarnings) COParams |= coIgnoreWarnings;
+  if (Params & ecReadProgress) COParams |= coReadProgress;
+  ReadCommandOutput(COParams, &CmdString);
 }
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::ExecCommand(TFSCommand Cmd, const TVarRec * args,
@@ -769,7 +761,7 @@ void __fastcall TSCPFileSystem::DetectReturnVar()
         if ((Output->Count != 1) || (StrToIntDef(Output->Strings[0], 256) > 255))
         {
           FTerminal->LogEvent(L"The response is not numerical exit code");
-          EXCEPTION;
+          Abort();
         }
       }
       catch (EFatal &E)
@@ -1768,7 +1760,7 @@ void __fastcall TSCPFileSystem::SCPSource(const UnicodeString FileName,
                 OperationProgress->AddTransfered(BlockSize);
                 if (OperationProgress->Cancel == csCancelTransfer)
                 {
-                  throw Exception(USER_TERMINATED);
+                  throw Exception(MainInstructions(LoadStr(USER_TERMINATED)));
                 }
               }
             }
@@ -1794,7 +1786,7 @@ void __fastcall TSCPFileSystem::SCPSource(const UnicodeString FileName,
           if ((OperationProgress->Cancel == csCancelTransfer) ||
               (OperationProgress->Cancel == csCancel && !OperationProgress->TransferingFile))
           {
-            throw Exception(USER_TERMINATED);
+            throw Exception(MainInstructions(LoadStr(USER_TERMINATED)));
           }
         }
         while (!OperationProgress->IsLocallyDone() || !OperationProgress->IsTransferDone());
@@ -2304,7 +2296,7 @@ void __fastcall TSCPFileSystem::SCPSink(const UnicodeString TargetDir,
         // last possibility to cancel transfer before it starts
         if (OperationProgress->Cancel)
         {
-          THROW_SKIP_FILE(NULL, LoadStr(USER_TERMINATED));
+          THROW_SKIP_FILE(NULL, MainInstructions(LoadStr(USER_TERMINATED)));
         }
 
         bool Dir = (Ctrl == L'D');
@@ -2453,7 +2445,7 @@ void __fastcall TSCPFileSystem::SCPSink(const UnicodeString TargetDir,
 
                   if (OperationProgress->Cancel == csCancelTransfer)
                   {
-                    throw Exception(USER_TERMINATED);
+                    throw Exception(MainInstructions(LoadStr(USER_TERMINATED)));
                   }
                 }
                 while (!OperationProgress->IsLocallyDone() || !

+ 1 - 1
source/core/Script.cpp

@@ -903,7 +903,7 @@ void __fastcall TScript::CallProc(TScriptProcParams * Parameters)
 {
   CheckSession();
 
-  // this is used only to log failures to open secondary shell session,
+  // this is used only to log failures to open separate shell session,
   // the actual call logging is done in TTerminal::AnyCommand
   TCallSessionAction Action(
     FTerminal->ActionLog, Parameters->ParamsStr, FTerminal->CurrentDirectory);

+ 5 - 3
source/core/SecureShell.cpp

@@ -1009,8 +1009,9 @@ unsigned int __fastcall TSecureShell::TimeoutPrompt(TQueryParamsTimerEvent PoolE
     Params.HelpKeyword = HELP_MESSAGE_HOST_IS_NOT_COMMUNICATING;
     Params.Timer = 500;
     Params.TimerEvent = PoolEvent;
-    Params.TimerMessage = FMTLOAD(TIMEOUT_STILL_WAITING3, (FSessionData->Timeout));
+    Params.TimerMessage = MainInstructionsFirstParagraph(FMTLOAD(TIMEOUT_STILL_WAITING3, (FSessionData->Timeout)));
     Params.TimerAnswers = qaAbort;
+    Params.TimerQueryType = qtInformation;
     if (FConfiguration->SessionReopenAutoStall > 0)
     {
       Params.Timeout = FConfiguration->SessionReopenAutoStall;
@@ -1087,7 +1088,7 @@ void __fastcall TSecureShell::DispatchSendBuffer(int BufSize)
           // fallthru
 
         case qaAbort:
-          FatalError(LoadStr(USER_TERMINATED));
+          FatalError(MainInstructions(LoadStr(USER_TERMINATED)));
           break;
       }
     }
@@ -1580,7 +1581,7 @@ void __fastcall TSecureShell::WaitForData()
           // fallthru
 
         case qaAbort:
-          FatalError(LoadStr(USER_TERMINATED));
+          FatalError(MainInstructions(LoadStr(USER_TERMINATED)));
           break;
       }
     }
@@ -1902,6 +1903,7 @@ struct TClipboardHandler
 
   void __fastcall Copy(TObject * /*Sender*/)
   {
+    TInstantOperationVisualizer Visualizer;
     CopyToClipboard(Text);
   }
 };

+ 3 - 2
source/core/SftpFileSystem.cpp

@@ -1956,7 +1956,7 @@ inline void __fastcall TSFTPFileSystem::BusyStart()
 {
   if (FBusy == 0 && FTerminal->UseBusyCursor && !FAvoidBusy)
   {
-    Busy(true);
+    FBusyToken = ::BusyStart();
   }
   FBusy++;
   assert(FBusy < 10);
@@ -1968,7 +1968,8 @@ inline void __fastcall TSFTPFileSystem::BusyEnd()
   FBusy--;
   if (FBusy == 0 && FTerminal->UseBusyCursor && !FAvoidBusy)
   {
-    Busy(false);
+    ::BusyEnd(FBusyToken);
+    FBusyToken = NULL;
   }
 }
 //---------------------------------------------------------------------------

+ 1 - 0
source/core/SftpFileSystem.h

@@ -95,6 +95,7 @@ protected:
   char FPreviousLoggedPacket;
   int FNotLoggedPackets;
   int FBusy;
+  void * FBusyToken;
   bool FAvoidBusy;
   TStrings * FExtensions;
   TSFTPSupport * FSupport;

+ 122 - 61
source/core/Terminal.cpp

@@ -63,6 +63,54 @@
 #define FILE_OPERATION_LOOP_EX(ALLOW_SKIP, MESSAGE, OPERATION) \
   FILE_OPERATION_LOOP_CUSTOM(this, ALLOW_SKIP, MESSAGE, OPERATION, L"")
 //---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+class TLoopDetector
+{
+public:
+  __fastcall TLoopDetector();
+  void __fastcall RecordVisitedDirectory(const UnicodeString & Directory);
+  bool __fastcall IsUnvisitedDirectory(const TRemoteFile * File);
+
+private:
+  std::auto_ptr<TStringList> FVisitedDirectories;
+};
+//---------------------------------------------------------------------------
+__fastcall TLoopDetector::TLoopDetector()
+{
+  FVisitedDirectories.reset(new TStringList());
+  FVisitedDirectories->Sorted = true;
+}
+//---------------------------------------------------------------------------
+void __fastcall TLoopDetector::RecordVisitedDirectory(const UnicodeString & Directory)
+{
+  FVisitedDirectories->Add(ExcludeTrailingBackslash(Directory));
+}
+//---------------------------------------------------------------------------
+bool __fastcall TLoopDetector::IsUnvisitedDirectory(const TRemoteFile * File)
+{
+  assert(File->IsDirectory);
+  UnicodeString Directory = UnixExcludeTrailingBackslash(File->FullFileName);
+  bool Result = (FVisitedDirectories->IndexOf(Directory) < 0);
+  if (Result)
+  {
+    if (File->IsSymLink)
+    {
+      UnicodeString BaseDirectory = UnixExtractFileDir(Directory);
+      UnicodeString SymlinkDirectory =
+        UnixExcludeTrailingBackslash(AbsolutePath(BaseDirectory, File->LinkTo));
+      Result = (FVisitedDirectories->IndexOf(SymlinkDirectory) < 0);
+    }
+  }
+
+  if (Result)
+  {
+    RecordVisitedDirectory(Directory);
+  }
+
+  return Result;
+}
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
 struct TMoveFileParams
 {
   UnicodeString Target;
@@ -75,6 +123,7 @@ struct TFilesFindParams
   TFileFoundEvent OnFileFound;
   TFindingFileEvent OnFindingFile;
   bool Cancel;
+  TLoopDetector LoopDetector;
 };
 //---------------------------------------------------------------------------
 TCalculateSizeStats::TCalculateSizeStats()
@@ -644,6 +693,9 @@ void __fastcall TTerminal::ResetConnection()
   // used to be called from Reopen(), why?
   FTunnelError = L"";
 
+  FRememberedPasswordTried = false;
+  FRememberedTunnelPasswordTried = false;
+
   if (FDirectoryChangesCache != NULL)
   {
     delete FDirectoryChangesCache;
@@ -1039,41 +1091,80 @@ bool __fastcall TTerminal::PromptUser(TSessionData * Data, TPromptKind Kind,
   // If PromptUser is overridden in descendant class, the overridden version
   // is not called when accessed via TSessionIU interface.
   // So this is workaround.
+  // Actually no longer needed as we do not uverride DoPromptUser
+  // anymore in TSecondaryTerminal.
   return DoPromptUser(Data, Kind, Name, Instructions, Prompts, Results);
 }
 //---------------------------------------------------------------------------
+TTerminal * __fastcall TTerminal::GetPasswordSource()
+{
+  return this;
+}
+//---------------------------------------------------------------------------
 bool __fastcall TTerminal::DoPromptUser(TSessionData * /*Data*/, TPromptKind Kind,
   UnicodeString Name, UnicodeString Instructions, TStrings * Prompts, TStrings * Results)
 {
   bool AResult = false;
 
+
   bool PasswordPrompt =
     (Prompts->Count == 1) && FLAGCLEAR(int(Prompts->Objects[0]), pupEcho) &&
     ((Kind == pkPassword) || (Kind == pkPassphrase) || (Kind == pkKeybInteractive) ||
      (Kind == pkTIS) || (Kind == pkCryptoCard));
-  if (PasswordPrompt && !Configuration->RememberPassword)
+  if (PasswordPrompt)
   {
-    Prompts->Objects[0] = (TObject*)(int(Prompts->Objects[0]) | pupRemember);
+    bool & PasswordTried =
+      FTunnelOpening ? FRememberedTunnelPasswordTried : FRememberedPasswordTried;
+    if (!PasswordTried)
+    {
+      // let's expect that the main session is already authenticated and its password
+      // is not written after, so no locking is necessary
+      // (no longer true, once the main session can be reconnected)
+      UnicodeString APassword;
+      if (FTunnelOpening)
+      {
+        APassword = GetPasswordSource()->TunnelPassword;
+      }
+      else
+      {
+        APassword = GetPasswordSource()->Password;
+      }
+      Results->Strings[0] = APassword;
+      if (!Results->Strings[0].IsEmpty())
+      {
+        LogEvent(L"Using remembered password.");
+        AResult = true;
+      }
+      PasswordTried = true;
+    }
   }
 
-  if (OnPromptUser != NULL)
+  if (!AResult)
   {
-    TCallbackGuard Guard(this);
-    OnPromptUser(this, Kind, Name, Instructions, Prompts, Results, AResult, NULL);
-    Guard.Verify();
-  }
+    if (PasswordPrompt && !Configuration->RememberPassword)
+    {
+      Prompts->Objects[0] = (TObject*)(int(Prompts->Objects[0]) | pupRemember);
+    }
 
-  if (AResult && PasswordPrompt &&
-      (Configuration->RememberPassword || FLAGSET(int(Prompts->Objects[0]), pupRemember)))
-  {
-    RawByteString EncryptedPassword = EncryptPassword(Results->Strings[0]);
-    if (FTunnelOpening)
+    if (OnPromptUser != NULL)
     {
-      FTunnelPassword = EncryptedPassword;
+      TCallbackGuard Guard(this);
+      OnPromptUser(this, Kind, Name, Instructions, Prompts, Results, AResult, NULL);
+      Guard.Verify();
     }
-    else
+
+    if (AResult && PasswordPrompt &&
+        (Configuration->RememberPassword || FLAGSET(int(Prompts->Objects[0]), pupRemember)))
     {
-      FPassword = EncryptedPassword;
+      RawByteString EncryptedPassword = EncryptPassword(Results->Strings[0]);
+      if (FTunnelOpening)
+      {
+        GetPasswordSource()->FTunnelPassword = EncryptedPassword;
+      }
+      else
+      {
+        GetPasswordSource()->FPassword = EncryptedPassword;
+      }
     }
   }
 
@@ -4887,7 +4978,14 @@ void __fastcall TTerminal::FileFind(UnicodeString FileName,
 
       if (File->IsDirectory)
       {
-        DoFilesFind(FullFileName, *AParams);
+        if (!AParams->LoopDetector.IsUnvisitedDirectory(File))
+        {
+          LogEvent(FORMAT(L"Already searched \"%s\" directory, link loop detected", (FullFileName)));
+        }
+        else
+        {
+          DoFilesFind(FullFileName, *AParams);
+        }
       }
     }
   }
@@ -4922,6 +5020,9 @@ void __fastcall TTerminal::FilesFind(UnicodeString Directory, const TFileMasks &
   Params.OnFileFound = OnFileFound;
   Params.OnFindingFile = OnFindingFile;
   Params.Cancel = false;
+
+  Params.LoopDetector.RecordVisitedDirectory(Directory);
+
   DoFilesFind(Directory, Params);
 }
 //---------------------------------------------------------------------------
@@ -5075,7 +5176,7 @@ bool __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
   }
   catch (Exception &E)
   {
-    CommandError(&E, LoadStr(TOREMOTE_COPY_ERROR));
+    CommandError(&E, MainInstructions(LoadStr(TOREMOTE_COPY_ERROR)));
     OnceDoneOperation = odoIdle;
   }
 
@@ -5166,7 +5267,7 @@ bool __fastcall TTerminal::CopyToLocal(TStrings * FilesToCopy,
         }
         catch (Exception &E)
         {
-          CommandError(&E, LoadStr(TOLOCAL_COPY_ERROR));
+          CommandError(&E, MainInstructions(LoadStr(TOLOCAL_COPY_ERROR)));
           OnceDoneOperation = odoIdle;
         }
 
@@ -5269,8 +5370,7 @@ void __fastcall TTerminal::CollectUsage()
 __fastcall TSecondaryTerminal::TSecondaryTerminal(TTerminal * MainTerminal,
   TSessionData * ASessionData, TConfiguration * Configuration, const UnicodeString & Name) :
   TTerminal(ASessionData, Configuration),
-  FMainTerminal(MainTerminal), FMasterPasswordTried(false),
-  FMasterTunnelPasswordTried(false)
+  FMainTerminal(MainTerminal)
 {
   Log->Parent = FMainTerminal->Log;
   Log->Name = Name;
@@ -5296,48 +5396,9 @@ void __fastcall TSecondaryTerminal::DirectoryModified(const UnicodeString Path,
   FMainTerminal->DirectoryModified(Path, SubDirs);
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSecondaryTerminal::DoPromptUser(TSessionData * Data,
-  TPromptKind Kind, UnicodeString Name, UnicodeString Instructions, TStrings * Prompts,
-  TStrings * Results)
+TTerminal * __fastcall TSecondaryTerminal::GetPasswordSource()
 {
-  bool AResult = false;
-
-  if ((Prompts->Count == 1) && FLAGCLEAR(int(Prompts->Objects[0]), pupEcho) &&
-      ((Kind == pkPassword) || (Kind == pkPassphrase) || (Kind == pkKeybInteractive) ||
-       (Kind == pkTIS) || (Kind == pkCryptoCard)))
-  {
-    bool & PasswordTried =
-      FTunnelOpening ? FMasterTunnelPasswordTried : FMasterPasswordTried;
-    if (!PasswordTried)
-    {
-      // let's expect that the main session is already authenticated and its password
-      // is not written after, so no locking is necessary
-      // (no longer true, once the main session can be reconnected)
-      UnicodeString Password;
-      if (FTunnelOpening)
-      {
-        Password = FMainTerminal->TunnelPassword;
-      }
-      else
-      {
-        Password = FMainTerminal->Password;
-      }
-      Results->Strings[0] = Password;
-      if (!Results->Strings[0].IsEmpty())
-      {
-        LogEvent(L"Using remembered password of the main session.");
-        AResult = true;
-      }
-      PasswordTried = true;
-    }
-  }
-
-  if (!AResult)
-  {
-    AResult = TTerminal::DoPromptUser(Data, Kind, Name, Instructions, Prompts, Results);
-  }
-
-  return AResult;
+  return FMainTerminal;
 }
 //---------------------------------------------------------------------------
 __fastcall TTerminalList::TTerminalList(TConfiguration * AConfiguration) :

+ 4 - 4
source/core/Terminal.h

@@ -202,6 +202,8 @@ private:
   TFindingFileEvent FOnFindingFile;
   bool FEnableSecureShellUsage;
   bool FCollectFileSystemUsage;
+  bool FRememberedPasswordTried;
+  bool FRememberedTunnelPasswordTried;
 
   void __fastcall CommandError(Exception * E, const UnicodeString Msg);
   unsigned int __fastcall CommandError(Exception * E, const UnicodeString Msg,
@@ -357,6 +359,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);
+  virtual TTerminal * __fastcall GetPasswordSource();
 
   __property TFileOperationProgressType * OperationProgress = { read=FOperationProgress };
 
@@ -517,12 +520,9 @@ protected:
   virtual void __fastcall DirectoryLoaded(TRemoteFileList * FileList);
   virtual void __fastcall DirectoryModified(const UnicodeString Path,
     bool SubDirs);
-  virtual bool __fastcall DoPromptUser(TSessionData * Data, TPromptKind Kind,
-    UnicodeString Name, UnicodeString Instructions, TStrings * Prompts, TStrings * Results);
+  virtual TTerminal * __fastcall GetPasswordSource();
 
 private:
-  bool FMasterPasswordTried;
-  bool FMasterTunnelPasswordTried;
   TTerminal * FMainTerminal;
 };
 //---------------------------------------------------------------------------

+ 1 - 0
source/core/WebDAVFileSystem.cpp

@@ -74,6 +74,7 @@ struct TClipboardHandler
 
   void __fastcall Copy(TObject * /*Sender*/)
   {
+    TInstantOperationVisualizer Visualizer;
     CopyToClipboard(Text);
   }
 };

+ 1 - 0
source/filezilla/FileZillaOpt.h

@@ -165,5 +165,6 @@
 #define OPTION_MPEXT_MIN_TLS_VERSION 1004
 #define OPTION_MPEXT_MAX_TLS_VERSION 1005
 #define OPTION_MPEXT_TRANSFER_ACTIVE_IMMEDIATELLY 1006
+#define OPTION_MPEXT_REMOVE_BOM 1007
 //---------------------------------------------------------------------------
 #endif // FileZillaOptH

+ 2 - 1
source/filezilla/TransferSocket.cpp

@@ -1289,7 +1289,8 @@ int CTransferSocket::ReadDataFromFile(char *buffer, int len)
 		// leaving it onto the server (what Filezilla 3 seems to do too)
 		const char Bom[3] = "\xEF\xBB\xBF";
 		int read = m_pFile->Read(buffer, len);
-		if (m_transferdata.bType && (read >= sizeof(Bom)) && (memcmp(buffer, Bom, sizeof(Bom)) == 0))
+		if (COptions::GetOptionVal(OPTION_MPEXT_REMOVE_BOM) &&
+				m_transferdata.bType && (read >= sizeof(Bom)) && (memcmp(buffer, Bom, sizeof(Bom)) == 0))
 		{
 			memcpy(buffer, buffer + sizeof(Bom), read - sizeof(Bom));
 			read -= sizeof(Bom);

+ 9 - 0
source/forms/About.cpp

@@ -223,3 +223,12 @@ void __fastcall TAboutDialog::RegistrationProductIdLabelClick(
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TAboutDialog::OKButtonMouseDown(TObject * /*Sender*/,
+  TMouseButton Button, TShiftState Shift, int /*X*/, int /*Y*/)
+{
+  if ((Button == mbRight) && Shift.Contains(ssAlt))
+  {
+    ACCESS_VIOLATION_TEST;
+  }
+}
+//---------------------------------------------------------------------------

+ 1 - 0
source/forms/About.dfm

@@ -3713,6 +3713,7 @@ object AboutDialog: TAboutDialog
     Default = True
     ModalResult = 1
     TabOrder = 0
+    OnMouseDown = OKButtonMouseDown
   end
   object LicenseButton: TButton
     Left = 72

+ 2 - 0
source/forms/About.h

@@ -56,6 +56,8 @@ __published:
   void __fastcall LicenseButtonClick(TObject *Sender);
   void __fastcall HelpButtonClick(TObject *Sender);
   void __fastcall RegistrationProductIdLabelClick(TObject *Sender);
+  void __fastcall OKButtonMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
+          int X, int Y);
 private:
   TConfiguration * FConfiguration;
   TNotifyEvent FOnRegistrationLink;

+ 2 - 1
source/forms/CopyParams.cpp

@@ -167,7 +167,8 @@ void __fastcall TCopyParamsFrame::UpdateControls()
   EnableControl(IncludeFileMaskLabel, IncludeFileMaskCombo->Enabled);
   EnableControl(ClearArchiveCheck, FLAGCLEAR(CopyParamAttrs, cpaNoClearArchive) &&
     FLAGCLEAR(CopyParamAttrs, cpaIncludeMaskOnly) && Enabled);
-  assert(FLAGCLEAR(CopyParamAttrs, cpaNoRemoveCtrlZ) == FLAGCLEAR(CopyParamAttrs, cpaNoRemoveBOM));
+  // TODO: Change RemoveCtrlZAndBOMCheck caption when only cpaNoRemoveBOM is set
+  // (FTP protocol)
   EnableControl(RemoveCtrlZAndBOMCheck,
     (FLAGCLEAR(CopyParamAttrs, cpaNoRemoveCtrlZ) || FLAGCLEAR(CopyParamAttrs, cpaNoRemoveBOM)) &&
     FLAGCLEAR(CopyParamAttrs, cpaIncludeMaskOnly) &&

+ 6 - 6
source/forms/CopyParams.dfm

@@ -29,7 +29,7 @@ object CopyParamsFrame: TCopyParamsFrame
       Width = 175
       Height = 17
       Anchors = [akLeft, akTop, akRight]
-      Caption = 'Preserve timesta&mp'
+      Caption = '&Preserve timestamp'
       ParentShowHint = False
       ShowHint = True
       TabOrder = 0
@@ -139,7 +139,7 @@ object CopyParamsFrame: TCopyParamsFrame
       Top = 98
       Width = 173
       Height = 17
-      Caption = 'Clear '#39'Archi&ve'#39' attribute'
+      Caption = 'Clear '#39'Arc&hive'#39' attribute'
       TabOrder = 3
     end
     object RemoveCtrlZAndBOMCheck: TCheckBox
@@ -147,7 +147,7 @@ object CopyParamsFrame: TCopyParamsFrame
       Top = 124
       Width = 173
       Height = 17
-      Caption = 'Remove BOM and &EOF marks'
+      Caption = 'Remo&ve BOM and EOF marks'
       TabOrder = 4
       OnClick = ControlChange
     end
@@ -177,7 +177,7 @@ object CopyParamsFrame: TCopyParamsFrame
       Width = 125
       Height = 17
       Anchors = [akLeft, akTop, akRight]
-      Caption = '&No change'
+      Caption = 'No chan&ge'
       TabOrder = 0
     end
     object CCUpperCaseButton: TRadioButton
@@ -203,7 +203,7 @@ object CopyParamsFrame: TCopyParamsFrame
       Top = 122
       Width = 125
       Height = 17
-      Caption = 'Replace '#39'\:*?'#39' ...'
+      Caption = 'Rep&lace '#39'\:*?'#39' ...'
       TabOrder = 4
       OnClick = ControlChange
     end
@@ -285,7 +285,7 @@ object CopyParamsFrame: TCopyParamsFrame
       Top = 20
       Width = 47
       Height = 13
-      Caption = 'File mas&k:'
+      Caption = 'File &mask:'
       FocusControl = IncludeFileMaskCombo
     end
     object IncludeFileMaskCombo: THistoryComboBox

+ 1 - 0
source/forms/Custom.cpp

@@ -414,6 +414,7 @@ TSessionData * __fastcall DoSaveSession(TSessionData * SessionData,
 
     if (CreateShortcut)
     {
+      TOperationVisualizer Visualizer;
       UnicodeString AdditionalParams =
         TProgramParams::FormatSwitch(DESKTOP_SWITCH) + L" " +
         TProgramParams::FormatSwitch(UPLOAD_IF_ANY_SWITCH);

+ 9 - 2
source/forms/CustomScpExplorer.cpp

@@ -2425,7 +2425,7 @@ void __fastcall TCustomScpExplorerForm::TemporarilyDownloadFiles(
   {
     CopyParam.TransferMode = tmAscii;
   }
-  // do not forget to add additional options to ExecutedFileChanged, FAR and SS
+  // do not forget to add additional options to ExecutedFileChanged and AS
   CopyParam.FileNameCase = ncNoChange;
   CopyParam.PreserveReadOnly = false;
   CopyParam.ReplaceInvalidChars = true;
@@ -2846,7 +2846,7 @@ void __fastcall TCustomScpExplorerForm::ExecutedFileChanged(const UnicodeString
     {
       CopyParam.TransferMode = tmAscii;
     }
-    // do not forget to add additional options to TemporarilyDownloadFiles, FAR and SS
+    // do not forget to add additional options to TemporarilyDownloadFiles, and AS
     CopyParam.FileNameCase = ncNoChange;
     CopyParam.PreserveRights = false;
     // so i do not need to worry if masking algorithm works in all cases
@@ -4674,6 +4674,7 @@ bool __fastcall TCustomScpExplorerForm::SaveWorkspace(bool EnableAutoSave)
 
     if (CreateShortcut)
     {
+      TOperationVisualizer Visualizer;
       UnicodeString AdditionalParams = TProgramParams::FormatSwitch(DESKTOP_SWITCH);
       CreateDesktopSessionShortCut(Name, L"", AdditionalParams, -1, WORKSPACE_ICON);
     }
@@ -5779,6 +5780,10 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDEnd(TObject * Sender)
         TDragResult DDResult = (Sender == RemoteDirView) ?
           RemoteDirView->LastDDResult : RemoteDriveView->LastDDResult;
 
+        // focus is moved to the target application,
+        // but as we are going to present the UI, we need to steal the focus back
+        Application->BringToFront();
+
         // note that we seem to never get drMove here, see also comment below
         if ((DDResult == drCopy) || (DDResult == drMove) || (DDResult == drInvalid))
         {
@@ -6176,6 +6181,7 @@ void __fastcall TCustomScpExplorerForm::PanelExportStore(TOperationSide /*Side*/
 {
   if (Destination == pedClipboard)
   {
+    TInstantOperationVisualizer Visualizer;
     CopyToClipboard(ExportData);
   }
   else
@@ -6834,6 +6840,7 @@ void __fastcall TCustomScpExplorerForm::UpdatesNoteClicked(TObject * /*Sender*/)
 
   if (!NonVisualDataModule->Busy)
   {
+    Configuration->Usage->Inc(L"UpdateNotificationsClicked");
     CheckForUpdates(true);
   }
 }

+ 2 - 2
source/forms/FileFind.cpp

@@ -187,7 +187,8 @@ void __fastcall TFileFindDialog::Start()
   {
     UpdateControls();
     Repaint();
-    Busy(true);
+
+    TOperationVisualizer Visualizer;
 
     assert(FOnFind != NULL);
     FDirectory = UnixExcludeTrailingBackslash(RemoteDirectoryEdit->Text);
@@ -195,7 +196,6 @@ void __fastcall TFileFindDialog::Start()
   }
   __finally
   {
-    Busy(false);
     FFindingInDirectory = L"";
     if (FState == ffFinding)
     {

+ 0 - 6
source/forms/FileFind.dfm

@@ -251,16 +251,10 @@ object FileFindDialog: TFileFindDialog
     Top = 398
     Width = 562
     Height = 19
-    Font.Charset = DEFAULT_CHARSET
-    Font.Color = clBtnText
-    Font.Height = -12
-    Font.Name = 'Segoe UI'
-    Font.Style = []
     Panels = <>
     ParentShowHint = False
     ShowHint = True
     SimplePanel = True
-    UseSystemFont = False
   end
   object FocusButton: TButton
     Left = 476

+ 7 - 0
source/forms/FileSystemInfo.cpp

@@ -206,6 +206,9 @@ void __fastcall TFileSystemInfoDialog::FeedControls()
 {
   FLastFeededControl = NULL;
   Feed(ControlsAddItem);
+  AdjustListColumnsWidth(ServerView);
+  AdjustListColumnsWidth(ProtocolView);
+  AdjustListColumnsWidth(SpaceAvailableView);
 }
 //---------------------------------------------------------------------
 void __fastcall TFileSystemInfoDialog::UpdateControls()
@@ -255,6 +258,8 @@ void __fastcall TFileSystemInfoDialog::ClipboardAddItem(TControl * Control,
 void __fastcall TFileSystemInfoDialog::ClipboardButtonClick(
   TObject * /*Sender*/)
 {
+  TInstantOperationVisualizer Visualizer;
+
   NeedSpaceAvailable();
   FLastFeededControl = NULL;
   FClipboard = L"";
@@ -264,6 +269,8 @@ void __fastcall TFileSystemInfoDialog::ClipboardButtonClick(
 //---------------------------------------------------------------------------
 void __fastcall TFileSystemInfoDialog::CopyClick(TObject * Sender)
 {
+  TInstantOperationVisualizer Visualizer;
+
   TComponent * Item = dynamic_cast<TComponent *>(Sender);
   assert(Item != NULL);
   TPopupMenu * PopupMenu = dynamic_cast<TPopupMenu *>(Item->Owner);

+ 17 - 17
source/forms/FileSystemInfo.dfm

@@ -6,7 +6,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
   BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
   BorderStyle = bsDialog
   Caption = 'Server and protocol information'
-  ClientHeight = 370
+  ClientHeight = 398
   ClientWidth = 371
   Color = clBtnFace
   ParentFont = True
@@ -15,12 +15,12 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
   OnShow = FormShow
   DesignSize = (
     371
-    370)
+    398)
   PixelsPerInch = 96
   TextHeight = 13
   object CloseButton: TButton
     Left = 204
-    Top = 336
+    Top = 364
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
@@ -32,7 +32,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
   end
   object HelpButton: TButton
     Left = 287
-    Top = 336
+    Top = 364
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
@@ -44,7 +44,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
     Left = 0
     Top = 0
     Width = 371
-    Height = 324
+    Height = 352
     ActivePage = ProtocolSheet
     Align = alTop
     Anchors = [akLeft, akTop, akRight, akBottom]
@@ -54,10 +54,10 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
       Caption = 'Protocol'
       DesignSize = (
         363
-        296)
+        324)
       object HostKeyGroup: TGroupBox
         Left = 6
-        Top = 174
+        Top = 202
         Width = 351
         Height = 41
         Anchors = [akLeft, akRight, akBottom]
@@ -84,7 +84,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
         Left = 6
         Top = 8
         Width = 351
-        Height = 159
+        Height = 187
         Anchors = [akLeft, akTop, akRight, akBottom]
         Columns = <
           item
@@ -108,7 +108,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
       end
       object CertificateGroup: TGroupBox
         Left = 6
-        Top = 218
+        Top = 246
         Width = 351
         Height = 72
         Anchors = [akLeft, akRight, akBottom]
@@ -146,10 +146,10 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
       ImageIndex = 1
       DesignSize = (
         363
-        296)
+        324)
       object InfoGroup: TGroupBox
         Left = 6
-        Top = 174
+        Top = 202
         Width = 351
         Height = 114
         Anchors = [akLeft, akRight, akBottom]
@@ -180,7 +180,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
         Left = 6
         Top = 8
         Width = 351
-        Height = 159
+        Height = 187
         Anchors = [akLeft, akTop, akRight, akBottom]
         Columns = <
           item
@@ -208,7 +208,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
       ImageIndex = 2
       DesignSize = (
         363
-        296)
+        324)
       object Label1: TLabel
         Left = 13
         Top = 13
@@ -221,7 +221,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
         Left = 6
         Top = 40
         Width = 351
-        Height = 127
+        Height = 155
         Anchors = [akLeft, akTop, akRight, akBottom]
         Columns = <
           item
@@ -269,7 +269,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
   end
   object ClipboardButton: TButton
     Left = 8
-    Top = 336
+    Top = 364
     Width = 121
     Height = 25
     Anchors = [akRight, akBottom]
@@ -278,8 +278,8 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
     OnClick = ClipboardButtonClick
   end
   object ListViewMenu: TPopupMenu
-    Left = 144
-    Top = 328
+    Left = 151
+    Top = 354
     object Copy: TMenuItem
       Caption = '&Copy'
       OnClick = CopyClick

+ 5 - 0
source/forms/Login.cpp

@@ -1416,6 +1416,9 @@ void __fastcall TLoginDialog::Dispatch(void * Message)
       assert(FSystemSettings);
       RevokeSystemSettings(this, FSystemSettings);
       FSystemSettings = NULL;
+      // have to undo the caption padding, otherwise the button does not
+      // get localized
+      UncenterButtonImage(LoginButton);
 
       Hide();
     }
@@ -1494,6 +1497,7 @@ void __fastcall TLoginDialog::DesktopIconActionExecute(TObject * /*Sender*/)
   Message = MainInstructions(Message);
   if (MessageDialog(Message, qtConfirmation, qaYes | qaNo, HELP_CREATE_SHORTCUT) == qaYes)
   {
+    TInstantOperationVisualizer Visualizer;
     CreateDesktopSessionShortCut(Name, L"", AdditionalParams, -1, IconIndex);
   }
 }
@@ -1506,6 +1510,7 @@ void __fastcall TLoginDialog::SendToHookActionExecute(TObject * /*Sender*/)
   if (MessageDialog(Message,
         qtConfirmation, qaYes | qaNo, HELP_CREATE_SENDTO) == qaYes)
   {
+    TInstantOperationVisualizer Visualizer;
     UnicodeString AdditionalParams =
       TProgramParams::FormatSwitch(SEND_TO_HOOK_SWITCH) + L" " +
       TProgramParams::FormatSwitch(UPLOAD_SWITCH);

+ 1 - 0
source/forms/MessageDlg.cpp

@@ -192,6 +192,7 @@ void __fastcall TMessageForm::KeyDown(Word & Key, TShiftState Shift)
 {
   if (Shift.Contains(ssCtrl) && (Key == L'C'))
   {
+    TInstantOperationVisualizer Visualizer;
     CopyToClipboard(GetFormText());
   }
   else

+ 29 - 7
source/forms/Preferences.cpp

@@ -286,8 +286,9 @@ void __fastcall TPreferencesDialog::LoadConfiguration()
     ShowFullAddressCheck->Checked =
       WinConfiguration->ScpExplorer.ShowFullAddress;
 
+    // select none when stNul
     RegistryStorageButton->Checked = (Configuration->Storage == stRegistry);
-    IniFileStorageButton2->Checked = (Configuration->Storage != stRegistry);
+    IniFileStorageButton2->Checked = (Configuration->Storage == stIniFile);
 
     RandomSeedFileEdit->Text = Configuration->RandomSeedFile;
 
@@ -864,8 +865,16 @@ void __fastcall TPreferencesDialog::SaveConfiguration()
         reinterpret_cast<LCID>(LanguagesView->ItemFocused->Data);
     }
 
-    // this possibly fails, make it last, so that the other settings are preserved
-    Configuration->Storage = RegistryStorageButton->Checked ? stRegistry : stIniFile;
+    // This possibly fails, make it last, so that the other settings are preserved.
+    // Do nothing when no option is selected (i.e. storage is stNul).
+    if (RegistryStorageButton->Checked)
+    {
+      Configuration->Storage = stRegistry;
+    }
+    else if (IniFileStorageButton2->Checked)
+    {
+      Configuration->Storage = stIniFile;
+    }
 
     #undef BOOLPROP
   }
@@ -1013,9 +1022,13 @@ void __fastcall TPreferencesDialog::UpdateControls()
       DDAllowMoveInitCheck->Checked);
     EnableControl(ConfirmTemporaryDirectoryCleanupCheck,
       TemporaryDirectoryCleanupCheck->Checked);
+    // allow only when some of the known storages is selected,
+    // and particularly do not allow switching storage, when we start with stNul,
+    // as that would destroy the stored configuration
+    EnableControl(StorageGroup, RegistryStorageButton->Checked || IniFileStorageButton2->Checked);
     IniFileStorageButton2->Caption =
       AnsiReplaceStr(IniFileStorageButton2->Caption, L"winscp.ini",
-        ExtractFileName(ExpandEnvironmentVariables(Configuration->IniFileStorageNameForReading)));
+        ExpandEnvironmentVariables(Configuration->IniFileStorageName));
 
     EditorFontLabel->WordWrap = EditorWordWrapCheck->Checked;
     bool EditorSelected = (EditorListView3->Selected != NULL);
@@ -1167,6 +1180,8 @@ void __fastcall TPreferencesDialog::IconButtonClick(TObject *Sender)
     }
   }
 
+  TInstantOperationVisualizer Visualizer;
+
   CreateDesktopShortCut(IconName,
     Application->ExeName, Params, L"", SpecialFolder);
 }
@@ -1208,7 +1223,7 @@ void __fastcall TPreferencesDialog::ListViewSelectItem(
 void __fastcall TPreferencesDialog::UpdateCustomCommandsView()
 {
   CustomCommandsView->Items->Count = FCustomCommandList->Count;
-  AdjustListColumnsWidth(CustomCommandsView, FCustomCommandList->Count);
+  AdjustListColumnsWidth(CustomCommandsView);
   CustomCommandsView->Invalidate();
 }
 //---------------------------------------------------------------------------
@@ -1629,7 +1644,7 @@ void __fastcall TPreferencesDialog::EditorListView3KeyDown(TObject * /*Sender*/,
 void __fastcall TPreferencesDialog::UpdateEditorListView()
 {
   EditorListView3->Items->Count = FEditorList->Count;
-  AdjustListColumnsWidth(EditorListView3, FEditorList->Count);
+  AdjustListColumnsWidth(EditorListView3);
   EditorListView3->Invalidate();
 }
 //---------------------------------------------------------------------------
@@ -1756,6 +1771,8 @@ void __fastcall TPreferencesDialog::RegisterAsUrlHandlerItemClick(TObject * /*Se
       qtConfirmation, qaYes | qaNo, HELP_REGISTER_URL);
   if (Result == qaYes)
   {
+    TInstantOperationVisualizer Visualizer;
+
     RegisterForDefaultProtocols();
   }
 }
@@ -1767,12 +1784,15 @@ void __fastcall TPreferencesDialog::UnregisterForDefaultProtocolsItemClick(TObje
       qtConfirmation, qaYes | qaNo, HELP_REGISTER_URL);
   if (Result == qaYes)
   {
+    TInstantOperationVisualizer Visualizer;
+
     UnregisterForProtocols();
   }
 }
 //---------------------------------------------------------------------------
 void __fastcall TPreferencesDialog::MakeDefaultHandlerItemClick(TObject * /*Sender*/)
 {
+  TOperationVisualizer Visualizer;
   LaunchAdvancedAssociationUI();
 }
 //---------------------------------------------------------------------------
@@ -1789,6 +1809,8 @@ void __fastcall TPreferencesDialog::AddSearchPathButtonClick(
   if (MessageDialog(MainInstructions(FMTLOAD(CONFIRM_ADD_SEARCH_PATH, (AppPath))),
         qtConfirmation, qaYes | qaNo, HELP_ADD_SEARCH_PATH) == qaYes)
   {
+    TInstantOperationVisualizer Visualizer;
+
     AddSearchPath(AppPath);
   }
 }
@@ -1802,7 +1824,7 @@ void __fastcall TPreferencesDialog::EditorFontLabelDblClick(
 void __fastcall TPreferencesDialog::UpdateCopyParamListView()
 {
   CopyParamListView->Items->Count = 1 + FCopyParamList->Count;
-  AdjustListColumnsWidth(CopyParamListView, 1 + FCopyParamList->Count);
+  AdjustListColumnsWidth(CopyParamListView);
   CopyParamListView->Invalidate();
 }
 //---------------------------------------------------------------------------

+ 5 - 4
source/forms/Preferences.dfm

@@ -1680,7 +1680,8 @@ object PreferencesDialog: TPreferencesDialog
             Top = 172
             Width = 198
             Height = 13
-            Caption = 'Display completed transfers in queue for:'
+            Caption = 'Display &completed transfers in queue for:'
+            FocusControl = QueueKeepDoneItemsForCombo
             OnClick = ControlChange
           end
           object QueueTransferLimitEdit: TUpDownEdit
@@ -2984,7 +2985,7 @@ object PreferencesDialog: TPreferencesDialog
             Width = 357
             Height = 17
             Anchors = [akLeft, akTop, akRight]
-            Caption = 'Use system file context menu'
+            Caption = 'Use &system file context menu'
             TabOrder = 1
             OnClick = ControlChange
           end
@@ -3038,9 +3039,9 @@ object PreferencesDialog: TPreferencesDialog
             OnSelectItem = ListViewSelectItem
           end
           object LanguagesGetMoreButton: TButton
-            Left = 297
+            Left = 272
             Top = 339
-            Width = 75
+            Width = 100
             Height = 25
             Anchors = [akRight, akBottom]
             Caption = 'Get &more...'

+ 0 - 1
source/forms/Progress.cpp

@@ -329,7 +329,6 @@ void __fastcall TProgressForm::MinimizeButtonClick(TObject * Sender)
 //---------------------------------------------------------------------------
 void __fastcall TProgressForm::CancelOperation()
 {
-  // partially duplicated in TWinSCPFileSystem::CancelConfiguration (far\WinSCPFileSystem)
   assert(FDataReceived);
   if (!FData.Suspended)
   {

+ 2 - 0
source/forms/Properties.cpp

@@ -642,6 +642,8 @@ void __fastcall TPropertiesDialog::ChecksumAlgEditChange(TObject * /*Sender*/)
 //---------------------------------------------------------------------------
 void __fastcall TPropertiesDialog::CopyClick(TObject * /*Sender*/)
 {
+  TInstantOperationVisualizer Visualizer;
+
   TListView * ListView = dynamic_cast<TListView *>(ListViewMenu->PopupComponent);
   assert(ListView != NULL);
 

+ 2 - 0
source/forms/Rights.cpp

@@ -302,6 +302,7 @@ void __fastcall TRightsFrame::RightsActionsExecute(TBasicAction * Action,
     }
     else if (Action == CopyTextAction)
     {
+      TInstantOperationVisualizer Visualizer;
       CopyToClipboard(Text);
       Changed = false;
     }
@@ -311,6 +312,7 @@ void __fastcall TRightsFrame::RightsActionsExecute(TBasicAction * Action,
       assert(!R.IsUndef);
       if (!R.IsUndef)
       {
+        TInstantOperationVisualizer Visualizer;
         CopyToClipboard(R.Octal);
       }
       Changed = false;

+ 2 - 0
source/forms/ScpCommander.cpp

@@ -1203,6 +1203,8 @@ void __fastcall TScpCommanderForm::AddEditLink(TOperationSide Side, bool Add)
 
     if (DoSymlinkDialog(FileName, PointTo, osLocal, SymbolicLink, Edit, false))
     {
+      Configuration->Usage->Inc(L"LocalShortcutsCreated");
+
       assert(SymbolicLink);
       assert(!FileName.IsEmpty());
       assert(!PointTo.IsEmpty());

+ 1 - 1
source/forms/SiteAdvanced.cpp

@@ -955,7 +955,7 @@ void __fastcall TSiteAdvancedDialog::UpdateControls()
     ScpSheet->Caption = LoadStr(ScpProtocol ? LOGIN_SCP_SHELL_PAGE : LOGIN_SHELL_PAGE);
     // hide also for SFTP with SCP fallback, as if someone wants to configure
     // these he/she probably intends to use SCP and should explicitly select it.
-    // (note that these are not used for secondary shell session)
+    // (note that these are not used for separate shell session)
     ScpLsOptionsGroup->Visible = ScpProtocol;
     OtherShellOptionsGroup->Visible = ScpProtocol;
 

+ 1 - 0
source/forms/Synchronize.cpp

@@ -520,6 +520,7 @@ void __fastcall TSynchronizeDialog::ClearLog()
 //---------------------------------------------------------------------------
 void __fastcall TSynchronizeDialog::CopyLog()
 {
+  TInstantOperationVisualizer Visualizer;
   UnicodeString Content;
   for (int i = 0; i < LogView->Items->Count; i++)
   {

+ 0 - 6
source/forms/SynchronizeChecklist.dfm

@@ -214,11 +214,6 @@ object SynchronizeChecklistDialog: TSynchronizeChecklistDialog
     Width = 695
     Height = 20
     Hint = 'Click to select all actions of this type'
-    Font.Charset = DEFAULT_CHARSET
-    Font.Color = clBtnText
-    Font.Height = -12
-    Font.Name = 'Segoe UI'
-    Font.Style = []
     Panels = <
       item
         Style = psOwnerDraw
@@ -260,7 +255,6 @@ object SynchronizeChecklistDialog: TSynchronizeChecklistDialog
       end>
     ParentShowHint = False
     ShowHint = True
-    UseSystemFont = False
     OnMouseDown = StatusBarMouseDown
     OnMouseMove = StatusBarMouseMove
     OnDrawPanel = StatusBarDrawPanel

+ 1 - 1
source/resource/TextsCore1.rc

@@ -205,7 +205,7 @@ BEGIN
   READ_ONLY_OVERWRITE, "File '%s' is read-only. Overwrite?"
   LOCAL_FILE_OVERWRITE2, "**Overwrite local file '%s'?**\n\nDestination directory already contains file '%s'.\nChoose, if you want to overwrite the file or skip this transfer and keep existing file."
   REMOTE_FILE_OVERWRITE2, "**Overwrite remote file '%s'?**\n\nDestination directory already contains file '%s'.\nChoose, if you want to overwrite the file or skip this transfer and keep existing file."
-  TIMEOUT_STILL_WAITING3, "Host is not communicating for more than %d seconds. Still waiting...\n\nNote: If the problem repeats, try turning off 'Optimize connection buffer size'."
+  TIMEOUT_STILL_WAITING3, "Host is not communicating for more than %d seconds.\nStill waiting...\n\nNote: If the problem repeats, try turning off 'Optimize connection buffer size'."
   KEX_BELOW_TRESHOLD, "The first key-exchange algorithm supported by the server is %s, which is below the configured warning threshold.\n\nDo you want to continue with this connection?"
   RECONNECT_BUTTON, "&Reconnect"
   RENAME_BUTTON, "New na&me"

+ 1 - 1
source/resource/TextsCore2.rc

@@ -74,7 +74,7 @@ BEGIN
     "  -explicittls       Explicit TLS (FTPS protocol only)\n"
     "  -explicitssl       Explicit SSL (FTPS protocol only)\n"
     "  -rawsettings setting1=value1 setting2=value2 ...\n"
-    "                     Configures any session settings using raw format\n"
+    "                     Configures any site settings using raw format\n"
     "                     as in an INI file\n"
     "examples:\n"
     "  open\n"

+ 1 - 1
source/resource/TextsWin1.rc

@@ -30,7 +30,7 @@ BEGIN
         REGISTER_URL_ERROR2, "Cannot register application to handle URL addresses."
         MUTEX_RELEASE_TIMEOUT, "Mutex was not released in required interval."
         DRAGEXT_MUTEX_RELEASE_TIMEOUT, "Shell drag extension mutex was not released in required interval."
-        DRAGEXT_TARGET_UNKNOWN2, "**WinSCP was not able to detect folder, where the dragged file(s) was dropped.** Either you have not dropped the file(s) to regular folder (e.g. Windows Explorer) or you have not restarted your computer yet after installation to load drag&drop shell extension. \n\nAlternativelly you can switch to compatible drag&drop mode (from Preferences window), which uses temporary folder for downloads. It allows you to drop files to any destination."
+        DRAGEXT_TARGET_UNKNOWN2, "**WinSCP was not able to detect folder, where the dragged file(s) was dropped.** Either you have not dropped the file(s) to regular folder (e.g. Windows Explorer) or you have not restarted your computer yet after installation to load drag&drop shell extension. \n\nAlternatively you can switch to compatible drag&drop mode (from Preferences window), which uses temporary folder for downloads. It allows you to drop files to any destination."
         UNKNOWN_TRANSLATION, "File '%s' does not contain translation for this product version."
         INCOMPATIBLE_TRANSLATION, "File '%s' contains translation for %s version %s."
         DRAGEXT_TARGET_NOT_INSTALLED2, "**Drag&drop shell extension use is enabled, but the extension is not installed.** Install the extension or switch to compatible drag&drop mode (from Preferences window), which uses temporary folder for downloads."

+ 1 - 0
source/windows/ConsoleRunner.cpp

@@ -1239,6 +1239,7 @@ void __fastcall TConsoleRunner::ScriptTerminalQueryUser(TObject * /*Sender*/,
       {
         Answers = Params->TimerAnswers;
       }
+      // not considering TimerQueryType as we do not use QueryType anyway
       if (!Params->TimerMessage.IsEmpty())
       {
         AQuery = Params->TimerMessage;

+ 15 - 21
source/windows/CustomWinConfiguration.cpp

@@ -347,33 +347,27 @@ void __fastcall TCustomWinConfiguration::LoadAdmin(THierarchicalStorage * Storag
 //---------------------------------------------------------------------------
 void __fastcall TCustomWinConfiguration::RecryptPasswords(TStrings * RecryptPasswordErrors)
 {
-  Busy(true);
-  try
-  {
-    StoredSessions->RecryptPasswords(RecryptPasswordErrors);
+  TOperationVisualizer Visualizer;
+
+  StoredSessions->RecryptPasswords(RecryptPasswordErrors);
 
-    if (OnMasterPasswordRecrypt != NULL)
+  if (OnMasterPasswordRecrypt != NULL)
+  {
+    try
     {
-      try
-      {
-        OnMasterPasswordRecrypt(NULL);
-      }
-      catch (Exception & E)
+      OnMasterPasswordRecrypt(NULL);
+    }
+    catch (Exception & E)
+    {
+      UnicodeString Message;
+      if (ExceptionMessage(&E, Message))
       {
-        UnicodeString Message;
-        if (ExceptionMessage(&E, Message))
-        {
-          // we do not expect this really to happen,
-          // so we do not bother providing context
-          RecryptPasswordErrors->Add(Message);
-        }
+        // we do not expect this really to happen,
+        // so we do not bother providing context
+        RecryptPasswordErrors->Add(Message);
       }
     }
   }
-  __finally
-  {
-    Busy(false);
-  }
 }
 //---------------------------------------------------------------------
 void __fastcall TCustomWinConfiguration::AskForMasterPasswordIfNotSetAndNeededToPersistSessionData(

+ 12 - 11
source/windows/Setup.cpp

@@ -917,19 +917,19 @@ void __fastcall QueryUpdates()
     }
 
     WinConfiguration->Updates = Updates;
-  }
-  catch(Exception & E)
-  {
-    throw ExtException(&E, LoadStr(CHECK_FOR_UPDATES_ERROR));
-  }
 
-  if (Complete)
-  {
+    if (!Complete)
+    {
+      EXCEPTION;
+    }
+
     Configuration->Usage->Reset();
+    Configuration->Usage->Inc(L"UpdateChecksSucceeded");
   }
-  else
+  catch(Exception & E)
   {
-    throw Exception(LoadStr(CHECK_FOR_UPDATES_ERROR));
+    Configuration->Usage->Inc(L"UpdateChecksFailed");
+    throw ExtException(&E, MainInstructions(LoadStr(CHECK_FOR_UPDATES_ERROR)));
   }
 }
 //---------------------------------------------------------------------------
@@ -993,7 +993,9 @@ static void __fastcall OpenHistory(void * /*Data*/, TObject * /*Sender*/)
 void __fastcall CheckForUpdates(bool CachedResults)
 {
   TCustomForm * ActiveForm = Screen->ActiveCustomForm;
-  Busy(true);
+
+  TOperationVisualizer Visualizer;
+
   try
   {
     if (ActiveForm)
@@ -1121,7 +1123,6 @@ void __fastcall CheckForUpdates(bool CachedResults)
     {
       ActiveForm->Enabled = true;
     }
-    Busy(false);
   }
 }
 //---------------------------------------------------------------------------

+ 3 - 7
source/windows/TerminalManager.cpp

@@ -697,11 +697,6 @@ void __fastcall TTerminalManager::SaveTerminal(TTerminal * Terminal)
     {
       Data->LocalDirectory = ManagedTerminal->LocalDirectory;
       Data->RemoteDirectory = ManagedTerminal->RemoteDirectory;
-      Changed = true;
-    }
-
-    if (Data->SynchronizeBrowsing != ManagedTerminal->SynchronizeBrowsing)
-    {
       Data->SynchronizeBrowsing = ManagedTerminal->SynchronizeBrowsing;
       Changed = true;
     }
@@ -1085,7 +1080,7 @@ void __fastcall TTerminalManager::TerminalInformation(
   {
     if (FAuthenticating == 0)
     {
-      Busy(true);
+      FBusyToken = BusyStart();
     }
     FAuthenticating++;
   }
@@ -1095,7 +1090,8 @@ void __fastcall TTerminalManager::TerminalInformation(
     FAuthenticating--;
     if (FAuthenticating == 0)
     {
-      Busy(false);
+      BusyEnd(FBusyToken);
+      FBusyToken = NULL;
     }
     SAFE_DESTROY(FAuthenticateForm);
   }

+ 1 - 0
source/windows/TerminalManager.h

@@ -99,6 +99,7 @@ private:
   unsigned int FTaskbarButtonCreatedMessage;
   ITaskbarList3 * FTaskbarList;
   int FAuthenticating;
+  void * FBusyToken;
 
   bool __fastcall ConnectActiveTerminalImpl(bool Reopen);
   bool __fastcall ConnectActiveTerminal();

+ 12 - 8
source/windows/VCLCommon.cpp

@@ -18,7 +18,7 @@
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
-void __fastcall AdjustListColumnsWidth(TListView* ListView, int RowCount, int RightPad)
+void __fastcall AdjustListColumnsWidth(TListView * ListView)
 {
   int OriginalWidth, NewWidth, i, CWidth, LastResizible;
 
@@ -34,15 +34,10 @@ void __fastcall AdjustListColumnsWidth(TListView* ListView, int RowCount, int Ri
   }
   assert(LastResizible >= 0);
 
-  // when listview is virtual, ListView->Items->Count seems to return invalid
-  // value, thus provide a method to pass actual count explicitly
-  if (RowCount < 0)
-  {
-    RowCount = ListView->Items->Count;
-  }
+  int RowCount = ListView->Items->Count;
 
   NewWidth = 0;
-  CWidth = ListView->ClientWidth - RightPad;
+  CWidth = ListView->ClientWidth;
   if ((ListView->VisibleRowCount < RowCount) &&
       (ListView->Width - ListView->ClientWidth < GetSystemMetrics(SM_CXVSCROLL)))
   {
@@ -1375,6 +1370,7 @@ static void __fastcall LinkLabelWindowProc(void * Data, TMessage & Message)
     TWMKey & Key = reinterpret_cast<TWMKey &>(Message);
     if ((GetKeyState(VK_CONTROL) < 0) && (Key.CharCode == L'C'))
     {
+      TInstantOperationVisualizer Visualizer;
       CopyToClipboard(StaticText->Caption);
       Message.Result = 1;
     }
@@ -1410,6 +1406,7 @@ static void __fastcall LinkLabelContextMenuClick(void * Data, TObject * Sender)
   }
   else
   {
+    TInstantOperationVisualizer Visualizer;
     CopyToClipboard(StaticText->Caption);
   }
 }
@@ -1650,6 +1647,13 @@ void __fastcall SetFormIcons(TForm * Form, const UnicodeString & BigIconName,
 //---------------------------------------------------------------------------
 void __fastcall UseDesktopFont(TControl * Control)
 {
+  TCustomStatusBar * StatusBar = dynamic_cast<TCustomStatusBar *>(Control);
+  if (StatusBar != NULL)
+  {
+    // otherwise setting DesktopFont below has no effect
+    StatusBar->UseSystemFont = false;
+  }
+
   class TPublicControl : public TControl
   {
   public:

+ 1 - 2
source/windows/VCLCommon.h

@@ -7,8 +7,7 @@
 #include "Exceptions.h"
 #include <ComCtrls.hpp>
 //---------------------------------------------------------------------------
-void __fastcall AdjustListColumnsWidth(TListView* ListView, int RowCount = -1,
-  int RightPad = 0);
+void __fastcall AdjustListColumnsWidth(TListView * ListView);
 void __fastcall EnableControl(TControl* Control, bool Enable);
 void __fastcall ReadOnlyControl(TControl * Control, bool ReadOnly = true);
 void __fastcall InitializeSystemSettings();

+ 48 - 51
source/windows/WinConfiguration.cpp

@@ -730,7 +730,8 @@ TStorage __fastcall TWinConfiguration::GetStorage()
       }
     }
   }
-  return TCustomWinConfiguration::GetStorage();
+  TStorage Result = TCustomWinConfiguration::GetStorage();
+  return Result;
 }
 //---------------------------------------------------------------------------
 void __fastcall TWinConfiguration::Saved()
@@ -773,14 +774,16 @@ bool __fastcall TWinConfiguration::GetUseMasterPassword()
 //---------------------------------------------------------------------------
 THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool SessionList)
 {
+  THierarchicalStorage * Result;
   if (SessionList && !FTemporarySessionFile.IsEmpty())
   {
-    return new TIniFileStorage(FTemporarySessionFile);
+    Result = new TIniFileStorage(FTemporarySessionFile);
   }
   else
   {
-    return TCustomWinConfiguration::CreateScpStorage(SessionList);
+    Result = TCustomWinConfiguration::CreateScpStorage(SessionList);
   }
+  return Result;
 }
 //---------------------------------------------------------------------------
 // duplicated from core\configuration.cpp
@@ -2028,65 +2031,59 @@ void __fastcall TWinConfiguration::SetResourceModule(HINSTANCE Instance)
 {
   TCustomWinConfiguration::SetResourceModule(Instance);
 
-  Busy(true);
-  try
-  {
-    int Count;
-    UnicodeString OrigName;
-    int OrigLeft;
-    int OrigTop;
+  TOperationVisualizer Visualizer;
 
-    TForm * Form;
-    Count = Screen->FormCount;
+  int Count;
+  UnicodeString OrigName;
+  int OrigLeft;
+  int OrigTop;
 
-    for (int Index = 0; Index < Count; Index++)
-    {
-      Form = Screen->Forms[Index];
-      SendMessage(Form->Handle, WM_LOCALE_CHANGE, 0, 1);
-    }
+  TForm * Form;
+  Count = Screen->FormCount;
 
-    ConfigureInterface();
+  for (int Index = 0; Index < Count; Index++)
+  {
+    Form = Screen->Forms[Index];
+    SendMessage(Form->Handle, WM_LOCALE_CHANGE, 0, 1);
+  }
 
-    for (int Index = 0; Index < Count; Index++)
+  ConfigureInterface();
+
+  for (int Index = 0; Index < Count; Index++)
+  {
+    Form = Screen->Forms[Index];
+    TComponent * Component;
+    for (int Index = 0; Index < Form->ComponentCount; Index++)
     {
-      Form = Screen->Forms[Index];
-      TComponent * Component;
-      for (int Index = 0; Index < Form->ComponentCount; Index++)
+      Component = Form->Components[Index];
+      if (dynamic_cast<TFrame*>(Component))
       {
-        Component = Form->Components[Index];
-        if (dynamic_cast<TFrame*>(Component))
-        {
-          OrigName = Component->Name;
-          InitComponent(Component, __classid(TFrame), Component->ClassType());
-          Component->Name = OrigName;
-        }
+        OrigName = Component->Name;
+        InitComponent(Component, __classid(TFrame), Component->ClassType());
+        Component->Name = OrigName;
       }
-
-      OrigLeft = Form->Left;
-      OrigTop = Form->Top;
-      OrigName = Form->Name;
-      InitComponent(Form, __classid(TForm), Form->ClassType());
-      Form->Name = OrigName;
-
-      Form->Position = poDesigned;
-      Form->Left = OrigLeft;
-      Form->Top = OrigTop;
-      SendMessage(Form->Handle, WM_LOCALE_CHANGE, 1, 1);
     }
 
-    TDataModule * DataModule;
-    Count = Screen->DataModuleCount;
-    for (int Index = 0; Index < Count; Index++)
-    {
-      DataModule = Screen->DataModules[Index];
-      OrigName = DataModule->Name;
-      InitComponent(DataModule, __classid(TDataModule), DataModule->ClassType());
-      DataModule->Name = OrigName;
-    }
+    OrigLeft = Form->Left;
+    OrigTop = Form->Top;
+    OrigName = Form->Name;
+    InitComponent(Form, __classid(TForm), Form->ClassType());
+    Form->Name = OrigName;
+
+    Form->Position = poDesigned;
+    Form->Left = OrigLeft;
+    Form->Top = OrigTop;
+    SendMessage(Form->Handle, WM_LOCALE_CHANGE, 1, 1);
   }
-  __finally
+
+  TDataModule * DataModule;
+  Count = Screen->DataModuleCount;
+  for (int Index = 0; Index < Count; Index++)
   {
-    Busy(false);
+    DataModule = Screen->DataModules[Index];
+    OrigName = DataModule->Name;
+    InitComponent(DataModule, __classid(TDataModule), DataModule->ClassType());
+    DataModule->Name = OrigName;
   }
 }
 //---------------------------------------------------------------------------

+ 33 - 30
source/windows/WinInterface.cpp

@@ -49,6 +49,7 @@ TMessageParams::TMessageParams(const TQueryParams * AParams)
     TimerEvent = AParams->TimerEvent;
     TimerMessage = AParams->TimerMessage;
     TimerAnswers = AParams->TimerAnswers;
+    TimerQueryType = AParams->TimerQueryType;
     Timeout = AParams->Timeout;
     TimeoutAnswer = AParams->TimeoutAnswer;
 
@@ -72,6 +73,7 @@ inline void TMessageParams::Reset()
   TimerEvent = NULL;
   TimerMessage = L"";
   TimerAnswers = 0;
+  TimerQueryType = static_cast<TQueryType>(-1);
   Timeout = 0;
   TimeoutAnswer = 0;
   NeverAskAgainTitle = L"";
@@ -440,6 +442,10 @@ unsigned int __fastcall MoreMessageDialog(const UnicodeString Message, TStrings
       {
         Answers = Params->TimerAnswers;
       }
+      if (Params->TimerQueryType >= 0)
+      {
+        Type = Params->TimerQueryType;
+      }
       if (!Params->TimerMessage.IsEmpty())
       {
         AMessage = Params->TimerMessage;
@@ -554,29 +560,16 @@ unsigned int __fastcall FatalExceptionMessageDialog(Exception * E, TQueryType Ty
   return ExceptionMessageDialog(E, Type, MessageFormat, Answers, HelpKeyword, &AParams);
 }
 //---------------------------------------------------------------------------
-void __fastcall Busy(bool Start)
+void * __fastcall BusyStart()
 {
-  static int Busy = 0;
-  static TCursor PrevCursor;
-  if (Start)
-  {
-    if (!Busy)
-    {
-      PrevCursor = Screen->Cursor;
-      Screen->Cursor = crHourGlass;
-    }
-    Busy++;
-    assert(Busy < 10);
-  }
-  else
-  {
-    assert(Busy > 0);
-    Busy--;
-    if (!Busy)
-    {
-      Screen->Cursor = PrevCursor;
-    }
-  }
+  void * Token = reinterpret_cast<void *>(Screen->Cursor);
+  Screen->Cursor = crHourGlass;
+  return Token;
+}
+//---------------------------------------------------------------------------
+void __fastcall BusyEnd(void * Token)
+{
+  Screen->Cursor = reinterpret_cast<TCursor>(Token);
 }
 //---------------------------------------------------------------------------
 void __fastcall CopyParamListButton(TButton * Button)
@@ -919,22 +912,32 @@ void __fastcall FixButtonImage(TButton * Button)
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall UncenterButtonImage(TButton * Button)
+{
+  Button->ImageMargins->Left = 0;
+  if (UseThemes())
+  {
+    Button->Caption = TrimLeft(Button->Caption);
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall CenterButtonImage(TButton * Button)
 {
+  UncenterButtonImage(Button);
+
   // with themes disabled, the text seems to be drawn over the icon,
   // so that the padding spaces hide away most of the icon
   if (UseThemes())
   {
     Button->ImageAlignment = iaCenter;
-    int ImageWidthWithPadding = Button->Images->Width;
+    int ImageWidth = Button->Images->Width;
 
     std::unique_ptr<TControlCanvas> Canvas(new TControlCanvas());
     Canvas->Control = Button;
 
     UnicodeString Caption = Button->Caption;
-    Caption = TrimLeft(Caption);
     UnicodeString Padding;
-    while (Canvas->TextWidth(Padding) < ImageWidthWithPadding)
+    while (Canvas->TextWidth(Padding) < ImageWidth)
     {
       Padding += L" ";
     }
@@ -942,11 +945,11 @@ void __fastcall CenterButtonImage(TButton * Button)
     Button->Caption = Caption;
 
     int CaptionWidth = Canvas->TextWidth(Caption);
-    // Image is bit to the left, than what it would be,
-    // if it were to be centered together with the caption.
-    // Windows elevation buttons have it the same
-    // (althought they have smaller padding between image and the caption)
-    Button->ImageMargins->Left = -(CaptionWidth / 2) - ScaleByTextHeight(Button, 8);
+    // The margins seem to extend the area over which the image is centered,
+    // so we have to set it to a double of desired padding.
+    // Note that (CaptionWidth / 2) - (ImageWidth / 2)
+    // is approximatelly same as half of caption width before padding.
+    Button->ImageMargins->Left = - 2 * ((CaptionWidth / 2) - (ImageWidth / 2) + ScaleByTextHeight(Button, 2));
   }
   else
   {

+ 2 - 0
source/windows/WinInterface.h

@@ -41,6 +41,7 @@ struct TMessageParams
   TQueryParamsTimerEvent TimerEvent;
   UnicodeString TimerMessage;
   unsigned int TimerAnswers;
+  TQueryType TimerQueryType;
   unsigned int Timeout;
   unsigned int TimeoutAnswer;
   UnicodeString NeverAskAgainTitle;
@@ -400,6 +401,7 @@ void __fastcall CreateSessionColorMenu(TComponent * AOwner, TColor Color,
 
 void __fastcall FixButtonImage(TButton * Button);
 void __fastcall CenterButtonImage(TButton * Button);
+void __fastcall UncenterButtonImage(TButton * Button);
 
 void __fastcall UpgradeSpeedButton(TSpeedButton * Button);