Martin Prikryl 17 years ago
parent
commit
3abc2ba368
64 changed files with 923 additions and 688 deletions
  1. 4 4
      Console.rc
  2. 4 4
      DragExt.rc
  3. 4 4
      DragExt64.rc
  4. 5 5
      WinSCP.rc
  5. 21 12
      components/LogMemo.cpp
  6. 2 1
      components/LogMemo.h
  7. 3 1
      components/UnixDriveView.cpp
  8. 11 0
      console/Main.cpp
  9. 0 2
      core/Bookmarks.cpp
  10. 5 5
      core/Configuration.cpp
  11. 34 1
      core/CopyParam.cpp
  12. 3 0
      core/CopyParam.h
  13. 19 21
      core/FtpFileSystem.cpp
  14. 1 2
      core/FtpFileSystem.h
  15. 46 38
      core/HierarchicalStorage.cpp
  16. 6 8
      core/HierarchicalStorage.h
  17. 24 5
      core/ScpFileSystem.cpp
  18. 1 0
      core/ScpFileSystem.h
  19. 25 7
      core/Script.cpp
  20. 1 0
      core/Script.h
  21. 148 234
      core/SessionData.cpp
  22. 6 12
      core/SessionData.h
  23. 1 1
      core/SftpFileSystem.cpp
  24. 15 2
      core/Terminal.cpp
  25. 14 0
      filezilla/FtpControlSocket.cpp
  26. 1 0
      forms/CopyParamPreset.cpp
  27. 1 0
      forms/CustomCommand.cpp
  28. 43 8
      forms/CustomScpExplorer.cpp
  29. 2 0
      forms/CustomScpExplorer.h
  30. 121 73
      forms/Editor.cpp
  31. 1 0
      forms/EditorPreferences.cpp
  32. 9 0
      forms/LogSettings.cpp
  33. 1 0
      forms/LogSettings.dfm
  34. 2 0
      forms/LogSettings.h
  35. 3 3
      forms/Login.cpp
  36. 7 7
      forms/Login.dfm
  37. 22 33
      forms/Preferences.cpp
  38. 1 0
      forms/Preferences.dfm
  39. 3 0
      forms/Preferences.h
  40. 0 12
      forms/Progress.cpp
  41. 15 49
      forms/Progress.dfm
  42. 0 4
      forms/Progress.h
  43. 5 1
      forms/ScpExplorer.cpp
  44. 2 0
      packages/filemng/DriveView.pas
  45. 5 0
      packages/my/ComboEdit.hpp
  46. 30 6
      packages/my/ComboEdit.pas
  47. 0 1
      packages/my/PasTools.hpp
  48. 1 1
      release/winscp.u3i
  49. 2 0
      resource/TextsCore.h
  50. 2 0
      resource/TextsCore1.rc
  51. 0 7
      resource/TextsWin.h
  52. 0 7
      resource/TextsWin1.rc
  53. 58 24
      windows/ConsoleRunner.cpp
  54. 2 2
      windows/CustomWinConfiguration.cpp
  55. 5 5
      windows/GUIConfiguration.cpp
  56. 2 2
      windows/GUITools.cpp
  57. 128 17
      windows/Tools.cpp
  58. 6 0
      windows/Tools.h
  59. 34 15
      windows/VCLCommon.cpp
  60. 1 0
      windows/VCLCommon.h
  61. 4 4
      windows/WinConfiguration.cpp
  62. 0 34
      windows/WinInterface.cpp
  63. 0 3
      windows/WinInterface.h
  64. 1 1
      windows/WinMain.cpp

+ 4 - 4
Console.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 2,1,1,97
-PRODUCTVERSION 2,1,1,97
+FILEVERSION 2,2,0,98
+PRODUCTVERSION 2,2,0,98
 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.1.1.97\0"
+            VALUE "FileVersion", "2.2.0.98\0"
             VALUE "InternalName", "console\0"
             VALUE "LegalCopyright", "(c) 2000-2008 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "winscp.com\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.1.6.0\0"
+            VALUE "ProductVersion", "4.1.7.0\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
     }

+ 4 - 4
DragExt.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 1,1,8,91
-PRODUCTVERSION 1,1,8,91
+FILEVERSION 1,1,8,92
+PRODUCTVERSION 1,1,8,92
 FILEOS 0x4
 FILETYPE 0x2
 {
@@ -10,13 +10,13 @@ FILETYPE 0x2
         {
             VALUE "CompanyName", "Martin Prikryl\0"
             VALUE "FileDescription", "Drag&Drop shell extension for WinSCP (32-bit)\0"
-            VALUE "FileVersion", "1.1.8.91\0"
+            VALUE "FileVersion", "1.1.8.92\0"
             VALUE "InternalName", "dragext32\0"
             VALUE "LegalCopyright", "(c) 2000-2008 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext.dll\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.1.6.0\0"
+            VALUE "ProductVersion", "4.1.7.0\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
     }

+ 4 - 4
DragExt64.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 1,1,8,91
-PRODUCTVERSION 1,1,8,91
+FILEVERSION 1,1,8,92
+PRODUCTVERSION 1,1,8,92
 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.8.91\0"
+            VALUE "FileVersion", "1.1.8.92\0"
             VALUE "InternalName", "dragext64\0"
             VALUE "LegalCopyright", "(c) 2000-2008 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext64.dll\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.1.6.0\0"
+            VALUE "ProductVersion", "4.1.7.0\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
     }

+ 5 - 5
WinSCP.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 4,1,6,412
-PRODUCTVERSION 4,1,6,412
+FILEVERSION 4,1,7,413
+PRODUCTVERSION 4,1,7,413
 FILEOS 0x4
 FILETYPE 0x1
 {
@@ -10,13 +10,13 @@ FILETYPE 0x1
         {
             VALUE "CompanyName", "Martin Prikryl\0"
             VALUE "FileDescription", "SFTP, FTP and SCP client\0"
-            VALUE "FileVersion", "4.1.6.412\0"
+            VALUE "FileVersion", "4.1.7.413\0"
             VALUE "InternalName", "winscp\0"
             VALUE "LegalCopyright", "(c) 2000-2008 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
-            VALUE "OriginalFilename", "winscp416.exe\0"
+            VALUE "OriginalFilename", "winscp417.exe\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.1.6.0\0"
+            VALUE "ProductVersion", "4.1.7.0\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
     }

+ 21 - 12
components/LogMemo.cpp

@@ -36,6 +36,7 @@ __fastcall TLogMemo::TLogMemo(TComponent* Owner)
   FWantScrollToEnd = false;
   FUpdating = false;
   FNeedsRepaint = false;
+  FLastUpdate = 0;
 
   FShowTypes = DEFAULT_LOGMEMO_SHOWTYPES;
   ReadOnly = true;
@@ -105,7 +106,17 @@ void __fastcall TLogMemo::SessionLogChange(TObject * Sender)
 #endif
   if (HandleAllocated())
   {
-    PostMessage(Handle, WM_LOG_UPDATE, 0, 0);
+    unsigned int Ticks = GetTickCount();
+    if ((FLastUpdate == 0) || (Ticks < FLastUpdate) || (Ticks - FLastUpdate > 200))
+    {
+      // forced update
+      UpdateFromLog();
+    }
+    else
+    {
+      // update later, once idle
+      PostMessage(Handle, WM_LOG_UPDATE, 0, 0);
+    }
   }
 }
 //---------------------------------------------------------------------------
@@ -177,6 +188,13 @@ void __fastcall TLogMemo::UpdateFromLog()
             }
             catch(...)
             {
+              if (Lines->Count < FIndexes->Count)
+              {
+                FIndexes->Delete(FIndexes->Count - 1);
+              }
+              assert(FIndexes->Count == Lines->Count);
+              // LastIndex is strangely reset to 0 when exception is caught
+              LastIndex = Indexes[Lines->Count-1];
             }
           }
           LastIndex++;
@@ -194,6 +212,8 @@ void __fastcall TLogMemo::UpdateFromLog()
       }
 
       assert(!Parent || FIndexes->Count == Lines->Count);
+
+      FLastUpdate = GetTickCount();
     }
     __finally
     {
@@ -336,7 +356,6 @@ void __fastcall TLogMemo::WMPaint(TWMPaint & Message)
       SelLength = 0;
       SelStart = Lines->Text.Length();
       SendMessage(Handle, EM_LINESCROLL, 0, Lines->Count);
-      //SendMessage(Handle, EM_LINESCROLL, 0, -LinesVisible+1);
     }
     HideCaret(Handle);
   }
@@ -373,16 +392,6 @@ void __fastcall TLogMemo::SetParent(TWinControl * AParent)
   if (AParent) UpdateFromLog();
 }
 //---------------------------------------------------------------------------
-void __fastcall TLogMemo::InitiateAction()
-{
-  TCustomRichEdit::InitiateAction();
-  /*if (FNeedsRepaint)
-  {
-    FNeedsRepaint = false;
-    Refresh();
-  } */
-}
-//---------------------------------------------------------------------------
 void __fastcall TLogMemo::Change()
 {
   if (Parent && Visible && !Application->Terminated)

+ 2 - 1
components/LogMemo.h

@@ -33,6 +33,8 @@ private:
   bool FUpdating;
   bool FWantScrollToEnd;
   bool FNeedsRepaint;
+  unsigned int FLastUpdate;
+
   void __fastcall CMShowingChanged(TMessage & Message);
   void CMVisibleChanged(TMessage & Message);
   void WMLogUpdate(TMessage & Message);
@@ -48,7 +50,6 @@ private:
   MESSAGE void __fastcall WMSetFocus(TWMSetFocus & Message);
 protected:
   DYNAMIC void __fastcall Change();
-  virtual void __fastcall InitiateAction();
   DYNAMIC void __fastcall KeyDown(Word & Key, TShiftState Shift);
   DYNAMIC void __fastcall MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y);
   void __fastcall ReloadFromLog();

+ 3 - 1
components/UnixDriveView.cpp

@@ -651,7 +651,7 @@ void __fastcall TCustomUnixDriveView::GetImageIndex(TTreeNode * Node)
 //---------------------------------------------------------------------------
 TTreeNode * __fastcall TCustomUnixDriveView::FindNodeToPath(AnsiString Path)
 {
-  TTreeNode * Result = NULL;
+  TTreeNode * Result;
   #ifndef DESIGN_ONLY
   if (IsUnixRootPath(Path))
   {
@@ -703,6 +703,8 @@ TTreeNode * __fastcall TCustomUnixDriveView::FindNodeToPath(AnsiString Path)
       }
     }
   }
+  #else
+  Result = NULL
   #endif
   return Result;
 }

+ 11 - 0
console/Main.cpp

@@ -233,6 +233,14 @@ void FinalizeConsole(int /*InstanceNumber*/, HANDLE RequestEvent,
 //---------------------------------------------------------------------------
 static char LastFromBeginning[sizeof(TConsoleCommStruct::TPrintEvent)] = "";
 //---------------------------------------------------------------------------
+inline void Flush()
+{
+  if ((OutputType == FILE_TYPE_DISK) || (OutputType == FILE_TYPE_PIPE))
+  {
+    fflush(stdout);
+  }
+}
+//---------------------------------------------------------------------------
 inline void Print(bool FromBeginning, const char * Message)
 {
   if ((OutputType == FILE_TYPE_DISK) || (OutputType == FILE_TYPE_PIPE))
@@ -258,6 +266,7 @@ inline void Print(bool FromBeginning, const char * Message)
       {
         printf("%s", Message);
       }
+      Flush();
     }
   }
   else
@@ -363,6 +372,7 @@ void ProcessInputEvent(TConsoleCommStruct::TInputEvent& Event)
       if (PendingCancel || !Event.Echo)
       {
         printf("\n");
+        Flush();
       }
 
       if (PendingCancel || (Read == 0))
