Martin Prikryl 18 years ago
parent
commit
9aac4dd857

+ 5 - 5
Console.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 2,0,0,80
-PRODUCTVERSION 2,0,0,80
+FILEVERSION 2,0,0,81
+PRODUCTVERSION 2,0,0,81
 FILEOS 0x4
 FILETYPE 0x1
 {
@@ -10,13 +10,13 @@ FILETYPE 0x1
         {
             VALUE "CompanyName", "Martin Prikryl\0"
             VALUE "FileDescription", "Console interface for WinSCP\0"
-            VALUE "FileVersion", "2.0.0.80\0"
+            VALUE "FileVersion", "2.0.0.81\0"
             VALUE "InternalName", "console\0"
-            VALUE "LegalCopyright", "(c) 2000-2007 Martin Prikryl\0"
+            VALUE "LegalCopyright", "(c) 2000-2008 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "winscp.com\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.0.5.0\0"
+            VALUE "ProductVersion", "4.0.6.0\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
     }

+ 5 - 5
DragExt.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 1,1,6,78
-PRODUCTVERSION 1,1,6,78
+FILEVERSION 1,1,6,79
+PRODUCTVERSION 1,1,6,79
 FILEOS 0x4
 FILETYPE 0x2
 {
@@ -10,13 +10,13 @@ FILETYPE 0x2
         {
             VALUE "CompanyName", "Martin Prikryl\0"
             VALUE "FileDescription", "Drag&Drop shell extension for WinSCP\0"
-            VALUE "FileVersion", "1.1.6.78\0"
+            VALUE "FileVersion", "1.1.6.79\0"
             VALUE "InternalName", "dragext\0"
-            VALUE "LegalCopyright", "(c) 2000-2007 Martin Prikryl\0"
+            VALUE "LegalCopyright", "(c) 2000-2008 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext.dll\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.0.5.0\0"
+            VALUE "ProductVersion", "4.0.6.0\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
     }

+ 5 - 5
DragExt64.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 1,1,6,78
-PRODUCTVERSION 1,1,6,78
+FILEVERSION 1,1,6,79
+PRODUCTVERSION 1,1,6,79
 FILEOS 0x4
 FILETYPE 0x2
 {
@@ -10,13 +10,13 @@ FILETYPE 0x2
         {
             VALUE "CompanyName", "Martin Prikryl\0"
             VALUE "FileDescription", "Drag&Drop shell extension for WinSCP (64-bit)\0"
-            VALUE "FileVersion", "1.1.6.78\0"
+            VALUE "FileVersion", "1.1.6.79\0"
             VALUE "InternalName", "dragext64\0"
-            VALUE "LegalCopyright", "(c) 2000-2007 Martin Prikryl\0"
+            VALUE "LegalCopyright", "(c) 2000-2008 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext64.dll\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.0.5.0\0"
+            VALUE "ProductVersion", "4.0.6.0\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
     }

+ 6 - 6
WinSCP.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 4,0,5,354
-PRODUCTVERSION 4,0,5,354
+FILEVERSION 4,0,6,358
+PRODUCTVERSION 4,0,6,358
 FILEOS 0x4
 FILETYPE 0x1
 {
@@ -10,13 +10,13 @@ FILETYPE 0x1
         {
             VALUE "CompanyName", "Martin Prikryl\0"
             VALUE "FileDescription", "Windows SFTP, FTP and SCP client\0"
-            VALUE "FileVersion", "4.0.5.354\0"
+            VALUE "FileVersion", "4.0.6.358\0"
             VALUE "InternalName", "winscp\0"
-            VALUE "LegalCopyright", "(c) 2000-2007 Martin Prikryl\0"
+            VALUE "LegalCopyright", "(c) 2000-2008 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
-            VALUE "OriginalFilename", "winscp405.exe\0"
+            VALUE "OriginalFilename", "winscp406.exe\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.0.5.0\0"
+            VALUE "ProductVersion", "4.0.6.0\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
     }

+ 25 - 15
core/Configuration.cpp

@@ -38,6 +38,7 @@ void __fastcall TConfiguration::Default()
   TGuard Guard(FCriticalSection);
 
   RandomSeedFile = FDefaultRandomSeedFile;
+  PuttyRegistryStorageKey = "Software\\SimonTatham\\PuTTY";
   FConfirmOverwriting = true;
   FConfirmResume = true;
   FAutoReadDirectoryAfterOp = true;
@@ -89,6 +90,7 @@ THierarchicalStorage * TConfiguration::CreateScpStorage(bool /*SessionList*/)
 #define REGCONFIG(CANCREATE) \
   BLOCK("Interface", CANCREATE, \
     KEY(String,   RandomSeedFile); \
+    KEY(String,   PuttyRegistryStorageKey); \
     KEY(Bool,     ConfirmOverwriting); \
     KEY(Bool,     ConfirmResume); \
     KEY(Bool,     AutoReadDirectoryAfterOp); \
@@ -113,31 +115,36 @@ void __fastcall TConfiguration::SaveData(THierarchicalStorage * Storage, bool /*
   #undef KEYEX
 }
 //---------------------------------------------------------------------------
-void __fastcall TConfiguration::Save(bool All)
+void __fastcall TConfiguration::Save(bool All, bool Explicit)
 {
   if (FDontSave) return;
 
-  if (Storage == stRegistry) CleanupIniFile();
-
-  THierarchicalStorage * Storage = CreateScpStorage(false);
+  THierarchicalStorage * AStorage = CreateScpStorage(false);
   try
   {
-    Storage->AccessMode = smReadWrite;
-    if (Storage->OpenSubKey(ConfigurationSubKey, true))
+    AStorage->AccessMode = smReadWrite;
+    AStorage->Explicit = Explicit;
+    if (AStorage->OpenSubKey(ConfigurationSubKey, true))
     {
-      SaveData(Storage, All);
+      SaveData(AStorage, All);
     }
   }
   __finally
   {
-    delete Storage;
+    delete AStorage;
   }
 
   Saved();
 
   if (All)
   {
-    StoredSessions->Save(true);
+    StoredSessions->Save(true, Explicit);
+  }
+
+  // clean up as last, so that if it fails (read only INI), the saving can proceed
+  if (Storage == stRegistry)
+  {
+    CleanupIniFile();
   }
 }
 //---------------------------------------------------------------------------
@@ -149,6 +156,7 @@ void __fastcall TConfiguration::Export(const AnsiString FileName)
   {
     ExportStorage = new TIniFileStorage(FileName);
     ExportStorage->AccessMode = smReadWrite;
+    ExportStorage->Explicit = true;
 
     Storage = CreateScpStorage(false);
     Storage->AccessMode = smRead;
@@ -679,11 +687,6 @@ AnsiString __fastcall TConfiguration::GetIniFileStorageName()
   }
 }
 //---------------------------------------------------------------------------
-AnsiString __fastcall TConfiguration::GetPuttyRegistryStorageKey()
-{
-  return PUTTY_REG_POS;
-}
-//---------------------------------------------------------------------------
 AnsiString __fastcall TConfiguration::GetPuttySessionsKey()
 {
   return PuttyRegistryStorageKey + "\\Sessions";
@@ -730,6 +733,7 @@ void __fastcall TConfiguration::SetStorage(TStorage value)
 
       TargetStorage = CreateScpStorage(false);
       TargetStorage->AccessMode = smReadWrite;
+      TargetStorage->Explicit = true;
 
       // copy before save as it removes the ini file,
       // when switching from ini to registry
@@ -741,7 +745,8 @@ void __fastcall TConfiguration::SetStorage(TStorage value)
       delete TargetStorage;
     }
 
-    Save(true);
+    // save all and explicit
+    Save(true, true);
   }
 }
 //---------------------------------------------------------------------------
@@ -781,6 +786,11 @@ void __fastcall TConfiguration::SetRandomSeedFile(AnsiString value)
     strcpy(seedpath, StripPathQuotes(ExpandEnvironmentVariables(FRandomSeedFile)).c_str());
   }
 }
+//---------------------------------------------------------------------
+void __fastcall TConfiguration::SetPuttyRegistryStorageKey(AnsiString value)
+{
+  SET_CONFIG_PROPERTY(PuttyRegistryStorageKey);
+}
 //---------------------------------------------------------------------------
 TEOLType __fastcall TConfiguration::GetLocalEOLType()
 {

+ 4 - 3
core/Configuration.h

@@ -42,6 +42,7 @@ private:
   bool FShowFtpWelcomeMessage;
   AnsiString FDefaultRandomSeedFile;
   AnsiString FRandomSeedFile;
+  AnsiString FPuttyRegistryStorageKey;
 
   bool FDisablePasswordStoring;
   bool FForceBanners;
@@ -58,8 +59,8 @@ private:
   AnsiString __fastcall TrimVersion(AnsiString Version);
   AnsiString __fastcall GetStoredSessionsSubKey();
   AnsiString __fastcall GetPuttySessionsKey();
-  AnsiString __fastcall GetPuttyRegistryStorageKey();
   void __fastcall SetRandomSeedFile(AnsiString value);
+  void __fastcall SetPuttyRegistryStorageKey(AnsiString value);
   AnsiString __fastcall GetSshHostKeysSubKey();
   AnsiString __fastcall GetRootKeyStr();
   AnsiString __fastcall GetConfigurationSubKey();
@@ -130,7 +131,7 @@ public:
   void __fastcall Initialize();
   virtual void __fastcall Default();
   virtual void __fastcall Load();
-  virtual void __fastcall Save(bool All = false);
+  virtual void __fastcall Save(bool All, bool Explicit);
   void __fastcall Export(const AnsiString FileName);
   void __fastcall CleanupConfiguration();
   void __fastcall CleanupIniFile();
@@ -151,7 +152,7 @@ public:
   __property TVSFixedFileInfo *FixedApplicationInfo  = { read=GetFixedApplicationInfo };
   __property void * ApplicationInfo  = { read=GetApplicationInfo };
   __property AnsiString StoredSessionsSubKey = {read=GetStoredSessionsSubKey};
-  __property AnsiString PuttyRegistryStorageKey  = { read=GetPuttyRegistryStorageKey };
+  __property AnsiString PuttyRegistryStorageKey  = { read=FPuttyRegistryStorageKey, write=SetPuttyRegistryStorageKey };
   __property AnsiString PuttySessionsKey  = { read=GetPuttySessionsKey };
   __property AnsiString RandomSeedFile  = { read=FRandomSeedFile, write=SetRandomSeedFile };
   __property AnsiString SshHostKeysSubKey  = { read=GetSshHostKeysSubKey };

+ 2 - 1
core/CoreMain.cpp

@@ -71,7 +71,8 @@ void CoreFinalize()
 {
   try
   {
-    Configuration->Save();
+    // only modified, implicit
+    Configuration->Save(false, false);
   }
   catch(Exception & E)
   {

+ 19 - 3
core/FtpFileSystem.cpp

@@ -422,6 +422,13 @@ AnsiString __fastcall TFTPFileSystem::AbsolutePath(AnsiString Path)
   }
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall TFTPFileSystem::ActualCurrentDirectory()
+{
+  char CurrentPath[1024];
+  FFileZillaIntf->GetCurrentPath(CurrentPath, sizeof(CurrentPath));
+  return AnsiString(CurrentPath);
+}
+//---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::EnsureLocation()
 {
   // if we do not know what's the current directory, do nothing
@@ -433,9 +440,7 @@ void __fastcall TFTPFileSystem::EnsureLocation()
     // 1) We did cached directory change
     // 2) Listing was requested for non-current directory, which
     // makes FAPI change its current directory (and not restoring it back afterwards)
-    char CurrentPath[1024];
-    FFileZillaIntf->GetCurrentPath(CurrentPath, sizeof(CurrentPath));
-    if (!UnixComparePaths(CurrentPath, FCurrentDirectory))
+    if (!UnixComparePaths(ActualCurrentDirectory(), FCurrentDirectory))
     {
       FTerminal->LogEvent(FORMAT("Synchronizing current directory \"%s\".",
         (FCurrentDirectory)));
@@ -1319,6 +1324,17 @@ void __fastcall TFTPFileSystem::DeleteFile(const AnsiString AFileName,
   {
     if (Dir)
     {
+      // Is current remote directory is in the directory being removed,
+      // some servers may refuse to delete it
+      // This is common as ProcessDirectory above would CWD to
+      // the directory to LIST it.
+      // EnsureLocation should reset actual current directory to user's working directory.
+      // If user's working directory is still below deleted directory, it is
+      // perfectly correct to report an error.
+      if (UnixIsChildPath(ActualCurrentDirectory(), FileName))
+      {
+        EnsureLocation();
+      }
       FFileZillaIntf->RemoveDir(FileNameOnly.c_str(), FilePath.c_str());
     }
     else

+ 1 - 0
core/FtpFileSystem.h

@@ -120,6 +120,7 @@ protected:
   bool __fastcall HandleReply(int Command, unsigned int Reply);
   bool __fastcall CheckError(int ReturnCode, const char * Context);
   void __fastcall EnsureLocation();
+  AnsiString __fastcall ActualCurrentDirectory();
   void __fastcall Discard();
   void __fastcall DoChangeDirectory(const AnsiString & Directory);
 

+ 110 - 24
core/HierarchicalStorage.cpp

@@ -3,8 +3,10 @@
 #pragma hdrstop
 
 #include "Common.h"
+#include "Exceptions.h"
 #include "PuttyIntf.h"
 #include "HierarchicalStorage.h"
+#include <TextsCore.h>
 #include <vector>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
@@ -52,6 +54,7 @@ __fastcall THierarchicalStorage::THierarchicalStorage(const AnsiString AStorage)
   FStorage = AStorage;
   FKeyHistory = new TStringList();
   AccessMode = smRead;
+  Explicit = false;
 }
 //---------------------------------------------------------------------------
 __fastcall THierarchicalStorage::~THierarchicalStorage()
@@ -532,12 +535,69 @@ __fastcall TIniFileStorage::TIniFileStorage(const AnsiString AStorage):
   THierarchicalStorage(AStorage)
 {
   FIniFile = new TMemIniFile(Storage);
+  FOriginal = new TStringList();
+  FIniFile->GetStrings(FOriginal);
+  ApplyOverrides();
 }
 //---------------------------------------------------------------------------
 __fastcall TIniFileStorage::~TIniFileStorage()
 {
-  FIniFile->UpdateFile();
-  delete FIniFile;
+  TStrings * Strings = new TStringList;
+  try
+  {
+    FIniFile->GetStrings(Strings);
+    if (!Strings->Equals(FOriginal))
+    {
+      int Attr;
+      // preserve attributes (especially hidden)
+      if (FileExists(Storage))
+      {
+        Attr = GetFileAttributes(Storage.c_str());
+      }
+      else
+      {
+        Attr = FILE_ATTRIBUTE_NORMAL;
+      }
+
+      HANDLE Handle = CreateFile(Storage.c_str(), GENERIC_READ | GENERIC_WRITE,
+        0, NULL, CREATE_ALWAYS, Attr, 0);
+
+      if (Handle == INVALID_HANDLE_VALUE)
+      {
+        // "access denied" errors upon implicit saves are ignored
+        if (Explicit || (GetLastError() != ERROR_ACCESS_DENIED))
+        {
+          try
+          {
+            RaiseLastOSError();
+          }
+          catch(Exception & E)
+          {
+            throw ExtException(&E, FMTLOAD(CREATE_FILE_ERROR, (Storage)));
+          }
+        }
+      }
+      else
+      {
+        TStream * Stream = new THandleStream(int(Handle));
+        try
+        {
+          Strings->SaveToStream(Stream);
+        }
+        __finally
+        {
+          CloseHandle(Handle);
+          delete Stream;
+        }
+      }
+    }
+  }
+  __finally
+  {
+    delete FOriginal;
+    delete Strings;
+    delete FIniFile;
+  }
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TIniFileStorage::GetCurrentSection()
@@ -655,6 +715,52 @@ int __fastcall TIniFileStorage::BinaryDataSize(const AnsiString Name)
   return ReadStringRaw(Name, "").Length() / 2;
 }
 //---------------------------------------------------------------------------
+void __fastcall TIniFileStorage::ApplyOverrides()
+{
+  AnsiString OverridesKey = IncludeTrailingBackslash("Override");
+
+  TStrings * Sections = new TStringList();
+  try
+  {
+    Sections->Clear();
+    FIniFile->ReadSections(Sections);
+    for (int i = 0; i < Sections->Count; i++)
+    {
+      AnsiString Section = Sections->Strings[i];
+
+      if (AnsiSameText(OverridesKey,
+            Section.SubString(1, OverridesKey.Length())))
+      {
+        AnsiString SubKey = Section.SubString(OverridesKey.Length() + 1,
+          Section.Length() - OverridesKey.Length());
+
+        TStrings * Names = new TStringList;
+        try
+        {
+          FIniFile->ReadSection(Section, Names);
+
+          for (int ii = 0; ii < Names->Count; ii++)
+          {
+            AnsiString Name = Names->Strings[ii];
+            AnsiString Value = FIniFile->ReadString(Section, Name, "");
+            FIniFile->WriteString(SubKey, Name, Value);
+          }
+        }
+        __finally
+        {
+          delete Names;
+        }
+
+        FIniFile->EraseSection(Section);
+      }
+    }
+  }
+  __finally
+  {
+    delete Sections;
+  }
+}
+//---------------------------------------------------------------------------
 bool __fastcall TIniFileStorage::ReadBool(const AnsiString Name, bool Default)
 {
   return FIniFile->ReadBool(CurrentSection, Name, Default);
@@ -741,20 +847,7 @@ double __fastcall TIniFileStorage::ReadFloat(const AnsiString Name, double Defau
 //---------------------------------------------------------------------------
 AnsiString __fastcall TIniFileStorage::ReadStringRaw(const AnsiString Name, AnsiString Default)
 {
-  AnsiString Section = CurrentSection;
-  AnsiString Result;
-  Result = FIniFile->ReadString(Section, Name, Default);
-  // TIniFile::ReadString has limit of 2 kB.
-  // We could straithly use our routine, but call to legacy code is preserved
-  // until ours is proved to work and also to save memory overhead
-  if (Result.Length() == 2047)
-  {
-    char Buffer[10240];
-    GetPrivateProfileString(Section.c_str(), Name.c_str(), Default.c_str(),
-      Buffer, sizeof(Buffer), FIniFile->FileName.c_str());
-    Result = Buffer;
-  }
-  return Result;
+  return FIniFile->ReadString(CurrentSection, Name, Default);
 }
 //---------------------------------------------------------------------------
 int __fastcall TIniFileStorage::ReadBinaryData(const AnsiString Name,
@@ -798,14 +891,7 @@ void __fastcall TIniFileStorage::WriteFloat(const AnsiString Name, double Value)
 //---------------------------------------------------------------------------
 void __fastcall TIniFileStorage::WriteStringRaw(const AnsiString Name, const AnsiString Value)
 {
-  if ((Value.Length() >= 2) && (Value[1] == '"') && (Value[Value.Length()] == '"'))
-  {
-    FIniFile->WriteString(CurrentSection, Name, "\"" + Value + "\"");
-  }
-  else
-  {
-    FIniFile->WriteString(CurrentSection, Name, Value);
-  }
+  FIniFile->WriteString(CurrentSection, Name, Value);
 }
 //---------------------------------------------------------------------------
 void __fastcall TIniFileStorage::WriteBinaryData(const AnsiString Name,

+ 5 - 1
core/HierarchicalStorage.h

@@ -56,11 +56,13 @@ public:
   __property AnsiString Storage  = { read=FStorage };
   __property AnsiString CurrentSubKey  = { read=GetCurrentSubKey };
   __property TStorageAccessMode AccessMode  = { read=FAccessMode, write=SetAccessMode };
+  __property bool Explicit = { read = FExplicit, write = FExplicit };
 
 protected:
   AnsiString FStorage;
   TStrings * FKeyHistory;
   TStorageAccessMode FAccessMode;
+  bool FExplicit;
 
   AnsiString __fastcall GetCurrentSubKey();
   virtual void __fastcall SetAccessMode(TStorageAccessMode value);
@@ -153,8 +155,10 @@ public:
   virtual void __fastcall GetValueNames(Classes::TStrings* Strings);
 
 private:
-  TCustomIniFile * FIniFile;
+  TMemIniFile * FIniFile;
+  TStrings * FOriginal;
   AnsiString __fastcall GetCurrentSection();
+  void __fastcall ApplyOverrides();
 protected:
   __property AnsiString CurrentSection  = { read=GetCurrentSection };
 };

+ 11 - 3
core/RemoteFiles.cpp

@@ -39,6 +39,13 @@ Boolean __fastcall UnixComparePaths(const AnsiString Path1, const AnsiString Pat
   return (UnixIncludeTrailingBackslash(Path1) == UnixIncludeTrailingBackslash(Path2));
 }
 //---------------------------------------------------------------------------
+bool __fastcall UnixIsChildPath(AnsiString Parent, AnsiString Child)
+{
+  Parent = UnixIncludeTrailingBackslash(Parent);
+  Child = UnixIncludeTrailingBackslash(Child);
+  return (Child.SubString(1, Parent.Length()) == Parent);
+}
+//---------------------------------------------------------------------------
 AnsiString __fastcall UnixExtractFileDir(const AnsiString Path)
 {
   int Pos = Path.LastDelimiter('/');
@@ -696,13 +703,14 @@ void __fastcall TRemoteFile::SetListingStr(AnsiString value)
     // so we get only first 9 characters and trim all following spaces (if any)
     Rights->Text = Line.SubString(1, 9);
     Line.Delete(1, 9);
-    // Rights column maybe followed by '+' sign, we ignore it
+    // Rights column maybe followed by '+' or '@' signs, we ignore them
     // (On MacOS, there may be a space in between)
-    if (!Line.IsEmpty() && (Line[1] == '+'))
+    if (!Line.IsEmpty() && ((Line[1] == '+') || (Line[1] == '@')))
     {
       Line.Delete(1, 1);
     }
-    else if ((Line.Length() >= 2) && (Line[1] == ' ') && (Line[2] == '+'))
+    else if ((Line.Length() >= 2) && (Line[1] == ' ') &&
+             ((Line[2] == '+') || (Line[2] == '@')))
     {
       Line.Delete(1, 2);
     }

+ 1 - 0
core/RemoteFiles.h

@@ -366,6 +366,7 @@ AnsiString __fastcall UnixExtractFilePath(const AnsiString Path);
 AnsiString __fastcall UnixExtractFileName(const AnsiString Path);
 AnsiString __fastcall UnixExtractFileExt(const AnsiString Path);
 Boolean __fastcall UnixComparePaths(const AnsiString Path1, const AnsiString Path2);
+bool __fastcall UnixIsChildPath(AnsiString Parent, AnsiString Child);
 bool __fastcall ExtractCommonPath(TStrings * Files, AnsiString & Path);
 bool __fastcall UnixExtractCommonPath(TStrings * Files, AnsiString & Path);
 AnsiString __fastcall ExtractFileName(const AnsiString & Path, bool Unix);

+ 2 - 1
core/Script.cpp

@@ -1387,7 +1387,8 @@ void __fastcall TManagementScript::FreeTerminal(TTerminal * Terminal)
 
       if (Changed)
       {
-        StoredSessions->Save();
+        // only modified, implicit
+        StoredSessions->Save(false, false);
       }
     }
   }

+ 134 - 64
core/SecureShell.cpp

@@ -494,15 +494,8 @@ void __fastcall TSecureShell::GotHostKey()
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::CWrite(const char * Data, int Length, bool Untrusted)
+void __fastcall TSecureShell::DumpCWrite()
 {
-  // some messages to stderr may indicate that something has changed with the
-  // session, so reset the session info
-  ResetSessionInfo();
-
-  // We send only whole line at once, so we have to cache incoming data
-  FCWriteTemp += DeleteChar(AnsiString(Data, Length), '\r');
-
   AnsiString Line;
   // Do we have at least one complete line in std error cache?
   while (FCWriteTemp.Pos("\n") > 0)
@@ -514,7 +507,7 @@ void __fastcall TSecureShell::CWrite(const char * Data, int Length, bool Untrust
     if (FAuthenticating)
     {
       // No point trying to translate message coming from server
-      if (!Untrusted)
+      if (!FCWriteTempUntrusted)
       {
         TranslateAuthenticationMessage(Line);
       }
@@ -523,13 +516,34 @@ void __fastcall TSecureShell::CWrite(const char * Data, int Length, bool Untrust
 
     // Untrusted means generally that it comes from the server,
     // do not use such a output as "information" for end user
-    if (!Untrusted)
+    if (!FCWriteTempUntrusted)
     {
       FUI->Information(Line, false);
     }
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TSecureShell::CWrite(const char * Data, int Length, bool Untrusted)
+{
+  // some messages to stderr may indicate that something has changed with the
+  // session, so reset the session info
+  ResetSessionInfo();
+
+  // if data coming from server were not ended with new line,
+  // dump rest of the line, once trusted output arrive
+  if (!FCWriteTemp.IsEmpty() &&
+      (FCWriteTempUntrusted != Untrusted))
+  {
+    FCWriteTemp += '\n';
+    DumpCWrite();
+  }
+
+  // We send only whole line at once, so we have to cache incoming data
+  FCWriteTemp += DeleteChar(AnsiString(Data, Length), '\r');
+  FCWriteTempUntrusted = Untrusted;
+  DumpCWrite();
+}
+//---------------------------------------------------------------------------
 void __fastcall TSecureShell::RegisterReceiveHandler(TNotifyEvent Handler)
 {
   assert(FOnReceive == NULL);
@@ -755,7 +769,7 @@ void __fastcall TSecureShell::Send(const char * Buf, Integer Len)
   }
   FLastDataSent = Now();
   // among other forces receive of pending data to free the servers's send buffer
-  EventSelectLoop(0, false);
+  EventSelectLoop(0, false, NULL);
 
   while (BufSize > MAX_BUFSIZE)
   {
@@ -765,7 +779,7 @@ void __fastcall TSecureShell::Send(const char * Buf, Integer Len)
         "need to send at least another %u bytes",
         (BufSize, BufSize - MAX_BUFSIZE)));
     }
-    EventSelectLoop(100, false);
+    EventSelectLoop(100, false, NULL);
     BufSize = FBackend->sendbuffer(FBackendHandle);
     if (Configuration->LogProtocol >= 1)
     {
@@ -1096,7 +1110,7 @@ void inline __fastcall TSecureShell::CheckConnection(int Message)
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::PoolForData(unsigned int & Result)
+void __fastcall TSecureShell::PoolForData(WSANETWORKEVENTS & Events, unsigned int & Result)
 {
   try
   {
@@ -1105,7 +1119,10 @@ void __fastcall TSecureShell::PoolForData(unsigned int & Result)
       LogEvent("Pooling for data in case they finally arrives");
     }
 
-    if (EventSelectLoop(0, false))
+    // in extreme condition it may happen that send buffer is full, but there
+    // will be no data comming and we may not empty the send buffer because we
+    // do not process FD_WRITE until we receive any FD_READ
+    if (EventSelectLoop(0, false, &Events))
     {
       LogEvent("Data has arrived, closing query to user.");
       Result = qaOK;
@@ -1116,11 +1133,32 @@ void __fastcall TSecureShell::PoolForData(unsigned int & Result)
     // if we let the exception out, it may popup another message dialog
     // in whole event loop, another call to PoolForData from original dialog
     // would be invoked, leading to an infinite loop.
-    // by retrying we hope (that probably fatal) error would repeat in WaitForData
+    // by retrying we hope (that probably fatal) error would repeat in WaitForData.
+    // anyway now once no actual work is done in EventSelectLoop,
+    // hardly any exception can occur actually
     Result = qaRetry;
   }
 }
 //---------------------------------------------------------------------------
+class TPoolForDataEvent
+{
+public:
+  __fastcall TPoolForDataEvent(TSecureShell * SecureShell, WSANETWORKEVENTS & Events) :
+    FSecureShell(SecureShell),
+    FEvents(Events)
+  {
+  }
+
+  void __fastcall PoolForData(unsigned int & Result)
+  {
+    FSecureShell->PoolForData(FEvents, Result);
+  }
+
+private:
+  TSecureShell * FSecureShell;
+  WSANETWORKEVENTS & FEvents;
+};
+//---------------------------------------------------------------------------
 void __fastcall TSecureShell::WaitForData()
 {
   // see winsftp.c
@@ -1133,13 +1171,17 @@ void __fastcall TSecureShell::WaitForData()
       LogEvent("Looking for incoming data");
     }
 
-    IncomingData = EventSelectLoop(FSessionData->Timeout * 1000, true);
+    IncomingData = EventSelectLoop(FSessionData->Timeout * 1000, true, NULL);
     if (!IncomingData)
     {
+      WSANETWORKEVENTS Events;
+      memset(&Events, 0, sizeof(Events));
+      TPoolForDataEvent Event(this, Events);
+
       LogEvent("Waiting for data timed out, asking user what to do.");
       TQueryParams Params(qpFatalAbort | qpAllowContinueOnError);
       Params.Timer = 500;
-      Params.TimerEvent = PoolForData;
+      Params.TimerEvent = Event.PoolForData;
       Params.TimerMessage = FMTLOAD(TIMEOUT_STILL_WAITING, (FSessionData->Timeout));
       Params.TimerAnswers = qaAbort;
       int Answer = FUI->QueryUser(FMTLOAD(CONFIRM_PROLONG_TIMEOUT2, (FSessionData->Timeout)),
@@ -1155,6 +1197,7 @@ void __fastcall TSecureShell::WaitForData()
           // make sure we do not try to select it again as it would timeout
           // unless another read event occurs
           IncomingData = true;
+          HandleNetworkEvents(FSocket, Events);
           break;
 
         default:
@@ -1175,63 +1218,33 @@ bool __fastcall TSecureShell::SshFallbackCmd() const
   return ssh_fallback_cmd(FBackendHandle);
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSecureShell::ProcessNetworkEvents(SOCKET Socket)
+bool __fastcall TSecureShell::EnumNetworkEvents(SOCKET Socket, WSANETWORKEVENTS & Events)
 {
-  bool Result = false;
-
   if (Configuration->LogProtocol >= 2)
   {
     LogEvent(FORMAT("Enumerating network events for socket %d", (int(Socket))));
   }
 
   // see winplink.c
-  WSANETWORKEVENTS Events;
-  if (WSAEnumNetworkEvents(Socket, NULL, &Events) == 0)
+  WSANETWORKEVENTS AEvents;
+  if (WSAEnumNetworkEvents(Socket, NULL, &AEvents) == 0)
   {
-    static const struct { int Bit, Mask; const char * Desc; } EventTypes[] =
-    {
-      { FD_READ_BIT, FD_READ, "read" },
-      { FD_WRITE_BIT, FD_WRITE, "write" },
-      { FD_OOB_BIT, FD_OOB, "oob" },
-      { FD_ACCEPT_BIT, FD_ACCEPT, "accept" },
-      { FD_CONNECT_BIT, FD_CONNECT, "connect" },
-      { FD_CLOSE_BIT, FD_CLOSE, "close" },
-    };
-
     noise_ultralight(Socket);
-    noise_ultralight(Events.lNetworkEvents);
+    noise_ultralight(AEvents.lNetworkEvents);
 
-    if (Configuration->LogProtocol >= 2)
+    Events.lNetworkEvents |= AEvents.lNetworkEvents;
+    for (int Index = 0; Index < FD_MAX_EVENTS; Index++)
     {
-      LogEvent(FORMAT("Enumerated %d network events for socket %d",
-        (int(Events.lNetworkEvents), int(Socket))));
+      if (AEvents.iErrorCode[Index] != 0)
+      {
+        Events.iErrorCode[Index] = AEvents.iErrorCode[Index];
+      }
     }
 
-    for (int Event = 0; Event < LENOF(EventTypes); Event++)
+    if (Configuration->LogProtocol >= 2)
     {
-      if (Events.lNetworkEvents & EventTypes[Event].Mask)
-      {
-        if (EventTypes[Event].Mask & FD_READ)
-        {
-          Result = true;
-        }
-
-        int Err = Events.iErrorCode[EventTypes[Event].Bit];
-        if (Configuration->LogProtocol >= 2)
-        {
-          LogEvent(FORMAT("Detected network %s event on socket %d with error %d",
-            (EventTypes[Event].Desc, int(Socket), Err)));
-        }
-        #pragma option push -w-prc
-        LPARAM SelectEvent = WSAMAKESELECTREPLY(EventTypes[Event].Mask, Err);
-        #pragma option pop
-        if (!select_result((WPARAM)Socket, SelectEvent))
-        {
-          // note that connection was closed definitely,
-          // so "check" is actually not required
-          CheckConnection();
-        }
-      }
+      LogEvent(FORMAT("Enumerated %d network events making %d cumulative events for socket %d",
+        (int(AEvents.lNetworkEvents), int(Events.lNetworkEvents), int(Socket))));
     }
   }
   else
@@ -1242,10 +1255,57 @@ bool __fastcall TSecureShell::ProcessNetworkEvents(SOCKET Socket)
     }
   }
 
+  return
+    FLAGSET(Events.lNetworkEvents, FD_READ) ||
+    FLAGSET(Events.lNetworkEvents, FD_CLOSE);
+}
+//---------------------------------------------------------------------------
+void __fastcall TSecureShell::HandleNetworkEvents(SOCKET Socket, WSANETWORKEVENTS & Events)
+{
+  static const struct { int Bit, Mask; const char * Desc; } EventTypes[] =
+  {
+    { FD_READ_BIT, FD_READ, "read" },
+    { FD_WRITE_BIT, FD_WRITE, "write" },
+    { FD_OOB_BIT, FD_OOB, "oob" },
+    { FD_ACCEPT_BIT, FD_ACCEPT, "accept" },
+    { FD_CONNECT_BIT, FD_CONNECT, "connect" },
+    { FD_CLOSE_BIT, FD_CLOSE, "close" },
+  };
+
+  for (int Event = 0; Event < LENOF(EventTypes); Event++)
+  {
+    if (FLAGSET(Events.lNetworkEvents, EventTypes[Event].Mask))
+    {
+      int Err = Events.iErrorCode[EventTypes[Event].Bit];
+      if (Configuration->LogProtocol >= 2)
+      {
+        LogEvent(FORMAT("Handling network %s event on socket %d with error %d",
+          (EventTypes[Event].Desc, int(Socket), Err)));
+      }
+      #pragma option push -w-prc
+      LPARAM SelectEvent = WSAMAKESELECTREPLY(EventTypes[Event].Mask, Err);
+      #pragma option pop
+      if (!select_result((WPARAM)Socket, SelectEvent))
+      {
+        // note that connection was closed definitely,
+        // so "check" is actually not required
+        CheckConnection();
+      }
+    }
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TSecureShell::ProcessNetworkEvents(SOCKET Socket)
+{
+  WSANETWORKEVENTS Events;
+  memset(&Events, 0, sizeof(Events));
+  bool Result = EnumNetworkEvents(Socket, Events);
+  HandleNetworkEvents(Socket, Events);
   return Result;
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventRequired)
+bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventRequired,
+  WSANETWORKEVENTS * Events)
 {
   CheckConnection();
 
@@ -1268,9 +1328,19 @@ bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventR
           LogEvent("Detected network event");
         }
 
-        if (ProcessNetworkEvents(FSocket))
+        if (Events == NULL)
         {
-          Result = true;
+          if (ProcessNetworkEvents(FSocket))
+          {
+            Result = true;
+          }
+        }
+        else
+        {
+          if (EnumNetworkEvents(FSocket, *Events))
+          {
+            Result = true;
+          }
         }
 
         {
@@ -1328,7 +1398,7 @@ void __fastcall TSecureShell::Idle(unsigned int MSec)
 
   call_ssh_timer(FBackendHandle);
 
-  EventSelectLoop(MSec, false);
+  EventSelectLoop(MSec, false, NULL);
 }
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::KeepAlive()

+ 12 - 3
core/SecureShell.h

@@ -12,17 +12,21 @@ struct Backend;
 struct Config;
 #endif
 //---------------------------------------------------------------------------
+struct _WSANETWORKEVENTS;
+typedef struct _WSANETWORKEVENTS WSANETWORKEVENTS;
 typedef UINT_PTR SOCKET;
 typedef std::set<SOCKET> TSockets;
 struct TPuttyTranslation;
 //---------------------------------------------------------------------------
 class TSecureShell
 {
+friend class TPoolForDataEvent;
+
 private:
   SOCKET FSocket;
   HANDLE FSocketEvent;
   TSockets FPortFwdSockets;
-  TSessionUI* FUI;
+  TSessionUI * FUI;
   TSessionData * FSessionData;
   bool FActive;
   TSessionInfo FSessionInfo;
@@ -51,6 +55,7 @@ private:
   AnsiString FStdErrorTemp;
   AnsiString FStdError;
   AnsiString FCWriteTemp;
+  bool FCWriteTempUntrusted;
   AnsiString FAuthenticationLog;
   AnsiString FLastTunnelError;
   AnsiString FUserName;
@@ -64,15 +69,19 @@ private:
   void __fastcall WaitForData();
   void __fastcall Discard();
   void __fastcall FreeBackend();
-  void __fastcall PoolForData(unsigned int & Result);
+  void __fastcall PoolForData(WSANETWORKEVENTS & Events, unsigned int & Result);
   inline void __fastcall CaptureOutput(TLogLineType Type,
     const AnsiString & Line);
   void __fastcall ResetConnection();
   void __fastcall ResetSessionInfo();
   void __fastcall SocketEventSelect(SOCKET Socket, HANDLE Event, bool Startup);
+  bool __fastcall EnumNetworkEvents(SOCKET Socket, WSANETWORKEVENTS & Events);
+  void __fastcall HandleNetworkEvents(SOCKET Socket, WSANETWORKEVENTS & Events);
   bool __fastcall ProcessNetworkEvents(SOCKET Socket);
-  bool __fastcall EventSelectLoop(unsigned int MSec, bool ReadEventRequired);
+  bool __fastcall EventSelectLoop(unsigned int MSec, bool ReadEventRequired,
+    WSANETWORKEVENTS * Events);
   void __fastcall UpdateSessionInfo();
+  void __fastcall DumpCWrite();
 
 protected:
   TCaptureOutputEvent FOnCaptureOutput;

+ 42 - 9
core/SessionData.cpp

@@ -26,6 +26,8 @@ const TCipher DefaultCipherList[CIPHER_COUNT] =
 const TKex DefaultKexList[KEX_COUNT] =
   { kexDHGEx, kexDHGroup14, kexDHGroup1, kexWarn };
 const char FSProtocolNames[FSPROTOCOL_COUNT][11] = { "SCP", "SFTP (SCP)", "SFTP", "SSH", "SFTP", "FTP" };
+const int SshPortNumber = 22;
+const int FtpPortNumber = 21;
 //--- TSessionData ----------------------------------------------------
 AnsiString TSessionData::FInvalidChars("/\\[]");
 //---------------------------------------------------------------------
@@ -39,7 +41,7 @@ __fastcall TSessionData::TSessionData(AnsiString aName):
 void __fastcall TSessionData::Default()
 {
   HostName = "";
-  PortNumber = 22;
+  PortNumber = SshPortNumber;
   UserName = "";
   Password = "";
   PingInterval = 30;
@@ -131,7 +133,7 @@ void __fastcall TSessionData::Default()
 
   Tunnel = false;
   TunnelHostName = "";
-  TunnelPortNumber = 22;
+  TunnelPortNumber = SshPortNumber;
   TunnelUserName = "";
   TunnelPassword = "";
   TunnelPublicKeyFile = "";
@@ -710,6 +712,7 @@ void __fastcall TSessionData::Remove()
   THierarchicalStorage * Storage = Configuration->CreateScpStorage(true);
   try
   {
+    Storage->Explicit = true;
     if (Storage->OpenSubKey(Configuration->StoredSessionsSubKey, false))
     {
       Storage->RecursiveDeleteSubKey(StorageKey);
@@ -1623,7 +1626,9 @@ void __fastcall TStoredSessionList::Load(THierarchicalStorage * Storage,
   bool AsModified, bool UseDefaults)
 {
   TStringList *SubKeys = new TStringList();
-  try {
+  TList * Loaded = new TList;
+  try
+  {
     Storage->GetSubKeyNames(SubKeys);
     for (int Index = 0; Index < SubKeys->Count; Index++)
     {
@@ -1655,6 +1660,7 @@ void __fastcall TStoredSessionList::Load(THierarchicalStorage * Storage,
             SessionData->Name = SessionName;
             Add(SessionData);
           }
+          Loaded->Add(SessionData);
           SessionData->Load(Storage);
           if (AsModified)
           {
@@ -1663,8 +1669,23 @@ void __fastcall TStoredSessionList::Load(THierarchicalStorage * Storage,
         }
       }
     }
-  } __finally {
+
+    if (!AsModified)
+    {
+      for (int Index = 0; Index < TObjectList::Count; Index++)
+      {
+        if (Loaded->IndexOf(Items[Index]) < 0)
+        {
+          Delete(Index);
+          Index--;
+        }
+      }
+    }
+  }
+  __finally
+  {
     delete SubKeys;
+    delete Loaded;
   }
 }
 //---------------------------------------------------------------------
@@ -1713,11 +1734,12 @@ void __fastcall TStoredSessionList::Save(THierarchicalStorage * Storage, bool Al
   }
 }
 //---------------------------------------------------------------------
-void __fastcall TStoredSessionList::Save(bool All)
+void __fastcall TStoredSessionList::Save(bool All, bool Explicit)
 {
   THierarchicalStorage * Storage = Configuration->CreateScpStorage(true);
   try {
     Storage->AccessMode = smReadWrite;
+    Storage->Explicit = Explicit;
     if (Storage->OpenSubKey(Configuration->StoredSessionsSubKey, True))
       Save(Storage, All);
   } __finally {
@@ -1773,7 +1795,8 @@ void __fastcall TStoredSessionList::Import(TStoredSessionList * From,
       Add(Session);
     }
   }
-  Save();
+  // only modified, explicit
+  Save(false, true);
 }
 //---------------------------------------------------------------------
 void __fastcall TStoredSessionList::SelectSessionsToImport
@@ -1844,7 +1867,8 @@ void __fastcall TStoredSessionList::SetDefaultSettings(TSessionData * value)
     FDefaultSettings->Name = DefaultSessionName;
     if (!FReadOnly)
     {
-      Save();
+      // only modified, explicit
+      Save(false, true);
     }
   }
 }
@@ -1906,21 +1930,25 @@ TSessionData * __fastcall TStoredSessionList::ParseUrl(AnsiString Url,
 {
   bool ProtocolDefined = false;
   TFSProtocol Protocol;
+  int PortNumber;
   if (Url.SubString(1, 4).LowerCase() == "scp:")
   {
     Protocol = fsSCPonly;
+    PortNumber = SshPortNumber;
     Url.Delete(1, 4);
     ProtocolDefined = true;
   }
   else if (Url.SubString(1, 5).LowerCase() == "sftp:")
   {
     Protocol = fsSFTPonly;
+    PortNumber = SshPortNumber;
     Url.Delete(1, 5);
     ProtocolDefined = true;
   }
   else if (Url.SubString(1, 4).LowerCase() == "ftp:")
   {
     Protocol = fsFTP;
+    PortNumber = FtpPortNumber;
     Url.Delete(1, 4);
     ProtocolDefined = true;
   }
@@ -1942,7 +1970,7 @@ TSessionData * __fastcall TStoredSessionList::ParseUrl(AnsiString Url,
     if (!Url.IsEmpty())
     {
       TSessionData * AData = NULL;
-      // lookup stored session session even if protocol was defined
+      // lookup stored session even if protocol was defined
       // (this allows setting for example default username for host
       // by creating stored session named by host)
       AnsiString ConnectInfo;
@@ -1956,6 +1984,10 @@ TSessionData * __fastcall TStoredSessionList::ParseUrl(AnsiString Url,
       if (AData == NULL)
       {
         Data->Assign(DefaultSettings);
+        if (ProtocolDefined)
+        {
+          Data->PortNumber = PortNumber;
+        }
         if (Data->ParseUrl(Url, Params, FileName))
         {
           Data->Name = "";
@@ -1978,7 +2010,8 @@ TSessionData * __fastcall TStoredSessionList::ParseUrl(AnsiString Url,
         {
           AData->Remove();
           Remove(AData);
-          Save();
+          // only modified, implicit
+          Save(false, false);
         }
       }
     }

+ 1 - 1
core/SessionData.h

@@ -372,7 +372,7 @@ public:
   __fastcall TStoredSessionList(bool aReadOnly = false);
   void __fastcall Load(AnsiString aKey, bool UseDefaults);
   void __fastcall Load();
-  void __fastcall Save(bool All = false);
+  void __fastcall Save(bool All, bool Explicit);
   void __fastcall Saved();
   void __fastcall Export(const AnsiString FileName);
   void __fastcall Load(THierarchicalStorage * Storage, bool AsModified = false,

+ 8 - 1
core/SftpFileSystem.cpp

@@ -521,7 +521,14 @@ public:
 
   inline AnsiString GetString(bool Utf)
   {
-    return (Utf ? GetUtfString() : GetString());
+    if (Utf)
+    {
+      return GetUtfString();
+    }
+    else
+    {
+      return GetString();
+    }
   }
 
   // now purposeless alias to GetString

+ 5 - 2
core/Terminal.cpp

@@ -2315,7 +2315,7 @@ void __fastcall TTerminal::ChangeFileProperties(AnsiString FileName,
            UnixToDateTime(RProperties->LastAccess, SessionData->DSTMode)))));
     }
   }
-  if (File) FileModified(File, FileName);
+  FileModified(File, FileName);
   DoChangeFileProperties(FileName, File, RProperties);
   ReactOnCommand(fsChangeProperties);
 }
@@ -3765,9 +3765,12 @@ void __fastcall TTerminal::SynchronizeRemoteTimestamp(const AnsiString /*FileNam
   Properties.Modification = ConvertTimestampToUnix(ChecklistItem->FLocalLastWriteTime,
     SessionData->DSTMode);
 
+  // unfortunatelly we never have a remote file here
+  assert(ChecklistItem->FRemoteFile == NULL);
+
   ChangeFileProperties(
     UnixIncludeTrailingBackslash(ChecklistItem->Remote.Directory) + ChecklistItem->FileName,
-    ChecklistItem->FRemoteFile, &Properties);
+    NULL, &Properties);
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::SpaceAvailable(const AnsiString Path,

+ 1 - 1
filezilla/FileZillaApi.cpp

@@ -153,7 +153,7 @@ int CFileZillaApi::Connect(const t_server &server)
 	}
 	if (!bUseGSS && server.user == "")
 		return FZ_REPLY_INVALIDPARAM;
-#endif
+#endif    
 		
 	if (!(server.nServerType&FZ_SERVERTYPE_HIGHMASK))
 		return FZ_REPLY_INVALIDPARAM;

+ 334 - 334
filezilla/MainThread.cpp

@@ -44,490 +44,490 @@ static char THIS_FILE[] = __FILE__;
 
 CMainThread::CMainThread()
 {
-	m_hOwnerWnd = 0;
-	m_pControlSocket = NULL;
-	m_pFtpControlSocket = NULL;
+    m_hOwnerWnd = 0;
+    m_pControlSocket = NULL;
+    m_pFtpControlSocket = NULL;
 #ifndef MPEXT_NO_SFTP
-	m_pSFtpControlSocket = NULL;
+    m_pSFtpControlSocket = NULL;
 #endif
-	m_bBusy = FALSE;
-	m_bConnected = FALSE;
+    m_bBusy = FALSE;
+    m_bConnected = FALSE;
 #ifndef MPEXT_NO_CACHE
-	m_pDirectoryCache = 0;
+    m_pDirectoryCache = 0;
 #endif
-	m_pWorkingDir = 0;
-	m_nAsyncRequestID = 0;
-	m_bQuit = FALSE;
+    m_pWorkingDir = 0;
+    m_nAsyncRequestID = 0;
+    m_bQuit = FALSE;
 #ifndef MPEXT_NO_IDENT
-	m_pIdentServer = 0;
+    m_pIdentServer = 0;
 #endif
-	m_hThread = 0;
-	m_dwThreadId = 0;
+    m_hThread = 0;
+    m_dwThreadId = 0;
 }
 
 CMainThread::~CMainThread()
 {
-	delete m_pWorkingDir;
-	CloseHandle(m_hThread);
+    delete m_pWorkingDir;
+    CloseHandle(m_hThread);
 }
 
 BOOL CMainThread::InitInstance()
-{	
-	m_nTimerID=SetTimer(0,1,1000,0);
+{
+    m_nTimerID=SetTimer(0,1,1000,0);
 #ifndef MPEXT_NO_CACHE
-	m_pDirectoryCache=new CDirectoryCache;					
+    m_pDirectoryCache=new CDirectoryCache;
 #endif
-	m_pPostKeepAliveCommand=0;
-	
-	// initialize Winsock library
-	BOOL res=TRUE;
-	WSADATA wsaData;
-	
-	WORD wVersionRequested = MAKEWORD(1, 1);
-	int nResult = WSAStartup(wVersionRequested, &wsaData);
-	if (nResult != 0)
-		res=FALSE;
-	else if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
-	{
-		WSACleanup();
-		res=FALSE;
-	}
-	
-	m_pFtpControlSocket=new CFtpControlSocket(this);
+    m_pPostKeepAliveCommand=0;
+
+    // initialize Winsock library
+    BOOL res=TRUE;
+    WSADATA wsaData;
+
+    WORD wVersionRequested = MAKEWORD(1, 1);
+    int nResult = WSAStartup(wVersionRequested, &wsaData);
+    if (nResult != 0)
+        res=FALSE;
+    else if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
+    {
+        WSACleanup();
+        res=FALSE;
+    }
+
+    m_pFtpControlSocket=new CFtpControlSocket(this);
 #ifndef MPEXT_NO_SFTP
-	m_pSFtpControlSocket=new CSFtpControlSocket(this);
+    m_pSFtpControlSocket=new CSFtpControlSocket(this);
 #endif
-	m_pControlSocket=m_pFtpControlSocket;
-	m_pFtpControlSocket->InitLog(this);
+    m_pControlSocket=m_pFtpControlSocket;
+    m_pFtpControlSocket->InitLog(this);
 #ifndef MPEXT_NO_SFTP
-	m_pSFtpControlSocket->InitLog(this);
+    m_pSFtpControlSocket->InitLog(this);
 #endif
 #ifndef MPEXT_NO_IDENT
-	if (COptions::GetOptionVal(OPTION_IDENT) && !COptions::GetOptionVal(OPTION_IDENTCONNECT))
-		m_pIdentServer=new CIdentServerControl(this);
+    if (COptions::GetOptionVal(OPTION_IDENT) && !COptions::GetOptionVal(OPTION_IDENTCONNECT))
+        m_pIdentServer=new CIdentServerControl(this);
 #endif
-	return TRUE;
+    return TRUE;
 }
 
 DWORD CMainThread::ExitInstance()
 {
-	KillTimer(0,m_nTimerID);
-	if (m_pFtpControlSocket)
-		delete m_pFtpControlSocket;
+    KillTimer(0,m_nTimerID);
+    if (m_pFtpControlSocket)
+        delete m_pFtpControlSocket;
 #ifndef MPEXT_NO_SFTP
-	if (m_pSFtpControlSocket)
-		delete m_pSFtpControlSocket;
+    if (m_pSFtpControlSocket)
+        delete m_pSFtpControlSocket;
 #endif
 #ifndef MPEXT_NO_CACHE
-	if (m_pDirectoryCache)
-		delete m_pDirectoryCache;
+    if (m_pDirectoryCache)
+        delete m_pDirectoryCache;
 #endif
 #ifndef MPEXT_NO_IDENT
-	if (m_pIdentServer)
-		delete m_pIdentServer;
+    if (m_pIdentServer)
+        delete m_pIdentServer;
 #endif
-	return 1;
+    return 1;
 }
 
 BOOL CMainThread::IsConnected()
 {
-	BOOL bConnected;
-	ECS;
-	bConnected=m_bConnected;
-	LCS;
-	return bConnected;
+    BOOL bConnected;
+    ECS;
+    bConnected=m_bConnected;
+    LCS;
+    return bConnected;
 }
 
 void CMainThread::OnTimer(WPARAM wParam, LPARAM lParam)
 {
-	if (!m_pControlSocket)
-		return;
-	
-	if (wParam==m_nTimerID)
-		m_pControlSocket->OnTimer();
-	
-	return;
+    if (!m_pControlSocket)
+        return;
+
+    if (wParam==m_nTimerID)
+        m_pControlSocket->OnTimer();
+
+    return;
 }
 
 void CMainThread::ShowStatus(CString status, int type)
 {
-	ECS;
-	if (m_bQuit)
-	{
-		LCS;
-		return;
-	}
-	LCS;
-	//Displays a message in the message log
-	t_ffam_statusmessage *pStatus = new t_ffam_statusmessage;
-	pStatus->post = TRUE;
-	pStatus->status = status;
-	pStatus->type = type;
-	if (!PostMessage(m_hOwnerWnd, m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_STATUS, 0), (LPARAM)pStatus))
-		delete pStatus;
+    ECS;
+    if (m_bQuit)
+    {
+        LCS;
+        return;
+    }
+    LCS;
+    //Displays a message in the message log
+    t_ffam_statusmessage *pStatus = new t_ffam_statusmessage;
+    pStatus->post = TRUE;
+    pStatus->status = status;
+    pStatus->type = type;
+    if (!PostMessage(m_hOwnerWnd, m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_STATUS, 0), (LPARAM)pStatus))
+        delete pStatus;
 }
 
 void CMainThread::ShowStatus(UINT nID, int type)
 {
-	ECS;
-	if (m_bQuit)
-	{
-		LCS;
-		return;
-	}
-	LCS;
-	CString str;
-	str.LoadString(nID);
-	ShowStatus(str,type);
+    ECS;
+    if (m_bQuit)
+    {
+        LCS;
+        return;
+    }
+    LCS;
+    CString str;
+    str.LoadString(nID);
+    ShowStatus(str,type);
 }
 
 BOOL CMainThread::OnThreadMessage(UINT Msg, WPARAM wParam, LPARAM lParam)
 {
-	if (Msg==m_nInternalMessageID)
-	{
-		if (wParam==FZAPI_THREADMSG_COMMAND)
-		{
-			if (m_pControlSocket && !m_pControlSocket->IsReady())
-				m_pPostKeepAliveCommand=(t_command *)lParam;
-			else
-			{
-				t_command *pCommand=(t_command *)lParam;
-				switch(pCommand->id)
-				{
-				case FZ_COMMAND_CONNECT:
-					ASSERT(!IsConnected());
-					SetCurrentPath(CServerPath());
+    if (Msg==m_nInternalMessageID)
+    {
+        if (wParam==FZAPI_THREADMSG_COMMAND)
+        {
+            if (m_pControlSocket && !m_pControlSocket->IsReady())
+                m_pPostKeepAliveCommand=(t_command *)lParam;
+            else
+            {
+                t_command *pCommand=(t_command *)lParam;
+                switch(pCommand->id)
+                {
+                case FZ_COMMAND_CONNECT:
+                    ASSERT(!IsConnected());
+                    SetCurrentPath(CServerPath());
 #ifndef MPEXT_NO_SFTP
-					if (pCommand->server.nServerType&FZ_SERVERTYPE_SUB_FTP_SFTP)
-						m_pControlSocket=m_pSFtpControlSocket;
-					else
+                    if (pCommand->server.nServerType&FZ_SERVERTYPE_SUB_FTP_SFTP)
+                        m_pControlSocket=m_pSFtpControlSocket;
+                    else
 #endif
-						m_pControlSocket=m_pFtpControlSocket;
-					ASSERT(m_pControlSocket);
-					m_pControlSocket->Connect(pCommand->server);
-					break;
-				case FZ_COMMAND_LIST:
-					ASSERT(m_pControlSocket);
-					m_pControlSocket->List(FALSE, 0, pCommand->path, pCommand->param1, pCommand->param4);
-					break;
-				case FZ_COMMAND_FILETRANSFER:
-					ASSERT(m_pControlSocket);
-					m_pControlSocket->FileTransfer(&pCommand->transferfile);
-					break;
-				case FZ_COMMAND_CUSTOMCOMMAND:
-					ASSERT(m_pControlSocket);
-					m_pControlSocket->FtpCommand(pCommand->param1);
-					break;
-				case FZ_COMMAND_DELETE:
-					ASSERT(m_pControlSocket);
-					m_pControlSocket->Delete(pCommand->param1, pCommand->path);
-					break;
-				case FZ_COMMAND_REMOVEDIR:
-					ASSERT(m_pControlSocket);
-					m_pControlSocket->RemoveDir(pCommand->param1, pCommand->path);
-					break;
-				case FZ_COMMAND_MAKEDIR:
-					ASSERT(m_pControlSocket);
-					m_pControlSocket->MakeDir(pCommand->path);
-					break;
-				case FZ_COMMAND_RENAME:
-					ASSERT(m_pControlSocket);
-					m_pControlSocket->Rename(pCommand->param1, pCommand->param2, pCommand->path, pCommand->newPath);
-					break;
-				case FZ_COMMAND_CHMOD:
-					ASSERT(m_pControlSocket);
-					m_pControlSocket->Chmod(pCommand->param1, pCommand->path, pCommand->param4);
-					break;
-				}
-				delete pCommand;
-			}
-		}
-		else if (wParam==FZAPI_THREADMSG_PROCESSREPLY)
-			m_pControlSocket->ProcessReply();
-		else if (wParam==FZAPI_THREADMSG_TRANSFEREND)
-			m_pControlSocket->TransferEnd(lParam);
-		else if (wParam==FZAPI_THREADMSG_CANCEL)
-			m_pControlSocket->Cancel(lParam);
-		else if (wParam==FZAPI_THREADMSG_DISCONNECT)
-			m_pControlSocket->Disconnect();
-		else if (wParam==FZAPI_THREADMSG_POSTKEEPALIVE)
-		{
-			if (m_pPostKeepAliveCommand)
-			{
-				PostThreadMessage(m_nInternalMessageID,FZAPI_THREADMSG_COMMAND,(LPARAM)m_pPostKeepAliveCommand);
-				m_pPostKeepAliveCommand=0;
-			}
-		}
-		else if (wParam==FZAPI_THREADMSG_ASYNCREQUESTREPLY)
-		{
-			CAsyncRequestData *pData=(CAsyncRequestData *)lParam;
-			if (pData)
-			{
-				if (pData->nRequestID!=GetAsyncRequestID())
-					LogMessage(__FILE__, __LINE__, this,FZ_LOG_INFO, _T("Ignoring old request ID"));
-				else
-					m_pControlSocket->SetAsyncRequestResult(pData->nRequestResult, pData);
-				delete pData;
-			}
-			else
-				LogMessage(__FILE__, __LINE__, this,FZ_LOG_WARNING, _T("Request reply without data"));
-		}
-		return TRUE;
-	}
-	else if (Msg==WM_TIMER)
-	{
-		OnTimer(wParam, lParam);
-	}
-	
-	return TRUE;
+                        m_pControlSocket=m_pFtpControlSocket;
+                    ASSERT(m_pControlSocket);
+                    m_pControlSocket->Connect(pCommand->server);
+                    break;
+                case FZ_COMMAND_LIST:
+                    ASSERT(m_pControlSocket);
+                    m_pControlSocket->List(FALSE, 0, pCommand->path, pCommand->param1, pCommand->param4);
+                    break;
+                case FZ_COMMAND_FILETRANSFER:
+                    ASSERT(m_pControlSocket);
+                    m_pControlSocket->FileTransfer(&pCommand->transferfile);
+                    break;
+                case FZ_COMMAND_CUSTOMCOMMAND:
+                    ASSERT(m_pControlSocket);
+                    m_pControlSocket->FtpCommand(pCommand->param1);
+                    break;
+                case FZ_COMMAND_DELETE:
+                    ASSERT(m_pControlSocket);
+                    m_pControlSocket->Delete(pCommand->param1, pCommand->path);
+                    break;
+                case FZ_COMMAND_REMOVEDIR:
+                    ASSERT(m_pControlSocket);
+                    m_pControlSocket->RemoveDir(pCommand->param1, pCommand->path);
+                    break;
+                case FZ_COMMAND_MAKEDIR:
+                    ASSERT(m_pControlSocket);
+                    m_pControlSocket->MakeDir(pCommand->path);
+                    break;
+                case FZ_COMMAND_RENAME:
+                    ASSERT(m_pControlSocket);
+                    m_pControlSocket->Rename(pCommand->param1, pCommand->param2, pCommand->path, pCommand->newPath);
+                    break;
+                case FZ_COMMAND_CHMOD:
+                    ASSERT(m_pControlSocket);
+                    m_pControlSocket->Chmod(pCommand->param1, pCommand->path, pCommand->param4);
+                    break;
+                }
+                delete pCommand;
+            }
+        }
+        else if (wParam==FZAPI_THREADMSG_PROCESSREPLY)
+            m_pControlSocket->ProcessReply();
+        else if (wParam==FZAPI_THREADMSG_TRANSFEREND)
+            m_pControlSocket->TransferEnd(lParam);
+        else if (wParam==FZAPI_THREADMSG_CANCEL)
+            m_pControlSocket->Cancel(lParam);
+        else if (wParam==FZAPI_THREADMSG_DISCONNECT)
+            m_pControlSocket->Disconnect();
+        else if (wParam==FZAPI_THREADMSG_POSTKEEPALIVE)
+        {
+            if (m_pPostKeepAliveCommand)
+            {
+                PostThreadMessage(m_nInternalMessageID,FZAPI_THREADMSG_COMMAND,(LPARAM)m_pPostKeepAliveCommand);
+                m_pPostKeepAliveCommand=0;
+            }
+        }
+        else if (wParam==FZAPI_THREADMSG_ASYNCREQUESTREPLY)
+        {
+            CAsyncRequestData *pData=(CAsyncRequestData *)lParam;
+            if (pData)
+            {
+                if (pData->nRequestID!=GetAsyncRequestID())
+                    LogMessage(__FILE__, __LINE__, this,FZ_LOG_INFO, _T("Ignoring old request ID"));
+                else
+                    m_pControlSocket->SetAsyncRequestResult(pData->nRequestResult, pData);
+                delete pData;
+            }
+            else
+                LogMessage(__FILE__, __LINE__, this,FZ_LOG_WARNING, _T("Request reply without data"));
+        }
+        return TRUE;
+    }
+    else if (Msg==WM_TIMER)
+    {
+        OnTimer(wParam, lParam);
+    }
+
+    return TRUE;
 }
 
 BOOL CMainThread::IsBusy()
 {
-	BOOL bBusy;
-	ECS;
-	bBusy=m_bBusy;
-	LCS;
-	return bBusy;
+    BOOL bBusy;
+    ECS;
+    bBusy=m_bBusy;
+    LCS;
+    return bBusy;
 }
 
 void CMainThread::Command(const t_command &command)
 {
-	ASSERT(!IsBusy());
-	ECS;
-	if (m_bQuit)
-	{
-		LCS;
-		return;
-	}
-	m_bBusy=TRUE;
-	t_command *pCommand=new t_command;
-	*pCommand=command;
-	VERIFY(PostThreadMessage(m_nInternalMessageID,FZAPI_THREADMSG_COMMAND,(LPARAM)pCommand));
-	m_LastCommand=command;
-	LCS;	
+    ASSERT(!IsBusy());
+    ECS;
+    if (m_bQuit)
+    {
+        LCS;
+        return;
+    }
+    m_bBusy=TRUE;
+    t_command *pCommand=new t_command;
+    *pCommand=command;
+    VERIFY(PostThreadMessage(m_nInternalMessageID,FZAPI_THREADMSG_COMMAND,(LPARAM)pCommand));
+    m_LastCommand=command;
+    LCS;
 }
 
 BOOL CMainThread::LastOperationSuccessful()
 {
-	return TRUE;
+    return TRUE;
 }
 
 void CMainThread::SetBusy(BOOL bBusy)
 {
-	ECS;
-	m_bBusy=bBusy;
-	LCS;
+    ECS;
+    m_bBusy=bBusy;
+    LCS;
 }
 
 void CMainThread::SetConnected(BOOL bConnected /*=TRUE*/)
 {
-	ECS;
-	m_bConnected=bConnected;
-	LCS;
+    ECS;
+    m_bConnected=bConnected;
+    LCS;
 }
 
 bool CMainThread::GetCurrentPath(CServerPath &dir)
 {
-	if (!IsConnected())
-		return false;
-	ECS;
-	dir=m_CurrentPath;
-	LCS;
-	return true;
+    if (!IsConnected())
+        return false;
+    ECS;
+    dir=m_CurrentPath;
+    LCS;
+    return true;
 }
 
 CServerPath CMainThread::GetCurrentPath()
 {
-	CServerPath path;
-	bool res = GetCurrentPath(path);
-	if (!res)
-		return CServerPath();
-	
-	return path;
+    CServerPath path;
+    bool res = GetCurrentPath(path);
+    if (!res)
+        return CServerPath();
+
+    return path;
 }
 
 BOOL CMainThread::GetCurrentServer(t_server &server)
 {
-	if (!IsConnected())
-		return FALSE;
-	ECS;
-	server=m_pControlSocket->GetCurrentServer();
-	LCS;
-	return TRUE;
+    if (!IsConnected())
+        return FALSE;
+    ECS;
+    server=m_pControlSocket->GetCurrentServer();
+    LCS;
+    return TRUE;
 }
 
 void CMainThread::Quit()
 {
-	ECS;
-	m_bQuit=TRUE;
-	LCS;
-	if (IsBusy())
-		PostThreadMessage(m_nInternalMessageID, FZAPI_THREADMSG_CANCEL, 1);
-	PostThreadMessage(WM_QUIT, 0, 0);
+    ECS;
+    m_bQuit=TRUE;
+    LCS;
+    if (IsBusy())
+        PostThreadMessage(m_nInternalMessageID, FZAPI_THREADMSG_CANCEL, 1);
+    PostThreadMessage(WM_QUIT, 0, 0);
 }
 
 void CMainThread::SetCurrentPath(CServerPath path)
 {
-	ECS;
-	m_CurrentPath=path;
-	LCS;
-	return;
+    ECS;
+    m_CurrentPath=path;
+    LCS;
+    return;
 }
 
 #ifndef MPEXT
 int CMainThread::GetOption(int nOption)
 {
-	int nValue=0;
-	ECS;
-	std::map<int, int>::iterator iter=m_Options.find(nOption);
-	if (iter!=m_Options.end())
-		nValue=iter->second;
-	LCS;
-	return nValue;
+    int nValue=0;
+    ECS;
+    std::map<int, int>::iterator iter=m_Options.find(nOption);
+    if (iter!=m_Options.end())
+        nValue=iter->second;
+    LCS;
+    return nValue;
 }
 
 void CMainThread::SetOption(int nOption, int nValue)
 {
-	ECS;
-	m_Options[nOption]=nValue;
-	LCS;
+    ECS;
+    m_Options[nOption]=nValue;
+    LCS;
 }
 #endif
 
 BOOL CMainThread::GetWorkingDir(t_directory *pWorkingDir)
 {
-	ECS;
-	if (m_pWorkingDir)
-	{
-		*pWorkingDir=*m_pWorkingDir;
-		LCS;
-		return TRUE;
-	}
-	LCS;
-	return FALSE;
+    ECS;
+    if (m_pWorkingDir)
+    {
+        *pWorkingDir=*m_pWorkingDir;
+        LCS;
+        return TRUE;
+    }
+    LCS;
+    return FALSE;
 }
 
 void CMainThread::SetWorkingDir(t_directory *pWorkingDir)
 {
-	if (!pWorkingDir)
-	{
-		ECS;
-		delete m_pWorkingDir;
-		m_pWorkingDir=0;
-		LCS;
-	}
-	else
-	{
-		ECS;
-		if (!m_pWorkingDir)
-			m_pWorkingDir=new t_directory;
-		*m_pWorkingDir=*pWorkingDir;
-		LCS;
-	}
-	if (pWorkingDir)
-	{
-		t_directory *pDirectoryToSend=new t_directory;
-		*pDirectoryToSend=*pWorkingDir;
-		PostMessage(m_hOwnerWnd, m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_LISTDATA, 0), (LPARAM)pDirectoryToSend);
-	}
-
-	return;
+    if (!pWorkingDir)
+    {
+        ECS;
+        delete m_pWorkingDir;
+        m_pWorkingDir=0;
+        LCS;
+    }
+    else
+    {
+        ECS;
+        if (!m_pWorkingDir)
+            m_pWorkingDir=new t_directory;
+        *m_pWorkingDir=*pWorkingDir;
+        LCS;
+    }
+    if (pWorkingDir)
+    {
+        t_directory *pDirectoryToSend=new t_directory;
+        *pDirectoryToSend=*pWorkingDir;
+        PostMessage(m_hOwnerWnd, m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_LISTDATA, 0), (LPARAM)pDirectoryToSend);
+    }
+
+    return;
 }
 
 bool CMainThread::GetWorkingDirPath(CServerPath &path)
 {
-	ECS;
-	if (m_pWorkingDir)
-	{
-		path = m_pWorkingDir->path;
-		LCS;
-		return true;
-	}
-	LCS;
-
-	return false;
+    ECS;
+    if (m_pWorkingDir)
+    {
+        path = m_pWorkingDir->path;
+        LCS;
+        return true;
+    }
+    LCS;
+
+    return false;
 }
 
 __int64 CMainThread::GetAsyncRequestID() const
 {
-	return m_nAsyncRequestID;
+    return m_nAsyncRequestID;
 }
 
 __int64 CMainThread::GetNextAsyncRequestID()
 {
-	return ++m_nAsyncRequestID;
+    return ++m_nAsyncRequestID;
 }
 
 CMainThread* CMainThread::Create(int nPriority /*=THREAD_PRIORITY_NORMAL*/, DWORD dwCreateFlags /*=0*/)
 {
-	CMainThread *pMainThread=new CMainThread();
-	pMainThread->m_hThread=CreateThread(0, 0, ThreadProc, pMainThread, dwCreateFlags, &pMainThread->m_dwThreadId);
-	if (!pMainThread->m_hThread)
-	{
-		delete pMainThread;
-		return NULL;
-	}
-	::SetThreadPriority(pMainThread->m_hThread, nPriority);
-	return pMainThread;
+    CMainThread *pMainThread=new CMainThread();
+    pMainThread->m_hThread=CreateThread(0, 0, ThreadProc, pMainThread, dwCreateFlags, &pMainThread->m_dwThreadId);
+    if (!pMainThread->m_hThread)
+    {
+        delete pMainThread;
+        return NULL;
+    }
+    ::SetThreadPriority(pMainThread->m_hThread, nPriority);
+    return pMainThread;
 }
 
 BOOL CMainThread::PostThreadMessage(UINT message, WPARAM wParam, LPARAM lParam)
 {
-	return ::PostThreadMessage(m_dwThreadId, message, wParam, lParam);
+    return ::PostThreadMessage(m_dwThreadId, message, wParam, lParam);
 }
 
 DWORD CMainThread::ResumeThread()
 {
-	BOOL res=::ResumeThread(m_hThread);
-	if (res)
-	{
-		m_EventStarted.Lock();
-		m_EventStarted.Unlock();
-	}
-	return res;
+    BOOL res=::ResumeThread(m_hThread);
+    if (res)
+    {
+        m_EventStarted.Lock();
+        m_EventStarted.Unlock();
+    }
+    return res;
 }
 
 DWORD WINAPI CMainThread::ThreadProc(LPVOID lpParameter)
 {
-	return ((CMainThread *)lpParameter)->Run();
+    return ((CMainThread *)lpParameter)->Run();
 }
 
 DWORD CMainThread::Run()
 {
-	ECS;
-	InitInstance();
-	m_EventStarted.SetEvent();
-	LCS;
-	MSG msg;
-	while (GetMessage(&msg, 0, 0, 0))
-	{
-		TranslateMessage(&msg);
-		if (!msg.hwnd)
-			OnThreadMessage(msg.message, msg.wParam, msg.lParam);
-		DispatchMessage(&msg);
-	}
-	DWORD res = ExitInstance();
-	delete this;
-	return res;
+    ECS;
+    InitInstance();
+    m_EventStarted.SetEvent();
+    LCS;
+    MSG msg;
+    while (GetMessage(&msg, 0, 0, 0))
+    {
+        TranslateMessage(&msg);
+        if (!msg.hwnd)
+            OnThreadMessage(msg.message, msg.wParam, msg.lParam);
+        DispatchMessage(&msg);
+    }
+    DWORD res = ExitInstance();
+    delete this;
+    return res;
 }
 
 BOOL CMainThread::IsValid() const
 {
-	if (!this)
-		return FALSE;
+    if (!this)
+        return FALSE;
 
-	if (IsBadWritePtr((VOID *)this, sizeof(CMainThread)) )
-		return FALSE;
+    if (IsBadWritePtr((VOID *)this, sizeof(CMainThread)) )
+        return FALSE;
 
-	if (m_pControlSocket &&
-		m_pControlSocket != m_pFtpControlSocket
+    if (m_pControlSocket &&
+        m_pControlSocket != m_pFtpControlSocket
 #ifndef MPEXT_NO_SFTP
-		&&
-		m_pControlSocket != m_pSFtpControlSocket
+        &&
+        m_pControlSocket != m_pSFtpControlSocket
 #endif
-		)
-		return FALSE;
+        )
+        return FALSE;
 
-	return TRUE;
+    return TRUE;
 }

+ 11 - 2
forms/About.cpp

@@ -102,7 +102,15 @@ __fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
   else
   {
     TranslatorLabel->Caption = LoadStr(TRANSLATOR_INFO);
-    LinkLabel(TranslatorUrlLabel, LoadStr(TRANSLATOR_URL));
+    AnsiString TranslatorUrl = LoadStr(TRANSLATOR_URL);
+    if (!TranslatorUrl.IsEmpty())
+    {
+      LinkLabel(TranslatorUrlLabel, TranslatorUrl);
+    }
+    else
+    {
+      TranslatorUrlLabel->Visible = false;
+    }
   }
 
   #ifdef NO_FILEZILLA
@@ -130,7 +138,8 @@ __fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
 void __fastcall TAboutDialog::LoadData()
 {
   AnsiString Version = FConfiguration->VersionStr;
-  if (FConfiguration->Version != FConfiguration->ProductVersion)
+  if (!FConfiguration->ProductName.IsEmpty() &&
+      (FConfiguration->Version != FConfiguration->ProductVersion))
   {
     Version = FMTLOAD(ABOUT_BASED_ON_PRODUCT,
       (Version, FConfiguration->ProductName, FConfiguration->ProductVersion));

+ 31 - 0
forms/Authenticate.cpp

@@ -39,6 +39,37 @@ void __fastcall TAuthenticateForm::HideAsModal()
   ::HideAsModal(this, FShowAsModalStorage);
 }
 //---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::WMNCCreate(TWMNCCreate & Message)
+{
+  // bypass TForm::WMNCCreate no prevent disabling "resize"
+  // (wish is done for bsDialog, see comments in CreateParams)
+  DefaultHandler(&Message);
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::Dispatch(void * AMessage)
+{
+  TMessage & Message = *reinterpret_cast<TMessage *>(AMessage);
+  if (Message.Msg == WM_NCCREATE)
+  {
+    WMNCCreate(*reinterpret_cast<TWMNCCreate *>(AMessage));
+  }
+  else
+  {
+    TForm::Dispatch(AMessage);
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::CreateParams(TCreateParams & Params)
+{
+  TForm::CreateParams(Params);
+
+  // Allow resizing of the window, even if this is bsDialog.
+  // This makes it more close to bsSizeable, but bsSizeable cannot for some
+  // reason receive focus, if window is shown atop non-main window
+  // (like editor)
+  Params.Style = Params.Style | WS_THICKFRAME;
+}
+//---------------------------------------------------------------------------
 void __fastcall TAuthenticateForm::FormShow(TObject * /*Sender*/)
 {
   AdjustControls();

+ 1 - 1
forms/Authenticate.dfm

@@ -3,8 +3,8 @@ object AuthenticateForm: TAuthenticateForm
   Top = 113
   HelpType = htKeyword
   HelpKeyword = 'ui_authenticate'
-  AutoScroll = False
   BorderIcons = [biSystemMenu]
+  BorderStyle = bsDialog
   Caption = 'AuthenticateForm'
   ClientHeight = 270
   ClientWidth = 375

+ 3 - 0
forms/Authenticate.h

@@ -54,6 +54,9 @@ protected:
   bool __fastcall Execute(AnsiString Status, TControl * Control,
     TWinControl * FocusControl, TButton * DefaultButton, TButton * CancelButton,
     bool FixHeight, bool Zoom, bool ForceLog);
+  virtual void __fastcall CreateParams(TCreateParams & Params);
+  virtual void __fastcall Dispatch(void * AMessage);
+  void __fastcall WMNCCreate(TWMNCCreate & Message);
 
 private:
   void * FShowAsModalStorage;

+ 73 - 6
forms/CustomScpExplorer.cpp

@@ -129,6 +129,8 @@ public:
   }
 };
 //---------------------------------------------------------------------------
+static const int OutPos = -32000;
+//---------------------------------------------------------------------------
 __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
     FFormRestored(False), TForm(Owner)
 {
@@ -234,6 +236,8 @@ __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
 //---------------------------------------------------------------------------
 __fastcall TCustomScpExplorerForm::~TCustomScpExplorerForm()
 {
+  Application->UnhookMainWindow(MainWindowHook);
+
   Application->OnHint = NULL;
   Application->OnMinimize = NULL;
   Application->OnRestore = NULL;
@@ -2748,7 +2752,8 @@ void __fastcall TCustomScpExplorerForm::DuplicateSession()
     {
       AnsiString SessionName = StoredSessions->HiddenPrefix + "duplicate";
       StoredSessions->NewSession(SessionName, SessionData);
-      StoredSessions->Save();
+      // modified only, explicit
+      StoredSessions->Save(false, true);
       if (!ExecuteShell(Application->ExeName, FORMAT("\"%s\"", (SessionName))))
       {
         throw Exception(FMTLOAD(EXECUTE_APP_ERROR, (Application->ExeName)));
@@ -3391,7 +3396,8 @@ void __fastcall TCustomScpExplorerForm::SaveCurrentSession()
       SessionData->Assign(Terminal->SessionData);
       UpdateSessionData(SessionData);
       StoredSessions->NewSession(SessionName, SessionData);
-      StoredSessions->Save();
+      // modified only, explicit
+      StoredSessions->Save(false, true);
     }
     __finally
     {
@@ -4012,15 +4018,33 @@ void __fastcall TCustomScpExplorerForm::CMAppSysCommand(TMessage & Message)
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::WMSysCommand(TMessage & Message)
 {
+  // The four low-order bits are used internally by Windows
+  unsigned int Cmd = (Message.WParam & 0xFFF0);
   // SC_RESTORE, SC_MAXIMIZE, SC_MINIMIZE - buttons on windows title
   // SC_DEFAULT - double click on windows title (does not work, at least on WinXP)
   // 61730 - restore thru double click - undocumented
   // 61490 - maximize thru double click - undocumented
-  if ((Message.WParam == SC_RESTORE) || (Message.WParam == SC_MAXIMIZE) ||
-      (Message.WParam == SC_MINIMIZE) || (Message.WParam == SC_DEFAULT) ||
-      (Message.WParam == 61730) || (Message.WParam == 61490))
+  if ((Cmd == SC_RESTORE) || (Cmd == SC_MAXIMIZE) ||
+      (Cmd == SC_MINIMIZE) || (Cmd == SC_DEFAULT))
   {
-    SysResizing(Message.WParam);
+    SysResizing(Cmd);
+  }
+  TForm::Dispatch(&Message);
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::WMWindowPosChanging(TWMWindowPosMsg & Message)
+{
+  // MSVDM (not sure is it is generic feature) sets size of all windows
+  // to iconic and moves top-level windows (with destop as parent) out
+  // of the screen (-32000:-32000). However other windows (such as
+  // VCL main window with hidden parent) are moved just above
+  // the task bar. Override this.
+  if (FLAGCLEAR(Message.WindowPos->flags, SWP_NOMOVE) &&
+      (Message.WindowPos->cx == GetSystemMetrics(SM_CXMINIMIZED)) &&
+      (Message.WindowPos->cy == GetSystemMetrics(SM_CYMINIMIZED)))
+  {
+    Message.WindowPos->x = OutPos;
+    Message.WindowPos->y = OutPos;
   }
   TForm::Dispatch(&Message);
 }
@@ -5461,6 +5485,10 @@ void __fastcall TCustomScpExplorerForm::Dispatch(void * Message)
       WMSysCommand(*M);
       break;
 
+    case WM_WINDOWPOSCHANGING:
+      WMWindowPosChanging(*reinterpret_cast<TWMWindowPosMsg *>(M));
+      break;
+
     case WM_COMPONENT_HIDE:
       {
         unsigned short Component = static_cast<unsigned short>(M->WParam);
@@ -5736,3 +5764,42 @@ void __fastcall TCustomScpExplorerForm::UnlockWindow()
   }
 }
 //---------------------------------------------------------------------------
+bool __fastcall TCustomScpExplorerForm::MainWindowHook(TMessage & AMessage)
+{
+  // workaround for problem with hidden application window.
+  // "groupped" window arrangement commands send WM_WINDOWPOSCHANGING to
+  // windows associated with taskbar buttons (i.e. the hidden one for VCL).
+  // we forward here the message to the main window.
+  // this does not solve "all windows" arrangement commands,
+  // which calculates size according to number of all visible windows.
+  // hence they count VCL application twice.
+
+  // code is said to be from Issue 4/95 of The Delphi Magazine
+  if (AMessage.Msg == WM_WINDOWPOSCHANGING)
+  {
+    TWMWindowPosMsg & Message = reinterpret_cast<TWMWindowPosMsg &>(AMessage);
+
+    assert(Message.WindowPos->hwnd == Application->Handle);
+    if ((Message.WindowPos->hwnd == Application->Handle) &&
+        !IsIconic(Message.WindowPos->hwnd) &&
+        (Message.WindowPos->cx > 0) &&
+        (Message.WindowPos->cy > 0))
+    {
+      unsigned int LocalFlags = Message.WindowPos->flags | SWP_NOZORDER;
+      if (BorderStyle == bsSizeable)
+      {
+        LocalFlags = LocalFlags & ~SWP_NOSIZE;
+      }
+      else
+      {
+        LocalFlags = LocalFlags | SWP_NOSIZE;
+      }
+
+      SetWindowPos(Handle, 0, Message.WindowPos->x, Message.WindowPos->y,
+        Message.WindowPos->cx, Message.WindowPos->cy, LocalFlags);
+    }
+  }
+
+  return false;
+}
+//---------------------------------------------------------------------------

+ 2 - 0
forms/CustomScpExplorer.h

@@ -213,6 +213,7 @@ private:
   void __fastcall QueueSplitterDblClick(TObject * Sender);
   void __fastcall ApplicationMinimize(TObject * Sender);
   void __fastcall ApplicationRestore(TObject * Sender);
+  bool __fastcall MainWindowHook(TMessage & Message);
 
 protected:
   TOperationSide FCurrentSide;
@@ -278,6 +279,7 @@ protected:
   void __fastcall CMAppSysCommand(TMessage & Message);
   void __fastcall WMAppCommand(TMessage & Message);
   void __fastcall WMSysCommand(TMessage & Message);
+  void __fastcall WMWindowPosChanging(TWMWindowPosMsg & Message);
   virtual void __fastcall SysResizing(unsigned int Cmd);
   DYNAMIC void __fastcall DoShow();
   TStrings * __fastcall CreateVisitedDirectories(TOperationSide Side);

+ 4 - 2
forms/Login.cpp

@@ -1140,7 +1140,8 @@ void __fastcall TLoginDialog::SaveSessionActionExecute(TObject * /*Sender*/)
       TListItem * Item;
       TSessionData *NewSession =
         StoredSessions->NewSession(SessionName, FSessionData);
-      StoredSessions->Save();
+      // modified only, explicit
+      StoredSessions->Save(false, true);
       SaveConfiguration();
       // by now list must contais same number of items or one less
       assert(StoredSessions->Count == SessionListView->Items->Count ||
@@ -1789,7 +1790,8 @@ void __fastcall TLoginDialog::SessionListViewEdited(TObject * /*Sender*/,
 
     int PrevCount = StoredSessions->Count;
     TSessionData * NewSession = StoredSessions->NewSession(S, Session);
-    StoredSessions->Save();
+    // modified only explicit
+    StoredSessions->Save(false, true);
     // the session may be the same, if only letter case has changed
     if (Session != NewSession)
     {

+ 2 - 2
forms/ScpCommander.cpp

@@ -1294,12 +1294,12 @@ void __fastcall TScpCommanderForm::SysResizing(unsigned int Cmd)
 {
   TCustomScpExplorerForm::SysResizing(Cmd);
 
-  if ((Cmd == SC_MAXIMIZE) || (Cmd == 61490) ||
+  if ((Cmd == SC_MAXIMIZE) ||
       ((Cmd == SC_DEFAULT) && (WindowState != wsMaximized)))
   {
     FNormalPanelsWidth = LocalPanel->Width + RemotePanel->Width;
   }
-  else if ((Cmd == SC_RESTORE) || (Cmd == 61730) ||
+  else if ((Cmd == SC_RESTORE) ||
     ((Cmd == SC_DEFAULT) && (WindowState == wsMaximized)))
   {
     if (FNormalPanelsWidth >= 0)

+ 2 - 0
makefile

@@ -19,6 +19,8 @@ default: DragExt64.dll
 default: WinSCP.com
 default: lib\DiscMon_B5.lib
 
+core: lib\Putty.lib lib\FileZilla.lib lib\ScpCore.lib lib\DiscMon_B5.lib
+
 WinSCP.exe: WinSCP.bpr
 WinSCP.exe: lib\Moje_B5.lib lib\DragDrop_B5.lib lib\DriveDir_B5.lib
 WinSCP.exe: lib\tb2k_cb6.lib lib\tbx_cb6.lib lib\ThemeManagerC6.lib

+ 25 - 0
release/install.u3.bat

@@ -0,0 +1,25 @@
+@echo off
+set WINSCP_INI=%U3_APP_DATA_PATH%\winscp.ini
+set WINSCP3_INI=%U3_APP_DATA_PATH%\winscp3.ini
+
+set VER_403=%U3_APP_DATA_PATH%\ver.403
+set VER_406=%U3_APP_DATA_PATH%\ver.406
+
+echo. > "%VER_406%"
+
+if not "%U3_IS_UPGRADE%" == "true" goto NO_UPGRADE
+
+rem 403
+if not exist "%WINSCP3_INI%" goto NO_WINSCP3_INI
+
+copy "%WINSCP_INI%" + "%WINSCP3_INI%" "%WINSCP_INI%"
+del "%WINSCP3_INI%"
+
+:NO_WINSCP3_INI
+
+rem 406
+echo [Override\Configuration\Interface] >> "%WINSCP_INI%"
+echo PuttyRegistryStorageKey=Software%%5CPuTTY%%20for%%20U3-%U3_DEVICE_VENDOR_ID%-%U3_DEVICE_SERIAL% >> "%WINSCP_INI%"
+echo PuttyPath=%%25U3_HOST_EXEC_PATH%%25%%5C..%%5C..%%5CD7A496BD-33D0-448C-A2A8-6F9FF3130636%%5CExec%%5Cputty.exe >> "%WINSCP_INI%"
+
+:NO_UPGRADE

+ 5 - 7
release/readme

@@ -1,11 +1,9 @@
 To create 'winscpxxxsetup.exe' install package, follow these steps:
 1) build 'WinSCP.exe', 'Console.com' and 'DragExt.dll' (see ..\readme)
-2) install 'My Inno Setup Extensions'
-   http://www.wintax.nl/isx
-   Copyright (c) 2000-2005 Martijn Laan
-   Copyright (c) 1998-2005 Jordan Russell (Inno Setup)
-3) install 'Putty' package to directory 'c:\program files\putty\'
+2) install 'Inno Setup'
+   http://www.jrsoftware.org/isinfo.php
+3) install 'PuTTY' package to directory 'c:\program files\putty\'
    http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
-   (A Windows-style installer (x86 only) for everything except PuTTYtel)
+   (A Windows-style installer for everything except PuTTYtel)
 4) run 'iscc winscpsetup.iss'
-4) file 'winscpxxxsetup.exe' is created in directory 'release/files'
+4) file 'winscpxxxsetup.exe' is created

+ 3 - 2
release/winscp.u3i

@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <u3manifest version="1.0">
-  <application uuid="48b341d1-d411-4b5a-a82c-f3b5d65602fc" version="4.0.4">
+  <application uuid="48b341d1-d411-4b5a-a82c-f3b5d65602fc" version="4.0.6">
     <icon>winscp.ico</icon>
     <name>WinSCP</name>
     <description>Freeware SFTP (SSH File Transfer Protocol), FTP (File Transfer Protocol) and SCP (Secure CoPy) client for Windows using SSH (Secure SHell). Its main function is safe copying of files between a local and a remote computer.</description>
@@ -15,6 +15,7 @@
   <actions>
     <hostCleanUp cmd="%U3_HOST_EXEC_PATH%\U3Action.exe">-hostCleanUp</hostCleanUp>
     <appStop cmd="%U3_HOST_EXEC_PATH%\U3Action.exe">-appStop</appStop>
-    <appStart cmd="%U3_HOST_EXEC_PATH%\U3Action.exe">-appStart \"%U3_HOST_EXEC_PATH%\WinSCP3.exe\" /ini="%U3_APP_DATA_PATH%\WinSCP3.ini"</appStart>
+    <appStart cmd="%U3_HOST_EXEC_PATH%\U3Action.exe">-appStart \"%U3_HOST_EXEC_PATH%\WinSCP.exe\" /ini=\"%U3_APP_DATA_PATH%\WinSCP.ini\"</appStart>
+    <deviceInstall cmd="%U3_HOST_EXEC_PATH%\U3Action.exe">-appStart -shell \"%U3_HOST_EXEC_PATH%\install.bat\"</deviceInstall>
   </actions>
 </u3manifest>

+ 1 - 1
release/winscpsetup.iss

@@ -7,7 +7,7 @@
 #define WebForum WebRoot+"forum/"
 #define WebDocumentation WebRoot+"eng/docs/"
 #define WebPuTTY "http://www.chiark.greenend.org.uk/~sgtatham/putty/"
-#define Year 2007
+#define Year 2008
 #define EnglishLang "English"
 #define SetupTypeData "SetupType"
 #define InnoSetupReg "Software\Microsoft\Windows\CurrentVersion\Uninstall\" + AppId + "_is1"

+ 1 - 1
resource/TextsWin1.rc

@@ -347,7 +347,7 @@ BEGIN
         FSINFO_SESSION_PROTOCOL, "Session protocol"
 
         WIN_VARIABLE_STRINGS, "WIN_VARIABLE"
-        WINSCP_COPYRIGHT, "Copyright © 2000-2007 Martin Prikryl"
+        WINSCP_COPYRIGHT, "Copyright © 2000-2008 Martin Prikryl"
         HOMEPAGE_URL, "http://winscp.net/"
         HISTORY_URL, "http://winscp.net/eng/docs/history"
         REQUIREMENTS_URL, "http://winscp.net/eng/docs/requirements"

+ 2 - 1
windows/TerminalManager.cpp

@@ -570,7 +570,8 @@ void __fastcall TTerminalManager::SaveTerminal(TTerminal * Terminal)
 
       if (Changed)
       {
-        StoredSessions->Save();
+        // modified only, implicit
+        StoredSessions->Save(false, false);
       }
     }
   }

+ 4 - 1
windows/Tools.cpp

@@ -134,7 +134,10 @@ AnsiString __fastcall StoreForm(TCustomForm * Form)
   assert(Form);
   return FORMAT("%d;%d;%d;%d;%d", ((int)Form->BoundsRect.Left, (int)Form->BoundsRect.Top,
     (int)Form->BoundsRect.Right, (int)Form->BoundsRect.Bottom,
-    (int)Form->WindowState));
+    // we do not want WinSCP to start minimized next time (we cannot handle that anyway).
+    // note that WindowState is wsNormal when window in minimized for some reason.
+    // actually it is wsMinimized only when minimized by MSVDM
+    (int)(Form->WindowState == wsMinimized ? wsNormal : Form->WindowState)));
 }
 //---------------------------------------------------------------------------
 bool __fastcall ExecuteShellAndWait(const AnsiString Path, const AnsiString Params)

+ 28 - 1
windows/VCLCommon.cpp

@@ -328,8 +328,19 @@ struct TShowAsModalStorage
 {
   void * FocusWindowList;
   void * FocusActiveWindow;
+  TFocusState FocusState;
 };
 //---------------------------------------------------------------------------
+static TCustomForm ** __fastcall FocusedForm()
+{
+  return reinterpret_cast<TCustomForm **>(reinterpret_cast<char *>(Screen) + 0x78);
+}
+//---------------------------------------------------------------------------
+static TList * __fastcall SaveFocusedList()
+{
+  return *reinterpret_cast<TList **>(reinterpret_cast<char *>(Screen) + 0x7C);
+}
+//---------------------------------------------------------------------------
 void __fastcall ShowAsModal(TForm * Form, void *& Storage)
 {
   SetCorrectFormParent(Form);
@@ -341,7 +352,9 @@ void __fastcall ShowAsModal(TForm * Form, void *& Storage)
   TShowAsModalStorage * AStorage = new TShowAsModalStorage;
 
   AStorage->FocusActiveWindow = GetActiveWindow();
-
+  AStorage->FocusState = SaveFocusState();
+  SaveFocusedList()->Insert(0, *FocusedForm());
+  *FocusedForm() = Form;
   AStorage->FocusWindowList = DisableTaskWindows(0);
   Form->Show();
   SendMessage(Form->Handle, CM_ACTIVATE, 0, 0);
@@ -364,11 +377,25 @@ void __fastcall HideAsModal(TForm * Form, void *& Storage)
 
   EnableTaskWindows(AStorage->FocusWindowList);
 
+  TList * ASaveFocusedList = SaveFocusedList();
+  TCustomForm ** AFocusedForm = FocusedForm();
+  if (ASaveFocusedList->Count > 0)
+  {
+    *AFocusedForm = static_cast<TCustomForm *>(ASaveFocusedList->First());
+    ASaveFocusedList->Remove(*AFocusedForm);
+  }
+  else
+  {
+    *AFocusedForm = NULL;
+  }
+
   if (AStorage->FocusActiveWindow != 0)
   {
     SetActiveWindow(AStorage->FocusActiveWindow);
   }
 
+  RestoreFocusState(AStorage->FocusState);
+
   (static_cast<TPublicForm*>(Form))->FFormState >> fsModal;
 
   delete AStorage;

+ 7 - 2
windows/WinConfiguration.cpp

@@ -956,17 +956,22 @@ bool __fastcall TWinConfiguration::GetDDExtInstalled()
   {
     if (IsWin64())
     {
-      // temporarily consider dragext always present of 64-bit system
+      // temporarily consider dragext always present on 64-bit system
       FDDExtInstalled = 1;
     }
     else
     {
-      void* DragExtRef;
+      void * DragExtRef;
       bool Result;
       Result = (CoCreateInstance(CLSID_ShellExtension, NULL,
         CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IUnknown,
         &DragExtRef) == S_OK);
       FDDExtInstalled = (Result ? 1 : 0);
+      if (Result)
+      {
+        reinterpret_cast<IUnknown *>(DragExtRef)->Release();
+        CoFreeUnusedLibraries();
+      }
     }
   }
   return (FDDExtInstalled > 0);

+ 1 - 1
windows/WinInterface.cpp

@@ -1035,7 +1035,7 @@ void __fastcall TTrayIcon::WndProc(TMessage & Message)
     }
     else
     {
-      DefWindowProc(FTrayIcon->hWnd, Message.Msg, Message.WParam, Message.LParam);
+      Message.Result = DefWindowProc(FTrayIcon->hWnd, Message.Msg, Message.WParam, Message.LParam);
     }
   }
   catch(Exception & E)