Martin Prikryl 10 years ago
parent
commit
674a512d79

+ 1 - 1
dotnet/properties/AssemblyInfo.cs

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

+ 1 - 1
source/Console.cbproj

@@ -65,7 +65,7 @@
 			<ProjectType>CppConsoleApplication</ProjectType>
 			<SanitizedProjectName>Console</SanitizedProjectName>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.1.0.0;InternalName=console;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.7.2.0;ReleaseType=stable;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.1.0.0;InternalName=console;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.7.3.0;ReleaseType=stable;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>4</VerInfo_MajorVer>
 			<VerInfo_MinorVer>1</VerInfo_MinorVer>

+ 1 - 1
source/DragExt.cbproj

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

+ 2 - 2
source/DragExt64.rc

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

+ 2 - 2
source/WinSCP.cbproj

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

+ 10 - 0
source/core/Common.cpp

@@ -96,6 +96,16 @@ void __fastcall Shred(UnicodeString & Str)
   }
 }
 //---------------------------------------------------------------------------
+UnicodeString AnsiToString(const RawByteString & S)
+{
+  return UnicodeString(AnsiString(S));
+}
+//---------------------------------------------------------------------------
+UnicodeString AnsiToString(const char * S, size_t Len)
+{
+  return UnicodeString(AnsiString(S, Len));
+}
+//---------------------------------------------------------------------------
 UnicodeString MakeValidFileName(UnicodeString FileName)
 {
   UnicodeString IllegalChars = L":;,=+<>|\"[] \\/?*";

+ 2 - 0
source/core/Common.h

@@ -35,6 +35,8 @@ UnicodeString DeleteChar(UnicodeString Str, wchar_t C);
 void PackStr(UnicodeString &Str);
 void PackStr(RawByteString &Str);
 void __fastcall Shred(UnicodeString & Str);
+UnicodeString AnsiToString(const RawByteString & S);
+UnicodeString AnsiToString(const char * S, size_t Len);
 UnicodeString MakeValidFileName(UnicodeString FileName);
 UnicodeString RootKeyToStr(HKEY RootKey);
 UnicodeString BooleanToStr(bool B);

+ 25 - 5
source/core/FtpFileSystem.cpp

@@ -2070,7 +2070,7 @@ void __fastcall TFTPFileSystem::DirectorySource(const UnicodeString DirectoryNam
       // ignore non-fatal error when the directory already exists
       bool Rethrow =
         !FTerminal->Active ||
-        !FTerminal->FileExists(UnixExcludeTrailingBackslash(DestFullName), &File) ||
+        !FTerminal->FileExists(DestFullName, &File) ||
         !File->IsDirectory;
       delete File;
       if (Rethrow)
@@ -2407,6 +2407,8 @@ void __fastcall TFTPFileSystem::AutoDetectTimeDifference(TRemoteFileList * FileL
       // Does not support MLST/MLSD, but supports MDTM at least
       !FFileZillaIntf->UsingMlsd() && SupportsReadingFile())
   {
+    FTerminal->LogEvent(L"Detecting timezone difference...");
+
     for (int Index = 0; Index < FileList->Count; Index++)
     {
       TRemoteFile * File = FileList->Files[Index];
@@ -2429,6 +2431,7 @@ void __fastcall TFTPFileSystem::AutoDetectTimeDifference(TRemoteFileList * FileL
           {
             throw;
           }
+          FTerminal->LogEvent(FORMAT(L"Failed to retrieve file %s attributes to detect timezone difference", (File->FullFileName)));
           break;
         }
 
@@ -2451,6 +2454,11 @@ void __fastcall TFTPFileSystem::AutoDetectTimeDifference(TRemoteFileList * FileL
         break;
       }
     }
+
+    if (FDetectTimeDifference)
+    {
+      FTerminal->LogEvent(L"Found no file to use for detecting timezone difference");
+    }
   }
 }
 //---------------------------------------------------------------------------
@@ -2536,8 +2544,18 @@ void __fastcall TFTPFileSystem::DoReadFile(const UnicodeString & AFileName,
   TRemoteFile *& AFile)
 {
   UnicodeString FileName = AbsolutePath(AFileName, false);
-  UnicodeString FileNameOnly = UnixExtractFileName(FileName);
-  UnicodeString FilePath = UnixExtractFilePath(FileName);
+  UnicodeString FileNameOnly;
+  UnicodeString FilePath;
+  if (IsUnixRootPath(FileName))
+  {
+    FileNameOnly = FileName;
+    FilePath = FileName;
+  }
+  else
+  {
+    FileNameOnly = UnixExtractFileName(FileName);
+    FilePath = UnixExtractFilePath(FileName);
+  }
 
   TRemoteFileList * FileList = new TRemoteFileList();
   try
@@ -4152,9 +4170,10 @@ bool __fastcall TFTPFileSystem::HandleAsynchRequestVerifyCertificate(
       RequestResult = 1;
     }
 
+    UnicodeString SiteKey = FTerminal->SessionData->SiteKey;
     if (RequestResult == 0)
     {
-      if (FTerminal->VerifyCertificate(CertificateStorageKey,
+      if (FTerminal->VerifyCertificate(CertificateStorageKey, SiteKey,
             FSessionInfo.CertificateFingerprint, CertificateSubject, Data.VerificationResult))
       {
         RequestResult = 1;
@@ -4206,7 +4225,8 @@ bool __fastcall TFTPFileSystem::HandleAsynchRequestVerifyCertificate(
       if (RequestResult == 2)
       {
         FTerminal->CacheCertificate(
-          CertificateStorageKey, FSessionInfo.CertificateFingerprint, Data.VerificationResult);
+          CertificateStorageKey, SiteKey,
+          FSessionInfo.CertificateFingerprint, Data.VerificationResult);
       }
     }
 

+ 1 - 1
source/core/PuttyIntf.cpp

@@ -514,7 +514,7 @@ UnicodeString KeyTypeName(TKeyType KeyType)
 __int64 __fastcall ParseSize(UnicodeString SizeStr)
 {
   AnsiString AnsiSizeStr = SizeStr;
-  return parse_blocksize(AnsiSizeStr.c_str());
+  return parse_blocksize64(AnsiSizeStr.c_str());
 }
 //---------------------------------------------------------------------------
 bool __fastcall HasGSSAPI(UnicodeString CustomPath)

+ 2 - 2
source/core/Script.cpp

@@ -634,7 +634,7 @@ TStrings * __fastcall TScript::CreateFileList(TScriptProcParams * Parameters, in
             FTerminal->ExceptionOnFail = true;
             try
             {
-              FTerminal->ReadFile(FileName, File);
+              FTerminal->ReadFile(UnixExcludeTrailingBackslash(FileName), File);
               if (!File->HaveFullFileName)
               {
                 File->FullFileName = FileName;
@@ -1058,7 +1058,7 @@ void __fastcall TScript::StatProc(TScriptProcParams * Parameters)
 {
   CheckSession();
 
-  UnicodeString Path = Parameters->Param[1];
+  UnicodeString Path = UnixExcludeTrailingBackslash(Parameters->Param[1]);
   FTerminal->ExceptionOnFail = true;
   TRemoteFile * File = NULL;
   try

+ 2 - 2
source/core/SecureShell.cpp

@@ -1080,11 +1080,11 @@ UnicodeString __fastcall TSecureShell::ConvertInput(const RawByteString & Input)
   UnicodeString Result;
   if (UtfStrings)
   {
-    Result = UnicodeString(UTF8String(Input.c_str()));
+    Result = UTF8ToString(Input);
   }
   else
   {
-    Result = UnicodeString(AnsiString(Input.c_str()));
+    Result = AnsiToString(Input);
   }
   return Result;
 }

+ 6 - 1
source/core/SessionData.cpp

@@ -1733,9 +1733,14 @@ UnicodeString __fastcall TSessionData::GetStorageKey()
   return SessionName;
 }
 //---------------------------------------------------------------------
+UnicodeString __fastcall TSessionData::FormatSiteKey(const UnicodeString & HostName, int PortNumber)
+{
+  return FORMAT(L"%s:%d", (HostName, PortNumber));
+}
+//---------------------------------------------------------------------
 UnicodeString __fastcall TSessionData::GetSiteKey()
 {
-  return FORMAT(L"%s:%d", (HostNameExpanded, PortNumber));
+  return FormatSiteKey(HostNameExpanded, PortNumber);
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::SetHostName(UnicodeString value)

+ 1 - 0
source/core/SessionData.h

@@ -402,6 +402,7 @@ public:
   static UnicodeString __fastcall ExtractFolderName(const UnicodeString & Name);
   static UnicodeString __fastcall ComposePath(const UnicodeString & Path, const UnicodeString & Name);
   static bool __fastcall IsSensitiveOption(const UnicodeString & Option);
+  static UnicodeString __fastcall FormatSiteKey(const UnicodeString & HostName, int PortNumber);
 
   __property UnicodeString HostName  = { read=FHostName, write=SetHostName };
   __property UnicodeString HostNameExpanded  = { read=GetHostNameExpanded };

+ 6 - 1
source/core/SftpFileSystem.cpp

@@ -1595,7 +1595,7 @@ protected:
     // but hanging the application for a long time waiting for responses
     // (common is that the progress window would not even manage to draw itself,
     // showing that upload finished, before the application "hangs")
-    OperationProgress->Progress();
+    FFileSystem->Progress(OperationProgress);
   }
 
   virtual bool __fastcall ReceivePacketAsynchronously()
@@ -2248,6 +2248,11 @@ unsigned long __fastcall TSFTPFileSystem::DownloadBlockSize(
   return Result;
 }
 //---------------------------------------------------------------------------
+void __fastcall TSFTPFileSystem::Progress(TFileOperationProgressType * OperationProgress)
+{
+  FTerminal->Progress(OperationProgress);
+}
+//---------------------------------------------------------------------------
 void __fastcall TSFTPFileSystem::SendPacket(const TSFTPPacket * Packet)
 {
   // putting here for a lack of better place

+ 1 - 0
source/core/SftpFileSystem.h

@@ -193,6 +193,7 @@ protected:
   inline unsigned long __fastcall DownloadBlockSize(
     TFileOperationProgressType * OperationProgress);
   inline int __fastcall PacketLength(unsigned char * LenBuf, int ExpectedType);
+  void __fastcall Progress(TFileOperationProgressType * OperationProgress);
 };
 //---------------------------------------------------------------------------
 #endif // SftpFileSystemH

+ 16 - 6
source/core/Terminal.cpp

@@ -1093,6 +1093,15 @@ void __fastcall TTerminal::ProcessGUI()
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TTerminal::Progress(TFileOperationProgressType * OperationProgress)
+{
+  if (FNesting == 0)
+  {
+    TAutoNestingCounter NestingCounter(FNesting);
+    OperationProgress->Progress();
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminal::Reopen(int Params)
 {
   TFSProtocol OrigFSProtocol = SessionData->FSProtocol;
@@ -2922,7 +2931,7 @@ bool __fastcall TTerminal::FileExists(const UnicodeString FileName, TRemoteFile
     ExceptionOnFail = true;
     try
     {
-      ReadFile(FileName, File);
+      ReadFile(UnixExcludeTrailingBackslash(FileName), File);
     }
     __finally
     {
@@ -5623,7 +5632,8 @@ static UnicodeString __fastcall FormatCertificateData(const UnicodeString & Fing
 }
 //---------------------------------------------------------------------------
 bool  __fastcall TTerminal::VerifyCertificate(
-  const UnicodeString & CertificateStorageKey, const UnicodeString & Fingerprint,
+  const UnicodeString & CertificateStorageKey, const UnicodeString & SiteKey,
+  const UnicodeString & Fingerprint,
   const UnicodeString & CertificateSubject, int Failures)
 {
   bool Result = false;
@@ -5635,9 +5645,9 @@ bool  __fastcall TTerminal::VerifyCertificate(
 
   if (Storage->OpenSubKey(CertificateStorageKey, false))
   {
-    if (Storage->ValueExists(SessionData->SiteKey))
+    if (Storage->ValueExists(SiteKey))
     {
-      UnicodeString CachedCertificateData = Storage->ReadString(SessionData->SiteKey, L"");
+      UnicodeString CachedCertificateData = Storage->ReadString(SiteKey, L"");
       if (CertificateData == CachedCertificateData)
       {
         LogEvent(FORMAT(L"Certificate for \"%s\" matches cached fingerprint and failures", (CertificateSubject)));
@@ -5676,7 +5686,7 @@ bool  __fastcall TTerminal::VerifyCertificate(
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::CacheCertificate(const UnicodeString & CertificateStorageKey,
-  const UnicodeString & Fingerprint, int Failures)
+  const UnicodeString & SiteKey, const UnicodeString & Fingerprint, int Failures)
 {
   UnicodeString CertificateData = FormatCertificateData(Fingerprint, Failures);
 
@@ -5685,7 +5695,7 @@ void __fastcall TTerminal::CacheCertificate(const UnicodeString & CertificateSto
 
   if (Storage->OpenSubKey(CertificateStorageKey, true))
   {
-    Storage->WriteString(SessionData->SiteKey, CertificateData);
+    Storage->WriteString(SiteKey, CertificateData);
   }
 }
 //---------------------------------------------------------------------------

+ 4 - 2
source/core/Terminal.h

@@ -351,6 +351,7 @@ protected:
   virtual void __fastcall DisplayBanner(const UnicodeString & Banner);
   virtual void __fastcall Closed();
   virtual void __fastcall ProcessGUI();
+  void __fastcall Progress(TFileOperationProgressType * OperationProgress);
   virtual void __fastcall HandleExtendedException(Exception * E);
   bool __fastcall IsListenerFree(unsigned int PortNumber);
   void __fastcall DoProgress(TFileOperationProgressType & ProgressData);
@@ -370,10 +371,11 @@ protected:
   virtual TTerminal * __fastcall GetPasswordSource();
   void __fastcall DoEndTransaction(bool Inform);
   bool  __fastcall VerifyCertificate(
-    const UnicodeString & CertificateStorageKey, const UnicodeString & Fingerprint,
+    const UnicodeString & CertificateStorageKey, const UnicodeString & SiteKey,
+    const UnicodeString & Fingerprint,
     const UnicodeString & CertificateSubject, int Failures);
   void __fastcall CacheCertificate(const UnicodeString & CertificateStorageKey,
-    const UnicodeString & Fingerprint, int Failures);
+    const UnicodeString & SiteKey, const UnicodeString & Fingerprint, int Failures);
   void __fastcall CollectTlsUsage(const UnicodeString & TlsVersionStr);
 
   __property TFileOperationProgressType * OperationProgress = { read=FOperationProgress };

+ 23 - 15
source/core/WebDAVFileSystem.cpp

@@ -64,7 +64,7 @@ struct TWebDAVCertificateData
 };
 //---------------------------------------------------------------------------
 #define SESSION_FS_KEY "filesystem"
-#define MAX_REDIRECT_ATTEMPTS 3
+#define MAX_REDIRECT_ATTEMPTS 5
 static const char CertificateStorageKey[] = "HttpsCertificates";
 static const UnicodeString CONST_WEBDAV_PROTOCOL_BASE_NAME = L"WebDAV";
 //---------------------------------------------------------------------------
@@ -240,15 +240,9 @@ void __fastcall TWebDAVFileSystem::Open()
 
   FSessionInfo.LoginTime = Now();
 
-  bool Ssl = (FTerminal->SessionData->Ftps != ftpsNone);
-  if (Ssl)
-  {
-    FSessionInfo.SecurityProtocolName = LoadStr(FTPS_IMPLICIT);
-  }
-
   UnicodeString HostName = Data->HostNameExpanded;
   size_t Port = Data->PortNumber;
-  UnicodeString ProtocolName = !Ssl ? WebDAVProtocol : WebDAVSProtocol;
+  UnicodeString ProtocolName = (FTerminal->SessionData->Ftps == ftpsNone) ? WebDAVProtocol : WebDAVSProtocol;
   UnicodeString Path = Data->RemoteDirectory;
   // PathToNeon is not used as we cannot call AbsolutePath here
   UnicodeString EscapedPath = UnicodeString(UTF8String(PathEscape(StrToNeon(Path)).c_str()));
@@ -349,6 +343,19 @@ void TWebDAVFileSystem::NeonOpen(UnicodeString & CorrectedUrl, const UnicodeStri
     uri.port = ne_uri_defaultport(uri.scheme);
   }
 
+  FHostName = StrFromNeon(uri.host);
+  FPortNumber = uri.port;
+
+  FSessionInfo.CSCipher = UnicodeString();
+  FSessionInfo.SCCipher = UnicodeString();
+  bool Ssl = SameText(StrFromNeon(uri.scheme), WebDAVSProtocol);
+  FSessionInfo.SecurityProtocolName = Ssl ? LoadStr(FTPS_IMPLICIT) : UnicodeString();
+
+  if (Ssl != (FTerminal->SessionData->Ftps != ftpsNone))
+  {
+    FTerminal->LogEvent(L"Warning: Redirected to an unencrypted URL.");
+  }
+
   TSessionData * Data = FTerminal->SessionData;
 
   assert(FNeonSession == NULL);
@@ -405,13 +412,13 @@ void TWebDAVFileSystem::NeonOpen(UnicodeString & CorrectedUrl, const UnicodeStri
   ne_set_useragent(FNeonSession, StrToNeon(FORMAT(L"%s/%s", (AppNameString(), Configuration->Version))));
 
   unsigned int NeonAuthTypes = NE_AUTH_BASIC | NE_AUTH_DIGEST;
-  if (Data->Ftps != ftpsNone)
+  if (Ssl)
   {
     NeonAuthTypes |= NE_AUTH_NEGOTIATE;
   }
   ne_add_server_auth(FNeonSession, NeonAuthTypes, NeonRequestAuth, this);
 
-  if (Data->Ftps != ftpsNone)
+  if (Ssl)
   {
     // When the CA certificate or server certificate has
     // verification problems, neon will call our verify function before
@@ -691,7 +698,7 @@ void __fastcall TWebDAVFileSystem::CheckStatus(int NeonStatus)
         break;
 
       case NE_LOOKUP:
-        Error = ReplaceStr(LoadStr(NET_TRANSL_HOST_NOT_EXIST2), L"%HOST%", FTerminal->SessionData->HostNameExpanded);
+        Error = ReplaceStr(LoadStr(NET_TRANSL_HOST_NOT_EXIST2), L"%HOST%", FHostName);
         break;
 
       case NE_AUTH:
@@ -707,7 +714,7 @@ void __fastcall TWebDAVFileSystem::CheckStatus(int NeonStatus)
         break;
 
       case NE_TIMEOUT:
-        Error = ReplaceStr(LoadStr(NET_TRANSL_TIMEOUT2), L"%HOST%", FTerminal->SessionData->HostNameExpanded);
+        Error = ReplaceStr(LoadStr(NET_TRANSL_TIMEOUT2), L"%HOST%", FHostName);
         break;
 
       case NE_REDIRECT:
@@ -2146,7 +2153,7 @@ bool TWebDAVFileSystem::VerifyCertificate(const TWebDAVCertificateData & Data)
     // NEON checks certificate host name on its own
     if (FLAGSET(FailuresToList, NE_SSL_IDMISMATCH))
     {
-      AddToList(Summary, FMTLOAD(CERT_NAME_MISMATCH, (FTerminal->SessionData->HostNameExpanded)), L" ");
+      AddToList(Summary, FMTLOAD(CERT_NAME_MISMATCH, (FHostName)), L" ");
       FailuresToList &= ~NE_SSL_IDMISMATCH;
     }
     if (FLAGSET(FailuresToList, NE_SSL_UNTRUSTED))
@@ -2181,10 +2188,11 @@ bool TWebDAVFileSystem::VerifyCertificate(const TWebDAVCertificateData & Data)
 
   if (!Result)
   {
+    UnicodeString SiteKey = TSessionData::FormatSiteKey(FHostName, FPortNumber);
     if (!Result)
     {
       Result = FTerminal->VerifyCertificate(
-        CertificateStorageKey, Data.Fingerprint, Data.Subject, Failures);
+        CertificateStorageKey, SiteKey, Data.Fingerprint, Data.Subject, Failures);
     }
 
     if (!Result)
@@ -2208,7 +2216,7 @@ bool TWebDAVFileSystem::VerifyCertificate(const TWebDAVCertificateData & Data)
       switch (Answer)
       {
         case qaYes:
-          FTerminal->CacheCertificate(CertificateStorageKey, Data.Fingerprint, Failures);
+          FTerminal->CacheCertificate(CertificateStorageKey, SiteKey, Data.Fingerprint, Failures);
           Result = true;
           break;
 

+ 2 - 0
source/core/WebDAVFileSystem.h

@@ -154,6 +154,8 @@ private:
   UnicodeString FResponse;
   RawByteString FPassword;
   UnicodeString FTlsVersionStr;
+  UnicodeString FHostName;
+  int FPortNumber;
   enum TIgnoreAuthenticationFailure { iafNo, iafWaiting, iafPasswordFailed } FIgnoreAuthenticationFailure;
 
   void __fastcall CustomReadFile(UnicodeString FileName,

+ 32 - 10
source/filezilla/FtpControlSocket.cpp

@@ -2468,11 +2468,12 @@ void CFtpControlSocket::ListFile(CString filename, const CServerPath &path)
 
 	#define LISTFILE_INIT	-1
 	#define LISTFILE_MLST	1
-	#define LISTFILE_SIZE	2
-	#define LISTFILE_MDTM	3
-	#define LISTFILE_PWD	4
-	#define LISTFILE_CWD	5
-	#define LISTFILE_CWD2	6
+  #define LISTFILE_TYPE  2
+  #define LISTFILE_SIZE  3
+  #define LISTFILE_MDTM  4
+  #define LISTFILE_PWD   5
+  #define LISTFILE_CWD   6
+  #define LISTFILE_CWD2  7
 
 	ASSERT(!m_Operation.nOpMode || m_Operation.nOpMode&CSMODE_LISTFILE);
 
@@ -2498,7 +2499,8 @@ void CFtpControlSocket::ListFile(CString filename, const CServerPath &path)
 		pData = new CListFileData;
 		pData->fileName = filename;
 		pData->dir = path.GetPath();
-		pData->path = path.FormatFilename(filename);
+    // special case for listing a root folder
+    pData->path = (filename == L"/") ? pData->dir : path.FormatFilename(filename);
 		m_Operation.pData = pData;
 		ShowStatus(IDS_STATUSMSG_RETRIEVINGLISTFILE, FZ_LOG_STATUS);
 		if (UsingMlsd())
@@ -2578,9 +2580,13 @@ void CFtpControlSocket::ListFile(CString filename, const CServerPath &path)
 		else
 		{
 			// CWD failed, file is not a directory, we should not need to restore PWD.
-			if (Send(L"SIZE " + pData->path))
+
+      // Force binary mode, as according to RFC 6359,
+      // SIZE command returns size as transferred over the stream.
+      // Moreover ProFTPD does not even support SIZE command in ASCII mode
+      if (Send(L"TYPE I"))
 			{
-				m_Operation.nOpState = LISTFILE_SIZE;
+        m_Operation.nOpState = LISTFILE_TYPE;
 			}
 			else
 			{
@@ -2603,6 +2609,17 @@ void CFtpControlSocket::ListFile(CString filename, const CServerPath &path)
 			error = TRUE;
 		}
 		break;
+  case LISTFILE_TYPE:
+    // Do not really care if TYPE succeeded or not
+    if (Send(L"SIZE " + pData->path))
+    {
+      m_Operation.nOpState = LISTFILE_SIZE;
+    }
+    else
+    {
+      error = TRUE;
+    }
+    break;
 	case LISTFILE_SIZE:
 		code = GetReplyCode();
 		// Ignore SIZE errors for directories
@@ -2646,8 +2663,9 @@ void CFtpControlSocket::ListFile(CString filename, const CServerPath &path)
 		pDirectoryListing->path.SetServer(pDirectoryListing->server);
 		pDirectoryListing->path = pData->dir;
 		ShowStatus(IDS_STATUSMSG_LISTFILESUCCESSFUL,FZ_LOG_STATUS);
-		SetDirectoryListing(pDirectoryListing);
-		delete pDirectoryListing;
+    // do not use SetDirectoryListing as that would make
+    // later operations believe that there's only this one file in the folder
+    m_pOwner->SendDirectoryListing(pDirectoryListing);
 		ResetOperation(FZ_REPLY_OK);
 	}
 }
@@ -3928,6 +3946,7 @@ void CFtpControlSocket::FileTransfer(t_transferfile *transferfile/*=0*/,BOOL bFi
 				m_pTransferSocket->m_pFile = m_pDataFile;
 				if (!pData->transferfile.get)
 				{
+          // See comment in !get branch below
 					pData->transferdata.transfersize=GetLength64(*m_pDataFile);
 					pData->transferdata.transferleft=pData->transferdata.transfersize;
 					if (pData->transferdata.bResume)
@@ -3954,6 +3973,9 @@ void CFtpControlSocket::FileTransfer(t_transferfile *transferfile/*=0*/,BOOL bFi
 				}
 				else
 				{
+          // Resetting transfersize here is pointless as we
+          // always provide valid size in call to FileTransfer.
+          // We unnecessary reply on the file being in the directory listing.
 					pData->transferdata.transfersize=-1;
 					CString remotefile=pData->transferfile.remotefile;
 					if (m_pDirectoryListing)

+ 9 - 2
source/filezilla/MainThread.cpp

@@ -474,13 +474,20 @@ void CMainThread::SetWorkingDir(t_directory *pWorkingDir)
 	{
 		t_directory *pDirectoryToSend=new t_directory;
 		*pDirectoryToSend=*pWorkingDir;
-		if (!PostMessage(m_hOwnerWnd, m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_LISTDATA, 0), (LPARAM)pDirectoryToSend))
-			delete pDirectoryToSend;
+    SendDirectoryListing(pDirectoryToSend);
 	}
 
 	return;
 }
 
+void CMainThread::SendDirectoryListing(t_directory * pDirectoryToSend)
+{
+  if (!PostMessage(NULL, 0, FZ_MSG_MAKEMSG(FZ_MSG_LISTDATA, 0), (LPARAM)pDirectoryToSend))
+  {
+    delete pDirectoryToSend;
+  }
+}
+
 bool CMainThread::GetWorkingDirPath(CServerPath &path)
 {
 	ECS;

+ 1 - 0
source/filezilla/MainThread.h

@@ -64,6 +64,7 @@ public:
 	bool GetWorkingDirPath(CServerPath &path);
 	void SetWorkingDir(t_directory *pWorkingDir);
 	BOOL GetWorkingDir(t_directory* pWorkingDir);
+  void SendDirectoryListing(t_directory * pDirectoryToSend);
 #ifndef MPEXT
 	void SetOption(int nOption, int nValue);
 	int GetOption(int nOption);

+ 14 - 0
source/forms/CustomScpExplorer.cpp

@@ -4031,6 +4031,20 @@ void __fastcall TCustomScpExplorerForm::ApplicationMinimize(TObject * /*Sender*/
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::ApplicationRestore(TObject * /*Sender*/)
 {
+  // WORKAROUND
+  // When restoring maximized window from minimization,
+  // rarely some controls do not align properly.
+  // Two instances seen (both for Commander):
+  // - When restoring, window is temporarily narrower (not maximizer),
+  //   causing toolbars on TopDock to wrap and dock to expand horizontally.
+  //   Once maximized already, top dock shinks back, but the session PageControl,
+  //   do not align up, leaving space between TopDock and PageControl.
+  // - Similar issue seem with LocalDirView not aligning down to status bar.
+  for (int Index = 0; Index < ControlCount; Index++)
+  {
+    RealignControl(Controls[Index]);
+  }
+
   if (FTrayIcon->Visible)
   {
     FTrayIcon->Visible = false;

+ 12 - 0
source/forms/Editor.cpp

@@ -658,6 +658,18 @@ __fastcall TEditorForm::TEditorForm(TComponent* Owner)
   EditorMemo->OnKeyUp = EditorMemoKeyUp;
   EditorMemo->OnMouseUp = EditorMemoMouseUp;
 
+  // By default the TEditAction's reflect state of the currently focused edit.
+  // Even if the edit is on a different window.
+  // This way we explicitly bind them to our editor.
+  for (int Index = 0; Index < EditorActions->ActionCount; Index++)
+  {
+    TEditAction * EditAction = dynamic_cast<TEditAction* >(EditorActions->Actions[Index]);
+    if (EditAction != NULL)
+    {
+      EditAction->Control = EditorMemo;
+    }
+  }
+
   FParentForm = NULL;
   FCaretPos = TPoint(-1, -1);
   FLastFindDialog = NULL;

+ 1 - 0
source/forms/FileFind.cpp

@@ -55,6 +55,7 @@ __fastcall TFileFindDialog::TFileFindDialog(TComponent * Owner, TFindEvent OnFin
 
   FSystemImageList = SharedSystemImageList(false);
   FileView->SmallImages = FSystemImageList;
+  FileView->ShowColumnIcon = false;
 
   UseDesktopFont(FileView);
   UseDesktopFont(StatusBar);

+ 4 - 0
source/forms/ScpCommander.cpp

@@ -1695,6 +1695,10 @@ void __fastcall TScpCommanderForm::LocalDirViewFileIconForName(
   {
     FileName.SetLength(FileName.Length() - PartialExt.Length());
   }
+  if (WinConfiguration->LocalIconsByExt)
+  {
+    FileName = ExtractFileName(FileName);
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TScpCommanderForm::LocalDirViewUpdateStatusBar(

+ 18 - 3
source/packages/filemng/DirView.pas

@@ -2088,12 +2088,14 @@ var
   i: Integer;
   ToDelete: Boolean;
   Updating: Boolean;
+  Updated: Boolean;
   Item: TListItem;
 begin
   if SelCount > 50 then Reload2
     else
   begin
     Updating := False;
+    Updated := False;
     FileList := CustomCreateFileList(True, False, True, nil, True);
     try
       for i := 0 to FileList.Count - 1 do
@@ -2111,12 +2113,21 @@ begin
             Items.BeginUpdate;
             Updating := True;
           end;
+          with PFileRec(Item.Data)^ do
+          begin
+            Dec(FFilesSize, Size);
+            // No need to decrease FFilesSelSize here as LVIF_STATE/deselect
+            // is called for item being deleted
+          end;
           Item.Delete;
+          Updated := True;
         end;
       end;
     finally
       if Updating then
         Items.EndUpdate;
+      if Updated then
+        UpdateStatusBar;
       FileList.Free;
     end;
   end;
@@ -2208,10 +2219,14 @@ begin
       StartIconUpdateThread;
 
     if WatchForChanges then StartWatchThread;
-    if Assigned(FDriveView) then
-      with FDriveView do
-        if not WatchThreadActive and Assigned(Selected) then
+    if Assigned(DriveView) then
+      with DriveView do
+      begin
+        if Assigned(Selected) then
           ValidateDirectory(Selected);
+        TDriveView(FDriveView).StartWatchThread;
+      end;
+
   end;
 end; {CreateDirectory}
 

+ 7 - 2
source/putty/MISC.C

@@ -19,10 +19,10 @@
  * All numbers are decimal, and suffixes refer to powers of two.
  * Case-insensitive.
  */
-unsigned long parse_blocksize(const char *bs)
+__int64 parse_blocksize64(const char *bs)
 {
     char *suf;
-    unsigned long r = strtoul(bs, &suf, 10);
+    __int64 r = strtoul(bs, &suf, 10);
     if (*suf != '\0') {
 	while (*suf && isspace((unsigned char)*suf)) suf++;
 	switch (*suf) {
@@ -43,6 +43,11 @@ unsigned long parse_blocksize(const char *bs)
     return r;
 }
 
+unsigned long parse_blocksize(const char *bs)
+{
+  return (unsigned long)parse_blocksize64(bs);
+}
+
 /*
  * Parse a ^C style character specification.
  * Returns NULL in `next' if we didn't recognise it as a control character,

+ 3 - 0
source/putty/MISC.H

@@ -21,6 +21,9 @@
 typedef struct Filename Filename;
 typedef struct FontSpec FontSpec;
 
+#ifdef MPEXT
+__int64 parse_blocksize64(const char *bs);
+#endif
 unsigned long parse_blocksize(const char *bs);
 char ctrlparse(char *s, char **next);
 

+ 13 - 4
source/windows/ConsoleRunner.cpp

@@ -531,6 +531,7 @@ private:
   inline void __fastcall FreeCommStruct(TConsoleCommStruct * CommStruct);
   inline void __fastcall SendEvent(int Timeout);
   void __fastcall Init();
+  void __fastcall CheckHandle(HANDLE Handle, const UnicodeString & Desc);
 };
 //---------------------------------------------------------------------------
 __fastcall TExternalConsole::TExternalConsole(
@@ -538,13 +539,13 @@ __fastcall TExternalConsole::TExternalConsole(
 {
   UnicodeString Name;
   Name = FORMAT(L"%s%s", (CONSOLE_EVENT_REQUEST, (Instance)));
-  FRequestEvent = OpenEvent(EVENT_ALL_ACCESS, false, Name.c_str());
+  CheckHandle(FRequestEvent = OpenEvent(EVENT_ALL_ACCESS, false, Name.c_str()), L"Request event");
   Name = FORMAT(L"%s%s", (CONSOLE_EVENT_RESPONSE, (Instance)));
-  FResponseEvent = OpenEvent(EVENT_ALL_ACCESS, false, Name.c_str());
+  CheckHandle(FResponseEvent = OpenEvent(EVENT_ALL_ACCESS, false, Name.c_str()), L"Response event");
   Name = FORMAT(L"%s%s", (CONSOLE_EVENT_CANCEL, (Instance)));
-  FCancelEvent = OpenEvent(EVENT_ALL_ACCESS, false, Name.c_str());
+  CheckHandle(FCancelEvent = OpenEvent(EVENT_ALL_ACCESS, false, Name.c_str()), L"Cancel event");
   Name = FORMAT(L"%s%s", (CONSOLE_MAPPING, (Instance)));
-  FFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, Name.c_str());
+  CheckHandle(FFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, Name.c_str()), L"File mapping");
 
   if ((FRequestEvent == NULL) || (FResponseEvent == NULL) || (FFileMapping == NULL))
   {
@@ -595,6 +596,14 @@ __fastcall TExternalConsole::~TExternalConsole()
   KillTimer(Application->Handle, 1);
 }
 //---------------------------------------------------------------------------
+void __fastcall TExternalConsole::CheckHandle(HANDLE Handle, const UnicodeString & Desc)
+{
+  if (Handle == NULL)
+  {
+    throw ExtException(LoadStr(EXTERNAL_CONSOLE_INIT_ERROR), FORMAT(L"%s\n%s", (Desc, LastSysErrorMessage())));
+  }
+}
+//---------------------------------------------------------------------------
 TConsoleCommStruct * __fastcall TExternalConsole::GetCommStruct()
 {
   TConsoleCommStruct * Result;

+ 2 - 1
source/windows/Tools.cpp

@@ -27,6 +27,7 @@
 #include <System.Win.ComObj.hpp>
 #include <StrUtils.hpp>
 #include <WinConfiguration.h>
+#include <ProgParams.h>
 //---------------------------------------------------------------------------
 // WORKAROUND
 // VCL includes wininet.h (even with NO_WIN32_LEAN_AND_MEAN)
@@ -300,7 +301,7 @@ void __fastcall ExecuteNewInstance(const UnicodeString & Param)
   UnicodeString Arg = Param;
   if (!Arg.IsEmpty())
   {
-    Arg = FORMAT(L"\"%s\"", (Arg));
+    Arg = FORMAT(L"\"%s\" %s", (Arg, TProgramParams::FormatSwitch(NEWINSTANCE_SWICH)));
   }
 
   if (!ExecuteShell(Application->ExeName, Arg))

+ 13 - 2
source/windows/VCLCommon.cpp

@@ -344,15 +344,26 @@ struct TSavedSystemSettings
   TWndMethod OldWndProc;
 };
 //---------------------------------------------------------------------------
-class TPublicControl : public TWinControl
+class TPublicWinControl : public TWinControl
 {
 friend TWndMethod __fastcall ControlWndProc(TWinControl * Control);
 };
 //---------------------------------------------------------------------------
 TWndMethod __fastcall ControlWndProc(TWinControl * Control)
+{
+  TPublicWinControl * PublicWinControl = static_cast<TPublicWinControl *>(Control);
+  return &PublicWinControl->WndProc;
+}
+//---------------------------------------------------------------------
+class TPublicControl : public TControl
+{
+friend void __fastcall RealignControl(TControl * Control);
+};
+//---------------------------------------------------------------------------
+void __fastcall RealignControl(TControl * Control)
 {
   TPublicControl * PublicControl = static_cast<TPublicControl *>(Control);
-  return &PublicControl->WndProc;
+  PublicControl->RequestAlign();
 }
 //---------------------------------------------------------------------------
 static Forms::TMonitor * LastMonitor = NULL;

+ 1 - 0
source/windows/VCLCommon.h

@@ -73,5 +73,6 @@ void __fastcall UseDesktopFont(TControl * Control);
 void __fastcall LoadResourceImage(TImage * Image, const UnicodeString & ImageName);
 UnicodeString __fastcall FormatFormCaption(TCustomForm * Form, const UnicodeString & Caption);
 UnicodeString __fastcall FormatMainFormCaption(const UnicodeString & Caption);
+void __fastcall RealignControl(TControl * Control);
 //---------------------------------------------------------------------------
 #endif  // VCLCommonH

+ 10 - 0
source/windows/WinConfiguration.cpp

@@ -540,6 +540,7 @@ void __fastcall TWinConfiguration::Default()
   FAutoImportedFromPuttyOrFilezilla = false;
   FGenerateUrlComponents = -1;
   FExternalSessionInExistingInstance = true;
+  FLocalIconsByExt = false;
   HonorDrivePolicy = true;
 
   FEditor.Font.FontName = DefaultFixedWidthFontName;
@@ -834,6 +835,9 @@ bool __fastcall TWinConfiguration::GetUseMasterPassword()
 //---------------------------------------------------------------------------
 THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool & SessionList)
 {
+  // Detect embedded session, if not checked yet
+  GetStorage();
+
   THierarchicalStorage * Result;
   if (SessionList && !FTemporarySessionFile.IsEmpty())
   {
@@ -919,6 +923,7 @@ THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool & SessionList)
     KEY(Bool,     AutoImportedFromPuttyOrFilezilla); \
     KEY(Integer,  GenerateUrlComponents); \
     KEY(Bool,     ExternalSessionInExistingInstance); \
+    KEY(Bool,     LocalIconsByExt); \
     KEY(Bool,     HonorDrivePolicy); \
   ); \
   BLOCK(L"Interface\\Editor", CANCREATE, \
@@ -1877,6 +1882,11 @@ void __fastcall TWinConfiguration::SetExternalSessionInExistingInstance(bool val
   SET_CONFIG_PROPERTY(ExternalSessionInExistingInstance);
 }
 //---------------------------------------------------------------------------
+void __fastcall TWinConfiguration::SetLocalIconsByExt(bool value)
+{
+  SET_CONFIG_PROPERTY(LocalIconsByExt);
+}
+//---------------------------------------------------------------------------
 bool __fastcall TWinConfiguration::GetHonorDrivePolicy()
 {
   return DriveInfo->HonorDrivePolicy;

+ 3 - 0
source/windows/WinConfiguration.h

@@ -386,6 +386,7 @@ private:
   bool FAutoImportedFromPuttyOrFilezilla;
   int FGenerateUrlComponents;
   bool FExternalSessionInExistingInstance;
+  bool FLocalIconsByExt;
   int FDontDecryptPasswords;
   int FMasterPasswordSession;
   bool FMasterPasswordSessionAsked;
@@ -466,6 +467,7 @@ private:
   void __fastcall SetAutoImportedFromPuttyOrFilezilla(bool value);
   void __fastcall SetGenerateUrlComponents(int value);
   void __fastcall SetExternalSessionInExistingInstance(bool value);
+  void __fastcall SetLocalIconsByExt(bool value);
   bool __fastcall GetHonorDrivePolicy();
   void __fastcall SetHonorDrivePolicy(bool value);
   bool __fastcall GetIsBeta();
@@ -625,6 +627,7 @@ public:
   __property bool AutoImportedFromPuttyOrFilezilla = { read = FAutoImportedFromPuttyOrFilezilla, write = SetAutoImportedFromPuttyOrFilezilla };
   __property int GenerateUrlComponents = { read = FGenerateUrlComponents, write = SetGenerateUrlComponents };
   __property bool ExternalSessionInExistingInstance = { read = FExternalSessionInExistingInstance, write = SetExternalSessionInExistingInstance };
+  __property bool LocalIconsByExt = { read = FLocalIconsByExt, write = SetLocalIconsByExt };
   __property bool HonorDrivePolicy = { read = GetHonorDrivePolicy, write = SetHonorDrivePolicy };
   __property TMasterPasswordPromptEvent OnMasterPasswordPrompt = { read = FOnMasterPasswordPrompt, write = FOnMasterPasswordPrompt };
   __property TFont * SystemIconFont = { read = GetSystemIconFont };

+ 1 - 0
source/windows/WinInterface.h

@@ -29,6 +29,7 @@ const int mpAllowContinueOnError = 0x02;
 #define DESKTOP_SWITCH L"Desktop"
 #define SEND_TO_HOOK_SWITCH L"SendToHook"
 #define UNSAFE_SWITCH L"Unsafe"
+#define NEWINSTANCE_SWICH L"NewInstance"
 
 struct TMessageParams
 {

+ 1 - 1
source/windows/WinMain.cpp

@@ -736,7 +736,7 @@ int __fastcall Execute()
       {
         if ((ParamCommand == pcNone) &&
             (WinConfiguration->ExternalSessionInExistingInstance != OpenInNewWindow()) &&
-            !Params->FindSwitch(L"NewInstance") &&
+            !Params->FindSwitch(NEWINSTANCE_SWICH) &&
             SendToAnotherInstance())
         {
           Configuration->Usage->Inc(L"SendToAnotherInstance");