Browse Source

Merge branch 'master' into dev

Source commit: b981bebd3cf9867dee2c3dad924e0943afec6998
Martin Prikryl 9 years ago
parent
commit
ff9181cbc0

+ 5 - 0
libs/neon/src/ne_auth.c

@@ -1672,11 +1672,16 @@ static void auth_register(ne_session *sess, int isproxy, unsigned protomask,
         ne_uri uri = {0};
         
         if (isproxy)
+        {
             ne_fill_proxy_uri(sess, &uri);
+        }
         else
+        {
             ne_fill_server_uri(sess, &uri);
+        }
 
         ahs->sspi_host = uri.host;
+
         uri.host = NULL;
 
         ne_uri_free(&uri);

+ 2 - 2
source/components/UnixDirView.cpp

@@ -561,7 +561,7 @@ void __fastcall TUnixDirView::DoReadDirectoryImpl(TObject * /*Sender*/, bool Rel
     }
     else
     {
-      Load();
+      Load(true);
       PathChanged();
     }
 
@@ -575,7 +575,7 @@ void __fastcall TUnixDirView::DoReadDirectoryImpl(TObject * /*Sender*/, bool Rel
     // Make sure file list is cleared, to remove all references to invalid
     // file objects. LoadFiles check for disconnected terminal, so no reloading
     // actually occures.
-    Load();
+    Load(true);
   }
 #else
   DebugUsedParam(ReloadOnly);

+ 19 - 1
source/console/Main.cpp

@@ -398,6 +398,7 @@ void Print(const wchar_t* Message)
 //---------------------------------------------------------------------------
 void Print(bool FromBeginning, const wchar_t* Message)
 {
+  size_t Len = wcslen(Message);
   if ((OutputType == FILE_TYPE_DISK) || (OutputType == FILE_TYPE_PIPE))
   {
     if (FromBeginning && (Message[0] != L'\n'))
@@ -431,7 +432,24 @@ void Print(bool FromBeginning, const wchar_t* Message)
     {
       WriteConsole(ConsoleOutput, L"\r", 1, &Written, NULL);
     }
-    WriteConsole(ConsoleOutput, Message, wcslen(Message), &Written, NULL);
+    bool WriteResult =
+      WriteConsole(ConsoleOutput, Message, Len, &Written, NULL);
+    int Error = GetLastError();
+    // The current console font does not support some characters in the message,
+    // fall back to ansi-writting
+    if (!WriteResult && (Error == ERROR_GEN_FAILURE))
+    {
+      int Size = WideCharToMultiByte(CP_ACP, 0, Message, -1, 0, 0, 0, 0);
+      if (Size > 0)
+      {
+        char* Buffer = new char[Size];
+        if (WideCharToMultiByte(CP_ACP, 0, Message, -1, Buffer, Size, 0, 0) > 0)
+        {
+          WriteConsoleA(ConsoleOutput, Buffer, strlen(Buffer), &Written, NULL);
+        }
+        delete[] Buffer;
+      }
+    }
   }
 }
 //---------------------------------------------------------------------------

+ 12 - 2
source/core/Common.cpp

@@ -2140,7 +2140,8 @@ static bool __fastcall DoRecursiveDeleteFile(const UnicodeString FileName, bool
 bool __fastcall RecursiveDeleteFile(const UnicodeString & FileName, bool ToRecycleBin)
 {
   UnicodeString ErrorPath; // unused
-  return DoRecursiveDeleteFile(FileName, ToRecycleBin, ErrorPath);
+  bool Result = DoRecursiveDeleteFile(FileName, ToRecycleBin, ErrorPath);
+  return Result;
 }
 //---------------------------------------------------------------------------
 void __fastcall RecursiveDeleteFileChecked(const UnicodeString & FileName, bool ToRecycleBin)
@@ -3477,7 +3478,16 @@ UnicodeString __fastcall AssemblyNewClassInstanceEnd(TAssemblyLanguage Language,
 //---------------------------------------------------------------------------
 void __fastcall LoadScriptFromFile(UnicodeString FileName, TStrings * Lines)
 {
-  Lines->LoadFromFile(ApiPath(FileName), TEncoding::UTF8);
+  std::auto_ptr<TFileStream> Stream(new TFileStream(ApiPath(FileName), fmOpenRead | fmShareDenyWrite));
+  Lines->DefaultEncoding = TEncoding::UTF8;
+  try
+  {
+    Lines->LoadFromStream(Stream.get());
+  }
+  catch (EEncodingError & E)
+  {
+    throw ExtException(LoadStr(TEXT_FILE_ENCODING), &E);
+  }
 }
 //---------------------------------------------------------------------------
 UnicodeString __fastcall StripEllipsis(const UnicodeString & S)

+ 15 - 0
source/core/Exceptions.cpp

@@ -212,6 +212,21 @@ TStrings * __fastcall ExceptionToMoreMessages(Exception * E)
   return Result;
 }
 //---------------------------------------------------------------------------
+bool __fastcall ExceptionFullMessage(Exception * E, UnicodeString & Message)
+{
+  bool Result = ExceptionMessage(E, Message);
+  if (Result)
+  {
+    Message += L"\n";
+    ExtException * EE = dynamic_cast<ExtException *>(E);
+    if ((EE != NULL) && (EE->MoreMessages != NULL))
+    {
+      Message += EE->MoreMessages->Text + L"\n";
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 UnicodeString __fastcall GetExceptionHelpKeyword(Exception * E)
 {
   UnicodeString HelpKeyword;

+ 1 - 0
source/core/Exceptions.h

@@ -10,6 +10,7 @@
 bool __fastcall ShouldDisplayException(Exception * E);
 bool __fastcall ExceptionMessage(Exception * E, UnicodeString & Message);
 bool __fastcall ExceptionMessageFormatted(Exception * E, UnicodeString & Message);
+bool __fastcall ExceptionFullMessage(Exception * E, UnicodeString & Message);
 UnicodeString __fastcall SysErrorMessageForError(int LastError);
 UnicodeString __fastcall LastSysErrorMessage();
 TStrings * __fastcall ExceptionToMoreMessages(Exception * E);

+ 12 - 12
source/core/FileMasks.cpp

@@ -12,7 +12,7 @@
 #include <StrUtils.hpp>
 //---------------------------------------------------------------------------
 extern const wchar_t IncludeExcludeFileMasksDelimiter = L'|';
-static UnicodeString FileMasksDelimiters = L";,";
+UnicodeString FileMasksDelimiters = L";,";
 static UnicodeString AllFileMasksDelimiters = FileMasksDelimiters + IncludeExcludeFileMasksDelimiter;
 static UnicodeString DirectoryMaskDelimiters = L"/\\";
 static UnicodeString FileMasksDelimiterStr = UnicodeString(FileMasksDelimiters[1]) + L' ';
@@ -974,7 +974,7 @@ bool __fastcall TCustomCommand::FindPattern(const UnicodeString & Command,
     int Len;
     wchar_t APatternCmd;
     GetToken(Command, Index, Len, APatternCmd);
-    if (((PatternCmd != L'!') && (PatternCmd == APatternCmd)) ||
+    if (((PatternCmd != L'!') && (tolower(PatternCmd) == tolower(APatternCmd))) ||
         ((PatternCmd == L'!') && (Len == 1) && (APatternCmd != TEXT_TOKEN)))
     {
       Result = true;
@@ -1170,17 +1170,17 @@ TFileCustomCommand::TFileCustomCommand(const TCustomCommandData & Data,
 int __fastcall TFileCustomCommand::PatternLen(const UnicodeString & Command, int Index)
 {
   int Len;
-  wchar_t PatternCmd = (Index < Command.Length()) ? Command[Index + 1] : L'\0';
+  wchar_t PatternCmd = (Index < Command.Length()) ? tolower(Command[Index + 1]) : L'\0';
   switch (PatternCmd)
   {
-    case L'S':
+    case L's':
     case L'@':
-    case L'U':
-    case L'P':
+    case L'u':
+    case L'p':
     case L'#':
     case L'/':
     case L'&':
-    case L'N':
+    case L'n':
       Len = 2;
       break;
 
@@ -1196,7 +1196,7 @@ bool __fastcall TFileCustomCommand::PatternReplacement(
 {
   // keep consistent with TSessionLog::OpenLogFile
 
-  if (AnsiSameText(Pattern, L"!s"))
+  if (SameText(Pattern, L"!s"))
   {
     Replacement = FData.SessionData->GenerateSessionUrl(sufComplete);
   }
@@ -1204,15 +1204,15 @@ bool __fastcall TFileCustomCommand::PatternReplacement(
   {
     Replacement = FData.SessionData->HostNameExpanded;
   }
-  else if (AnsiSameText(Pattern, L"!u"))
+  else if (SameText(Pattern, L"!u"))
   {
     Replacement = FData.SessionData->UserName;
   }
-  else if (AnsiSameText(Pattern, L"!p"))
+  else if (SameText(Pattern, L"!p"))
   {
     Replacement = FData.SessionData->Password;
   }
-  else if (AnsiSameText(Pattern, L"!#"))
+  else if (SameText(Pattern, L"!#"))
   {
     Replacement = IntToStr(FData.SessionData->PortNumber);
   }
@@ -1226,7 +1226,7 @@ bool __fastcall TFileCustomCommand::PatternReplacement(
     // already delimited
     Delimit = false;
   }
-  else if (AnsiSameText(Pattern, L"!n"))
+  else if (SameText(Pattern, L"!n"))
   {
     Replacement = FData.SessionData->SessionName;
   }

+ 1 - 0
source/core/FileMasks.h

@@ -231,5 +231,6 @@ private:
 };
 //---------------------------------------------------------------------------
 typedef TFileCustomCommand TRemoteCustomCommand;
+extern UnicodeString FileMasksDelimiters;
 //---------------------------------------------------------------------------
 #endif

+ 1 - 1
source/core/HierarchicalStorage.cpp

@@ -1264,7 +1264,7 @@ void __fastcall TIniFileStorage::ApplyOverrides()
   {
     UnicodeString Section = FSections->Strings[i];
 
-    if (AnsiSameText(OverridesKey,
+    if (SameText(OverridesKey,
           Section.SubString(1, OverridesKey.Length())))
     {
       UnicodeString SubKey = Section.SubString(OverridesKey.Length() + 1,

+ 5 - 0
source/core/Http.cpp

@@ -241,3 +241,8 @@ int THttp::NeonServerSSLCallbackImpl(int Failures, const ne_ssl_certificate * Ce
   return (Failures == 0) ? NE_OK : NE_ERROR;
 }
 //---------------------------------------------------------------------------
+bool THttp::IsCertificateError()
+{
+  return !FCertificateError.IsEmpty();
+}
+//---------------------------------------------------------------------------

+ 1 - 0
source/core/Http.h

@@ -20,6 +20,7 @@ public:
 
   void Get();
   void Post(const UnicodeString & Request);
+  bool IsCertificateError();
 
   __property UnicodeString URL = { read = FURL, write = FURL };
   __property UnicodeString ProxyHost = { read = FProxyHost, write = FProxyHost };

+ 2 - 2
source/core/Option.cpp

@@ -122,8 +122,8 @@ bool __fastcall TOptions::FindSwitch(const UnicodeString Switch,
     }
     else if (FOptions[Index].Type == otSwitch)
     {
-      if ((!CaseSensitive && AnsiSameText(FOptions[Index].Name, Switch)) ||
-          (CaseSensitive && AnsiSameStr(FOptions[Index].Name, Switch)))
+      if ((!CaseSensitive && SameText(FOptions[Index].Name, Switch)) ||
+          (CaseSensitive && SameStr(FOptions[Index].Name, Switch)))
       {
         Found = true;
         Value = FOptions[Index].Value;

+ 1 - 1
source/core/RemoteFiles.cpp

@@ -465,7 +465,7 @@ int __fastcall FakeFileImageIndex(UnicodeString FileName, unsigned long Attrs,
   }
   // this should be somewhere else, probably in TUnixDirView,
   // as the "partial" overlay is added there too
-  if (AnsiSameText(UnixExtractFileExt(FileName), PARTIAL_EXT))
+  if (SameText(UnixExtractFileExt(FileName), PARTIAL_EXT))
   {
     static const size_t PartialExtLen = LENOF(PARTIAL_EXT) - 1;
     FileName.SetLength(FileName.Length() - PartialExtLen);

+ 2 - 2
source/core/Script.cpp

@@ -186,7 +186,7 @@ int __fastcall TScriptCommands::FindCommand(TStrings * Commands,
     for (int i = 0; i < Commands->Count; i++)
     {
       if ((Command.Length() <= Commands->Strings[i].Length()) &&
-          AnsiSameText(Command, Commands->Strings[i].SubString(1, Command.Length())))
+          SameText(Command, Commands->Strings[i].SubString(1, Command.Length())))
       {
         if (Matches != NULL)
         {
@@ -1639,7 +1639,7 @@ void __fastcall TScript::OptionImpl(UnicodeString OptionName, UnicodeString Valu
     if (SetValue && !PrintReconnectTime)
     {
       int Value;
-      if (AnsiSameText(ValueName, ToggleNames[ToggleOff]))
+      if (SameText(ValueName, ToggleNames[ToggleOff]))
       {
         Value = 0;
       }

+ 10 - 2
source/core/Security.cpp

@@ -122,7 +122,14 @@ bool WindowsValidateCertificate(const unsigned char * Certificate, size_t Len, U
     CERT_CHAIN_ENGINE_CONFIG ChainConfig;
 
     memset(&ChainConfig, 0, sizeof(ChainConfig));
-    ChainConfig.cbSize = sizeof(CERT_CHAIN_ENGINE_CONFIG);
+    const size_t ChainConfigSize =
+      reinterpret_cast<const char *>(&ChainConfig.CycleDetectionModulus) + sizeof(ChainConfig.CycleDetectionModulus) -
+      reinterpret_cast<const char *>(&ChainConfig);
+    // The hExclusiveRoot and hExclusiveTrustedPeople were added in Windows 7.
+    // The CertGetCertificateChain fails with E_INVALIDARG when we include them to ChainConfig.cbSize.
+    DebugAssert(ChainConfigSize == 40);
+    DebugAssert(ChainConfigSize == sizeof(CERT_CHAIN_ENGINE_CONFIG) - sizeof(ChainConfig.hExclusiveRoot) - sizeof(ChainConfig.hExclusiveTrustedPeople));
+    ChainConfig.cbSize = ChainConfigSize;
     ChainConfig.hRestrictedRoot = NULL;
     ChainConfig.hRestrictedTrust = NULL;
     ChainConfig.hRestrictedOther = NULL;
@@ -134,7 +141,8 @@ bool WindowsValidateCertificate(const unsigned char * Certificate, size_t Len, U
     ChainConfig.CycleDetectionModulus = 0;
 
     HCERTCHAINENGINE ChainEngine;
-    if (CertCreateCertificateChainEngine(&ChainConfig, &ChainEngine))
+    bool ChainEngineResult = CertCreateCertificateChainEngine(&ChainConfig, &ChainEngine);
+    if (ChainEngineResult)
     {
       const CERT_CHAIN_CONTEXT * ChainContext = NULL;
       if (CertGetCertificateChain(ChainEngine, CertContext, NULL, NULL, &ChainPara,

+ 3 - 13
source/core/SessionData.cpp

@@ -111,7 +111,6 @@ void __fastcall TSessionData::Default()
   AuthKIPassword = true;
   AuthGSSAPI = false;
   GSSAPIFwdTGT = false;
-  GSSAPIServerRealm = L"";
   ChangeUsername = false;
   Compression = false;
   SshProt = ssh2only;
@@ -320,7 +319,6 @@ void __fastcall TSessionData::NonPersistant()
   PROPERTY(AuthKIPassword); \
   PROPERTY(AuthGSSAPI); \
   PROPERTY(GSSAPIFwdTGT); \
-  PROPERTY(GSSAPIServerRealm); \
   PROPERTY(DeleteToRecycleBin); \
   PROPERTY(OverwrittenToRecycleBin); \
   PROPERTY(RecycleBinPath); \
@@ -535,7 +533,6 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool & Rewr
   // Both vaclav tomec and official putty use AuthGSSAPI
   AuthGSSAPI = Storage->ReadBool(L"AuthGSSAPI", Storage->ReadBool(L"AuthSSPI", AuthGSSAPI));
   GSSAPIFwdTGT = Storage->ReadBool(L"GSSAPIFwdTGT", Storage->ReadBool(L"GssapiFwd", Storage->ReadBool(L"SSPIFwdTGT", GSSAPIFwdTGT)));
-  GSSAPIServerRealm = Storage->ReadString(L"GSSAPIServerRealm", Storage->ReadString(L"KerbPrincipal", GSSAPIServerRealm));
   ChangeUsername = Storage->ReadBool(L"ChangeUsername", ChangeUsername);
   Compression = Storage->ReadBool(L"Compression", Compression);
   TSshProt ASshProt = (TSshProt)Storage->ReadInteger(L"SshProt", SshProt);
@@ -834,7 +831,6 @@ void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
 
   WRITE_DATA(Bool, AuthGSSAPI);
   WRITE_DATA(Bool, GSSAPIFwdTGT);
-  WRITE_DATA(String, GSSAPIServerRealm);
   Storage->DeleteValue(L"TryGSSKEX");
   Storage->DeleteValue(L"UserNameFromEnvironment");
   Storage->DeleteValue("GSSAPIServerChoosesUserName");
@@ -844,7 +840,6 @@ void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
     // duplicate kerberos setting with keys of the vintela quest putty
     WRITE_DATA_EX(Bool, L"AuthSSPI", AuthGSSAPI, );
     WRITE_DATA_EX(Bool, L"SSPIFwdTGT", GSSAPIFwdTGT, );
-    WRITE_DATA_EX(String, L"KerbPrincipal", GSSAPIServerRealm, );
     // duplicate kerberos setting with keys of the official putty
     WRITE_DATA_EX(Bool, L"GssapiFwd", GSSAPIFwdTGT, );
   }
@@ -1403,7 +1398,7 @@ bool __fastcall TSessionData::IsProtocolUrl(
 //---------------------------------------------------------------------
 bool __fastcall TSessionData::IsSensitiveOption(const UnicodeString & Option)
 {
-  return AnsiSameText(Option, PassphraseOption);
+  return SameText(Option, PassphraseOption);
 }
 //---------------------------------------------------------------------
 bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
@@ -1629,7 +1624,7 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
       {
         UnicodeString ConnectionParam = CutToChar(ConnectionParams, UrlParamSeparator, false);
         UnicodeString ConnectionParamName = CutToChar(ConnectionParam, UrlParamValueSeparator, false);
-        if (AnsiSameText(ConnectionParamName, UrlHostKeyParamName))
+        if (SameText(ConnectionParamName, UrlHostKeyParamName))
         {
           HostKey = ConnectionParam;
           FOverrideCachedHostKey = false;
@@ -1652,7 +1647,7 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
       {
         UnicodeString SessionParam = CutToChar(SessionParams, UrlParamSeparator, false);
         UnicodeString SessionParamName = CutToChar(SessionParam, UrlParamValueSeparator, false);
-        if (AnsiSameText(SessionParamName, UrlSaveParamName))
+        if (SameText(SessionParamName, UrlSaveParamName))
         {
           FSaveOnly = (StrToIntDef(SessionParam, 1) != 0);
         }
@@ -2046,11 +2041,6 @@ void __fastcall TSessionData::SetGSSAPIFwdTGT(bool value)
   SET_SESSION_PROPERTY(GSSAPIFwdTGT);
 }
 //---------------------------------------------------------------------
-void __fastcall TSessionData::SetGSSAPIServerRealm(UnicodeString value)
-{
-  SET_SESSION_PROPERTY(GSSAPIServerRealm);
-}
-//---------------------------------------------------------------------
 void __fastcall TSessionData::SetChangeUsername(bool value)
 {
   SET_SESSION_PROPERTY(ChangeUsername);

+ 1 - 4
source/core/SessionData.h

@@ -98,8 +98,7 @@ private:
   bool FAuthKI;
   bool FAuthKIPassword;
   bool FAuthGSSAPI;
-  bool FGSSAPIFwdTGT; // not supported anymore
-  UnicodeString FGSSAPIServerRealm; // not supported anymore
+  bool FGSSAPIFwdTGT;
   bool FChangeUsername;
   bool FCompression;
   TSshProt FSshProt;
@@ -222,7 +221,6 @@ private:
   void __fastcall SetAuthKIPassword(bool value);
   void __fastcall SetAuthGSSAPI(bool value);
   void __fastcall SetGSSAPIFwdTGT(bool value);
-  void __fastcall SetGSSAPIServerRealm(UnicodeString value);
   void __fastcall SetChangeUsername(bool value);
   void __fastcall SetCompression(bool value);
   void __fastcall SetSshProt(TSshProt value);
@@ -461,7 +459,6 @@ public:
   __property bool AuthKIPassword  = { read=FAuthKIPassword, write=SetAuthKIPassword };
   __property bool AuthGSSAPI  = { read=FAuthGSSAPI, write=SetAuthGSSAPI };
   __property bool GSSAPIFwdTGT = { read=FGSSAPIFwdTGT, write=SetGSSAPIFwdTGT };
-  __property UnicodeString GSSAPIServerRealm = { read=FGSSAPIServerRealm, write=SetGSSAPIServerRealm };
   __property bool ChangeUsername  = { read=FChangeUsername, write=SetChangeUsername };
   __property bool Compression  = { read=FCompression, write=SetCompression };
   __property TSshProt SshProt  = { read=FSshProt, write=SetSshProt };

+ 2 - 2
source/core/SessionInfo.cpp

@@ -1137,8 +1137,8 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
            BooleanToEngStr(Data->AuthKI), BooleanToEngStr(Data->AuthGSSAPI)));
         if (Data->AuthGSSAPI)
         {
-          ADF(L"GSSAPI: Forwarding: %s; Server realm: %s",
-            (BooleanToEngStr(Data->GSSAPIFwdTGT), Data->GSSAPIServerRealm));
+          ADF(L"GSSAPI: Forwarding: %s",
+            (BooleanToEngStr(Data->GSSAPIFwdTGT)));
         }
         ADF(L"Ciphers: %s; Ssh2DES: %s",
           (Data->CipherList, BooleanToEngStr(Data->Ssh2DES)));

+ 1 - 1
source/core/SftpFileSystem.cpp

@@ -2009,7 +2009,7 @@ const TFileSystemInfo & __fastcall TSFTPFileSystem::GetFileSystemInfo(bool /*Ret
 //---------------------------------------------------------------------------
 bool __fastcall TSFTPFileSystem::TemporaryTransferFile(const UnicodeString & FileName)
 {
-  return AnsiSameText(UnixExtractFileExt(FileName), PARTIAL_EXT);
+  return SameText(UnixExtractFileExt(FileName), PARTIAL_EXT);
 }
 //---------------------------------------------------------------------------
 bool __fastcall TSFTPFileSystem::GetStoredCredentialsTried()

+ 21 - 0
source/core/Terminal.cpp

@@ -1116,6 +1116,8 @@ void __fastcall TTerminal::OpenTunnel()
     FTunnelData->TunnelPortFwd = FORMAT(L"L%d\t%s:%d",
       (FTunnelLocalPortNumber, FSessionData->HostNameExpanded, FSessionData->PortNumber));
     FTunnelData->HostKey = FSessionData->TunnelHostKey;
+
+    // inherit proxy options on the main session
     FTunnelData->ProxyMethod = FSessionData->ProxyMethod;
     FTunnelData->ProxyHost = FSessionData->ProxyHost;
     FTunnelData->ProxyPort = FSessionData->ProxyPort;
@@ -1126,6 +1128,25 @@ void __fastcall TTerminal::OpenTunnel()
     FTunnelData->ProxyDNS = FSessionData->ProxyDNS;
     FTunnelData->ProxyLocalhost = FSessionData->ProxyLocalhost;
 
+    // inherit most SSH options of the main session (except for private key and bugs)
+    FTunnelData->Compression = FSessionData->Compression;
+    FTunnelData->SshProt = FSessionData->SshProt;
+    FTunnelData->CipherList = FSessionData->CipherList;
+    FTunnelData->Ssh2DES = FSessionData->Ssh2DES;
+
+    FTunnelData->KexList = FSessionData->KexList;
+    FTunnelData->RekeyData = FSessionData->RekeyData;
+    FTunnelData->RekeyTime = FSessionData->RekeyTime;
+
+    FTunnelData->SshNoUserAuth = FSessionData->SshNoUserAuth;
+    FTunnelData->AuthGSSAPI = FSessionData->AuthGSSAPI;
+    FTunnelData->GSSAPIFwdTGT = FSessionData->GSSAPIFwdTGT;
+    FTunnelData->TryAgent = FSessionData->TryAgent;
+    FTunnelData->AgentFwd = FSessionData->AgentFwd;
+    FTunnelData->AuthTIS = FSessionData->AuthTIS;
+    FTunnelData->AuthKI = FSessionData->AuthKI;
+    FTunnelData->AuthKIPassword = FSessionData->AuthKIPassword;
+
     FTunnelLog = new TSessionLog(this, FTunnelData, Configuration);
     FTunnelLog->Parent = FLog;
     FTunnelLog->Name = L"Tunnel";

+ 12 - 5
source/core/Usage.cpp

@@ -10,6 +10,7 @@
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
 const UnicodeString LastInternalExceptionCounter(L"LastInternalException2");
+const UnicodeString LastUpdateExceptionCounter(L"LastUpdateException");
 //---------------------------------------------------------------------------
 __fastcall TUsage::TUsage(TConfiguration * Configuration)
 {
@@ -162,7 +163,7 @@ void __fastcall TUsage::Reset()
   TGuard Guard(FCriticalSection);
   UpdateLastReport();
   FPeriodCounters.clear();
-  ResetLastInternalException();
+  ResetLastExceptions();
 }
 //---------------------------------------------------------------------------
 void __fastcall TUsage::UpdateCurrentVersion()
@@ -187,22 +188,28 @@ void __fastcall TUsage::UpdateCurrentVersion()
 
     if (PrevVersion != CompoundVersion)
     {
-      ResetLastInternalException();
+      ResetLastExceptions();
     }
   }
   Set(L"CurrentVersion", CompoundVersion);
 }
 //---------------------------------------------------------------------------
-void __fastcall TUsage::ResetLastInternalException()
+void __fastcall TUsage::ResetValue(const UnicodeString & Key)
 {
-  TGuard Guard(FCriticalSection);
-  int Index = FValues->IndexOfName(LastInternalExceptionCounter);
+  int Index = FValues->IndexOfName(Key);
   if (Index >= 0)
   {
     FValues->Delete(Index);
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TUsage::ResetLastExceptions()
+{
+  TGuard Guard(FCriticalSection);
+  ResetValue(LastInternalExceptionCounter);
+  ResetValue(LastUpdateExceptionCounter);
+}
+//---------------------------------------------------------------------------
 void __fastcall TUsage::Inc(const UnicodeString & Key, int Increment)
 {
   if (Collect)

+ 3 - 1
source/core/Usage.h

@@ -51,9 +51,11 @@ private:
   void __fastcall SetMax(const UnicodeString & Key, int Value, TCounters & Counters);
   void __fastcall Serialize(UnicodeString& List,
     const UnicodeString & Name, const TCounters & Counters) const;
-  void __fastcall ResetLastInternalException();
+  void __fastcall ResetLastExceptions();
+  void __fastcall ResetValue(const UnicodeString & Key);
 };
 //---------------------------------------------------------------------------
 extern const UnicodeString LastInternalExceptionCounter;
+extern const UnicodeString LastUpdateExceptionCounter;
 //---------------------------------------------------------------------------
 #endif

+ 99 - 60
source/forms/CustomScpExplorer.cpp

@@ -466,6 +466,11 @@ void __fastcall TCustomScpExplorerForm::CreateHiddenWindow()
   }
 }
 //---------------------------------------------------------------------------
+bool __fastcall TCustomScpExplorerForm::CanConsole()
+{
+  return (Terminal != NULL) && (Terminal->IsCapable[fcAnyCommand] || Terminal->IsCapable[fcSecondaryShell]);
+}
+//---------------------------------------------------------------------------
 bool __fastcall TCustomScpExplorerForm::CanCommandLineFromAnotherInstance()
 {
   bool Result = !NonVisualDataModule->Busy;
@@ -1371,7 +1376,17 @@ void __fastcall TCustomScpExplorerForm::OperationComplete(
   if (GUIConfiguration->BeepOnFinish &&
       (Now() - StartTime > GUIConfiguration->BeepOnFinishAfter))
   {
-    MessageBeep(MB_OK);
+    UnicodeString BeepSound = GUIConfiguration->BeepSound;
+    DWORD Sound;
+    if (!ExtractFileExt(BeepSound).IsEmpty())
+    {
+      Sound = SND_FILENAME;
+    }
+    else
+    {
+      Sound = SND_ALIAS;
+    }
+    PlaySound(BeepSound.c_str(), NULL, Sound | SND_ASYNC);
   }
 }
 //---------------------------------------------------------------------------
@@ -2635,83 +2650,95 @@ void __fastcall TCustomScpExplorerForm::EditNew(TOperationSide Side)
   {
     Name = LoadStr(NEW_FILE);
   }
+  UnicodeString Names = Name;
   std::unique_ptr<TStrings> History(CloneStrings(CustomWinConfiguration->History[L"EditFile"]));
-  if (InputDialog(LoadStr(EDIT_FILE_CAPTION), LoadStr(EDIT_FILE_PROMPT), Name,
+  if (InputDialog(LoadStr(EDIT_FILE_CAPTION), LoadStr(EDIT_FILE_PROMPT), Names,
         HELP_EDIT_NEW, History.get(), true))
   {
-    CustomWinConfiguration->History[L"EditFile"] = History.get();
-    UnicodeString TargetFileName;
-    UnicodeString LocalFileName;
-    UnicodeString RootTempDir;
-    UnicodeString TempDir;
-    UnicodeString RemoteDirectory;
-    if (Side == osRemote)
+    while (!Names.IsEmpty())
     {
-      Name = AbsolutePath(FTerminal->CurrentDirectory, Name);
-
-      TRemoteFile * File = NULL;
-      if (FTerminal->FileExists(Name, &File))
+      Name = CutToChar(Names, FileMasksDelimiters[1], false);
+      CustomWinConfiguration->History[L"EditFile"] = History.get();
+      UnicodeString TargetFileName;
+      UnicodeString LocalFileName;
+      UnicodeString RootTempDir;
+      UnicodeString TempDir;
+      UnicodeString RemoteDirectory;
+      bool ExistingFile = false;
+      if (Side == osRemote)
       {
-        try
+        Name = AbsolutePath(FTerminal->CurrentDirectory, Name);
+
+        TRemoteFile * File = NULL;
+        if (FTerminal->FileExists(Name, &File))
         {
-          ExecuteRemoteFile(Name, File, efDefaultEditor);
-          return;
+          try
+          {
+            ExecuteRemoteFile(Name, File, efDefaultEditor);
+            ExistingFile = true;
+          }
+          __finally
+          {
+            delete File;
+          }
         }
-        __finally
+
+        if (!ExistingFile)
         {
-          delete File;
+          RemoteDirectory = UnixExtractFilePath(Name);
+          TemporaryDirectoryForRemoteFiles(
+            RemoteDirectory, GUIConfiguration->CurrentCopyParam, TempDir, RootTempDir);
+
+          TargetFileName = UnixExtractFileName(Name);
+          TCopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;
+          LocalFileName = TempDir +
+            // We probably do not want to trim the VMS version here
+            FTerminal->ChangeFileName(&CopyParam, TargetFileName, osRemote, false);
         }
       }
-
-      RemoteDirectory = UnixExtractFilePath(Name);
-      TemporaryDirectoryForRemoteFiles(
-        RemoteDirectory, GUIConfiguration->CurrentCopyParam, TempDir, RootTempDir);
-
-      TargetFileName = UnixExtractFileName(Name);
-      TCopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;
-      LocalFileName = TempDir +
-        // We probably do not want to trim the VMS version here
-        FTerminal->ChangeFileName(&CopyParam, TargetFileName, osRemote, false);
-    }
-    else
-    {
-      if (ExtractFilePath(Name).IsEmpty())
-      {
-        LocalFileName = IncludeTrailingBackslash(DirView(Side)->PathName) + Name;
-      }
       else
       {
-        LocalFileName = ExpandFileName(Name);
-      }
+        if (ExtractFilePath(Name).IsEmpty())
+        {
+          LocalFileName = IncludeTrailingBackslash(DirView(Side)->PathName) + Name;
+        }
+        else
+        {
+          LocalFileName = ExpandFileName(Name);
+        }
 
-      TargetFileName = ExtractFileName(Name);
-    }
+        TargetFileName = ExtractFileName(Name);
+      }
 
-    if (!FileExists(ApiPath(LocalFileName)))
-    {
-      int File = FileCreate(ApiPath(LocalFileName));
-      if (File < 0)
+      if (!ExistingFile)
       {
-        if (!RootTempDir.IsEmpty())
+        if (!FileExists(ApiPath(LocalFileName)))
         {
-          RecursiveDeleteFile(ExcludeTrailingBackslash(RootTempDir), false);
+          int File = FileCreate(ApiPath(LocalFileName));
+          if (File < 0)
+          {
+            if (!RootTempDir.IsEmpty())
+            {
+              RecursiveDeleteFile(ExcludeTrailingBackslash(RootTempDir), false);
+            }
+            throw Exception(FMTLOAD(CREATE_FILE_ERROR, (LocalFileName)));
+          }
+          else
+          {
+            FileClose(File);
+          }
         }
-        throw Exception(FMTLOAD(CREATE_FILE_ERROR, (LocalFileName)));
-      }
-      else
-      {
-        FileClose(File);
-      }
-    }
 
-    TExecuteFileBy ExecuteFileBy = efDefaultEditor;
-    const TEditorData * ExternalEditor = NULL;
-    TFileMasks::TParams MaskParams; // size not known
-    ExecuteFileNormalize(ExecuteFileBy, ExternalEditor, TargetFileName,
-      false, MaskParams);
+        TExecuteFileBy ExecuteFileBy = efDefaultEditor;
+        const TEditorData * ExternalEditor = NULL;
+        TFileMasks::TParams MaskParams; // size not known
+        ExecuteFileNormalize(ExecuteFileBy, ExternalEditor, TargetFileName,
+          false, MaskParams);
 
-    CustomExecuteFile(Side, ExecuteFileBy, LocalFileName, TargetFileName,
-      ExternalEditor, RootTempDir, RemoteDirectory);
+        CustomExecuteFile(Side, ExecuteFileBy, LocalFileName, TargetFileName,
+          ExternalEditor, RootTempDir, RemoteDirectory);
+      }
+    }
   }
 }
 //---------------------------------------------------------------------------
@@ -4922,6 +4949,8 @@ void __fastcall TCustomScpExplorerForm::Synchronize(const UnicodeString LocalDir
   BatchStart(BatchStorage);
   FAutoOperation = true;
 
+  bool AnyOperation = false;
+  TDateTime StartTime = Now();
   TSynchronizeChecklist * AChecklist = NULL;
   try
   {
@@ -4944,6 +4973,12 @@ void __fastcall TCustomScpExplorerForm::Synchronize(const UnicodeString LocalDir
       FSynchronizeProgressForm->Start();
     }
 
+    for (int Index = 0; !AnyOperation && (Index < AChecklist->Count); Index++)
+    {
+      AnyOperation = AChecklist->Item[Index]->Checked;
+    }
+
+    // No need to call if !AnyOperation
     Terminal->SynchronizeApply(AChecklist, LocalDirectory, RemoteDirectory,
       &CopyParam, Params | spNoConfirmation, TerminalSynchronizeDirectory);
   }
@@ -4962,6 +4997,10 @@ void __fastcall TCustomScpExplorerForm::Synchronize(const UnicodeString LocalDir
     SAFE_DESTROY(FSynchronizeProgressForm);
     BatchEnd(BatchStorage);
     ReloadLocalDirectory();
+    if (AnyOperation)
+    {
+      OperationComplete(StartTime);
+    }
   }
 }
 //---------------------------------------------------------------------------
@@ -7358,7 +7397,7 @@ void __fastcall TCustomScpExplorerForm::DirViewGetOverlay(
     Ext = ExtractFileExt(DirView->ItemFileName(Item));
   }
 
-  if (AnsiSameText(Ext, Configuration->PartialExt))
+  if (SameText(Ext, Configuration->PartialExt))
   {
     Indexes |= oiPartial;
   }

+ 1 - 0
source/forms/CustomScpExplorer.h

@@ -678,6 +678,7 @@ public:
   void __fastcall UpdateTaskbarList(ITaskbarList3 * TaskbarList);
   virtual void __fastcall DisplaySystemContextMenu();
   virtual void __fastcall GoToAddress() = 0;
+  bool __fastcall CanConsole();
 
   __property bool ComponentVisible[Byte Component] = { read = GetComponentVisible, write = SetComponentVisible };
   __property bool EnableFocusedOperation[TOperationSide Side] = { read = GetEnableFocusedOperation, index = 0 };

+ 1 - 1
source/forms/NonVisual.cpp

@@ -435,7 +435,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
   UPD(CompareDirectoriesAction, HasTerminal)
   UPD(SynchronizeAction, HasTerminal)
   UPD(FullSynchronizeAction, HasTerminal)
-  UPD(ConsoleAction, HasTerminal && (ScpExplorer->Terminal->IsCapable[fcAnyCommand] || ScpExplorer->Terminal->IsCapable[fcSecondaryShell]))
+  UPD(ConsoleAction, ScpExplorer->CanConsole())
   UPD(PuttyAction, HasTerminal && TTerminalManager::Instance()->CanOpenInPutty())
   UPD(SynchronizeBrowsingAction, HasTerminal)
   UPD(CloseApplicationAction, true)

+ 2 - 2
source/forms/ScpCommander.cpp

@@ -539,7 +539,7 @@ void __fastcall TScpCommanderForm::LocalDefaultDirectory()
   }
   catch(Exception & E)
   {
-    Terminal->ShowExtendedException(&E);
+    ShowExtendedException(NULL, &E);
     LocalDirView->Path = ExtractFilePath(Application->ExeName);
   }
 }
@@ -818,7 +818,7 @@ void __fastcall TScpCommanderForm::UpdateControls()
     UpdateToolbar2ItemCaption(CurrentMoveToolbar2Item);
   }
 
-  CommandLineCombo->Enabled = (Terminal != NULL);
+  CommandLineCombo->Enabled = CanConsole();
   CommandLinePromptLabel->Enabled = CommandLineCombo->Enabled;
 }
 //---------------------------------------------------------------------------

+ 10 - 6
source/packages/filemng/CustomDirView.pas

@@ -326,12 +326,12 @@ type
     procedure DoDisplayPropertiesMenu;
     procedure DoExecute(Item: TListItem);
     procedure DoExecuteParentDirectory;
+    procedure Load(DoFocusSomething: Boolean); virtual;
     property ImageList16: TImageList read FImageList16;
     property ImageList32: TImageList read FImageList32;
   public
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
-    procedure Load; virtual;
     procedure Reload(CacheIcons: Boolean); virtual;
     function CreateFocusedFileList(FullPath: Boolean; FileList: TStrings = nil): TStrings;
     function CreateFileList(Focused: Boolean; FullPath: Boolean; FileList: TStrings = nil): TStrings;
@@ -1795,7 +1795,7 @@ begin
         end;
       end;
 
-      Load;
+      Load(False);
 
       OldSelection.Sort;
       if CacheIcons then IconCache.Sort;
@@ -1841,8 +1841,9 @@ begin
       FocusItem(ItemToFocus);
     end;
 
-    // cannot scroll when focus is not visible because
-    // of hack-implementation of FocusItem()
+    // could not scroll when focus is not visible because
+    // of previous hack-implementation of FocusItem()
+    // - no longer true, this can be re-enabled after some testing
     {$IF False}
     // previously focus item was not visible, scroll to the same position
     // as before
@@ -1864,7 +1865,7 @@ begin
   end;
 end;
 
-procedure TCustomDirView.Load;
+procedure TCustomDirView.Load(DoFocusSomething: Boolean);
 var
   SaveCursor: TCursor;
   Delimiters: string;
@@ -1943,7 +1944,10 @@ begin
 
         FNotifyEnabled := True;
 
-        FocusSomething;
+        if DoFocusSomething then
+        begin
+          FocusSomething;
+        end;
 
         if Assigned(FOnLoaded) then
         begin

+ 6 - 26
source/packages/filemng/DirView.pas

@@ -237,6 +237,7 @@ type
     procedure StartFileDeleteThread;
     procedure WMDestroy(var Msg: TWMDestroy); message WM_DESTROY;
     procedure CMRecreateWnd(var Message: TMessage); message CM_RECREATEWND;
+    procedure Load(DoFocusSomething: Boolean); override;
     function HiddenCount: Integer; override;
     function FilteredCount: Integer; override;
 
@@ -300,7 +301,6 @@ type
     function GetFileRec(Index: Integer): PFileRec;
 
     {Populate / repopulate the filelist:}
-    procedure Load; override;
     procedure Reload(CacheIcons : Boolean); override;
     procedure Reload2;
 
@@ -805,7 +805,7 @@ begin
       SetLength(Value, Length(Value) - 1);
     PathChanging(True);
     FPath := Value;
-    Load;
+    Load(True);
   finally
     PathChanged;
   end;
@@ -1163,7 +1163,7 @@ begin
   end;
 end;
 
-procedure TDirView.Load;
+procedure TDirView.Load(DoFocusSomething: Boolean);
 begin
   try
     StopIconUpdateThread;
@@ -2705,7 +2705,6 @@ procedure TDirView.ExecuteFile(Item: TListItem);
 var
   DefDir: string;
   FileName: string;
-  Node: TTreeNode;
 begin
   if (UpperCase(PFileRec(Item.Data)^.FileExt) = 'LNK') or
      PFileRec(Item.Data)^.IsDirectory then
@@ -2727,27 +2726,8 @@ begin
 
     if DirExists(FileName) then
     begin
-      if Assigned(FDriveView) then
-        with TDriveView(FDriveView) do
-        begin
-          Node := FindNodeToPath(FileName);
-          if not Assigned(Node) then
-          begin
-            ValidateDirectory(GetDriveStatus(FileName[1]).RootNode);
-            Node := FindNodeToPath(FileName);
-          end;
-          if Assigned(Node) then
-          begin
-            Directory := FileName;
-            CenterNode(Selected);
-          end;
-          Exit;
-        end
-      else
-      begin
-        Path := FileName;
-        Exit;
-      end;
+      Path := FileName;
+      Exit;
     end
       else
     if not FileExists(ApiPath(FileName)) then
@@ -2813,7 +2793,7 @@ begin
   try
     PathChanging(False);
     FPath := ExtractFileDrive(Path);
-    Load;
+    Load(True);
   finally
     PathChanged;
   end;

+ 14 - 14
source/packages/my/ListViewColProperties.pas

@@ -277,6 +277,7 @@ begin
     for Index := 0 to Count - 1 do
       GetProperties(Index).Order := -1;
 
+    // First order invisible columns (not True), then visible (not not True)
     Phase := True;
     Order := 0;
 
@@ -294,19 +295,19 @@ begin
           Inc(Order);
         end;
       end;
-    until Phase;
 
-    // this does not make sure hidden columns are first,
-    // but it gets fixed on the next run
-    for Index := 0 to Count - 1 do
-    begin
-      Properties := GetProperties(Index);
-      if Properties.Order < 0 then
+      // add missing columns from the same visibility class
+      for Index := 0 to Count - 1 do
       begin
-        Properties.Order := Order;
-        Inc(Order);
+        Properties := GetProperties(Index);
+        if (Properties.Visible = Phase) and
+           (Properties.Order < 0) then
+        begin
+          Properties.Order := Order;
+          Inc(Order);
+        end;
       end;
-    end;
+    until Phase;
 
     if ColumnsExists then
       UpdateListViewOrder;
@@ -325,12 +326,11 @@ begin
   S := CutToChar(Value, '|', True);
   WidthsStr := CutToChar(S, '@', True);
   PixelsPerInch := LoadPixelsPerInch(S);
+  SetWidthsStr(WidthsStr, PixelsPerInch);
+  // Have to set order after visibility, otherwise we lost ordering of columns that are invisible by default,
+  // but visible by configuration (as they would get ordered to the front)
   OrderStr := CutToChar(Value, '|', True);
-  // set first orders, only than the widths/visibility,
-  // as setting visibility can reorder hidden/visible columns
-  // as needed, while setting order cannot ensure this
   SetOrderStr(OrderStr);
-  SetWidthsStr(WidthsStr, PixelsPerInch);
 end;
 
 procedure TCustomListViewColProperties.SetVisible(Index: Integer; Value: Boolean);

+ 9 - 71
source/packages/my/NortonLikeListView.pas

@@ -35,7 +35,6 @@ type
     FLButtonDownShiftState: TShiftState;
     FLButtonDownPos: TPoint;
     FLastSelectMethod: TSelectMethod;
-    FPendingInternalFocus: TListItem;
     procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
     procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
     procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
@@ -80,7 +79,6 @@ type
     function GetSelCount: Integer; override;
     procedure DDBeforeDrag;
     function CanEdit(Item: TListItem): Boolean; override;
-    procedure DoEnter; override;
   public
     { Public declarations }
     constructor Create(AOwner: TComponent); override;
@@ -126,7 +124,6 @@ begin
   FUpdatingSelection := 0;
   FFocusingItem := False;
   FLastSelectMethod := smNoneYet;
-  FPendingInternalFocus := nil;
   // On Windows Vista, native GetNextItem for selection stops working once we
   // disallow deselecting any item (see ExCanChange).
   // So we need to manage selection state ourselves
@@ -223,10 +220,6 @@ begin
   begin
     ItemUnselected(Item, -1);
   end;
-  if FPendingInternalFocus = Item then
-  begin
-    FPendingInternalFocus := nil;
-  end;
   FLastDeletedItem := Item;
   inherited;
   FLastDeletedItem := nil;
@@ -605,71 +598,16 @@ begin
 end;
 
 procedure TCustomNortonLikeListView.FocusItem(Item: TListItem);
-var
-  P: TPoint;
-  PLastSelectMethod: TSelectMethod;
-  PDontUnSelectItem: Boolean;
-  PDontSelectItem: Boolean;
-  WParam: UINT_PTR;
-  LParam: INT_PTR;
-begin
-  // This whole is replacement for mere ItemFocused := Item
-  // because that does not reset some internal focused pointer,
-  // causing subsequent Shift-Click selects range from the first item,
-  // not from focused item.
-  Item.MakeVisible(False);
-  if Focused then
-  begin
-    P := Item.GetPosition;
-    PLastSelectMethod := FLastSelectMethod;
-    PDontSelectItem := FDontSelectItem;
-    PDontUnSelectItem := FDontUnSelectItem;
-    FLastSelectMethod := smNoneYet;
-    FDontSelectItem := True;
-    FDontUnSelectItem := True;
-    FFocusingItem := True;
-    try
-      // HACK
-      // WM_LBUTTONDOWN enters loop, waiting for WM_LBUTTONUP,
-      // so we have to post it in advance to break the loop immediately
-
-      // Without MK_CONTROL, if there are more items selected,
-      // they won't get unselected on subsequent focus change
-      // (with explorer-style selection).
-      // And it also makes the click the least obtrusive, affecting the focused
-      // file only.
-      WParam := MK_LBUTTON or MK_CONTROL;
-      LParam := MAKELPARAM(P.X, P.Y);
-      PostMessage(Handle, WM_LBUTTONUP, WParam, LParam);
-      SendMessage(Handle, WM_LBUTTONDOWN, WParam, LParam);
-    finally
-      FFocusingItem := False;
-      FLastSelectMethod := PLastSelectMethod;
-      FDontSelectItem := PDontSelectItem;
-      FDontUnSelectItem := PDontUnSelectItem;
-    end;
-    FPendingInternalFocus := nil;
-  end
-    else
-  begin
-    FPendingInternalFocus := Item;
-  end;
-  if ItemFocused <> Item then
-    ItemFocused := Item;
-end;
-
-procedure TCustomNortonLikeListView.DoEnter;
 begin
-  inherited;
-
-  if Assigned(FPendingInternalFocus) then
-  begin
-    if FPendingInternalFocus = ItemFocused then
-    begin
-      FocusItem(FPendingInternalFocus);
-    end;
-    FPendingInternalFocus := nil;
-  end;
+  // This method was introduced in 3.7.6 for reasons long forgotten.
+  // It simulated a mouse click on the item. Possibly because the mere ItemFocused := Item
+  // did not work due to at-the-time-not-realized conflict with FocusSomething.
+  // Now that this is fixed, the method is no longer needed.
+  // Keeping it for a while with this comment, in case some regression is discovered.
+  // References:
+  // - 3.7.6: When reloading directory content, file panel tries to preserve its position.
+  // - Bugs 999 and 1161
+  ItemFocused := Item;
 end;
 
 procedure TCustomNortonLikeListView.SelectAll(Mode: TSelectMode; Exclude: TListItem);

+ 7 - 0
source/putty/ssh.c

@@ -9634,6 +9634,9 @@ static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen,
 		    logevent("Further authentication required");
 		}
 
+#ifdef MPEXT	
+		logeventf(ssh, "Server offered these authentication methods: %s", methods);
+#endif
 		s->can_pubkey =
 		    in_commasep_string("publickey", methods, methlen);
 		s->can_passwd =
@@ -10092,7 +10095,11 @@ static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen,
 		}
 #endif
 		s->gss_stat = s->gsslib->import_name(s->gsslib,
+#ifdef MPEXT
+						     fullhostname,
+#else
 						     ssh->fullhostname,
+#endif
 						     &s->gss_srv_name);
 		if (s->gss_stat != SSH_GSS_OK) {
 		    if (s->gss_stat == SSH_GSS_BAD_HOST_NAME)

+ 1 - 0
source/resource/TextsCore.h

@@ -452,6 +452,7 @@
 #define CODE_CONNECT            551
 #define CODE_PS_ADD_TYPE        553
 #define COPY_INFO_PRESERVE_TIME_DIRS 554
+#define TEXT_FILE_ENCODING      555
 
 #define CORE_VARIABLE_STRINGS   600
 #define PUTTY_BASED_ON          601

+ 1 - 0
source/resource/TextsCore1.rc

@@ -422,6 +422,7 @@ BEGIN
   CODE_CONNECT, "Connect"
   CODE_PS_ADD_TYPE, "Load WinSCP .NET assembly"
   COPY_INFO_PRESERVE_TIME_DIRS, "%s (including directories)"
+  TEXT_FILE_ENCODING, "The file must be in UTF-8 or UTF-16 encoding."
 
   CORE_VARIABLE_STRINGS, "CORE_VARIABLE"
   PUTTY_BASED_ON, "SSH and SCP code based on PuTTY %s"

+ 2 - 17
source/windows/ConsoleRunner.cpp

@@ -39,21 +39,6 @@ void TrimNewLine(UnicodeString & Str)
   }
 }
 //---------------------------------------------------------------------------
-static bool __fastcall ExceptionConsoleMessage(Exception * E, UnicodeString & Message)
-{
-  bool Result = ExceptionMessage(E, Message);
-  if (Result)
-  {
-    Message += L"\n";
-    ExtException * EE = dynamic_cast<ExtException *>(E);
-    if ((EE != NULL) && (EE->MoreMessages != NULL))
-    {
-      Message += EE->MoreMessages->Text + L"\n";
-    }
-  }
-  return Result;
-}
-//---------------------------------------------------------------------------
 class TConsole
 {
 public:
@@ -1796,7 +1781,7 @@ void __fastcall TConsoleRunner::DoShowException(TTerminal * Terminal, Exception
   }
 
   UnicodeString Message;
-  if (ExceptionConsoleMessage(E, Message))
+  if (ExceptionFullMessage(E, Message))
   {
     FCommandError = true;
     PrintMessage(Message);
@@ -2294,7 +2279,7 @@ void __fastcall BatchSettings(TConsole * Console, TProgramParams * Params)
 static int __fastcall HandleException(TConsole * Console, Exception & E)
 {
   UnicodeString Message;
-  if (ExceptionConsoleMessage(&E, Message))
+  if (ExceptionFullMessage(&E, Message))
   {
     Console->Print(Message);
   }

+ 2 - 0
source/windows/GUIConfiguration.cpp

@@ -568,6 +568,7 @@ void __fastcall TGUIConfiguration::Default()
   FPuttySession = L"WinSCP temporary session";
   FBeepOnFinish = false;
   FBeepOnFinishAfter = TDateTime(0, 0, 30, 0);
+  FBeepSound = L"SystemDefault";
   FCopyParamCurrent = L"";
   FKeepUpToDateChangeDelay = 500;
   FChecksumAlg = L"sha1";
@@ -643,6 +644,7 @@ void __fastcall TGUIConfiguration::UpdateStaticUsage()
     KEY(DateTime, IgnoreCancelBeforeFinish); \
     KEY(Bool,     BeepOnFinish); \
     KEY(DateTime, BeepOnFinishAfter); \
+    KEY(String,   BeepSound); \
     KEY(Integer,  KeepUpToDateChangeDelay); \
     KEY(String,   ChecksumAlg); \
     KEY(Integer,  SessionReopenAutoIdle); \

+ 2 - 0
source/windows/GUIConfiguration.h

@@ -169,6 +169,7 @@ private:
   TGUICopyParamType FDefaultCopyParam;
   bool FBeepOnFinish;
   TDateTime FBeepOnFinishAfter;
+  UnicodeString FBeepSound;
   UnicodeString FDefaultPuttyPathOnly;
   UnicodeString FDefaultPuttyPath;
   TCopyParamList * FCopyParamList;
@@ -256,6 +257,7 @@ public:
   __property TGUICopyParamType DefaultCopyParam = { read = FDefaultCopyParam, write = SetDefaultCopyParam };
   __property bool BeepOnFinish = { read = FBeepOnFinish, write = FBeepOnFinish };
   __property TDateTime BeepOnFinishAfter = { read = FBeepOnFinishAfter, write = FBeepOnFinishAfter };
+  __property UnicodeString BeepSound = { read = FBeepSound, write = FBeepSound };
   __property const TCopyParamList * CopyParamList = { read = GetCopyParamList, write = SetCopyParamList };
   __property UnicodeString CopyParamCurrent = { read = FCopyParamCurrent, write = SetCopyParamCurrent };
   __property int CopyParamIndex = { read = GetCopyParamIndex, write = SetCopyParamIndex };

+ 56 - 26
source/windows/Setup.cpp

@@ -605,6 +605,7 @@ static void __fastcall RegisterForDefaultPrograms()
   {
     try
     {
+      // Maybe we should skip this if HKLM key existed already (we are running non-privileged)
       RegisterProtocolsForDefaultPrograms(HKEY_CURRENT_USER);
     }
     catch (Exception & E)
@@ -669,7 +670,20 @@ void __fastcall LaunchAdvancedAssociationUI()
 
   if (IsWin10())
   {
-    ExecuteShell(L"control.exe", L"/name Microsoft.DefaultPrograms /page pageDefaultProgram");
+    // WORKAROUND: On Windows 10, the IApplicationAssociationRegistrationUI::LaunchAdvancedAssociationUI does not work.
+    // http://stackoverflow.com/q/32178986/850848
+    // This approach (IOpenControlPanel::Open) works on Windows 7 too, but not on Windows Vista.
+    IOpenControlPanel * OpenControlPanel;
+
+    HRESULT Result =
+      CoCreateInstance(CLSID_OpenControlPanel,
+        NULL, CLSCTX_INPROC, __uuidof(IOpenControlPanel), (void**)&OpenControlPanel);
+    if (SUCCEEDED(Result))
+    {
+      UnicodeString Page = FORMAT(L"pageDefaultProgram\\pageAdvancedSettings?pszAppName=%s", (AppNameString()));
+      OpenControlPanel->Open(L"Microsoft.DefaultPrograms", Page.c_str(), NULL);
+      OpenControlPanel->Release();
+    }
   }
   else
   {
@@ -892,15 +906,26 @@ static bool __fastcall DoQueryUpdates(TUpdatesConfiguration & Updates, bool Coll
     CheckForUpdatesHTTP->URL = URL;
     // sanity check
     CheckForUpdatesHTTP->ResponseLimit = 102400;
-    if (CollectUsage)
+    try
     {
-      UnicodeString Usage = GetUsageData();
+      if (CollectUsage)
+      {
+        UnicodeString Usage = GetUsageData();
 
-      CheckForUpdatesHTTP->Post(Usage);
+        CheckForUpdatesHTTP->Post(Usage);
+      }
+      else
+      {
+        CheckForUpdatesHTTP->Get();
+      }
     }
-    else
+    catch (...)
     {
-      CheckForUpdatesHTTP->Get();
+      if (CheckForUpdatesHTTP->IsCertificateError())
+      {
+        Configuration->Usage->Inc(L"UpdateCertificateErrors");
+      }
+      throw;
     }
     Response = CheckForUpdatesHTTP->Response;
   }
@@ -922,7 +947,7 @@ static bool __fastcall DoQueryUpdates(TUpdatesConfiguration & Updates, bool Coll
   {
     UnicodeString Line = CutToChar(Response, L'\n', false);
     UnicodeString Name = CutToChar(Line, L'=', false);
-    if (AnsiSameText(Name, "Version"))
+    if (SameText(Name, "Version"))
     {
       int NewVersion = StrToCompoundVersion(Line);
       Changed |= (NewVersion != PrevResults.Version);
@@ -933,45 +958,45 @@ static bool __fastcall DoQueryUpdates(TUpdatesConfiguration & Updates, bool Coll
       Updates.Results.Version = NewVersion;
       Complete = true;
     }
-    else if (AnsiSameText(Name, L"Message"))
+    else if (SameText(Name, L"Message"))
     {
       Changed |= (PrevResults.Message != Line);
       Updates.Results.Message = Line;
     }
-    else if (AnsiSameText(Name, L"Critical"))
+    else if (SameText(Name, L"Critical"))
     {
       bool NewCritical = (StrToIntDef(Line, 0) != 0);
       Changed |= (PrevResults.Critical != NewCritical);
       Updates.Results.Critical = NewCritical;
     }
-    else if (AnsiSameText(Name, L"Release"))
+    else if (SameText(Name, L"Release"))
     {
       Changed |= (PrevResults.Release != Line);
       Updates.Results.Release = Line;
     }
-    else if (AnsiSameText(Name, L"Disabled"))
+    else if (SameText(Name, L"Disabled"))
     {
       bool NewDisabled = (StrToIntDef(Line, 0) != 0);
       Changed |= (PrevResults.Disabled != NewDisabled);
       Updates.Results.Disabled = NewDisabled;
       Complete = true;
     }
-    else if (AnsiSameText(Name, L"Url"))
+    else if (SameText(Name, L"Url"))
     {
       Changed |= (PrevResults.Url != Line);
       Updates.Results.Url = Line;
     }
-    else if (AnsiSameText(Name, L"UrlButton"))
+    else if (SameText(Name, L"UrlButton"))
     {
       Changed |= (PrevResults.UrlButton != Line);
       Updates.Results.UrlButton = Line;
     }
-    else if (AnsiSameText(Name, L"NewsUrl"))
+    else if (SameText(Name, L"NewsUrl"))
     {
       Changed |= (PrevResults.NewsUrl != Line);
       Updates.Results.NewsUrl = Line;
     }
-    else if (AnsiSameText(Name, L"NewsSize"))
+    else if (SameText(Name, L"NewsSize"))
     {
       TSize NewsSize;
       NewsSize.Width = StrToIntDef(CutToChar(Line, L',', true), 0);
@@ -979,48 +1004,48 @@ static bool __fastcall DoQueryUpdates(TUpdatesConfiguration & Updates, bool Coll
       Changed |= (PrevResults.NewsSize != NewsSize);
       Updates.Results.NewsSize = NewsSize;
     }
-    else if (AnsiSameText(Name, L"DownloadUrl"))
+    else if (SameText(Name, L"DownloadUrl"))
     {
       Changed |= (PrevResults.DownloadUrl != Line);
       Updates.Results.DownloadUrl = Line;
     }
-    else if (AnsiSameText(Name, L"DownloadSize"))
+    else if (SameText(Name, L"DownloadSize"))
     {
       Updates.Results.DownloadSize = StrToInt64Def(Line, 0);
     }
-    else if (AnsiSameText(Name, L"DownloadSha256"))
+    else if (SameText(Name, L"DownloadSha256"))
     {
       Updates.Results.DownloadSha256 = Line;
     }
-    else if (AnsiSameText(Name, L"AuthenticationError"))
+    else if (SameText(Name, L"AuthenticationError"))
     {
       Changed |= (PrevResults.AuthenticationError != Line);
       Updates.Results.AuthenticationError = Line;
     }
-    else if (AnsiSameText(Name, L"OpenGettingStarted"))
+    else if (SameText(Name, L"OpenGettingStarted"))
     {
       Updates.Results.OpenGettingStarted = (StrToIntDef(Line, 0) != 0);
     }
-    else if (AnsiSameText(Name, L"DownloadingUrl"))
+    else if (SameText(Name, L"DownloadingUrl"))
     {
       Updates.Results.DownloadingUrl = Line;
     }
-    else if (AnsiSameText(Name, L"TipsSize"))
+    else if (SameText(Name, L"TipsSize"))
     {
       TSize TipsSize;
       TipsSize.Width = StrToIntDef(CutToChar(Line, L',', true), 0);
       TipsSize.Height = StrToIntDef(CutToChar(Line, L',', true), 0);
       Updates.Results.TipsSize = TipsSize;
     }
-    else if (AnsiSameText(Name, L"TipsUrl"))
+    else if (SameText(Name, L"TipsUrl"))
     {
       Updates.Results.TipsUrl = Line;
     }
-    else if (AnsiSameText(Name, L"Tips"))
+    else if (SameText(Name, L"Tips"))
     {
       Updates.Results.Tips = Line;
     }
-    else if (AnsiSameText(Name, L"TipsIntervalDays"))
+    else if (SameText(Name, L"TipsIntervalDays"))
     {
       int TipsIntervalDays = StrToIntDef(Line, Updates.Results.TipsIntervalDays);
       if (TipsIntervalDays < 0)
@@ -1029,7 +1054,7 @@ static bool __fastcall DoQueryUpdates(TUpdatesConfiguration & Updates, bool Coll
       }
       Updates.Results.TipsIntervalDays = TipsIntervalDays;
     }
-    else if (AnsiSameText(Name, L"TipsIntervalRuns"))
+    else if (SameText(Name, L"TipsIntervalRuns"))
     {
       int TipsIntervalRuns = StrToIntDef(Line, Updates.Results.TipsIntervalRuns);
       if (TipsIntervalRuns < 0)
@@ -1074,6 +1099,11 @@ static void __fastcall DoQueryUpdates(bool CollectUsage)
   catch(Exception & E)
   {
     Configuration->Usage->Inc(L"UpdateChecksFailed");
+    UnicodeString Message;
+    if (DebugAlwaysTrue(ExceptionFullMessage(&E, Message)))
+    {
+      Configuration->Usage->Set(LastUpdateExceptionCounter, Message);
+    }
     throw ExtException(&E, MainInstructions(LoadStr(CHECK_FOR_UPDATES_ERROR)));
   }
 }

+ 1 - 1
source/windows/UserInterface.cpp

@@ -38,7 +38,7 @@ TConfiguration * __fastcall CreateConfiguration()
   UnicodeString IniFileName = Params->SwitchValue(INI_SWITCH);
   if (!IniFileName.IsEmpty())
   {
-    if (AnsiSameText(IniFileName, INI_NUL))
+    if (SameText(IniFileName, INI_NUL))
     {
       WinConfiguration->SetNulStorage();
     }

+ 1 - 1
source/windows/WinConfiguration.cpp

@@ -1445,7 +1445,7 @@ void __fastcall TWinConfiguration::AddVersionToHistory()
 bool __fastcall TWinConfiguration::DoIsBeta(const UnicodeString & ReleaseType)
 {
   // What about "Development" release type?
-  return AnsiSameText(ReleaseType, L"beta") || AnsiSameText(ReleaseType, L"rc");
+  return SameText(ReleaseType, L"beta") || SameText(ReleaseType, L"rc");
 }
 //---------------------------------------------------------------------------
 bool __fastcall TWinConfiguration::GetIsBeta()