Martin Prikryl 14 سال پیش
والد
کامیت
1065652fa0
60فایلهای تغییر یافته به همراه968 افزوده شده و 283 حذف شده
  1. 1 1
      Console.rc
  2. 1 1
      DragExt.rc
  3. 1 1
      DragExt64.rc
  4. 1 1
      Putty.bpr
  5. 4 4
      WinSCP.rc
  6. 1 0
      components/UnixDirView.h
  7. 59 3
      core/Common.cpp
  8. 2 0
      core/Common.h
  9. 33 7
      core/FileBuffer.cpp
  10. 4 4
      core/FileBuffer.h
  11. 2 2
      core/FtpFileSystem.cpp
  12. 10 0
      core/HierarchicalStorage.cpp
  13. 4 0
      core/HierarchicalStorage.h
  14. 1 0
      core/Interface.h
  15. 16 6
      core/ScpFileSystem.cpp
  16. 48 5
      core/SessionData.cpp
  17. 6 1
      core/SessionData.h
  18. 10 1
      core/SessionInfo.cpp
  19. 8 4
      core/SftpFileSystem.cpp
  20. 12 1
      core/Terminal.cpp
  21. 8 0
      filezilla/AsyncSslSocketLayer.cpp
  22. 2 2
      forms/About.cpp
  23. 1 2
      forms/About.dfm
  24. 1 1
      forms/About.h
  25. 31 12
      forms/CustomScpExplorer.cpp
  26. 4 0
      forms/CustomScpExplorer.h
  27. 30 4
      forms/Login.cpp
  28. 0 1
      forms/Login.dfm
  29. 2 0
      forms/Login.h
  30. 2 2
      forms/NonVisual.cpp
  31. 53 43
      forms/ScpCommander.cpp
  32. 2 0
      forms/ScpCommander.dfm
  33. 3 0
      forms/ScpCommander.h
  34. 12 4
      forms/Synchronize.cpp
  35. 5 4
      packages/filemng/CustomDirView.hpp
  36. 21 7
      packages/filemng/CustomDirView.pas
  37. 1 0
      packages/filemng/DirView.hpp
  38. 8 4
      packages/filemng/DirView.pas
  39. 2 1
      packages/my/NortonLikeListView.hpp
  40. 14 9
      packages/my/NortonLikeListView.pas
  41. 1 0
      packages/my/PasTools.hpp
  42. 54 0
      packages/my/PasTools.pas
  43. 100 25
      putty/SSH.C
  44. 3 0
      putty/SSH.H
  45. 123 98
      putty/SSHBN.C
  46. 3 0
      putty/SSHZLIB.C
  47. 9 1
      putty/windows/WINNET.C
  48. 4 0
      putty/windows/WINPGNTC.C
  49. 14 15
      release/winscpsetup.iss
  50. 1 1
      resource/TextsCore1.rc
  51. 0 1
      resource/TextsWin.h
  52. 0 1
      resource/TextsWin1.rc
  53. 17 0
      windows/Setup.cpp
  54. 3 0
      windows/Setup.h
  55. 80 2
      windows/TerminalManager.cpp
  56. 11 0
      windows/TerminalManager.h
  57. 21 0
      windows/Tools.cpp
  58. 1 0
      windows/Tools.h
  59. 1 1
      windows/VCLCommon.cpp
  60. 96 0
      windows/WinApi.h

+ 1 - 1
Console.rc

@@ -16,7 +16,7 @@ FILETYPE 0x1
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "winscp.com\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.3.2.0\0"
+            VALUE "ProductVersion", "4.3.3.0\0"
             VALUE "ReleaseType", "stable\0"
             VALUE "WWW", "http://winscp.net/\0"
         }

+ 1 - 1
DragExt.rc

@@ -16,7 +16,7 @@ FILETYPE 0x2
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext.dll\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.3.2.0\0"
+            VALUE "ProductVersion", "4.3.3.0\0"
             VALUE "ReleaseType", "stable\0"
             VALUE "WWW", "http://winscp.net/\0"
         }

+ 1 - 1
DragExt64.rc

@@ -16,7 +16,7 @@ FILETYPE 0x2
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext64.dll\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.3.2.0\0"
+            VALUE "ProductVersion", "4.3.3.0\0"
             VALUE "ReleaseType", "stable\0"
             VALUE "WWW", "http://winscp.net/\0"
         }

+ 1 - 1
Putty.bpr

@@ -28,7 +28,7 @@
     <PATHRC value=".;"/>
     <PATHASM value=".;"/>
     <LINKER value="TLib"/>
-    <USERDEFINES value="SECURITY_WIN32;MPEXT;_WINDOWS"/>
+    <USERDEFINES value="SECURITY_WIN32;NO_SECURITY;NET_SETUP_DIAGNOSTICS;MPEXT;_WINDOWS"/>
     <SYSDEFINES value="_RTLDLL;NO_STRICT"/>
     <MAINSOURCE value="Putty.bpf"/>
     <INCLUDEPATH value="putty;putty\CHARSET;putty\WINDOWS;$(BCB)\include;$(BCB)\include\vcl"/>

+ 4 - 4
WinSCP.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 4,3,2,1201
-PRODUCTVERSION 4,3,2,1201
+FILEVERSION 4,3,3,1340
+PRODUCTVERSION 4,3,3,1340
 FILEOS 0x4
 FILETYPE 0x1
 {
@@ -10,13 +10,13 @@ FILETYPE 0x1
         {
             VALUE "CompanyName", "Martin Prikryl\0"
             VALUE "FileDescription", "WinSCP: SFTP, FTP and SCP client\0"
-            VALUE "FileVersion", "4.3.2.1201\0"
+            VALUE "FileVersion", "4.3.3.1340\0"
             VALUE "InternalName", "winscp\0"
             VALUE "LegalCopyright", "(c) 2000-2011 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "winscp.exe\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.3.2.0\0"
+            VALUE "ProductVersion", "4.3.3.0\0"
             VALUE "ReleaseType", "stable\0"
             VALUE "WWW", "http://winscp.net/\0"
         }

+ 1 - 0
components/UnixDirView.h

@@ -151,6 +151,7 @@ __published:
   __property OnBeginRename;
   __property OnEndRename;
   __property OnHistoryChange;
+  __property OnHistoryGo;
   __property OnPathChange;
 
   __property ColumnClick;

+ 59 - 3
core/Common.cpp

@@ -98,7 +98,7 @@ void PackStr(AnsiString &Str)
 //---------------------------------------------------------------------------
 AnsiString MakeValidFileName(AnsiString FileName)
 {
-  AnsiString IllegalChars = ";,=+<>|\"[] \\/?*";
+  AnsiString IllegalChars = ":;,=+<>|\"[] \\/?*";
   for (int Index = 0; Index < IllegalChars.Length(); Index++)
   {
     FileName = ReplaceChar(FileName, IllegalChars[Index+1], '-');
@@ -766,7 +766,7 @@ static TDateTimeParams * __fastcall GetDateTimeParams()
       DateTimeParams.StandardDate = TZI.StandardDate;
       DateTimeParams.DaylightDate = TZI.DaylightDate;
 
-      DateTimeParams.DaylightHack = !IsWin7();
+      DateTimeParams.DaylightHack = !IsWin7() || IsExactly2008R2();
 
       DateTimeParamsInitialized = true;
     }
@@ -926,7 +926,7 @@ TDateTime __fastcall UnixToDateTime(__int64 TimeStamp, TDSTMode DSTMode)
   return Result;
 }
 //---------------------------------------------------------------------------
-inline __int64 __fastcall Round(double Number)
+__int64 __fastcall Round(double Number)
 {
   double Floor = floor(Number);
   double Ceil = ceil(Number);
@@ -1517,3 +1517,59 @@ bool __fastcall IsWin7()
     (Win32MajorVersion > 6) ||
     ((Win32MajorVersion == 6) && (Win32MinorVersion >= 1));
 }
+//---------------------------------------------------------------------------
+bool __fastcall IsExactly2008R2()
+{
+  HANDLE Kernel32 = GetModuleHandle(kernel32);
+  typedef BOOL WINAPI (* TGetProductInfo)(DWORD, DWORD, DWORD, DWORD, PDWORD);
+  TGetProductInfo GetProductInfo =
+      (TGetProductInfo)GetProcAddress(Kernel32, "GetProductInfo");
+  bool Result;
+  if (GetProductInfo == NULL)
+  {
+    Result = false;
+  }
+  else
+  {
+    DWORD Type;
+    GetProductInfo(Win32MajorVersion, Win32MinorVersion, 0, 0, &Type);
+    switch (Type)
+    {
+      case 0x0008 /*PRODUCT_DATACENTER_SERVER*/:
+      case 0x000C /*PRODUCT_DATACENTER_SERVER_CORE}*/:
+      case 0x0027 /*PRODUCT_DATACENTER_SERVER_CORE_V*/:
+      case 0x0025 /*PRODUCT_DATACENTER_SERVER_V*/:
+      case 0x000A /*PRODUCT_ENTERPRISE_SERVE*/:
+      case 0x000E /*PRODUCT_ENTERPRISE_SERVER_COR*/:
+      case 0x0029 /*PRODUCT_ENTERPRISE_SERVER_CORE_*/:
+      case 0x000F /*PRODUCT_ENTERPRISE_SERVER_IA6*/:
+      case 0x0026 /*PRODUCT_ENTERPRISE_SERVER_*/:
+      case 0x002A /*PRODUCT_HYPER*/:
+      case 0x001E /*PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMEN*/:
+      case 0x0020 /*PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGIN*/:
+      case 0x001F /*PRODUCT_MEDIUMBUSINESS_SERVER_SECURIT*/:
+      case 0x0018 /*PRODUCT_SERVER_FOR_SMALLBUSINES*/:
+      case 0x0023 /*PRODUCT_SERVER_FOR_SMALLBUSINESS_*/:
+      case 0x0021 /*PRODUCT_SERVER_FOUNDATIO*/:
+      case 0x0009 /*PRODUCT_SMALLBUSINESS_SERVE*/:
+      case 0x0038 /*PRODUCT_SOLUTION_EMBEDDEDSERVE*/:
+      case 0x0007 /*PRODUCT_STANDARD_SERVE*/:
+      case 0x000D /*PRODUCT_STANDARD_SERVER_COR*/:
+      case 0x0028 /*PRODUCT_STANDARD_SERVER_CORE_*/:
+      case 0x0024 /*PRODUCT_STANDARD_SERVER_*/:
+      case 0x0017 /*PRODUCT_STORAGE_ENTERPRISE_SERVE*/:
+      case 0x0014 /*PRODUCT_STORAGE_EXPRESS_SERVE*/:
+      case 0x0015 /*PRODUCT_STORAGE_STANDARD_SERVE*/:
+      case 0x0016 /*PRODUCT_STORAGE_WORKGROUP_SERVE*/:
+      case 0x0011 /*PRODUCT_WEB_SERVE*/:
+      case 0x001D /*PRODUCT_WEB_SERVER_COR*/:
+        Result = true;
+        break;
+
+      default:
+        Result = false;
+        break;
+    }
+  }
+  return Result;
+}

+ 2 - 0
core/Common.h

@@ -73,8 +73,10 @@ bool __fastcall CutToken(AnsiString & Str, AnsiString & Token);
 void __fastcall AddToList(AnsiString & List, const AnsiString & Value, char Delimiter);
 bool __fastcall Is2000();
 bool __fastcall IsWin7();
+bool __fastcall IsExactly2008R2();
 struct TPasLibModule;
 TPasLibModule * __fastcall FindModule(void * Instance);
+__int64 __fastcall Round(double Number);
 //---------------------------------------------------------------------------
 typedef void __fastcall (__closure* TProcessLocalFileEvent)
   (const AnsiString FileName, const TSearchRec Rec, void * Param);

+ 33 - 7
core/FileBuffer.cpp

@@ -92,7 +92,8 @@ DWORD __fastcall TFileBuffer::LoadStream(TStream * Stream, const DWORD Len, bool
   return ReadStream(Stream, Len, ForceLen);
 }
 //---------------------------------------------------------------------------
-void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params)
+void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params,
+  bool & /*Token*/)
 {
   assert(strlen(Source) <= 2);
   assert(strlen(Dest) <= 2);
@@ -118,6 +119,12 @@ void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params)
   // one character source EOL
   if (!Source[1])
   {
+    // Disabled, not worth risking it is not safe enough, for the bugfix release
+    #if 0
+    bool PrevToken = Token;
+    Token = false;
+    #endif
+
     for (int Index = 0; Index < Size; Index++)
     {
       // EOL already in wanted format, make sure to pass unmodified
@@ -126,8 +133,24 @@ void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params)
         Index++;
         Ptr++;
       }
+      #if 0
+      // last buffer ended with the first char of wanted EOL format,
+      // which got expanded to wanted format.
+      // now we got the second char, so get rid of it.
+      else if ((Index == 0) && PrevToken && (*Ptr == Dest[1]))
+      {
+        Delete(Index, 1);
+      }
+      #endif
       else if (*Ptr == Source[0])
       {
+        #if 0
+        if ((*Ptr == Dest[0]) && (Index == Size - 1))
+        {
+          Token = true;
+        }
+        #endif
+
         *Ptr = Dest[0];
         if (Dest[1])
         {
@@ -168,19 +191,22 @@ void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params)
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TFileBuffer::Convert(TEOLType Source, TEOLType Dest, int Params)
+void __fastcall TFileBuffer::Convert(TEOLType Source, TEOLType Dest, int Params,
+  bool & Token)
 {
-  Convert(EOLToStr(Source), EOLToStr(Dest), Params);
+  Convert(EOLToStr(Source), EOLToStr(Dest), Params, Token);
 }
 //---------------------------------------------------------------------------
-void __fastcall TFileBuffer::Convert(char * Source, TEOLType Dest, int Params)
+void __fastcall TFileBuffer::Convert(char * Source, TEOLType Dest, int Params,
+  bool & Token)
 {
-  Convert(Source, EOLToStr(Dest), Params);
+  Convert(Source, EOLToStr(Dest), Params, Token);
 }
 //---------------------------------------------------------------------------
-void __fastcall TFileBuffer::Convert(TEOLType Source, char * Dest, int Params)
+void __fastcall TFileBuffer::Convert(TEOLType Source, char * Dest, int Params,
+  bool & Token)
 {
-  Convert(EOLToStr(Source), Dest, Params);
+  Convert(EOLToStr(Source), Dest, Params, Token);
 }
 //---------------------------------------------------------------------------
 void __fastcall TFileBuffer::Insert(int Index, const char * Buf, int Len)

+ 4 - 4
core/FileBuffer.h

@@ -13,10 +13,10 @@ class TFileBuffer
 public:
   __fastcall TFileBuffer();
   virtual __fastcall ~TFileBuffer();
-  void __fastcall Convert(char * Source, char * Dest, int Params);
-  void __fastcall Convert(TEOLType Source, TEOLType Dest, int Params);
-  void __fastcall Convert(char * Source, TEOLType Dest, int Params);
-  void __fastcall Convert(TEOLType Source, char * Dest, int Params);
+  void __fastcall Convert(char * Source, char * Dest, int Params, bool & Token);
+  void __fastcall Convert(TEOLType Source, TEOLType Dest, int Params, bool & Token);
+  void __fastcall Convert(char * Source, TEOLType Dest, int Params, bool & Token);
+  void __fastcall Convert(TEOLType Source, char * Dest, int Params, bool & Token);
   void __fastcall Insert(int Index, const char * Buf, int Len);
   void __fastcall Delete(int Index, int Len);
   DWORD __fastcall LoadStream(TStream * Stream, const DWORD Len, bool ForceLen);

+ 2 - 2
core/FtpFileSystem.cpp

@@ -351,7 +351,7 @@ void __fastcall TFTPFileSystem::Open()
       break;
   }
   int Pasv = (Data->FtpPasvMode ? 1 : 2);