@@ -387,6 +397,7 @@ void ProcessInputEvent(TConsoleCommStruct::TInputEvent& Event)
 //---------------------------------------------------------------------------
 void ProcessChoiceEvent(TConsoleCommStruct::TChoiceEvent& Event)
 {
+  // note that if output is redirected to file, input is still FILE_TYPE_CHAR
   if ((InputType == FILE_TYPE_DISK) || (InputType == FILE_TYPE_PIPE))
   {
     Event.Result = Event.Cancel;

+ 0 - 2
core/Bookmarks.cpp

@@ -206,7 +206,6 @@ void __fastcall TBookmarks::ModifyAll(bool Modify)
 //---------------------------------------------------------------------------
 TBookmarkList * __fastcall TBookmarks::GetBookmarks(AnsiString Index)
 {
-  Index = SimpleMungeStr(Index);
   int I = FBookmarkLists->IndexOf(Index);
   if (I >= 0)
   {
@@ -220,7 +219,6 @@ TBookmarkList * __fastcall TBookmarks::GetBookmarks(AnsiString Index)
 //---------------------------------------------------------------------------
 void __fastcall TBookmarks::SetBookmarks(AnsiString Index, TBookmarkList * value)
 {
-  Index = SimpleMungeStr(Index);
   int I = FBookmarkLists->IndexOf(Index);
   if (I >= 0)
   {

+ 5 - 5
core/Configuration.cpp

@@ -45,6 +45,10 @@ void __fastcall TConfiguration::Default()
 {
   TGuard Guard(FCriticalSection);
 
+  FDisablePasswordStoring = false;
+  FForceBanners = false;
+  FDisableAcceptingHostKeys = false;
+
   TRegistryStorage * AdminStorage;
   AdminStorage = new TRegistryStorage(RegistryStorageKey, HKEY_LOCAL_MACHINE);
   try
@@ -80,10 +84,6 @@ void __fastcall TConfiguration::Default()
   FLogWindowLines = 100;
   FLogProtocol = 0;
 
-  FDisablePasswordStoring = false;
-  FForceBanners = false;
-  FDisableAcceptingHostKeys = false;
-
   Changed();
 }
 //---------------------------------------------------------------------------
@@ -109,7 +109,7 @@ THierarchicalStorage * TConfiguration::CreateScpStorage(bool /*SessionList*/)
 #define LASTELEM(ELEM) \
   ELEM.SubString(ELEM.LastDelimiter(".>")+1, ELEM.Length() - ELEM.LastDelimiter(".>"))
 #define BLOCK(KEY, CANCREATE, BLOCK) \
-  if (Storage->OpenSubKey(KEY, CANCREATE)) try { BLOCK } __finally { Storage->CloseSubKey(); }
+  if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
 #define KEY(TYPE, VAR) KEYEX(TYPE, VAR, VAR)
 #define REGCONFIG(CANCREATE) \
   BLOCK("Interface", CANCREATE, \

+ 34 - 1
core/CopyParam.cpp

@@ -166,7 +166,7 @@ AnsiString __fastcall TCopyParamType::GetInfoStr(AnsiString Separator, int Optio
 
   if (CPSLimit > 0)
   {
-    ADD(FMTLOAD(COPY_INFO_CPS_LIMIT, (int(CPSLimit))), cpaExcludeMaskOnly);
+    ADD(FMTLOAD(COPY_INFO_CPS_LIMIT, (int(CPSLimit / 1024))), cpaExcludeMaskOnly);
   }
 
   if (SomeAttrExcluded)
@@ -552,3 +552,36 @@ bool __fastcall TCopyParamType::operator==(const TCopyParamType & rhp) const
 }
 #undef C
 //---------------------------------------------------------------------------
+unsigned long __fastcall GetSpeedLimit(const AnsiString & Text)
+{
+  unsigned long Speed;
+  if (AnsiSameText(Text, LoadStr(SPEED_UNLIMITED)))
+  {
+    Speed = 0;
+  }
+  else
+  {
+    int SSpeed;
+    if (!TryStrToInt(Text, SSpeed) ||
+        (SSpeed < 0))
+    {
+      throw Exception(FMTLOAD(SPEED_INVALID, (Text)));
+    }
+    Speed = SSpeed;
+  }
+  return Speed * 1024;
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall SetSpeedLimit(unsigned long Limit)
+{
+  AnsiString Text;
+  if (Limit == 0)
+  {
+    Text = LoadStr(SPEED_UNLIMITED);
+  }
+  else
+  {
+    Text = IntToStr(Limit / 1024);
+  }
+  return Text;
+}

+ 3 - 0
core/CopyParam.h

@@ -110,4 +110,7 @@ public:
   __property unsigned long CPSLimit = { read = FCPSLimit, write = FCPSLimit };
 };
 //---------------------------------------------------------------------------
+unsigned long __fastcall GetSpeedLimit(const AnsiString & Text);
+AnsiString __fastcall SetSpeedLimit(unsigned long Limit);
+//---------------------------------------------------------------------------
 #endif

+ 19 - 21
core/FtpFileSystem.cpp

@@ -733,19 +733,6 @@ void __fastcall TFTPFileSystem::ResetFileTransfer()
   FFileTransferResumed = 0;
 }
 //---------------------------------------------------------------------------
-void __fastcall TFTPFileSystem::CheckFileTransferAbort()
-{
-  switch (FFileTransferAbort)
-  {
-    case ftaSkip:
-      THROW_SKIP_FILE_NULL;
-
-    case ftaCancel:
-      Abort();
-      break;
-  }
-}
-//---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::ReadDirectoryProgress(__int64 Bytes)
 {
   // with FTP we do not know exactly how many entries we have received,
@@ -766,7 +753,7 @@ void __fastcall TFTPFileSystem::ReadDirectoryProgress(__int64 Bytes)
 }
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::FileTransferProgress(__int64 TransferSize,
-  __int64 Bytes, int /*Percent*/)
+  __int64 Bytes)
 {
   TFileOperationProgressType * OperationProgress = FTerminal->OperationProgress;
 
@@ -805,6 +792,22 @@ void __fastcall TFTPFileSystem::FileTransfer(const AnsiString & FileName,
     unsigned int Reply = WaitForReply();
     GotReply(Reply, FLAGMASK(FFileTransferCancelled, REPLY_ALLOW_CANCEL));
   );
+
+  switch (FFileTransferAbort)
+  {
+    case ftaSkip:
+      THROW_SKIP_FILE_NULL;
+
+    case ftaCancel:
+      Abort();
+      break;
+  }
+
+  if (!FFileTransferCancelled)
+  {
+    // show completion of transfer
+    FileTransferProgress(OperationProgress->TransferSize, OperationProgress->TransferSize);
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::CopyToLocal(TStrings * FilesToCopy,
@@ -1002,8 +1005,6 @@ void __fastcall TFTPFileSystem::Sink(const AnsiString FileName,
       FIgnoreFileList = false;
     }
 
-    CheckFileTransferAbort();
-
     // in case dest filename is changed from overwrite dialog
     if (DestFileName != UserData.FileName)
     {
@@ -1226,8 +1227,6 @@ void __fastcall TFTPFileSystem::Source(const AnsiString FileName,
     {
       FIgnoreFileList = false;
     }
-
-    CheckFileTransferAbort();
   }
 
   /* TODO : Delete also read-only files. */
@@ -2601,7 +2600,7 @@ bool __fastcall TFTPFileSystem::HandleListData(const char * Path,
 }
 //---------------------------------------------------------------------------
 bool __fastcall TFTPFileSystem::HandleTransferStatus(bool Valid, __int64 TransferSize,
-  __int64 Bytes, int Percent, int /*TimeElapsed*/, int /*TimeLeft*/, int /*TransferRate*/,
+  __int64 Bytes, int /*Percent*/, int /*TimeElapsed*/, int /*TimeLeft*/, int /*TransferRate*/,
   bool FileTransfer)
 {
   if (!FActive)
@@ -2613,11 +2612,10 @@ bool __fastcall TFTPFileSystem::HandleTransferStatus(bool Valid, __int64 Transfe
   }
   else if (FileTransfer)
   {
-    FileTransferProgress(TransferSize, Bytes, Percent);
+    FileTransferProgress(TransferSize, Bytes);
   }
   else
   {
-    assert(Percent == -1);
     ReadDirectoryProgress(Bytes);
   }
   return true;

+ 1 - 2
core/FtpFileSystem.h

@@ -145,10 +145,9 @@ protected:
   bool __fastcall ConfirmOverwrite(AnsiString & FileName,
     TOverwriteMode & OverwriteMode, TFileOperationProgressType * OperationProgress,
     const TOverwriteFileParams * FileParams, int Params, bool AutoResume);
-  void __fastcall CheckFileTransferAbort();
   void __fastcall ReadDirectoryProgress(__int64 Bytes);
   void __fastcall ResetFileTransfer();
-  void __fastcall FileTransferProgress(__int64 TransferSize, __int64 Bytes, int Percent);
+  void __fastcall FileTransferProgress(__int64 TransferSize, __int64 Bytes);
   void __fastcall ResetCaches();
   void __fastcall CaptureOutput(const AnsiString & Str);
   void __fastcall DoReadDirectory(TRemoteFileList * FileList);

+ 46 - 38
core/HierarchicalStorage.cpp

@@ -36,17 +36,9 @@ AnsiString __fastcall UnMungeStr(const AnsiString Str)
   return Result;
 }
 //---------------------------------------------------------------------------
-AnsiString __fastcall SimpleMungeStr(const AnsiString Str)
+AnsiString __fastcall PuttyMungeStr(const AnsiString Str)
 {
-  AnsiString Result = Str;
-  for (int i = 1; i < Result.Length(); i++)
-  {
-    if ((Result[i] == '\\') || (Result[i] == '[') || (Result[i] == ']'))
-    {
-      Result[i] = '_';
-    }
-  }
-  return Result;
+  return MungeStr(Str);
 }
 //===========================================================================
 __fastcall THierarchicalStorage::THierarchicalStorage(const AnsiString AStorage)
@@ -67,26 +59,47 @@ void __fastcall THierarchicalStorage::SetAccessMode(TStorageAccessMode value)
   FAccessMode = value;
 }
 //---------------------------------------------------------------------------
-AnsiString __fastcall THierarchicalStorage::GetCurrentSubKey()
+AnsiString __fastcall THierarchicalStorage::GetCurrentSubKeyMunged()
 {
   if (FKeyHistory->Count) return FKeyHistory->Strings[FKeyHistory->Count-1];
     else return "";
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall THierarchicalStorage::GetCurrentSubKey()
+{
+  return UnMungeStr(GetCurrentSubKeyMunged());
+}
+//---------------------------------------------------------------------------
 bool __fastcall THierarchicalStorage::OpenRootKey(bool CanCreate)
 {
   return OpenSubKey("", CanCreate);
 }
 //---------------------------------------------------------------------------
-bool __fastcall THierarchicalStorage::OpenSubKey(const AnsiString SubKey, bool )
+AnsiString __fastcall THierarchicalStorage::MungeSubKey(AnsiString Key, bool Path)
 {
-  FKeyHistory->Add(IncludeTrailingBackslash(CurrentSubKey+SubKey));
-  return true;
+  AnsiString Result;
+  if (Path)
+  {
+    assert(Key.IsEmpty() || (Key[Key.Length()] != '\\'));
+    while (!Key.IsEmpty())
+    {
+      if (!Result.IsEmpty())
+      {
+        Result += '\\';
+      }
+      Result += MungeStr(CutToChar(Key, '\\', false));
+    }
+  }
+  else
+  {
+    Result = MungeStr(Key);
+  }
+  return Result;
 }
 //---------------------------------------------------------------------------
-bool __fastcall THierarchicalStorage::CreateSubKey(const AnsiString SubKey)
+bool __fastcall THierarchicalStorage::OpenSubKey(const AnsiString SubKey, bool /*CanCreate*/, bool Path)
 {
-  FKeyHistory->Add(IncludeTrailingBackslash(CurrentSubKey+SubKey));
+  FKeyHistory->Add(IncludeTrailingBackslash(CurrentSubKey+MungeSubKey(SubKey, Path)));
   return true;
 }
 //---------------------------------------------------------------------------
@@ -292,7 +305,7 @@ bool __fastcall TRegistryStorage::Copy(TRegistryStorage * Storage)
     int Index = 0;
     while ((Index < Names->Count) && Result)
     {
-      AnsiString Name = Names->Strings[Index];
+      AnsiString Name = MungeStr(Names->Strings[Index]);
       unsigned long Size = Buffer.size();
       unsigned long Type;
       int RegResult;
@@ -342,22 +355,13 @@ void __fastcall TRegistryStorage::SetAccessMode(TStorageAccessMode value)
   }
 }
 //---------------------------------------------------------------------------
-bool __fastcall TRegistryStorage::OpenSubKey(const AnsiString SubKey, bool CanCreate)
+bool __fastcall TRegistryStorage::OpenSubKey(const AnsiString SubKey, bool CanCreate, bool Path)
 {
   bool Result;
   if (FKeyHistory->Count > 0) FRegistry->CloseKey();
   Result = FRegistry->OpenKey(
-    ExcludeTrailingBackslash(Storage + CurrentSubKey + SubKey), CanCreate);
-  if (Result) Result = THierarchicalStorage::OpenSubKey(SubKey, CanCreate);
-  return Result;
-}
-//---------------------------------------------------------------------------
-bool __fastcall TRegistryStorage::CreateSubKey(const AnsiString SubKey)
-{
-  bool Result;
-  if (FKeyHistory->Count) FRegistry->CloseKey();
-  Result = FRegistry->CreateKey(ExcludeTrailingBackslash(Storage + CurrentSubKey + SubKey));
-  if (Result) Result = THierarchicalStorage::CreateSubKey(CurrentSubKey + SubKey);
+    ExcludeTrailingBackslash(Storage + CurrentSubKey + MungeSubKey(SubKey, Path)), CanCreate);
+  if (Result) Result = THierarchicalStorage::OpenSubKey(SubKey, CanCreate, Path);
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -375,13 +379,17 @@ bool __fastcall TRegistryStorage::DeleteSubKey(const AnsiString SubKey)
 {
   AnsiString K;
   if (FKeyHistory->Count == 0) K = Storage + CurrentSubKey;
-  K += SubKey;
+  K += MungeStr(SubKey);
   return FRegistry->DeleteKey(K);
 }
 //---------------------------------------------------------------------------
 void __fastcall TRegistryStorage::GetSubKeyNames(Classes::TStrings* Strings)
 {
   FRegistry->GetKeyNames(Strings);
+  for (int Index = 0; Index < Strings->Count; Index++)
+  {
+    Strings->Strings[Index] = UnMungeStr(Strings->Strings[Index]);
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TRegistryStorage::GetValueNames(Classes::TStrings* Strings)
@@ -396,7 +404,7 @@ bool __fastcall TRegistryStorage::DeleteValue(const AnsiString Name)
 //---------------------------------------------------------------------------
 bool __fastcall TRegistryStorage::KeyExists(const AnsiString SubKey)
 {
-  return FRegistry->KeyExists(SubKey);
+  return FRegistry->KeyExists(MungeStr(SubKey));
 }
 //---------------------------------------------------------------------------
 bool __fastcall TRegistryStorage::ValueExists(const AnsiString Value)
@@ -602,10 +610,10 @@ __fastcall TIniFileStorage::~TIniFileStorage()
 //---------------------------------------------------------------------------
 AnsiString __fastcall TIniFileStorage::GetCurrentSection()
 {
-  return ExcludeTrailingBackslash(CurrentSubKey);
+  return ExcludeTrailingBackslash(GetCurrentSubKeyMunged());
 }
 //---------------------------------------------------------------------------
-bool __fastcall TIniFileStorage::OpenSubKey(const AnsiString SubKey, bool CanCreate)
+bool __fastcall TIniFileStorage::OpenSubKey(const AnsiString SubKey, bool CanCreate, bool Path)
 {
   bool Result = CanCreate;
 
@@ -616,7 +624,7 @@ bool __fastcall TIniFileStorage::OpenSubKey(const AnsiString SubKey, bool CanCre
     {
       Sections->Sorted = true;
       FIniFile->ReadSections(Sections);
-      AnsiString NewKey = ExcludeTrailingBackslash(CurrentSubKey+SubKey);
+      AnsiString NewKey = ExcludeTrailingBackslash(CurrentSubKey+MungeSubKey(SubKey, Path));
       int Index = -1;
       if (Sections->Count)
       {
@@ -636,7 +644,7 @@ bool __fastcall TIniFileStorage::OpenSubKey(const AnsiString SubKey, bool CanCre
 
   if (Result)
   {
-    Result = THierarchicalStorage::OpenSubKey(SubKey, CanCreate);
+    Result = THierarchicalStorage::OpenSubKey(SubKey, CanCreate, Path);
   }
   return Result;
 }
@@ -646,7 +654,7 @@ bool __fastcall TIniFileStorage::DeleteSubKey(const AnsiString SubKey)
   bool Result;
   try
   {
-    FIniFile->EraseSection(CurrentSubKey + SubKey);
+    FIniFile->EraseSection(CurrentSubKey + MungeStr(SubKey));
     Result = true;
   }
   catch (...)
@@ -678,7 +686,7 @@ void __fastcall TIniFileStorage::GetSubKeyNames(Classes::TStrings* Strings)
         }
         if (Strings->IndexOf(SubSection) < 0)
         {
-          Strings->Add(SubSection);
+          Strings->Add(UnMungeStr(SubSection));
         }
       }
     }
@@ -696,7 +704,7 @@ void __fastcall TIniFileStorage::GetValueNames(Classes::TStrings* Strings)
 //---------------------------------------------------------------------------
 bool __fastcall TIniFileStorage::KeyExists(const AnsiString SubKey)
 {
-  return FIniFile->SectionExists(CurrentSubKey + SubKey);
+  return FIniFile->SectionExists(CurrentSubKey + MungeStr(SubKey));
 }
 //---------------------------------------------------------------------------
 bool __fastcall TIniFileStorage::ValueExists(const AnsiString Value)

+ 6 - 8
core/HierarchicalStorage.h

@@ -13,8 +13,7 @@ public:
   __fastcall THierarchicalStorage(const AnsiString AStorage);
   virtual __fastcall ~THierarchicalStorage();
   bool __fastcall OpenRootKey(bool CanCreate);
-  virtual bool __fastcall OpenSubKey(const AnsiString SubKey, bool CanCreate);
-  virtual bool __fastcall CreateSubKey(const AnsiString SubKey);
+  virtual bool __fastcall OpenSubKey(const AnsiString SubKey, bool CanCreate, bool Path = false);
   virtual void __fastcall CloseSubKey();
   virtual bool __fastcall DeleteSubKey(const AnsiString SubKey) = 0;
   virtual void __fastcall GetSubKeyNames(Classes::TStrings* Strings) = 0;
@@ -65,9 +64,11 @@ protected:
   bool FExplicit;
 
   AnsiString __fastcall GetCurrentSubKey();
+  AnsiString __fastcall GetCurrentSubKeyMunged();
   virtual void __fastcall SetAccessMode(TStorageAccessMode value);
   static AnsiString __fastcall IncludeTrailingBackslash(const AnsiString & S);
   static AnsiString __fastcall ExcludeTrailingBackslash(const AnsiString & S);
+  AnsiString __fastcall MungeSubKey(AnsiString Key, bool Path);
 };
 //---------------------------------------------------------------------------
 class TRegistryStorage : public THierarchicalStorage
@@ -79,8 +80,7 @@ public:
 
   bool __fastcall Copy(TRegistryStorage * Storage);
 
-  virtual bool __fastcall OpenSubKey(const AnsiString SubKey, bool CanCreate);
-  virtual bool __fastcall CreateSubKey(const AnsiString SubKey);
+  virtual bool __fastcall OpenSubKey(const AnsiString SubKey, bool CanCreate, bool Path = false);
   virtual void __fastcall CloseSubKey();
   virtual bool __fastcall DeleteSubKey(const AnsiString SubKey);
   virtual bool __fastcall DeleteValue(const AnsiString Name);
@@ -127,7 +127,7 @@ public:
   __fastcall TIniFileStorage(const AnsiString FileName);
   virtual __fastcall ~TIniFileStorage();
 
-  virtual bool __fastcall OpenSubKey(const AnsiString SubKey, bool CanCreate);
+  virtual bool __fastcall OpenSubKey(const AnsiString SubKey, bool CanCreate, bool Path = false);
   virtual bool __fastcall DeleteSubKey(const AnsiString SubKey);
   virtual bool __fastcall DeleteValue(const AnsiString Name);
   virtual void __fastcall GetSubKeyNames(Classes::TStrings* Strings);
@@ -163,8 +163,6 @@ protected:
   __property AnsiString CurrentSection  = { read=GetCurrentSection };
 };
 //---------------------------------------------------------------------------
-AnsiString __fastcall MungeStr(const AnsiString Str);
-AnsiString __fastcall UnMungeStr(const AnsiString Str);
-AnsiString __fastcall SimpleMungeStr(const AnsiString Str);
+AnsiString __fastcall PuttyMungeStr(const AnsiString Str);
 //---------------------------------------------------------------------------
 #endif

+ 24 - 5
core/ScpFileSystem.cpp

@@ -86,6 +86,7 @@ public:
   AnsiString __fastcall Command(TFSCommand Cmd, const TVarRec * args, int size);
   TStrings * __fastcall CreateCommandList();
   AnsiString __fastcall FullCommand(TFSCommand Cmd, const TVarRec * args, int size);
+  static AnsiString __fastcall ExtractCommand(AnsiString Command);
   __property int MaxLines[TFSCommand Cmd]  = { read=GetMaxLines};
   __property int MinLines[TFSCommand Cmd]  = { read=GetMinLines };
   __property bool ModifiesFiles[TFSCommand Cmd]  = { read=GetModifiesFiles };
@@ -251,6 +252,16 @@ AnsiString __fastcall TCommandSet::GetReturnVar()
     else return AnsiString('$') + SessionData->ReturnVar;
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall TCommandSet::ExtractCommand(AnsiString Command)
+{
+  int P = Command.Pos(" ");
+  if (P > 0)
+  {
+    Command.SetLength(P-1);
+  }
+  return Command;
+}
+//---------------------------------------------------------------------------
 TStrings * __fastcall TCommandSet::CreateCommandList()
 {
   TStrings * CommandList = new TStringList();
@@ -259,8 +270,7 @@ TStrings * __fastcall TCommandSet::CreateCommandList()
     AnsiString Cmd = Commands[(TFSCommand)Index];
     if (!Cmd.IsEmpty())
     {
-      Integer P = Cmd.Pos(" ");
-      if (P) Cmd.SetLength(P-1);
+      Cmd = ExtractCommand(Cmd);
       if ((Cmd != "%s") && (CommandList->IndexOf(Cmd) < 0))
         CommandList->Add(Cmd);
     }
@@ -774,19 +784,28 @@ void __fastcall TSCPFileSystem::DetectReturnVar()
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TSCPFileSystem::ClearAlias(AnsiString Alias)
+{
+  if (!Alias.IsEmpty())
+  {
+    // this command usually fails, because there will never be
+    // aliases on all commands -> see last False parametr
+    ExecCommand(fsUnalias, ARRAYOFCONST((Alias)), false);
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::ClearAliases()
 {
   try
   {
     FTerminal->LogEvent("Clearing all aliases.");
+    ClearAlias(TCommandSet::ExtractCommand(FTerminal->SessionData->ListingCommand));
     TStrings * CommandList = FCommandSet->CreateCommandList();
     try
     {
       for (int Index = 0; Index < CommandList->Count; Index++)
       {
-        // this command usually fails, becouse there will never be
-        // aliases on all commands -> see last False parametr
-        ExecCommand(fsUnalias, ARRAYOFCONST((CommandList->Strings[Index])), false);
+        ClearAlias(CommandList->Strings[Index]);
       }
     }
     __finally

+ 1 - 0
core/ScpFileSystem.h

@@ -87,6 +87,7 @@ private:
   TCaptureOutputEvent FOnCaptureOutput;
 
   void __fastcall ClearAliases();
+  void __fastcall ClearAlias(AnsiString Alias);
   void __fastcall CustomReadFile(const AnsiString FileName,
     TRemoteFile *& File, TRemoteFile * ALinkedByFile);
   static AnsiString __fastcall DelimitStr(AnsiString Str);

+ 25 - 7
core/Script.cpp

@@ -1713,8 +1713,7 @@ void __fastcall TManagementScript::DoConnect(const AnsiString & Session,
 {
   bool DefaultsOnly;
 
-  TSessionData * Data = FStoredSessions->ParseUrl(Session, Options, DefaultsOnly,
-    puDecodeUrlChars, NULL);
+  TSessionData * Data = FStoredSessions->ParseUrl(Session, Options, DefaultsOnly);
   try
   {
     if (CheckParams)
@@ -1757,6 +1756,21 @@ void __fastcall TManagementScript::DoConnect(const AnsiString & Session,
     }
 
     FTerminal = Terminal;
+
+    if (!Data->LocalDirectory.IsEmpty())
+    {
+      try
+      {
+        DoChangeLocalDirectory(Data->LocalDirectory);
+      }
+      catch(Exception & E)
+      {
+        if (!HandleExtendedException(&E))
+        {
+          throw;
+        }
+      }
+    }
   }
   __finally
   {
@@ -1805,6 +1819,14 @@ void __fastcall TManagementScript::DoClose(TTerminal * Terminal)
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TManagementScript::DoChangeLocalDirectory(AnsiString Directory)
+{
+  if (!SetCurrentDir(Directory))
+  {
+    throw Exception(FMTLOAD(CHANGE_DIR_ERROR, (Directory)));
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TManagementScript::ExitProc(TScriptProcParams * /*Parameters*/)
 {
   FContinue = false;
@@ -1865,11 +1887,7 @@ void __fastcall TManagementScript::LCdProc(TScriptProcParams * Parameters)
 {
   assert(Parameters->ParamCount == 1);
 
-  AnsiString Directory = Parameters->Param[1];
-  if (!SetCurrentDir(Directory))
-  {
-    throw Exception(FMTLOAD(CHANGE_DIR_ERROR, (Directory)));
-  }
+  DoChangeLocalDirectory(Parameters->Param[1]);
   PrintLine(GetCurrentDir());
 }
 //---------------------------------------------------------------------------

+ 1 - 0
core/Script.h

@@ -173,6 +173,7 @@ protected:
     const AnsiString RemoteDirectory, bool & Continue, bool Collect);
   void __fastcall DoConnect(const AnsiString & Session, TOptions * Options,
     bool CheckParams);
+  void __fastcall DoChangeLocalDirectory(AnsiString Directory);
   void __fastcall DoClose(TTerminal * Terminal);
   virtual bool __fastcall HandleExtendedException(Exception * E,
     TTerminal * Terminal = NULL);

+ 148 - 234
core/SessionData.cpp

@@ -36,8 +36,6 @@ TDateTime __fastcall SecToDateTime(int Sec)
     (unsigned short)(Sec/60%60), (unsigned short)(Sec%60), 0);
 }
 //--- TSessionData ----------------------------------------------------
-AnsiString TSessionData::FInvalidChars("\\[]");
-//---------------------------------------------------------------------
 __fastcall TSessionData::TSessionData(AnsiString aName):
   TNamedObject(aName)
 {
@@ -820,166 +818,180 @@ void __fastcall TSessionData::Remove()
   }
 }
 //---------------------------------------------------------------------
-AnsiString __fastcall TSessionData::DecodeUrlChars(const AnsiString & S, bool Decode)
+bool __fastcall TSessionData::ParseUrl(AnsiString Url, TOptions * Options,
+  TStoredSessionList * StoredSessions, bool & DefaultsOnly, AnsiString * FileName,
+  bool * AProtocolDefined)
 {
-  if (Decode)
+  bool ProtocolDefined = false;
+  TFSProtocol AFSProtocol;
+  int APortNumber;
+  if (Url.SubString(1, 4).LowerCase() == "scp:")
   {
-    return ::DecodeUrlChars(S);
+    AFSProtocol = fsSCPonly;
+    APortNumber = SshPortNumber;
+    Url.Delete(1, 4);
+    ProtocolDefined = true;
   }
-  else
+  else if (Url.SubString(1, 5).LowerCase() == "sftp:")
   {
-    return S;
+    AFSProtocol = fsSFTPonly;
+    APortNumber = SshPortNumber;
+    Url.Delete(1, 5);
+    ProtocolDefined = true;
+  }
+  else if (Url.SubString(1, 4).LowerCase() == "ftp:")
+  {
+    AFSProtocol = fsFTP;
+    APortNumber = FtpPortNumber;
+    Url.Delete(1, 4);
+    ProtocolDefined = true;
   }
-}
-//---------------------------------------------------------------------
-bool __fastcall TSessionData::ParseUrl(AnsiString Url, int Params,
-  AnsiString * ConnectInfo, AnsiString * HostName, int * PortNumber,
-  AnsiString * UserName, AnsiString * Password, AnsiString * Path,
-  AnsiString * FileName)
-{
-  #define DECODE(S) DecodeUrlChars(S, FLAGSET(Params, puDecodeUrlChars))
 
-  int PSlash = Url.Pos("/");
-  if (PSlash == 0)
+  if (ProtocolDefined && (Url.SubString(1, 2) == "//"))
   {
-    PSlash = Url.Length() + 1;
+    Url.Delete(1, 2);
   }
 
-  AnsiString AConnectInfo;
-  AConnectInfo = Url.SubString(1, PSlash - 1);
+  if (AProtocolDefined != NULL)
+  {
+    *AProtocolDefined = ProtocolDefined;
+  }
 
-  int P = AConnectInfo.LastDelimiter("@");
-  bool Result = (P > 0) || ((Params & puRequireUsername) == 0);
-  if (Result)
+  if (!Url.IsEmpty())
   {
-    if ((Path != NULL) || (FileName != NULL))
+    AnsiString DecodedUrl = DecodeUrlChars(Url);
+    // lookup stored session even if protocol was defined
+    // (this allows setting for example default username for host
+    // by creating stored session named by host)
+    TSessionData * Data = NULL;
+    for (Integer Index = 0; Index < StoredSessions->Count; Index++)
     {
-      bool ExcludeLeadingSlash = (Params & puExcludeLeadingSlash) != 0;
-      int Delta = ExcludeLeadingSlash ? 1 : 0;
-      AnsiString APath = Url.SubString(PSlash + Delta,
-        Url.Length() - PSlash - Delta + 1);
-      if (ExcludeLeadingSlash || (APath != "/"))
+      AnsiString Name = StoredSessions->Sessions[Index]->Name;
+      if (AnsiSameText(Name, DecodedUrl) ||
+          AnsiSameText(Name + "/", DecodedUrl.SubString(1, Name.Length() + 1)))
       {
-        if ((APath.Length() > 0) && (APath[APath.Length()] != '/'))
-        {
-          if (FileName != NULL)
-          {
-            *FileName = DECODE(UnixExtractFileName(APath));
-          }
-          if (FLAGSET(Params, puExtractFileName))
-          {
-            APath = UnixExtractFilePath(APath);
-          }
-        }
-        if (Path != NULL)
-        {
-          *Path = DECODE(APath);
-        }
+        Data = StoredSessions->Sessions[Index];
+        break;
       }
     }
 
-    if (ConnectInfo != NULL)
-    {
-      *ConnectInfo = DECODE(AConnectInfo);
-    }
-
-    AnsiString UserInfo;
-    AnsiString HostInfo;
+    AnsiString ARemoteDirectory;
 
-    if (P > 0)
+    if (Data != NULL)
     {
-      UserInfo = AConnectInfo.SubString(1, P - 1);
-      HostInfo = AConnectInfo.SubString(P + 1, AConnectInfo.Length() - P);
-    }
-    else
-    {
-      HostInfo = AConnectInfo;
-    }
+      DefaultsOnly = false;
+      Assign(Data);
+      if (StoredSessions->IsHidden(Data))
+      {
+        Data->Remove();
+        StoredSessions->Remove(Data);
+        // only modified, implicit
+        StoredSessions->Save(false, false);
+      }
 
-    if (HostName != NULL)
-    {
-      *HostName = DECODE(CutToChar(HostInfo, ':', true));
+      int P = 1;
+      while (!AnsiSameText(DecodeUrlChars(Url.SubString(1, P)), Data->Name))
+      {
+        P++;
+        assert(P <= Url.Length());
+      }
+      ARemoteDirectory = Url.SubString(P + 1, Url.Length() - P);
     }
     else
     {
-      CutToChar(HostInfo, ':', true);
-    }
+      Assign(StoredSessions->DefaultSettings);
+      Name = "";
 
-    if (PortNumber != NULL)
-    {
-      // expanded from ?: operator, as it caused strange "access violation" errors
-      if (HostInfo.IsEmpty())
+      int PSlash = Url.Pos("/");
+      if (PSlash == 0)
       {
-        *PortNumber = -1;
+        PSlash = Url.Length() + 1;
+      }
+
+      AnsiString ConnectInfo = Url.SubString(1, PSlash - 1);
+
+      int P = ConnectInfo.LastDelimiter("@");
+
+      AnsiString UserInfo;
+      AnsiString HostInfo;
+
+      if (P > 0)
+      {
+        UserInfo = ConnectInfo.SubString(1, P - 1);
+        HostInfo = ConnectInfo.SubString(P + 1, ConnectInfo.Length() - P);
       }
       else
       {
-        *PortNumber = StrToIntDef(DECODE(HostInfo), -1);
+        HostInfo = ConnectInfo;
       }
-    }
 
-    if (UserName != NULL)
-    {
-      *UserName = DECODE(CutToChar(UserInfo, ':', false));
-    }
-    else
-    {
-      CutToChar(UserInfo, ':', false);
-    }
+      HostName = DecodeUrlChars(CutToChar(HostInfo, ':', true));
 
-    if (Password != NULL)
-    {
-      *Password = DECODE(UserInfo);
+      // expanded from ?: operator, as it caused strange "access violation" errors
+      if (!HostInfo.IsEmpty())
+      {
+        PortNumber = StrToIntDef(DecodeUrlChars(HostInfo), -1);
+      }
+      else if (ProtocolDefined)
+      {
+        PortNumber = APortNumber;
+      }
+
+      UserName = DecodeUrlChars(CutToChar(UserInfo, ':', false));
+      Password = DecodeUrlChars(UserInfo);
+
+      ARemoteDirectory = Url.SubString(PSlash, Url.Length() - PSlash + 1);
     }
-  }
-  return Result;
-  #undef DECODE
-}
-//---------------------------------------------------------------------
-bool __fastcall TSessionData::ParseUrl(AnsiString Url, int Params,
-  AnsiString * FileName)
-{
-  AnsiString AHostName = HostName;
-  int APortNumber = PortNumber;
-  AnsiString AUserName = UserName;
-  AnsiString APassword = Password;
-  AnsiString ARemoteDirectory = RemoteDirectory;
 
-  bool Result = ParseUrl(Url, Params, NULL, &AHostName, &APortNumber,
-    &AUserName, &APassword, &ARemoteDirectory, FileName);
-  if (Result)
-  {
-    HostName = AHostName;
-    if (APortNumber >= 0)
+    if (!ARemoteDirectory.IsEmpty() && (ARemoteDirectory != "/"))
     {
-      PortNumber = APortNumber;
+      if ((ARemoteDirectory[ARemoteDirectory.Length()] != '/') &&
+          (FileName != NULL))
+      {
+        *FileName = DecodeUrlChars(UnixExtractFileName(ARemoteDirectory));
+        ARemoteDirectory = UnixExtractFilePath(ARemoteDirectory);
+      }
+      RemoteDirectory = DecodeUrlChars(ARemoteDirectory);
     }
-    UserName = AUserName;
-    Password = APassword;
-    RemoteDirectory = ARemoteDirectory;
-  }
-  return Result;
-}
-//---------------------------------------------------------------------
-bool __fastcall TSessionData::ParseOptions(TOptions * Options)
-{
-  AnsiString Value;
-  if (Options->FindSwitch("privatekey", Value))
-  {
-    PublicKeyFile = Value;
+
+    DefaultsOnly = false;
   }
-  if (Options->FindSwitch("timeout", Value))
+  else
   {
-    Timeout = StrToInt(Value);
+    Assign(StoredSessions->DefaultSettings);
+
+    DefaultsOnly = true;
   }
-  if (Options->FindSwitch("hostkey", Value))
+
+  if (ProtocolDefined)
   {
-    HostKey = Value;
+    FSProtocol = AFSProtocol;
   }
-  if (Options->FindSwitch("passive", Value))
+
+  if (Options != NULL)
   {
-    FtpPasvMode = (StrToIntDef(Value, 1) != 0);
+    // we deliberatelly do keep defaultonly to false, in presence of any option,
+    // as the option should not make session "connectable"
+
+    AnsiString Value;
+    if (Options->FindSwitch("privatekey", Value))
+    {
+      PublicKeyFile = Value;
+    }
+    if (Options->FindSwitch("timeout", Value))
+    {
+      Timeout = StrToInt(Value);
+    }
+    if (Options->FindSwitch("hostkey", Value))
+    {
+      HostKey = Value;
+    }
+    if (Options->FindSwitch("passive", Value))
+    {
+      FtpPasvMode = (StrToIntDef(Value, 1) != 0);
+    }
   }
+
   return true;
 }
 //---------------------------------------------------------------------
@@ -1004,17 +1016,14 @@ void __fastcall TSessionData::RollbackTunnel()
 //---------------------------------------------------------------------
 void __fastcall TSessionData::ValidatePath(const AnsiString Path)
 {
-  if (Path.LastDelimiter(FInvalidChars) > 0)
-  {
-    throw Exception(FMTLOAD(ITEM_NAME_INVALID, (Path, FInvalidChars)));
-  }
+  // noop
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::ValidateName(const AnsiString Name)
 {
-  if (Name.LastDelimiter(FInvalidChars + "/") > 0)
+  if (Name.LastDelimiter("/") > 0)
   {
-    throw Exception(FMTLOAD(ITEM_NAME_INVALID, (Name, FInvalidChars + "/")));
+    throw Exception(FMTLOAD(ITEM_NAME_INVALID, (Name, "/")));
   }
 }
 //---------------------------------------------------------------------
@@ -1031,7 +1040,14 @@ AnsiString __fastcall TSessionData::GetSessionKey()
 AnsiString __fastcall TSessionData::GetStorageKey()
 {
   // particularly OpenSessionInPutty expect that StorageKey always returns something
-  return MungeStr(Name.IsEmpty() ? SessionKey : Name);
+  if (Name.IsEmpty())
+  {
+    return SessionKey;
+  }
+  else
+  {
+    return Name;
+  }
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::SetHostName(AnsiString value)
@@ -1878,7 +1894,7 @@ void __fastcall TStoredSessionList::Load(THierarchicalStorage * Storage,
     for (int Index = 0; Index < SubKeys->Count; Index++)
     {
       TSessionData *SessionData;
-      AnsiString SessionName = UnMungeStr(SubKeys->Strings[Index]);
+      AnsiString SessionName = SubKeys->Strings[Index];
       bool ValidName = true;
       try
       {
@@ -2145,7 +2161,7 @@ void __fastcall TStoredSessionList::ImportHostKeys(const AnsiString TargetKey,
         Session = Sessions->Sessions[Index];
         if (!OnlySelected || Session->Selected)
         {
-          HostKeyName = MungeStr(FORMAT("@%d:%s", (Session->PortNumber, Session->HostName)));
+          HostKeyName = PuttyMungeStr(FORMAT("@%d:%s", (Session->PortNumber, Session->HostName)));
           AnsiString KeyName;
           for (int KeyIndex = 0; KeyIndex < KeyList->Count; KeyIndex++)
           {
@@ -2170,115 +2186,13 @@ void __fastcall TStoredSessionList::ImportHostKeys(const AnsiString TargetKey,
 }
 //---------------------------------------------------------------------------
 TSessionData * __fastcall TStoredSessionList::ParseUrl(AnsiString Url,
-  TOptions * Options, bool & DefaultsOnly, int Params, AnsiString * FileName,
+  TOptions * Options, bool & DefaultsOnly, AnsiString * FileName,
   bool * AProtocolDefined)
 {
-  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;
-  }
-
-  if (ProtocolDefined && (Url.SubString(1, 2) == "//"))
-  {
-    Url.Delete(1, 2);
-  }
-
-  if (AProtocolDefined != NULL)
-  {
-    *AProtocolDefined = ProtocolDefined;
-  }
-
-  DefaultsOnly = true;
   TSessionData * Data = new TSessionData("");
   try
   {
-    if (!Url.IsEmpty())
-    {
-      TSessionData * AData = NULL;
-      // 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;
-      AnsiString RemoteDirectory;
-      if (TSessionData::ParseUrl(Url, Params, &ConnectInfo, NULL, NULL, NULL,
-            NULL, &RemoteDirectory, FileName))
-      {
-        AData = dynamic_cast<TSessionData *>(FindByName(ConnectInfo, false));
-      }
-
-      if (AData == NULL)
-      {
-        Data->Assign(DefaultSettings);
-        if (ProtocolDefined)
-        {
-          Data->PortNumber = PortNumber;
-        }
-        if (Data->ParseUrl(Url, Params, FileName))
-        {
-          Data->Name = "";
-          DefaultsOnly = false;
-        }
-        else
-        {
-          throw Exception(FMTLOAD(SESSION_NOT_EXISTS_ERROR, (Url)));
-        }
-      }
-      else
-      {
-        DefaultsOnly = false;
-        Data->Assign(AData);
-        if (!RemoteDirectory.IsEmpty())
-        {
-          Data->RemoteDirectory = RemoteDirectory;
-        }
-        if (IsHidden(AData))
-        {
-          AData->Remove();
-          Remove(AData);
-          // only modified, implicit
-          Save(false, false);
-        }
-      }
-    }
-    else
-    {
-      Data->Assign(DefaultSettings);
-    }
-
-    if (ProtocolDefined)
-    {
-      Data->FSProtocol = Protocol;
-    }
-
-    if (Options != NULL)
-    {
-      // we deliberatelly do set defaultonly to false, in presence of any option,
-      // as the option should not make session "connectable"
-      if (!Data->ParseOptions(Options))
-      {
-        Abort();
-      }
-    }
+    Data->ParseUrl(Url, Options, this, DefaultsOnly, FileName, AProtocolDefined);
   }
   catch(...)
   {

+ 6 - 12
core/SessionData.h

@@ -28,10 +28,6 @@ enum TSftpBug { sbSymlink, sbSignedTS };
 enum TAutoSwitch { asOn, asOff, asAuto };
 enum TPingType { ptOff, ptNullPacket, ptDummyCommand };
 enum TAddressFamily { afAuto, afIPv4, afIPv6 };
-const puRequireUsername =     0x01;
-const puExcludeLeadingSlash = 0x02;
-const puExtractFileName =     0x04;
-const puDecodeUrlChars =      0x08;
 //---------------------------------------------------------------------------
 extern const char CipherNames[CIPHER_COUNT][10];
 extern const char KexNames[KEX_COUNT][20];
@@ -41,10 +37,11 @@ extern const TCipher DefaultCipherList[CIPHER_COUNT];
 extern const TKex DefaultKexList[KEX_COUNT];
 extern const char FSProtocolNames[FSPROTOCOL_COUNT][11];
 //---------------------------------------------------------------------------
+class TStoredSessionList;
+//---------------------------------------------------------------------------
 class TSessionData : public TNamedObject
 {
 private:
-  static AnsiString FInvalidChars;
   AnsiString FHostName;
   int FPortNumber;
   AnsiString FUserName;
@@ -269,7 +266,6 @@ private:
   void __fastcall SetUtf(TAutoSwitch value);
   void __fastcall SetHostKey(AnsiString value);
   TDateTime __fastcall GetTimeoutDT();
-  static AnsiString __fastcall DecodeUrlChars(const AnsiString & S, bool Decode);
 
 public:
   __fastcall TSessionData(AnsiString aName);
@@ -280,14 +276,12 @@ public:
     const TSessionData * Default = NULL);
   void __fastcall Remove();
   virtual void __fastcall Assign(TPersistent * Source);
-  bool __fastcall ParseUrl(AnsiString Url, int Params, AnsiString * FileName);
+  bool __fastcall ParseUrl(AnsiString Url, TOptions * Options,
+    TStoredSessionList * StoredSessions, bool & DefaultsOnly,
+    AnsiString * FileName, bool * AProtocolDefined);
   bool __fastcall ParseOptions(TOptions * Options);
   void __fastcall ConfigureTunnel(int PortNumber);
   void __fastcall RollbackTunnel();
-  static bool __fastcall ParseUrl(AnsiString Url, int Params,
-    AnsiString * ConnectInfo, AnsiString * HostName, int * PortNumber,
-    AnsiString * UserName, AnsiString * Password, AnsiString * Path,
-    AnsiString * FileName);
   static void __fastcall ValidatePath(const AnsiString Path);
   static void __fastcall ValidateName(const AnsiString Name);
 
@@ -429,7 +423,7 @@ public:
   int __fastcall IndexOf(TSessionData * Data);
   TSessionData * __fastcall NewSession(AnsiString SessionName, TSessionData * Session);
   TSessionData * __fastcall ParseUrl(AnsiString Url, TOptions * Options, bool & DefaultsOnly,
-    int Params, AnsiString * FileName = NULL, bool * ProtocolDefined = NULL);
+    AnsiString * FileName = NULL, bool * ProtocolDefined = NULL);
   virtual __fastcall ~TStoredSessionList();
   __property TSessionData * Sessions[int Index]  = { read=AtSession };
   __property TSessionData * DefaultSettings  = { read=FDefaultSettings, write=SetDefaultSettings };

+ 1 - 1
core/SftpFileSystem.cpp

@@ -3237,7 +3237,7 @@ void __fastcall TSFTPFileSystem::CreateDirectory(const AnsiString DirName,
   // But do nothing unless there was any properties change really required
   // (saves bandwidth, and some servers does not allow SSH_FXP_SETSTAT on dirs,
   // e.g. Serv-u)
-  if (!Properties->Valid.Empty())
+  if ((Properties != NULL) && !Properties->Valid.Empty())
   {
     try
     {

+ 15 - 2
core/Terminal.cpp

@@ -1580,14 +1580,27 @@ bool __fastcall TTerminal::GetExceptionOnFail() const
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::FatalError(Exception * E, AnsiString Msg)
 {
-  if (Active)
+  bool SecureShellActive = (FSecureShell != NULL) && FSecureShell->Active;
+  if (Active || SecureShellActive)
   {
     // We log this instead of exception handler, because Close() would
     // probably cause exception handler to loose pointer to TShellLog()
     LogEvent("Attempt to close connection due to fatal exception:");
     Log->Add(llException, Msg);
     Log->AddException(E);
-    Close();
+
+    if (Active)
+    {
+      Close();
+    }
+
+    // this may happen if failure of authentication of SSH, owned by terminal yet
+    // (because the protocol was not decided yet), is detected by us (not by putty).
+    // e.g. not verified host key
+    if (SecureShellActive)
+    {
+      FSecureShell->Close();
+    }
   }
 
   if (FCallbackGuard != NULL)

+ 14 - 0
filezilla/FtpControlSocket.cpp

@@ -1080,6 +1080,20 @@ void CFtpControlSocket::OnConnect(int nErrorCode)
 	{
 		if (nErrorCode == WSAHOST_NOT_FOUND)
 			ShowStatus(IDS_ERRORMSG_CANTRESOLVEHOST, 1);
+#ifdef MPEXT
+		else
+		{
+			char Buffer[255];
+			int Len = FormatMessage(
+				FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+				NULL, nErrorCode, 0, Buffer, sizeof(Buffer), NULL);
+			while ((Len > 0) && ((Buffer[Len - 1] >= 0) && (Buffer[Len - 1] <= 32)))
+			{
+				--Len;
+			}
+			ShowStatus(CString(Buffer, Len), 1);
+		}
+#endif
 		DoClose();
 	}
 }

+ 1 - 0
forms/CopyParamPreset.cpp

@@ -36,6 +36,7 @@ __fastcall TCopyParamPresetDialog::TCopyParamPresetDialog(TComponent * Owner,
   TCopyParamPresetMode Mode, TCopyParamRuleData * CurrentRuleData)
   : TForm(Owner)
 {
+  SetCorrectFormParent(this);
   UseSystemSettings(this);
   CopyParamsFrame->Direction = pdAll;
   FMode = Mode;

+ 1 - 0
forms/CustomCommand.cpp

@@ -50,6 +50,7 @@ bool __fastcall DoCustomCommandDialog(AnsiString & Description,
 __fastcall TCustomCommandDialog::TCustomCommandDialog(TComponent* Owner, unsigned int Options)
   : TForm(Owner)
 {
+  SetCorrectFormParent(this);
   UseSystemSettings(this);
   FCustomCommands = NULL;
   FMode = ccmEdit;

+ 43 - 8
forms/CustomScpExplorer.cpp

@@ -179,6 +179,8 @@ __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
   FEditorManager->OnFileReload = ExecutedFileReload;
   FEditorManager->OnFileEarlyClosed = ExecutedFileEarlyClosed;
 
+  FLocalEditors = new TList();
+
   FQueueStatus = NULL;
   FQueueStatusSection = new TCriticalSection();
   FQueueStatusInvalidated = false;
@@ -264,6 +266,9 @@ __fastcall TCustomScpExplorerForm::~TCustomScpExplorerForm()
   FEditorManager->CloseInternalEditors(ForceCloseInternalEditor);
   delete FEditorManager;
 
+  assert(FLocalEditors->Count == 0);
+  delete FLocalEditors;
+
   if (FDelayedDeletionTimer)
   {
     DoDelayedDeletion(NULL);
@@ -626,12 +631,20 @@ void __fastcall TCustomScpExplorerForm::ConfigurationChanged()
   UpdateControls();
 
   // this can be called even before constuctor finishes.
-  // can we be sure that the FEditorManager is NULL then?
   if (FEditorManager != NULL)
   {
     FEditorManager->ProcessFiles(FileConfigurationChanged, NULL);
   }
 
+  // this can be called even before constuctor finishes.
+  if (FLocalEditors != NULL)
+  {
+    for (int Index = 0; Index < FLocalEditors->Count; Index++)
+    {
+      ReconfigureEditorForm(static_cast<TForm *>(FLocalEditors->Items[Index]));
+    }
+  }
+
   if (ComponentVisible[fcCustomCommandsBand])
   {
     UpdateCustomCommandsToolbar();
@@ -1773,7 +1786,7 @@ void __fastcall TCustomScpExplorerForm::CustomExecuteFile(TOperationSide Side,
     }
     else
     {
-      ShowEditorForm(FileName, this, NULL, NULL, NULL, "");
+      FLocalEditors->Add(ShowEditorForm(FileName, this, NULL, NULL, LocalEditorClosed, ""));
     }
   }
   else
@@ -1827,6 +1840,11 @@ void __fastcall TCustomScpExplorerForm::CustomExecuteFile(TOperationSide Side,
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::LocalEditorClosed(TObject * Sender)
+{
+  CHECK(FLocalEditors->Extract(Sender) >= 0);
+}
+//---------------------------------------------------------------------------
 AnsiString __fastcall TCustomScpExplorerForm::TemporaryDirectoryForRemoteFiles(
   TCopyParamType CopyParam, AnsiString & RootDirectory)
 {
@@ -2084,12 +2102,12 @@ void __fastcall TCustomScpExplorerForm::ExecutedFileReload(
       (ExtractFileName(FileName), Data.SessionName)));
   }
 
+  TRemoteFile * File = NULL;
   TStrings * FileList = new TStringList();
   try
   {
     AnsiString RemoteFileName =
       UnixIncludeTrailingBackslash(Data.RemoteDirectory) + Data.OriginalFileName;
-    TRemoteFile * File = NULL;
     FTerminal->ExceptionOnFail = true;
     try
     {
@@ -2115,6 +2133,7 @@ void __fastcall TCustomScpExplorerForm::ExecutedFileReload(
   }
   __finally
   {
+    delete File;
     delete FileList;
   }
 }
@@ -2934,11 +2953,27 @@ void __fastcall TCustomScpExplorerForm::FormCloseQuery(TObject * /*Sender*/,
 
   if (CanClose)
   {
-    CanClose = FEditorManager->CloseInternalEditors(CloseInternalEditor) &&
-      FEditorManager->CloseExternalFilesWithoutProcess() &&
-      (FEditorManager->Empty(true) ||
-       (MessageDialog(LoadStr(PENDING_EDITORS), qtWarning, qaIgnore | qaCancel,
-          HELP_NONE) == qaIgnore));
+    CanClose =
+      FEditorManager->CloseInternalEditors(CloseInternalEditor) &&
+      FEditorManager->CloseExternalFilesWithoutProcess();
+
+    if (CanClose)
+    {
+      while (CanClose && (FLocalEditors->Count > 0))
+      {
+        int PrevCount = FLocalEditors->Count;
+        static_cast<TForm *>(FLocalEditors->Items[0])->Close();
+        CanClose = (FLocalEditors->Count < PrevCount);
+      }
+
+      if (CanClose)
+      {
+        CanClose =
+          FEditorManager->Empty(true) ||
+          (MessageDialog(LoadStr(PENDING_EDITORS), qtWarning, qaIgnore | qaCancel,
+            HELP_NONE) == qaIgnore);
+      }
+    }
   }
 }
 //---------------------------------------------------------------------------

+ 2 - 0
forms/CustomScpExplorer.h

@@ -191,6 +191,7 @@ private:
   int FLastDropEffect;
   bool FPendingTempSpaceWarn;
   TEditorManager * FEditorManager;
+  TList * FLocalEditors;
   TStrings * FCapturedLog;
   bool FDragDropOperation;
   AnsiString FCopyParamDefault;
@@ -370,6 +371,7 @@ protected:
   void __fastcall TemporarilyDownloadFiles(TStrings * FileList, bool ForceText,
     AnsiString & RootTempDir, AnsiString & TempDir, bool AllFiles, bool GetTargetNames,
     bool AutoOperation);
+  void __fastcall LocalEditorClosed(TObject * Sender);
   TTBXPopupMenu * __fastcall HistoryMenu(TOperationSide Side, bool Back);
   AnsiString __fastcall FileStatusBarText(const TStatusFileInfo & FileInfo);
   void __fastcall UpdateFileStatusBar(TTBXStatusBar * StatusBar,

+ 121 - 73
forms/Editor.cpp

@@ -62,6 +62,7 @@ public:
   void __fastcall SetFormat(AnsiString FontName, int FontHeight,
     TFontCharset FontCharset, TFontStyles FontStyles, unsigned int TabSize,
     bool AWordWrap);
+  void __fastcall ResetFormat();
   int __fastcall FindText(const AnsiString SearchStr, int StartPos, int Length,
     TSearchTypes Options, bool Down);
   void __fastcall Redo();
@@ -70,17 +71,19 @@ public:
   __property bool CanRedo = { read = GetCanRedo };
 
 protected:
-  virtual void __fastcall CreateWnd(void);
   virtual void __fastcall CreateParams(TCreateParams & Params);
   virtual void __fastcall DestroyWnd();
+  void __fastcall Dispatch(void * Message);
   bool __fastcall GetCanRedo();
-  void __fastcall ApplyTabSize();
+  void __fastcall SetTabSize(unsigned int TabSize);
+  void __fastcall WMPaste();
 
 private:
   HINSTANCE FLibrary;
   bool FVersion20;
   bool FWordWrap;
   unsigned int FTabSize;
+  bool FInitialized;
 };
 //---------------------------------------------------------------------------
 __fastcall TRichEdit20::TRichEdit20(TComponent * AOwner) :
@@ -88,7 +91,8 @@ __fastcall TRichEdit20::TRichEdit20(TComponent * AOwner) :
   FLibrary(0),
   FVersion20(false),
   FTabSize(0),
-  FWordWrap(true)
+  FWordWrap(true),
+  FInitialized(false)
 {
 }
 //---------------------------------------------------------------------------
@@ -96,39 +100,62 @@ void __fastcall TRichEdit20::SetFormat(AnsiString FontName, int FontHeight,
   TFontCharset FontCharset, TFontStyles FontStyles, unsigned int TabSize,
   bool AWordWrap)
 {
-  bool RecalculateTabs = (Font->Name != FontName) || (Font->Height != FontHeight) ||
-    (TabSize != FTabSize);
+
+  if (!FInitialized)
+  {
+    // for efficiency we should be creating handle here
+    assert(!HandleAllocated());
+  }
+
+  // setting DefAttributes is noop if we do not have a handle
+  // (btw code below would create one anyway)
+  HandleNeeded();
 
   LockWindowUpdate(Handle);
 
-  Font->Name = FontName;
-  Font->Height = FontHeight;
-  Font->Charset = FontCharset;
-  Font->Style = FontStyles;
-  DefAttributes->Assign(Font);
-  FTabSize = TabSize;
+  // setting DefAttributes may take quite time, even if the font attributes
+  // do not change, so avoid that if not necessary
+  if (!FInitialized ||
+      (Font->Name != FontName) ||
+      (Font->Height != FontHeight) ||
+      (Font->Charset != FontCharset) ||
+      (Font->Style != FontStyles))
+  {
+    Font->Name = FontName;
+    Font->Height = FontHeight;
+    Font->Charset = FontCharset;
+    Font->Style = FontStyles;
+    DefAttributes->Assign(Font);
+  }
 
-  if (RecalculateTabs && HandleAllocated())
+  if (!FInitialized ||
+      (FTabSize != TabSize))
   {
-    ApplyTabSize();
+    SetTabSize(TabSize);
+    FTabSize = TabSize;
   }
 
-  if (FWordWrap != AWordWrap)
+  if (!FInitialized ||
+      (FWordWrap != AWordWrap))
   {
-    if (Visible)
-    {
-      // Undocumented usage of EM_SETTARGETDEVICE.
-      // But note that it is used by MFC in CRichEditView::WrapChanged()
-      SendMessage(Handle, EM_SETTARGETDEVICE, 0, (AWordWrap ? 0 : 1));
-    }
-    else
-    {
-      WordWrap = AWordWrap;
-    }
+    assert(HandleAllocated());
+    // Undocumented usage of EM_SETTARGETDEVICE.
+    // But note that it is used by MFC in CRichEditView::WrapChanged()
+    SendMessage(Handle, EM_SETTARGETDEVICE, 0, (AWordWrap ? 0 : 1));
     FWordWrap = AWordWrap;
   }
 
   LockWindowUpdate(NULL);
+
+  FInitialized = true;
+
+}
+//---------------------------------------------------------------------------
+void __fastcall TRichEdit20::ResetFormat()
+{
+  // tabs are paragraph attributes, which default values cannot be set,
+  // so we need to reapply them after loading file
+  SetTabSize(FTabSize);
 }
 //---------------------------------------------------------------------------
 int __fastcall TRichEdit20::FindText(const AnsiString SearchStr, int StartPos,
@@ -163,13 +190,6 @@ void __fastcall TRichEdit20::Redo()
   SendMessage(Handle, EM_REDO, 0, 0);
 }
 //---------------------------------------------------------------------------
-void __fastcall TRichEdit20::CreateWnd(void)
-{
-  TRichEdit::CreateWnd();
-
-  ApplyTabSize();
-}
-//---------------------------------------------------------------------------
 void __fastcall TRichEdit20::CreateParams(TCreateParams & Params)
 {
   const char RichEditModuleName[] = "RICHED20.DLL";
@@ -207,55 +227,89 @@ void __fastcall TRichEdit20::DestroyWnd()
   }
 }
 //---------------------------------------------------------------------------
-bool __fastcall TRichEdit20::GetCanRedo()
+void __fastcall TRichEdit20::WMPaste()
 {
-  return FVersion20 && (SendMessage(Handle, EM_CANREDO, 0, 0) != 0);
+  // override default pasting to prevent inserting formatted text (RTF).
+  const char * Text = NULL;
+  HANDLE Handle = OpenTextFromClipboard(Text);
+  if (Handle != NULL)
+  {
+    try
+    {
+      // replacement for EM_PASTESPECIAL,
+      // which ignores trailing line end for some rea
+      SetSelTextBuf(const_cast<char *>(Text));
+    }
+    __finally
+    {
+      CloseTextFromClipboard(Handle);
+    }
+  }
 }
 //---------------------------------------------------------------------------
-void __fastcall TRichEdit20::ApplyTabSize()
+void __fastcall TRichEdit20::Dispatch(void * Message)
 {
-  if (FTabSize > 0)
+  TMessage * M = static_cast<TMessage *>(Message);
+  switch (M->Msg)
   {
-    HDC DC = GetDC(Handle);
-    SaveDC(DC);
-    SetMapMode(DC, MM_TEXT);
-    SelectObject(DC, Font->Handle);
+    case WM_PASTE:
+      WMPaste();
+      break;
 
-    int LogPixelsX = GetDeviceCaps(DC, LOGPIXELSX);
+    default:
+      TRichEdit::Dispatch(Message);
+      break;
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TRichEdit20::GetCanRedo()
+{
+  return FVersion20 && (SendMessage(Handle, EM_CANREDO, 0, 0) != 0);
+}
+//---------------------------------------------------------------------------
+void __fastcall TRichEdit20::SetTabSize(unsigned int TabSize)
+{
+  assert(TabSize > 0);
 
-    SIZE Size;
-    GetTextExtentPoint(DC, AnsiString::StringOfChar('X', FTabSize).c_str(),
-      FTabSize, &Size);
+  HDC DC = GetDC(Handle);
+  SaveDC(DC);
+  SetMapMode(DC, MM_TEXT);
+  SelectObject(DC, Font->Handle);
 
-    RestoreDC(DC, -1);
-    ReleaseDC(Handle, DC);
+  int LogPixelsX = GetDeviceCaps(DC, LOGPIXELSX);
 
-    unsigned int TabTwips = MulDiv(Size.cx, 1440, LogPixelsX);
+  SIZE Size;
+  GetTextExtentPoint(DC, AnsiString::StringOfChar('X', TabSize).c_str(),
+    TabSize, &Size);
 
-    // save selection
-    CHARRANGE CharRange;
-    SendMessage(Handle, EM_EXGETSEL, 0, (LPARAM)&CharRange);
+  RestoreDC(DC, -1);
+  ReleaseDC(Handle, DC);
 
-    CHARRANGE CharRangeAll;
-    CharRangeAll.cpMin = 0;
-    CharRangeAll.cpMax = -1;
-    SendMessage(Handle, EM_EXSETSEL, 0, (LPARAM)&CharRangeAll);
+  unsigned int TabTwips = MulDiv(Size.cx, 1440, LogPixelsX);
 
-    PARAFORMAT2 ParaFormat;
-    ParaFormat.cbSize = sizeof(ParaFormat);
-    ParaFormat.dwMask = PFM_TABSTOPS;
-    ParaFormat.cTabCount = MAX_TAB_STOPS;
+  // save selection
+  CHARRANGE CharRange;
+  SendMessage(Handle, EM_EXGETSEL, 0, (LPARAM)&CharRange);
 
-    for (int i = 0; i < ParaFormat.cTabCount; i++)
-    {
-      ParaFormat.rgxTabs[i] = (i + 1) * TabTwips;
-    }
+  CHARRANGE CharRangeAll;
+  CharRangeAll.cpMin = 0;
+  CharRangeAll.cpMax = -1;
+  SendMessage(Handle, EM_EXSETSEL, 0, (LPARAM)&CharRangeAll);
 
-    SendMessage(Handle, EM_SETPARAFORMAT, 0, (LPARAM)&ParaFormat);
+  PARAFORMAT2 ParaFormat;
+  ParaFormat.cbSize = sizeof(ParaFormat);
+  ParaFormat.dwMask = PFM_TABSTOPS;
+  ParaFormat.cTabCount = MAX_TAB_STOPS;
 
-    // restore selection
-    SendMessage(Handle, EM_EXSETSEL, 0, (LPARAM)&CharRange);
+  for (int i = 0; i < ParaFormat.cTabCount; i++)
+  {
+    ParaFormat.rgxTabs[i] = (i + 1) * TabTwips;
   }
+
+  SendMessage(Handle, EM_SETPARAFORMAT, 0, (LPARAM)&ParaFormat);
+
+  // restore selection
+  SendMessage(Handle, EM_EXSETSEL, 0, (LPARAM)&CharRange);
 }
 //---------------------------------------------------------------------------
 class TFindDialogEx : public TFindDialog
@@ -455,14 +509,6 @@ void __fastcall TEditorForm::EditorActionsExecute(TBasicAction *Action,
   {
     EditorMemo->Redo();
   }
-  else if (Action == EditPaste)
-  {
-    // original source: http://home.att.net/~robertdunn/FAQs/Faqs.html
-    // tell the Rich Edit control to insert unformatted text (CF_TEXT)
-    REPASTESPECIAL RepasteSpecial = { 0, 0 };
-    SendMessage(EditorMemo->Handle, EM_PASTESPECIAL, CF_TEXT,
-      (LPARAM)&RepasteSpecial);
-  }
   else if (Action == HelpAction)
   {
     FormHelp(this);
@@ -657,9 +703,11 @@ void __fastcall TEditorForm::FormShow(TObject * /*Sender*/)
 void __fastcall TEditorForm::LoadFile()
 {
   EditorMemo->Lines->LoadFromFile(FFileName);
+  EditorMemo->ResetFormat();
   EditorMemo->Modified = false;
   FCaretPos.x = -1;
-  ApplyConfiguration();
+  // this is important particularly after reload
+  UpdateControls();
 }
 //---------------------------------------------------------------------------
 bool __fastcall TEditorForm::CursorInUpperPart()

+ 1 - 0
forms/EditorPreferences.cpp

@@ -39,6 +39,7 @@ __fastcall TEditorPreferencesDialog::TEditorPreferencesDialog(
   TComponent * Owner) :
   TForm(Owner)
 {
+  SetCorrectFormParent(this);
   UseSystemSettings(this);
 
   InstallPathWordBreakProc(ExternalEditorEdit);

+ 9 - 0
forms/LogSettings.cpp

@@ -10,6 +10,7 @@
 #include <TextsWin.h>
 
 #include <VCLCommon.h>
+#include <Tools.h>
 #include "CustomWinConfiguration.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
@@ -157,3 +158,11 @@ void __fastcall TLoggingFrame::LogFileNameEditAfterDialog(TObject * /*Sender*/,
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TLoggingFrame::LogFileNameEditCreateEditDialog(
+  TObject * Sender, TFileDialogKind DialogKind, TOpenDialog *& Dialog)
+{
+  USEDPARAM(DialogKind);
+  assert(DialogKind == dkOpen);
+  Dialog = CreateOpenDialog(dynamic_cast<TComponent *>(Sender));
+}
+//---------------------------------------------------------------------------

+ 1 - 0
forms/LogSettings.dfm

@@ -63,6 +63,7 @@ object LoggingFrame: TLoggingFrame
       Filter = 'Log files (*.log)|*.log|All files (*.*)|*.*'
       DialogOptions = [ofHideReadOnly, ofPathMustExist]
       DialogTitle = 'Select file for session log.'
+      OnCreateEditDialog = LogFileNameEditCreateEditDialog
       ClickKey = 16397
       Anchors = [akLeft, akTop, akRight]
       TabOrder = 2

+ 2 - 0
forms/LogSettings.h

@@ -37,6 +37,8 @@ __published:
           AnsiString &Name, bool &Action);
   void __fastcall LogFileNameEditAfterDialog(TObject *Sender,
           AnsiString &Name, bool &Action);
+  void __fastcall LogFileNameEditCreateEditDialog(TObject *Sender,
+          TFileDialogKind DialogKind, TOpenDialog *&Dialog);
 private:
   bool FEnableLogWindow;
   AnsiString FBeforeDialogPath;

+ 3 - 3
forms/Login.cpp

@@ -754,14 +754,14 @@ void __fastcall TLoginDialog::SaveSession(TSessionData * aSessionData)
       AnsiString() : SftpServerEdit->Text);
   aSessionData->SFTPMaxVersion = SFTPMaxVersionCombo->ItemIndex;
 
-  // FTP tab
-  aSessionData->PostLoginCommands = PostLoginCommandsMemo->Lines->Text;
-
   #define SAVE_SFTP_BUG_COMBO(BUG) aSessionData->SFTPBug[sb ## BUG] = (TAutoSwitch)(2 - SFTPBug ## BUG ## Combo->ItemIndex);
   SAVE_SFTP_BUG_COMBO(Symlink);
   SAVE_SFTP_BUG_COMBO(SignedTS);
   #undef SAVE_SFTP_BUG_COMBO
 
+  // FTP tab
+  aSessionData->PostLoginCommands = PostLoginCommandsMemo->Lines->Text;
+
   // Proxy tab
   aSessionData->ProxyMethod = (TProxyMethod)SshProxyMethodCombo->ItemIndex;
   aSessionData->ProxyHost = ProxyHostEdit->Text;

+ 7 - 7
forms/Login.dfm

@@ -301,7 +301,7 @@ object LoginDialog: TLoginDialog
           353
           286)
         object LoadButton: TButton
-          Left = 258
+          Left = 259
           Top = 35
           Width = 88
           Height = 25
@@ -310,7 +310,7 @@ object LoginDialog: TLoginDialog
           TabOrder = 2
         end
         object DeleteButton: TButton
-          Left = 258
+          Left = 259
           Top = 67
           Width = 88
           Height = 25
@@ -349,7 +349,7 @@ object LoginDialog: TLoginDialog
           OnStartDrag = SessionTreeStartDrag
         end
         object NewButton: TButton
-          Left = 258
+          Left = 259
           Top = 3
           Width = 88
           Height = 25
@@ -386,7 +386,7 @@ object LoginDialog: TLoginDialog
           TabOrder = 7
         end
         object RenameButton: TButton
-          Left = 257
+          Left = 258
           Top = 99
           Width = 88
           Height = 25
@@ -395,7 +395,7 @@ object LoginDialog: TLoginDialog
           TabOrder = 4
         end
         object NewFolderButton: TButton
-          Left = 257
+          Left = 258
           Top = 131
           Width = 88
           Height = 25
@@ -2138,7 +2138,7 @@ object LoginDialog: TLoginDialog
             Width = 305
             Height = 17
             Anchors = [akLeft, akTop, akRight]
-            Caption = 'Respond with &password to the first prompt'
+            Caption = 'Respond with pass&word to the first prompt'
             TabOrder = 3
             OnClick = DataChange
           end
@@ -2147,7 +2147,7 @@ object LoginDialog: TLoginDialog
             Top = 111
             Width = 325
             Height = 17
-            Caption = 'Attempt GSSAPI/SSPI authentication (SSH-2)'
+            Caption = 'Attempt &GSSAPI/SSPI authentication (SSH-2)'
             TabOrder = 4
             OnClick = AuthGSSAPICheck2Click
           end

+ 22 - 33
forms/Preferences.cpp

@@ -70,6 +70,7 @@ __fastcall TPreferencesDialog::TPreferencesDialog(TComponent* AOwner)
 
   FCustomCommandsScrollOnDragOver = new TListViewScrollOnDragOver(CustomCommandsView, true);
   FCopyParamScrollOnDragOver = new TListViewScrollOnDragOver(CopyParamListView, true);
+  FEditorScrollOnDragOver = new TListViewScrollOnDragOver(EditorListView, true);
 
   LoggingFrame->Init();
   InstallPathWordBreakProc(RandomSeedFileEdit);
@@ -80,6 +81,7 @@ __fastcall TPreferencesDialog::TPreferencesDialog(TComponent* AOwner)
 //---------------------------------------------------------------------------
 __fastcall TPreferencesDialog::~TPreferencesDialog()
 {
+  SAFE_DESTROY(FEditorScrollOnDragOver);
   SAFE_DESTROY(FCopyParamScrollOnDragOver);
   SAFE_DESTROY(FCustomCommandsScrollOnDragOver);
   delete FEditorFont;
@@ -707,21 +709,9 @@ void __fastcall TPreferencesDialog::UpdateControls()
 //---------------------------------------------------------------------------
 void __fastcall TPreferencesDialog::EditorFontButtonClick(TObject * /*Sender*/)
 {
-  TFontDialog * Dialog = new TFontDialog(Application);
-  try
-  {
-    Dialog->Device = fdScreen;
-    Dialog->Options = TFontDialogOptions() << fdForceFontExist;
-    Dialog->Font = FEditorFont;
-    if (Dialog->Execute())
-    {
-      FEditorFont->Assign(Dialog->Font);
-      UpdateControls();
-    }
-  }
-  __finally
+  if (FontDialog(FEditorFont))
   {
-    delete Dialog;
+    UpdateControls();
   }
 }
 //---------------------------------------------------------------------------
@@ -971,6 +961,10 @@ TListViewScrollOnDragOver * __fastcall TPreferencesDialog::ScrollOnDragOver(TObj
   {
     return FCustomCommandsScrollOnDragOver;
   }
+  else if (ListView == EditorListView)
+  {
+    return FEditorScrollOnDragOver;
+  }
   else
   {
     assert(false);
@@ -1434,26 +1428,13 @@ void __fastcall TPreferencesDialog::PuttyPathResetButtonClick(
 //---------------------------------------------------------------------------
 void __fastcall TPreferencesDialog::ExportButtonClick(TObject * /*Sender*/)
 {
-  TSaveDialog * Dialog = new TSaveDialog(Application);
-  try
+  AnsiString PersonalDirectory;
+  ::SpecialFolderLocation(CSIDL_PERSONAL, PersonalDirectory);
+  AnsiString FileName = IncludeTrailingBackslash(PersonalDirectory) +
+    ExtractFileName(ExpandEnvironmentVariables(Configuration->IniFileStorageName));
+  if (SaveDialog(LoadStr(EXPORT_CONF_TITLE), LoadStr(EXPORT_CONF_FILTER), "ini", FileName))
   {
-    Dialog->DefaultExt = "ini";
-    Dialog->Filter = LoadStr(EXPORT_CONF_FILTER);
-    Dialog->Title = LoadStr(EXPORT_CONF_TITLE);
-    AnsiString PersonalDirectory;
-    ::SpecialFolderLocation(CSIDL_PERSONAL, PersonalDirectory);
-    Dialog->FileName = IncludeTrailingBackslash(PersonalDirectory) +
-      ExtractFileName(ExpandEnvironmentVariables(Configuration->IniFileStorageName));
-    Dialog->Options = Dialog->Options << ofOverwritePrompt << ofPathMustExist <<
-      ofNoReadOnlyReturn;
-    if (Dialog->Execute())
-    {
-      Configuration->Export(Dialog->FileName);
-    }
-  }
-  __finally
-  {
-    delete Dialog;
+    Configuration->Export(FileName);
   }
 }
 //---------------------------------------------------------------------------
@@ -1485,3 +1466,11 @@ void __fastcall TPreferencesDialog::ListViewEndDrag(
   ScrollOnDragOver(Sender)->EndDrag();
 }
 //---------------------------------------------------------------------------
+void __fastcall TPreferencesDialog::RandomSeedFileEditCreateEditDialog(
+  TObject * Sender, TFileDialogKind DialogKind, TOpenDialog *& Dialog)
+{
+  USEDPARAM(DialogKind);
+  assert(DialogKind == dkOpen);
+  Dialog = CreateOpenDialog(dynamic_cast<TComponent *>(Sender));
+}
+//---------------------------------------------------------------------------

+ 1 - 0
forms/Preferences.dfm

@@ -1523,6 +1523,7 @@ object PreferencesDialog: TPreferencesDialog
             Filter = 'Random seed files (*.rnd)|*.rnd|All files (*.*)|*.*'
             DialogOptions = [ofHideReadOnly, ofPathMustExist]
             DialogTitle = 'Select file for random seed'
+            OnCreateEditDialog = RandomSeedFileEditCreateEditDialog
             ClickKey = 16397
             Anchors = [akLeft, akTop, akRight]
             TabOrder = 0

+ 3 - 0
forms/Preferences.h

@@ -277,6 +277,8 @@ __published:
           TTreeNode *Node, bool &AllowCollapse);
   void __fastcall ListViewEndDrag(TObject *Sender,
           TObject *Target, int X, int Y);
+  void __fastcall RandomSeedFileEditCreateEditDialog(TObject *Sender,
+          TFileDialogKind DialogKind, TOpenDialog *&Dialog);
 private:
   TPreferencesMode FPreferencesMode;
   TFont * FEditorFont;
@@ -291,6 +293,7 @@ private:
   AnsiString FBeforeDialogPath;
   TListViewScrollOnDragOver * FCustomCommandsScrollOnDragOver;
   TListViewScrollOnDragOver * FCopyParamScrollOnDragOver;
+  TListViewScrollOnDragOver * FEditorScrollOnDragOver;
   bool FNoUpdate;
   void __fastcall SetPreferencesMode(TPreferencesMode value);
   void __fastcall CMDialogKey(TWMKeyDown & Message);

+ 0 - 12
forms/Progress.cpp

@@ -210,18 +210,6 @@ void __fastcall TProgressForm::UpdateControls()
     CPSLabel->Caption = FORMAT("%s/s", (FormatBytes(FData.CPS())));
     FileProgress->Position = FData.TransferProgress();
     FileProgress->Hint = FORMAT("%d%%", (FileProgress->Position));
-
-    TransferModeLabel->Caption =
-      LoadStr(FData.AsciiTransfer ? TRANSFER_ASCII : TRANSFER_BINARY);
-
-    AnsiString ResumeStatusStr;
-    switch (FData.ResumeStatus) {
-      case rsEnabled: ResumeStatusStr = LoadStr(RESUME_ENABLED); break;
-      case rsDisabled: ResumeStatusStr = LoadStr(RESUME_DISABLED); break;
-      case rsNotAvailable: ResumeStatusStr = LoadStr(RESUME_NOT_AVAILABLE); break;
-      default:  assert(false);
-    }
-    ResumeLabel->Caption = ResumeStatusStr;
   }
 }
 //---------------------------------------------------------------------

+ 15 - 49
forms/Progress.dfm

@@ -6,7 +6,7 @@ object ProgressForm: TProgressForm
   BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
   BorderStyle = bsDialog
   Caption = 'Operation'
-  ClientHeight = 240
+  ClientHeight = 224
   ClientWidth = 394
   Color = clBtnFace
   ParentFont = True
@@ -16,7 +16,7 @@ object ProgressForm: TProgressForm
   OnShow = FormShow
   DesignSize = (
     394
-    240)
+    224)
   PixelsPerInch = 96
   TextHeight = 13
   object Animate: TAnimate
@@ -114,13 +114,13 @@ object ProgressForm: TProgressForm
     Left = 8
     Top = 133
     Width = 299
-    Height = 79
+    Height = 63
     Anchors = [akLeft, akTop, akRight]
     BevelOuter = bvNone
     TabOrder = 4
     DesignSize = (
       299
-      79)
+      63)
     object StartTimeLabel: TLabel
       Left = 88
       Top = 18
@@ -132,7 +132,7 @@ object ProgressForm: TProgressForm
     end
     object TimeLeftLabel: TLabel
       Left = 88
-      Top = 18
+      Top = 2
       Width = 65
       Height = 13
       Alignment = taRightJustify
@@ -141,14 +141,14 @@ object ProgressForm: TProgressForm
     end
     object TimeLeftLabelLabel: TLabel
       Left = 0
-      Top = 18
+      Top = 2
       Width = 43
       Height = 13
       Caption = 'Time left:'
     end
     object CPSLabel: TLabel
       Left = 234
-      Top = 34
+      Top = 18
       Width = 65
       Height = 13
       Alignment = taRightJustify
@@ -157,16 +157,6 @@ object ProgressForm: TProgressForm
       Caption = '0 KiB/s'
     end
     object TimeElapsedLabel: TLabel
-      Left = 234
-      Top = 18
-      Width = 65
-      Height = 13
-      Alignment = taRightJustify
-      Anchors = [akTop, akRight]
-      AutoSize = False
-      Caption = '00:00:00'
-    end
-    object ResumeLabel: TLabel
       Left = 234
       Top = 2
       Width = 65
@@ -174,20 +164,11 @@ object ProgressForm: TProgressForm
       Alignment = taRightJustify
       Anchors = [akTop, akRight]
       AutoSize = False
-      Caption = 'Enabled'
-    end
-    object TransferModeLabel: TLabel
-      Left = 88
-      Top = 2
-      Width = 65
-      Height = 13
-      Alignment = taRightJustify
-      AutoSize = False
-      Caption = 'Binary'
+      Caption = '00:00:00'
     end
     object BytesTransferedLabel: TLabel
       Left = 88
-      Top = 34
+      Top = 18
       Width = 65
       Height = 13
       Alignment = taRightJustify
@@ -196,7 +177,7 @@ object ProgressForm: TProgressForm
     end
     object Label3: TLabel
       Left = 162
-      Top = 18
+      Top = 2
       Width = 66
       Height = 13
       Anchors = [akTop, akRight]
@@ -204,44 +185,29 @@ object ProgressForm: TProgressForm
     end
     object StartTimeLabelLabel: TLabel
       Left = 0
-      Top = 18
+      Top = 2
       Width = 47
       Height = 13
       Caption = 'Start time:'
     end
     object Label4: TLabel
       Left = 0
-      Top = 34
+      Top = 18
       Width = 82
       Height = 13
       Caption = 'Bytes transferred:'
     end
     object Label12: TLabel
       Left = 162
-      Top = 34
+      Top = 18
       Width = 34
       Height = 13
       Anchors = [akTop, akRight]
       Caption = 'Speed:'
     end
-    object Label10: TLabel
-      Left = 0
-      Top = 2
-      Width = 71
-      Height = 13
-      Caption = 'Transfer mode:'
-    end
-    object Label11: TLabel
-      Left = 162
-      Top = 2
-      Width = 42
-      Height = 13
-      Anchors = [akTop, akRight]
-      Caption = 'Resume:'
-    end
     object FileProgress: TProgressBar
       Left = 0
-      Top = 53
+      Top = 37
       Width = 299
       Height = 16
       Anchors = [akLeft, akTop, akRight]
@@ -254,7 +220,7 @@ object ProgressForm: TProgressForm
   end
   object DisconnectWhenCompleteCheck: TCheckBox
     Left = 16
-    Top = 214
+    Top = 198
     Width = 289
     Height = 17
     Caption = '&Disconnect when operation finishes'

+ 0 - 4
forms/Progress.h

@@ -42,10 +42,6 @@ __published:
   TProgressBar *FileProgress;
   TTimer *UpdateTimer;
   TCheckBox *DisconnectWhenCompleteCheck;
-  TLabel *Label10;
-  TLabel *TransferModeLabel;
-  TLabel *Label11;
-  TLabel *ResumeLabel;
   TPanel *SpeedPanel;
   TLabel *SpeedLabel2;
   TLabel *TimeLeftLabelLabel;

+ 5 - 1
forms/ScpExplorer.cpp

@@ -265,7 +265,11 @@ AnsiString __fastcall TScpExplorerForm::RemotePathComboBoxText()
   }
   else
   {
-    Result = UnixPathComboBox->Strings->Strings[UnixPathComboBox->Strings->Count - 1];
+    // this is called couple of times before the combo box is populated
+    if (UnixPathComboBox->Strings->Count > 0)
+    {
+      Result = UnixPathComboBox->Strings->Strings[UnixPathComboBox->Strings->Count - 1];
+    }
   }
 
   return Result;

+ 2 - 0
packages/filemng/DriveView.pas

@@ -1180,8 +1180,10 @@ begin
       NodeData.shAttr := NodeData.shAttr or SFGAO_HASSUBFOLDER;
 
     if not Assigned(NodeData.ShellFolder) then
+    begin
       ParentFolder.BindToObject(NodeData.PIDL, nil, IID_IShellFolder,
         Pointer(NodeData.ShellFolder));
+    end;
   end;
 end; {GetNodeAttr}
 

+ 5 - 0
packages/my/ComboEdit.hpp

@@ -236,6 +236,8 @@ public:
 enum TFileDialogKind { dkOpen, dkSave, dkOpenPicture, dkSavePicture };
 #pragma option pop
 
+typedef void __fastcall (__closure *TCreateEditDialogEvent)(System::TObject* Sender, TFileDialogKind DialogKind, Dialogs::TOpenDialog* &Dialog);
+
 class DELPHICLASS TFilenameEdit;
 class PASCALIMPLEMENTATION TFilenameEdit : public TFileDirEdit 
 {
@@ -244,6 +246,7 @@ class PASCALIMPLEMENTATION TFilenameEdit : public TFileDirEdit
 private:
 	Dialogs::TOpenDialog* FDialog;
 	TFileDialogKind FDialogKind;
+	TCreateEditDialogEvent FOnCreateEditDialog;
 	void __fastcall CreateEditDialog(void);
 	AnsiString __fastcall GetFileName();
 	AnsiString __fastcall GetDefaultExt();
@@ -265,6 +268,7 @@ private:
 	void __fastcall SetHistoryList(Classes::TStrings* Value);
 	void __fastcall SetOptions(Dialogs::TOpenOptions Value);
 	void __fastcall SetDialogTitle(const AnsiString Value);
+	void __fastcall SetOnCreateEditDialog(TCreateEditDialogEvent Value);
 	bool __fastcall IsCustomTitle(void);
 	bool __fastcall IsCustomFilter(void);
 	
@@ -291,6 +295,7 @@ __published:
 	__property Classes::TStrings* HistoryList = {read=GetHistoryList, write=SetHistoryList};
 	__property Dialogs::TOpenOptions DialogOptions = {read=GetOptions, write=SetOptions, default=4};
 	__property AnsiString DialogTitle = {read=GetDialogTitle, write=SetDialogTitle, stored=IsCustomTitle};
+	__property TCreateEditDialogEvent OnCreateEditDialog = {read=FOnCreateEditDialog, write=SetOnCreateEditDialog};
 	__property AutoSelect  = {default=1};
 	__property ButtonHint ;
 	__property BorderStyle  = {default=1};

+ 30 - 6
packages/my/ComboEdit.pas

@@ -194,10 +194,14 @@ type
   TFileDialogKind = (dkOpen, dkSave , dkOpenPicture,
     dkSavePicture);
 
+  TCreateEditDialogEvent = procedure(Sender: TObject; DialogKind: TFileDialogKind;
+    var Dialog: TOpenDialog) of object;
+
   TFilenameEdit = class(TFileDirEdit)
   private
     FDialog: TOpenDialog;
     FDialogKind: TFileDialogKind;
+    FOnCreateEditDialog: TCreateEditDialogEvent;
     procedure CreateEditDialog;
     function GetFileName: string;
     function GetDefaultExt: TFileExt;
@@ -219,6 +223,7 @@ type
     procedure SetHistoryList(Value: TStrings);
     procedure SetOptions(Value: TOpenOptions);
     procedure SetDialogTitle(const Value: string);
+    procedure SetOnCreateEditDialog(Value: TCreateEditDialogEvent);
     function IsCustomTitle: Boolean;
     function IsCustomFilter: Boolean;
   protected
@@ -246,6 +251,8 @@ type
       default [ofHideReadOnly];
     property DialogTitle: string read GetDialogTitle write SetDialogTitle
       stored IsCustomTitle;
+    property OnCreateEditDialog: TCreateEditDialogEvent read FOnCreateEditDialog
+      write SetOnCreateEditDialog;
     property AutoSelect;
     property ButtonHint;
     property BorderStyle;
@@ -1010,12 +1017,18 @@ procedure TFilenameEdit.CreateEditDialog;
 var
   NewDialog: TOpenDialog;
 begin
-  case FDialogKind of
-    dkOpen: NewDialog := TOpenDialog.Create(Self);
-    dkOpenPicture: NewDialog := TOpenPictureDialog.Create(Self);
-    dkSavePicture: NewDialog := TSavePictureDialog.Create(Self);
-    else {dkSave} NewDialog := TSaveDialog.Create(Self);
-  end;
+  NewDialog := nil;
+  if Assigned(FOnCreateEditDialog) then
+    FOnCreateEditDialog(Self, FDialogKind, NewDialog);
+
+  if not Assigned(NewDialog) then
+    case FDialogKind of
+      dkOpen: NewDialog := TOpenDialog.Create(Self);
+      dkOpenPicture: NewDialog := TOpenPictureDialog.Create(Self);
+      dkSavePicture: NewDialog := TSavePictureDialog.Create(Self);
+      else {dkSave} NewDialog := TSaveDialog.Create(Self);
+    end;
+
   try
     if FDialog <> nil then begin
       with NewDialog do begin
@@ -1181,6 +1194,17 @@ begin
   end;
 end;
 
+procedure TFilenameEdit.SetOnCreateEditDialog(Value: TCreateEditDialogEvent);
+begin
+  if @FOnCreateEditDialog <> @Value then
+  begin
+    FOnCreateEditDialog := Value;
+    // to recreate a dialog with every change is stupid way,
+    // but its done only once, so it is acceptable
+    CreateEditDialog;
+  end;
+end;
+
 procedure TFilenameEdit.SetDefaultExt(Value: TFileExt);
 begin
   FDialog.DefaultExt := Value;

+ 0 - 1
packages/my/PasTools.hpp

@@ -116,7 +116,6 @@ public:
 
 
 //-- var, const, procedure ---------------------------------------------------
-extern PACKAGE unsigned __fastcall GetTraceFile(void);
 extern PACKAGE Classes::TComponent* __fastcall Construct(TMetaClass* ComponentClass, Classes::TComponent* Owner);
 extern PACKAGE bool __fastcall IsVista(void);
 

+ 1 - 1
release/winscp.u3i

@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <u3manifest version="1.0">
-  <application uuid="48b341d1-d411-4b5a-a82c-f3b5d65602fc" version="4.1.6">
+  <application uuid="48b341d1-d411-4b5a-a82c-f3b5d65602fc" version="4.1.7">
     <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>

+ 2 - 0
resource/TextsCore.h

@@ -188,6 +188,7 @@
 #define EXECUTE_APP_ERROR       262
 #define FILE_NOT_FOUND          263
 #define DOCUMENT_WAIT_ERROR     264
+#define SPEED_INVALID           265
 
 #define CORE_CONFIRMATION_STRINGS 300
 #define CONFIRM_PROLONG_TIMEOUT2 301
@@ -333,6 +334,7 @@
 #define SCRIPT_SYNCHRONIZE_COLLECTING 507
 #define SCRIPT_SYNCHRONIZE_SYNCHRONIZING 508
 #define SCRIPT_SYNCHRONIZE_NODIFFERENCE 509
+#define SPEED_UNLIMITED         510
 
 #define CORE_VARIABLE_STRINGS   600
 #define PUTTY_BASED_ON          601

+ 2 - 0
resource/TextsCore1.rc

@@ -161,6 +161,7 @@ BEGIN
   EXECUTE_APP_ERROR, "Cannot execute '%s'."
   FILE_NOT_FOUND, "File '%s' not found."
   DOCUMENT_WAIT_ERROR, "Error waiting for document to close."
+  SPEED_INVALID, "'%s' is not a valid speed limit."
 
   CORE_CONFIRMATION_STRINGS, "CORE_CONFIRMATION"
   CONFIRM_PROLONG_TIMEOUT2, "Host has not answered for %d seconds.\n\nWait for another %0:d seconds?"
@@ -306,6 +307,7 @@ BEGIN
   SCRIPT_SYNCHRONIZE_COLLECTING, "Comparing..."
   SCRIPT_SYNCHRONIZE_SYNCHRONIZING, "Synchronizing..."
   SCRIPT_SYNCHRONIZE_NODIFFERENCE, "Nothing to synchronize."
+  SPEED_UNLIMITED, "Unlimited"
 
   CORE_VARIABLE_STRINGS, "CORE_VARIABLE"
   PUTTY_BASED_ON, "SSH and SCP code based on PuTTY %s"

+ 0 - 7
resource/TextsWin.h

@@ -57,7 +57,6 @@
 #define COPY_PARAM_DUPLICATE    1163
 #define CUSTOM_COMMAND_IMPOSSIBLE 1164
 #define EDIT_SESSION_CLOSED_RELOAD 1165
-#define SPEED_INVALID           1166
 #define UNSAFE_ACTIONS_DISABLED 1167
 
 #define WIN_CONFIRMATION_STRINGS 1300
@@ -165,7 +164,6 @@
 #define UPDATE_DISABLED         1501
 #define UPDATE_URL_BUTTON       1502
 #define WHATS_NEW_BUTTON        1503
-#define SPEED_UNLIMITED         1504
 #define BALLOON_OPERATION_COMPLETE 1505
 #define CUSTOM_COMMAND_PRINT    1506
 
@@ -216,11 +214,6 @@
 #define LICENSE_CAPTION         1649
 #define OPEN_DIRECTORY_BROWSE_CAPTION 1657
 #define OPEN_DIRECTORY_ADD_BOOMARK_ACTION 1658
-#define RESUME_ENABLED          1659
-#define RESUME_DISABLED         1660
-#define RESUME_NOT_AVAILABLE    1661
-#define TRANSFER_ASCII          1662
-#define TRANSFER_BINARY         1663
 #define EDITOR_LINE_STATUS      1664
 #define EDITOR_COLUMN_STATUS    1665
 #define EDITOR_CHARACTER_STATUS2 1666

+ 0 - 7
resource/TextsWin1.rc

@@ -62,7 +62,6 @@ BEGIN
         CUSTOM_COMMAND_IMPOSSIBLE, "Custom command '%s' cannot be executed right now. Please select files for the command first."
         CUSTOM_COMMAND_AD_HOC_NAME, "Ad Hoc"
         EDIT_SESSION_CLOSED_RELOAD, "Cannot reload file '%s', the session '%s' has been already closed."
-        SPEED_INVALID, "'%s' is not a valid speed limit."
         UNSAFE_ACTIONS_DISABLED, "Automatic actions are disabled when URL address is provided on command-line."
 
         WIN_CONFIRMATION_STRINGS, "WIN_CONFIRMATION"
@@ -168,7 +167,6 @@ BEGIN
         UPDATE_DISABLED, "Check for application updates is temporarily disabled. Please try again later."
         UPDATE_URL_BUTTON, "&Go To"
         WHATS_NEW_BUTTON, "What's New"
-        SPEED_UNLIMITED, "Unlimited"
         BALLOON_OPERATION_COMPLETE, "Operation was completed."
         CUSTOM_COMMAND_PRINT, "&Print"
 
@@ -217,11 +215,6 @@ BEGIN
         SET_DEFAULT_SESSION_SETTINGS, "Set current session settings as default?"
         OPEN_DIRECTORY_BROWSE_CAPTION, "Open directory"
         OPEN_DIRECTORY_ADD_BOOMARK_ACTION, "Manage bookmarks"
-        RESUME_ENABLED, "Enabled"
-        RESUME_DISABLED, "Disabled"
-        RESUME_NOT_AVAILABLE, "N/A"
-        TRANSFER_ASCII, "Text"
-        TRANSFER_BINARY, "Binary"
         EDITOR_LINE_STATUS, "Line: %d/%d"
         EDITOR_COLUMN_STATUS, "Column: %d"
         EDITOR_CHARACTER_STATUS2, "Character: %d (0x%.2x)"

+ 58 - 24
windows/ConsoleRunner.cpp

@@ -16,7 +16,7 @@
 #include "ProgParams.h"
 #include "TextsWin.h"
 #include "TextsCore.h"
-#include "CustomWinConfiguration.h"
+#include "WinConfiguration.h"
 #include "SynchronizeController.h"
 #include "GUITools.h"
 enum { RESULT_SUCCESS = 0, RESULT_ANY_ERROR = 1 };
@@ -37,6 +37,7 @@ public:
   virtual bool __fastcall PendingAbort() = 0;
   virtual void __fastcall SetTitle(AnsiString Title) = 0;
   virtual bool __fastcall LimitedOutput() = 0;
+  virtual bool __fastcall LiveOutput() = 0;
   virtual void __fastcall WaitBeforeExit() = 0;
 };
 //---------------------------------------------------------------------------
@@ -52,6 +53,7 @@ public:
   virtual bool __fastcall PendingAbort();
   virtual void __fastcall SetTitle(AnsiString Title);
   virtual bool __fastcall LimitedOutput();
+  virtual bool __fastcall LiveOutput();
   virtual void __fastcall WaitBeforeExit();
 
 protected:
@@ -343,6 +345,11 @@ bool __fastcall TOwnConsole::LimitedOutput()
   return true;
 }
 //---------------------------------------------------------------------------
+bool __fastcall TOwnConsole::LiveOutput()
+{
+  return true;
+}
+//---------------------------------------------------------------------------
 void __fastcall TOwnConsole::WaitBeforeExit()
 {
   unsigned long Read;
@@ -371,6 +378,7 @@ public:
   virtual bool __fastcall PendingAbort();
   virtual void __fastcall SetTitle(AnsiString Title);
   virtual bool __fastcall LimitedOutput();
+  virtual bool __fastcall LiveOutput();
   virtual void __fastcall WaitBeforeExit();
 
 private:
@@ -380,6 +388,7 @@ private:
   HANDLE FCancelEvent;
   HANDLE FFileMapping;
   bool FLimitedOutput;
+  bool FLiveOutput;
   static const int PrintTimeout = 5000;
 
   inline TConsoleCommStruct * __fastcall GetCommStruct();
@@ -476,7 +485,8 @@ void __fastcall TExternalConsole::FreeCommStruct(TConsoleCommStruct * CommStruct
 void __fastcall TExternalConsole::SendEvent(int Timeout)
 {
   SetEvent(FRequestEvent);
-  if (WaitForSingleObject(FResponseEvent, Timeout) != WAIT_OBJECT_0)
+  unsigned int Result = WaitForSingleObject(FResponseEvent, Timeout);
+  if (Result != WAIT_OBJECT_0)
   {
     throw Exception(LoadStr(CONSOLE_SEND_TIMEOUT));
   }
@@ -618,6 +628,9 @@ void __fastcall TExternalConsole::Init()
   try
   {
     FLimitedOutput = (CommStruct->InitEvent.OutputType == FILE_TYPE_CHAR);
+    FLiveOutput =
+      (CommStruct->InitEvent.OutputType != FILE_TYPE_DISK) &&
+      (CommStruct->InitEvent.OutputType != FILE_TYPE_PIPE);
   }
   __finally
   {
@@ -630,6 +643,11 @@ bool __fastcall TExternalConsole::LimitedOutput()
   return FLimitedOutput;
 }
 //---------------------------------------------------------------------------
+bool __fastcall TExternalConsole::LiveOutput()
+{
+  return FLiveOutput;
+}
+//---------------------------------------------------------------------------
 void __fastcall TExternalConsole::WaitBeforeExit()
 {
   // noop
@@ -647,6 +665,7 @@ public:
   virtual bool __fastcall PendingAbort();
   virtual void __fastcall SetTitle(AnsiString Title);
   virtual bool __fastcall LimitedOutput();
+  virtual bool __fastcall LiveOutput();
   virtual void __fastcall WaitBeforeExit();
 };
 //---------------------------------------------------------------------------
@@ -686,6 +705,11 @@ bool __fastcall TNullConsole::LimitedOutput()
   return false;
 }
 //---------------------------------------------------------------------------
+bool __fastcall TNullConsole::LiveOutput()
+{
+  return false;
+}
+//---------------------------------------------------------------------------
 void __fastcall TNullConsole::WaitBeforeExit()
 {
   assert(false);
@@ -1108,6 +1132,7 @@ void __fastcall TConsoleRunner::ScriptTerminalQueryUser(TObject * /*Sender*/,
   assert(Accels.Pos(' ') == 0);
 
   bool Timeouting = (Timeout > 0);
+  bool FirstOutput = true;
 
   do
   {
@@ -1119,35 +1144,43 @@ void __fastcall TConsoleRunner::ScriptTerminalQueryUser(TObject * /*Sender*/,
     {
       Retry = false;
 
-      AnsiString Output;
-      for (int i = 0; i < ButtonCount; i++)
+      if (FirstOutput || FConsole->LiveOutput())
       {
-        if (i > 0)
+        AnsiString Output;
+        for (int i = 0; i < ButtonCount; i++)
         {
-          Output += ", ";
-        }
+          if (i > 0)
+          {
+            Output += ", ";
+          }
 
-        AnsiString Caption = Captions[i];
-        int P = Caption.Pos('&');
-        assert(P >= 0);
+          AnsiString Caption = Captions[i];
+          int P = Caption.Pos('&');
+          assert(P >= 0);
 
-        Caption[P] = '(';
-        Caption.Insert(")", P + 2);
+          Caption[P] = '(';
+          Caption.Insert(")", P + 2);
 
-        if (i + 1 == TimeoutIndex)
-        {
-          assert(Timeouting);
-          Caption = FMTLOAD(TIMEOUT_BUTTON, (Caption, int(Timeout / 1000)));
+          if (i + 1 == TimeoutIndex)
+          {
+            assert(Timeouting);
+            Caption = FMTLOAD(TIMEOUT_BUTTON, (Caption, int(Timeout / 1000)));
+          }
+
+          Output += Caption;
         }
+        Output += ": ";
 
-        Output += Caption;
-      }
-      Output += ": ";
+        // note that length of string may decrease over time due to number of
+        // seconds length, but supposing it decreases by one character at time
+        // at most, we do not mind as the prompt is terminated with space
 
-      // note that length of string may decrease over time due to number of
-      // seconds length, but supposing it decreases by one character at time
-      // at most, we do not mind as the prompt is terminated with space
-      Print(Output, true);
+        // If output is not live (file or pipe), do no use 'from beginning'
+        // as it means that the output is not actually stored until new line
+        // is sent (and we will not [because we cannot] rewrite the output anyway)
+        Print(Output, !FirstOutput);
+        FirstOutput = false;
+      }
 
       if (!Timeouting && (FScript->Batch == TScript::BatchContinue))
       {
@@ -1208,6 +1241,7 @@ void __fastcall TConsoleRunner::ScriptTerminalQueryUser(TObject * /*Sender*/,
       assert(P >= 0);
       AnswerCaption.Delete(P, 1);
       PrintLine(AnswerCaption);
+      FirstOutput = true;
 
       if (OnClicks[AnswerIndex - 1] != NULL)
       {
@@ -1544,7 +1578,7 @@ int __fastcall Console(bool Help)
 
         bool DefaultsOnly;
         delete StoredSessions->ParseUrl(Session, Params, DefaultsOnly,
-          puDecodeUrlChars, NULL, &Url);
+          NULL, &Url);
 
         if (Url || Params->FindSwitch("Unsafe"))
         {

+ 2 - 2
windows/CustomWinConfiguration.cpp

@@ -3,7 +3,7 @@
 #pragma hdrstop
 
 #include <Common.h>
-#include <TextsWin.h>
+#include <TextsCore.h>
 #include "CustomWinConfiguration.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
@@ -99,7 +99,7 @@ void __fastcall TCustomWinConfiguration::Saved()
 #define LASTELEM(ELEM) \
   ELEM.SubString(ELEM.LastDelimiter(".>")+1, ELEM.Length() - ELEM.LastDelimiter(".>"))
 #define BLOCK(KEY, CANCREATE, BLOCK) \
-  if (Storage->OpenSubKey(KEY, CANCREATE)) try { BLOCK } __finally { Storage->CloseSubKey(); }
+  if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
 #define REGCONFIG(CANCREATE) \
   BLOCK("Interface", CANCREATE, \
     KEY(Integer,  Interface); \

+ 5 - 5
windows/GUIConfiguration.cpp

@@ -613,7 +613,7 @@ AnsiString __fastcall TGUIConfiguration::PropertyToKey(const AnsiString Property
 //---------------------------------------------------------------------------
 // duplicated from core\configuration.cpp
 #define BLOCK(KEY, CANCREATE, BLOCK) \
-  if (Storage->OpenSubKey(KEY, CANCREATE)) try { BLOCK } __finally { Storage->CloseSubKey(); }
+  if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
 #define REGCONFIG(CANCREATE) \
   BLOCK("Interface", CANCREATE, \
     KEY(Bool,     CopyParamDialogExpanded); \
@@ -649,7 +649,7 @@ void __fastcall TGUIConfiguration::SaveData(THierarchicalStorage * Storage, bool
   REGCONFIG(true);
   #undef KEY
 
-  if (Storage->OpenSubKey("Interface\\CopyParam", true))
+  if (Storage->OpenSubKey("Interface\\CopyParam", true, true))
   try
   {
     FDefaultCopyParam.Save(Storage);
@@ -670,7 +670,7 @@ void __fastcall TGUIConfiguration::SaveData(THierarchicalStorage * Storage, bool
     Storage->CloseSubKey();
   }
 
-  if (Storage->OpenSubKey("Interface\\NewDirectory", true))
+  if (Storage->OpenSubKey("Interface\\NewDirectory", true, true))
   try
   {
     FNewDirectoryProperties.Save(Storage);
@@ -692,7 +692,7 @@ void __fastcall TGUIConfiguration::LoadData(THierarchicalStorage * Storage)
   #pragma warn +eas
   #undef KEY
 
-  if (Storage->OpenSubKey("Interface\\CopyParam", false))
+  if (Storage->OpenSubKey("Interface\\CopyParam", false, true))
   try
   {
     // must be loaded before eventual setting defaults for CopyParamList
@@ -731,7 +731,7 @@ void __fastcall TGUIConfiguration::LoadData(THierarchicalStorage * Storage)
     FPuttyPath = FormatCommand(FPuttyPath, "");
   }
 
-  if (Storage->OpenSubKey("Interface\\NewDirectory", false))
+  if (Storage->OpenSubKey("Interface\\NewDirectory", false, true))
   try
   {
     FNewDirectoryProperties.Load(Storage);

+ 2 - 2
windows/GUITools.cpp

@@ -67,8 +67,8 @@ void __fastcall OpenSessionInPutty(const AnsiString PuttyPath,
         else
         {
           SourceStorage = new TRegistryStorage(Configuration->PuttySessionsKey);
-          if (SourceStorage->OpenSubKey(MungeStr(StoredSessions->DefaultSettings->Name), false) &&
-              Storage->OpenSubKey(MungeStr(GUIConfiguration->PuttySession), true))
+          if (SourceStorage->OpenSubKey(StoredSessions->DefaultSettings->Name, false) &&
+              Storage->OpenSubKey(GUIConfiguration->PuttySession, true))
           {
             Storage->Copy(SourceStorage);
             Storage->CloseSubKey();

+ 128 - 17
windows/Tools.cpp

@@ -328,33 +328,46 @@ bool __fastcall IsFormatInClipboard(unsigned int Format)
   return Result;
 }
 //---------------------------------------------------------------------------
-bool __fastcall TextFromClipboard(AnsiString & Text)
+HANDLE __fastcall OpenTextFromClipboard(const char *& Text)
 {
-  bool Result = OpenClipboard(0);
-  if (Result)
+  HANDLE Result = NULL;
+  if (OpenClipboard(0))
   {
-    HANDLE Handle = NULL;
-    try
+    Result = GetClipboardData(CF_TEXT);
+    if (Result != NULL)
     {
-      Handle = GetClipboardData(CF_TEXT);
-      Result = (Handle != NULL);
-      if (Result)
-      {
-        Text = static_cast<const char*>(GlobalLock(Handle));
-      }
+      Text = static_cast<const char*>(GlobalLock(Result));
     }
-    __finally
+    else
     {
-      if (Handle != NULL)
-      {
-        GlobalUnlock(Handle);
-      }
       CloseClipboard();
     }
   }
   return Result;
 }
 //---------------------------------------------------------------------------
+void __fastcall CloseTextFromClipboard(HANDLE Handle)
+{
+  if (Handle != NULL)
+  {
+    GlobalUnlock(Handle);
+  }
+  CloseClipboard();
+}
+//---------------------------------------------------------------------------
+bool __fastcall TextFromClipboard(AnsiString & Text)
+{
+  const char * AText = NULL;
+  HANDLE Handle = OpenTextFromClipboard(AText);
+  bool Result = (Handle != NULL);
+  if (Result)
+  {
+    Text = AText;
+    CloseTextFromClipboard(Handle);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 static bool __fastcall GetResource(
   const AnsiString ResName, void *& Content, unsigned long & Size)
 {
@@ -424,6 +437,56 @@ AnsiString __fastcall ReadResource(const AnsiString ResName)
 }
 //---------------------------------------------------------------------------
 template <class T>
+class TChildCommonDialog : public T
+{
+public:
+  __fastcall TChildCommonDialog(TComponent * AOwner) :
+    T(AOwner)
+  {
+  }
+
+protected:
+  // all common-dialog structures we use (save, open, font) start like this:
+  typedef struct
+  {
+      DWORD        lStructSize;
+      HWND         hwndOwner;
+  } COMMONDLG;
+
+  virtual BOOL __fastcall TaskModalDialog(void * DialogFunc, void * DialogData)
+  {
+    COMMONDLG * CommonDlg = static_cast<COMMONDLG *>(DialogData);
+    HWND Parent = GetCorrectFormParent();
+    if (Parent != NULL)
+    {
+      CommonDlg->hwndOwner = Parent;
+    }
+
+    return T::TaskModalDialog(DialogFunc, DialogData);
+  }
+};
+//---------------------------------------------------------------------------
+// without this intermediate class, failure occurs during construction in release version
+#define CHILDCOMMONDIALOG(DIALOG) \
+  class TChild ## DIALOG ## Dialog : public TChildCommonDialog<T ## DIALOG ## Dialog> \
+  { \
+    public: \
+      __fastcall TChild ## DIALOG ## Dialog(TComponent * AOwner) : \
+        TChildCommonDialog<T ## DIALOG ## Dialog>(AOwner) \
+      { \
+      } \
+  }
+//---------------------------------------------------------------------------
+CHILDCOMMONDIALOG(Open);
+CHILDCOMMONDIALOG(Save);
+CHILDCOMMONDIALOG(Font);
+//---------------------------------------------------------------------------
+TOpenDialog * __fastcall CreateOpenDialog(TComponent * AOwner)
+{
+  return new TChildOpenDialog(AOwner);
+}
+//---------------------------------------------------------------------------
+template <class T>
 void __fastcall BrowseForExecutableT(T * Control, AnsiString Title,
   AnsiString Filter, bool FileNameCommand, bool Escape)
 {
@@ -435,7 +498,7 @@ void __fastcall BrowseForExecutableT(T * Control, AnsiString Title,
   }
   SplitCommand(Executable, Program, Params, Dir);
 
-  TOpenDialog * FileDialog = new TOpenDialog(Application);
+  TOpenDialog * FileDialog = CreateOpenDialog(Application);
   try
   {
     if (Escape)
@@ -493,6 +556,54 @@ void __fastcall BrowseForExecutable(TComboBox * Control, AnsiString Title,
   BrowseForExecutableT(Control, Title, Filter, FileNameCommand, Escape);
 }
 //---------------------------------------------------------------------------
+bool __fastcall FontDialog(TFont * Font)
+{
+  bool Result;
+  TFontDialog * Dialog = new TChildFontDialog(Application);
+  try
+  {
+    Dialog->Device = fdScreen;
+    Dialog->Options = TFontDialogOptions() << fdForceFontExist;
+    Dialog->Font = Font;
+    Result = Dialog->Execute();
+    if (Result)
+    {
+      Font->Assign(Dialog->Font);
+    }
+  }
+  __finally
+  {
+    delete Dialog;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+bool __fastcall SaveDialog(AnsiString Title, AnsiString Filter,
+  AnsiString DefaultExt, AnsiString & FileName)
+{
+  bool Result;
+  TSaveDialog * Dialog = new TChildSaveDialog(Application);
+  try
+  {
+    Dialog->Title = Title;
+    Dialog->Filter = Filter;
+    Dialog->DefaultExt = DefaultExt;
+    Dialog->FileName = FileName;
+    Dialog->Options = Dialog->Options << ofOverwritePrompt << ofPathMustExist <<
+      ofNoReadOnlyReturn;
+    Result = Dialog->Execute();
+    if (Result)
+    {
+      FileName = Dialog->FileName;
+    }
+  }
+  __finally
+  {
+    delete Dialog;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall CopyToClipboard(AnsiString Text)
 {
   HANDLE Data;

+ 6 - 0
windows/Tools.h

@@ -24,14 +24,20 @@ void __fastcall ValidateMaskEdit(TEdit * Edit);
 void __fastcall OpenBrowser(AnsiString URL);
 bool __fastcall IsFormatInClipboard(unsigned int Format);
 bool __fastcall TextFromClipboard(AnsiString & Text);
+HANDLE __fastcall OpenTextFromClipboard(const char *& Text);
+void __fastcall CloseTextFromClipboard(HANDLE Handle);
 void __fastcall ExitActiveControl(TForm * Form);
 AnsiString __fastcall ReadResource(const AnsiString ResName);
 bool __fastcall DumpResourceToFile(const AnsiString ResName,
   const AnsiString FileName);
+TOpenDialog * __fastcall CreateOpenDialog(TComponent * AOwner);
 void __fastcall BrowseForExecutable(TEdit * Control, AnsiString Title,
   AnsiString Filter, bool FileNameCommand, bool Escape);
 void __fastcall BrowseForExecutable(TComboBox * Control, AnsiString Title,
   AnsiString Filter, bool FileNameCommand, bool Escape);
+bool __fastcall FontDialog(TFont * Font);
+bool __fastcall SaveDialog(AnsiString Title, AnsiString Filter,
+  AnsiString DefaultExt, AnsiString & FileName);
 bool __fastcall AutodetectProxyUrl(AnsiString & Proxy);
 bool __fastcall IsWin64();
 void __fastcall CopyToClipboard(AnsiString Text);

+ 34 - 15
windows/VCLCommon.cpp

@@ -848,28 +848,47 @@ void __fastcall ResizeForm(TCustomForm * Form, int Width, int Height)
   Form->SetBounds(Left, Top, Width, Height);
 }
 //---------------------------------------------------------------------------
-void __fastcall SetCorrectFormParent(TForm * Form)
+HWND __fastcall GetCorrectFormParent()
 {
-  try
-  {
-    // Kind of hack (i do not understand this much).
-    // Rationale: for example when the preferences window is opened from login dialog
-    // settings Parent to Screen->ActiveForm leads to "cannot focus disabled control",
-    // so we set Parent only when absolutelly necessary
-    // (dialog opened from log window or editor)
-    // TODO: does not work for dialogs opened from preferences dialog
-    if ((Application->MainForm != NULL) &&
-        (Application->MainForm != Screen->ActiveForm))
+  HWND Result = NULL;
+  // Kind of hack (i do not understand this much).
+  // Rationale: for example when the preferences window is opened from login dialog
+  // settings Parent to Screen->ActiveForm leads to "cannot focus disabled control",
+  // so we set Parent only when absolutelly necessary
+  // (dialog opened from log window or editor)
+  // TODO: does not work for dialogs opened from preferences dialog
+  if ((Application->MainForm != NULL) &&
+      (Application->MainForm != Screen->ActiveForm))
+  {
+    AnsiString C = Screen->ActiveForm->Caption;
+    if (Screen->ActiveForm != NULL)
     {
+      // the case when we are invoking dialog from (e.g. prefences) dialog
+      // invokend form non modal window (e.g. editor)
+      if (Screen->ActiveForm->ParentWindow != NULL)
+      {
+        Result = Screen->ActiveForm->Handle;
+      }
       // this should better be check for modal form
-      AnsiString C = Screen->ActiveForm->Caption;
-      if ((Screen->ActiveForm != NULL) &&
-          (Screen->ActiveForm->BorderStyle != bsDialog))
+      else if (Screen->ActiveForm->BorderStyle != bsDialog)
       {
-        Form->ParentWindow = Screen->ActiveForm->Handle;
+        Result = Screen->ActiveForm->Handle;
       }
     }
   }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall SetCorrectFormParent(TForm * Form)
+{
+  try
+  {
+    HWND Parent = GetCorrectFormParent();
+    if (Parent != NULL)
+    {
+      Form->ParentWindow = Parent;
+    }
+  }
   catch(...)
   {
     // avoid any errors, however we want to know about this in debug version.

+ 1 - 0
windows/VCLCommon.h

@@ -39,6 +39,7 @@ void __fastcall MakeNextInTabOrder(TWinControl * Control, TWinControl * After);
 void __fastcall CutFormToDesktop(TForm * Form);
 void __fastcall UpdateFormPosition(TCustomForm * Form, TPosition Position);
 void __fastcall ResizeForm(TCustomForm * Form, int Width, int Height);
+HWND __fastcall GetCorrectFormParent();
 void __fastcall SetCorrectFormParent(TForm * Form);
 void __fastcall InvokeHelp(TWinControl * Control);
 TMonitor *  __fastcall FormMonitor(TCustomForm * Form);

+ 4 - 4
windows/WinConfiguration.cpp

@@ -639,7 +639,7 @@ THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool SessionList)
 #define LASTELEM(ELEM) \
   ELEM.SubString(ELEM.LastDelimiter(".>")+1, ELEM.Length() - ELEM.LastDelimiter(".>"))
 #define BLOCK(KEY, CANCREATE, BLOCK) \
-  if (Storage->OpenSubKey(KEY, CANCREATE)) try { BLOCK } __finally { Storage->CloseSubKey(); }
+  if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
 #define KEY(TYPE, VAR) KEYEX(TYPE, VAR, VAR)
 #define REGCONFIG(CANCREATE) \
   BLOCK("Interface", CANCREATE, \
@@ -798,7 +798,7 @@ void __fastcall TWinConfiguration::SaveData(THierarchicalStorage * Storage, bool
   }
 
   if ((All || FEditorList->Modified) &&
-      Storage->OpenSubKey("Interface\\Editor", true))
+      Storage->OpenSubKey("Interface\\Editor", true, true))
   try
   {
     FEditorList->Save(Storage);
@@ -914,7 +914,7 @@ void __fastcall TWinConfiguration::LoadData(THierarchicalStorage * Storage)
   }
   FCustomCommandsModified = false;
 
-  if (Storage->OpenSubKey("Interface\\Editor", false))
+  if (Storage->OpenSubKey("Interface\\Editor", false, true))
   try
   {
     FEditorList->Clear();
@@ -927,7 +927,7 @@ void __fastcall TWinConfiguration::LoadData(THierarchicalStorage * Storage)
 
   // load legacy editor configuration
   assert(FLegacyEditor != NULL);
-  if (Storage->OpenSubKey("Interface\\Editor", false))
+  if (Storage->OpenSubKey("Interface\\Editor", false, true))
   {
     try
     {

+ 0 - 34
windows/WinInterface.cpp

@@ -842,40 +842,6 @@ bool __fastcall IsGlobalMinimizeHandler()
   return (GlobalOnMinimize != NULL);
 }
 //---------------------------------------------------------------------------
-unsigned long __fastcall GetSpeedLimit(const AnsiString & Text)
-{
-  unsigned long Speed;
-  if (AnsiSameText(Text, LoadStr(SPEED_UNLIMITED)))
-  {
-    Speed = 0;
-  }
-  else
-  {
-    int SSpeed;
-    if (!TryStrToInt(Text, SSpeed) ||
-        (SSpeed < 0))
-    {
-      throw Exception(FMTLOAD(SPEED_INVALID, (Text)));
-    }
-    Speed = SSpeed;
-  }
-  return Speed * 1024;
-}
-//---------------------------------------------------------------------------
-AnsiString __fastcall SetSpeedLimit(unsigned long Limit)
-{
-  AnsiString Text;
-  if (Limit == 0)
-  {
-    Text = LoadStr(SPEED_UNLIMITED);
-  }
-  else
-  {
-    Text = IntToStr(Limit / 1024);
-  }
-  return Text;
-}
-//---------------------------------------------------------------------------
 struct TNotifyIconData5
 {
   DWORD cbSize;

+ 0 - 3
windows/WinInterface.h

@@ -352,9 +352,6 @@ void __fastcall SetGlobalMinimizeHandler(TNotifyEvent OnMinimize);
 TNotifyEvent __fastcall GetGlobalMinimizeHandler();
 bool __fastcall IsGlobalMinimizeHandler();
 
-unsigned long __fastcall GetSpeedLimit(const AnsiString & Text);
-AnsiString __fastcall SetSpeedLimit(unsigned long Limit);
-
 void __fastcall ShowNotification(TTerminal * Terminal, const AnsiString & Str,
   TQueryType Type);
 

+ 1 - 1
windows/WinMain.cpp

@@ -27,7 +27,7 @@ TSessionData * GetLoginData(AnsiString SessionName, TOptions * Options,
   TSessionData * Data;
 
   Data = StoredSessions->ParseUrl(SessionName, Options, DefaultsOnly,
-    puExtractFileName | puDecodeUrlChars, &DownloadFile, &Url);
+    &DownloadFile, &Url);
   assert(Data != NULL);
 
   if (!Data->CanLogin || DefaultsOnly)