-  int TimeZoneOffset = int(double(Data->TimeDifference) * 24 * 60);
+  int TimeZoneOffset = int(Round(double(Data->TimeDifference) * 24 * 60));
   int UTF8 = 0;
   switch (Data->NotUtf)
   {
@@ -792,7 +792,7 @@ bool __fastcall TFTPFileSystem::ConfirmOverwrite(AnsiString & FileName,
 
     // rename
     case qaIgnore:
-      if (FTerminal->PromptUser(FTerminal->SessionData, pkPrompt,
+      if (FTerminal->PromptUser(FTerminal->SessionData, pkFileName,
             LoadStr(RENAME_TITLE), "", LoadStr(RENAME_PROMPT2), true, 0, FileName))
       {
         OverwriteMode = omOverwrite;

+ 10 - 0
core/HierarchicalStorage.cpp

@@ -392,6 +392,11 @@ bool __fastcall TRegistryStorage::Copy(TRegistryStorage * Storage)
   return Result;
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall TRegistryStorage::GetSource()
+{
+  return RootKeyToStr(FRegistry->RootKey) + "\\" + Storage;
+}
+//---------------------------------------------------------------------------
 void __fastcall TRegistryStorage::SetAccessMode(TStorageAccessMode value)
 {
   THierarchicalStorage::SetAccessMode(value);
@@ -667,6 +672,11 @@ __fastcall TIniFileStorage::~TIniFileStorage()
   }
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall TIniFileStorage::GetSource()
+{
+  return Storage;
+}
+//---------------------------------------------------------------------------
 AnsiString __fastcall TIniFileStorage::GetCurrentSection()
 {
   return ExcludeTrailingBackslash(GetCurrentSubKeyMunged());

+ 4 - 0
core/HierarchicalStorage.h

@@ -58,6 +58,7 @@ public:
   __property TStorageAccessMode AccessMode  = { read=FAccessMode, write=SetAccessMode };
   __property bool Explicit = { read = FExplicit, write = FExplicit };
   __property bool MungeStringValues = { read = FMungeStringValues, write = FMungeStringValues };
+  __property AnsiString Source = { read = GetSource };
 
 protected:
   AnsiString FStorage;
@@ -72,6 +73,7 @@ protected:
   static AnsiString __fastcall IncludeTrailingBackslash(const AnsiString & S);
   static AnsiString __fastcall ExcludeTrailingBackslash(const AnsiString & S);
   AnsiString __fastcall MungeSubKey(AnsiString Key, bool Path);
+  virtual AnsiString __fastcall GetSource() = 0;
 };
 //---------------------------------------------------------------------------
 class TRegistryStorage : public THierarchicalStorage
@@ -114,6 +116,7 @@ public:
 protected:
   int __fastcall GetFailed();
   virtual void __fastcall SetAccessMode(TStorageAccessMode value);
+  virtual AnsiString __fastcall GetSource();
 
   __property int Failed  = { read=GetFailed, write=FFailed };
 
@@ -164,6 +167,7 @@ private:
   void __fastcall ApplyOverrides();
 protected:
   __property AnsiString CurrentSection  = { read=GetCurrentSection };
+  virtual AnsiString __fastcall GetSource();
 };
 //---------------------------------------------------------------------------
 AnsiString __fastcall PuttyMungeStr(const AnsiString Str);

+ 1 - 0
core/Interface.h

@@ -71,6 +71,7 @@ enum TQueryType { qtConfirmation, qtWarning, qtError, qtInformation };
 enum TPromptKind
 {
   pkPrompt,
+  pkFileName,
   pkUserName,
   pkPassphrase,
   pkTIS,

+ 16 - 6
core/ScpFileSystem.cpp

@@ -600,7 +600,9 @@ void __fastcall TSCPFileSystem::ReadCommandOutput(int Params, const AnsiString *
         Message += FOutput->Text;
       }
       while (!Message.IsEmpty() && (Message.LastDelimiter("\n\r") == Message.Length()))
+      {
         Message.SetLength(Message.Length() - 1);
+      }
 
       bool WrongReturnCode =
         (ReturnCode > 1) || (ReturnCode == 1 && !(Params & coIgnoreWarnings));
@@ -1151,8 +1153,11 @@ void __fastcall TSCPFileSystem::ChangeFileProperties(const AnsiString FileName,
       Action.Recursive();
     }
 
-    ExecCommand(fsChangeMode,
-      ARRAYOFCONST((RecursiveStr, Rights.SimplestStr, DelimitedName)));
+    if ((Rights.NumberSet | Rights.NumberUnset) != TRights::rfNo)
+    {
+      ExecCommand(fsChangeMode,
+        ARRAYOFCONST((RecursiveStr, Rights.SimplestStr, DelimitedName)));
+    }
 
     // if file is directory and we do recursive mode settings with
     // add-x-to-directories option on, add those X
@@ -1285,7 +1290,7 @@ void __fastcall TSCPFileSystem::SCPResponse(bool * GotLastLine)
       AnsiString Line = AnsiString(Resp) + Msg;
       if (IsLastLine(Line))
       {
-        if (GotLastLine)
+        if (GotLastLine != NULL)
         {
           *GotLastLine = true;
         }
@@ -1300,7 +1305,10 @@ void __fastcall TSCPFileSystem::SCPResponse(bool * GotLastLine)
         catch(...)
         {
           // when ReadCommandOutput() fails than remote SCP is terminated already
-          *GotLastLine = true;
+          if (GotLastLine != NULL)
+          {
+            *GotLastLine = true;
+          }
           throw;
         }
       }
@@ -1615,6 +1623,7 @@ void __fastcall TSCPFileSystem::SCPSource(const AnsiString FileName,
         // than convert EOL and send it at once, because before converting EOL
         // we can't know its size
         TFileBuffer AsciiBuf;
+        bool ConvertToken = false;
         do
         {
           // Buffer for one block of data
@@ -1635,7 +1644,7 @@ void __fastcall TSCPFileSystem::SCPSource(const AnsiString FileName,
           if (OperationProgress->AsciiTransfer)
           {
             BlockBuf.Convert(FTerminal->Configuration->LocalEOLType,
-              FTerminal->SessionData->EOLType, cpRemoveCtrlZ | cpRemoveBOM);
+              FTerminal->SessionData->EOLType, cpRemoveCtrlZ | cpRemoveBOM, ConvertToken);
             BlockBuf.Memory->Seek(0, soFromBeginning);
             AsciiBuf.ReadStream(BlockBuf.Memory, BlockBuf.Size, true);
             // We don't need it any more
@@ -2375,6 +2384,7 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
               {
                 // Buffer for one block of data
                 TFileBuffer BlockBuf;
+                bool ConvertToken = false;
 
                 do
                 {
@@ -2388,7 +2398,7 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
                   {
                     unsigned int PrevBlockSize = BlockBuf.Size;
                     BlockBuf.Convert(FTerminal->SessionData->EOLType,
-                      FTerminal->Configuration->LocalEOLType, 0);
+                      FTerminal->Configuration->LocalEOLType, 0, ConvertToken);
                     OperationProgress->SetLocalSize(
                       OperationProgress->LocalSize - PrevBlockSize + BlockBuf.Size);
                   }

+ 48 - 5
core/SessionData.cpp

@@ -170,6 +170,7 @@ void __fastcall TSessionData::Default()
 
   Selected = false;
   FModified = false;
+  FSource = ::ssNone;
 
   // add also to TSessionLog::AddStartupInfo()
 }
@@ -302,6 +303,7 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
 
     #undef DUPL
     FModified = ((TSessionData *)Source)->Modified;
+    FSource = ((TSessionData *)Source)->FSource;
   }
   else
   {
@@ -568,6 +570,7 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
   }
 
   FModified = false;
+  FSource = ssStored;
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
@@ -851,6 +854,34 @@ bool __fastcall TSessionData::HasAnyPassword()
   return !FPassword.IsEmpty() || !FProxyPassword.IsEmpty() || !FTunnelPassword.IsEmpty();
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::Modify()
+{
+  FModified = true;
+  if (FSource == ssStored)
+  {
+    FSource = ssStoredModified;
+  }
+}
+//---------------------------------------------------------------------
+AnsiString __fastcall TSessionData::GetSource()
+{
+  switch (FSource)
+  {
+    case ::ssNone:
+      return "Ad-Hoc session";
+
+    case ssStored:
+      return "Stored session";
+
+    case ssStoredModified:
+      return "Modified stored session";
+
+    default:
+      assert(false);
+      return "";
+  }
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::SaveRecryptedPasswords(THierarchicalStorage * Storage)
 {
   if (Storage->OpenSubKey(InternalStorageKey, true))
@@ -998,7 +1029,19 @@ bool __fastcall TSessionData::ParseUrl(AnsiString Url, TOptions * Options,
         HostInfo = ConnectInfo;
       }
 
-      HostName = DecodeUrlChars(CutToChar(HostInfo, ':', true));
+      if ((HostInfo.Length() >= 2) && (HostInfo[1] == '[') && ((P = HostInfo.Pos("]")) > 0))
+      {
+        HostName = HostInfo.SubString(2, P - 2);
+        HostInfo.Delete(1, P);
+        if (!HostInfo.IsEmpty() && (HostInfo[1] == ':'))
+        {
+          HostInfo.Delete(1, 1);
+        }
+      }
+      else
+      {
+        HostName = DecodeUrlChars(CutToChar(HostInfo, ':', true));
+      }
 
       // expanded from ?: operator, as it caused strange "access violation" errors
       if (!HostInfo.IsEmpty())
@@ -1206,7 +1249,7 @@ void __fastcall TSessionData::SetHostName(AnsiString value)
       value = value.SubString(P + 1, value.Length() - P);
     }
     FHostName = value;
-    FModified = true;
+    Modify();
 
     Password = XPassword;
     if (!XPassword.IsEmpty())
@@ -1470,7 +1513,7 @@ void __fastcall TSessionData::SetPublicKeyFile(AnsiString value)
   if (FPublicKeyFile != value)
   {
     FPublicKeyFile = StripPathQuotes(value);
-    FModified = true;
+    Modify();
   }
 }
 //---------------------------------------------------------------------
@@ -1900,7 +1943,7 @@ void __fastcall TSessionData::SetTunnelHostName(AnsiString value)
       value = value.SubString(P + 1, value.Length() - P);
     }
     FTunnelHostName = value;
-    FModified = true;
+    Modify();
 
     TunnelPassword = XTunnelPassword;
     if (!XTunnelPassword.IsEmpty())
@@ -1945,7 +1988,7 @@ void __fastcall TSessionData::SetTunnelPublicKeyFile(AnsiString value)
   if (FTunnelPublicKeyFile != value)
   {
     FTunnelPublicKeyFile = StripPathQuotes(value);
-    FModified = true;
+    Modify();
   }
 }
 //---------------------------------------------------------------------

+ 6 - 1
core/SessionData.h

@@ -10,7 +10,7 @@
 #include "Configuration.h"
 //---------------------------------------------------------------------------
 #define SET_SESSION_PROPERTY(Property) \
-  if (F##Property != value) { F##Property = value; FModified = true; }
+  if (F##Property != value) { F##Property = value; Modify(); }
 //---------------------------------------------------------------------------
 enum TCipher { cipWarn, cip3DES, cipBlowfish, cipAES, cipDES, cipArcfour };
 #define CIPHER_COUNT (cipArcfour+1)
@@ -31,6 +31,7 @@ enum TSftpBug { sbSymlink, sbSignedTS };
 enum TPingType { ptOff, ptNullPacket, ptDummyCommand };
 enum TAddressFamily { afAuto, afIPv4, afIPv6 };
 enum TFtps { ftpsNone, ftpsImplicit, ftpsExplicitSsl, ftpsExplicitTls };
+enum TSessionSource { ssNone, ssStored, ssStoredModified };
 //---------------------------------------------------------------------------
 extern const char CipherNames[CIPHER_COUNT][10];
 extern const char KexNames[KEX_COUNT][20];
@@ -147,6 +148,7 @@ private:
   AnsiString FOrigHostName;
   int FOrigPortNumber;
   TProxyMethod FOrigProxyMethod;
+  TSessionSource FSource;
 
   void __fastcall SetHostName(AnsiString value);
   void __fastcall SetPortNumber(int value);
@@ -277,6 +279,8 @@ private:
   TDateTime __fastcall GetTimeoutDT();
   void __fastcall SavePasswords(THierarchicalStorage * Storage, bool PuttyExport);
   AnsiString __fastcall GetLocalName();
+  void __fastcall Modify();
+  AnsiString __fastcall GetSource();
   static AnsiString __fastcall EncryptPassword(const AnsiString & Password, AnsiString Key);
   static AnsiString __fastcall DecryptPassword(const AnsiString & Password, AnsiString Key);
   static AnsiString __fastcall StronglyRecryptPassword(const AnsiString & Password, AnsiString Key);
@@ -422,6 +426,7 @@ public:
   __property AnsiString OrigHostName = { read = FOrigHostName };
   __property int OrigPortNumber = { read = FOrigPortNumber };
   __property AnsiString LocalName = { read = GetLocalName };
+  __property AnsiString Source = { read = GetSource };
 };
 //---------------------------------------------------------------------------
 class TStoredSessionList : public TNamedObjectList

+ 10 - 1
core/SessionInfo.cpp

@@ -899,9 +899,18 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
     #define ADF(S, F) DoAdd(llMessage, FORMAT(S, F), DoAddToSelf);
     AddSeparator();
     ADF("WinSCP %s (OS %s)", (FConfiguration->VersionStr, FConfiguration->OSVersionStr));
+    THierarchicalStorage * Storage = FConfiguration->CreateScpStorage(false);
+    try
+    {
+      ADF("Configuration: %s", (Storage->Source));
+    }
+    __finally
+    {
+      delete Storage;
+    }
     ADF("Login time: %s", (FormatDateTime("dddddd tt", Now())));
     AddSeparator();
-    ADF("Session name: %s", (Data->SessionName));
+    ADF("Session name: %s (%s)", (Data->SessionName, Data->Source));
     ADF("Host name: %s (Port: %d)", (Data->HostName, Data->PortNumber));
     ADF("User name: %s (Password: %s, Key file: %s)",
       (Data->UserName, BooleanToEngStr(!Data->Password.IsEmpty()),

+ 8 - 4
core/SftpFileSystem.cpp

@@ -542,7 +542,8 @@ public:
 
   inline AnsiString GetUtfString()
   {
-    return DecodeUTF(GetString());
+    AnsiString Result = DecodeUTF(GetString());
+    return Result;
   }
 
   inline AnsiString GetString(bool Utf)
@@ -1340,6 +1341,7 @@ public:
     OperationProgress = NULL;
     FLastBlockSize = 0;
     FEnd = false;
+    FConvertToken = false;
   }
 
   virtual __fastcall ~TSFTPUploadQueue()
@@ -1387,7 +1389,7 @@ protected:
         {
           __int64 PrevBufSize = BlockBuf.Size;
           BlockBuf.Convert(FTerminal->Configuration->LocalEOLType,
-            FFileSystem->GetEOL(), cpRemoveCtrlZ | cpRemoveBOM);
+            FFileSystem->GetEOL(), cpRemoveCtrlZ | cpRemoveBOM, FConvertToken);
           // update transfer size with difference arised from EOL conversion
           OperationProgress->ChangeTransferSize(OperationProgress->TransferSize -
             PrevBufSize + BlockBuf.Size);
@@ -1447,6 +1449,7 @@ private:
   bool FEnd;
   __int64 FTransfered;
   AnsiString FHandle;
+  bool FConvertToken;
 };
 //---------------------------------------------------------------------------
 class TSFTPLoadFilesPropertiesQueue : public TSFTPFixedLenQueue
@@ -3759,7 +3762,7 @@ void __fastcall TSFTPFileSystem::SFTPConfirmOverwrite(AnsiString & FileName,
   }
   else if (Answer == qaIgnore)
   {
-    if (FTerminal->PromptUser(FTerminal->SessionData, pkPrompt, LoadStr(RENAME_TITLE), "",
+    if (FTerminal->PromptUser(FTerminal->SessionData, pkFileName, LoadStr(RENAME_TITLE), "",
           LoadStr(RENAME_PROMPT2), true, 0, FileName))
     {
       OverwriteMode = omOverwrite;
@@ -5053,6 +5056,7 @@ void __fastcall TSFTPFileSystem::SFTPSink(const AnsiString FileName,
           unsigned long Missing = 0;
           unsigned long DataLen = 0;
           unsigned long BlockSize;
+          bool ConvertToken = false;
 
           while (!Eof)
           {
@@ -5136,7 +5140,7 @@ void __fastcall TSFTPFileSystem::SFTPSink(const AnsiString FileName,
                 assert(!ResumeTransfer && !ResumeAllowed);
 
                 unsigned int PrevBlockSize = BlockBuf.Size;
-                BlockBuf.Convert(GetEOL(), FTerminal->Configuration->LocalEOLType, 0);
+                BlockBuf.Convert(GetEOL(), FTerminal->Configuration->LocalEOLType, 0, ConvertToken);
                 OperationProgress->SetLocalSize(
                   OperationProgress->LocalSize - PrevBlockSize + BlockBuf.Size);
               }

+ 12 - 1
core/Terminal.cpp

@@ -645,6 +645,10 @@ void __fastcall TTerminal::ResetConnection()
     delete FDirectoryChangesCache;
     FDirectoryChangesCache = NULL;
   }
+
+  FFiles->Directory = "";
+  // note that we cannot clear contained files
+  // as they can still be referenced in the GUI atm
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::Open()
@@ -956,7 +960,14 @@ void __fastcall TTerminal::Reopen(int Params)
       AutoReadDirectory = false;
     }
 
-    SessionData->RemoteDirectory = CurrentDirectory;
+    // only peek, we may not be connected at all atm,
+    // so make sure we do not try retrieving current directory from the server
+    // (particularly with FTP)
+    AnsiString ACurrentDirectory = PeekCurrentDirectory();
+    if (!ACurrentDirectory.IsEmpty())
+    {
+      SessionData->RemoteDirectory = ACurrentDirectory;
+    }
     if (SessionData->FSProtocol == fsSFTP)
     {
       SessionData->FSProtocol = (FFSProtocol == cfsSCP ? fsSCPonly : fsSFTPonly);

+ 8 - 0
filezilla/AsyncSslSocketLayer.cpp

@@ -1288,6 +1288,10 @@ BOOL CAsyncSslSocketLayer::ShutDown(int nHow /*=sends*/)
 			int error = pSSL_get_error(m_ssl, -1);
 			if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)
 			{
+#ifdef MPEXT
+				// retry shutdown later
+				m_nShutDown = 0;
+#endif
 				TriggerEvents();
 				WSASetLastError(WSAEWOULDBLOCK);
 				return FALSE;
@@ -1331,9 +1335,13 @@ BOOL CAsyncSslSocketLayer::ShutDownComplete()
 	} while (numread > 0);
 
 	if (pBIO_ctrl_pending(m_nbio))
+	{
 		return FALSE;
+	}
 	else
+	{
 		return TRUE;
+	}
 }
 
 void CAsyncSslSocketLayer::apps_ssl_info_callback(const SSL *s, int where, int ret)

+ 2 - 2
forms/About.cpp

@@ -177,9 +177,9 @@ void __fastcall TAboutDialog::LoadData()
   VersionLabel->Caption = Version;
 }
 //---------------------------------------------------------------------------
-void __fastcall TAboutDialog::DisplayLicense(TObject * Sender)
+void __fastcall TAboutDialog::PuttyLicenseLabelClick(TObject * /*Sender*/)
 {
-  DoLicenseDialog((TLicense)((TComponent*)Sender)->Tag);
+  DoLicenseDialog(lcPutty);
 }
 //---------------------------------------------------------------------------
 void __fastcall TAboutDialog::LicenseButtonClick(TObject * /*Sender*/)

+ 1 - 2
forms/About.dfm

@@ -3658,7 +3658,6 @@ object AboutDialog: TAboutDialog
       Caption = 'Copyright '#169' xxxx The OpenSSL Project'
     end
     object PuttyLicenseLabel: TStaticText
-      Tag = 1
       Left = 8
       Top = 80
       Width = 74
@@ -3666,7 +3665,7 @@ object AboutDialog: TAboutDialog
       Caption = 'Display license'
       TabOrder = 0
       TabStop = True
-      OnClick = DisplayLicense
+      OnClick = PuttyLicenseLabelClick
     end
     object PuttyHomepageLabel: TStaticText
       Left = 8

+ 1 - 1
forms/About.h

@@ -57,7 +57,7 @@ __published:
   TLabel *OpenSSLVersionLabel;
   TStaticText *OpenSSLHomepageLabel;
   TLabel *OpenSSLCopyrightLabel;
-  void __fastcall DisplayLicense(TObject *Sender);
+  void __fastcall PuttyLicenseLabelClick(TObject *Sender);
   void __fastcall LicenseButtonClick(TObject *Sender);
   void __fastcall HelpButtonClick(TObject *Sender);
   void __fastcall RegistrationProductIdLabelClick(TObject *Sender);

+ 31 - 12
forms/CustomScpExplorer.cpp

@@ -1,4 +1,5 @@
 //---------------------------------------------------------------------------
+#define NO_WIN32_LEAN_AND_MEAN
 #include <vcl.h>
 #pragma hdrstop
 
@@ -21,6 +22,7 @@
 #include <SynchronizeProgress.h>
 
 #include <DragExt.h>
+#include <WinApi.h>
 
 #include "GUITools.h"
 #include "NonVisual.h"
@@ -890,10 +892,20 @@ void __fastcall TCustomScpExplorerForm::FileOperationProgress(
     {
       FProgressForm->OnceDoneOperation = odoDisconnect;
     }
+
+    if (FTaskbarList != NULL)
+    {
+      FTaskbarList->SetProgressState(Application->Handle, TBPF_NORMAL);
+    }
   }
   // operation is finished (or terminated), so we hide progress form
   else if (!ProgressData.InProgress && FProgressForm)
   {
+    if (FTaskbarList != NULL)
+    {
+      FTaskbarList->SetProgressState(Application->Handle, TBPF_NOPROGRESS);
+    }
+
     SAFE_DESTROY(FProgressForm);
 
     if ((ProgressData.Operation != foCalculateSize) &&
@@ -907,6 +919,13 @@ void __fastcall TCustomScpExplorerForm::FileOperationProgress(
   if (FProgressForm)
   {
     FProgressForm->SetProgressData(ProgressData);
+
+    if (FTaskbarList != NULL)
+    {
+      assert(ProgressData.InProgress);
+      FTaskbarList->SetProgressValue(Application->Handle, ProgressData.OverallProgress(), 100);
+    }
+
     if (FProgressForm->Cancel > ProgressData.Cancel)
     {
       ProgressData.Cancel = FProgressForm->Cancel;
@@ -1026,11 +1045,16 @@ struct THistoryItemData
   short int Index;
 };
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::HistoryGo(TOperationSide Side, int Index)
+{
+  DirView(Side)->HistoryGo(Index);
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::HistoryItemClick(System::TObject* Sender)
 {
   TTBCustomItem * Item = dynamic_cast<TTBCustomItem *>(Sender);
   THistoryItemData Data = *reinterpret_cast<THistoryItemData*>(&(Item->Tag));
-  DirView(Data.Side)->HistoryGo(Data.Index);
+  HistoryGo(Data.Side, Data.Index);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::UpdateHistoryMenu(TOperationSide Side,
@@ -6477,17 +6501,7 @@ void __fastcall TCustomScpExplorerForm::DirViewEditing(
     // OnEditing is called also from TCustomListView::CanEdit
     if (Edit != NULL)
     {
-      AnsiString Text;
-      Text.SetLength(GetWindowTextLength(Edit) + 1);
-      GetWindowText(Edit, Text.c_str(), Text.Length());
-
-      int P = Text.LastDelimiter(".");
-      if (P > 0)
-      {
-        // SendMessage does not work, edit control is probably not fully
-        // initialized yet atm
-        PostMessage(Edit, EM_SETSEL, 0, P - 1);
-      }
+      EditSelectBaseName(Edit);
     }
   }
 }
@@ -6528,3 +6542,8 @@ void __fastcall TCustomScpExplorerForm::FindFiles()
     DoFocusRemotePath(Path);
   }
 }
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::UpdateTaskbarList(ITaskbarList3 * TaskbarList)
+{
+  FTaskbarList = TaskbarList;
+}

+ 4 - 0
forms/CustomScpExplorer.h

@@ -42,6 +42,7 @@ class TEditorManager;
 class TEditorData;
 class TTransferPresetNoteData;
 struct TEditedFileData;
+class ITaskbarList3;
 //---------------------------------------------------------------------------
 enum TActionAllowed { aaShortCut, aaUpdate, aaExecute };
 enum TActionFlag { afLocal = 1, afRemote = 2, afExplorer = 4 , afCommander = 8 };
@@ -206,6 +207,7 @@ private:
   TTBXPopupMenu * FCustomCommandMenu;
   TStrings * FCustomCommandLocalFileList;
   TStrings * FCustomCommandRemoteFileList;
+  ITaskbarList3 * FTaskbarList;
 
   bool __fastcall GetEnableFocusedOperation(TOperationSide Side, int FilesOnly);
   bool __fastcall GetEnableSelectedOperation(TOperationSide Side, int FilesOnly);
@@ -524,6 +526,8 @@ public:
   void __fastcall PopupTrayBalloon(TTerminal * Terminal, const AnsiString & Str,
     TQueryType Type, Exception * E = NULL, unsigned int Seconds = 0);
   void __fastcall FindFiles();
+  virtual void __fastcall HistoryGo(TOperationSide Side, int Index);
+  void __fastcall UpdateTaskbarList(ITaskbarList3 * TaskbarList);
 
   __property bool ComponentVisible[Word Component] = { read = GetComponentVisible, write = SetComponentVisible };
   __property bool EnableFocusedOperation[TOperationSide Side] = { read = GetEnableFocusedOperation, index = 0 };

+ 30 - 4
forms/Login.cpp

@@ -1221,6 +1221,7 @@ void __fastcall TLoginDialog::FormShow(TObject * /*Sender*/)
       SessionTree->Selected->MakeVisible();
     }
     LoadConfiguration();
+    LoadState();
   }
 }
 //---------------------------------------------------------------------------
@@ -1532,7 +1533,9 @@ bool __fastcall TLoginDialog::Execute(TSessionData *& Data)
 {
   SetSessionData(Data);
   LoadConfiguration();
+  LoadState();
   bool Result = (ShowModal() == mrOk);
+  SaveState();
   if (Result)
   {
     SaveConfiguration();
@@ -1547,6 +1550,17 @@ bool __fastcall TLoginDialog::Execute(TSessionData *& Data)
   return Result;
 }
 //---------------------------------------------------------------------------
+void __fastcall TLoginDialog::SaveState()
+{
+  assert(CustomWinConfiguration);
+  CustomWinConfiguration->ShowAdvancedLoginOptions = ShowAdvancedLoginOptionsCheck->Checked;
+}
+//---------------------------------------------------------------------------
+void __fastcall TLoginDialog::LoadState()
+{
+  ShowAdvancedLoginOptionsCheck->Checked = CustomWinConfiguration->ShowAdvancedLoginOptions;
+}
+//---------------------------------------------------------------------------
 void __fastcall TLoginDialog::SaveConfiguration()
 {
   assert(CustomWinConfiguration);
@@ -1555,7 +1569,6 @@ void __fastcall TLoginDialog::SaveConfiguration()
   {
     LoggingFrame->SaveConfiguration();
     GeneralSettingsFrame->SaveConfiguration();
-    CustomWinConfiguration->ShowAdvancedLoginOptions = ShowAdvancedLoginOptionsCheck->Checked;
   }
   __finally
   {
@@ -1568,7 +1581,6 @@ void __fastcall TLoginDialog::LoadConfiguration()
   assert(CustomWinConfiguration);
   LoggingFrame->LoadConfiguration();
   GeneralSettingsFrame->LoadConfiguration();
-  ShowAdvancedLoginOptionsCheck->Checked = CustomWinConfiguration->ShowAdvancedLoginOptions;
   UpdateControls();
 }
 //---------------------------------------------------------------------------
@@ -1707,6 +1719,7 @@ void __fastcall TLoginDialog::Dispatch(void * Message)
     if (M->WParam == 0)
     {
       SaveConfiguration();
+      SaveState();
       SaveSession(FSessionData);
       FSavedTab = PageControl->ActivePage;
       FSavedSession = ((SessionTree->Selected != NULL) ?
@@ -1863,13 +1876,19 @@ void __fastcall TLoginDialog::SessionTreeCustomDrawItem(
 {
   TSessionData * Data = (TSessionData *)Node->Data;
   TFontStyles Styles = Sender->Canvas->Font->Style;
+
   if ((Data != NULL) && Data->Special)
   {
     Styles = Styles << fsBold << fsUnderline;
   }
   else
   {
-    if ((Data == NULL) && State.Empty() && !Node->DropTarget)
+    Styles = Styles >> fsBold >> fsUnderline;
+  }
+
+  if (State.Empty() && !Node->DropTarget)
+  {
+    if (Data == NULL)
     {
       bool AnySession = false;
       TTreeNode * ANode = Node->GetNext();
@@ -1884,8 +1903,15 @@ void __fastcall TLoginDialog::SessionTreeCustomDrawItem(
         Sender->Canvas->Font->Color = clGrayText;
       }
     }
-    Styles = Styles >> fsBold >> fsUnderline;
+    else
+    {
+      if (Data->Color != 0)
+      {
+        Sender->Canvas->Brush->Color = (TColor)Data->Color;
+      }
+    }
   }
+
   Sender->Canvas->Font->Style = Styles;
   DefaultDraw = true;
 }

+ 0 - 1
forms/Login.dfm

@@ -1161,7 +1161,6 @@ object LoginDialog: TLoginDialog
             Width = 321
             Height = 53
             Anchors = [akLeft, akTop, akRight]
-            MaxLength = 50
             ScrollBars = ssVertical
             TabOrder = 0
           end

+ 2 - 0
forms/Login.h

@@ -421,6 +421,8 @@ protected:
   void __fastcall Default();
   void __fastcall LoadConfiguration();
   void __fastcall SaveConfiguration();
+  void __fastcall LoadState();
+  void __fastcall SaveState();
   void __fastcall ShowPreferencesDialog();
   void __fastcall ChangePage(TTabSheet * Tab);
   virtual void __fastcall Dispatch(void * Message);

+ 2 - 2
forms/NonVisual.cpp

@@ -518,8 +518,8 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
     #undef STYLEACTION
 
     #define PANEL_ACTIONS(SIDE) \
-      EXE(SIDE ## BackAction, DirView(os ## SIDE)->HistoryGo(-1)) \
-      EXE(SIDE ## ForwardAction, DirView(os ## SIDE)->HistoryGo(1)) \
+      EXE(SIDE ## BackAction, ScpExplorer->HistoryGo(os ## SIDE, -1)) \
+      EXE(SIDE ## ForwardAction, ScpExplorer->HistoryGo(os ## SIDE, 1)) \
       EXE(SIDE ## ParentDirAction, DirView(os ## SIDE)->ExecuteParentDirectory()) \
       EXE(SIDE ## RootDirAction, DirView(os ## SIDE)->ExecuteRootDirectory()) \
       EXE(SIDE ## HomeDirAction, ScpExplorer->HomeDirectory(os ## SIDE)) \

+ 53 - 43
forms/ScpCommander.cpp

@@ -46,6 +46,24 @@
 #pragma resource "*.dfm"
 #endif
 //---------------------------------------------------------------------------
+class TSynchronizedBrowsingGuard
+{
+public:
+  TSynchronizedBrowsingGuard()
+  {
+    FWasSynchronisingBrowsing = NonVisualDataModule->SynchronizeBrowsingAction->Checked;
+    NonVisualDataModule->SynchronizeBrowsingAction->Checked = false;
+  }
+
+  ~TSynchronizedBrowsingGuard()
+  {
+    NonVisualDataModule->SynchronizeBrowsingAction->Checked = FWasSynchronisingBrowsing;
+  }
+
+private:
+  bool FWasSynchronisingBrowsing;
+};
+//---------------------------------------------------------------------------
 __fastcall TScpCommanderForm::TScpCommanderForm(TComponent* Owner)
         : TCustomScpExplorerForm(Owner)
 {
@@ -1211,16 +1229,8 @@ void __fastcall TScpCommanderForm::DoOpenDirectoryDialog(TOpenDirectoryMode Mode
     }
     else
     {
-      bool WasSynchronisingBrowsing = NonVisualDataModule->SynchronizeBrowsingAction->Checked;
-      NonVisualDataModule->SynchronizeBrowsingAction->Checked = false;
-      try
-      {
-        TCustomScpExplorerForm::DoOpenDirectoryDialog(Mode, Side);
-      }
-      __finally
-      {
-        NonVisualDataModule->SynchronizeBrowsingAction->Checked = WasSynchronisingBrowsing;
-      }
+      TSynchronizedBrowsingGuard SynchronizedBrowsingGuard;
+      TCustomScpExplorerForm::DoOpenDirectoryDialog(Mode, Side);
     }
 
     // for second and further rounds, always do browse only
@@ -1231,30 +1241,22 @@ void __fastcall TScpCommanderForm::DoOpenDirectoryDialog(TOpenDirectoryMode Mode
 //---------------------------------------------------------------------------
 void __fastcall TScpCommanderForm::DoOpenBookmark(AnsiString Local, AnsiString Remote)
 {
-  bool WasSynchronisingBrowsing = NonVisualDataModule->SynchronizeBrowsingAction->Checked;
-  NonVisualDataModule->SynchronizeBrowsingAction->Checked = false;
+  TSynchronizedBrowsingGuard SynchronizedBrowsingGuard;
+  // make sure that whatever path is valid it is opened first and only
+  // after that an eventual error is reported
   try
   {
-    // make sure that whatever path is valid it is opened first and only
-    // after that an eventual error is reported
-    try
-    {
-      if (!Local.IsEmpty())
-      {
-        LocalDirView->Path = Local;
-      }
-    }
-    __finally
+    if (!Local.IsEmpty())
     {
-      if (!Remote.IsEmpty())
-      {
-        RemoteDirView->Path = Remote;
-      }
+      LocalDirView->Path = Local;
     }
   }
   __finally
   {
-    NonVisualDataModule->SynchronizeBrowsingAction->Checked = WasSynchronisingBrowsing;
+    if (!Remote.IsEmpty())
+    {
+      RemoteDirView->Path = Remote;
+    }
   }
 }
 //---------------------------------------------------------------------------
@@ -1896,16 +1898,8 @@ void __fastcall TScpCommanderForm::LocalDriveViewRefreshDrives(TObject * /*Sende
 //---------------------------------------------------------------------------
 void __fastcall TScpCommanderForm::HomeDirectory(TOperationSide Side)
 {
-  bool WasSynchronisingBrowsing = NonVisualDataModule->SynchronizeBrowsingAction->Checked;
-  NonVisualDataModule->SynchronizeBrowsingAction->Checked = false;
-  try
-  {
-    TCustomScpExplorerForm::HomeDirectory(Side);
-  }
-  __finally
-  {
-    NonVisualDataModule->SynchronizeBrowsingAction->Checked = WasSynchronisingBrowsing;
-  }
+  TSynchronizedBrowsingGuard SynchronizedBrowsingGuard;
+  TCustomScpExplorerForm::HomeDirectory(Side);
 }
 //---------------------------------------------------------------------------
 void __fastcall TScpCommanderForm::QueueSubmenuItemPopup(
@@ -1916,15 +1910,31 @@ void __fastcall TScpCommanderForm::QueueSubmenuItemPopup(
 //---------------------------------------------------------------------------
 void __fastcall TScpCommanderForm::DoFocusRemotePath(AnsiString Path)
 {
-  bool WasSynchronisingBrowsing = NonVisualDataModule->SynchronizeBrowsingAction->Checked;
-  NonVisualDataModule->SynchronizeBrowsingAction->Checked = false;
-  try
+  TSynchronizedBrowsingGuard SynchronizedBrowsingGuard;
+  TCustomScpExplorerForm::DoFocusRemotePath(Path);
+}
+//---------------------------------------------------------------------------
+void __fastcall TScpCommanderForm::HistoryGo(TOperationSide Side, int Index)
+{
+  TOperationSide OtherSide = ((Side == osLocal) ? osRemote : osLocal);
+  if (NonVisualDataModule->SynchronizeBrowsingAction->Checked &&
+      ((Index < 0) ? (-Index < DirView(OtherSide)->BackCount) : (Index < DirView(OtherSide)->ForwardCount)))
   {
-    TCustomScpExplorerForm::DoFocusRemotePath(Path);
+    TSynchronizedBrowsingGuard SynchronizedBrowsingGuard;
+    TCustomScpExplorerForm::HistoryGo(Side, Index);
+    TCustomScpExplorerForm::HistoryGo(OtherSide, Index);
   }
-  __finally
+  else
   {
-    NonVisualDataModule->SynchronizeBrowsingAction->Checked = WasSynchronisingBrowsing;
+    TCustomScpExplorerForm::HistoryGo(Side, Index);
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TScpCommanderForm::DirViewHistoryGo(
+  TCustomDirView * Sender, int Index, bool & Cancel)
+{
+  TOperationSide Side = (Sender == DirView(osRemote) ? osRemote : osLocal);
+  HistoryGo(Side, Index);
+  Cancel = true;
+}
+//---------------------------------------------------------------------------

+ 2 - 0
forms/ScpCommander.dfm

@@ -1135,6 +1135,7 @@ inherited ScpCommanderForm: TScpCommanderForm
       PathLabel = RemotePathLabel
       AddParentDir = True
       OnDDFileOperationExecuted = RemoteFileControlDDFileOperationExecuted
+      OnHistoryGo = DirViewHistoryGo
       OnPathChange = RemoteDirViewPathChange
     end
     inherited RemoteDriveView: TUnixDriveView
@@ -1336,6 +1337,7 @@ inherited ScpCommanderForm: TScpCommanderForm
       WatchForChanges = True
       OnFileIconForName = LocalDirViewFileIconForName
       OnHistoryChange = DirViewHistoryChange
+      OnHistoryGo = DirViewHistoryGo
       OnPathChange = LocalDirViewPathChange
     end
     object LocalTopDock: TTBXDock

+ 3 - 0
forms/ScpCommander.h

@@ -433,6 +433,8 @@ __published:
   void __fastcall LocalDriveViewRefreshDrives(TObject *Sender);
   void __fastcall QueueSubmenuItemPopup(TTBCustomItem *Sender,
           bool FromLink);
+  void __fastcall DirViewHistoryGo(TCustomDirView *Sender, int Index,
+          bool &Cancel);
 
 private:
   float FLastLeftPanelWidth;
@@ -530,6 +532,7 @@ public:
   virtual AnsiString __fastcall PathForCaption();
   virtual void __fastcall BeforeAction();
   virtual void __fastcall HomeDirectory(TOperationSide Side);
+  virtual void __fastcall HistoryGo(TOperationSide Side, int Index);
 
   __property float LeftPanelWidth = { read = GetLeftPanelWidth, write = SetLeftPanelWidth };
 };

+ 12 - 4
forms/Synchronize.cpp

@@ -421,11 +421,19 @@ bool __fastcall TSynchronizeDialog::GetSaveSettings()
 //---------------------------------------------------------------------------
 void __fastcall TSynchronizeDialog::FormShow(TObject * /*Sender*/)
 {
-  ClearLog();
-  UpdateControls();
-  if (FStartImmediatelly)
+  // OnShow gets called more than once sometimes
+  if (!FSynchronizing)
+  {
+    ClearLog();
+    UpdateControls();
+    if (FStartImmediatelly)
+    {
+      StartButtonClick(NULL);
+    }
+  }
+  else
   {
-    StartButtonClick(NULL);
+    assert(FStartImmediatelly);
   }
 }
 //---------------------------------------------------------------------------

+ 5 - 4
packages/filemng/CustomDirView.hpp

@@ -116,15 +116,13 @@ struct TFileFilter
 	System::TDateTime ModificationTo;
 } ;
 
-#pragma option push -b-
-enum THistoryDirection { hdBack, hdForward };
-#pragma option pop
-
 class DELPHICLASS TCustomDirView;
 typedef void __fastcall (__closure *TDirViewNotifyEvent)(TCustomDirView* Sender);
 
 typedef void __fastcall (__closure *TDVGetFilterEvent)(TCustomDirView* Sender, bool Select, TFileFilter &Filter);
 
+typedef void __fastcall (__closure *TDVHistoryGoEvent)(TCustomDirView* Sender, int Index, bool &Cancel);
+
 #pragma option push -b-
 enum TCompareCriteria { ccTime, ccSize };
 #pragma option pop
@@ -234,6 +232,7 @@ private:
 	TRenameEvent FOnBeginRename;
 	TRenameEvent FOnEndRename;
 	TDirViewNotifyEvent FOnHistoryChange;
+	TDVHistoryGoEvent FOnHistoryGo;
 	TDirViewNotifyEvent FOnPathChange;
 	bool FShowHiddenFiles;
 	bool FSavedSelection;
@@ -369,6 +368,7 @@ protected:
 	virtual void __fastcall SetMask(AnsiString Value);
 	void __fastcall ScrollOnDragOverBeforeUpdate(System::TObject* ObjectToValidate);
 	void __fastcall ScrollOnDragOverAfterUpdate(void);
+	void __fastcall DoHistoryGo(int Index);
 	virtual int __fastcall HiddenCount(void) = 0 ;
 	virtual int __fastcall FilteredCount(void) = 0 ;
 	__property Controls::TImageList* ImageList16 = {read=FImageList16};
@@ -482,6 +482,7 @@ public:
 	__property Dragdrop::TOnMenuPopup OnDDMenuPopup = {read=FOnDDMenuPopup, write=FOnDDMenuPopup};
 	__property TDirViewExecFileEvent OnExecFile = {read=FOnExecFile, write=FOnExecFile};
 	__property TDirViewNotifyEvent OnHistoryChange = {read=FOnHistoryChange, write=FOnHistoryChange};
+	__property TDVHistoryGoEvent OnHistoryGo = {read=FOnHistoryGo, write=FOnHistoryGo};
 	__property TDirViewNotifyEvent OnPathChange = {read=FOnPathChange, write=FOnPathChange};
 	__property TMatchMaskEvent OnMatchMask = {read=FOnMatchMask, write=FOnMatchMask};
 	__property TDirViewGetOverlayEvent OnGetOverlay = {read=FOnGetOverlay, write=FOnGetOverlay};

+ 21 - 7
packages/filemng/CustomDirView.pas

@@ -107,10 +107,10 @@ type
     ModificationFrom: TDateTime;
     ModificationTo: TDateTime;
   end;
-  THistoryDirection = (hdBack, hdForward);
   TDirViewNotifyEvent = procedure(Sender: TCustomDirView) of object;
   TDVGetFilterEvent = procedure(Sender: TCustomDirView; Select: Boolean;
     var Filter: TFileFilter) of object;
+  TDVHistoryGoEvent = procedure(Sender: TCustomDirView; Index: Integer; var Cancel: Boolean) of object;
   TCompareCriteria = (ccTime, ccSize);
   TCompareCriterias = set of TCompareCriteria;
 
@@ -192,6 +192,7 @@ type
     FOnBeginRename: TRenameEvent;
     FOnEndRename: TRenameEvent;
     FOnHistoryChange: TDirViewNotifyEvent;
+    FOnHistoryGo: TDVHistoryGoEvent;
     FOnPathChange: TDirViewNotifyEvent;
     FShowHiddenFiles: Boolean;
     FSavedSelection: Boolean;
@@ -343,6 +344,7 @@ type
     procedure SetMask(Value: string); virtual;
     procedure ScrollOnDragOverBeforeUpdate(ObjectToValidate: TObject);
     procedure ScrollOnDragOverAfterUpdate;
+    procedure DoHistoryGo(Index: Integer);
     function HiddenCount: Integer; virtual; abstract;
     function FilteredCount: Integer; virtual; abstract;
     property ImageList16: TImageList read FImageList16;
@@ -492,6 +494,7 @@ type
     property OnExecFile: TDirViewExecFileEvent
       read FOnExecFile write FOnExecFile;
     property OnHistoryChange: TDirViewNotifyEvent read FOnHistoryChange write FOnHistoryChange;
+    property OnHistoryGo: TDVHistoryGoEvent read FOnHistoryGo write FOnHistoryGo;
     property OnPathChange: TDirViewNotifyEvent read FOnPathChange write FOnPathChange;
     property OnMatchMask: TMatchMaskEvent read FOnMatchMask write FOnMatchMask;
     property OnGetOverlay: TDirViewGetOverlayEvent read FOnGetOverlay write FOnGetOverlay;
@@ -1426,12 +1429,12 @@ begin
       else
     if (Key = VK_LEFT) and (ssAlt in Shift) then
     begin
-      if BackCount >= 1 then HistoryGo(-1);
+      if BackCount >= 1 then DoHistoryGo(-1);
     end
       else
     if (Key = VK_RIGHT) and (ssAlt in Shift) then
     begin
-      if ForwardCount >= 1 then HistoryGo(1);
+      if ForwardCount >= 1 then DoHistoryGo(1);
     end
       else
     begin
@@ -1629,13 +1632,13 @@ procedure TCustomDirView.WMXButtonUp(var Message: TWMXMouse);
 begin
   if Message.Button = _XBUTTON1 then
   begin
-    if BackCount >= 1 then HistoryGo(-1);
+    if BackCount >= 1 then DoHistoryGo(-1);
     Message.Result := 1;
   end
     else
   if Message.Button = _XBUTTON2 then
   begin
-    if ForwardCount >= 1 then HistoryGo(1);
+    if ForwardCount >= 1 then DoHistoryGo(1);
     Message.Result := 1;
   end;
 end;
@@ -2637,13 +2640,13 @@ begin
     if Command = _APPCOMMAND_BROWSER_BACKWARD then
     begin
       Message.Result := 1;
-      if BackCount >= 1 then HistoryGo(-1);
+      if BackCount >= 1 then DoHistoryGo(-1);
     end
       else
     if Command = _APPCOMMAND_BROWSER_FORWARD then
     begin
       Message.Result := 1;
-      if ForwardCount >= 1 then HistoryGo(1);
+      if ForwardCount >= 1 then DoHistoryGo(1);
     end
       else
     if Command = _APPCOMMAND_BROWSER_REFRESH then
@@ -2772,6 +2775,17 @@ begin
     OnHistoryChange(Self);
 end; { DoHistoryChange }
 
+procedure TCustomDirView.DoHistoryGo(Index: Integer);
+var
+  Cancel: Boolean;
+begin
+  Cancel := False;
+  if Assigned(OnHistoryGo) then
+    OnHistoryGo(Self, Index, Cancel);
+
+  if not Cancel then HistoryGo(Index);
+end;
+
 procedure TCustomDirView.HistoryGo(Index: Integer);
 var
   PrevPath: string;

+ 1 - 0
packages/filemng/DirView.hpp

@@ -535,6 +535,7 @@ __published:
 	__property OnBeginRename ;
 	__property OnEndRename ;
 	__property OnHistoryChange ;
+	__property OnHistoryGo ;
 	__property OnPathChange ;
 	__property ColumnClick  = {default=1};
 	__property MultiSelect  = {default=1};

+ 8 - 4
packages/filemng/DirView.pas

@@ -527,6 +527,7 @@ type
     property OnBeginRename;
     property OnEndRename;
     property OnHistoryChange;
+    property OnHistoryGo;
     property OnPathChange;
 
     property ColumnClick;
@@ -553,7 +554,7 @@ uses
   ShellAPI, ComObj,
   ActiveX, ImgList,
   ShellDialogs, IEDriveInfo,
-  FileChanges, Math;
+  FileChanges, Math, PasTools;
 
 var
   DaylightHack: Boolean;
@@ -4367,10 +4368,13 @@ end;
 
 {=================================================================}
 
+var
+  IsWin7: Boolean;
 initialization
   LastClipBoardOperation := cboNone;
   LastIOResult := 0;
-  DaylightHack := not
-    ((Win32MajorVersion > 6) or
-     ((Win32MajorVersion = 6) and (Win32MinorVersion >= 1)));
+  IsWin7 :=
+    (Win32MajorVersion > 6) or
+    ((Win32MajorVersion = 6) and (Win32MinorVersion >= 1));
+  DaylightHack := (not IsWin7) or IsExactly2008R2;
 end.

+ 2 - 1
packages/my/NortonLikeListView.hpp

@@ -58,7 +58,7 @@ private:
 	bool FManageSelection;
 	int FFirstSelected;
 	int FLastSelected;
-	System::TDateTime FNotFocusedWhenClicked;
+	System::TDateTime FFocused;
 	HIDESBASE MESSAGE void __fastcall WMLButtonDown(Messages::TWMMouse &Message);
 	HIDESBASE MESSAGE void __fastcall WMRButtonDown(Messages::TWMMouse &Message);
 	HIDESBASE MESSAGE void __fastcall WMKeyDown(Messages::TWMKey &Message);
@@ -66,6 +66,7 @@ private:
 	HIDESBASE MESSAGE void __fastcall WMNotify(Messages::TWMNotify &Message);
 	HIDESBASE MESSAGE void __fastcall CNNotify(Messages::TWMNotify &Message);
 	MESSAGE void __fastcall LVMEditLabel(Messages::TMessage &Message);
+	HIDESBASE MESSAGE void __fastcall WMSetFocus(Messages::TWMSetFocus &Message);
 	int __fastcall GetMarkedCount(void);
 	Comctrls::TListItem* __fastcall GetMarkedFile(void);
 	void __fastcall ItemSelected(Comctrls::TListItem* Item, int Index);

+ 14 - 9
packages/my/NortonLikeListView.pas

@@ -26,7 +26,7 @@ type
     FManageSelection: Boolean;
     FFirstSelected: Integer;
     FLastSelected: Integer;
-    FNotFocusedWhenClicked: TDateTime;
+    FFocused: TDateTime;
     procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
     procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
     procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
@@ -34,6 +34,7 @@ type
     procedure WMNotify(var Message: TWMNotify); message WM_NOTIFY;
     procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
     procedure LVMEditLabel(var Message: TMessage); message LVM_EDITLABEL;
+    procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
     function GetMarkedCount: Integer;
     function GetMarkedFile: TListItem;
     procedure ItemSelected(Item: TListItem; Index: Integer);
@@ -199,7 +200,7 @@ begin
   // cannot use Win32MajorVersion as it is affected by compatibility mode and
   // the bug is present even in compatibility mode
   FManageSelection := IsVista;
-  FNotFocusedWhenClicked := 0;
+  FFocused := 0;
 end;
 
 destructor TCustomNortonLikeListView.Destroy;
@@ -620,8 +621,6 @@ var
   PDontSelectItem: Boolean;
   Shift: TShiftState;
 begin
-  if not Focused then FNotFocusedWhenClicked := Now
-    else FNotFocusedWhenClicked := 0;
   Shift := KeysToShiftState(Message.Keys);
   PDontSelectItem := FDontSelectItem;
   PDontUnSelectItem := FDontUnSelectItem;
@@ -812,8 +811,8 @@ end;
 procedure TCustomNortonLikeListView.LVMEditLabel(var Message: TMessage);
 begin
   // explicitly requesting editing (e.g. F2),
-  // so we do not care anymore what state the view was in when last clicked
-  FNotFocusedWhenClicked := 0;
+  // so we do not care anymore when the view was focused
+  FFocused := 0;
   inherited;
 end;
 
@@ -824,13 +823,19 @@ var
 begin
   N := Now;
   Result := inherited CanEdit(Item);
-  if Result and (FNotFocusedWhenClicked > 0) then
+  if Result and (FFocused > 0) then
   begin
-    Delta := N - FNotFocusedWhenClicked;
+    Delta := N - FFocused;
     // it takes little more than 500ms to trigger editing after click
     Result := Delta > (750.0/(24*60*60*1000));
   end;
-  FNotFocusedWhenClicked := 0;
+  FFocused := 0;
+end;
+
+procedure TCustomNortonLikeListView.WMSetFocus(var Message: TWMSetFocus);
+begin
+  FFocused := Now;
+  inherited;
 end;
 
 end.

+ 1 - 0
packages/my/PasTools.hpp

@@ -118,6 +118,7 @@ public:
 //-- var, const, procedure ---------------------------------------------------
 extern PACKAGE Classes::TComponent* __fastcall Construct(TMetaClass* ComponentClass, Classes::TComponent* Owner);
 extern PACKAGE bool __fastcall IsVista(void);
+extern PACKAGE bool __fastcall IsExactly2008R2(void);
 
 }	/* namespace Pastools */
 using namespace Pastools;

+ 54 - 0
packages/my/PasTools.pas

@@ -9,6 +9,8 @@ function Construct(ComponentClass: TComponentClass; Owner: TComponent): TCompone
 
 function IsVista: Boolean;
 
+function IsExactly2008R2: Boolean;
+
 type
   TControlScrollBeforeUpdate = procedure(ObjectToValidate: TObject) of object;
   TControlScrollAfterUpdate = procedure of object;
@@ -81,6 +83,58 @@ begin
   Result := (GetProcAddress(GetModuleHandle(Kernel32), 'GetLocaleInfoEx') <> nil);
 end;
 
+function IsExactly2008R2: Boolean;
+var
+  GetProductInfo: function(dwOSMajorVersion, dwOSMinorVersion, dwSpMajorVersion, dwSpMinorVersion: DWORD; var dwReturnedProductType: DWORD): BOOL stdcall;
+  Kernel: THandle;
+  ProductType: DWORD;
+begin
+  Result := (Win32MajorVersion = 6) and (Win32MinorVersion = 1);
+  if Result then
+  begin
+    Kernel := GetModuleHandle(Windows.Kernel32);
+    @GetProductInfo := GetProcAddress(Kernel, 'GetProductInfo');
+    if not Assigned(GetProductInfo) then Result := False
+      else
+    begin
+      GetProductInfo(Win32MajorVersion, Win32MinorVersion, 0, 0, ProductType);
+      case ProductType of
+        $0008 {PRODUCT_DATACENTER_SERVER},
+        $000C {PRODUCT_DATACENTER_SERVER_CORE},
+        $0027 {PRODUCT_DATACENTER_SERVER_CORE_V},
+        $0025 {PRODUCT_DATACENTER_SERVER_V},
+        $000A {PRODUCT_ENTERPRISE_SERVER},
+        $000E {PRODUCT_ENTERPRISE_SERVER_CORE},
+        $0029 {PRODUCT_ENTERPRISE_SERVER_CORE_V},
+        $000F {PRODUCT_ENTERPRISE_SERVER_IA64},
+        $0026 {PRODUCT_ENTERPRISE_SERVER_V},
+        $002A {PRODUCT_HYPERV},
+        $001E {PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT},
+        $0020 {PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING},
+        $001F {PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY},
+        $0018 {PRODUCT_SERVER_FOR_SMALLBUSINESS},
+        $0023 {PRODUCT_SERVER_FOR_SMALLBUSINESS_V},
+        $0021 {PRODUCT_SERVER_FOUNDATION},
+        $0009 {PRODUCT_SMALLBUSINESS_SERVER},
+        $0038 {PRODUCT_SOLUTION_EMBEDDEDSERVER},
+        $0007 {PRODUCT_STANDARD_SERVER},
+        $000D {PRODUCT_STANDARD_SERVER_CORE},
+        $0028 {PRODUCT_STANDARD_SERVER_CORE_V},
+        $0024 {PRODUCT_STANDARD_SERVER_V},
+        $0017 {PRODUCT_STORAGE_ENTERPRISE_SERVER},
+        $0014 {PRODUCT_STORAGE_EXPRESS_SERVER},
+        $0015 {PRODUCT_STORAGE_STANDARD_SERVER},
+        $0016 {PRODUCT_STORAGE_WORKGROUP_SERVER},
+        $0011 {PRODUCT_WEB_SERVER},
+        $001D {PRODUCT_WEB_SERVER_CORE}:
+          Result := True;
+        else
+          Result := False;
+      end;
+    end;
+  end;
+end;
+
   { TCustomControlScrollOnDragOver }
 
 constructor TCustomControlScrollOnDragOver.Create(Control: TControl;

+ 100 - 25
putty/SSH.C

@@ -544,7 +544,7 @@ static int ssh_comp_none_disable(void *handle)
     return 0;
 }
 const static struct ssh_compress ssh_comp_none = {
-    "none",
+    "none", NULL,
     ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,
     ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,
     ssh_comp_none_disable, NULL
@@ -5431,6 +5431,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
 	int n_preferred_ciphers;
 	const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX];
 	const struct ssh_compress *preferred_comp;
+	int userauth_succeeded;	    /* for delayed compression */
+	int pending_compression;
 	int got_session_id, activated_authconn;
 	struct Packet *pktout;
         int dlgret;
@@ -5446,6 +5448,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
     s->cscomp_tobe = s->sccomp_tobe = NULL;
 
     s->got_session_id = s->activated_authconn = FALSE;
+    s->userauth_succeeded = FALSE;
+    s->pending_compression = FALSE;
 
     /*
      * Be prepared to work around the buggy MAC problem.
@@ -5610,26 +5614,32 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
 	    if (i < s->nmacs - 1)
 		ssh2_pkt_addstring_str(s->pktout, ",");
 	}
-	/* List client->server compression algorithms. */
-	ssh2_pkt_addstring_start(s->pktout);
-	assert(lenof(compressions) > 1);
-	ssh2_pkt_addstring_str(s->pktout, s->preferred_comp->name);
-	for (i = 0; i < lenof(compressions); i++) {
-	    const struct ssh_compress *c = compressions[i];
-	    if (c != s->preferred_comp) {
+	/* List client->server compression algorithms,
+	 * then server->client compression algorithms. (We use the
+	 * same set twice.) */
+	for (j = 0; j < 2; j++) {
+	    ssh2_pkt_addstring_start(s->pktout);
+	    assert(lenof(compressions) > 1);
+	    /* Prefer non-delayed versions */
+	    ssh2_pkt_addstring_str(s->pktout, s->preferred_comp->name);
+	    /* We don't even list delayed versions of algorithms until
+	     * they're allowed to be used, to avoid a race. See the end of
+	     * this function. */
+	    if (s->userauth_succeeded && s->preferred_comp->delayed_name) {
 		ssh2_pkt_addstring_str(s->pktout, ",");
-		ssh2_pkt_addstring_str(s->pktout, c->name);
+		ssh2_pkt_addstring_str(s->pktout,
+				       s->preferred_comp->delayed_name);
 	    }
-	}
-	/* List server->client compression algorithms. */
-	ssh2_pkt_addstring_start(s->pktout);
-	assert(lenof(compressions) > 1);
-	ssh2_pkt_addstring_str(s->pktout, s->preferred_comp->name);
-	for (i = 0; i < lenof(compressions); i++) {
-	    const struct ssh_compress *c = compressions[i];
-	    if (c != s->preferred_comp) {
-		ssh2_pkt_addstring_str(s->pktout, ",");
-		ssh2_pkt_addstring_str(s->pktout, c->name);
+	    for (i = 0; i < lenof(compressions); i++) {
+		const struct ssh_compress *c = compressions[i];
+		if (c != s->preferred_comp) {
+		    ssh2_pkt_addstring_str(s->pktout, ",");
+		    ssh2_pkt_addstring_str(s->pktout, c->name);
+		    if (s->userauth_succeeded && c->delayed_name) {
+			ssh2_pkt_addstring_str(s->pktout, ",");
+			ssh2_pkt_addstring_str(s->pktout, c->delayed_name);
+		    }
+		}
 	    }
 	}
 	/* List client->server languages. Empty list. */
@@ -5778,6 +5788,13 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
 	    if (in_commasep_string(c->name, str, len)) {
 		s->cscomp_tobe = c;
 		break;
+	    } else if (in_commasep_string(c->delayed_name, str, len)) {
+		if (s->userauth_succeeded) {
+		    s->cscomp_tobe = c;
+		    break;
+		} else {
+		    s->pending_compression = TRUE;  /* try this later */
+		}
 	    }
 	}
 	ssh_pkt_getstring(pktin, &str, &len);  /* server->client compression */
@@ -5787,8 +5804,19 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
 	    if (in_commasep_string(c->name, str, len)) {
 		s->sccomp_tobe = c;
 		break;
+	    } else if (in_commasep_string(c->delayed_name, str, len)) {
+		if (s->userauth_succeeded) {
+		    s->sccomp_tobe = c;
+		    break;
+		} else {
+		    s->pending_compression = TRUE;  /* try this later */
+		}
 	    }
 	}
+	if (s->pending_compression) {
+	    logevent("Server supports delayed compression; "
+		     "will try this later");
+	}
 	ssh_pkt_getstring(pktin, &str, &len);  /* client->server language */
 	ssh_pkt_getstring(pktin, &str, &len);  /* server->client language */
 	s->ignorepkt = ssh2_pkt_getbool(pktin) && !s->guessok;
@@ -6324,19 +6352,52 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
      * start.
      * 
      * We _also_ go back to the start if we see pktin==NULL and
-     * inlen==-1, because this is a special signal meaning
+     * inlen negative, because this is a special signal meaning
      * `initiate client-driven rekey', and `in' contains a message
      * giving the reason for the rekey.
+     *
+     * inlen==-1 means always initiate a rekey;
+     * inlen==-2 means that userauth has completed successfully and
+     *   we should consider rekeying (for delayed compression).
      */
     while (!((pktin && pktin->type == SSH2_MSG_KEXINIT) ||
-	     (!pktin && inlen == -1))) {
+	     (!pktin && inlen < 0))) {
         wait_for_rekey:
 	crReturn(1);
     }
     if (pktin) {
 	logevent("Server initiated key re-exchange");
     } else {
+	if (inlen == -2) {
+	    /* 
+	     * authconn has seen a USERAUTH_SUCCEEDED. Time to enable
+	     * delayed compression, if it's available.
+	     *
+	     * draft-miller-secsh-compression-delayed-00 says that you
+	     * negotiate delayed compression in the first key exchange, and
+	     * both sides start compressing when the server has sent
+	     * USERAUTH_SUCCESS. This has a race condition -- the server
+	     * can't know when the client has seen it, and thus which incoming
+	     * packets it should treat as compressed.
+	     *
+	     * Instead, we do the initial key exchange without offering the
+	     * delayed methods, but note if the server offers them; when we
+	     * get here, if a delayed method was available that was higher
+	     * on our list than what we got, we initiate a rekey in which we
+	     * _do_ list the delayed methods (and hopefully get it as a
+	     * result). Subsequent rekeys will do the same.
+	     */
+	    assert(!s->userauth_succeeded); /* should only happen once */
+	    s->userauth_succeeded = TRUE;
+	    if (!s->pending_compression)
+		/* Can't see any point rekeying. */
+		goto wait_for_rekey;       /* this is utterly horrid */
+	    /* else fall through to rekey... */
+	    s->pending_compression = FALSE;
+	}
         /*
+	 * Now we've decided to rekey.
+	 *
          * Special case: if the server bug is set that doesn't
          * allow rekeying, we give a different log message and
          * continue waiting. (If such a server _initiates_ a rekey,
@@ -6354,7 +6415,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
                     schedule_timer(ssh->cfg.ssh_rekey_time*60*TICKSPERSEC,
                                    ssh2_timer, ssh);
             }
-            goto wait_for_rekey;       /* this is utterly horrid */
+            goto wait_for_rekey;       /* this is still utterly horrid */
         } else {
             logeventf(ssh, "Initiating key re-exchange (%s)", (char *)in);
         }
@@ -7265,7 +7326,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
 	int tried_gssapi;
 #endif
 	int kbd_inter_refused;
-	int we_are_in;
+	int we_are_in, userauth_success;
 	prompts_t *cur_prompt;
 	int num_prompts;
 	char username[100];
@@ -7301,7 +7362,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
     crBegin(ssh->do_ssh2_authconn_crstate);
 
     s->done_service_req = FALSE;
-    s->we_are_in = FALSE;
+    s->we_are_in = s->userauth_success = FALSE;
 #ifndef NO_GSSAPI
     s->tried_gssapi = FALSE;
 #endif
@@ -7594,7 +7655,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
 	    }
 	    if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {
 		logevent("Access granted");
-		s->we_are_in = TRUE;
+		s->we_are_in = s->userauth_success = TRUE;
 		break;
 	    }
 
@@ -8602,6 +8663,20 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
     if (s->agent_response)
 	sfree(s->agent_response);
 
+    if (s->userauth_success) {
+	/*
+	 * We've just received USERAUTH_SUCCESS, and we haven't sent any
+	 * packets since. Signal the transport layer to consider enacting
+	 * delayed compression.
+	 *
+	 * (Relying on we_are_in is not sufficient, as
+	 * draft-miller-secsh-compression-delayed is quite clear that it
+	 * triggers on USERAUTH_SUCCESS specifically, and we_are_in can
+	 * become set for other reasons.)
+	 */
+	do_ssh2_transport(ssh, "enabling delayed compression", -2, NULL);
+    }
+
     /*
      * Now the connection protocol has started, one way or another.
      */

+ 3 - 0
putty/SSH.H

@@ -261,6 +261,9 @@ struct ssh_signkey {
 
 struct ssh_compress {
     char *name;
+    /* For [email protected]: if non-NULL, this name will be considered once
+     * userauth has completed successfully. */
+    char *delayed_name;
     void *(*compress_init) (void);
     void (*compress_cleanup) (void *);
     int (*compress) (void *, unsigned char *block, int len,

+ 123 - 98
putty/SSHBN.C

@@ -213,15 +213,28 @@ static void internal_sub(const BignumInt *a, const BignumInt *b,
  * Compute c = a * b.
  * Input is in the first len words of a and b.
  * Result is returned in the first 2*len words of c.
+ *
+ * 'scratch' must point to an array of BignumInt of size at least
+ * mul_compute_scratch(len). (This covers the needs of internal_mul
+ * and all its recursive calls to itself.)
  */
 #define KARATSUBA_THRESHOLD 50
+static int mul_compute_scratch(int len)
+{
+    int ret = 0;
+    while (len > KARATSUBA_THRESHOLD) {
+        int toplen = len/2, botlen = len - toplen; /* botlen is the bigger */
+        int midlen = botlen + 1;
+        ret += 4*midlen;
+        len = midlen;
+    }
+    return ret;
+}
 static void internal_mul(const BignumInt *a, const BignumInt *b,
-			 BignumInt *c, int len)
+			 BignumInt *c, int len, BignumInt *scratch)
 {
-    int i, j;
-    BignumDblInt t;
-
     if (len > KARATSUBA_THRESHOLD) {
+        int i;
 
         /*
          * Karatsuba divide-and-conquer algorithm. Cut each input in
@@ -257,7 +270,6 @@ static void internal_mul(const BignumInt *a, const BignumInt *b,
 
         int toplen = len/2, botlen = len - toplen; /* botlen is the bigger */
         int midlen = botlen + 1;
-        BignumInt *scratch;
         BignumDblInt carry;
 #ifdef KARA_DEBUG
         int i;
@@ -285,7 +297,7 @@ static void internal_mul(const BignumInt *a, const BignumInt *b,
 #endif
 
         /* a_1 b_1 */
-        internal_mul(a, b, c, toplen);
+        internal_mul(a, b, c, toplen, scratch);
 #ifdef KARA_DEBUG
         printf("a1b1 = 0x");
         for (i = 0; i < 2*toplen; i++) {
@@ -295,7 +307,7 @@ static void internal_mul(const BignumInt *a, const BignumInt *b,
 #endif
 
         /* a_0 b_0 */
-        internal_mul(a + toplen, b + toplen, c + 2*toplen, botlen);
+        internal_mul(a + toplen, b + toplen, c + 2*toplen, botlen, scratch);
 #ifdef KARA_DEBUG
         printf("a0b0 = 0x");
         for (i = 0; i < 2*botlen; i++) {
@@ -304,23 +316,14 @@ static void internal_mul(const BignumInt *a, const BignumInt *b,
         printf("\n");
 #endif
 
-        /*
-         * We must allocate scratch space for the central coefficient,
-         * and also for the two input values that we multiply when
-         * computing it. Since either or both may carry into the
-         * (botlen+1)th word, we must use a slightly longer length
-         * 'midlen'.
-         */
-        scratch = snewn(4 * midlen, BignumInt);
-
         /* Zero padding. midlen exceeds toplen by at most 2, so just
          * zero the first two words of each input and the rest will be
          * copied over. */
         scratch[0] = scratch[1] = scratch[midlen] = scratch[midlen+1] = 0;
 
-        for (j = 0; j < toplen; j++) {
-            scratch[midlen - toplen + j] = a[j]; /* a_1 */
-            scratch[2*midlen - toplen + j] = b[j]; /* b_1 */
+        for (i = 0; i < toplen; i++) {
+            scratch[midlen - toplen + i] = a[i]; /* a_1 */
+            scratch[2*midlen - toplen + i] = b[i]; /* b_1 */
         }
 
         /* compute a_1 + a_0 */
@@ -346,7 +349,8 @@ static void internal_mul(const BignumInt *a, const BignumInt *b,
         /*
          * Now we can do the third multiplication.
          */
-        internal_mul(scratch, scratch + midlen, scratch + 2*midlen, midlen);
+        internal_mul(scratch, scratch + midlen, scratch + 2*midlen, midlen,
+                     scratch + 4*midlen);
 #ifdef KARA_DEBUG
         printf("a1plusa0timesb1plusb0 = 0x");
         for (i = 0; i < 2*midlen; i++) {
@@ -361,8 +365,8 @@ static void internal_mul(const BignumInt *a, const BignumInt *b,
          * product to obtain the middle one.
          */
         scratch[0] = scratch[1] = scratch[2] = scratch[3] = 0;
-        for (j = 0; j < 2*toplen; j++)
-            scratch[2*midlen - 2*toplen + j] = c[j];
+        for (i = 0; i < 2*toplen; i++)
+            scratch[2*midlen - 2*toplen + i] = c[i];
         scratch[1] = internal_add(scratch+2, c + 2*toplen,
                                   scratch+2, 2*botlen);
 #ifdef KARA_DEBUG
@@ -392,13 +396,13 @@ static void internal_mul(const BignumInt *a, const BignumInt *b,
         carry = internal_add(c + 2*len - botlen - 2*midlen,
                              scratch + 2*midlen,
                              c + 2*len - botlen - 2*midlen, 2*midlen);
-        j = 2*len - botlen - 2*midlen - 1;
+        i = 2*len - botlen - 2*midlen - 1;
         while (carry) {
-            assert(j >= 0);
-            carry += c[j];
-            c[j] = (BignumInt)carry;
+            assert(i >= 0);
+            carry += c[i];
+            c[i] = (BignumInt)carry;
             carry >>= BIGNUM_INT_BITS;
-            j--;
+            i--;
         }
 #ifdef KARA_DEBUG
         printf("ab = 0x");
@@ -408,29 +412,28 @@ static void internal_mul(const BignumInt *a, const BignumInt *b,
         printf("\n");
 #endif
 
-        /* Free scratch. */
-        for (j = 0; j < 4 * midlen; j++)
-            scratch[j] = 0;
-        sfree(scratch);
-
     } else {
+        int i;
+        BignumInt carry;
+        BignumDblInt t;
+        const BignumInt *ap, *bp;
+        BignumInt *cp, *cps;
 
         /*
          * Multiply in the ordinary O(N^2) way.
          */
 
-        for (j = 0; j < 2 * len; j++)
-            c[j] = 0;
+        for (i = 0; i < 2 * len; i++)
+            c[i] = 0;
 
-        for (i = len - 1; i >= 0; i--) {
-            t = 0;
-            for (j = len - 1; j >= 0; j--) {
-                t += MUL_WORD(a[i], (BignumDblInt) b[j]);
-                t += (BignumDblInt) c[i + j + 1];
-                c[i + j + 1] = (BignumInt) t;
-                t = t >> BIGNUM_INT_BITS;
+        for (cps = c + 2*len, ap = a + len; ap-- > a; cps--) {
+            carry = 0;
+            for (cp = cps, bp = b + len; cp--, bp-- > b ;) {
+                t = (MUL_WORD(*ap, *bp) + carry) + *cp;
+                *cp = (BignumInt) t;
+                carry = t >> BIGNUM_INT_BITS;
             }
-            c[i] = (BignumInt) t;
+            *cp = carry;
         }
     }
 }
@@ -441,12 +444,10 @@ static void internal_mul(const BignumInt *a, const BignumInt *b,
  * (everything above that is thrown away).
  */
 static void internal_mul_low(const BignumInt *a, const BignumInt *b,
-                             BignumInt *c, int len)
+                             BignumInt *c, int len, BignumInt *scratch)
 {
-    int i, j;
-    BignumDblInt t;
-
     if (len > KARATSUBA_THRESHOLD) {
+        int i;
 
         /*
          * Karatsuba-aware version of internal_mul_low. As before, we
@@ -481,29 +482,30 @@ static void internal_mul_low(const BignumInt *a, const BignumInt *b,
          */
 
         int toplen = len/2, botlen = len - toplen; /* botlen is the bigger */
-        BignumInt *scratch;
 
         /*
-         * Allocate scratch space for the various bits and pieces
-         * we're going to be adding together. We need botlen*2 words
-         * for a_0 b_0 (though we may end up throwing away its topmost
-         * word), and toplen words for each of a_1 b_0 and a_0 b_1.
-         * That adds up to exactly 2*len.
+         * Scratch space for the various bits and pieces we're going
+         * to be adding together: we need botlen*2 words for a_0 b_0
+         * (though we may end up throwing away its topmost word), and
+         * toplen words for each of a_1 b_0 and a_0 b_1. That adds up
+         * to exactly 2*len.
          */
-        scratch = snewn(len*2, BignumInt);
 
         /* a_0 b_0 */
-        internal_mul(a + toplen, b + toplen, scratch + 2*toplen, botlen);
+        internal_mul(a + toplen, b + toplen, scratch + 2*toplen, botlen,
+                     scratch + 2*len);
 
         /* a_1 b_0 */
-        internal_mul_low(a, b + len - toplen, scratch + toplen, toplen);
+        internal_mul_low(a, b + len - toplen, scratch + toplen, toplen,
+                         scratch + 2*len);
 
         /* a_0 b_1 */
-        internal_mul_low(a + len - toplen, b, scratch, toplen);
+        internal_mul_low(a + len - toplen, b, scratch, toplen,
+                         scratch + 2*len);
 
         /* Copy the bottom half of the big coefficient into place */
-        for (j = 0; j < botlen; j++)
-            c[toplen + j] = scratch[2*toplen + botlen + j];
+        for (i = 0; i < botlen; i++)
+            c[toplen + i] = scratch[2*toplen + botlen + i];
 
         /* Add the two small coefficients, throwing away the returned carry */
         internal_add(scratch, scratch + toplen, scratch, toplen);
@@ -512,26 +514,28 @@ static void internal_mul_low(const BignumInt *a, const BignumInt *b,
         internal_add(scratch, scratch + 2*toplen + botlen - toplen,
                      c, toplen);
 
-        /* Free scratch. */
-        for (j = 0; j < len*2; j++)
-            scratch[j] = 0;
-        sfree(scratch);
-
     } else {
+        int i;
+        BignumInt carry;
+        BignumDblInt t;
+        const BignumInt *ap, *bp;
+        BignumInt *cp, *cps;
 
-        for (j = 0; j < len; j++)
-            c[j] = 0;
+        /*
+         * Multiply in the ordinary O(N^2) way.
+         */
 
-        for (i = len - 1; i >= 0; i--) {
-            t = 0;
-            for (j = len - 1; j >= len - i - 1; j--) {
-                t += MUL_WORD(a[i], (BignumDblInt) b[j]);
-                t += (BignumDblInt) c[i + j + 1 - len];
-                c[i + j + 1 - len] = (BignumInt) t;
-                t = t >> BIGNUM_INT_BITS;
+        for (i = 0; i < len; i++)
+            c[i] = 0;
+
+        for (cps = c + len, ap = a + len; ap-- > a; cps--) {
+            carry = 0;
+            for (cp = cps, bp = b + len; bp--, cp-- > c ;) {
+                t = (MUL_WORD(*ap, *bp) + carry) + *cp;
+                *cp = (BignumInt) t;
+                carry = t >> BIGNUM_INT_BITS;
             }
         }
-
     }
 }
 
@@ -546,8 +550,8 @@ static void internal_mul_low(const BignumInt *a, const BignumInt *b,
  * each, containing respectively n and the multiplicative inverse of
  * -n mod r.
  *
- * 'tmp' is an array of at least '3*len' BignumInts used as scratch
- * space.
+ * 'tmp' is an array of BignumInt used as scratch space, of length at
+ * least 3*len + mul_compute_scratch(len).
  */
 static void monty_reduce(BignumInt *x, const BignumInt *n,
                          const BignumInt *mninv, BignumInt *tmp, int len)
@@ -560,7 +564,7 @@ static void monty_reduce(BignumInt *x, const BignumInt *n,
      * that mn is congruent to -x mod r. Hence, mn+x is an exact
      * multiple of r, and is also (obviously) congruent to x mod n.
      */
-    internal_mul_low(x + len, mninv, tmp, len);
+    internal_mul_low(x + len, mninv, tmp, len, tmp + 3*len);
 
     /*
      * Compute t = (mn+x)/r in ordinary, non-modular, integer
@@ -571,7 +575,7 @@ static void monty_reduce(BignumInt *x, const BignumInt *n,
      * significant half of the 'x' array, so then we must shift it
      * down.
      */
-    internal_mul(tmp, n, tmp+len, len);
+    internal_mul(tmp, n, tmp+len, len, tmp + 3*len);
     carry = internal_add(x, tmp+len, x, 2*len);
     for (i = 0; i < len; i++)
         x[len + i] = x[i], x[i] = 0;
@@ -721,9 +725,9 @@ static void internal_mod(BignumInt *a, int alen,
  */
 Bignum modpow_simple(Bignum base_in, Bignum exp, Bignum mod)
 {
-    BignumInt *a, *b, *n, *m;
+    BignumInt *a, *b, *n, *m, *scratch;
     int mshift;
-    int mlen, i, j;
+    int mlen, scratchlen, i, j;
     Bignum base, result;
 
     /*
@@ -770,6 +774,10 @@ Bignum modpow_simple(Bignum base_in, Bignum exp, Bignum mod)
 	a[i] = 0;
     a[2 * mlen - 1] = 1;
 
+    /* Scratch space for multiplies */
+    scratchlen = mul_compute_scratch(mlen);
+    scratch = snewn(scratchlen, BignumInt);
+
     /* Skip leading zero bits of exp. */
     i = 0;
     j = BIGNUM_INT_BITS-1;
@@ -784,10 +792,10 @@ Bignum modpow_simple(Bignum base_in, Bignum exp, Bignum mod)
     /* Main computation */
     while (i < (int)exp[0]) {
 	while (j >= 0) {
-	    internal_mul(a + mlen, a + mlen, b, mlen);
+	    internal_mul(a + mlen, a + mlen, b, mlen, scratch);
 	    internal_mod(b, mlen * 2, m, mlen, NULL, 0);
 	    if ((exp[exp[0] - i] & (1 << j)) != 0) {
-		internal_mul(b + mlen, n, a, mlen);
+		internal_mul(b + mlen, n, a, mlen, scratch);
 		internal_mod(a, mlen * 2, m, mlen, NULL, 0);
 	    } else {
 		BignumInt *t;
@@ -822,6 +830,9 @@ Bignum modpow_simple(Bignum base_in, Bignum exp, Bignum mod)
     for (i = 0; i < 2 * mlen; i++)
 	a[i] = 0;
     sfree(a);
+    for (i = 0; i < scratchlen; i++)
+	scratch[i] = 0;
+    sfree(scratch);
     for (i = 0; i < 2 * mlen; i++)
 	b[i] = 0;
     sfree(b);
@@ -843,8 +854,8 @@ Bignum modpow_simple(Bignum base_in, Bignum exp, Bignum mod)
  */
 Bignum modpow(Bignum base_in, Bignum exp, Bignum mod)
 {
-    BignumInt *a, *b, *x, *n, *mninv, *tmp;
-    int len, i, j;
+    BignumInt *a, *b, *x, *n, *mninv, *scratch;
+    int len, scratchlen, i, j;
     Bignum base, base2, r, rn, inv, result;
 
     /*
@@ -917,7 +928,9 @@ Bignum modpow(Bignum base_in, Bignum exp, Bignum mod)
 	a[2*len - 1 - j] = (j < rn[0] ? rn[j + 1] : 0);
     freebn(rn);
 
-    tmp = snewn(3*len, BignumInt);
+    /* Scratch space for multiplies */
+    scratchlen = 3*len + mul_compute_scratch(len);
+    scratch = snewn(scratchlen, BignumInt);
 
     /* Skip leading zero bits of exp. */
     i = 0;
@@ -933,11 +946,11 @@ Bignum modpow(Bignum base_in, Bignum exp, Bignum mod)
     /* Main computation */
     while (i < (int)exp[0]) {
 	while (j >= 0) {
-	    internal_mul(a + len, a + len, b, len);
-            monty_reduce(b, n, mninv, tmp, len);
+	    internal_mul(a + len, a + len, b, len, scratch);
+            monty_reduce(b, n, mninv, scratch, len);
 	    if ((exp[exp[0] - i] & (1 << j)) != 0) {
-                internal_mul(b + len, x, a, len);
-                monty_reduce(a, n, mninv, tmp, len);
+                internal_mul(b + len, x, a, len,  scratch);
+                monty_reduce(a, n, mninv, scratch, len);
 	    } else {
 		BignumInt *t;
 		t = a;
@@ -954,7 +967,7 @@ Bignum modpow(Bignum base_in, Bignum exp, Bignum mod)
      * Final monty_reduce to get back from the adjusted Montgomery
      * representation.
      */
-    monty_reduce(a, n, mninv, tmp, len);
+    monty_reduce(a, n, mninv, scratch, len);
 
     /* Copy result to buffer */
     result = newbn(mod[0]);
@@ -964,9 +977,9 @@ Bignum modpow(Bignum base_in, Bignum exp, Bignum mod)
 	result[0]--;
 
     /* Free temporary arrays */
-    for (i = 0; i < 3 * len; i++)
-	tmp[i] = 0;
-    sfree(tmp);
+    for (i = 0; i < scratchlen; i++)
+	scratch[i] = 0;
+    sfree(scratch);
     for (i = 0; i < 2 * len; i++)
 	a[i] = 0;
     sfree(a);
@@ -993,8 +1006,8 @@ Bignum modpow(Bignum base_in, Bignum exp, Bignum mod)
  */
 Bignum modmul(Bignum p, Bignum q, Bignum mod)
 {
-    BignumInt *a, *n, *m, *o;
-    int mshift;
+    BignumInt *a, *n, *m, *o, *scratch;
+    int mshift, scratchlen;
     int pqlen, mlen, rlen, i, j;
     Bignum result;
 
@@ -1036,8 +1049,12 @@ Bignum modmul(Bignum p, Bignum q, Bignum mod)
     /* Allocate a of size 2*pqlen for result */
     a = snewn(2 * pqlen, BignumInt);
 
+    /* Scratch space for multiplies */
+    scratchlen = mul_compute_scratch(pqlen);
+    scratch = snewn(scratchlen, BignumInt);
+
     /* Main computation */
-    internal_mul(n, o, a, pqlen);
+    internal_mul(n, o, a, pqlen, scratch);
     internal_mod(a, pqlen * 2, m, mlen, NULL, 0);
 
     /* Fixup result in case the modulus was shifted */
@@ -1059,6 +1076,9 @@ Bignum modmul(Bignum p, Bignum q, Bignum mod)
 	result[0]--;
 
     /* Free temporary arrays */
+    for (i = 0; i < scratchlen; i++)
+	scratch[i] = 0;
+    sfree(scratch);
     for (i = 0; i < 2 * pqlen; i++)
 	a[i] = 0;
     sfree(a);
@@ -1347,18 +1367,21 @@ Bignum bigmuladd(Bignum a, Bignum b, Bignum addend)
     int alen = a[0], blen = b[0];
     int mlen = (alen > blen ? alen : blen);
     int rlen, i, maxspot;
+    int wslen;
     BignumInt *workspace;
     Bignum ret;
 
-    /* mlen space for a, mlen space for b, 2*mlen for result */
-    workspace = snewn(mlen * 4, BignumInt);
+    /* mlen space for a, mlen space for b, 2*mlen for result,
+     * plus scratch space for multiplication */
+    wslen = mlen * 4 + mul_compute_scratch(mlen);
+    workspace = snewn(wslen, BignumInt);
     for (i = 0; i < mlen; i++) {
 	workspace[0 * mlen + i] = (mlen - i <= (int)a[0] ? a[mlen - i] : 0);
 	workspace[1 * mlen + i] = (mlen - i <= (int)b[0] ? b[mlen - i] : 0);
     }
 
     internal_mul(workspace + 0 * mlen, workspace + 1 * mlen,
-		 workspace + 2 * mlen, mlen);
+		 workspace + 2 * mlen, mlen, workspace + 4 * mlen);
 
     /* now just copy the result back */
     rlen = alen + blen + 1;
@@ -1387,6 +1410,8 @@ Bignum bigmuladd(Bignum a, Bignum b, Bignum addend)
     }
     ret[0] = maxspot;
 
+    for (i = 0; i < wslen; i++)
+        workspace[i] = 0;
     sfree(workspace);
     return ret;
 }

+ 3 - 0
putty/SSHZLIB.C

@@ -1259,6 +1259,8 @@ int zlib_decompress_block(void *handle, unsigned char *block, int len,
 		goto finished;
 	    nlen = dctx->bits & 0xFFFF;
 	    EATBITS(16);
+	    if (dctx->uncomplen != (nlen ^ 0xFFFF))
+		goto decode_error;
 	    if (dctx->uncomplen == 0)
 		dctx->state = OUTSIDEBLK;	/* block is empty */
 	    else
@@ -1369,6 +1371,7 @@ int main(int argc, char **argv)
 
 const struct ssh_compress ssh_zlib = {
     "zlib",
+    "[email protected]", /* delayed version */
     zlib_compress_init,
     zlib_compress_cleanup,
     zlib_compress_block,

+ 9 - 1
putty/windows/WINNET.C

@@ -236,7 +236,9 @@ void sk_init(void)
 	winsock_module = load_system32_dll("wsock32.dll");
     }
     if (!winsock_module)
+    {
 	fatalbox("Unable to load any WinSock library");
+    }
 
 #ifndef NO_IPV6
     /* Check if we have getaddrinfo in Winsock */
@@ -453,7 +455,9 @@ SockAddr sk_namelookup(const char *host, char **canonicalname,
 	    hints.ai_family = hint_family;
 	    hints.ai_flags = AI_CANONNAME;
 	    if ((err = p_getaddrinfo(host, NULL, &hints, &ret->ais)) == 0)
+	    {
 		ret->resolved = TRUE;
+	    }
 	} else
 #endif
 	{
@@ -487,9 +491,11 @@ SockAddr sk_namelookup(const char *host, char **canonicalname,
 		/* Are we in IPv4 fallback mode? */
 		/* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */
 		if (ret->ais->ai_family == AF_INET)
+		{
 		    memcpy(&a,
 			   (char *) &((SOCKADDR_IN *) ret->ais->
 				      ai_addr)->sin_addr, sizeof(a));
+		}
 
 		if (ret->ais->ai_canonname)
 		    strncpy(realhost, ret->ais->ai_canonname, lenof(realhost));
@@ -882,7 +888,7 @@ static DWORD try_connect(Actual_Socket sock)
 	p_setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b));
     }
 
-#ifdef MPEXT
+#ifdef MPEXT2
     {
 	int bufsize = 262144;
 	p_setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *) &bufsize, sizeof(bufsize));
@@ -1032,7 +1038,9 @@ static DWORD try_connect(Actual_Socket sock)
     add234(sktree, sock);
 
     if (err)
+	{
 	plug_log(sock->plug, 1, sock->addr, sock->port, sock->error, err);
+	}
     return err;
 }
 

+ 4 - 0
putty/windows/WINPGNTC.C

@@ -119,6 +119,10 @@ int agent_query(void *in, int inlen, void **out, int *outlen,
 	return 1;		       /* *out == NULL, so failure */
     mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId());
 
+#ifdef MPEXT
+    psa = NULL;
+#endif
+
 #ifndef NO_SECURITY
     if (advapi_initialised || init_advapi()) {
         /*

+ 14 - 15
release/winscpsetup.iss

@@ -7,14 +7,14 @@
 #define WebForum WebRoot+"forum/"
 #define WebDocumentation WebRoot+"eng/docs/"
 #define WebPuTTY "http://www.chiark.greenend.org.uk/~sgtatham/putty/"
-#define Year 2010
+#define Year 2011
 #define EnglishLang "English"
 #define SetupTypeData "SetupType"
 #define InnoSetupReg "Software\Microsoft\Windows\CurrentVersion\Uninstall\" + AppId + "_is1"
 #define InnoSetupAppPathReg "Inno Setup: App Path"
 
 #ifexist "interm\winscpsetup.inc.iss"
-  #include "interm\winscpsetup.inc.iss"
+  #include "..\interm\winscpsetup.inc.iss"
 #else
   #define Status "unofficial"
   #define SourceDir ".."
@@ -38,7 +38,7 @@
 #define Version Str(Major)+"."+Str(Minor)+(Rev > 0 ? "."+Str(Rev) : "")+(Status != "" ? " "+Status : "")
 
 #ifdef OpenCandy
-#include "opencandy\OCSetupHlp.iss"
+#include "..\opencandy\OCSetupHlp.iss"
 #endif
 
 [Setup]
@@ -63,10 +63,11 @@ OutputDir={#OutputDir}
 DisableStartupPrompt=yes
 AppVersion={#Version}
 AppVerName=WinSCP {#Version}
-OutputBaseFilename=winscp{#Major}{#Minor}{#Rev}setup
+OutputBaseFilename=winscp{#Major}{#Minor}{#Rev}setup{#OutputSuffix}
 SolidCompression=yes
 ShowTasksTreeLines=yes
 PrivilegesRequired=none
+UsePreviousLanguage=yes
 
 ; Some features of ISCC requires path relative to script,
 ; some path relative to CWD
@@ -246,11 +247,11 @@ Source: "licence"; DestDir: "{app}"; \
   Components: main; Flags: ignoreversion
 Source: "{#ShellExtFileSource}"; DestDir: "{app}"; \
   Components: shellext; \
-  Flags: ignoreversion regserver restartreplace uninsrestartdelete; \
+  Flags: regserver restartreplace uninsrestartdelete; \
   Check: not IsWin64
 Source: "{#ShellExt64FileSource}"; DestDir: "{app}"; \
   Components: shellext; \
-  Flags: ignoreversion regserver restartreplace uninsrestartdelete; \
+  Flags: regserver restartreplace uninsrestartdelete; \
   Check: IsWin64
 Source: "{#PuttySourceDir}\LICENCE"; DestDir: "{app}\PuTTY"; \
   Components: pageant puttygen; Flags: ignoreversion
@@ -261,11 +262,8 @@ Source: "{#PuttySourceDir}\pageant.exe"; DestDir: "{app}\PuTTY"; \
 Source: "{#PuttySourceDir}\puttygen.exe"; DestDir: "{app}\PuTTY"; \
   Components: puttygen; Flags: ignoreversion
 #ifdef OpenCandy
-Source: "..\opencandy\{#OCREADME}"; DestDir: {app}\OpenCandy; \
-  Flags: overwritereadonly ignoreversion; Check: OpenCandyCheckInstallReadme
-Source: "..\opencandy\{#OCDLL}"; DestDir: {app}\OpenCandy; \
-  Flags: overwritereadonly ignoreversion; \
-  Check: OpenCandyCheckInstallDLL; AfterInstall: OpenCandyProcessEmbedded
+Source: "{#OC_OCSETUPHLP_FILE_PATH}"; \
+  Flags: dontcopy ignoreversion
 #endif
 
 [Registry]
@@ -729,9 +727,8 @@ begin
   AdvancedTabsCheckbox.Parent := InterfacePage.Surface;
 
 #ifdef OpenCandy
-  OpenCandyInitRemnant2('WinSCP', '{#OpenCandyKey}', '3d0f240d63cf2239f9e45c3562d8bdbc',
-    ExpandConstant('{cm:LanguageISOCode}'), '{#ParentRegistryKey}\OpenCandy',
-    WizardSilent(), False);
+  OpenCandyAsyncInit('{#OC_STR_MY_PRODUCT_NAME}', '{#OC_STR_KEY}', '{#OC_STR_SECRET}',
+    ExpandConstant('{cm:LanguageISOCode}'), {#OC_INIT_MODE_NORMAL});
 #endif
 end;
 
@@ -761,7 +758,9 @@ end;
 #ifdef OpenCandy
 function BackButtonClick(CurPageID: Integer): Boolean;
 begin
-  Result := OpenCandyBackButtonClick(CurPageID);
+  Result := True;
+
+  OpenCandyBackButtonClick(CurPageID);
 end;
 
 function NextButtonClick(CurPageID: Integer): Boolean;

+ 1 - 1
resource/TextsCore1.rc

@@ -342,7 +342,7 @@ BEGIN
   FILEZILLA_BASED_ON, "FTP code based on FileZilla %s"
   FILEZILLA_VERSION, "2.2.32"
   FILEZILLA_COPYRIGHT, "Copyright © 2001-2007 Tim Kosse"
-  FILEZILLA_URL, "http://filezilla.sourceforge.net/"
+  FILEZILLA_URL, "http://filezilla-project.org/"
   OPENSSL_BASED_ON, "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s."
   OPENSSL_COPYRIGHT, "Copyright © 1998-2011 The OpenSSL Project"
   OPENSSL_VERSION, "1.0.0d"

+ 0 - 1
resource/TextsWin.h

@@ -388,7 +388,6 @@
 #define WINSCP_COPYRIGHT        1901
 #define HOMEPAGE_URL            1902
 #define HISTORY_URL             1903
-#define REQUIREMENTS_URL        1904
 #define FORUM_URL               1905
 #define UPDATES_URL             1906
 #define DOWNLOAD_URL            1907

+ 0 - 1
resource/TextsWin1.rc

@@ -390,7 +390,6 @@ BEGIN
         WINSCP_COPYRIGHT, "Copyright © 2000-2011 Martin Prikryl"
         HOMEPAGE_URL, "http://winscp.net/"
         HISTORY_URL, "http://winscp.net/eng/docs/history"
-        REQUIREMENTS_URL, "http://winscp.net/eng/docs/requirements"
         FORUM_URL, "http://winscp.net/forum/"
         UPDATES_URL, "http://winscp.net/updates.php"
         DOWNLOAD_URL, "http://winscp.net/eng/download.php"

+ 17 - 0
windows/Setup.cpp

@@ -603,6 +603,23 @@ AnsiString __fastcall VersionStrFromCompoundVersion(int Version)
   return Result;
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall CampaignUrl(AnsiString URL)
+{
+  if (URL.Pos("?") == 0)
+  {
+    URL += "?";
+  }
+  else
+  {
+    URL += "&";
+  }
+
+  int CurrentCompoundVer = Configuration->CompoundVersion;
+  AnsiString Version = VersionStrFromCompoundVersion(CurrentCompoundVer);
+  URL += FORMAT("utm_source=winscp&utm_medium=app&utm_campaign=%s", (Version));
+  return URL;
+}
+//---------------------------------------------------------------------------
 void __fastcall QueryUpdates()
 {
   bool Complete = false;

+ 3 - 0
windows/Setup.h

@@ -2,6 +2,8 @@
 #ifndef SetupH
 #define SetupH
 //---------------------------------------------------------------------------
+#include <Interface.h>
+//---------------------------------------------------------------------------
 void __fastcall AddSearchPath(const AnsiString Path);
 void __fastcall RemoveSearchPath(const AnsiString Path);
 void __fastcall GetUpdatesMessage(AnsiString & Message, bool & New, TQueryType & Type, bool Force);
@@ -10,5 +12,6 @@ void __fastcall RegisterAsUrlHandler();
 void __fastcall TemporaryDirectoryCleanup();
 void __fastcall StartUpdateThread(TThreadMethod OnUpdatesChecked);
 void __fastcall StopUpdateThread();
+AnsiString __fastcall CampaignUrl(AnsiString URL);
 //---------------------------------------------------------------------------
 #endif

+ 80 - 2
windows/TerminalManager.cpp

@@ -1,4 +1,5 @@
 //---------------------------------------------------------------------------
+#define NO_WIN32_LEAN_AND_MEAN
 #include <vcl.h>
 #pragma hdrstop
 
@@ -8,6 +9,7 @@
 #include "LogMemo.h"
 #include "NonVisual.h"
 #include "WinConfiguration.h"
+#include "Tools.h"
 #include <Log.h>
 #include <Common.h>
 #include <CoreMain.h>
@@ -17,6 +19,7 @@
 #include <Progress.h>
 #include <Exceptions.h>
 #include <VCLCommon.h>
+#include <WinApi.h>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
@@ -67,6 +70,7 @@ __fastcall TTerminalManager::TTerminalManager() :
   FDirectoryReadingStart = 0;
   FAuthenticateForm = NULL;
   FQueueWithEvent = NULL;
+  FTaskbarList = NULL;
 
   assert(Application && !Application->OnException);
   Application->OnException = ApplicationException;
@@ -74,9 +78,13 @@ __fastcall TTerminalManager::TTerminalManager() :
   Application->OnShowHint = ApplicationShowHint;
   assert(Application->OnActivate == NULL);
   Application->OnActivate = ApplicationActivate;
+  assert(Application->OnMessage == NULL);
+  Application->OnMessage = ApplicationMessage;
   assert(WinConfiguration->OnMasterPasswordPrompt == NULL);
   WinConfiguration->OnMasterPasswordPrompt = MasterPasswordPrompt;
 
+  InitTaskbarButtonCreatedMessage();
+
   assert(Configuration && !Configuration->OnChange);
   Configuration->OnChange = ConfigurationChange;
   FOnLastTerminalClosed = NULL;
@@ -102,6 +110,8 @@ __fastcall TTerminalManager::~TTerminalManager()
   Application->OnShowHint = ApplicationShowHint;
   assert(Application->OnActivate == ApplicationActivate);
   Application->OnActivate = NULL;
+  assert(Application->OnMessage == ApplicationMessage);
+  Application->OnMessage = NULL;
   assert(WinConfiguration->OnMasterPasswordPrompt == MasterPasswordPrompt);
   WinConfiguration->OnMasterPasswordPrompt = NULL;
 
@@ -110,6 +120,7 @@ __fastcall TTerminalManager::~TTerminalManager()
   delete FTerminalList;
   delete FAuthenticateForm;
   delete FQueueSection;
+  ReleaseTaskbarList();
 }
 //---------------------------------------------------------------------------
 TTerminalQueue * __fastcall TTerminalManager::NewQueue(TTerminal * Terminal)
@@ -449,6 +460,7 @@ void __fastcall TTerminalManager::SetScpExplorer(TCustomScpExplorerForm * value)
       FScpExplorer->Queue = ActiveQueue;
       FOnLastTerminalClosed = FScpExplorer->LastTerminalClosed;
       FOnTerminalListChanged = FScpExplorer->TerminalListChanged;
+      UpdateTaskbarList();
     }
     else
     {
@@ -668,6 +680,59 @@ void __fastcall TTerminalManager::ApplicationActivate(TObject * /*Sender*/)
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TTerminalManager::ApplicationMessage(TMsg & Msg, bool & /*Handled*/)
+{
+  if (Msg.message == FTaskbarButtonCreatedMessage)
+  {
+    CreateTaskbarList();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminalManager::InitTaskbarButtonCreatedMessage()
+{
+
+  FTaskbarButtonCreatedMessage = RegisterWindowMessage("TaskbarButtonCreated");
+
+  HANDLE User32Library = LoadLibrary("user32.dll");
+  ChangeWindowMessageFilterExProc ChangeWindowMessageFilterEx =
+    (ChangeWindowMessageFilterExProc)GetProcAddress(User32Library, "ChangeWindowMessageFilterEx");
+
+  if (ChangeWindowMessageFilterEx != NULL)
+  {
+    // without this we won't get TaskbarButtonCreated, when app is running elevated
+    ChangeWindowMessageFilterEx(
+      Application->Handle, FTaskbarButtonCreatedMessage, MSGFLT_ALLOW, NULL);
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminalManager::CreateTaskbarList()
+{
+
+  ReleaseTaskbarList();
+
+  if(SUCCEEDED(CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL,
+        IID_ITaskbarList3, (void **) &FTaskbarList)))
+  {
+    if (ScpExplorer != NULL)
+    {
+      UpdateTaskbarList();
+    }
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminalManager::ReleaseTaskbarList()
+{
+  if (FTaskbarList != NULL)
+  {
+    FTaskbarList->Release();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminalManager::UpdateTaskbarList()
+{
+  ScpExplorer->UpdateTaskbarList(FTaskbarList);
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminalManager::DeleteLocalFile(const AnsiString FileName, bool Alternative)
 {
   if (!RecursiveDeleteFile(FileName, (WinConfiguration->DeleteToRecycleBin != Alternative)))
@@ -719,18 +784,31 @@ TAuthenticateForm * __fastcall TTerminalManager::MakeAuthenticateForm(
   return Dialog;
 }
 //---------------------------------------------------------------------------
+void __fastcall TTerminalManager::FileNameInputDialogInitializeRenameBaseName(
+  TObject * /*Sender*/, TInputDialogData * Data)
+{
+  EditSelectBaseName(Data->Edit->Handle);
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminalManager::TerminalPromptUser(
   TTerminal * Terminal, TPromptKind Kind, AnsiString Name, AnsiString Instructions,
   TStrings * Prompts, TStrings * Results, bool & Result, void * /*Arg*/)
 {
-  if ((Kind == pkPrompt) && (FAuthenticateForm == NULL) &&
+  if (((Kind == pkPrompt) || (Kind == pkFileName)) && (FAuthenticateForm == NULL) &&
       (Terminal->Status != ssOpening))
   {
     assert(Instructions.IsEmpty());
     assert(Prompts->Count == 1);
     assert(bool(Prompts->Objects[0]));
     AnsiString AResult = Results->Strings[0];
-    Result = InputDialog(Name, Prompts->Strings[0], AResult);
+
+    TInputDialogInitialize InputDialogInitialize = NULL;
+    if ((Kind == pkFileName) && !WinConfiguration->RenameWholeName)
+    {
+      InputDialogInitialize = FileNameInputDialogInitializeRenameBaseName;
+    }
+
+    Result = InputDialog(Name, Prompts->Strings[0], AResult, "", NULL, false, InputDialogInitialize);
     if (Result)
     {
       Results->Strings[0] = AResult;

+ 11 - 0
windows/TerminalManager.h

@@ -5,11 +5,13 @@
 #include <Terminal.h>
 #include <Queue.h>
 #include <FileOperationProgress.h>
+#include <WinInterface.h>
 //---------------------------------------------------------------------------
 class TCustomScpExplorerForm;
 class TLogMemo;
 class TTerminalQueue;
 class TAuthenticateForm;
+class ITaskbarList3;
 //---------------------------------------------------------------------------
 enum TTerminalPendingAction { tpNull, tpNone, tpReconnect, tpFree };
 //---------------------------------------------------------------------------
@@ -83,6 +85,8 @@ private:
   TCriticalSection * FQueueSection;
   TTerminalQueue * FQueueWithEvent;
   TQueueEvent FQueueEvent;
+  unsigned int FTaskbarButtonCreatedMessage;
+  ITaskbarList3 * FTaskbarList;
 
   bool __fastcall ConnectActiveTerminalImpl(bool Reopen);
   TTerminalQueue * __fastcall NewQueue(TTerminal * Terminal);
@@ -96,6 +100,7 @@ private:
   void __fastcall ApplicationShowHint(AnsiString & HintStr, bool & CanShow,
     THintInfo & HintInfo);
   void __fastcall ApplicationActivate(TObject * Sender);
+  void __fastcall ApplicationMessage(TMsg & Msg, bool & Handled);
   void __fastcall ConfigurationChange(TObject * Sender);
   void __fastcall TerminalUpdateStatus(TTerminal * Terminal, bool Active);
   void __fastcall TerminalQueryUser(TObject * Sender,
@@ -130,6 +135,12 @@ private:
   void __fastcall QueueEvent(TTerminalQueue * Queue, TQueueEvent Event);
   TAuthenticateForm * __fastcall MakeAuthenticateForm(TSessionData * Data);
   void __fastcall MasterPasswordPrompt();
+  void __fastcall FileNameInputDialogInitializeRenameBaseName(
+    TObject * Sender, TInputDialogData * Data);
+  void __fastcall InitTaskbarButtonCreatedMessage();
+  void __fastcall ReleaseTaskbarList();
+  void __fastcall CreateTaskbarList();
+  void __fastcall UpdateTaskbarList();
 };
 //---------------------------------------------------------------------------
 #endif

+ 21 - 0
windows/Tools.cpp

@@ -13,6 +13,7 @@
 
 #include "GUITools.h"
 #include "VCLCommon.h"
+#include "Setup.h"
 #include "Tools.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
@@ -335,6 +336,11 @@ void __fastcall ExitActiveControl(TForm * Form)
 //---------------------------------------------------------------------------
 void __fastcall OpenBrowser(AnsiString URL)
 {
+  AnsiString HomePageUrl = LoadStr(HOMEPAGE_URL);
+  if (AnsiSameText(URL.SubString(1, HomePageUrl.Length()), HomePageUrl))
+  {
+    URL = CampaignUrl(URL);
+  }
   ShellExecute(Application->Handle, "open", URL.c_str(), NULL, NULL, SW_SHOWNORMAL);
 }
 //---------------------------------------------------------------------------
@@ -734,6 +740,21 @@ void __fastcall ShutDownWindows()
     SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED));
 }
 //---------------------------------------------------------------------------
+void __fastcall EditSelectBaseName(HWND Edit)
+{
+  AnsiString Text;
+  Text.SetLength(GetWindowTextLength(Edit) + 1);
+  GetWindowText(Edit, Text.c_str(), Text.Length());
+
+  int P = Text.LastDelimiter(".");
+  if (P > 0)
+  {
+    // SendMessage does not work, if edit control is not fully
+    // initialized yet
+    PostMessage(Edit, EM_SETSEL, 0, P - 1);
+  }
+}
+//---------------------------------------------------------------------------
 // Code from http://gentoo.osuosl.org/distfiles/cl331.zip/io/
 
 // The autoproxy functions were only documented in WinHTTP 5.1, so we have to

+ 1 - 0
windows/Tools.h

@@ -45,6 +45,7 @@ bool __fastcall IsWin64();
 void __fastcall CopyToClipboard(AnsiString Text);
 void __fastcall CopyToClipboard(TStrings * Strings);
 void __fastcall ShutDownWindows();
+void __fastcall EditSelectBaseName(HWND Edit);
 //---------------------------------------------------------------------------
 #define IUNKNOWN \
   virtual HRESULT __stdcall QueryInterface(const GUID& IID, void **Obj) \

+ 1 - 1
windows/VCLCommon.cpp

@@ -1328,7 +1328,7 @@ static void __fastcall LinkLabelClick(TStaticText * StaticText)
   else
   {
     AnsiString Url = StaticText->Caption;
-    if (!SameText(Url.SubString(1, 4), "http") && (Url.Pos("@") > 0))
+    if (!AnsiSameText(Url.SubString(1, 4), "http") && (Url.Pos("@") > 0))
     {
       Url = "mailto:" + Url;
     }

+ 96 - 0
windows/WinApi.h

@@ -0,0 +1,96 @@
+//---------------------------------------------------------------------------
+#ifndef WinApiH
+#define WinApiH
+//---------------------------------------------------------------------------
+#include <shlobj.h>
+//---------------------------------------------------------------------------
+EXTERN_C const GUID DECLSPEC_SELECTANY IID_ITaskbarList3
+        = { 0xEA1AFB91, 0x9E28, 0x4B86, { 0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF } };
+//---------------------------------------------------------------------------
+typedef /* [v1_enum] */
+enum TBPFLAG
+{
+  TBPF_NOPROGRESS = 0,
+  TBPF_INDETERMINATE = 0x1,
+  TBPF_NORMAL = 0x2,
+  TBPF_ERROR = 0x4,
+  TBPF_PAUSED = 0x8
+} TBPFLAG;
+//---------------------------------------------------------------------------
+// Do not need this ATM
+typedef void * LPTHUMBBUTTON;
+//---------------------------------------------------------------------------
+MIDL_INTERFACE("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")
+ITaskbarList3 : public ITaskbarList2
+{
+public:
+    virtual HRESULT STDMETHODCALLTYPE SetProgressValue(
+        /* [in] */ HWND hwnd,
+        /* [in] */ ULONGLONG ullCompleted,
+        /* [in] */ ULONGLONG ullTotal) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetProgressState(
+        /* [in] */ HWND hwnd,
+        /* [in] */ TBPFLAG tbpFlags) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE RegisterTab(
+        /* [in] */ HWND hwndTab,
+        /* [in] */ HWND hwndMDI) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE UnregisterTab(
+        /* [in] */ HWND hwndTab) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetTabOrder(
+        /* [in] */ HWND hwndTab,
+        /* [in] */ HWND hwndInsertBefore) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetTabActive(
+        /* [in] */ HWND hwndTab,
+        /* [in] */ HWND hwndMDI,
+        /* [in] */ DWORD dwReserved) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE ThumbBarAddButtons(
+        /* [in] */ HWND hwnd,
+        /* [in] */ UINT cButtons,
+        /* [size_is][in] */ LPTHUMBBUTTON pButton) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE ThumbBarUpdateButtons(
+        /* [in] */ HWND hwnd,
+        /* [in] */ UINT cButtons,
+        /* [size_is][in] */ LPTHUMBBUTTON pButton) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE ThumbBarSetImageList(
+        /* [in] */ HWND hwnd,
+        /* [in] */ ::HIMAGELIST himl) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetOverlayIcon(
+        /* [in] */ HWND hwnd,
+        /* [in] */ HICON hIcon,
+        /* [string][unique][in] */ LPCWSTR pszDescription) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetThumbnailTooltip(
+        /* [in] */ HWND hwnd,
+        /* [string][unique][in] */ LPCWSTR pszTip) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SetThumbnailClip(
+        /* [in] */ HWND hwnd,
+        /* [in] */ RECT *prcClip) = 0;
+
+};
+//---------------------------------------------------------------------------
+typedef struct tagCHANGEFILTERSTRUCT {
+    DWORD cbSize;
+    DWORD ExtStatus;
+} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT;
+
+/*
+ * Message filter action values (action parameter to ChangeWindowMessageFilterEx)
+ */
+#define MSGFLT_RESET                            (0)
+#define MSGFLT_ALLOW                            (1)
+#define MSGFLT_DISALLOW                         (2)
+
+typedef BOOL WINAPI (* ChangeWindowMessageFilterExProc)(
+    HWND hwnd, UINT message, DWORD action, PCHANGEFILTERSTRUCT pChangeFilterStruct);
+//---------------------------------------------------------------------------
+#endif  // WinApiH