Martin Prikryl 22 years ago
parent
commit
75dbf768f1
100 changed files with 5605 additions and 1796 deletions
  1. 7 18
      Putty.bpr
  2. 2 2
      RScpComp.bpr
  3. 13 15
      ScpCore.bpr
  4. 3 0
      ScpForms.bpf
  5. 19 14
      ScpForms.bpr
  6. 23 25
      WinSCP3.bpr
  7. 2 2
      WinSCP3.cpp
  8. 629 0
      WinSCP3.drc
  9. BIN
      WinSCP3.res
  10. 1 0
      components/LogMemo.cpp
  11. 1 1
      core/Bookmarks.cpp
  12. 0 0
      core/Bookmarks.h
  13. 194 0
      core/Common.cpp
  14. 14 0
      core/Common.h
  15. 47 19
      core/Configuration.cpp
  16. 4 2
      core/Configuration.h
  17. 10 2
      core/CopyParam.cpp
  18. 4 1
      core/CopyParam.h
  19. 4 1
      core/Exceptions.cpp
  20. 9 1
      core/FileBuffer.cpp
  21. 8 8
      core/FileInfo.cpp
  22. 62 0
      core/FileMasks.cpp
  23. 2 0
      core/FileMasks.h
  24. 22 6
      core/FileOperationProgress.cpp
  25. 22 2
      core/FileOperationProgress.h
  26. 4 0
      core/FileSystems.h
  27. 123 0
      core/HierarchicalStorage.cpp
  28. 20 0
      core/HierarchicalStorage.h
  29. 11 4
      core/Net.cpp
  30. 2 7
      core/PuttyIntf.h
  31. 146 82
      core/RemoteFiles.cpp
  32. 34 9
      core/RemoteFiles.h
  33. 246 64
      core/ScpFileSystem.cpp
  34. 10 3
      core/ScpFileSystem.h
  35. 118 44
      core/SecureShell.cpp
  36. 23 24
      core/SecureShell.h
  37. 158 22
      core/SessionData.cpp
  38. 18 3
      core/SessionData.h
  39. 424 304
      core/SftpFileSystem.cpp
  40. 17 5
      core/SftpFileSystem.h
  41. 610 43
      core/Terminal.cpp
  42. 71 22
      core/Terminal.h
  43. 10 1
      forms/About.cpp
  44. 3 0
      forms/About.h
  45. 64 43
      forms/Console.cpp
  46. 3 4
      forms/Console.dfm
  47. 9 2
      forms/Console.h
  48. 126 62
      forms/Copy.cpp
  49. 23 11
      forms/Copy.dfm
  50. 19 12
      forms/Copy.h
  51. 5 3
      forms/CopyParams.cpp
  52. 1 1
      forms/CopyParams.dfm
  53. 139 150
      forms/CustomScpExplorer.cpp
  54. 10 0
      forms/CustomScpExplorer.h
  55. 84 0
      forms/FileSystemInfo.cpp
  56. 269 0
      forms/FileSystemInfo.dfm
  57. 61 0
      forms/FileSystemInfo.h
  58. 179 0
      forms/FullSynchronize.cpp
  59. 163 0
      forms/FullSynchronize.dfm
  60. 60 0
      forms/FullSynchronize.h
  61. 6 3
      forms/GeneralSettings.cpp
  62. 40 16
      forms/LogSettings.cpp
  63. 4 0
      forms/LogSettings.h
  64. 91 43
      forms/Login.cpp
  65. 174 125
      forms/Login.dfm
  66. 18 12
      forms/Login.h
  67. 7 33
      forms/NonVisual.cpp
  68. 196 334
      forms/NonVisual.dfm
  69. 13 16
      forms/NonVisual.h
  70. 1 1
      forms/OpenDirectory.cpp
  71. 5 32
      forms/OperationStatus.cpp
  72. 1 2
      forms/OperationStatus.h
  73. 3 1
      forms/Preferences.cpp
  74. 1 0
      forms/Preferences.dfm
  75. 34 44
      forms/Progress.cpp
  76. 28 12
      forms/Progress.dfm
  77. 10 5
      forms/Progress.h
  78. 20 7
      forms/Properties.cpp
  79. 1 1
      forms/Properties.dfm
  80. 2 1
      forms/Properties.h
  81. 59 17
      forms/Rights.cpp
  82. 186 3
      forms/Rights.dfm
  83. 17 3
      forms/Rights.h
  84. 17 2
      forms/ScpCommander.cpp
  85. 10 5
      forms/ScpCommander.dfm
  86. 2 0
      forms/ScpCommander.h
  87. 10 0
      forms/ScpExplorer.cpp
  88. 15 1
      forms/ScpExplorer.dfm
  89. 3 0
      forms/ScpExplorer.h
  90. 2 2
      forms/SelectMask.cpp
  91. 82 0
      forms/SynchronizeProgress.cpp
  92. 100 0
      forms/SynchronizeProgress.dfm
  93. 47 0
      forms/SynchronizeProgress.h
  94. 3 3
      general/DragDrop_B5.bpk
  95. 3 3
      general/DriveDir_B5.bpk
  96. 3 3
      general/Moje_B5.bpk
  97. 11 8
      general/filemanager toolset/BaseUtils.pas
  98. 2 6
      general/moje komponenty/filemanager toolset/CustomDirView.pas
  99. 8 0
      putty/CMDLINE.C
  100. 5 8
      putty/CONFIG.C

+ 7 - 18
Putty.bpr

@@ -7,14 +7,14 @@
     <OBJFILES value="putty\BE_NONE.obj putty\CMDLINE.obj putty\INT64.obj 
       putty\LOGGING.obj putty\MISC.obj putty\NOISE.obj 
       putty\PAGEANTC.obj putty\PORTFWD.obj putty\PPROXY.obj 
-      putty\PROXY.obj putty\SETTINGS.obj putty\SSH.obj putty\SSHAES.obj 
+      putty\PROXY.obj putty\SETTINGS.obj putty\SSH_.obj putty\SSHAES.obj 
       putty\SSHBLOWF.obj putty\SSHBN.obj putty\SSHCRC.obj 
       putty\SSHCRCDA.obj putty\SSHDES.obj putty\SSHDH.obj 
       putty\SSHDSS.obj putty\SSHMD5.obj putty\SSHPUBK.obj 
       putty\SSHRAND.obj putty\SSHRSA.obj putty\SSHSH512.obj 
       putty\SSHSHA.obj putty\SSHZLIB.obj putty\TREE234.obj 
       putty\UTF8.obj putty\WILDCARD.obj putty\WINDEFS.obj 
-      putty\WINMISC.obj putty\WINNET.obj putty\WINSTORE.obj 
+      putty\WINMISC.obj putty\WINNET.obj putty\WINSTORE_.obj 
       putty\X11FWD.obj"/>
     <RESFILES value=""/>
     <DEFFILE value=""/>
@@ -27,12 +27,12 @@
     <PATHRC value=".;"/>
     <PATHASM value=".;"/>
     <LINKER value="TLib"/>
-    <USERDEFINES value="PUTTY_LIB;WINSOCK_TWO;AUTO_WINSOCK;_WINDOWS"/>
+    <USERDEFINES value="PUTTY_LIB;_WINDOWS;_MSC_VER=1000"/>
     <SYSDEFINES value="_RTLDLL;NO_STRICT"/>
     <MAINSOURCE value="Putty.bpf"/>
-    <INCLUDEPATH value="putty\CHARSET;putty;$(BCB)\include;$(BCB)\include\vcl"/>
+    <INCLUDEPATH value="putty;putty\CHARSET;$(BCB)\include;$(BCB)\include\vcl"/>
     <LIBPATH value="putty\CHARSET;putty;$(BCB)\lib\obj;$(BCB)\lib"/>
-    <WARNINGS value="-w-par"/>
+    <WARNINGS value="-w-sus -w-rvl -w-rch -w-pia -w-pck -w-pch -w-par -w-eff -w-aus"/>
     <LISTFILE value=""/>
     <OTHERFILES value=""/>
   </MACROS>
@@ -61,7 +61,7 @@
       <FILE FILENAME="putty\PPROXY.C" FORMNAME="" UNITNAME="PPROXY.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\PROXY.C" FORMNAME="" UNITNAME="PROXY.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SETTINGS.C" FORMNAME="" UNITNAME="SETTINGS.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="putty\SSH.C" FORMNAME="" UNITNAME="SSH.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="putty\SSH_.C" FORMNAME="" UNITNAME="SSH_" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHAES.C" FORMNAME="" UNITNAME="SSHAES.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHBLOWF.C" FORMNAME="" UNITNAME="SSHBLOWF.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHBN.C" FORMNAME="" UNITNAME="SSHBN.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
@@ -83,23 +83,12 @@
       <FILE FILENAME="putty\WINDEFS.C" FORMNAME="" UNITNAME="WINDEFS.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\WINMISC.C" FORMNAME="" UNITNAME="WINMISC.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\WINNET.C" FORMNAME="" UNITNAME="WINNET.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="putty\WINSTORE.C" FORMNAME="" UNITNAME="WINSTORE.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="putty\WINSTORE_.C" FORMNAME="" UNITNAME="WINSTORE_" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\X11FWD.C" FORMNAME="" UNITNAME="X11FWD.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
   </FILELIST>
   <BUILDTOOLS>
   </BUILDTOOLS>
 
-  <FILES>
-    <FILE type="override" value="putty\SSH.C" translator="Auto">
-      <USERDEFINES value="PUTTY_LIB;WINSOCK_TWO;AUTO_WINSOCK;_WINDOWS;_DEBUG;SSH_FILE"/>
-      <CFLAG1 value="-O2"/>
-    </FILE>
-    <FILE type="override" value="putty\WINSTORE.C" translator="Auto">
-      <USERDEFINES value="PUTTY_LIB;WINSOCK_TWO;AUTO_WINSOCK;_WINDOWS;_DEBUG;WINSTORE_FILE"/>
-      <CFLAG1 value="-O2"/>
-    </FILE>
-  </FILES>
-
   <IDEOPTIONS>
 [Version Info]
 IncludeVerInfo=0

+ 2 - 2
RScpComp.bpr

@@ -28,8 +28,8 @@
     <OTHERFILES value=""/>
   </MACROS>
   <OPTIONS>
-    <CFLAG1 value="-O2 -H=c:\PROGRA~1\borland\CBUILD~1\lib\vcl60.csm -Hc -Vx -Ve -X- -a8 -b- 
-      -k- -vi -c -tW -tWM"/>
+    <CFLAG1 value="-O2 -H=c:\PROGRA~1\borland\CBUILD~1\lib\vcl60.csm -Hc -w -Vx -Ve -X- -a8 
+      -b- -k- -vi -c -tW -tWM"/>
     <PFLAGS value="  -$Y- -$L- -$D- -$C- -$A8 -v -JPHNE -M"/>
     <AFLAGS value="/mx /w2 /zn"/>
     <LFLAGS value="/P32"/>

+ 13 - 15
ScpCore.bpr

@@ -4,14 +4,14 @@
   <MACROS>
     <VERSION value="BCB.06.00"/>
     <PROJECT value="lib\ScpCore.lib"/>
-    <OBJFILES value="core\Common.obj core\Configuration.obj core\CopyParam.obj 
-      core\Exceptions.obj core\FileBuffer.obj core\FileInfo.obj 
-      core\FileMasks.obj core\FileOperationProgress.obj 
-      core\FileSystems.obj core\HierarchicalStorage.obj core\KeyGen.obj 
-      core\NamedObjs.obj core\Net.obj core\PuttyIntf.obj 
-      core\RemoteFiles.obj core\ScpFileSystem.obj core\ScpMain.obj 
-      core\SecureShell.obj core\Security.obj core\SessionData.obj 
-      core\SftpFileSystem.obj core\Terminal.obj"/>
+    <OBJFILES value="core\Bookmarks.obj core\Common.obj core\Configuration.obj 
+      core\CopyParam.obj core\Exceptions.obj core\FileBuffer.obj 
+      core\FileInfo.obj core\FileMasks.obj 
+      core\FileOperationProgress.obj core\FileSystems.obj 
+      core\HierarchicalStorage.obj core\NamedObjs.obj core\Net.obj 
+      core\PuttyIntf.obj core\RemoteFiles.obj core\ScpFileSystem.obj 
+      core\ScpMain.obj core\SecureShell.obj core\Security.obj 
+      core\SessionData.obj core\SftpFileSystem.obj core\Terminal.obj"/>
     <RESFILES value=""/>
     <DEFFILE value=""/>
     <RESDEPEN value="$(RESFILES)"/>
@@ -23,18 +23,18 @@
     <PATHRC value=".;"/>
     <PATHASM value=".;"/>
     <LINKER value="TLib"/>
-    <USERDEFINES value="NO_WIN32_LEAN_AND_MEAN;WINSOCK_TWO;AUTO_WINSOCK;USE_COMPATIBLE_THREAD;_WINDOWS"/>
+    <USERDEFINES value="USE_COMPATIBLE_THREAD;_WINDOWS"/>
     <SYSDEFINES value="NO_STRICT"/>
     <MAINSOURCE value="ScpCore.bpf"/>
-    <INCLUDEPATH value="core;putty;resource;packages\my\filemng;$(BCB)\include;$(BCB)\include\vcl"/>
-    <LIBPATH value="core;$(BCB)\lib\obj;$(BCB)\lib"/>
+    <INCLUDEPATH value="windows;core;putty;resource;packages\my\filemng;$(BCB)\include;$(BCB)\include\vcl"/>
+    <LIBPATH value="windows;core;$(BCB)\lib\obj;$(BCB)\lib"/>
     <WARNINGS value="-w8092 -w8091 -w8090 -w8089 -w8087 -wprc -wuse -wucp -wstv -wstu -wsig 
       -wpin -wnod -wnak -wdef -wcln -wbbf -wasm -wamp -wamb"/>
     <LISTFILE value=""/>
     <OTHERFILES value=""/>
   </MACROS>
   <OPTIONS>
-    <CFLAG1 value="-O2 -H=$(BCB)\lib\vcl60.csm -Hc -Vx -Ve -X- -a8 -b- -k- -vi -c -tW -tWM"/>
+    <CFLAG1 value="-O2 -H=$(BCB)\lib\vcl60.csm -Hc -w -Vx -Ve -X- -a8 -b- -k- -vi -c -tW -tWM"/>
     <PFLAGS value="  -$Y- -$L- -$D- -$A8 -v -JPHNE -M"/>
     <AFLAGS value="/mx /w2 /zn"/>
     <LFLAGS value="/P128"/>
@@ -47,6 +47,7 @@
   </LINKER>
   <FILELIST>
       <FILE FILENAME="ScpCore.bpf" FORMNAME="" UNITNAME="ScpCore" CONTAINERID="BPF" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="core\Bookmarks.cpp" FORMNAME="" UNITNAME="Bookmarks" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\Common.cpp" FORMNAME="" UNITNAME="Common.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\Configuration.cpp" FORMNAME="" UNITNAME="Configuration.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\CopyParam.cpp" FORMNAME="" UNITNAME="CopyParam.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
@@ -57,7 +58,6 @@
       <FILE FILENAME="core\FileOperationProgress.cpp" FORMNAME="" UNITNAME="FileOperationProgress.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\FileSystems.cpp" FORMNAME="" UNITNAME="FileSystems" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\HierarchicalStorage.cpp" FORMNAME="" UNITNAME="HierarchicalStorage.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="core\KeyGen.cpp" FORMNAME="" UNITNAME="KeyGen" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\NamedObjs.cpp" FORMNAME="" UNITNAME="NamedObjs.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\Net.cpp" FORMNAME="" UNITNAME="Net.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\PuttyIntf.c" FORMNAME="" UNITNAME="PuttyIntf" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
@@ -76,8 +76,6 @@
   <FILES>
     <FILE type="override" value="core\SftpFileSystem.cpp" translator="Auto">
     </FILE>
-    <FILE type="override" value="core\KeyGen.cpp" translator="Auto">
-    </FILE>
   </FILES>
 
   <IDEOPTIONS>

+ 3 - 0
ScpForms.bpf

@@ -10,6 +10,8 @@ USEFORM("forms\Copy.cpp", CopyDialog);
 USEFORM("forms\CopyParams.cpp", CopyParamsFrame); /* TFrame: File Type */
 USEFORM("forms\ComboInput.cpp", ComboInputDialog);
 USEFORM("forms\Editor.cpp", EditorForm);
+USEFORM("forms\FileSystemInfo.cpp", FileSystemInfoDialog);
+USEFORM("forms\FullSynchronize.cpp", FullSynchronizeDialog);
 USEFORM("forms\GeneralSettings.cpp", GeneralSettingsFrame); /* TFrame: File Type */
 USEFORM("forms\ImportSessions.cpp", ImportSessionsDialog);
 USEFORM("forms\Licence.cpp", LicenceDialog);
@@ -26,6 +28,7 @@ USEFORM("forms\Rights.cpp", RightsFrame); /* TFrame: File Type */
 USEFORM("forms\SelectMask.cpp", SelectMaskDialog);
 USEFORM("forms\Symlink.cpp", SymlinkDialog);
 USEFORM("forms\Synchronize.cpp", SynchronizeDialog);
+USEFORM("forms\SynchronizeProgress.cpp", SynchronizeProgressForm);
 //---------------------------------------------------------------------------
 #define Library
 

+ 19 - 14
ScpForms.bpr

@@ -7,22 +7,24 @@
     <OBJFILES value="forms\InputDlg.obj forms\VCLCommon.obj forms\About.obj 
       forms\Cleanup.obj forms\OperationStatus.obj forms\Console.obj 
       forms\Copy.obj forms\CopyParams.obj forms\ComboInput.obj 
-      forms\Editor.obj forms\GeneralSettings.obj forms\ImportSessions.obj 
-      forms\Licence.obj forms\LocationProfiles.obj forms\Log.obj 
-      forms\LogSettings.obj forms\Login.obj forms\OpenDirectory.obj 
-      forms\Password.obj forms\Preferences.obj forms\Progress.obj 
-      forms\Properties.obj forms\Rights.obj forms\SelectMask.obj 
-      forms\Symlink.obj forms\Synchronize.obj"/>
+      forms\Editor.obj forms\FileSystemInfo.obj forms\FullSynchronize.obj 
+      forms\GeneralSettings.obj forms\ImportSessions.obj forms\Licence.obj 
+      forms\LocationProfiles.obj forms\Log.obj forms\LogSettings.obj 
+      forms\Login.obj forms\OpenDirectory.obj forms\Password.obj 
+      forms\Preferences.obj forms\Progress.obj forms\Properties.obj 
+      forms\Rights.obj forms\SelectMask.obj forms\Symlink.obj 
+      forms\Synchronize.obj forms\SynchronizeProgress.obj"/>
     <RESFILES value=""/>
     <DEFFILE value=""/>
     <RESDEPEN value="$(RESFILES) forms\About.dfm forms\Cleanup.dfm forms\OperationStatus.dfm 
       forms\Console.dfm forms\Copy.dfm forms\CopyParams.dfm forms\ComboInput.dfm 
-      forms\Editor.dfm forms\GeneralSettings.dfm forms\ImportSessions.dfm 
-      forms\Licence.dfm forms\LocationProfiles.dfm forms\Log.dfm 
-      forms\LogSettings.dfm forms\Login.dfm forms\OpenDirectory.dfm 
-      forms\Password.dfm forms\Preferences.dfm forms\Progress.dfm 
-      forms\Properties.dfm forms\Rights.dfm forms\SelectMask.dfm 
-      forms\Symlink.dfm forms\Synchronize.dfm"/>
+      forms\Editor.dfm forms\FileSystemInfo.dfm forms\FullSynchronize.dfm 
+      forms\GeneralSettings.dfm forms\ImportSessions.dfm forms\Licence.dfm 
+      forms\LocationProfiles.dfm forms\Log.dfm forms\LogSettings.dfm 
+      forms\Login.dfm forms\OpenDirectory.dfm forms\Password.dfm 
+      forms\Preferences.dfm forms\Progress.dfm forms\Properties.dfm 
+      forms\Rights.dfm forms\SelectMask.dfm forms\Symlink.dfm 
+      forms\Synchronize.dfm forms\SynchronizeProgress.dfm"/>
     <LIBFILES value=""/>
     <LIBRARIES value=""/>
     <SPARELIBS value=""/>
@@ -49,8 +51,8 @@
     <OTHERFILES value=""/>
   </MACROS>
   <OPTIONS>
-    <CFLAG1 value="-O2 -H=c:\PROGRA~1\borland\CBUILD~1\lib\vcl60.csm -Hc -Vx -Ve -X- -a8 -b- 
-      -k- -vi -c -tW -tWM"/>
+    <CFLAG1 value="-O2 -H=c:\PROGRA~1\borland\CBUILD~1\lib\vcl60.csm -Hc -w -Vx -Ve -X- -a8 
+      -b- -k- -vi -c -tW -tWM"/>
     <PFLAGS value="  -$Y- -$L- -$D- -$C- -$A8 -v -JPHNE -M"/>
     <AFLAGS value="/mx /w2 /zn"/>
     <LFLAGS value="/P128"/>
@@ -73,6 +75,8 @@
       <FILE FILENAME="forms\CopyParams.cpp" FORMNAME="CopyParamsFrame" UNITNAME="CopyParams" CONTAINERID="CCompiler" DESIGNCLASS="TFrame" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\ComboInput.cpp" FORMNAME="ComboInputDialog" UNITNAME="ComboInput" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Editor.cpp" FORMNAME="EditorForm" UNITNAME="Editor" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="forms\FileSystemInfo.cpp" FORMNAME="FileSystemInfoDialog" UNITNAME="FileSystemInfo" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="forms\FullSynchronize.cpp" FORMNAME="FullSynchronizeDialog" UNITNAME="FullSynchronize" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\GeneralSettings.cpp" FORMNAME="GeneralSettingsFrame" UNITNAME="GeneralSettings" CONTAINERID="CCompiler" DESIGNCLASS="TFrame" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\ImportSessions.cpp" FORMNAME="ImportSessionsDialog" UNITNAME="ImportSessions" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Licence.cpp" FORMNAME="LicenceDialog" UNITNAME="Licence" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
@@ -89,6 +93,7 @@
       <FILE FILENAME="forms\SelectMask.cpp" FORMNAME="SelectMaskDialog" UNITNAME="SelectMask" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Symlink.cpp" FORMNAME="SymlinkDialog" UNITNAME="Symlink" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Synchronize.cpp" FORMNAME="SynchronizeDialog" UNITNAME="Synchronize" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="forms\SynchronizeProgress.cpp" FORMNAME="SynchronizeProgressForm" UNITNAME="SynchronizeProgress" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
   </FILELIST>
   <BUILDTOOLS>
   </BUILDTOOLS>

+ 23 - 25
WinSCP3.bpr

@@ -4,15 +4,16 @@
   <MACROS>
     <VERSION value="BCB.06.00"/>
     <PROJECT value="WinSCP3.exe"/>
-    <OBJFILES value="windows\WinSCP3.obj windows\Bookmarks.obj windows\CustomScpExplorer.obj 
-      windows\GUIConfiguration.obj windows\NonVisual.obj windows\ProgParams.obj 
+    <OBJFILES value="windows\WinSCP3.obj windows\CustomScpExplorer.obj 
+      windows\CustomWinConfiguration.obj windows\GUIConfiguration.obj 
+      windows\GUITools.obj windows\NonVisual.obj windows\ProgParams.obj 
       windows\ScpCommander.obj windows\ScpExplorer.obj 
       windows\TerminalManager.obj windows\Tools.obj windows\UserInterface.obj 
       windows\WinConfiguration.obj windows\WinInterface.obj windows\WinMain.obj"/>
-    <RESFILES value="resource\TextsWin.res resource\TextsCore.res resource\DirImg.res 
-      resource\Icons.res resource\Manifest.res WinSCP3.res"/>
+    <RESFILES value="windows\Windows.res WinSCP3.res"/>
     <DEFFILE value=""/>
-    <RESDEPEN value="$(RESFILES) forms\CustomScpExplorer.dfm forms\NonVisual.dfm"/>
+    <RESDEPEN value="$(RESFILES) forms\CustomScpExplorer.dfm forms\NonVisual.dfm 
+      forms\ScpCommander.dfm forms\ScpExplorer.dfm"/>
     <LIBFILES value="lib\Putty.lib lib\RScpComp.lib lib\ScpCore.lib lib\ScpForms.lib"/>
     <LIBRARIES value="bcbie.lib visualdbclx.lib bcb2kaxserver.lib indy.lib dbxcds.lib dclocx.lib 
       soaprtl.lib dbexpress.lib inetdbxpress.lib inetdb.lib inetdbbde.lib 
@@ -32,9 +33,9 @@
       inetdbbde.bpi inetdbxpress.bpi inetdb.bpi nmfast.bpi bcbie.bpi soaprtl.bpi 
       dclocx.bpi dbexpress.bpi dbxcds.bpi indy.bpi bcb2kaxserver.bpi 
       visualclx.bpi visualdbclx.bpi"/>
-    <PATHCPP value=".;windows;forms"/>
+    <PATHCPP value=".;forms;windows"/>
     <PATHPAS value=".;"/>
-    <PATHRC value=".;"/>
+    <PATHRC value=".;windows"/>
     <PATHASM value=".;"/>
     <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
     <RELEASELIBPATH value="$(BCB)\lib\release"/>
@@ -43,17 +44,17 @@
     <SYSDEFINES value="NO_STRICT"/>
     <MAINSOURCE value="WinSCP3.cpp"/>
     <INCLUDEPATH value="core;forms;windows;resource;components;packages\filemng;packages\dragndrop;packages\my;packages\my\filemng;$(BCB)\include;$(BCB)\include\vcl"/>
-    <LIBPATH value="lib;windows;forms;$(BCB)\lib\obj;$(BCB)\lib;"/>
+    <LIBPATH value="lib;windows;forms;packages\my\filemng;$(BCB)\lib\obj;$(BCB)\lib;"/>
     <WARNINGS value="-w8092 -w8091 -w8090 -w8089 -w8087 -wprc -wuse -wucp -wstv -wstu -wsig 
       -wpin -wnod -wnak -wdef -wcln -wbbf -wasm -wamp -wamb"/>
     <OTHERFILES value=""/>
   </MACROS>
   <OPTIONS>
-    <CFLAG1 value="-O2 -H=$(BCB)\lib\vcl60.csm -Hc -Vx -Ve -X- -a8 -b- -k- -vi -c -tW -tWM"/>
+    <CFLAG1 value="-O2 -H=$(BCB)\lib\vcl60.csm -Hc -w -Vx -Ve -X- -a8 -b- -k- -vi -c -tW -tWM"/>
     <PFLAGS value="  -$Y- -$L- -$D- -$A8 -v -JPHNE -M"/>
     <RFLAGS value=""/>
     <AFLAGS value="/mx /w2 /zn"/>
-    <LFLAGS value="-I -D&quot;&quot; -aa -Tpe -GD -x -Gn"/>
+    <LFLAGS value="-I -D&quot;&quot; -S:0x1000000 -aa -Tpe -GD -s -Gn"/>
     <OTHERFILES value=""/>
   </OPTIONS>
   <LINKER>
@@ -64,13 +65,14 @@
   </LINKER>
   <FILELIST>
       <FILE FILENAME="WinSCP3.cpp" FORMNAME="" UNITNAME="WinSCP3" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="windows\Bookmarks.cpp" FORMNAME="" UNITNAME="Bookmarks" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\CustomScpExplorer.cpp" FORMNAME="CustomScpExplorerForm" UNITNAME="CustomScpExplorer" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="windows\CustomWinConfiguration.cpp" FORMNAME="" UNITNAME="CustomWinConfiguration" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="windows\GUIConfiguration.cpp" FORMNAME="" UNITNAME="GUIConfiguration" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="windows\GUITools.cpp" FORMNAME="" UNITNAME="GUITools" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\NonVisual.cpp" FORMNAME="NonVisualDataModule" UNITNAME="NonVisual" CONTAINERID="CCompiler" DESIGNCLASS="TDataModule" LOCALCOMMAND=""/>
       <FILE FILENAME="windows\ProgParams.cpp" FORMNAME="" UNITNAME="ProgParams" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="forms\ScpCommander.cpp" FORMNAME="" UNITNAME="ScpCommander" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="forms\ScpExplorer.cpp" FORMNAME="" UNITNAME="ScpExplorer" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="forms\ScpCommander.cpp" FORMNAME="ScpCommanderForm" UNITNAME="ScpCommander" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="forms\ScpExplorer.cpp" FORMNAME="ScpExplorerForm" UNITNAME="ScpExplorer" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="windows\TerminalManager.cpp" FORMNAME="" UNITNAME="TerminalManager" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="windows\Tools.cpp" FORMNAME="" UNITNAME="Tools.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="windows\UserInterface.cpp" FORMNAME="" UNITNAME="UserInterface" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
@@ -81,11 +83,7 @@
       <FILE FILENAME="lib\RScpComp.lib" FORMNAME="" UNITNAME="RScpComp.lib" CONTAINERID="LibTool" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="lib\ScpCore.lib" FORMNAME="" UNITNAME="ScpCore.lib" CONTAINERID="LibTool" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="lib\ScpForms.lib" FORMNAME="" UNITNAME="ScpForms.lib" CONTAINERID="LibTool" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="resource\TextsWin.res" FORMNAME="" UNITNAME="TextsWin.res" CONTAINERID="ResTool" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="resource\TextsCore.res" FORMNAME="" UNITNAME="TextsCore.res" CONTAINERID="ResTool" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="resource\DirImg.res" FORMNAME="" UNITNAME="DirImg.res" CONTAINERID="ResTool" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="resource\Icons.res" FORMNAME="" UNITNAME="Icons.res" CONTAINERID="ResTool" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="resource\Manifest.res" FORMNAME="" UNITNAME="Manifest.res" CONTAINERID="ResTool" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="windows\Windows.rc" FORMNAME="" UNITNAME="Windows.rc" CONTAINERID="RC" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="WinSCP3.res" FORMNAME="" UNITNAME="WinSCP3.res" CONTAINERID="ResTool" DESIGNCLASS="" LOCALCOMMAND=""/>
   </FILELIST>
   <BUILDTOOLS>
@@ -96,9 +94,9 @@
 IncludeVerInfo=1
 AutoIncBuild=1
 MajorVer=3
-MinorVer=4
-Release=2
-Build=197
+MinorVer=5
+Release=0
+Build=204
 Debug=0
 PreRelease=1
 Special=0
@@ -110,13 +108,13 @@ CodePage=1252
 [Version Info Keys]
 CompanyName=Martin Prikryl
 FileDescription=Windows SCP/SFTP client
-FileVersion=3.4.2.197
+FileVersion=3.5.0.204
 InternalName=winscp3
-LegalCopyright=(c) 2000-2003 Martin Prikryl
+LegalCopyright=(c) 2000-2004 Martin Prikryl
 LegalTrademarks=
-OriginalFilename=winscp330.exe
+OriginalFilename=winscp350.exe
 ProductName=WinSCP
-ProductVersion=3.3.0.0
+ProductVersion=3.5.0.0
 WWW=http://winscp.sourceforge.net/
 
 [Compiler]

+ 2 - 2
WinSCP3.cpp

@@ -3,10 +3,11 @@
 #pragma hdrstop
 USEFORM("forms\CustomScpExplorer.cpp", CustomScpExplorerForm);
 USEFORM("forms\NonVisual.cpp", NonVisualDataModule); /* TDataModule: File Type */
+USEFORM("forms\ScpCommander.cpp", ScpCommanderForm);
+USEFORM("forms\ScpExplorer.cpp", ScpExplorerForm);
 //---------------------------------------------------------------------------
 #include <ScpMain.h>
 #include <WinInterface.h>
-#include <UserInterface.h>
 #include <ProgParams.h>
 //---------------------------------------------------------------------------
 WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
@@ -37,4 +38,3 @@ WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
   return 0;
 }
 //---------------------------------------------------------------------------
-

+ 629 - 0
WinSCP3.drc

@@ -0,0 +1,629 @@
+/*
+  Generated by the Borland C++ Incremental Linker
+  because -GD was supplied to the linker.
+
+  It contains compiler-generated resource bound to the executable.
+  If it is empty, no compiler-generated resources were bound to the
+  produced executable.
+*/
+
+#define Consts_SMultiSelectRequired 65216
+#define Consts_SSeparator 65217
+#define Consts_SErrorSettingCount 65218
+#define Consts_SListBoxMustBeVirtual 65219
+#define Consts_sAllFilter 65232
+#define Consts_SInsertLineError 65233
+#define Consts_SInvalidClipFmt 65234
+#define Consts_SIconToClipboard 65235
+#define Consts_SCannotOpenClipboard 65236
+#define Consts_SInvalidMemoSize 65237
+#define Consts_SNoDefaultPrinter 65238
+#define Consts_SDuplicateMenus 65239
+#define Consts_SPictureLabel 65240
+#define Consts_SPictureDesc 65241
+#define Consts_SPreviewLabel 65242
+#define Consts_SCannotOpenAVI 65243
+#define Consts_SDockedCtlNeedsName 65244
+#define Consts_SDockTreeRemoveError 65245
+#define Consts_SDockZoneNotFound 65246
+#define Consts_SDockZoneHasNoCtl 65247
+#define Consts_SmkcSpace 65248
+#define Consts_SmkcPgUp 65249
+#define Consts_SmkcPgDn 65250
+#define Consts_SmkcEnd 65251
+#define Consts_SmkcHome 65252
+#define Consts_SmkcLeft 65253
+#define Consts_SmkcUp 65254
+#define Consts_SmkcRight 65255
+#define Consts_SmkcDown 65256
+#define Consts_SmkcIns 65257
+#define Consts_SmkcDel 65258
+#define Consts_SmkcShift 65259
+#define Consts_SmkcCtrl 65260
+#define Consts_SmkcAlt 65261
+#define Consts_srNone 65262
+#define Consts_SOutOfRange 65263
+#define Consts_SMsgDlgConfirm 65264
+#define Consts_SMsgDlgYes 65265
+#define Consts_SMsgDlgNo 65266
+#define Consts_SMsgDlgOK 65267
+#define Consts_SMsgDlgCancel 65268
+#define Consts_SMsgDlgHelp 65269
+#define Consts_SMsgDlgAbort 65270
+#define Consts_SMsgDlgRetry 65271
+#define Consts_SMsgDlgIgnore 65272
+#define Consts_SMsgDlgAll 65273
+#define Consts_SMsgDlgNoToAll 65274
+#define Consts_SMsgDlgYesToAll 65275
+#define Consts_SmkcBkSp 65276
+#define Consts_SmkcTab 65277
+#define Consts_SmkcEsc 65278
+#define Consts_SmkcEnter 65279
+#define Consts_SHelpButton 65280
+#define Consts_SCloseButton 65281
+#define Consts_SIgnoreButton 65282
+#define Consts_SRetryButton 65283
+#define Consts_SAbortButton 65284
+#define Consts_SAllButton 65285
+#define Consts_SCannotDragForm 65286
+#define Consts_SVMetafiles 65287
+#define Consts_SVEnhMetafiles 65288
+#define Consts_SVIcons 65289
+#define Consts_SVBitmaps 65290
+#define Consts_SMaskErr 65291
+#define Consts_SMaskEditErr 65292
+#define Consts_SMsgDlgWarning 65293
+#define Consts_SMsgDlgError 65294
+#define Consts_SMsgDlgInformation 65295
+#define Consts_SPropertyOutOfRange 65296
+#define Consts_SMenuIndexError 65297
+#define Consts_SMenuReinserted 65298
+#define Consts_SMenuNotFound 65299
+#define Consts_SNoTimers 65300
+#define Consts_SNotPrinting 65301
+#define Consts_SPrinting 65302
+#define Consts_SInvalidPrinter 65303
+#define Consts_SDeviceOnPort 65304
+#define Consts_SGroupIndexTooLow 65305
+#define Consts_SNoMDIForm 65306
+#define Consts_SControlParentSetToSelf 65307
+#define Consts_SOKButton 65308
+#define Consts_SCancelButton 65309
+#define Consts_SYesButton 65310
+#define Consts_SNoButton 65311
+#define Consts_SOutOfResources 65312
+#define Consts_SNoCanvasHandle 65313
+#define Consts_SInvalidImageSize 65314
+#define Consts_SInvalidImageList 65315
+#define Consts_SReplaceImage 65316
+#define Consts_SImageIndexError 65317
+#define Consts_SImageReadFail 65318
+#define Consts_SImageWriteFail 65319
+#define Consts_SWindowDCError 65320
+#define Consts_SWindowClass 65321
+#define Consts_SCannotFocus 65322
+#define Consts_SParentRequired 65323
+#define Consts_SParentGivenNotAParent 65324
+#define Consts_SMDIChildNotVisible 65325
+#define Consts_SVisibleChanged 65326
+#define Consts_SCannotShowModal 65327
+#define Comstrs_sInsertError 65328
+#define Comstrs_sInvalidOwner 65329
+#define Comstrs_sRichEditInsertError 65330
+#define Comstrs_sRichEditLoadFail 65331
+#define Comstrs_sRichEditSaveFail 65332
+#define Comstrs_sPageIndexError 65333
+#define Comstrs_sInvalidComCtl32 65334
+#define Consts_SInvalidTabPosition 65335
+#define Consts_SInvalidTabStyle 65336
+#define Consts_SInvalidBitmap 65337
+#define Consts_SInvalidIcon 65338
+#define Consts_SInvalidMetafile 65339
+#define Consts_SInvalidImage 65340
+#define Consts_SChangeIconSize 65341
+#define Consts_SUnknownExtension 65342
+#define Consts_SUnknownClipboardFormat 65343
+#define Sysconst_SLongDayNameSun 65344
+#define Sysconst_SLongDayNameMon 65345
+#define Sysconst_SLongDayNameTue 65346
+#define Sysconst_SLongDayNameWed 65347
+#define Sysconst_SLongDayNameThu 65348
+#define Sysconst_SLongDayNameFri 65349
+#define Sysconst_SLongDayNameSat 65350
+#define Sysconst_SCannotCreateDir 65351
+#define Comstrs_sTabFailClear 65352
+#define Comstrs_sTabFailDelete 65353
+#define Comstrs_sTabFailRetrieve 65354
+#define Comstrs_sTabFailGetObject 65355
+#define Comstrs_sTabFailSet 65356
+#define Comstrs_sTabFailSetObject 65357
+#define Comstrs_sTabMustBeMultiLine 65358
+#define Comstrs_sInvalidIndex 65359
+#define Sysconst_SLongMonthNameApr 65360
+#define Sysconst_SLongMonthNameMay 65361
+#define Sysconst_SLongMonthNameJun 65362
+#define Sysconst_SLongMonthNameJul 65363
+#define Sysconst_SLongMonthNameAug 65364
+#define Sysconst_SLongMonthNameSep 65365
+#define Sysconst_SLongMonthNameOct 65366
+#define Sysconst_SLongMonthNameNov 65367
+#define Sysconst_SLongMonthNameDec 65368
+#define Sysconst_SShortDayNameSun 65369
+#define Sysconst_SShortDayNameMon 65370
+#define Sysconst_SShortDayNameTue 65371
+#define Sysconst_SShortDayNameWed 65372
+#define Sysconst_SShortDayNameThu 65373
+#define Sysconst_SShortDayNameFri 65374
+#define Sysconst_SShortDayNameSat 65375
+#define Sysconst_SUnkOSError 65376
+#define Sysconst_SShortMonthNameJan 65377
+#define Sysconst_SShortMonthNameFeb 65378
+#define Sysconst_SShortMonthNameMar 65379
+#define Sysconst_SShortMonthNameApr 65380
+#define Sysconst_SShortMonthNameMay 65381
+#define Sysconst_SShortMonthNameJun 65382
+#define Sysconst_SShortMonthNameJul 65383
+#define Sysconst_SShortMonthNameAug 65384
+#define Sysconst_SShortMonthNameSep 65385
+#define Sysconst_SShortMonthNameOct 65386
+#define Sysconst_SShortMonthNameNov 65387
+#define Sysconst_SShortMonthNameDec 65388
+#define Sysconst_SLongMonthNameJan 65389
+#define Sysconst_SLongMonthNameFeb 65390
+#define Sysconst_SLongMonthNameMar 65391
+#define Sysconst_SInvalidVarNullOp 65392
+#define Sysconst_SVarTypeCouldNotConvert 65393
+#define Sysconst_SVarTypeConvertOverflow 65394
+#define Sysconst_SVarOverflow 65395
+#define Sysconst_SVarInvalid 65396
+#define Sysconst_SVarBadType 65397
+#define Sysconst_SVarNotImplemented 65398
+#define Sysconst_SVarUnexpected 65399
+#define Sysconst_SExternalException 65400
+#define Sysconst_SAssertionFailed 65401
+#define Sysconst_SIntfCastError 65402
+#define Sysconst_SSafecallException 65403
+#define Sysconst_SAssertError 65404
+#define Sysconst_SAbstractError 65405
+#define Sysconst_SModuleAccessViolation 65406
+#define Sysconst_SOSError 65407
+#define Sysconst_SOperationAborted 65408
+#define Sysconst_SException 65409
+#define Sysconst_SExceptTitle 65410
+#define Sysconst_SInvalidFormat 65411
+#define Sysconst_SArgumentMissing 65412
+#define Sysconst_SDispatchError 65413
+#define Sysconst_SReadAccess 65414
+#define Sysconst_SWriteAccess 65415
+#define Sysconst_SFormatTooLong 65416
+#define Sysconst_SVarArrayCreate 65417
+#define Sysconst_SVarArrayBounds 65418
+#define Sysconst_SVarArrayLocked 65419
+#define Sysconst_SInvalidVarCast 65420
+#define Sysconst_SInvalidVarOp 65421
+#define Sysconst_SInvalidVarOpWithHResult 65422
+#define Sysconst_SVarNotArray 65423
+#define Sysconst_SEndOfFile 65424
+#define Sysconst_SDiskFull 65425
+#define Sysconst_SInvalidInput 65426
+#define Sysconst_SDivByZero 65427
+#define Sysconst_SRangeError 65428
+#define Sysconst_SIntOverflow 65429
+#define Sysconst_SInvalidOp 65430
+#define Sysconst_SZeroDivide 65431
+#define Sysconst_SOverflow 65432
+#define Sysconst_SUnderflow 65433
+#define Sysconst_SInvalidPointer 65434
+#define Sysconst_SInvalidCast 65435
+#define Sysconst_SAccessViolation 65436
+#define Sysconst_SStackOverflow 65437
+#define Sysconst_SControlC 65438
+#define Sysconst_SPrivilege 65439
+#define Comconst_SNoMethod 65440
+#define Comconst_SVarNotObject 65441
+#define Comconst_STooManyParams 65442
+#define Sysconst_SInvalidInteger 65443
+#define Sysconst_SInvalidFloat 65444
+#define Sysconst_SInvalidDate 65445
+#define Sysconst_SInvalidTime 65446
+#define Sysconst_SInvalidDateTime 65447
+#define Sysconst_STimeEncodeError 65448
+#define Sysconst_SDateEncodeError 65449
+#define Sysconst_SOutOfMemory 65450
+#define Sysconst_SInOutError 65451
+#define Sysconst_SFileNotFound 65452
+#define Sysconst_SInvalidFilename 65453
+#define Sysconst_STooManyOpenFiles 65454
+#define Sysconst_SAccessDenied 65455
+#define Rtlconsts_SListIndexError 65456
+#define Rtlconsts_SMemoryStreamError 65457
+#define Rtlconsts_SPropertyException 65458
+#define Rtlconsts_SReadError 65459
+#define Rtlconsts_SReadOnlyProperty 65460
+#define Rtlconsts_SRegCreateFailed 65461
+#define Rtlconsts_SRegGetDataFailed 65462
+#define Rtlconsts_SRegisterError 65463
+#define Rtlconsts_SRegSetDataFailed 65464
+#define Rtlconsts_SResNotFound 65465
+#define Rtlconsts_SSeekNotImplemented 65466
+#define Rtlconsts_SSortedListError 65467
+#define Rtlconsts_SUnknownGroup 65468
+#define Rtlconsts_SUnknownProperty 65469
+#define Rtlconsts_SWriteError 65470
+#define Comconst_SOleError 65471
+#define Rtlconsts_SDuplicateClass 65472
+#define Rtlconsts_SDuplicateItem 65473
+#define Rtlconsts_SDuplicateName 65474
+#define Rtlconsts_SDuplicateString 65475
+#define Rtlconsts_SFCreateError 65476
+#define Rtlconsts_SFOpenError 65477
+#define Rtlconsts_SIniFileWriteError 65478
+#define Rtlconsts_SInvalidImage 65479
+#define Rtlconsts_SInvalidMask 65480
+#define Rtlconsts_SInvalidName 65481
+#define Rtlconsts_SInvalidProperty 65482
+#define Rtlconsts_SInvalidPropertyPath 65483
+#define Rtlconsts_SInvalidPropertyValue 65484
+#define Rtlconsts_SInvalidRegType 65485
+#define Rtlconsts_SListCapacityError 65486
+#define Rtlconsts_SListCountError 65487
+#define Associatedstatusbar_SDefaultFileInfoFormat 65488
+#define Morebutton_SDefaultExpandedCaption 65489
+#define Morebutton_SDefaultCollapsedCaption 65490
+#define Comboedit_SBrowse 65491
+#define Comboedit_SDefaultFilter 65492
+#define Comboedit_SInvalidFileName 65493
+#define HelpIntfs_16398 65494
+#define HelpIntfs_16400 65495
+#define HelpIntfs_16402 65496
+#define HelpIntfs_16404 65497
+#define Rtlconsts_SAncestorNotFound 65498
+#define Rtlconsts_SAssignError 65499
+#define Rtlconsts_SBitsIndexError 65500
+#define Rtlconsts_SCantWriteResourceStreamError 65501
+#define Rtlconsts_SCheckSynchronizeError 65502
+#define Rtlconsts_SClassNotFound 65503
+#define Dirviewcolproperties_SDirViewExtCol 65504
+#define Customdirview_SErrorOpenFile 65505
+#define Customdirview_SErrorRenameFile 65506
+#define Customdirview_SErrorRenameFileExists 65507
+#define Customdirview_SErrorInvalidName 65508
+#define Customdirview_STextFileExt 65509
+#define Customdirview_STextFiles 65510
+#define Customdirview_STextDirectories 65511
+#define Customdirview_SParentDir 65512
+#define Customdirview_SIconUpdateThreadTerminationError 65513
+#define Customdirview_SDragDropError 65514
+#define Customdirview_SDirNotExists 65515
+#define Customunixdirview_SDragDropDirException 65516
+#define Unixdirviewcolproperties_SUnixDirViewRightsCol 65517
+#define Unixdirviewcolproperties_SUnixDirViewOwnerCol 65518
+#define Unixdirviewcolproperties_SUnixDirViewGroupCol 65519
+#define Dragdrop_MICopyStr 65520
+#define Dragdrop_MIMoveStr 65521
+#define Dragdrop_MILinkStr 65522
+#define Dragdrop_MIAbortStr 65523
+#define Dirview_coFileOperatorTitle 65524
+#define Dirview_coInvalidDosChars 65525
+#define Dirview_Space 65526
+#define Fileoperator_SFileOperation 65527
+#define Baseutils_SNoValidPath 65528
+#define Baseutils_SUcpPathsNotSupported 65529
+#define Iedriveinfo_ErrorInvalidDrive 65530
+#define Dirviewcolproperties_SDirViewNameCol 65531
+#define Dirviewcolproperties_SDirViewSizeCol 65532
+#define Dirviewcolproperties_SDirViewTypeCol 65533
+#define Dirviewcolproperties_SDirViewChangedCol 65534
+#define Dirviewcolproperties_SDirViewAttrCol 65535
+STRINGTABLE
+BEGIN
+	Consts_SMultiSelectRequired,	"Multiselect mode must be on for this feature"
+	Consts_SSeparator,	"Separator"
+	Consts_SErrorSettingCount,	"Error setting %s.Count"
+	Consts_SListBoxMustBeVirtual,	"Listbox (%s) style must be virtual in order to set Count"
+	Consts_sAllFilter,	"All"
+	Consts_SInsertLineError,	"Unable to insert a line"
+	Consts_SInvalidClipFmt,	"Invalid clipboard format"
+	Consts_SIconToClipboard,	"Clipboard does not support Icons"
+	Consts_SCannotOpenClipboard,	"Cannot open clipboard"
+	Consts_SInvalidMemoSize,	"Text exceeds memo capacity"
+	Consts_SNoDefaultPrinter,	"There is no default printer currently selected"
+	Consts_SDuplicateMenus,	"Menu '%s' is already being used by another form"
+	Consts_SPictureLabel,	"Picture:"
+	Consts_SPictureDesc,	" (%dx%d)"
+	Consts_SPreviewLabel,	"Preview"
+	Consts_SCannotOpenAVI,	"Cannot open AVI"
+	Consts_SDockedCtlNeedsName,	"Docked control must have a name"
+	Consts_SDockTreeRemoveError,	"Error removing control from dock tree"
+	Consts_SDockZoneNotFound,	" - Dock zone not found"
+	Consts_SDockZoneHasNoCtl,	" - Dock zone has no control"
+	Consts_SmkcSpace,	"Space"
+	Consts_SmkcPgUp,	"PgUp"
+	Consts_SmkcPgDn,	"PgDn"
+	Consts_SmkcEnd,	"End"
+	Consts_SmkcHome,	"Home"
+	Consts_SmkcLeft,	"Left"
+	Consts_SmkcUp,	"Up"
+	Consts_SmkcRight,	"Right"
+	Consts_SmkcDown,	"Down"
+	Consts_SmkcIns,	"Ins"
+	Consts_SmkcDel,	"Del"
+	Consts_SmkcShift,	"Shift+"
+	Consts_SmkcCtrl,	"Ctrl+"
+	Consts_SmkcAlt,	"Alt+"
+	Consts_srNone,	"(None)"
+	Consts_SOutOfRange,	"Value must be between %d and %d"
+	Consts_SMsgDlgConfirm,	"Confirm"
+	Consts_SMsgDlgYes,	"&Yes"
+	Consts_SMsgDlgNo,	"&No"
+	Consts_SMsgDlgOK,	"OK"
+	Consts_SMsgDlgCancel,	"Cancel"
+	Consts_SMsgDlgHelp,	"&Help"
+	Consts_SMsgDlgAbort,	"&Abort"
+	Consts_SMsgDlgRetry,	"&Retry"
+	Consts_SMsgDlgIgnore,	"&Ignore"
+	Consts_SMsgDlgAll,	"&All"
+	Consts_SMsgDlgNoToAll,	"N&o to All"
+	Consts_SMsgDlgYesToAll,	"Yes to &All"
+	Consts_SmkcBkSp,	"BkSp"
+	Consts_SmkcTab,	"Tab"
+	Consts_SmkcEsc,	"Esc"
+	Consts_SmkcEnter,	"Enter"
+	Consts_SHelpButton,	"&Help"
+	Consts_SCloseButton,	"&Close"
+	Consts_SIgnoreButton,	"&Ignore"
+	Consts_SRetryButton,	"&Retry"
+	Consts_SAbortButton,	"Abort"
+	Consts_SAllButton,	"&All"
+	Consts_SCannotDragForm,	"Cannot drag a form"
+	Consts_SVMetafiles,	"Metafiles"
+	Consts_SVEnhMetafiles,	"Enhanced Metafiles"
+	Consts_SVIcons,	"Icons"
+	Consts_SVBitmaps,	"Bitmaps"
+	Consts_SMaskErr,	"Invalid input value"
+	Consts_SMaskEditErr,	"Invalid input value.  Use escape key to abandon changes"
+	Consts_SMsgDlgWarning,	"Warning"
+	Consts_SMsgDlgError,	"Error"
+	Consts_SMsgDlgInformation,	"Information"
+	Consts_SPropertyOutOfRange,	"%s property out of range"
+	Consts_SMenuIndexError,	"Menu index out of range"
+	Consts_SMenuReinserted,	"Menu inserted twice"
+	Consts_SMenuNotFound,	"Sub-menu is not in menu"
+	Consts_SNoTimers,	"Not enough timers available"
+	Consts_SNotPrinting,	"Printer is not currently printing"
+	Consts_SPrinting,	"Printing in progress"
+	Consts_SInvalidPrinter,	"Printer selected is not valid"
+	Consts_SDeviceOnPort,	"%s on %s"
+	Consts_SGroupIndexTooLow,	"GroupIndex cannot be less than a previous menu item's GroupIndex"
+	Consts_SNoMDIForm,	"Cannot create form. No MDI forms are currently active"
+	Consts_SControlParentSetToSelf,	"A control cannot have itself as its parent"
+	Consts_SOKButton,	"OK"
+	Consts_SCancelButton,	"Cancel"
+	Consts_SYesButton,	"&Yes"
+	Consts_SNoButton,	"&No"
+	Consts_SOutOfResources,	"Out of system resources"
+	Consts_SNoCanvasHandle,	"Canvas does not allow drawing"
+	Consts_SInvalidImageSize,	"Invalid image size"
+	Consts_SInvalidImageList,	"Invalid ImageList"
+	Consts_SReplaceImage,	"Unable to Replace Image"
+	Consts_SImageIndexError,	"Invalid ImageList Index"
+	Consts_SImageReadFail,	"Failed to read ImageList data from stream"
+	Consts_SImageWriteFail,	"Failed to write ImageList data to stream"
+	Consts_SWindowDCError,	"Error creating window device context"
+	Consts_SWindowClass,	"Error creating window class"
+	Consts_SCannotFocus,	"Cannot focus a disabled or invisible window"
+	Consts_SParentRequired,	"Control '%s' has no parent window"
+	Consts_SParentGivenNotAParent,	"Parent given is not a parent of '%s'"
+	Consts_SMDIChildNotVisible,	"Cannot hide an MDI Child Form"
+	Consts_SVisibleChanged,	"Cannot change Visible in OnShow or OnHide"
+	Consts_SCannotShowModal,	"Cannot make a visible window modal"
+	Comstrs_sInsertError,	"Unable to insert an item"
+	Comstrs_sInvalidOwner,	"Invalid owner"
+	Comstrs_sRichEditInsertError,	"RichEdit line insertion error"
+	Comstrs_sRichEditLoadFail,	"Failed to Load Stream"
+	Comstrs_sRichEditSaveFail,	"Failed to Save Stream"
+	Comstrs_sPageIndexError,	"%d is an invalid PageIndex value.  PageIndex must be between 0 and %d"
+	Comstrs_sInvalidComCtl32,	"This control requires version 4.70 or greater of COMCTL32.DLL"
+	Consts_SInvalidTabPosition,	"Tab position incompatible with current tab style"
+	Consts_SInvalidTabStyle,	"Tab style incompatible with current tab position"
+	Consts_SInvalidBitmap,	"Bitmap image is not valid"
+	Consts_SInvalidIcon,	"Icon image is not valid"
+	Consts_SInvalidMetafile,	"Metafile is not valid"
+	Consts_SInvalidImage,	"Invalid image"
+	Consts_SChangeIconSize,	"Cannot change the size of an icon"
+	Consts_SUnknownExtension,	"Unknown picture file extension (.%s)"
+	Consts_SUnknownClipboardFormat,	"Unsupported clipboard format"
+	Sysconst_SLongDayNameSun,	"Sunday"
+	Sysconst_SLongDayNameMon,	"Monday"
+	Sysconst_SLongDayNameTue,	"Tuesday"
+	Sysconst_SLongDayNameWed,	"Wednesday"
+	Sysconst_SLongDayNameThu,	"Thursday"
+	Sysconst_SLongDayNameFri,	"Friday"
+	Sysconst_SLongDayNameSat,	"Saturday"
+	Sysconst_SCannotCreateDir,	"Unable to create directory"
+	Comstrs_sTabFailClear,	"Failed to clear tab control"
+	Comstrs_sTabFailDelete,	"Failed to delete tab at index %d"
+	Comstrs_sTabFailRetrieve,	"Failed to retrieve tab at index %d"
+	Comstrs_sTabFailGetObject,	"Failed to get object at index %d"
+	Comstrs_sTabFailSet,	"Failed to set tab \"%s\" at index %d"
+	Comstrs_sTabFailSetObject,	"Failed to set object at index %d"
+	Comstrs_sTabMustBeMultiLine,	"MultiLine must be True when TabPosition is tpLeft or tpRight"
+	Comstrs_sInvalidIndex,	"Invalid index"
+	Sysconst_SLongMonthNameApr,	"April"
+	Sysconst_SLongMonthNameMay,	"May"
+	Sysconst_SLongMonthNameJun,	"June"
+	Sysconst_SLongMonthNameJul,	"July"
+	Sysconst_SLongMonthNameAug,	"August"
+	Sysconst_SLongMonthNameSep,	"September"
+	Sysconst_SLongMonthNameOct,	"October"
+	Sysconst_SLongMonthNameNov,	"November"
+	Sysconst_SLongMonthNameDec,	"December"
+	Sysconst_SShortDayNameSun,	"Sun"
+	Sysconst_SShortDayNameMon,	"Mon"
+	Sysconst_SShortDayNameTue,	"Tue"
+	Sysconst_SShortDayNameWed,	"Wed"
+	Sysconst_SShortDayNameThu,	"Thu"
+	Sysconst_SShortDayNameFri,	"Fri"
+	Sysconst_SShortDayNameSat,	"Sat"
+	Sysconst_SUnkOSError,	"A call to an OS function failed"
+	Sysconst_SShortMonthNameJan,	"Jan"
+	Sysconst_SShortMonthNameFeb,	"Feb"
+	Sysconst_SShortMonthNameMar,	"Mar"
+	Sysconst_SShortMonthNameApr,	"Apr"
+	Sysconst_SShortMonthNameMay,	"May"
+	Sysconst_SShortMonthNameJun,	"Jun"
+	Sysconst_SShortMonthNameJul,	"Jul"
+	Sysconst_SShortMonthNameAug,	"Aug"
+	Sysconst_SShortMonthNameSep,	"Sep"
+	Sysconst_SShortMonthNameOct,	"Oct"
+	Sysconst_SShortMonthNameNov,	"Nov"
+	Sysconst_SShortMonthNameDec,	"Dec"
+	Sysconst_SLongMonthNameJan,	"January"
+	Sysconst_SLongMonthNameFeb,	"February"
+	Sysconst_SLongMonthNameMar,	"March"
+	Sysconst_SInvalidVarNullOp,	"Invalid NULL variant operation"
+	Sysconst_SVarTypeCouldNotConvert,	"Could not convert variant of type (%s) into type (%s)"
+	Sysconst_SVarTypeConvertOverflow,	"Overflow while converting variant of type (%s) into type (%s)"
+	Sysconst_SVarOverflow,	"Variant overflow"
+	Sysconst_SVarInvalid,	"Invalid argument"
+	Sysconst_SVarBadType,	"Invalid variant type"
+	Sysconst_SVarNotImplemented,	"Operation not supported"
+	Sysconst_SVarUnexpected,	"Unexpected variant error"
+	Sysconst_SExternalException,	"External exception %x"
+	Sysconst_SAssertionFailed,	"Assertion failed"
+	Sysconst_SIntfCastError,	"Interface not supported"
+	Sysconst_SSafecallException,	"Exception in safecall method"
+	Sysconst_SAssertError,	"%s (%s, line %d)"
+	Sysconst_SAbstractError,	"Abstract Error"
+	Sysconst_SModuleAccessViolation,	"Access violation at address %p in module '%s'. %s of address %p"
+	Sysconst_SOSError,	"System Error.  Code: %d.\r\n%s"
+	Sysconst_SOperationAborted,	"Operation aborted"
+	Sysconst_SException,	"Exception %s in module %s at %p.\r\n%s%s\r\n"
+	Sysconst_SExceptTitle,	"Application Error"
+	Sysconst_SInvalidFormat,	"Format '%s' invalid or incompatible with argument"
+	Sysconst_SArgumentMissing,	"No argument for format '%s'"
+	Sysconst_SDispatchError,	"Variant method calls not supported"
+	Sysconst_SReadAccess,	"Read"
+	Sysconst_SWriteAccess,	"Write"
+	Sysconst_SFormatTooLong,	"Format string too long"
+	Sysconst_SVarArrayCreate,	"Error creating variant array"
+	Sysconst_SVarArrayBounds,	"Variant array index out of bounds"
+	Sysconst_SVarArrayLocked,	"Variant array is locked"
+	Sysconst_SInvalidVarCast,	"Invalid variant type conversion"
+	Sysconst_SInvalidVarOp,	"Invalid variant operation"
+	Sysconst_SInvalidVarOpWithHResult,	"Invalid variant operation ($%.8x)"
+	Sysconst_SVarNotArray,	"Variant is not an array"
+	Sysconst_SEndOfFile,	"Read beyond end of file"
+	Sysconst_SDiskFull,	"Disk full"
+	Sysconst_SInvalidInput,	"Invalid numeric input"
+	Sysconst_SDivByZero,	"Division by zero"
+	Sysconst_SRangeError,	"Range check error"
+	Sysconst_SIntOverflow,	"Integer overflow"
+	Sysconst_SInvalidOp,	"Invalid floating point operation"
+	Sysconst_SZeroDivide,	"Floating point division by zero"
+	Sysconst_SOverflow,	"Floating point overflow"
+	Sysconst_SUnderflow,	"Floating point underflow"
+	Sysconst_SInvalidPointer,	"Invalid pointer operation"
+	Sysconst_SInvalidCast,	"Invalid class typecast"
+	Sysconst_SAccessViolation,	"Access violation at address %p. %s of address %p"
+	Sysconst_SStackOverflow,	"Stack overflow"
+	Sysconst_SControlC,	"Control-C hit"
+	Sysconst_SPrivilege,	"Privileged instruction"
+	Comconst_SNoMethod,	"Method '%s' not supported by automation object"
+	Comconst_SVarNotObject,	"Variant does not reference an automation object"
+	Comconst_STooManyParams,	"Dispatch methods do not support more than 64 parameters"
+	Sysconst_SInvalidInteger,	"'%s' is not a valid integer value"
+	Sysconst_SInvalidFloat,	"'%s' is not a valid floating point value"
+	Sysconst_SInvalidDate,	"'%s' is not a valid date"
+	Sysconst_SInvalidTime,	"'%s' is not a valid time"
+	Sysconst_SInvalidDateTime,	"'%s' is not a valid date and time"
+	Sysconst_STimeEncodeError,	"Invalid argument to time encode"
+	Sysconst_SDateEncodeError,	"Invalid argument to date encode"
+	Sysconst_SOutOfMemory,	"Out of memory"
+	Sysconst_SInOutError,	"I/O error %d"
+	Sysconst_SFileNotFound,	"File not found"
+	Sysconst_SInvalidFilename,	"Invalid filename"
+	Sysconst_STooManyOpenFiles,	"Too many open files"
+	Sysconst_SAccessDenied,	"File access denied"
+	Rtlconsts_SListIndexError,	"List index out of bounds (%d)"
+	Rtlconsts_SMemoryStreamError,	"Out of memory while expanding memory stream"
+	Rtlconsts_SPropertyException,	"Error reading %s%s%s: %s"
+	Rtlconsts_SReadError,	"Stream read error"
+	Rtlconsts_SReadOnlyProperty,	"Property is read-only"
+	Rtlconsts_SRegCreateFailed,	"Failed to create key %s"
+	Rtlconsts_SRegGetDataFailed,	"Failed to get data for '%s'"
+	Rtlconsts_SRegisterError,	"Invalid component registration"
+	Rtlconsts_SRegSetDataFailed,	"Failed to set data for '%s'"
+	Rtlconsts_SResNotFound,	"Resource %s not found"
+	Rtlconsts_SSeekNotImplemented,	"%s.Seek not implemented"
+	Rtlconsts_SSortedListError,	"Operation not allowed on sorted list"
+	Rtlconsts_SUnknownGroup,	"%s not in a class registration group"
+	Rtlconsts_SUnknownProperty,	"Property %s does not exist"
+	Rtlconsts_SWriteError,	"Stream write error"
+	Comconst_SOleError,	"OLE error %.8x"
+	Rtlconsts_SDuplicateClass,	"A class named %s already exists"
+	Rtlconsts_SDuplicateItem,	"List does not allow duplicates ($0%x)"
+	Rtlconsts_SDuplicateName,	"A component named %s already exists"
+	Rtlconsts_SDuplicateString,	"String list does not allow duplicates"
+	Rtlconsts_SFCreateError,	"Cannot create file %s"
+	Rtlconsts_SFOpenError,	"Cannot open file %s"
+	Rtlconsts_SIniFileWriteError,	"Unable to write to %s"
+	Rtlconsts_SInvalidImage,	"Invalid stream format"
+	Rtlconsts_SInvalidMask,	"'%s' is an invalid mask at (%d)"
+	Rtlconsts_SInvalidName,	"''%s'' is not a valid component name"
+	Rtlconsts_SInvalidProperty,	"Invalid property value"
+	Rtlconsts_SInvalidPropertyPath,	"Invalid property path"
+	Rtlconsts_SInvalidPropertyValue,	"Invalid property value"
+	Rtlconsts_SInvalidRegType,	"Invalid data type for '%s'"
+	Rtlconsts_SListCapacityError,	"List capacity out of bounds (%d)"
+	Rtlconsts_SListCountError,	"List count out of bounds (%d)"
+	Associatedstatusbar_SDefaultFileInfoFormat,	"%s of %s in %s of %s"
+	Morebutton_SDefaultExpandedCaption,	"<< &Less"
+	Morebutton_SDefaultCollapsedCaption,	"&More >>"
+	Comboedit_SBrowse,	"Browse"
+	Comboedit_SDefaultFilter,	"All files (*.*)|*.*"
+	Comboedit_SInvalidFileName,	"Invalid file name - %s"
+	HelpIntfs_16398,	"Unable to find a Table of Contents"
+	HelpIntfs_16400,	"No help found for %s"
+	HelpIntfs_16402,	"No context-sensitive help installed"
+	HelpIntfs_16404,	"No topic-based help system installed"
+	Rtlconsts_SAncestorNotFound,	"Ancestor for '%s' not found"
+	Rtlconsts_SAssignError,	"Cannot assign a %s to a %s"
+	Rtlconsts_SBitsIndexError,	"Bits index out of range"
+	Rtlconsts_SCantWriteResourceStreamError,	"Can't write to a read-only resource stream"
+	Rtlconsts_SCheckSynchronizeError,	"CheckSynchronize called from thread $%x, which is NOT the main thread"
+	Rtlconsts_SClassNotFound,	"Class %s not found"
+	Dirviewcolproperties_SDirViewExtCol,	"Ext"
+	Customdirview_SErrorOpenFile,	"Can't open file: "
+	Customdirview_SErrorRenameFile,	"Can't rename file or directory: "
+	Customdirview_SErrorRenameFileExists,	"File already exists: "
+	Customdirview_SErrorInvalidName,	"Filename contains invalid characters:"
+	Customdirview_STextFileExt,	"File %s"
+	Customdirview_STextFiles,	"%u Files"
+	Customdirview_STextDirectories,	"%u Directories"
+	Customdirview_SParentDir,	"Parent directory"
+	Customdirview_SIconUpdateThreadTerminationError,	"Can't terminate icon update thread."
+	Customdirview_SDragDropError,	"DragDrop Error: %d"
+	Customdirview_SDirNotExists,	"Directory '%s' doesn't exist."
+	Customunixdirview_SDragDropDirException,	"Can't create temporary drag&drop directory '%s'."
+	Unixdirviewcolproperties_SUnixDirViewRightsCol,	"Rights"
+	Unixdirviewcolproperties_SUnixDirViewOwnerCol,	"Owner"
+	Unixdirviewcolproperties_SUnixDirViewGroupCol,	"Group"
+	Dragdrop_MICopyStr,	"&Copy Here"
+	Dragdrop_MIMoveStr,	"&Move Here"
+	Dragdrop_MILinkStr,	"&Shortcut(s) Create Here"
+	Dragdrop_MIAbortStr,	"&Abort"
+	Dirview_coFileOperatorTitle,	"Filesystem Operation"
+	Dirview_coInvalidDosChars,	"\\/:*?\"<>|"
+	Dirview_Space,	" "
+	Fileoperator_SFileOperation,	"File Operation"
+	Baseutils_SNoValidPath,	"Can't find any valid path."
+	Baseutils_SUcpPathsNotSupported,	"UNC paths are not supported."
+	Iedriveinfo_ErrorInvalidDrive,	"%s is a invalid drive letter."
+	Dirviewcolproperties_SDirViewNameCol,	"Name"
+	Dirviewcolproperties_SDirViewSizeCol,	"Size"
+	Dirviewcolproperties_SDirViewTypeCol,	"Type"
+	Dirviewcolproperties_SDirViewChangedCol,	"Changed"
+	Dirviewcolproperties_SDirViewAttrCol,	"Attr"
+END
+

BIN
WinSCP3.res


+ 1 - 0
components/LogMemo.cpp

@@ -91,6 +91,7 @@ void __fastcall TLogMemo::SetSessionLog(TSessionLog * value)
 void __fastcall TLogMemo::SessionLogChange(TObject * Sender)
 {
 #ifndef DESIGN_ONLY
+  USEDPARAM(Sender);
   assert(Sender && (Sender == SessionLog));
 #endif
   UpdateFromLog();

+ 1 - 1
windows/Bookmarks.cpp → core/Bookmarks.cpp

@@ -4,7 +4,7 @@
 #include <Common.h>
 #include "Bookmarks.h"
 #include "HierarchicalStorage.h"
-#include "TextsWin.h"
+#include "TextsCore.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------

+ 0 - 0
windows/Bookmarks.h → core/Bookmarks.h


+ 194 - 0
core/Common.cpp

@@ -5,6 +5,8 @@
 #include "Common.h"
 #include "Exceptions.h"
 #include "TextsCore.h"
+#include <math.h>
+#include <shellapi.h>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
@@ -219,6 +221,56 @@ AnsiString __fastcall FormatCommand(AnsiString Program, AnsiString Params)
   return Program + Params;
 }
 //---------------------------------------------------------------------------
+bool __fastcall IsDisplayableStr(const AnsiString Str)
+{
+  bool Displayable = true;
+  int Index = 1;
+  while ((Index <= Str.Length()) && Displayable)
+  {
+    if (Str[Index] < '\32')
+    {
+      Displayable = false;
+    }
+    Index++;
+  }
+  return Displayable;
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall StrToHex(const AnsiString Str)
+{
+  AnsiString Result;
+  for (int i = 1; i <= Str.Length(); i++)
+  {
+    Result += IntToHex(Str[i], 2);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall HexToStr(const AnsiString Hex)
+{
+  static AnsiString Digits = "01234556789ABCDEF";
+  AnsiString Result;
+  int L, P1, P2;
+  L = Hex.Length();
+  if (L % 2 == 0)
+  {
+    for (int i = 1; i <= Hex.Length(); i += 2)
+    {
+      P1 = Digits.Pos(Hex[i]);
+      P2 = Digits.Pos(Hex[i + 1]);
+      if (P1 <= 0 || P2 <= 0)
+      {
+        break;
+      }
+      else
+      {
+        Result += static_cast<char>((P1 - 1) * 16 + P2 - 1);
+      }
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 bool __fastcall FileSearchRec(const AnsiString FileName, TSearchRec & Rec)
 {
   int FindAttrs = faReadOnly | faHidden | faSysFile | faDirectory | faArchive;
@@ -266,4 +318,146 @@ void __fastcall ProcessLocalDirectory(AnsiString DirName,
     }
   }
 }
+//---------------------------------------------------------------------------
+void __fastcall DateTimeParams(TDateTime * AUnixEpoch,
+  double * ADifference, long * ADifferenceSec)
+{
+  static double Difference;
+  static long DifferenceSec;
+  static TDateTime UnixEpoch = 0;
+
+  if (double(UnixEpoch) == 0)
+  {
+    TIME_ZONE_INFORMATION TZI;
+    unsigned long GTZI;
+
+    GTZI = GetTimeZoneInformation(&TZI);
+    switch (GTZI) {
+      case TIME_ZONE_ID_UNKNOWN:
+        Difference = 0;
+        break;
+
+      case TIME_ZONE_ID_STANDARD:
+        DifferenceSec = TZI.Bias + TZI.StandardBias;
+        break;
+
+      case TIME_ZONE_ID_DAYLIGHT:
+        DifferenceSec = TZI.Bias + TZI.DaylightBias;
+        break;
+
+      case TIME_ZONE_ID_INVALID:
+      default:
+        throw Exception(TIMEZONE_ERROR);
+    }
+    // Is it same as SysUtils::UnixDateDelta = 25569 ??
+    UnixEpoch = EncodeDate(1970, 1, 1);
+    Difference = double(DifferenceSec) / 1440;
+    DifferenceSec *= 60;
+  }
+  if (AUnixEpoch) *AUnixEpoch = UnixEpoch;
+  if (ADifference) *ADifference = Difference;
+  if (ADifferenceSec) *ADifferenceSec = DifferenceSec;
+}
+//---------------------------------------------------------------------------
+TDateTime __fastcall UnixToDateTime(unsigned long TimeStamp)
+{
+  TDateTime UnixEpoch;
+  double Difference;
+  DateTimeParams(&UnixEpoch, &Difference, NULL);
+
+  TDateTime Result;
+  Result = UnixEpoch + (double(TimeStamp) / 86400) - Difference;
+  return Result;
+}
+//---------------------------------------------------------------------------
+inline __int64 __fastcall Round(double Number)
+{
+  double Floor = floor(Number);
+  double Ceil = ceil(Number);
+  return ((Number - Floor) > (Ceil - Number)) ? Ceil : Floor;
+}
+//---------------------------------------------------------------------------
+FILETIME __fastcall DateTimeToFileTime(const TDateTime DateTime)
+{
+  __int64 UnixTimeStamp;
+  FILETIME Result;
+  TDateTime UnixEpoch;
+  long Difference;
+
+  DateTimeParams(&UnixEpoch, NULL, &Difference);
+  UnixTimeStamp = Round(double(DateTime - UnixEpoch) * 86400) + Difference;
+  TIME_POSIX_TO_WIN(UnixTimeStamp, Result);
+  return Result;
+}
+//---------------------------------------------------------------------------
+TDateTime __fastcall AdjustDateTimeFromUnix(const TDateTime DateTime)
+{
+  // to be implemented
+  return DateTime;
+}
+//---------------------------------------------------------------------------
+__inline static bool __fastcall UnifySignificance(unsigned short & V1,
+  unsigned short & V2)
+{
+  bool Result = (V1 == 0) || (V2 == 0);
+  if (Result)
+  {
+    V1 = 0;
+    V2 = 0;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall UnifyDateTimePrecision(TDateTime & DateTime1, TDateTime & DateTime2)
+{
+  unsigned short Y1, M1, D1, H1, N1, S1, MS1;
+  unsigned short Y2, M2, D2, H2, N2, S2, MS2;
+  bool Changed;
+
+  if (DateTime1 != DateTime2)
+  {
+    DateTime1.DecodeDate(&Y1, &M1, &D1);
+    DateTime1.DecodeTime(&H1, &N1, &S1, &MS1);
+    DateTime2.DecodeDate(&Y2, &M2, &D2);
+    DateTime2.DecodeTime(&H2, &N2, &S2, &MS2);
+    Changed = UnifySignificance(MS1, MS2);
+    if (Changed && UnifySignificance(S1, S2) && UnifySignificance(N1, N2) &&
+        UnifySignificance(H1, H2) && UnifySignificance(D1, D2) &&
+        UnifySignificance(M1, M2))
+    {
+      UnifySignificance(Y1, Y2);
+    }
+    if (Changed)
+    {
+      DateTime1 = EncodeDate(Y1, M1, D1) + EncodeTime(H1, N1, S1, MS1);
+      DateTime2 = EncodeDate(Y2, M2, D2) + EncodeTime(H2, N2, S2, MS2);
+    }
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall RecursiveDeleteFile(const AnsiString FileName, bool ToRecycleBin)
+{
+  SHFILEOPSTRUCT Data;
 
+  memset(&Data, 0, sizeof(Data)); 
+  Data.hwnd = Application->Handle;
+  Data.wFunc = FO_DELETE;
+  AnsiString FileList(FileName);
+  FileList.SetLength(FileList.Length() + 2);
+  FileList[FileList.Length() - 1] = '\0';
+  FileList[FileList.Length()] = '\0';
+  Data.pFrom = FileList.c_str();
+  Data.pTo = "";
+  Data.fFlags = FOF_NOCONFIRMATION | FOF_RENAMEONCOLLISION | FOF_NOCONFIRMMKDIR |
+    FOF_NOERRORUI | FOF_SILENT;
+  if (ToRecycleBin)
+  {
+    Data.fFlags |= FOF_ALLOWUNDO;
+  }
+  int Result = SHFileOperation(&Data);
+  if (Result != 0)
+  {
+    //Win32Check(false);
+  }
+  return (Result == 0);
+}

+ 14 - 0
core/Common.h

@@ -35,6 +35,10 @@ AnsiString __fastcall AddPathQuotes(AnsiString Path);
 void __fastcall SplitCommand(AnsiString Command, AnsiString &Program,
   AnsiString & Params, AnsiString & Dir);
 AnsiString __fastcall FormatCommand(AnsiString Program, AnsiString Params);
+bool __fastcall IsDisplayableStr(const AnsiString Str);
+AnsiString __fastcall StrToHex(const AnsiString Str);
+AnsiString __fastcall HexToStr(const AnsiString Hex);
+bool __fastcall RecursiveDeleteFile(const AnsiString FileName, bool ToRecycleBin);
 //---------------------------------------------------------------------------
 typedef void __fastcall (__closure *TProcessLocalFileEvent)
   (const AnsiString FileName, const TSearchRec Rec, void * Param);
@@ -42,6 +46,16 @@ bool __fastcall FileSearchRec(const AnsiString FileName, TSearchRec & Rec);
 void __fastcall ProcessLocalDirectory(AnsiString DirName,
   TProcessLocalFileEvent CallBackFunc, void * Param = NULL, int FindAttrs = -1);
 //---------------------------------------------------------------------------
+#define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
+    ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
+#define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
+    ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
+TDateTime __fastcall UnixToDateTime(unsigned long TimeStamp);
+FILETIME __fastcall DateTimeToFileTime(const TDateTime DateTime);
+TDateTime __fastcall UnixToDateTime(unsigned long TimeStamp);
+TDateTime __fastcall AdjustDateTimeFromUnix(const TDateTime DateTime);
+void __fastcall UnifyDateTimePrecision(TDateTime & DateTime1, TDateTime & DateTime2);
+//---------------------------------------------------------------------------
 #endif
 //---------------------------------------------------------------------------
 #include <assert.h>

+ 47 - 19
core/Configuration.cpp

@@ -2,7 +2,6 @@
 #include <vcl.h>
 #pragma hdrstop
 
-#include <shlobj.hpp>
 #include <FileInfo.h>
 
 #include "Exceptions.h"
@@ -14,19 +13,6 @@
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
-bool SpecialFolderLocation(int PathID, AnsiString & Path)
-{
-  LPITEMIDLIST Pidl;
-  char Buf[256];
-  if (SHGetSpecialFolderLocation(NULL, PathID, &Pidl) == NO_ERROR &&
-      SHGetPathFromIDList(Pidl, Buf))
-  {
-    Path = AnsiString(Buf);
-    return true;
-  }
-  return false;
-}
-//---------------------------------------------------------------------------
 __fastcall TConfiguration::TConfiguration()
 {
   FUpdating = 0;
@@ -168,6 +154,47 @@ void __fastcall TConfiguration::Load()
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TConfiguration::LoadDirectoryChangesCache(const AnsiString SessionKey,
+  TRemoteDirectoryChangesCache * DirectoryChangesCache)
+{
+  THierarchicalStorage * Storage = CreateScpStorage(false); 
+  try
+  {
+    Storage->AccessMode = smRead;
+    if (Storage->OpenSubKey(ConfigurationSubKey, false) &&
+        Storage->OpenSubKey("CDCache", false) &&
+        Storage->ValueExists(SessionKey))
+    {
+      DirectoryChangesCache->Deserialize(Storage->ReadBinaryData(SessionKey));
+    }
+  }
+  __finally
+  {
+    delete Storage;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TConfiguration::SaveDirectoryChangesCache(const AnsiString SessionKey,
+  TRemoteDirectoryChangesCache * DirectoryChangesCache)
+{
+  THierarchicalStorage * Storage = CreateScpStorage(false); 
+  try
+  {
+    Storage->AccessMode = smReadWrite;
+    if (Storage->OpenSubKey(ConfigurationSubKey, true) &&
+        Storage->OpenSubKey("CDCache", true))
+    {
+      AnsiString Data;
+      DirectoryChangesCache->Serialize(Data);
+      Storage->WriteBinaryData(SessionKey, Data);
+    }
+  }
+  __finally
+  {
+    delete Storage;
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TConfiguration::Changed()
 {
   if (FUpdating == 0)
@@ -307,7 +334,8 @@ AnsiString __fastcall TConfiguration::GetProductVersion()
 //---------------------------------------------------------------------------
 AnsiString __fastcall TConfiguration::TrimVersion(AnsiString Version)
 {
-  while (Version.SubString(Version.Length() - 1, 2) == ".0")
+  while ((Version.Pos(".") != Version.LastDelimiter(".")) &&
+    (Version.SubString(Version.Length() - 1, 2) == ".0"))
   {
     Version.SetLength(Version.Length() - 2);
   }
@@ -335,10 +363,10 @@ AnsiString __fastcall TConfiguration::GetVersion()
   try
   {
     AnsiString Result;
-    Result = TrimVersion(FORMAT("%d.%d.%d.%d", (HIWORD(FixedApplicationInfo->dwFileVersionMS),
+    Result = TrimVersion(FORMAT("%d.%d.%d", (
+      HIWORD(FixedApplicationInfo->dwFileVersionMS),
       LOWORD(FixedApplicationInfo->dwFileVersionMS),
-      HIWORD(FixedApplicationInfo->dwFileVersionLS),
-      LOWORD(FixedApplicationInfo->dwFileVersionLS))));
+      HIWORD(FixedApplicationInfo->dwFileVersionLS))));
     return Result;
   }
   catch (Exception &E)
@@ -402,7 +430,7 @@ AnsiString __fastcall TConfiguration::GetPuttySessionsKey()
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TConfiguration::GetStoredSessionsSubKey()
-{
+{   
   return "Sessions";
 }
 //---------------------------------------------------------------------------

+ 4 - 2
core/Configuration.h

@@ -96,6 +96,10 @@ public:
   void __fastcall CleanupRandomSeedFile();
   void __fastcall BeginUpdate();
   void __fastcall EndUpdate();
+  void __fastcall LoadDirectoryChangesCache(const AnsiString SessionKey,
+    TRemoteDirectoryChangesCache * DirectoryChangesCache);   
+  void __fastcall SaveDirectoryChangesCache(const AnsiString SessionKey,
+    TRemoteDirectoryChangesCache * DirectoryChangesCache);
   virtual THierarchicalStorage * CreateScpStorage(bool SessionList);
 
   __property TVSFixedFileInfo *FixedApplicationInfo  = { read=GetFixedApplicationInfo };
@@ -138,6 +142,4 @@ public:
   __property bool DisablePasswordStoring = { read = FDisablePasswordStoring };
 };
 //---------------------------------------------------------------------------
-bool SpecialFolderLocation(int PathID, AnsiString & Path);
-//---------------------------------------------------------------------------
 #endif

+ 10 - 2
core/CopyParam.cpp

@@ -31,6 +31,7 @@ void __fastcall TCopyParamType::Default()
   ReplaceInvalidChars = true;
   LocalInvalidChars = "/\\:*?\"<>|";
   CalculateSize = true;
+  FileMask = "*.*";
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamType::Assign(const TCopyParamType & Source)
@@ -49,6 +50,7 @@ void __fastcall TCopyParamType::Assign(const TCopyParamType & Source)
   COPY(ReplaceInvalidChars);
   COPY(LocalInvalidChars);
   COPY(CalculateSize);
+  COPY(FileMask);
   #undef COPY
 }
 //---------------------------------------------------------------------------
@@ -68,8 +70,13 @@ AnsiString __fastcall TCopyParamType::ValidLocalFileName(AnsiString FileName) co
   return FileName;
 }
 //---------------------------------------------------------------------------
-AnsiString __fastcall TCopyParamType::ChangeFileName(AnsiString FileName, TOperationSide Side) const
+AnsiString __fastcall TCopyParamType::ChangeFileName(AnsiString FileName,
+  TOperationSide Side, bool FirstLevel) const
 {
+  if (FirstLevel)
+  {
+    FileName = MaskFileName(FileName, FileMask);
+  }
   switch (FileNameCase) {
     case ncUpperCase: FileName = FileName.UpperCase(); break;
     case ncLowerCase: FileName = FileName.LowerCase(); break;
@@ -114,7 +121,7 @@ AnsiString __fastcall TCopyParamType::GetLogStr() const
   char ResumeC[] = "YSN";
   return FORMAT(
     "  PrTime: %s; PrRO: %s; Rght: %s; PrR: %s; FnCs: %s; RIC: %s; "
-      "Resume: %s (%d); CalcS: %s\n"
+      "Resume: %s (%d); CalcS: %s; Mask: %s\n"
     "  TM: %s; AscM: %s ",
     (BooleanToEngStr(PreserveTime),
      BooleanToEngStr(PreserveReadOnly),
@@ -125,6 +132,7 @@ AnsiString __fastcall TCopyParamType::GetLogStr() const
      ResumeC[ResumeSupport],
      (int)ResumeThreshold,
      BooleanToEngStr(CalculateSize),
+     FileMask,
      ModeC[TransferMode],
      AsciiFileMask.Masks));
 }

+ 4 - 1
core/CopyParam.h

@@ -27,6 +27,7 @@ private:
   bool FReplaceInvalidChars;
   AnsiString FLocalInvalidChars;
   bool FCalculateSize;
+  AnsiString FFileMask;
 
 public:
   __fastcall TCopyParamType();
@@ -34,7 +35,8 @@ public:
   TCopyParamType & __fastcall operator =(const TCopyParamType & rhp);
   void __fastcall Assign(const TCopyParamType & Source);
   void __fastcall Default();
-  AnsiString __fastcall ChangeFileName(AnsiString FileName, TOperationSide Side) const;
+  AnsiString __fastcall ChangeFileName(AnsiString FileName,
+    TOperationSide Side, bool FirstLevel) const;
   int __fastcall LocalFileAttrs(const TRights & Rights) const;
   TRights __fastcall RemoteFileRights(int Attrs) const;
   bool __fastcall UseAsciiTransfer(const AnsiString FileName) const;
@@ -55,6 +57,7 @@ public:
   __property bool ReplaceInvalidChars = { read = FReplaceInvalidChars, write = FReplaceInvalidChars };
   __property AnsiString LocalInvalidChars = { read = FLocalInvalidChars, write = FLocalInvalidChars };
   __property bool CalculateSize = { read = FCalculateSize, write = FCalculateSize };
+  __property AnsiString FileMask = { read = FFileMask, write = FFileMask };
 };
 //---------------------------------------------------------------------------
 #endif

+ 4 - 1
core/Exceptions.cpp

@@ -30,7 +30,10 @@ void __fastcall ExtException::AddMoreMessages(Exception* E)
     	FMoreMessages->Assign(((ExtException*)E)->MoreMessages);
     }
 
-    FMoreMessages->Insert(0, E->Message);
+    if (!E->Message.IsEmpty())
+    {
+      FMoreMessages->Insert(0, E->Message);
+    }
   }
 }
 //---------------------------------------------------------------------------

+ 9 - 1
core/FileBuffer.cpp

@@ -129,6 +129,14 @@ void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params)
           Ptr = Data + Index;
         }
       }
+      // this should fix LF -> CR/LF conversion "bug" on CR/FL files,
+      // which led to CR/CR/FL
+      else if (*Ptr == Dest[0] || *Ptr == Dest[1])
+      {
+        Delete(Index, 1);
+        Index--;
+        Ptr = Data + Index;
+      }
       Ptr++;
     }
   }
@@ -160,7 +168,7 @@ void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params)
     }
   }
 
-  if (RemoveCtrlZ && ((*(Data + Size - 1)) == '\x1A'))
+  if (RemoveCtrlZ && (Size > 0) && ((*(Data + Size - 1)) == '\x1A'))
   {
     Delete(Size-1, 1);
   }

+ 8 - 8
core/FileInfo.cpp

@@ -10,19 +10,19 @@
 // Return pointer to file version info block
 void * __fastcall CreateFileInfo(AnsiString FileName)
 {
-        DWORD Handle, Size;
-        void * Result = NULL;
+  DWORD Handle, Size;
+  void * Result = NULL;
 
   // Get file version info block size
   Size = GetFileVersionInfoSize(FileName.c_str(), &Handle);
   // If size is valid
   if (Size)
   {
-                Result = new char[Size];
+    Result = new char[Size];
     // Get file version info block
     if (!GetFileVersionInfo(FileName.c_str(), Handle, Size, Result))
     {
-        delete Result;
+      delete[] Result;
       Result = NULL;
     }
   }
@@ -32,7 +32,7 @@ void * __fastcall CreateFileInfo(AnsiString FileName)
 // Free file version info block memory
 void __fastcall FreeFileInfo(void * FileInfo)
 {
-  delete FileInfo;
+  delete[] FileInfo;
 }
 //---------------------------------------------------------------------------
 typedef TTranslation TTranslations[65536];
@@ -41,8 +41,8 @@ typedef TTranslation *PTranslations;
 // Return pointer to fixed file version info
 PVSFixedFileInfo __fastcall GetFixedFileInfo(void * FileInfo)
 {
-        UINT Len;
-        PVSFixedFileInfo Result;
+  UINT Len;
+  PVSFixedFileInfo Result;
   if (!VerQueryValue(FileInfo, "\\", (void**)&Result, &Len))
     throw Exception("Fixed file info not available");
   return Result;
@@ -61,7 +61,7 @@ unsigned __fastcall GetTranslationCount(void * FileInfo)
 // Return i-th translation in the file version info translation list
 TTranslation __fastcall GetTranslation(void * FileInfo, unsigned i)
 {
-        PTranslations P;
+  PTranslations P;
   UINT Len;
 
   if (!VerQueryValue(FileInfo, "\\VarFileInfo\\Translation", (void**)&P, &Len))

+ 62 - 0
core/FileMasks.cpp

@@ -8,6 +8,68 @@
 
 #include "Common.h"
 //---------------------------------------------------------------------------
+AnsiString __fastcall MaskFilePart(const AnsiString Part, const AnsiString Mask)
+{
+  AnsiString Result;
+  int RestStart = 1;
+  for (int Index = 1; Index <= Mask.Length(); Index++)
+  {
+    switch (Mask[Index])
+    {
+      case '*':
+        Result += Part.SubString(RestStart, Part.Length() - RestStart + 1);
+        RestStart = Part.Length() + 1; 
+        break;
+
+      case '?':
+        if (RestStart <= Part.Length())
+        {
+          Result += Part[RestStart];
+          RestStart++;
+        }
+        break;
+
+      default:
+        Result += Mask[Index];
+        RestStart++;
+        break; 
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall MaskFileName(AnsiString FileName, const AnsiString Mask)
+{
+  if (!Mask.IsEmpty() && (Mask != "*") && (Mask != "*.*"))
+  {
+    int P = Mask.LastDelimiter(".");
+    if (P > 0)
+    {
+      int P2 = FileName.LastDelimiter(".");
+      // only dot at beginning of file name is not considered as
+      // name/ext separator
+      AnsiString FileExt = P2 > 1 ?
+        FileName.SubString(P2 + 1, FileName.Length() - P2) : AnsiString();
+      FileExt = MaskFilePart(FileExt, Mask.SubString(P + 1, Mask.Length() - P));
+      if (P2 > 1)
+      {
+        FileName.SetLength(P2 - 1);
+      }
+      FileName = MaskFilePart(FileName, Mask.SubString(1, P - 1));
+      if (!FileExt.IsEmpty())
+      {
+        FileName += "." + FileExt;
+      }
+    }
+    else
+    {
+      FileName = MaskFilePart(FileName, Mask);
+    }
+  }
+  return FileName;
+}
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
 __fastcall TFileMasks::TFileMasks()
 {
   FMasks = "";

+ 2 - 0
core/FileMasks.h

@@ -23,4 +23,6 @@ private:
   AnsiString FMasks;
 };
 //---------------------------------------------------------------------------
+AnsiString __fastcall MaskFileName(AnsiString FileName, const AnsiString Mask);
+//---------------------------------------------------------------------------
 #endif

+ 22 - 6
core/FileOperationProgress.cpp

@@ -40,7 +40,7 @@ void __fastcall TFileOperationProgressType::Clear()
   TotalTransfered = 0;
   TotalResumed = 0;
   TotalSize = 0;
-  FTotalSizeSet = false;
+  TotalSizeSet = false;
   Operation = foNone;
   DragDrop = false;
   YesToAll = false;
@@ -112,13 +112,14 @@ int __fastcall TFileOperationProgressType::TransferProgress()
 //---------------------------------------------------------------------------
 int __fastcall TFileOperationProgressType::TotalTransferProgress()
 {
-  assert(FTotalSizeSet);
-  return TotalSize > 0 ? (int)((TotalTransfered * 100)/TotalSize) : 0;
+  assert(TotalSizeSet);
+  int Result = TotalSize > 0 ? (int)((TotalTransfered * 100)/TotalSize) : 0;
+  return Result < 100 ? Result : Result;
 }
 //---------------------------------------------------------------------------
 int __fastcall TFileOperationProgressType::OverallProgress()
 {
-  if (FTotalSizeSet)
+  if (TotalSizeSet)
   {
     assert((Operation == foCopy) || (Operation == foMove));
     return TotalTransferProgress();
@@ -189,7 +190,7 @@ unsigned long __fastcall TFileOperationProgressType::LocalBlockSize()
 void __fastcall TFileOperationProgressType::SetTotalSize(__int64 ASize)
 {
   TotalSize = ASize;
-  FTotalSizeSet = true;
+  TotalSizeSet = true;
   DoProgress();
 }
 //---------------------------------------------------------------------------
@@ -206,7 +207,7 @@ void __fastcall TFileOperationProgressType::AddTransfered(__int64 ASize)
   {
     // this can happen with SFTP when downloading file that
     // grows while being downloaded
-    if (FTotalSizeSet)
+    if (TotalSizeSet)
     {
       TotalSize += (TransferedSize - TransferSize); 
     }
@@ -279,4 +280,19 @@ TDateTime __fastcall TFileOperationProgressType::TimeExpected()
   if (CurCps) return TDateTime((double)(((double)(TransferSize - TransferedSize)) / CurCps) / (24 * 60 * 60));
     else return 0; 
 }
+//---------------------------------------------------------------------------
+TDateTime __fastcall TFileOperationProgressType::TotalTimeExpected()
+{
+  assert(TotalSizeSet);
+  unsigned int CurCps = CPS();
+  if (CurCps > 0)
+  {
+    return TDateTime((double)((double)TotalSize / CurCps) /
+      (24 * 60 * 60));
+  }
+  else
+  {
+    return 0;
+  }
+}
 

+ 22 - 2
core/FileOperationProgress.h

@@ -27,7 +27,6 @@ private:
   // how long current file transfer was stopped (e.g. while displaying error message)
   TDateTime FFileStopped;
   int FFilesFinished;
-  bool FTotalSizeSet;
   TFileOperationProgressEvent FOnProgress;
   TFileOperationFinished FOnFinished;
 
@@ -64,6 +63,8 @@ public:
   bool YesToAll;
   bool NoToAll;
 
+  bool TotalSizeSet;
+
   bool Suspended;
 
   __fastcall TFileOperationProgressType(
@@ -82,7 +83,7 @@ public:
   void __fastcall SetFile(AnsiString AFileName);
   int __fastcall OperationProgress();
   unsigned long __fastcall TransferBlockSize();
-  unsigned long __fastcall StaticBlockSize();
+  static unsigned long __fastcall StaticBlockSize();
   void __fastcall Resume();
   void __fastcall SetLocalSize(__int64 ASize);
   void __fastcall SetAsciiTransfer(bool AAsciiTransfer);
@@ -99,11 +100,30 @@ public:
   TDateTime __fastcall TimeElapsed();
   // only current file
   TDateTime __fastcall TimeExpected();
+  TDateTime __fastcall TotalTimeExpected();
   int __fastcall TransferProgress();
   int __fastcall OverallProgress();
   int __fastcall TotalTransferProgress();
 };
 //---------------------------------------------------------------------------
+class TSuspendFileOperationProgress
+{
+public:
+  __fastcall TSuspendFileOperationProgress(TFileOperationProgressType * OperationProgress)
+  {
+    FOperationProgress = OperationProgress;
+    FOperationProgress->Suspend();
+  }
+
+  __fastcall ~TSuspendFileOperationProgress()
+  {
+    FOperationProgress->Resume();
+  }
+
+private:
+  TFileOperationProgressType * FOperationProgress;
+};
+//---------------------------------------------------------------------------
 #endif
 
 

+ 4 - 0
core/FileSystems.h

@@ -28,8 +28,11 @@ public:
   static AnsiString __fastcall CompleteCustomCommand(AnsiString Command,
     const AnsiString FileName, TGetParamValueEvent OnGetParamValue);
 
+  virtual AnsiString __fastcall AbsolutePath(AnsiString Path) = 0;
+  virtual void __fastcall KeepAlive() = 0;
   virtual void __fastcall AnyCommand(const AnsiString Command) = 0;
   virtual void __fastcall ChangeDirectory(const AnsiString Directory) = 0;
+  virtual void __fastcall CachedChangeDirectory(const AnsiString Directory) = 0;
   virtual void __fastcall ChangeFileProperties(const AnsiString FileName,
     const TRemoteFile * File, const TRemoteProperties * Properties) = 0;
   virtual void __fastcall CopyToLocal(TStrings * FilesToCopy,
@@ -50,6 +53,7 @@ public:
   virtual void __fastcall DoStartup() = 0;
   virtual void __fastcall HomeDirectory() = 0;
   virtual bool __fastcall IsCapable(int Capability) const = 0;
+  virtual void __fastcall AdditionalInfo(TStrings * AdditionalInfo, bool Initial) = 0;
   virtual void __fastcall LookupUserGroups() = 0;
   virtual void __fastcall ReadCurrentDirectory() = 0;
   virtual void __fastcall ReadDirectory(TRemoteFileList * FileList) = 0;

+ 123 - 0
core/HierarchicalStorage.cpp

@@ -117,6 +117,38 @@ bool __fastcall THierarchicalStorage::HasSubKeys()
   return Result;
 }
 //---------------------------------------------------------------------------
+bool __fastcall THierarchicalStorage::KeyExists(const AnsiString SubKey)
+{
+  bool Result;
+  TStrings * SubKeys = new TStringList();
+  try
+  {
+    GetSubKeyNames(SubKeys);
+    Result = (SubKeys->IndexOf(SubKey) >= 0);
+  }
+  __finally
+  {
+    delete SubKeys;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+bool __fastcall THierarchicalStorage::ValueExists(const AnsiString Value)
+{
+  bool Result;
+  TStrings * Values = new TStringList();
+  try
+  {
+    GetValueNames(Values);
+    Result = (Values->IndexOf(Value) >= 0);
+  }
+  __finally
+  {
+    delete Values;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall THierarchicalStorage::ReadValues(Classes::TStrings* Strings,
   bool MaintainKeys)
 {
@@ -187,11 +219,26 @@ AnsiString __fastcall THierarchicalStorage::ReadString(const AnsiString Name, co
   return UnMungeStr(ReadStringRaw(Name, Default));
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall THierarchicalStorage::ReadBinaryData(const AnsiString Name)
+{
+  int Size = BinaryDataSize(Name);
+  AnsiString Value;
+  Value.SetLength(Size);
+  ReadBinaryData(Name, Value.c_str(), Size);
+  return Value;
+}
+//---------------------------------------------------------------------------
 void __fastcall THierarchicalStorage::WriteString(const AnsiString Name, const AnsiString Value)
 {
   WriteStringRaw(Name, MungeStr(Value));
 }
 //---------------------------------------------------------------------------
+void __fastcall THierarchicalStorage::WriteBinaryData(const AnsiString Name,
+  const AnsiString Value)
+{
+  WriteBinaryData(Name, Value.c_str(), Value.Length());
+}
+//---------------------------------------------------------------------------
 AnsiString __fastcall THierarchicalStorage::IncludeTrailingBackslash(const AnsiString S) const
 {
   return S.IsEmpty() ? S : ::IncludeTrailingBackslash(S);
@@ -297,6 +344,21 @@ bool __fastcall TRegistryStorage::DeleteValue(const AnsiString Name)
   return FRegistry->DeleteValue(Name);
 }
 //---------------------------------------------------------------------------
+bool __fastcall TRegistryStorage::KeyExists(const AnsiString SubKey)
+{
+  return FRegistry->KeyExists(SubKey);
+}
+//---------------------------------------------------------------------------
+bool __fastcall TRegistryStorage::ValueExists(const AnsiString Value)
+{
+  return FRegistry->ValueExists(Value);
+}
+//---------------------------------------------------------------------------
+int __fastcall TRegistryStorage::BinaryDataSize(const AnsiString Name)
+{
+  return FRegistry->GetDataSize(Name);
+}
+//---------------------------------------------------------------------------
 bool __fastcall TRegistryStorage::ReadBool(const AnsiString Name, bool Default)
 {
   READ_REGISTRY(ReadBool);
@@ -339,6 +401,29 @@ AnsiString __fastcall TRegistryStorage::ReadStringRaw(const AnsiString Name, con
   READ_REGISTRY(ReadString);
 }
 //---------------------------------------------------------------------------
+int __fastcall TRegistryStorage::ReadBinaryData(const AnsiString Name,
+  void * Buffer, int Size)
+{
+  int Result;
+  if (FRegistry->ValueExists(Name))
+  {
+    try
+    {
+      Result = FRegistry->ReadBinaryData(Name, Buffer, Size);
+    }
+    catch(...)
+    {
+      Result = 0;
+      FFailed++;
+    }
+  }
+  else
+  {
+    Result = 0;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall TRegistryStorage::WriteBool(const AnsiString Name, bool Value)
 {
   WRITE_REGISTRY(WriteBool);
@@ -376,6 +461,19 @@ void __fastcall TRegistryStorage::WriteInt64(const AnsiString Name, __int64 Valu
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TRegistryStorage::WriteBinaryData(const AnsiString Name,
+  void * Buffer, int Size)
+{
+  try
+  {
+    FRegistry->WriteBinaryData(Name, Buffer, Size);
+  }
+  catch(...)
+  {
+    FFailed++;
+  }
+}
+//---------------------------------------------------------------------------
 int __fastcall TRegistryStorage::GetFailed()
 {
   int Result = FFailed;
@@ -494,6 +592,11 @@ bool __fastcall TIniFileStorage::DeleteValue(const AnsiString Name)
   return true;
 }
 //---------------------------------------------------------------------------
+int __fastcall TIniFileStorage::BinaryDataSize(const AnsiString Name)
+{
+  return FIniFile->ReadString(CurrentSection, Name, "").Length() / 2;
+}
+//---------------------------------------------------------------------------
 bool __fastcall TIniFileStorage::ReadBool(const AnsiString Name, bool Default)
 {
   return FIniFile->ReadBool(CurrentSection, Name, Default);
@@ -531,6 +634,20 @@ AnsiString __fastcall TIniFileStorage::ReadStringRaw(const AnsiString Name, Ansi
   return FIniFile->ReadString(CurrentSection, Name, Default);
 }
 //---------------------------------------------------------------------------
+int __fastcall TIniFileStorage::ReadBinaryData(const AnsiString Name,
+  void * Buffer, int Size)
+{
+  AnsiString Value = HexToStr(ReadStringRaw(Name, ""));
+  int Len = Value.Length();
+  if (Size > Len)
+  {
+    Size = Len;
+  }
+  assert(Buffer);
+  memcpy(Buffer, Value.c_str(), Size);
+  return Size;
+}
+//---------------------------------------------------------------------------
 void __fastcall TIniFileStorage::WriteBool(const AnsiString Name, bool Value)
 {
   FIniFile->WriteBool(CurrentSection, Name, Value);
@@ -560,3 +677,9 @@ void __fastcall TIniFileStorage::WriteStringRaw(const AnsiString Name, const Ans
 {
   FIniFile->WriteString(CurrentSection, Name, Value);
 }
+//---------------------------------------------------------------------------
+void __fastcall TIniFileStorage::WriteBinaryData(const AnsiString Name,
+  void * Buffer, int Size)
+{
+  WriteStringRaw(Name, StrToHex(AnsiString(static_cast<char*>(Buffer), Size)));
+}

+ 20 - 0
core/HierarchicalStorage.h

@@ -20,20 +20,26 @@ public:
   virtual void __fastcall GetSubKeyNames(Classes::TStrings* Strings) = 0;
   virtual void __fastcall GetValueNames(Classes::TStrings* Strings) = 0;
   bool __fastcall HasSubKeys();
+  virtual bool __fastcall KeyExists(const AnsiString SubKey);
+  virtual bool __fastcall ValueExists(const AnsiString Value);
   virtual void __fastcall RecursiveDeleteSubKey(const AnsiString Key);
   virtual void __fastcall ReadValues(Classes::TStrings* Strings, bool MaintainKeys = false);
   virtual void __fastcall WriteValues(Classes::TStrings* Strings, bool MaintainKeys = false);
   virtual void __fastcall ClearValues();
   virtual bool __fastcall DeleteValue(const AnsiString Name) = 0;
 
+  virtual int __fastcall BinaryDataSize(const AnsiString Name) = 0;
+
   virtual bool __fastcall ReadBool(const AnsiString Name, bool Default) = 0;
   virtual int __fastcall ReadInteger(const AnsiString Name, int Default) = 0;
   virtual __int64 __fastcall ReadInt64(const AnsiString Name, __int64 Default) = 0;
   virtual TDateTime __fastcall ReadDateTime(const AnsiString Name, TDateTime Default) = 0;
   virtual double __fastcall ReadFloat(const AnsiString Name, double Default) = 0;
   virtual AnsiString __fastcall ReadStringRaw(const AnsiString Name, const AnsiString Default) = 0;
+  virtual int __fastcall ReadBinaryData(const AnsiString Name, void * Buffer, int Size) = 0;
 
   virtual AnsiString __fastcall ReadString(AnsiString Name, AnsiString Default);
+  AnsiString __fastcall ReadBinaryData(const AnsiString Name);
 
   virtual void __fastcall WriteBool(const AnsiString Name, bool Value) = 0;
   virtual void __fastcall WriteStringRaw(const AnsiString Name, const AnsiString Value) = 0;
@@ -41,8 +47,10 @@ public:
   virtual void __fastcall WriteInt64(AnsiString Name, __int64 Value) = 0;
   virtual void __fastcall WriteDateTime(const AnsiString Name, TDateTime Value) = 0;
   virtual void __fastcall WriteFloat(const AnsiString Name, double Value) = 0;
+  virtual void __fastcall WriteBinaryData(const AnsiString Name, void * Buffer, int Size) = 0;
 
   virtual void __fastcall WriteString(const AnsiString Name, const AnsiString Value);
+  void __fastcall WriteBinaryData(const AnsiString Name, const AnsiString Value);
 
   __property AnsiString Storage  = { read=FStorage };
   __property AnsiString CurrentSubKey  = { read=GetCurrentSubKey };
@@ -71,6 +79,10 @@ public:
   virtual bool __fastcall DeleteSubKey(const AnsiString SubKey);
   virtual bool __fastcall DeleteValue(const AnsiString Name);
   virtual void __fastcall GetSubKeyNames(Classes::TStrings* Strings);
+  virtual bool __fastcall KeyExists(const AnsiString SubKey);
+  virtual bool __fastcall ValueExists(const AnsiString Value);
+
+  virtual int __fastcall BinaryDataSize(const AnsiString Name);
 
   virtual bool __fastcall ReadBool(const AnsiString Name, bool Default);
   virtual int __fastcall ReadInteger(const AnsiString Name, int Default);
@@ -78,6 +90,7 @@ public:
   virtual TDateTime __fastcall ReadDateTime(const AnsiString Name, TDateTime Default);
   virtual double __fastcall ReadFloat(const AnsiString Name, double Default);
   virtual AnsiString __fastcall ReadStringRaw(const AnsiString Name, const AnsiString Default);
+  virtual int __fastcall ReadBinaryData(const AnsiString Name, void * Buffer, int Size);
 
   virtual void __fastcall WriteBool(const AnsiString Name, bool Value);
   virtual void __fastcall WriteInteger(const AnsiString Name, int Value);
@@ -85,6 +98,8 @@ public:
   virtual void __fastcall WriteDateTime(const AnsiString Name, TDateTime Value);
   virtual void __fastcall WriteFloat(const AnsiString Name, double Value);
   virtual void __fastcall WriteStringRaw(const AnsiString Name, const AnsiString Value);
+  virtual void __fastcall WriteBinaryData(const AnsiString Name, void * Buffer, int Size);
+
   virtual void __fastcall GetValueNames(Classes::TStrings* Strings);
 
 protected:
@@ -111,12 +126,15 @@ public:
   virtual bool __fastcall DeleteValue(const AnsiString Name);
   virtual void __fastcall GetSubKeyNames(Classes::TStrings* Strings);
 
+  virtual int __fastcall BinaryDataSize(const AnsiString Name);
+
   virtual bool __fastcall ReadBool(const AnsiString Name, bool Default);
   virtual int __fastcall ReadInteger(const AnsiString Name, int Default);
   virtual __int64 __fastcall ReadInt64(const AnsiString Name, __int64 Default);
   virtual TDateTime __fastcall ReadDateTime(const AnsiString Name, TDateTime Default);
   virtual double __fastcall ReadFloat(const AnsiString Name, double Default);
   virtual AnsiString __fastcall ReadStringRaw(const AnsiString Name, const AnsiString Default);
+  virtual int __fastcall ReadBinaryData(const AnsiString Name, void * Buffer, int Size);
 
   virtual void __fastcall WriteBool(const AnsiString Name, bool Value);
   virtual void __fastcall WriteInteger(const AnsiString Name, int Value);
@@ -124,6 +142,8 @@ public:
   virtual void __fastcall WriteDateTime(const AnsiString Name, TDateTime Value);
   virtual void __fastcall WriteFloat(const AnsiString Name, double Value);
   virtual void __fastcall WriteStringRaw(const AnsiString Name, const AnsiString Value);
+  virtual void __fastcall WriteBinaryData(const AnsiString Name, void * Buffer, int Size);
+
   virtual void __fastcall GetValueNames(Classes::TStrings* Strings);
 
 private:

+ 11 - 4
core/Net.cpp

@@ -57,13 +57,17 @@ void __fastcall InitWinsock(void)
   }
 }
 //---------------------------------------------------------------------------
-char * do_select(SOCKET skt, int startup)
+extern "C" char * do_select(SOCKET skt, int startup)
 {
   assert(CurrentSSH);
 
   if (CurrentSSH)
   {
-    CurrentSSH->Socket = startup ? skt : INVALID_SOCKET;
+    if (!startup)
+    {
+      skt = INVALID_SOCKET;
+    }
+    CurrentSSH->SetSocket(&skt);
   }
   return NULL;
 }
@@ -127,8 +131,11 @@ static int get_line(const char * prompt, char * str, int maxlen, int is_pw)
 //---------------------------------------------------------------------------
 void SSHLogEvent(void * frontend, char * string)
 {
-  assert(frontend);
-  ((TSecureShell *)frontend)->LogEvent(string);
+  // Frontend maybe NULL here
+  if (frontend != NULL)
+  {
+    ((TSecureShell *)frontend)->LogEvent(string);
+  }
 }
 //---------------------------------------------------------------------------
 void SSHFatalError(char * string)

+ 2 - 7
core/PuttyIntf.h

@@ -6,10 +6,6 @@
   #error Should be included sooner than "Putty.h" !!
 #endif
 //---------------------------------------------------------------------------
-#ifndef AUTO_WINSOCK
-#include <winsock2.h>
-#endif
-//---------------------------------------------------------------------------
 struct charset_spec;
 #include "charset\Charset.h"
 //---------------------------------------------------------------------------
@@ -48,11 +44,10 @@ extern "C"
   int get_ssh_state_closed(void * handle);
   int get_ssh_exitcode(void * handle);
   int ssh_fallback_cmd(void * handle);
+  unsigned int ssh2_remmaxpkt(void * handle);
+  unsigned int ssh2_remwindow(void * handle);
 
   // -------------
-  char * do_select(SOCKET skt, int startup);
-  /*void fatalbox(char * fmt, ...);
-  void modalfatalbox(char *fmt, ...);*/
   int from_backend(void * frontend, int is_stderr, char * data, int datalen);
 
   // from ssh.h for key generation

+ 146 - 82
core/RemoteFiles.cpp

@@ -33,99 +33,31 @@ Boolean __fastcall UnixComparePaths(const AnsiString Path1, const AnsiString Pat
 //---------------------------------------------------------------------------
 AnsiString __fastcall UnixExtractFileDir(const AnsiString Path)
 {
-  Integer Pos = Path.LastDelimiter('/');
-  if (Pos > 1) return Path.SubString(1, Pos - 1);
-    else
-  if (Pos == 1) return "/";
-    else return Path;
+  int Pos = Path.LastDelimiter('/');
+  // it used to return Path when no slash was found
+  return (Pos > 1) ? Path.SubString(1, Pos - 1) :
+    ((Pos == 1) ? AnsiString("/") : AnsiString());
 }
 //---------------------------------------------------------------------------
 // must return trailing backslash
 AnsiString __fastcall UnixExtractFilePath(const AnsiString Path)
 {
-  Integer Pos = Path.LastDelimiter('/');
-  if (Pos) return Path.SubString(1, Pos);
-    else return Path;
+  int Pos = Path.LastDelimiter('/');
+  // it used to return Path when no slash was found
+  return (Pos > 0) ? Path.SubString(1, Pos) : AnsiString();
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall UnixExtractFileName(const AnsiString Path)
 {
-  Integer Pos = Path.LastDelimiter('/');
-  if (Pos) return Path.SubString(Pos + 1, Path.Length() - Pos);
-    else return Path;
+  int Pos = Path.LastDelimiter('/');
+  return (Pos > 0) ? Path.SubString(Pos + 1, Path.Length() - Pos) : Path;
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall UnixExtractFileExt(const AnsiString Path)
 {
   AnsiString FileName = UnixExtractFileName(Path);
-  Integer Pos = FileName.LastDelimiter(".");
-  if (Pos) return Path.SubString(Pos, Path.Length() - Pos + 1);
-    else return "";
-}
-//---------------------------------------------------------------------------
-void __fastcall DateTimeParams(TDateTime * AUnixEpoch, double * ADifference)
-{
-  static double Difference;
-  static TDateTime UnixEpoch = 0;
-
-  if (double(UnixEpoch) == 0)
-  {
-    TIME_ZONE_INFORMATION TZI;
-    unsigned long GTZI;
-
-    GTZI = GetTimeZoneInformation(&TZI);
-    switch (GTZI) {
-      case TIME_ZONE_ID_UNKNOWN:
-        Difference = 0;
-        break;
-
-      case TIME_ZONE_ID_STANDARD:
-        Difference = double(TZI.Bias + TZI.StandardBias) / 1440;
-        break;
-
-      case TIME_ZONE_ID_DAYLIGHT:
-        Difference = double(TZI.Bias + TZI.DaylightBias) / 1440;
-        break;
-
-      case TIME_ZONE_ID_INVALID:
-      default:
-        throw Exception(TIMEZONE_ERROR);
-    }
-    // Is it same as SysUtils::UnixDateDelta = 25569 ?? 
-    UnixEpoch = EncodeDate(1970, 1, 1);
-  }
-  if (AUnixEpoch) *AUnixEpoch = UnixEpoch;
-  if (ADifference) *ADifference = Difference;
-}
-//---------------------------------------------------------------------------
-TDateTime __fastcall UnixToDateTime(unsigned long TimeStamp)
-{
-  TDateTime UnixEpoch;
-  double Difference;
-  DateTimeParams(&UnixEpoch, &Difference);
-
-  TDateTime Result;
-  Result = UnixEpoch + (double(TimeStamp) / 86400) - Difference;
-  return Result;
-}
-//---------------------------------------------------------------------------
-FILETIME __fastcall DateTimeToFileTime(const TDateTime DateTime)
-{
-  unsigned long UnixTimeStamp;
-  FILETIME Result;
-  TDateTime UnixEpoch;
-  double Difference;
-
-  DateTimeParams(&UnixEpoch, &Difference);
-  UnixTimeStamp = (unsigned long)((double(DateTime - UnixEpoch + Difference) * 86400));
-  TIME_POSIX_TO_WIN(UnixTimeStamp, Result);
-  return Result;
-}
-//---------------------------------------------------------------------------
-TDateTime AdjustDateTimeFromUnix(const TDateTime DateTime)
-{
-  // to be implemented
-  return DateTime;
+  int Pos = FileName.LastDelimiter(".");
+  return (Pos > 0) ? Path.SubString(Pos, Path.Length() - Pos + 1) : AnsiString();
 }
 //- TRemoteFiles ------------------------------------------------------------
 __fastcall TRemoteFile::TRemoteFile(TRemoteFile * ALinkedByFile):
@@ -592,6 +524,16 @@ void __fastcall TRemoteFile::SetTerminal(TTerminal * value)
     FLinkedFile->Terminal = value;
   }
 }
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+__fastcall TRemoteParentDirectory::TRemoteParentDirectory() : TRemoteFile()
+{
+  FileName = "..";
+  Modification = Now();
+  LastAccess = Modification;
+  Type = 'D';
+  Size = 0;
+}
 //=== TRemoteFileList ------------------------------------------------------
 __fastcall TRemoteFileList::TRemoteFileList():
   TObjectList()
@@ -790,13 +732,30 @@ __fastcall TRemoteDirectoryCache::TRemoteDirectoryCache(): TStringList()
 //---------------------------------------------------------------------------
 __fastcall TRemoteDirectoryCache::~TRemoteDirectoryCache()
 {
-  for (int Index = 0; Index < Count; Index++)
+  Clear();
+}
+//---------------------------------------------------------------------------
+void __fastcall TRemoteDirectoryCache::Clear()
+{
+  try
   {
-    delete (TRemoteFileList *)Objects[Index];
-    Objects[Index] = NULL;
+    for (int Index = 0; Index < Count; Index++)
+    {
+      delete (TRemoteFileList *)Objects[Index];
+      Objects[Index] = NULL;
+    }
+  }
+  __finally
+  {
+    TStringList::Clear();
   }
 }
 //---------------------------------------------------------------------------
+bool __fastcall TRemoteDirectoryCache::GetIsEmpty() const
+{
+  return (const_cast<TRemoteDirectoryCache*>(this)->Count == 0);
+}
+//---------------------------------------------------------------------------
 TRemoteFileList * __fastcall TRemoteDirectoryCache::GetFileList(const AnsiString Directory)
 {
   int Index = IndexOf(UnixExcludeTrailingBackslash(Directory));
@@ -839,6 +798,111 @@ void __fastcall TRemoteDirectoryCache::Delete(int Index)
   delete (TRemoteFileList *)Objects[Index];
   TStringList::Delete(Index);
 }
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+__fastcall TRemoteDirectoryChangesCache::TRemoteDirectoryChangesCache() :
+  TStringList()
+{
+}
+//---------------------------------------------------------------------------
+void __fastcall TRemoteDirectoryChangesCache::Clear()
+{
+  TStringList::Clear();
+}
+//---------------------------------------------------------------------------
+bool __fastcall TRemoteDirectoryChangesCache::GetIsEmpty() const
+{
+  return (const_cast<TRemoteDirectoryChangesCache*>(this)->Count == 0);
+}
+//---------------------------------------------------------------------------
+void __fastcall TRemoteDirectoryChangesCache::AddDirectoryChange(
+  const AnsiString SourceDir, const AnsiString Change,
+  const AnsiString TargetDir)
+{
+  assert(!TargetDir.IsEmpty());
+  Values[TargetDir] = "//";
+  if (TTerminal::ExpandFileName(Change, SourceDir) != TargetDir)
+  {
+    AnsiString Key;
+    if (DirectoryChangeKey(SourceDir, Change, Key))
+    {
+      Values[Key] = TargetDir;
+    }
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TRemoteDirectoryChangesCache::ClearDirectoryChange(
+  AnsiString SourceDir)
+{
+  for (int Index = 0; Index < Count; Index++)
+  {
+    if (Names[Index].SubString(1, SourceDir.Length()) == SourceDir)
+    {
+      Delete(Index);
+      Index--;
+    }
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TRemoteDirectoryChangesCache::GetDirectoryChange(
+  const AnsiString SourceDir, const AnsiString Change, AnsiString & TargetDir)
+{
+  AnsiString Key;
+  bool Result;
+  Key = TTerminal::ExpandFileName(Change, SourceDir);
+  Result = (IndexOfName(Key) >= 0);
+  if (Result)
+  {
+    TargetDir = Key;
+  }
+  else
+  {
+    Result = DirectoryChangeKey(SourceDir, Change, Key);
+    if (Result)
+    {
+      AnsiString Directory = Values[Key];
+      Result = !Directory.IsEmpty();
+      if (Result)
+      {
+        TargetDir = Directory;
+      }
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TRemoteDirectoryChangesCache::Serialize(AnsiString & Data)
+{
+  Data = "A" + Text;
+}
+//---------------------------------------------------------------------------
+void __fastcall TRemoteDirectoryChangesCache::Deserialize(const AnsiString Data)
+{
+  if (Data.IsEmpty())
+  {
+    Text = "";
+  }
+  else
+  {
+    Text = Data.c_str() + 1; 
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TRemoteDirectoryChangesCache::DirectoryChangeKey(
+  const AnsiString SourceDir, const AnsiString Change, AnsiString & Key)
+{
+  bool Result = !Change.IsEmpty();
+  if (Result)
+  {
+    bool Absolute = TTerminal::IsAbsolutePath(Change);
+    Result = !SourceDir.IsEmpty() || Absolute;
+    if (Result)
+    {
+      Key = Absolute ? Change : SourceDir + "," + Change;
+    }
+  }
+  return Result;
+}
 //=== TRights ---------------------------------------------------------------
 __fastcall TRights::TRights()
 {

+ 34 - 9
core/RemoteFiles.h

@@ -41,11 +41,6 @@ enum TRightState {rsNo, rsYes, rsUndef};
 #define FILETYPE_SYMLINK 'L'
 #define FILETYPE_DIRECTORY 'D'
 //---------------------------------------------------------------------------
-#define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
-    ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
-#define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
-    ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
-//---------------------------------------------------------------------------
 class TRemoteDirectory;
 class TTerminal;
 class TRights;
@@ -138,6 +133,12 @@ public:
   __property AnsiString Extension  = { read=GetExtension };
 };
 //---------------------------------------------------------------------------
+class TRemoteParentDirectory : public TRemoteFile
+{
+public:
+  __fastcall TRemoteParentDirectory();
+};
+//---------------------------------------------------------------------------
 class TRemoteFileList : public TObjectList
 {
 friend class TSCPFileSystem;
@@ -184,7 +185,6 @@ private:
   void __fastcall SetIncludeThisDirectory(Boolean value);
 protected:
   virtual void __fastcall Clear();
-  //virtual TRemoteFile * __fastcall NewFile(TRemoteFile * ALinkedByFile = NULL);
 public:
   __fastcall TRemoteDirectory(TTerminal * aTerminal);
   virtual void __fastcall AddFile(TRemoteFile * File);
@@ -206,8 +206,36 @@ public:
   TRemoteFileList * __fastcall GetFileList(const AnsiString Directory);
   void __fastcall AddFileList(TRemoteFileList * FileList);
   void __fastcall ClearFileList(AnsiString Directory, bool SubDirs);
+  void __fastcall Clear();
+
+  __property bool IsEmpty = { read = GetIsEmpty };
 protected:
   virtual void __fastcall Delete(int Index);
+private:
+  bool __fastcall GetIsEmpty() const;
+};
+//---------------------------------------------------------------------------
+class TRemoteDirectoryChangesCache : private TStringList
+{
+public:
+  __fastcall TRemoteDirectoryChangesCache();
+
+  void __fastcall AddDirectoryChange(const AnsiString SourceDir,
+    const AnsiString Change, const AnsiString TargetDir);
+  void __fastcall ClearDirectoryChange(AnsiString SourceDir);
+  bool __fastcall GetDirectoryChange(const AnsiString SourceDir,
+    const AnsiString Change, AnsiString & TargetDir);
+  void __fastcall Clear();
+
+  void __fastcall Serialize(AnsiString & Data);
+  void __fastcall Deserialize(const AnsiString Data);
+
+  __property bool IsEmpty = { read = GetIsEmpty };
+
+private:
+  static bool __fastcall DirectoryChangeKey(const AnsiString SourceDir,
+    const AnsiString Change, AnsiString & Key);
+  bool __fastcall GetIsEmpty() const;
 };
 //---------------------------------------------------------------------------
 class TRights {
@@ -302,8 +330,5 @@ AnsiString __fastcall UnixExtractFileName(const AnsiString Path);
 AnsiString __fastcall UnixExtractFileExt(const AnsiString Path);
 Boolean __fastcall UnixComparePaths(const AnsiString Path1, const AnsiString Path2);
 //---------------------------------------------------------------------------
-TDateTime __fastcall UnixToDateTime(unsigned long TimeStamp);
-FILETIME __fastcall DateTimeToFileTime(const TDateTime DateTime);
-//---------------------------------------------------------------------------
 #endif
 

+ 246 - 64
core/ScpFileSystem.cpp

@@ -13,6 +13,9 @@
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
+#define FILE_OPERATION_LOOP_EX(ALLOW_SKIP, MESSAGE, OPERATION) \
+  FILE_OPERATION_LOOP_CUSTOM(FTerminal, ALLOW_SKIP, MESSAGE, OPERATION)
+//---------------------------------------------------------------------------
 const coRaiseExcept = 1;
 const coExpectNoOutput = 2;
 const coWaitForLastLine = 4;
@@ -110,7 +113,7 @@ const TCommandType DefaultCommandSet[ShellCommandCount] = {
 /*ListDirectory*/       { -1, -1, F, F, F, "ls -la \"%s\"" /* directory */ },
 /*ListCurrentDirectory*/{ -1, -1, F, F, F, "ls -la" },
 /*ListFile*/            {  1,  1, F, F, F, "ls -lad \"%s\"" /* file/directory */ },
-/*LookupUserGroups*/    {  1,  1, F, F, F, "groups" },
+/*LookupUserGroups*/    {  0,  1, F, F, F, "groups" },
 /*CopyToRemote*/        { -1, -1, T, F, T, "scp -r %s -d -t \"%s\"" /* options, directory */ },
 /*CopyToLocal*/         { -1, -1, F, F, T, "scp -r %s -d -f \"%s\"" /* options, file */ },
 /*DeleteFile*/          {  0,  0, T, F, F, "rm -f -r \"%s\"" /* file/directory */},
@@ -264,6 +267,7 @@ __fastcall TSCPFileSystem::TSCPFileSystem(TTerminal * ATerminal):
 {
   FCommandSet = new TCommandSet(FTerminal->SessionData);
   FOutput = new TStringList();
+  FProcessingCommand = false;
 }
 //---------------------------------------------------------------------------
 __fastcall TSCPFileSystem::~TSCPFileSystem()
@@ -277,6 +281,37 @@ AnsiString __fastcall TSCPFileSystem::GetProtocolName() const
   return "SCP";
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall TSCPFileSystem::AbsolutePath(AnsiString Path)
+{
+  AnsiString Result;
+  if (Path.IsEmpty())
+  {
+    Result = CurrentDirectory;
+  }
+  else if (Path[1] == '/')
+  {
+    Result = UnixExcludeTrailingBackslash(Path);
+  }
+  else
+  {
+    Result = UnixIncludeTrailingBackslash(
+      UnixIncludeTrailingBackslash(CurrentDirectory) + Path);
+    int P;
+    while ((P = Result.Pos("/../")) > 0)
+    {
+      int P2 = Result.SubString(1, P-1).LastDelimiter("/");
+      assert(P2 > 0);
+      Result.Delete(P2, P - P2 + 3); 
+    }
+    while ((P = Result.Pos("/./")) > 0)
+    {
+      Result.Delete(P, 2); 
+    }
+    Result = UnixExcludeTrailingBackslash(Result);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 bool __fastcall TSCPFileSystem::IsCapable(int Capability) const
 {
   assert(FTerminal);
@@ -295,12 +330,73 @@ bool __fastcall TSCPFileSystem::IsCapable(int Capability) const
     case fcTextMode:
       return FTerminal->SessionData->EOLType != FTerminal->Configuration->LocalEOLType;
 
+    case fcNativeTextMode:
+      return false;
+
     default:
       assert(false);
       return false;
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TSCPFileSystem::KeepAlive()
+{
+  if (!FProcessingCommand)
+  {
+    ExecCommand(fsNull, NULL, 0, 0);
+  }
+  else
+  {
+    FTerminal->LogEvent("Cannot send keepalive, command is being executed");
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TSCPFileSystem::AdditionalInfo(TStrings * AdditionalInfo,
+  bool Initial)
+{
+  if (Initial)
+  {
+    AnsiString UName;
+    FTerminal->ExceptionOnFail = true;
+    try
+    {
+      try
+      {
+        AnyCommand("uname -a");
+        for (int Index = 0; Index < Output->Count; Index++)
+        {
+          if (Index > 0)
+          {
+            UName += "; ";
+          }
+          UName += Output->Strings[Index];
+        }
+      }
+      catch(...)
+      {
+        if (!FTerminal->Active)
+        {
+          throw;
+        }
+      }
+    }
+    __finally
+    {
+      FTerminal->ExceptionOnFail = false;
+    }
+
+    if (!UName.IsEmpty())
+    {
+      AdditionalInfo->Add(LoadStr(SCP_UNIX_NAME));
+      AdditionalInfo->Add(UName);
+    }
+    else
+    {
+      AdditionalInfo->Add(LoadStr(SCP_NO_UNIX_NAME));
+    }
+  }
+}
+//---------------------------------------------------------------------------
 AnsiString __fastcall TSCPFileSystem::DelimitStr(AnsiString Str)
 {
   if (!Str.IsEmpty())
@@ -326,8 +422,35 @@ AnsiString __fastcall TSCPFileSystem::DelimitStr(AnsiString Str)
   return Str;
 }
 //---------------------------------------------------------------------------
+void __fastcall TSCPFileSystem::EnsureLocation()
+{
+  if (!FCachedDirectoryChange.IsEmpty())
+  {
+    FTerminal->LogEvent(FORMAT("Locating to cached directory \"%s\".",
+      (FCachedDirectoryChange)));
+    AnsiString Directory = FCachedDirectoryChange;
+    FCachedDirectoryChange = "";
+    try
+    {
+      ChangeDirectory(Directory);
+    }
+    catch(...)
+    {
+      // when location to cached directory fails, pretend again
+      // location in cached directory 
+      if (FTerminal->Active && (CurrentDirectory != Directory))
+      {
+        FCachedDirectoryChange = Directory;
+      }
+      throw;
+    }
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::SendCommand(const AnsiString Cmd)
 {
+  EnsureLocation();
+
   AnsiString Line;
   FTerminal->ClearStdError();
   FReturnCode = 0;
@@ -335,6 +458,7 @@ void __fastcall TSCPFileSystem::SendCommand(const AnsiString Cmd)
   // We suppose, that 'Cmd' already contains command that ensures,
   // that 'LastLine' will be printed
   FTerminal->SendLine(Cmd);
+  FProcessingCommand = true;
 }
 //---------------------------------------------------------------------------
 bool __fastcall TSCPFileSystem::IsTotalListingLine(const AnsiString Line)
@@ -393,6 +517,7 @@ void __fastcall TSCPFileSystem::SkipFirstLine()
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::ReadCommandOutput(int Params)
 {
+  FProcessingCommand = false;
   if (Params & coWaitForLastLine)
   {
     AnsiString Line;
@@ -538,20 +663,23 @@ void __fastcall TSCPFileSystem::LookupUserGroups()
 {
   ExecCommand(fsLookupUserGroups);
   FTerminal->FUserGroups->Clear();
-  FTerminal->FUserGroups->BeginUpdate();
-  try
+  if (FOutput->Count > 0)
   {
-    AnsiString Groups = FOutput->Strings[0];
-    while (!Groups.IsEmpty())
+    FTerminal->FUserGroups->BeginUpdate();
+    try
+    {
+      AnsiString Groups = FOutput->Strings[0];
+      while (!Groups.IsEmpty())
+      {
+        AnsiString NewGroup = CutToChar(Groups, ' ', False);
+        FTerminal->FUserGroups->Add(NewGroup);
+      }
+    }
+    __finally
     {
-      AnsiString NewGroup = CutToChar(Groups, ' ', False);
-      FTerminal->FUserGroups->Add(NewGroup);
+      FTerminal->FUserGroups->EndUpdate();
     }
   }
-  __finally
-  {
-    FTerminal->FUserGroups->EndUpdate();
-  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::DetectReturnVar()
@@ -667,8 +795,15 @@ void __fastcall TSCPFileSystem::UnsetNationalVars()
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::ReadCurrentDirectory()
 {
-  ExecCommand(fsCurrentDirectory);
-  FCurrentDirectory = UnixExcludeTrailingBackslash(FOutput->Strings[0]);
+  if (FCachedDirectoryChange.IsEmpty())
+  {
+    ExecCommand(fsCurrentDirectory);
+    FCurrentDirectory = UnixExcludeTrailingBackslash(FOutput->Strings[0]);
+  }
+  else
+  {
+    FCurrentDirectory = FCachedDirectoryChange;
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::HomeDirectory()
@@ -679,7 +814,8 @@ void __fastcall TSCPFileSystem::HomeDirectory()
 void __fastcall TSCPFileSystem::ChangeDirectory(const AnsiString Directory)
 {
   AnsiString ToDir;
-  if (!Directory.IsEmpty() && (Directory[1] != '~'))
+  if (!Directory.IsEmpty() &&
+      ((Directory[1] != '~') || (Directory.SubString(1, 2) == "~ ")))
   {
     ToDir = "\"" + DelimitStr(Directory) + "\"";
   }
@@ -688,6 +824,12 @@ void __fastcall TSCPFileSystem::ChangeDirectory(const AnsiString Directory)
     ToDir = DelimitStr(Directory);
   }
   ExecCommand(fsChangeDirectory, ARRAYOFCONST((ToDir)));
+  FCachedDirectoryChange = "";
+}
+//---------------------------------------------------------------------------
+void __fastcall TSCPFileSystem::CachedChangeDirectory(const AnsiString Directory)
+{
+  FCachedDirectoryChange = Directory;
 }
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::ReadDirectory(TRemoteFileList * FileList)
@@ -923,7 +1065,16 @@ void __fastcall TSCPFileSystem::SCPResponse(bool * GotLastLine)
         /* TODO 1 : Show stderror to user? */
         FTerminal->ClearStdError();
 
-        ReadCommandOutput(coExpectNoOutput | coRaiseExcept | coOnlyReturnCode);
+        try
+        {
+          ReadCommandOutput(coExpectNoOutput | coRaiseExcept | coOnlyReturnCode);
+        }
+        catch(...)
+        {
+          // when ReadCommandOutput() fails than remote SCP is terminated already
+          *GotLastLine = true;
+          throw;
+        }
       }
         else
       if (Resp == 1)
@@ -1000,8 +1151,7 @@ void __fastcall TSCPFileSystem::CopyToRemote(TStrings * FilesToCopy,
       bool CanProceed;
 
       AnsiString FileNameOnly =
-        CopyParam->ChangeFileName(ExtractFileName(FileName), osLocal);
-
+        CopyParam->ChangeFileName(ExtractFileName(FileName), osLocal, true);
 
       if (CheckExistence)
       {
@@ -1011,19 +1161,39 @@ void __fastcall TSCPFileSystem::CopyToRemote(TStrings * FilesToCopy,
         {
           CanProceed = false;
         }
-          else
-        if (File && !OperationProgress->YesToAll &&
-            FTerminal->Configuration->ConfirmOverwriting && !(Params & cpNoConfirmation))
+        else if (File && !OperationProgress->YesToAll &&
+          FTerminal->Configuration->ConfirmOverwriting && !(Params & cpNoConfirmation))
         {
-          AnsiString QuestionFmt;
-          if (File->IsDirectory) QuestionFmt = LoadStr(DIRECTORY_OVERWRITE);
-            else QuestionFmt = LoadStr(FILE_OVERWRITE);
           int Answer;
-          SUSPEND_OPERATION (
-            Answer = FTerminal->DoQueryUser(FORMAT(QuestionFmt, (FileNameOnly)), 
-              qaYes | qaNo | qaAbort | qaYesToAll | qaNoToAll,
-              qpNeverAskAgainCheck);
-          );
+          if (File->IsDirectory)
+          {
+            SUSPEND_OPERATION
+            (
+              Answer = FTerminal->DoQueryUser(
+                FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly)),
+                qaYes | qaNo | qaAbort | qaYesToAll | qaNoToAll,
+                qpNeverAskAgainCheck);
+            );
+          }
+          else
+          {
+            unsigned long MTime;
+            TOverwriteFileParams FileParams;
+            FTerminal->OpenLocalFile(FileName, GENERIC_READ,
+              NULL, NULL, NULL, &MTime, NULL,
+              &FileParams.SourceSize);
+            FileParams.SourceTimestamp = UnixToDateTime(MTime);
+            FileParams.DestSize = File->Size;
+            FileParams.DestTimestamp = File->Modification;
+
+            SUSPEND_OPERATION
+            (
+              Answer = FTerminal->ConfirmFileOverwrite(
+                FileNameOnly, &FileParams,
+                qaYes | qaNo | qaAbort | qaYesToAll | qaNoToAll,
+                qpNeverAskAgainCheck);
+            );
+          }
           switch (Answer) {
             case qaNeverAskAgain:
               FTerminal->Configuration->ConfirmOverwriting = false;
@@ -1062,7 +1232,7 @@ void __fastcall TSCPFileSystem::CopyToRemote(TStrings * FilesToCopy,
         AnsiString OrigFileNameOnly = ExtractFileName(FileName);
         try
         {
-          SCPSource(FileName, CopyParam, Params, OperationProgress);
+          SCPSource(FileName, CopyParam, Params, OperationProgress, 0);
           OperationProgress->Finish(OrigFileNameOnly, true, DisconnectWhenComplete);
         }
         catch (EScpFileSkipped &E)
@@ -1124,18 +1294,15 @@ void __fastcall TSCPFileSystem::CopyToRemote(TStrings * FilesToCopy,
         HandleExtendedException(&E, this);
       }
     }
-    else
-    {
-      throw;
-    }
   }
 }
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::SCPSource(const AnsiString FileName,
   const TCopyParamType * CopyParam, int Params,
-  TFileOperationProgressType * OperationProgress)
+  TFileOperationProgressType * OperationProgress, int Level)
 {
-  AnsiString DestFileName = CopyParam->ChangeFileName(ExtractFileName(FileName), osLocal);
+  AnsiString DestFileName = CopyParam->ChangeFileName(
+    ExtractFileName(FileName), osLocal, Level == 0);
 
   FTerminal->LogEvent(FORMAT("File: \"%s\"", (FileName)));
 
@@ -1151,7 +1318,7 @@ void __fastcall TSCPFileSystem::SCPSource(const AnsiString FileName,
 
   if (Attrs & faDirectory)
   {
-    SCPDirectorySource(FileName, CopyParam, Params, OperationProgress);
+    SCPDirectorySource(FileName, CopyParam, Params, OperationProgress, Level);
   }
     else
   try
@@ -1186,7 +1353,7 @@ void __fastcall TSCPFileSystem::SCPSource(const AnsiString FileName,
         TFileBuffer BlockBuf;
 
         // This is crucial, if it fails during file transfer, it's fatal error
-        FILE_OPERATION_LOOP (FileName, FMTLOAD(READ_ERROR, (FileName)),
+        FILE_OPERATION_LOOP (FMTLOAD(READ_ERROR, (FileName)),
           BlockBuf.LoadFile(File, OperationProgress->LocalBlockSize(), true);
         );
 
@@ -1343,17 +1510,18 @@ void __fastcall TSCPFileSystem::SCPSource(const AnsiString FileName,
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::SCPDirectorySource(const AnsiString DirectoryName,
   const TCopyParamType * CopyParam, int Params,
-  TFileOperationProgressType * OperationProgress)
+  TFileOperationProgressType * OperationProgress, int Level)
 {
   int Attrs;
 
   FTerminal->LogEvent(FORMAT("Entering directory \"%s\".", (DirectoryName)));
 
   OperationProgress->SetFile(DirectoryName);
-  AnsiString DestFileName = CopyParam->ChangeFileName(ExtractFileName(DirectoryName), osLocal);
+  AnsiString DestFileName = CopyParam->ChangeFileName(
+    ExtractFileName(DirectoryName), osLocal, Level == 0);
 
   // Get directory attributes
-  FILE_OPERATION_LOOP (DirectoryName, FMTLOAD(CANT_GET_ATTRS, (DirectoryName)),
+  FILE_OPERATION_LOOP (FMTLOAD(CANT_GET_ATTRS, (DirectoryName)),
     Attrs = FileGetAttr(DirectoryName);
     if (Attrs == -1) EXCEPTION;
   )
@@ -1374,7 +1542,7 @@ void __fastcall TSCPFileSystem::SCPDirectorySource(const AnsiString DirectoryNam
     TSearchRec SearchRec;
     bool FindOK;
 
-    FILE_OPERATION_LOOP (DirectoryName, FMTLOAD(LIST_DIR_ERROR, (DirectoryName)),
+    FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName)),
       FindOK = (bool)(FindFirst(IncludeTrailingBackslash(DirectoryName) + "*.*",
         FindAttrs, SearchRec) == 0);
     );
@@ -1386,7 +1554,7 @@ void __fastcall TSCPFileSystem::SCPDirectorySource(const AnsiString DirectoryNam
       {
         if ((SearchRec.Name != ".") && (SearchRec.Name != ".."))
         {
-          SCPSource(FileName, CopyParam, Params, OperationProgress);
+          SCPSource(FileName, CopyParam, Params, OperationProgress, Level + 1);
         }
       }
       catch (EScpSkipFile &E)
@@ -1402,7 +1570,7 @@ void __fastcall TSCPFileSystem::SCPDirectorySource(const AnsiString DirectoryNam
         );
       }
 
-      FILE_OPERATION_LOOP (DirectoryName, FMTLOAD(LIST_DIR_ERROR, (DirectoryName)),
+      FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName)),
         FindOK = (FindNext(SearchRec) == 0);
       );
     };
@@ -1458,7 +1626,7 @@ void __fastcall TSCPFileSystem::CopyToLocal(TStrings * FilesToCopy,
 
         // Filename is used only for error messaging
         SCPSink(TargetDir, FileName, CopyParam, Success, OperationProgress,
-          Params, false);
+          Params, 0);
         // operation succeded (no exception), so it's ok that
         // remote side closed SCP, but we continue with next file
         if (OperationProgress->Cancel == csRemoteAbort)
@@ -1475,8 +1643,7 @@ void __fastcall TSCPFileSystem::CopyToLocal(TStrings * FilesToCopy,
             FTerminal->ExceptionOnFail = true;
             try
             {
-              FILE_OPERATION_LOOP(FileName,
-                FMTLOAD(DELETE_FILE_ERROR, (FileName)),
+              FILE_OPERATION_LOOP(FMTLOAD(DELETE_FILE_ERROR, (FileName)),
                 FTerminal->DeleteFile("", File)
               );
             }
@@ -1566,7 +1733,7 @@ void __fastcall TSCPFileSystem::SCPSendError(const AnsiString Message, bool Fata
 void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
   const AnsiString FileName, const TCopyParamType * CopyParam, bool & Success,
   TFileOperationProgressType * OperationProgress, int Params,
-  bool Initialized)
+  int Level)
 {
   struct
   {
@@ -1577,8 +1744,10 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
     int Attrs;
     bool Exists;
   } FileData;
+  TDateTime SourceTimestamp;
 
   bool SkipConfirmed = false;
+  bool Initialized = (Level > 0);
 
   FileData.SetTime = 0;
 
@@ -1608,7 +1777,11 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
         FTerminal->ClearStdError();
         try
         {
-          ReadCommandOutput(coExpectNoOutput | coRaiseExcept | coOnlyReturnCode);
+          // coIgnoreWarnings should allow batch transfer to continue when
+          // download of one the files failes (user denies overwritting
+          // of target local file, no read permissions...)
+          ReadCommandOutput(coExpectNoOutput | coRaiseExcept |
+            coOnlyReturnCode | coIgnoreWarnings);
           if (!Initialized)
           {
             throw Exception("");
@@ -1655,6 +1828,7 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
             {
               TIME_POSIX_TO_WIN(ATime, FileData.AcTime);
               TIME_POSIX_TO_WIN(MTime, FileData.WrTime);
+              SourceTimestamp = UnixToDateTime(MTime);
               FTerminal->SendNull();
               // File time is only valid until next pass
               FileData.SetTime = 2;
@@ -1712,7 +1886,8 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
 
         AnsiString DestFileName =
           IncludeTrailingBackslash(TargetDir) +
-          CopyParam->ChangeFileName(OperationProgress->FileName, osRemote);
+          CopyParam->ChangeFileName(OperationProgress->FileName, osRemote,
+            Level == 0);
 
         FileData.Attrs = FileGetAttr(DestFileName);
         // If getting attrs failes, we suppose, that file/folder doesn't exists
@@ -1726,7 +1901,7 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
 
           if (!FileData.Exists)
           {
-            FILE_OPERATION_LOOP (DestFileName, FMTLOAD(CREATE_DIR_ERROR, (DestFileName)),
+            FILE_OPERATION_LOOP (FMTLOAD(CREATE_DIR_ERROR, (DestFileName)),
               if (!ForceDirectories(DestFileName)) EXCEPTION;
             );
             /* SCP: can we set the timestamp for directories ? */
@@ -1734,7 +1909,7 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
           /* TODO 1 : Send whole path, CopyData.SourceFileName is not enough
              (just error messaging)*/
           SCPSink(DestFileName, OperationProgress->FileName, CopyParam,
-            Success, OperationProgress, Params, true);
+            Success, OperationProgress, Params, Level + 1);
           continue;
         }
           else
@@ -1760,9 +1935,19 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
                     !(Params & cpNoConfirmation))
                 {
                   int Answer;
+
+                  unsigned long MTime;
+                  TOverwriteFileParams FileParams;
+                  FileParams.SourceSize = OperationProgress->TransferSize;
+                  FileParams.SourceTimestamp = SourceTimestamp;
+                  FTerminal->OpenLocalFile(DestFileName, GENERIC_READ,
+                    NULL, NULL, NULL, &MTime, NULL,
+                    &FileParams.DestSize);
+                  FileParams.DestTimestamp = UnixToDateTime(MTime);
+                  
                   SUSPEND_OPERATION (
-                    Answer = FTerminal->DoQueryUser(
-                      FMTLOAD(FILE_OVERWRITE, (OperationProgress->FileName)),
+                    Answer = FTerminal->ConfirmFileOverwrite(
+                      OperationProgress->FileName, &FileParams,
                       qaYes | qaNo | qaAbort | qaYesToAll | qaNoToAll,
                       qpNeverAskAgainCheck);
                   );
@@ -1777,12 +1962,11 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
                 }
               }
 
-              // Create file
-              FILE_OPERATION_LOOP (DestFileName, FMTLOAD(CREATE_FILE_ERROR, (DestFileName)),
-                File = CreateFile(DestFileName.c_str(), GENERIC_WRITE, 0, NULL,
-                  CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
-                if (File == INVALID_HANDLE_VALUE) EXCEPTION;
-              );
+              if (!FTerminal->CreateLocalFile(DestFileName, OperationProgress, &File))
+              {
+                SkipConfirmed = true;
+                EXCEPTION;
+              }
 
               FileStream = new THandleStream((THandle)File);
             }
@@ -1816,7 +2000,7 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
               {
                 BlockBuf.Size = OperationProgress->TransferBlockSize();
                 BlockBuf.Position = 0;
-                
+
                 FTerminal->Receive(BlockBuf.Data, BlockBuf.Size);
                 OperationProgress->AddTransfered(BlockBuf.Size);
 
@@ -1830,8 +2014,7 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
                 }
 
                 // This is crucial, if it fails during file transfer, it's fatal error
-                FILE_OPERATION_LOOP_EX (
-                  DestFileName, false, FMTLOAD(WRITE_ERROR, (DestFileName)),
+                FILE_OPERATION_LOOP_EX (false, FMTLOAD(WRITE_ERROR, (DestFileName)),
                   BlockBuf.WriteToStream(FileStream, BlockBuf.Size);
                 );
 
@@ -1888,8 +2071,7 @@ void __fastcall TSCPFileSystem::SCPSink(const AnsiString TargetDir,
           int NewAttrs = CopyParam->LocalFileAttrs(FileData.RemoteRights);
           if ((NewAttrs & FileData.Attrs) != NewAttrs)
           {
-            FILE_OPERATION_LOOP (DestFileName, FMTLOAD(CANT_SET_ATTRS, (DestFileName)),
-
+            FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DestFileName)),
               FileSetAttr(DestFileName, FileData.Attrs | NewAttrs);
             );
           }

+ 10 - 3
core/ScpFileSystem.h

@@ -12,8 +12,11 @@ public:
   __fastcall TSCPFileSystem(TTerminal * ATerminal);
   virtual __fastcall ~TSCPFileSystem();
 
+  virtual AnsiString __fastcall AbsolutePath(AnsiString Path);
+  virtual void __fastcall KeepAlive();
   virtual void __fastcall AnyCommand(const AnsiString Command);
   virtual void __fastcall ChangeDirectory(const AnsiString Directory);
+  virtual void __fastcall CachedChangeDirectory(const AnsiString Directory);
   virtual void __fastcall ChangeFileProperties(const AnsiString FileName,
     const TRemoteFile * File, const TRemoteProperties * Properties);
   virtual void __fastcall CopyToLocal(TStrings * FilesToCopy,
@@ -34,6 +37,7 @@ public:
   virtual void __fastcall DoStartup();
   virtual void __fastcall HomeDirectory();
   virtual bool __fastcall IsCapable(int Capability) const;
+  virtual void __fastcall AdditionalInfo(TStrings * AdditionalInfo, bool Initial);
   virtual void __fastcall LookupUserGroups();
   virtual void __fastcall ReadCurrentDirectory();
   virtual void __fastcall ReadDirectory(TRemoteFileList * FileList);
@@ -60,6 +64,8 @@ private:
   AnsiString FCurrentDirectory;
   TStrings * FOutput;
   int FReturnCode;
+  AnsiString FCachedDirectoryChange;
+  bool FProcessingCommand;
 
   void __fastcall AliasGroupList();
   void __fastcall ClearAliases();
@@ -69,6 +75,7 @@ private:
   void __fastcall DetectReturnVar();
   bool __fastcall IsLastLine(AnsiString & Line);
   static bool __fastcall IsTotalListingLine(const AnsiString Line);
+  void __fastcall EnsureLocation();
   void __fastcall ExecCommand(const AnsiString Cmd, int Params = -1);
   void __fastcall ExecCommand(TFSCommand Cmd, const TVarRec * args = NULL,
     int size = 0, int Params = -1);
@@ -76,15 +83,15 @@ private:
   void __fastcall SCPResponse(bool * GotLastLine = NULL);
   void __fastcall SCPDirectorySource(const AnsiString DirectoryName,
     const TCopyParamType * CopyParam, int Params,
-    TFileOperationProgressType * OperationProgress);
+    TFileOperationProgressType * OperationProgress, int Level);
   void __fastcall SCPError(const AnsiString Message, bool Fatal);
   void __fastcall SCPSendError(const AnsiString Message, bool Fatal);
   void __fastcall SCPSink(const AnsiString TargetDir,
     const AnsiString FileName, const TCopyParamType * CopyParam, bool & Success,
-    TFileOperationProgressType * OperationProgress, int Params, bool Initialized);
+    TFileOperationProgressType * OperationProgress, int Params, int Level);
   void __fastcall SCPSource(const AnsiString FileName,
     const TCopyParamType * CopyParam, int Params,
-    TFileOperationProgressType * OperationProgress);
+    TFileOperationProgressType * OperationProgress, int Level);
   void __fastcall SendCommand(const AnsiString Cmd);
   void __fastcall SkipFirstLine();
   void __fastcall SkipStartupMessage();

+ 118 - 44
core/SecureShell.cpp

@@ -10,6 +10,10 @@
 #include "SecureShell.h"
 #include "TextsCore.h"
 #include "Common.h"
+
+#ifndef AUTO_WINSOCK
+#include <winsock2.h>
+#endif
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
@@ -35,12 +39,23 @@ __fastcall TSecureShell::TSecureShell()
   FReachedStatus = 0;
   UpdateStatus(sshClosed);
   FConfig = new Config();
+  FSocket = new SOCKET;
+  FMaxPacketSize = 0;
 }
 //---------------------------------------------------------------------------
 __fastcall TSecureShell::~TSecureShell()
 {
   try
   {
+    if (FReachedStatus)
+    {
+      SessionsCount--;
+      if (SessionsCount == 0)
+      {
+        NetFinalize();
+      }
+    }
+
     ClearStdError();
     Active = false;
     SAFE_DESTROY(FSessionData);
@@ -48,6 +63,8 @@ __fastcall TSecureShell::~TSecureShell()
     delete FConfig;
     FConfig = NULL;
     UserObject = NULL;
+    delete FSocket;
+    FSocket = NULL;
   }
   __finally
   {
@@ -402,13 +419,21 @@ void __fastcall TSecureShell::FatalError(AnsiString Error)
   FatalError(NULL, Error);
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::SetSocket(SOCKET value)
+void __fastcall TSecureShell::SetSocket(void * value)
 {
-  if (FActive && (value != INVALID_SOCKET))
+  assert(value);
+  if (FActive && (*static_cast<SOCKET*>(value) != INVALID_SOCKET))
     FatalError("Cannot set socket during connection");
-  FSocket = value;
-  FActive = (FSocket != INVALID_SOCKET);
-  if (!FActive) FStatus = sshClosed;
+  assert(FSocket);
+  *static_cast<SOCKET*>(FSocket) = *static_cast<SOCKET*>(value);
+  if (*static_cast<SOCKET*>(FSocket) != INVALID_SOCKET)
+  {
+    FActive = true;
+  }
+  else
+  {
+    Discard();
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::SetSessionData(TSessionData * value)
@@ -436,11 +461,24 @@ void __fastcall TSecureShell::SetActive(bool value)
   }
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSecureShell::GetActive()
+bool __fastcall TSecureShell::GetActive() const
 {
   return FActive;
 }
 //---------------------------------------------------------------------------
+void __fastcall TSecureShell::Discard()
+{
+  bool WasActive = FActive;
+  FActive = false;
+
+  if (WasActive && OnClose)
+  {
+    OnClose(this);
+  }
+  
+  FStatus = sshClosed;
+}
+//---------------------------------------------------------------------------
 void __fastcall TSecureShell::Close()
 {
   LogEvent("Closing connection.");
@@ -452,24 +490,15 @@ void __fastcall TSecureShell::Close()
   try
   {
     ssh_close(FBackendHandle);
+    // This should be called insted, but there seem tu be error in freeing
+    // FBackend->free(FBackendHandle);
   }
   __finally
   {
     CurrentSSH = PCurrentSSH;
   }
 
-  FActive = false;
-
-  SessionsCount--;
-  if (SessionsCount == 0)
-  {
-    NetFinalize();
-  }
-
-  if (OnClose)
-  {
-    OnClose(this);
-  }
+  Discard();
 }
 //---------------------------------------------------------------------------
 void inline __fastcall TSecureShell::CheckConnection(int Message)
@@ -497,7 +526,7 @@ void __fastcall TSecureShell::WaitForData()
     struct timeval time;
     fd_set readfds;
     FD_ZERO(&readfds);
-    FD_SET(FSocket, &readfds);
+    FD_SET(*static_cast<SOCKET*>(FSocket), &readfds);
 
     time.tv_sec = FSessionData->Timeout;
     time.tv_usec = 0;
@@ -524,7 +553,7 @@ void __fastcall TSecureShell::WaitForData()
   CurrentSSH = this;
   try
   {
-    select_result((WPARAM)FSocket, (LPARAM)FD_READ);
+    select_result((WPARAM)(*static_cast<SOCKET*>(FSocket)), (LPARAM)FD_READ);
   }
   __finally
   {
@@ -532,12 +561,12 @@ void __fastcall TSecureShell::WaitForData()
   }
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSecureShell::SshFallbackCmd()
+bool __fastcall TSecureShell::SshFallbackCmd() const
 {
   return ssh_fallback_cmd(FBackendHandle);
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::Error(AnsiString Error)
+void __fastcall TSecureShell::Error(const AnsiString Error) const
 {
   SSH_ERROR(Error);
 }
@@ -548,14 +577,21 @@ void __fastcall TSecureShell::Idle()
   // each 10 min when in background
   noise_regular();
   // Keep session alive
-  if (FSessionData->PingEnabled &&
+  if ((FSessionData->PingType != ptOff) &&
       (Now() - FLastDataSent > FSessionData->PingIntervalDT))
   {
-    LogEvent("Pinging host to keep session alive.");
-    SendSpecial(TS_PING);
+    KeepAlive();
+    // in case keep alive could not be processed, postpone next attempt
+    FLastDataSent = Now();
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TSecureShell::KeepAlive()
+{
+  LogEvent("Sending null packet to keep session alive.");
+  SendSpecial(TS_PING);
+}
+//---------------------------------------------------------------------------
 void __fastcall TSecureShell::SetLog(TSessionLog * value)
 {
   FLog->Assign(value);
@@ -568,12 +604,34 @@ void __fastcall TSecureShell::SetConfiguration(TConfiguration *value)
   Log->Configuration = value;
 }
 //---------------------------------------------------------------------------
-TDateTime __fastcall TSecureShell::GetDuration()
+TDateTime __fastcall TSecureShell::GetDuration() const
 {
   return Now() - FLoginTime;
 }
 //---------------------------------------------------------------------------
-TCompressionType __fastcall TSecureShell::FuncToCompression(const void * Compress)
+unsigned long __fastcall TSecureShell::MaxPacketSize()
+{
+  if (SshVersion == 1)
+  {
+    return 0;
+  }
+  else
+  {
+    if (FMaxPacketSize == 0)
+    {
+      unsigned long RemWindow = ssh2_remwindow(FBackendHandle);
+      FMaxPacketSize = ssh2_remmaxpkt(FBackendHandle);
+      if (RemWindow < FMaxPacketSize)
+      {
+        FMaxPacketSize = RemWindow;
+      }
+    }
+    return FMaxPacketSize;
+  }
+}
+//---------------------------------------------------------------------------
+TCompressionType __fastcall TSecureShell::FuncToCompression(
+  const void * Compress) const
 {
   if (SshVersion == 1)
   {
@@ -585,25 +643,25 @@ TCompressionType __fastcall TSecureShell::FuncToCompression(const void * Compres
   }
 }
 //---------------------------------------------------------------------------
-TCompressionType __fastcall TSecureShell::GetCSCompression()
+TCompressionType __fastcall TSecureShell::GetCSCompression() const
 {
-  CheckConnection();
+  assert(Active);
   return FuncToCompression(get_cscomp(FBackendHandle));
 }
 //---------------------------------------------------------------------------
-TCompressionType __fastcall TSecureShell::GetSCCompression()
+TCompressionType __fastcall TSecureShell::GetSCCompression() const
 {
-  CheckConnection();
+  assert(Active);
   return FuncToCompression(get_sccomp(FBackendHandle));
 }
 //---------------------------------------------------------------------------
-Integer __fastcall TSecureShell::GetSshVersion()
+int __fastcall TSecureShell::GetSshVersion() const
 {
-  CheckConnection();
+  assert(Active);
   return get_ssh_version(FBackendHandle);
 }
 //---------------------------------------------------------------------------
-TCipher __fastcall TSecureShell::FuncToSsh1Cipher(const void * Cipher)
+TCipher __fastcall TSecureShell::FuncToSsh1Cipher(const void * Cipher) const
 {
   const ssh_cipher *CipherFuncs[] =
     {&ssh_3des, &ssh_des, &ssh_blowfish_ssh1};
@@ -611,14 +669,19 @@ TCipher __fastcall TSecureShell::FuncToSsh1Cipher(const void * Cipher)
   assert(LENOF(CipherFuncs) == LENOF(TCiphers));
   TCipher Result = cipWarn;
 
-  for (Integer Index = 0; Index < LENOF(TCiphers); Index++)
-    if ((ssh_cipher *)Cipher == CipherFuncs[Index]) Result = TCiphers[Index];
+  for (int Index = 0; Index < LENOF(TCiphers); Index++)
+  {
+    if ((ssh_cipher *)Cipher == CipherFuncs[Index])
+    {
+      Result = TCiphers[Index];
+    }
+  }
 
   assert(Result != cipWarn);
   return Result;
 }
 //---------------------------------------------------------------------------
-TCipher __fastcall TSecureShell::FuncToSsh2Cipher(const void * Cipher)
+TCipher __fastcall TSecureShell::FuncToSsh2Cipher(const void * Cipher) const
 {
   const ssh2_ciphers *CipherFuncs[] =
     {&ssh2_3des, &ssh2_des, &ssh2_aes, &ssh2_blowfish};
@@ -629,16 +692,21 @@ TCipher __fastcall TSecureShell::FuncToSsh2Cipher(const void * Cipher)
   for (int C = 0; C < LENOF(TCiphers); C++)
   {
     for (int F = 0; F < CipherFuncs[C]->nciphers; F++)
-      if ((ssh2_cipher *)Cipher == CipherFuncs[C]->list[F]) Result = TCiphers[C];
+    {
+      if ((ssh2_cipher *)Cipher == CipherFuncs[C]->list[F])
+      {
+        Result = TCiphers[C];
+      }
+    }
   }
 
   assert(Result != cipWarn);
   return Result;
 }
 //---------------------------------------------------------------------------
-TCipher __fastcall TSecureShell::GetCSCipher()
+TCipher __fastcall TSecureShell::GetCSCipher() 
 {
-  CheckConnection();
+  assert(Active);
 
   if (FCSCipher == cipWarn)
   {
@@ -773,12 +841,12 @@ void __fastcall TSecureShell::OldKeyfileWarning()
   DoQueryUser(LoadStr(OLD_KEY), NULL, qaOK, 0, qtWarning);
 }
 //---------------------------------------------------------------------------
-Integer __fastcall TSecureShell::GetStatus()
+int __fastcall TSecureShell::GetStatus() const
 {
   return FStatus;
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::UpdateStatus(Integer Value)
+void __fastcall TSecureShell::UpdateStatus(int Value)
 {
   if (FStatus != Value)
   {
@@ -1055,8 +1123,9 @@ void __fastcall TSessionLog::AddStartupInfo()
          BooleanToEngStr(Data->AuthKI)));
       ADF("Ciphers: %s; Ssh2DES: %s",
         (Data->CipherList, BooleanToEngStr(Data->Ssh2DES)));
-      ADF("Ping interval: %d sec (0 = off); Timeout: %d sec",
-        (Data->PingInterval, Data->Timeout));
+      char * PingTypes = "-NC";
+      ADF("Ping type: %s, Ping interval: %d sec; Timeout: %d sec",
+        (AnsiString(PingTypes[Data->PingType]), Data->PingInterval, Data->Timeout));
       AnsiString Bugs;
       char const * BugFlags = "A+-";
       for (int Index = 0; Index < BUG_COUNT; Index++)
@@ -1084,6 +1153,9 @@ void __fastcall TSessionLog::AddStartupInfo()
          (Data->RemoteDirectory.IsEmpty() ? AnsiString("home") : Data->RemoteDirectory),
          BooleanToEngStr(Data->UpdateDirectories),
          BooleanToEngStr(Data->CacheDirectories)));
+      ADF("Cache directory changes: %s, Permanent: %s",
+        (BooleanToEngStr(Data->CacheDirectoryChanges),
+         BooleanToEngStr(Data->PreserveDirectoryChanges)));
       ADF("Clear aliases: %s, Unset nat.vars: %s, Resolve symlinks: %s",
         (BooleanToEngStr(Data->ClearAliases), BooleanToEngStr(Data->UnsetNationalVars),
          BooleanToEngStr(Data->ResolveSymlinks)));
@@ -1142,3 +1214,5 @@ void __fastcall TSessionLog::Clear()
 
 
 
+
+

+ 23 - 24
core/SecureShell.h

@@ -2,10 +2,6 @@
 #ifndef SecureShellH
 #define SecureShellH
 
-#ifndef AUTO_WINSOCK
-#include <winsock2.h>
-#endif
-
 #include "Interface.h"
 #include "Configuration.h"
 #include "Exceptions.h"
@@ -100,7 +96,7 @@ class TSecureShell : public TObject
 {
 private:
   bool FPasswordTried;
-  SOCKET FSocket;
+  void * FSocket;
   TSessionData * FSessionData;
   bool FActive;
   __int64 FBytesReceived;
@@ -110,6 +106,7 @@ private:
   TQueryUserEvent FOnQueryUser;
   Backend * FBackend;
   void * FBackendHandle;
+  unsigned long FMaxPacketSize;
   Config * FConfig;
 
   unsigned PendLen;
@@ -131,43 +128,45 @@ private:
   TCipher FCSCipher;
   TCipher FSCCipher;
 
-  TCipher __fastcall FuncToSsh1Cipher(const void * Cipher);
-  TCipher __fastcall FuncToSsh2Cipher(const void * Cipher);
-  TCompressionType __fastcall FuncToCompression(const void * Compress);
+  TCipher __fastcall FuncToSsh1Cipher(const void * Cipher) const;
+  TCipher __fastcall FuncToSsh2Cipher(const void * Cipher) const;
+  TCompressionType __fastcall FuncToCompression(const void * Compress) const;
   void __fastcall Init();
-  void __fastcall SetSocket(SOCKET value);
   void __fastcall SetSessionData(TSessionData * value);
-  void __fastcall SetActive(Boolean value);
-  bool __fastcall GetActive();
+  void __fastcall SetActive(bool value);
+  bool __fastcall GetActive() const;
   TCipher __fastcall GetCSCipher();
-  TCompressionType __fastcall GetCSCompression();
-  TDateTime __fastcall GetDuration();
+  TCompressionType __fastcall GetCSCompression() const;
+  TDateTime __fastcall GetDuration() const;
   TCipher __fastcall GetSCCipher();
-  TCompressionType __fastcall GetSCCompression();
-  int __fastcall GetSshVersion();
-  int __fastcall GetStatus();
+  TCompressionType __fastcall GetSCCompression() const;
+  int __fastcall GetSshVersion() const;
+  int __fastcall GetStatus() const;
   void inline __fastcall CheckConnection(int Message = -1);
   void __fastcall WaitForData();
   void __fastcall SetLog(TSessionLog * value);
   void __fastcall SetConfiguration(TConfiguration * value);
   void __fastcall SetUserObject(TObject * value);
+  void __fastcall Discard();
 
 protected:
   AnsiString StdError;
-  void __fastcall Error(AnsiString Error);
-  virtual void __fastcall UpdateStatus(Integer Value);
-  bool __fastcall SshFallbackCmd();
+  void __fastcall Error(const AnsiString Error) const;
+  virtual void __fastcall UpdateStatus(int Value);
+  bool __fastcall SshFallbackCmd() const;
   void __fastcall GotHostKey();
+  unsigned long __fastcall MaxPacketSize();
+  virtual void __fastcall KeepAlive();
 
 public:
   __fastcall TSecureShell();
   __fastcall ~TSecureShell();
   virtual void __fastcall Open();
   virtual void __fastcall Close();
-  Integer __fastcall GetPassword(AnsiString &Password);
-  Integer __fastcall Receive(char * Buf, Integer Len);
+  int __fastcall GetPassword(AnsiString & Password);
+  int __fastcall Receive(char * Buf, int Len);
   AnsiString __fastcall ReceiveLine();
-  void __fastcall Send(const char * Buf, Integer Len);
+  void __fastcall Send(const char * Buf, int Len);
   void __fastcall SendStr(AnsiString Str);
   void __fastcall SendSpecial(int Code);
   void __fastcall AddStdError(AnsiString Str);
@@ -177,9 +176,10 @@ public:
   void __fastcall SendLine(AnsiString Line);
   void __fastcall FatalError(Exception * E, AnsiString Msg);
   void __fastcall SendNull();
+  void __fastcall SetSocket(void * value);
 
   void __fastcall FatalError(AnsiString Error);
-  void __fastcall FromBackend(Boolean IsStdErr, char * Data, Integer Length);
+  void __fastcall FromBackend(bool IsStdErr, char * Data, int Length);
   void __fastcall VerifyHostKey(const AnsiString Host, int Port,
     const AnsiString KeyType, const AnsiString KeyStr, const AnsiString Fingerprint);
   void __fastcall AskCipher(const AnsiString CipherName, int CipherType);
@@ -202,7 +202,6 @@ public:
     if (IsLogging()) Log->Add(llMessage, Str);
   }
 
-  __property SOCKET Socket = { read = FSocket, write = SetSocket };
   __property TSessionData * SessionData = { read = FSessionData, write = SetSessionData };
   __property bool Active = { read = GetActive, write = SetActive };
   __property __int64 BytesReceived = { read = FBytesReceived };

+ 158 - 22
core/SessionData.cpp

@@ -36,7 +36,8 @@ void __fastcall TSessionData::Default()
   PortNumber = default_port;
   UserName = "";
   Password = "";
-  PingInterval = 0;
+  PingInterval = 30;
+  PingType = ptOff;
   Timeout = 15;
   AgentFwd = false;
   AuthTIS = false;
@@ -68,13 +69,15 @@ void __fastcall TSessionData::Default()
   }
 
   Special = false;
-  FSProtocol = fsSCPonly;
+  FSProtocol = fsSFTP;
 
   // FS common
   LocalDirectory = "";
   RemoteDirectory = "";
   UpdateDirectories = false;
   CacheDirectories = true;
+  CacheDirectoryChanges = true;
+  PreserveDirectoryChanges = true;
   LockInHome = false;
   ResolveSymlinks = true;
 
@@ -116,6 +119,7 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
     DUPL(UserName);
     DUPL(Password);
     DUPL(PingInterval);
+    DUPL(PingType);
     DUPL(Timeout);
     DUPL(AgentFwd);
     DUPL(AuthTIS);
@@ -130,6 +134,9 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
     DUPL(RemoteDirectory);
     DUPL(UpdateDirectories);
     DUPL(CacheDirectories);
+    DUPL(CacheDirectoryChanges);
+    DUPL(PreserveDirectoryChanges);
+
     DUPL(ResolveSymlinks);
     DUPL(LockInHome);
     DUPL(Special);
@@ -185,7 +192,8 @@ void __fastcall TSessionData::StoreToConfig(void * config)
   ASCOPY(cfg->username, UserName);
   cfg->port = PortNumber;
   cfg->protocol = PROT_SSH;
-  cfg->ping_interval = PingInterval;
+  // ping_interval is not used anyway
+  cfg->ping_interval = (PingType == ptNullPacket) ? PingInterval : 0;
   cfg->compression = Compression;
   cfg->agentfwd = AgentFwd;
 
@@ -287,7 +295,7 @@ void __fastcall TSessionData::StoreToConfig(void * config)
 //---------------------------------------------------------------------
 void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
 {
-  if (Storage->OpenSubKey(MungeStr(Name), False))
+  if (Storage->OpenSubKey(StorageKey, False))
   {
     PortNumber = Storage->ReadInteger("PortNumber", PortNumber);
     UserName = Storage->ReadString("UserName", UserName);
@@ -301,6 +309,12 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
     PingInterval =
       Storage->ReadInteger("PingInterval", PingInterval/60)*60 +
       Storage->ReadInteger("PingIntervalSec", PingInterval%60);
+    PingType = static_cast<TPingType>
+      (Storage->ReadInteger("PingType", PingInterval > 0 ? ptNullPacket : ptOff));
+    if (PingInterval == 0)
+    {
+      PingInterval = 60;
+    }
     Timeout = Storage->ReadInteger("Timeout", Timeout);
     AgentFwd = Storage->ReadBool("AgentFwd", AgentFwd);
     AuthTIS = Storage->ReadBool("AuthTIS", AuthTIS);
@@ -316,6 +330,9 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
     RemoteDirectory = Storage->ReadString("RemoteDirectory", RemoteDirectory);
     UpdateDirectories = Storage->ReadBool("UpdateDirectories", UpdateDirectories);
     CacheDirectories = Storage->ReadBool("CacheDirectories", CacheDirectories);
+    CacheDirectoryChanges = Storage->ReadBool("CacheDirectoryChanges", CacheDirectoryChanges);
+    PreserveDirectoryChanges = Storage->ReadBool("PreserveDirectoryChanges", PreserveDirectoryChanges);
+
     ResolveSymlinks = Storage->ReadBool("ResolveSymlinks", ResolveSymlinks);
     LockInHome = Storage->ReadBool("LockInHome", LockInHome);
     Special = Storage->ReadBool("Special", Special);
@@ -396,7 +413,7 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
 //---------------------------------------------------------------------
 void __fastcall TSessionData::Save(THierarchicalStorage * Storage, bool PuttyExport)
 {
-  if (Modified && Storage->OpenSubKey(MungeStr(Name), true))
+  if (Modified && Storage->OpenSubKey(StorageKey, true))
   {
     Storage->WriteString("HostName", HostName);
     Storage->WriteInteger("PortNumber", PortNumber);
@@ -407,6 +424,7 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage, bool PuttyExp
     }
     Storage->WriteInteger("PingInterval", PingInterval/60);
     Storage->WriteInteger("PingIntervalSec", PingInterval%60);
+    Storage->WriteInteger("PingType", PingType);
     Storage->WriteInteger("Timeout", Timeout);
     Storage->WriteBool("AgentFwd", AgentFwd);
     Storage->WriteBool("AuthTIS", AuthTIS);
@@ -430,6 +448,9 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage, bool PuttyExp
       Storage->WriteString("RemoteDirectory", RemoteDirectory);
       Storage->WriteBool("UpdateDirectories", UpdateDirectories);
       Storage->WriteBool("CacheDirectories", CacheDirectories);
+      Storage->WriteBool("CacheDirectoryChanges", CacheDirectoryChanges);
+      Storage->WriteBool("PreserveDirectoryChanges", PreserveDirectoryChanges);
+
       Storage->WriteBool("ResolveSymlinks", ResolveSymlinks);
       Storage->WriteBool("LockInHome", LockInHome);
       // Special is never stored (if it would, login dialog must be modified not to
@@ -520,7 +541,7 @@ void __fastcall TSessionData::Remove()
   {
     if (Storage->OpenSubKey(Configuration->StoredSessionsSubKey, false))
     {
-      Storage->RecursiveDeleteSubKey(MungeStr(Name));
+      Storage->RecursiveDeleteSubKey(StorageKey);
     }
   }
   __finally
@@ -529,6 +550,103 @@ void __fastcall TSessionData::Remove()
   }
 }
 //---------------------------------------------------------------------
+bool __fastcall TSessionData::ParseUrl(AnsiString Url, int Params,
+  AnsiString * ConnectInfo, AnsiString * HostName, int * PortNumber,
+  AnsiString * UserName, AnsiString * Password, AnsiString * Path)
+{
+  int PSlash = Url.Pos("/");
+  if (PSlash == 0)
+  {
+    PSlash = Url.Length() + 1;
+  }
+
+  AnsiString AConnectInfo;
+  AConnectInfo = Url.SubString(1, PSlash - 1);
+
+  int P = AConnectInfo.Pos("@");
+  bool Result = (P > 0) || ((Params & puRequireUsername) == 0);
+  if (Result)
+  {
+    if (Path != NULL)
+    {
+      int Delta = ((Params & puExcludeLeadingSlash) == 0) ? 0 : 1;
+      *Path = Url.SubString(PSlash + Delta,
+        Url.Length() - PSlash - Delta + 1);
+    }
+
+    if (ConnectInfo != NULL)
+    {
+      *ConnectInfo = AConnectInfo;
+    }
+
+    AnsiString UserInfo;
+    AnsiString HostInfo;
+
+    if (P > 0)
+    {
+      UserInfo = AConnectInfo.SubString(1, P - 1);
+      HostInfo = AConnectInfo.SubString(P + 1, AConnectInfo.Length() - P);
+    }
+    else
+    {
+      HostInfo = AConnectInfo;
+    }
+
+    if (HostName != NULL)
+    {
+      *HostName = CutToChar(HostInfo, ':', true);
+    }
+    else
+    {
+      CutToChar(HostInfo, ':', true);
+    }
+
+    if (PortNumber != NULL)
+    {
+      *PortNumber = HostInfo.IsEmpty() ? -1 : StrToIntDef(HostInfo, -1);
+    }
+
+    if (UserName != NULL)
+    {
+      *UserName = CutToChar(UserInfo, ':', false);
+    }
+    else
+    {
+      CutToChar(UserInfo, ':', false);
+    }
+
+    if (Password != NULL)
+    {
+      *Password = UserInfo;
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------
+bool __fastcall TSessionData::ParseUrl(AnsiString Url, int Params)
+{
+  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);
+  if (Result)
+  {
+    HostName = AHostName;
+    if (APortNumber >= 0)
+    {
+      PortNumber = APortNumber;
+    }
+    UserName = AUserName;
+    Password = APassword;
+    RemoteDirectory = ARemoteDirectory;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------
 bool __fastcall TSessionData::GetCanLogin()
 {
   return !FHostName.IsEmpty() && !FUserName.IsEmpty();
@@ -539,6 +657,11 @@ AnsiString __fastcall TSessionData::GetSessionKey()
   return FORMAT("%s@%s", (UserName, HostName));
 }
 //---------------------------------------------------------------------
+AnsiString __fastcall TSessionData::GetStorageKey()
+{
+  return MungeStr(Name);
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::SetHostName(AnsiString value)
 {
   if (FHostName != value)
@@ -811,27 +934,30 @@ TDateTime __fastcall TSessionData::GetPingIntervalDT()
     (unsigned short)(PingInterval/60%60), (unsigned short)(PingInterval%60), 0);
 }
 //---------------------------------------------------------------------------
-void __fastcall TSessionData::SetPingEnabled(bool value)
+void __fastcall TSessionData::SetPingType(TPingType value)
 {
-  if (value && !FPingInterval) FPingInterval = 60;
-    else
-  if (!value) FPingInterval = 0;
-}
-//---------------------------------------------------------------------------
-bool __fastcall TSessionData::GetPingEnabled()
-{
-  return (bool)(FPingInterval > 0);
+  SET_SESSION_PROPERTY(PingType);
 }
 //---------------------------------------------------------------------
 AnsiString __fastcall TSessionData::GetSessionName()
 {
-  if (!Name.IsEmpty() && !TNamedObjectList::IsHidden(this)) return Name;
-    else
-  if (!HostName.IsEmpty() && !UserName.IsEmpty())
-      return Format("%s@%s", ARRAYOFCONST((UserName, HostName)));
-    else
-  if (!HostName.IsEmpty()) return HostName;
-    else return "session";
+  if (!Name.IsEmpty() && !TNamedObjectList::IsHidden(this) &&
+      (Name != DefaultSessionName))
+  {
+    return Name;
+  }
+  else if (!HostName.IsEmpty() && !UserName.IsEmpty())
+  {
+    return FORMAT("%s@%s", (UserName, HostName));
+  }
+  else if (!HostName.IsEmpty())
+  {
+    return HostName;
+  }
+  else
+  {
+    return "session";
+  }
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::SetTimeDifference(TDateTime value)
@@ -859,6 +985,16 @@ void __fastcall TSessionData::SetCacheDirectories(bool value)
   SET_SESSION_PROPERTY(CacheDirectories);
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::SetCacheDirectoryChanges(bool value)
+{
+  SET_SESSION_PROPERTY(CacheDirectoryChanges);
+}
+//---------------------------------------------------------------------
+void __fastcall TSessionData::SetPreserveDirectoryChanges(bool value)
+{
+  SET_SESSION_PROPERTY(PreserveDirectoryChanges);
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::SetResolveSymlinks(bool value)
 {
   SET_SESSION_PROPERTY(ResolveSymlinks);

+ 18 - 3
core/SessionData.h

@@ -21,6 +21,9 @@ enum TSshBug { sbIgnore1, sbPlainPW1, sbRSA1, sbHMAC2, sbDeriveKey2, sbRSAPad2,
   sbDHGEx2, sbPKSessID2 };
 #define BUG_COUNT (sbPKSessID2+1)
 enum TAutoSwitch { asOn, asOff, asAuto };
+enum TPingType { ptOff, ptNullPacket, ptDummyCommand };
+const puRequireUsername =     0x01;
+const puExcludeLeadingSlash = 0x02;
 //---------------------------------------------------------------------------
 extern const char CipherNames[CIPHER_COUNT][10];
 extern const char SshProtList[][10];
@@ -36,6 +39,7 @@ private:
   AnsiString FUserName;
   AnsiString FPassword;
   int FPingInterval;
+  TPingType FPingType;
   bool FAgentFwd;
   bool FAliasGroupList;
   bool FAuthTIS;
@@ -56,6 +60,8 @@ private:
   bool FSpecial;
   bool FUpdateDirectories;
   bool FCacheDirectories;
+  bool FCacheDirectoryChanges;
+  bool FPreserveDirectoryChanges;
   bool FSelected;
   bool FLookupUserGroups;
   AnsiString FReturnVar;
@@ -104,8 +110,7 @@ private:
   void __fastcall SetPingIntervalDT(TDateTime value);
   TDateTime __fastcall GetPingIntervalDT();
   void __fastcall SetTimeDifference(TDateTime value);
-  void __fastcall SetPingEnabled(bool value);
-  bool __fastcall GetPingEnabled();
+  void __fastcall SetPingType(TPingType value);
   AnsiString __fastcall GetSessionName();
   void __fastcall SetFSProtocol(TFSProtocol value);
   AnsiString __fastcall GetFSProtocolStr();
@@ -113,6 +118,8 @@ private:
   void __fastcall SetRemoteDirectory(AnsiString value);
   void __fastcall SetUpdateDirectories(bool value);
   void __fastcall SetCacheDirectories(bool value);
+  void __fastcall SetCacheDirectoryChanges(bool value);
+  void __fastcall SetPreserveDirectoryChanges(bool value);
   void __fastcall SetLockInHome(bool value);
   void __fastcall SetSpecial(bool value);
   AnsiString __fastcall GetInfoTip();
@@ -153,6 +160,7 @@ private:
   void __fastcall SetSFTPDownloadQueue(int value);
   void __fastcall SetSFTPUploadQueue(int value);
   void __fastcall SetSFTPListingQueue(int value);
+  AnsiString __fastcall GetStorageKey();
 
 public:
   __fastcall TSessionData(AnsiString aName);
@@ -162,6 +170,10 @@ public:
   void __fastcall Save(THierarchicalStorage * Storage, bool PuttyExport = false);
   void __fastcall Remove();
   virtual void __fastcall Assign(TPersistent * Source);
+  bool __fastcall ParseUrl(AnsiString Url, int Params);
+  static bool __fastcall ParseUrl(AnsiString Url, int Params,
+    AnsiString * ConnectInfo, AnsiString * HostName, int * PortNumber,
+    AnsiString * UserName, AnsiString * Password, AnsiString * Path);
 
   __property AnsiString HostName  = { read=FHostName, write=SetHostName };
   __property int PortNumber  = { read=FPortNumber, write=SetPortNumber };
@@ -186,12 +198,14 @@ public:
   __property bool ClearAliases = { read = FClearAliases, write = SetClearAliases };
   __property TDateTime PingIntervalDT = { read = GetPingIntervalDT, write = SetPingIntervalDT };
   __property TDateTime TimeDifference = { read = FTimeDifference, write = SetTimeDifference };
-  __property bool PingEnabled = { read = GetPingEnabled, write = SetPingEnabled };
+  __property TPingType PingType = { read = FPingType, write = SetPingType };
   __property AnsiString SessionName  = { read=GetSessionName };
   __property AnsiString LocalDirectory  = { read=FLocalDirectory, write=SetLocalDirectory };
   __property AnsiString RemoteDirectory  = { read=FRemoteDirectory, write=SetRemoteDirectory };
   __property bool UpdateDirectories = { read=FUpdateDirectories, write=SetUpdateDirectories };
   __property bool CacheDirectories = { read=FCacheDirectories, write=SetCacheDirectories };
+  __property bool CacheDirectoryChanges = { read=FCacheDirectoryChanges, write=SetCacheDirectoryChanges };
+  __property bool PreserveDirectoryChanges = { read=FPreserveDirectoryChanges, write=SetPreserveDirectoryChanges };
   __property bool LockInHome = { read=FLockInHome, write=SetLockInHome };
   __property bool Special = { read=FSpecial, write=SetSpecial };
   __property bool Selected  = { read=FSelected, write=FSelected };
@@ -226,6 +240,7 @@ public:
   __property int SFTPDownloadQueue = { read = FSFTPDownloadQueue, write = SetSFTPDownloadQueue };
   __property int SFTPUploadQueue = { read = FSFTPUploadQueue, write = SetSFTPUploadQueue };
   __property int SFTPListingQueue = { read = FSFTPListingQueue, write = SetSFTPListingQueue };
+  __property AnsiString StorageKey = { read = GetStorageKey };
 };
 //---------------------------------------------------------------------------
 class TStoredSessionList : public TNamedObjectList

File diff suppressed because it is too large
+ 424 - 304
core/SftpFileSystem.cpp


+ 17 - 5
core/SftpFileSystem.h

@@ -5,6 +5,7 @@
 #include <FileSystems.h>
 //---------------------------------------------------------------------------
 class TSFTPPacket;
+class TOverwriteFileParams;
 //---------------------------------------------------------------------------
 enum TSFTPOverwriteMode { omOverwrite, omAppend, omResume };
 //---------------------------------------------------------------------------
@@ -13,12 +14,16 @@ class TSFTPFileSystem : public TCustomFileSystem
 friend class TSFTPPacket;
 friend class TSFTPQueue;
 friend class TSFTPUploadQueue;
+friend class TSFTPBusy;
 public:
   __fastcall TSFTPFileSystem(TTerminal * ATerminal);
   virtual __fastcall ~TSFTPFileSystem();
 
+  virtual AnsiString __fastcall AbsolutePath(AnsiString Path);
+  virtual void __fastcall KeepAlive();
   virtual void __fastcall AnyCommand(const AnsiString Command);
   virtual void __fastcall ChangeDirectory(const AnsiString Directory);
+  virtual void __fastcall CachedChangeDirectory(const AnsiString Directory);
   virtual void __fastcall ChangeFileProperties(const AnsiString FileName,
     const TRemoteFile * File, const TRemoteProperties * Properties);
   virtual void __fastcall CopyToLocal(TStrings * FilesToCopy,
@@ -39,6 +44,7 @@ public:
   virtual void __fastcall DoStartup();
   virtual void __fastcall HomeDirectory();
   virtual bool __fastcall IsCapable(int Capability) const;
+  virtual void __fastcall AdditionalInfo(TStrings * AdditionalInfo, bool Initial);
   virtual void __fastcall LookupUserGroups();
   virtual void __fastcall ReadCurrentDirectory();
   virtual void __fastcall ReadDirectory(TRemoteFileList * FileList);
@@ -61,9 +67,11 @@ protected:
   int FNotLoggedPackets;
   int FBusy;
   bool FAvoidBusy;
+  TStrings * FExtensions;
 
   void __fastcall CustomReadFile(const AnsiString FileName,
-    TRemoteFile *& File, char Type, TRemoteFile * ALinkedByFile = NULL);
+    TRemoteFile *& File, char Type, TRemoteFile * ALinkedByFile = NULL,
+    bool AllowNonexistence = false);
   virtual AnsiString __fastcall GetCurrentDirectory();
   AnsiString __fastcall GetHomeDirectory();
   unsigned long __fastcall GotStatusPacket(TSFTPPacket * Packet, int AllowStatus);
@@ -92,25 +100,29 @@ protected:
 
   void __fastcall SFTPSource(const AnsiString FileName,
     const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params,
-    TFileOperationProgressType * OperationProgress);
+    TFileOperationProgressType * OperationProgress, int Level);
   int __fastcall SFTPOpenRemote(void * AOpenParams, void * /*Param2*/);
+  void __fastcall SFTPCloseRemote(const AnsiString Handle,
+    const AnsiString FileName, TFileOperationProgressType * OperationProgress,
+    bool TransferFinished);
   void __fastcall SFTPDirectorySource(const AnsiString DirectoryName,
     const AnsiString TargetDir, int /*Attrs*/, const TCopyParamType * CopyParam,
-    int Params, TFileOperationProgressType * OperationProgress);
+    int Params, TFileOperationProgressType * OperationProgress, int Level);
   void __fastcall SFTPConfirmOverwrite(const AnsiString FileName,
     bool TargetBiggerThanSource, TFileOperationProgressType * OperationProgress,
-    TSFTPOverwriteMode & Mode);
+    TSFTPOverwriteMode & Mode, const TOverwriteFileParams * FileParams);
   bool SFTPConfirmResume(const AnsiString DestFileName, bool PartialBiggerThanSource,
     TFileOperationProgressType * OperationProgress);
   void __fastcall SFTPSink(const AnsiString FileName,
     const TRemoteFile * File, const AnsiString TargetDir,
     const TCopyParamType * CopyParam, int Params,
-    TFileOperationProgressType * OperationProgress);
+    TFileOperationProgressType * OperationProgress, int Level);
   void __fastcall SFTPSinkFile(AnsiString FileName,
     const TRemoteFile * File, void * Param);
   char * __fastcall GetEOL() const; 
   inline void __fastcall BusyStart();
   inline void __fastcall BusyEnd();
+  unsigned long __fastcall MaxTransferBlockSize(unsigned long Overhead);
 
   static AnsiString __fastcall DecodeUTF(const AnsiString UTF);
 };

+ 610 - 43
core/Terminal.cpp

@@ -26,6 +26,9 @@
       case qaAbort: Abort(); \
     } \
   }
+
+#define FILE_OPERATION_LOOP_EX(ALLOW_SKIP, MESSAGE, OPERATION) \
+  FILE_OPERATION_LOOP_CUSTOM(this, ALLOW_SKIP, MESSAGE, OPERATION)
 //---------------------------------------------------------------------------
 __fastcall TTerminal::TTerminal(): TSecureShell()
 {
@@ -38,17 +41,84 @@ __fastcall TTerminal::TTerminal(): TSecureShell()
   FUserGroups = new TUserGroupsList();
   FOnProgress = NULL;
   FOnFinished = NULL;
+  FOnDeleteLocalFile = NULL;
+  FAdditionalInfo = NULL;
   FUseBusyCursor = True;
   FLockDirectory = "";
   FDirectoryCache = new TRemoteDirectoryCache();
+  FDirectoryChangesCache = NULL;
+  FFSProtocol = cfsUnknown;
 }
 //---------------------------------------------------------------------------
 __fastcall TTerminal::~TTerminal()
 {
+  if (SessionData->CacheDirectoryChanges && SessionData->PreserveDirectoryChanges &&
+      (FDirectoryChangesCache != NULL))
+  {
+    Configuration->SaveDirectoryChangesCache(SessionData->SessionKey,
+      FDirectoryChangesCache);
+  }
+
   SAFE_DESTROY(FFileSystem);
   delete FFiles;
   delete FUserGroups;
   delete FDirectoryCache;
+  delete FDirectoryChangesCache;
+  delete FAdditionalInfo;
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminal::KeepAlive()
+{
+  if (SessionData->PingType == ptDummyCommand)
+  {
+    LogEvent("Executing dummy command to keep session alive.");
+    assert(Active);
+    assert(FFileSystem != NULL);
+    try
+    {
+      FFileSystem->KeepAlive();
+    }
+    catch(Exception & E)
+    {
+      if (Active)
+      {
+        HandleExtendedException(&E, this);
+      }
+      else
+      {
+        throw;
+      }
+    }
+  }
+  else
+  {
+    TSecureShell::KeepAlive();
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TTerminal::IsAbsolutePath(const AnsiString Path)
+{
+  return !Path.IsEmpty() && Path[1] == '/';
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall TTerminal::ExpandFileName(AnsiString Path,
+  const AnsiString BasePath)
+{
+  Path = UnixExcludeTrailingBackslash(Path);
+  if (!IsAbsolutePath(Path) && !BasePath.IsEmpty())
+  {
+    // TODO: Handle more complicated cases like "../../xxx"
+    if (Path == "..")
+    {
+      Path = UnixExcludeTrailingBackslash(UnixExtractFilePath(
+        UnixExcludeTrailingBackslash(BasePath)));
+    }
+    else
+    {
+      Path = UnixIncludeTrailingBackslash(BasePath) + Path;
+    }
+  }
+  return Path;
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TTerminal::GetProtocolName()
@@ -70,14 +140,25 @@ void __fastcall TTerminal::Open()
   if ((SessionData->FSProtocol == fsSCPonly) ||
       (SessionData->FSProtocol == fsSFTP && SshFallbackCmd()))
   {
+    FFSProtocol = cfsSCP;
     FFileSystem = new TSCPFileSystem(this);
     LogEvent("Using SCP protocol.");
   }
   else
   {
+    FFSProtocol = cfsSFTP;
     FFileSystem = new TSFTPFileSystem(this);
     LogEvent("Using SFTP protocol.");
   }
+  if (SessionData->CacheDirectoryChanges)
+  {
+    FDirectoryChangesCache = new TRemoteDirectoryChangesCache();
+    if (SessionData->PreserveDirectoryChanges)
+    {
+      Configuration->LoadDirectoryChangesCache(SessionData->SessionKey,
+        FDirectoryChangesCache);
+    }
+  }
 }
 //---------------------------------------------------------------------------
 bool __fastcall TTerminal::GetIsCapable(TFSCapability Capability) const
@@ -86,6 +167,23 @@ bool __fastcall TTerminal::GetIsCapable(TFSCapability Capability) const
   return FFileSystem->IsCapable(Capability);
 }
 //---------------------------------------------------------------------------
+TStrings * __fastcall TTerminal::GetAdditionalInfo()
+{
+  bool Initial = (FAdditionalInfo == NULL);
+  if (Initial)
+  {
+    FAdditionalInfo = new TStringList();
+  }
+  assert(FFileSystem);
+  FFileSystem->AdditionalInfo(FAdditionalInfo, Initial);
+  return FAdditionalInfo;
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall TTerminal::AbsolutePath(AnsiString Path)
+{
+  return FFileSystem->AbsolutePath(Path);
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminal::ReactOnCommand(int /*TFSCommand*/ Cmd)
 {
   bool ChangesDirectory = false;
@@ -147,10 +245,9 @@ int __fastcall TTerminal::FileOperationLoop(TFileOperationEvent CallBackFunc,
 {
   assert(CallBackFunc);
   int Result;
-  TTerminal * FTerminal = this; // required by FILE_OPERATION_LOOP_EX macro
   FILE_OPERATION_LOOP_EX
   (
-    "", AllowSkip, Message,
+    AllowSkip, Message,
     Result = CallBackFunc(Param1, Param2);
   );
 
@@ -177,6 +274,15 @@ AnsiString __fastcall TTerminal::TranslateLockedPath(AnsiString Path, bool Lock)
   return Path;
 }
 //---------------------------------------------------------------------------
+void __fastcall TTerminal::ClearCaches()
+{
+  FDirectoryCache->Clear();
+  if (FDirectoryChangesCache != NULL)
+  {
+    FDirectoryChangesCache->Clear();
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminal::SetCurrentDirectory(AnsiString value)
 {
   assert(FFileSystem);
@@ -201,6 +307,16 @@ AnsiString __fastcall TTerminal::GetCurrentDirectory()
   return TranslateLockedPath(FCurrentDirectory, true);
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall TTerminal::PeekCurrentDirectory()
+{
+  if (FFileSystem)
+  {
+    FCurrentDirectory = FFileSystem->CurrentDirectory;
+  }
+
+  return TranslateLockedPath(FCurrentDirectory, true);
+}
+//---------------------------------------------------------------------------
 TUserGroupsList * __fastcall TTerminal::GetUserGroups()
 {
   assert(FFileSystem);
@@ -218,6 +334,12 @@ AnsiString __fastcall TTerminal::GetUserName() const
   return SessionData->UserName;
 }
 //---------------------------------------------------------------------------
+bool __fastcall TTerminal::GetAreCachesEmpty() const
+{
+  return FDirectoryCache->IsEmpty &&
+    ((FDirectoryChangesCache == NULL) || FDirectoryChangesCache->IsEmpty);
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminal::DoChangeDirectory()
 {
   if (FOnChangeDirectory)
@@ -356,18 +478,42 @@ void __fastcall TTerminal::CloseOnCompletion(const AnsiString Message)
     Message.IsEmpty() ? LoadStr(CLOSED_ON_COMPLETION) : Message);
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::FileModified(const TRemoteFile * File)
+int __fastcall TTerminal::ConfirmFileOverwrite(const AnsiString FileName,
+  const TOverwriteFileParams * FileParams, int Answers, int Params)
 {
-  assert(File);
-  if (SessionData->CacheDirectories && File->Directory)
+  AnsiString Message = FMTLOAD(FILE_OVERWRITE, (FileName));
+  if (FileParams)
   {
-    if (File->IsDirectory)
+    Message = FMTLOAD(FILE_OVERWRITE_DETAILS, (Message,
+      IntToStr(FileParams->SourceSize),
+      FormatDateTime("ddddd tt", FileParams->SourceTimestamp),
+      IntToStr(FileParams->DestSize),
+      FormatDateTime("ddddd tt", FileParams->DestTimestamp)));
+  }
+  return DoQueryUser(Message, Answers, Params);
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminal::FileModified(const TRemoteFile * File,
+  const AnsiString FileName)
+{
+  if (SessionData->CacheDirectories)
+  {
+    if ((File != NULL) && (File->Directory != NULL))
     {
-      // do not use UnixIncludeTrailingBackslash(CurrentDirectory) 
+      if (File->IsDirectory)
+      {
+        // do not use UnixIncludeTrailingBackslash(CurrentDirectory)
+        FDirectoryCache->ClearFileList(
+          File->Directory->FullDirectory + File->FileName, true);
+      }
+      FDirectoryCache->ClearFileList(File->Directory->Directory, false);
+    }
+    else if (!FileName.IsEmpty())
+    {
+      AnsiString Directory = UnixExtractFilePath(FileName);
       FDirectoryCache->ClearFileList(
-        File->Directory->FullDirectory + File->FileName, true);
+        !Directory.IsEmpty() ? Directory : CurrentDirectory, false);
     }
-    FDirectoryCache->ClearFileList(File->Directory->Directory, false);
   }
 }
 //---------------------------------------------------------------------------
@@ -383,6 +529,11 @@ void __fastcall TTerminal::ReloadDirectory()
   {
     FDirectoryCache->ClearFileList(CurrentDirectory, false);
   }
+  if (SessionData->CacheDirectoryChanges)
+  {
+    assert(FDirectoryChangesCache != NULL);
+    FDirectoryChangesCache->ClearDirectoryChange(CurrentDirectory);
+  }
 
   ReadCurrentDirectory();
   FReadCurrentDirectoryPending = false;
@@ -450,6 +601,13 @@ void __fastcall TTerminal::ReadCurrentDirectory()
     FFileSystem->ReadCurrentDirectory();
     ReactOnCommand(fsCurrentDirectory);
 
+    if (SessionData->CacheDirectoryChanges)
+    {
+      assert(FDirectoryChangesCache != NULL);
+      FDirectoryChangesCache->AddDirectoryChange(OldDirectory,
+        FLastDirectoryChange, CurrentDirectory);
+    }
+
     if (OldDirectory.IsEmpty())
     {
       FLockDirectory = (SessionData->LockInHome ?
@@ -471,21 +629,29 @@ void __fastcall TTerminal::ReadDirectory(bool ReloadOnly)
     CachedFileList = FDirectoryCache->GetFileList(CurrentDirectory);
   }
 
-  DoStartReadDirectory();
   if (CachedFileList)
   {
-    try
+    if (ReloadOnly)
     {
-      CachedFileList->DuplicateTo(FFiles);
+      LogEvent("Cached directory not reloaded.");
     }
-    __finally
+    else
     {
-      DoReadDirectory(ReloadOnly);
+      DoStartReadDirectory();
+      try
+      {
+        CachedFileList->DuplicateTo(FFiles);
+      }
+      __finally
+      {
+        DoReadDirectory(ReloadOnly);
+      }
+      LogEvent("Directory content loaded from cache.");
     }
-    LogEvent("Directory content loaded from cache.");
   }
   else
   {
+    DoStartReadDirectory();
     FFiles->Directory = CurrentDirectory;
 
     try
@@ -638,18 +804,20 @@ void __fastcall TTerminal::ReadFile(const AnsiString FileName,
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::ProcessFiles(TStrings * FileList,
-  TFileOperation Operation, TProcessFileEvent ProcessFile, void * Param)
+bool __fastcall TTerminal::ProcessFiles(TStrings * FileList,
+  TFileOperation Operation, TProcessFileEvent ProcessFile, void * Param,
+  TOperationSide Side)
 {
   assert(FFileSystem);
   assert(FileList);
 
+  bool Result = false;
   bool DisconnectWhenComplete = false;
 
   try
   {
     TFileOperationProgressType Progress(FOnProgress, FOnFinished);
-    Progress.Start(Operation, osRemote, FileList->Count);
+    Progress.Start(Operation, Side, FileList->Count);
 
     FOperationProgress = &Progress;
     try
@@ -671,8 +839,9 @@ void __fastcall TTerminal::ProcessFiles(TStrings * FileList,
           }
           __finally
           {
-            Progress.Finish(UnixExtractFileName(FileName),
-              Success, DisconnectWhenComplete);
+            AnsiString FileNameOnly = (Side == osRemote) ?
+              UnixExtractFileName(FileName) : ExtractFileName(FileName);
+            Progress.Finish(FileNameOnly, Success, DisconnectWhenComplete);
           }
           Index++;
         }
@@ -681,6 +850,11 @@ void __fastcall TTerminal::ProcessFiles(TStrings * FileList,
       {
         EndTransaction();
       }
+      
+      if (Progress.Cancel == csContinue)
+      {
+        Result = true;
+      }
     }
     __finally
     {
@@ -700,6 +874,8 @@ void __fastcall TTerminal::ProcessFiles(TStrings * FileList,
   {
     CloseOnCompletion();
   }
+
+  return Result;
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::DeleteFile(AnsiString FileName,
@@ -715,7 +891,7 @@ void __fastcall TTerminal::DeleteFile(AnsiString FileName,
     OperationProgress->SetFile(FileName);
   }
   LogEvent(FORMAT("Deleting file \"%s\".", (FileName)));
-  if (File) FileModified(File);
+  if (File) FileModified(File, FileName);
   DoDeleteFile(FileName, File, Recursive);
   ReactOnCommand(fsDeleteFile);
 }
@@ -740,9 +916,30 @@ void __fastcall TTerminal::DoDeleteFile(const AnsiString FileName,
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::DeleteFiles(TStrings * FilesToDelete, bool * Recursive)
+bool __fastcall TTerminal::DeleteFiles(TStrings * FilesToDelete, bool * Recursive)
+{
+  return ProcessFiles(FilesToDelete, foDelete, DeleteFile, Recursive);
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminal::DeleteLocalFile(AnsiString FileName,
+  const TRemoteFile * /*File*/, void * /*Param*/)
+{
+  if (OnDeleteLocalFile == NULL)
+  {
+    if (!RecursiveDeleteFile(FileName, false))
+    {
+      throw Exception(FMTLOAD(DELETE_FILE_ERROR, (FileName)));
+    }
+  }
+  else
+  {
+    OnDeleteLocalFile(FileName);
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TTerminal::DeleteLocalFiles(TStrings * FileList)
 {
-  ProcessFiles(FilesToDelete, foDelete, DeleteFile, Recursive);
+  return ProcessFiles(FileList, foDelete, DeleteLocalFile, NULL, osLocal);
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::CustomCommandOnFile(AnsiString FileName,
@@ -760,7 +957,7 @@ void __fastcall TTerminal::CustomCommandOnFile(AnsiString FileName,
   }
   LogEvent(FORMAT("Executing custom command \"%s\" (%d) on file \"%s\".",
     (Params->Command, Params->Params, FileName)));
-  if (File) FileModified(File);
+  if (File) FileModified(File, FileName);
   DoCustomCommandOnFile(FileName, File, Params->Command, Params->Params);
   ReactOnCommand(fsAnyCommand);
 }
@@ -824,7 +1021,7 @@ void __fastcall TTerminal::ChangeFileProperties(AnsiString FileName,
       LogEvent(FORMAT(" - owner: \"%s\"", (RProperties->Owner)));
     }
   }
-  if (File) FileModified(File);
+  if (File) FileModified(File, FileName);
   DoChangeFileProperties(FileName, File, RProperties);
   ReactOnCommand(fsChangeProperties);
 }
@@ -863,7 +1060,7 @@ void __fastcall TTerminal::CalculateFileSize(AnsiString FileName,
   {
     FileName = File->FileName;
   }
-  if (File->IsDirectory)
+  if (File->IsDirectory && !File->IsSymLink)
   {
     LogEvent(FORMAT("Getting size of directory \"%s\"", (FileName)));
     DoCalculateDirectorySize(FileName, File,
@@ -952,7 +1149,7 @@ void __fastcall TTerminal::RenameFile(const TRemoteFile * File,
 
   if (Proceed)
   {
-    FileModified(File);
+    FileModified(File, File->FileName);
     RenameFile(File->FileName, NewName);
   }
 }
@@ -980,10 +1177,7 @@ void __fastcall TTerminal::CreateDirectory(const AnsiString DirName,
 {
   assert(FFileSystem);
   EnsureNonExistence(DirName);
-  if (SessionData->CacheDirectories)
-  {
-    FDirectoryCache->ClearFileList(CurrentDirectory, false);
-  }
+  FileModified(NULL, DirName);
 
   LogEvent(FORMAT("Creating directory \"%s\".", (DirName)));
   DoCreateDirectory(DirName, Properties);
@@ -1062,8 +1256,22 @@ void __fastcall TTerminal::ChangeDirectory(const AnsiString Directory)
   assert(FFileSystem);
   try
   {
-    LogEvent(FORMAT("Changing directory to \"%s\".", (Directory)));
-    FFileSystem->ChangeDirectory(Directory);
+    AnsiString CachedDirectory;
+    assert(!SessionData->CacheDirectoryChanges || (FDirectoryChangesCache != NULL));
+    if (SessionData->CacheDirectoryChanges &&
+        FDirectoryChangesCache->GetDirectoryChange(PeekCurrentDirectory(),
+          Directory, CachedDirectory))
+    {
+      LogEvent(FORMAT("Cached directory change via \"%s\" to \"%s\".",
+        (Directory, CachedDirectory)));
+      FFileSystem->CachedChangeDirectory(CachedDirectory);
+    }
+    else
+    {
+      LogEvent(FORMAT("Changing directory to \"%s\".", (Directory)));
+      FFileSystem->ChangeDirectory(Directory);
+    }
+    FLastDirectoryChange = Directory;
     ReactOnCommand(fsChangeDirectory);
   }
   catch (Exception &E)
@@ -1116,22 +1324,96 @@ void __fastcall TTerminal::AnyCommand(const AnsiString Command)
   }
 }
 //---------------------------------------------------------------------------
+bool __fastcall TTerminal::CreateLocalFile(const AnsiString FileName,
+  TFileOperationProgressType * OperationProgress, HANDLE * AHandle)
+{
+  assert(AHandle);
+  bool Result = true;
+
+  FILE_OPERATION_LOOP (FMTLOAD(CREATE_FILE_ERROR, (FileName)),
+    bool Done;
+    do
+    {
+      *AHandle = CreateFile(FileName.c_str(), GENERIC_WRITE, 0, NULL,
+        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+      Done = (*AHandle != INVALID_HANDLE_VALUE);
+      if (!Done)
+      {
+        int FileAttr;
+        if (FileExists(FileName) &&
+          (((FileAttr = FileGetAttr(FileName)) & faReadOnly) != 0))
+        {
+          if (OperationProgress->NoToAll)
+          {
+            Result = false;
+          }
+          else if (!OperationProgress->YesToAll)
+          {
+            int Answer;
+            SUSPEND_OPERATION
+            (
+              Answer = DoQueryUser(
+                FMTLOAD(READ_ONLY_OVERWRITE, (FileName)),
+                qaYes | qaNo | qaAbort | qaYesToAll | qaNoToAll, 0);
+            );
+            switch (Answer) {
+              case qaYesToAll: OperationProgress->YesToAll = true; break;
+              case qaAbort: OperationProgress->Cancel = csCancel; // continue on next case
+              case qaNoToAll: OperationProgress->NoToAll = true;
+              case qaNo: Result = false; break;
+            }
+          }
+
+          if (Result)
+          {
+            FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (FileName)),
+              if (FileSetAttr(FileName, FileAttr & ~faReadOnly) != 0)
+              {
+                EXCEPTION;
+              }
+            );
+          }
+          else
+          {
+            Done = true;
+          }
+        }
+        else
+        {
+          EXCEPTION;
+        }
+      }
+    }
+    while (!Done);
+  );
+  
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminal::OpenLocalFile(const AnsiString FileName,
   int Access, int * AAttrs, HANDLE * AHandle, unsigned long * ACTime,
-  unsigned long * AMTime, unsigned long * AATime, __int64 * ASize)
+  unsigned long * AMTime, unsigned long * AATime, __int64 * ASize,
+  bool TryWriteReadOnly)
 {
-  TTerminal * FTerminal = this; //required by FILE_OPERATION_LOOP macro
   int Attrs = 0;
   HANDLE Handle = 0;
 
-  FILE_OPERATION_LOOP (FileName, FMTLOAD(FILE_NOT_EXISTS, (FileName)),
+  FILE_OPERATION_LOOP (FMTLOAD(FILE_NOT_EXISTS, (FileName)),
     Attrs = FileGetAttr(FileName);
     if (Attrs == -1) EXCEPTION;
   )
 
   if ((Attrs & faDirectory) == 0)
   {
-    FILE_OPERATION_LOOP (FileName, FMTLOAD(OPENFILE_ERROR, (FileName)),
+    bool NoHandle = false;
+    if (!TryWriteReadOnly && (Access == GENERIC_WRITE) &&
+        ((Attrs & faReadOnly) != 0))
+    {
+      Access = GENERIC_READ;
+      NoHandle = true;
+    }
+    
+    FILE_OPERATION_LOOP (FMTLOAD(OPENFILE_ERROR, (FileName)),
       Handle = CreateFile(FileName.c_str(), Access,
         Access == GENERIC_READ ? FILE_SHARE_READ : 0,
         NULL, OPEN_EXISTING, 0, 0);
@@ -1147,7 +1429,7 @@ void __fastcall TTerminal::OpenLocalFile(const AnsiString FileName,
       if (AATime || AMTime)
       {
         // Get last file access and modification time
-        FILE_OPERATION_LOOP (FileName, FMTLOAD(CANT_GET_ATTRS, (FileName)),
+        FILE_OPERATION_LOOP (FMTLOAD(CANT_GET_ATTRS, (FileName)),
           FILETIME ATime;
           FILETIME MTime;
           FILETIME CTime;
@@ -1161,7 +1443,7 @@ void __fastcall TTerminal::OpenLocalFile(const AnsiString FileName,
       if (ASize)
       {
         // Get file size
-        FILE_OPERATION_LOOP (FileName, FMTLOAD(CANT_GET_ATTRS, (FileName)),
+        FILE_OPERATION_LOOP (FMTLOAD(CANT_GET_ATTRS, (FileName)),
           unsigned long LSize;
           unsigned long HSize;
           LSize = GetFileSize(Handle, &HSize);
@@ -1169,6 +1451,12 @@ void __fastcall TTerminal::OpenLocalFile(const AnsiString FileName,
           *ASize = (__int64(HSize) << 32) + LSize;
         );
       }
+
+      if ((AHandle == NULL) || NoHandle)
+      {
+        CloseHandle(Handle);
+        Handle = NULL;
+      }
     }
     catch(...)
     {
@@ -1228,16 +1516,281 @@ void __fastcall TTerminal::CalculateLocalFilesSize(TStrings * FileList, __int64
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
+struct TSynchronizeFileData
+{
+  int Time;
+  int Attr;
+  unsigned long SizeHigh;
+  unsigned long SizeLow;
+  FILETIME LastWriteTime;
+  bool Modified;
+  bool New;
+};
+//---------------------------------------------------------------------------
+struct TSynchronizeData
+{
+  AnsiString LocalDirectory;
+  AnsiString RemoteDirectory;
+  TTerminal::TSynchronizeMode Mode;
+  int Params;
+  TSynchronizeDirectory OnSynchronizeDirectory;
+  TStringList * LocalFileList;
+  TStringList * ModifiedRemoteFileList;
+  TStringList * NewRemoteFileList;
+};
+//---------------------------------------------------------------------------
+void __fastcall TTerminal::Synchronize(const AnsiString LocalDirectory,
+  const AnsiString RemoteDirectory, TSynchronizeMode Mode, int Params,
+  TSynchronizeDirectory OnSynchronizeDirectory)
+{
+  BeginTransaction();
+  try
+  {
+    DoSynchronizeDirectory(LocalDirectory, RemoteDirectory, Mode, Params,
+      OnSynchronizeDirectory);
+  }
+  __finally
+  {
+    EndTransaction();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminal::DoSynchronizeDirectory(const AnsiString LocalDirectory,
+  const AnsiString RemoteDirectory, TSynchronizeMode Mode, int Params,
+  TSynchronizeDirectory OnSynchronizeDirectory)
+{
+  TSearchRec SearchRec;
+  bool Found;
+  bool Delete = (Params & spDelete) != 0;
+  TSynchronizeData Data;
+
+  Data.LocalDirectory = IncludeTrailingBackslash(LocalDirectory);
+  Data.RemoteDirectory = UnixIncludeTrailingBackslash(RemoteDirectory);
+  Data.Mode = Mode;
+  Data.Params = Params;
+  Data.OnSynchronizeDirectory = OnSynchronizeDirectory;
+  Data.LocalFileList = NULL;
+  Data.NewRemoteFileList = NULL;
+  Data.ModifiedRemoteFileList = NULL;
+  TStrings * LocalFileList = NULL;
+
+  LogEvent(FORMAT("Synchronizing local directory '%s' with remote directory '%s', "
+    "mode = %d, params = %d", (LocalDirectory, RemoteDirectory,
+    int(Mode), int(Params))));
+
+  bool Continue = true;
+  OnSynchronizeDirectory(LocalDirectory, RemoteDirectory, Continue);
+
+  if (!Continue)
+  {
+    Abort();
+  }
+
+  try
+  {
+    Data.LocalFileList = new TStringList();
+    Data.LocalFileList->Sorted = true;
+    Data.LocalFileList->CaseSensitive = false;
+    Data.NewRemoteFileList = new TStringList();
+    Data.ModifiedRemoteFileList = new TStringList();
+    LocalFileList = new TStringList();
+
+    FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (LocalDirectory)),
+      int FindAttrs = faReadOnly | faHidden | faSysFile | faDirectory | faArchive;
+      Found = (FindFirst(Data.LocalDirectory + "*.*", FindAttrs, SearchRec) == 0);
+    );
+
+    if (Found)
+    {
+      try
+      {
+        AnsiString FileName;
+        while (Found)
+        {
+          FileName = SearchRec.Name;
+          if ((FileName != ".") && (FileName != ".."))
+          {
+            TSynchronizeFileData * FileData = new TSynchronizeFileData;
+            FileData->Time = SearchRec.Time;
+            FileData->SizeHigh = SearchRec.FindData.nFileSizeHigh;
+            FileData->SizeLow = SearchRec.FindData.nFileSizeLow;
+            FileData->Attr = SearchRec.Attr;
+            FileData->LastWriteTime = SearchRec.FindData.ftLastWriteTime;
+            FileData->New = true;
+            FileData->Modified = false;
+            Data.LocalFileList->AddObject(FileName,
+              reinterpret_cast<TObject*>(FileData));
+          }
+
+          FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (LocalDirectory)),
+            Found = (FindNext(SearchRec) == 0);
+          );
+        }
+      }
+      __finally
+      {
+        FindClose(SearchRec);
+      }
+
+      ProcessDirectory(RemoteDirectory, SynchronizeFile, &Data);
+
+      TSynchronizeFileData * FileData;
+      for (int Index = 0; Index < Data.LocalFileList->Count; Index++)
+      {
+        FileData = reinterpret_cast<TSynchronizeFileData *>
+          (Data.LocalFileList->Objects[Index]);
+        if ((FileData->Modified && ((Mode == smBoth) || (Mode == smRemote))) ||
+            (FileData->New))
+        {
+          LocalFileList->Add(Data.LocalDirectory + Data.LocalFileList->Strings[Index]);
+        }
+      }
+
+      TCopyParamType CopyParam = Configuration->CopyParam;
+      CopyParam.PreserveTime = true;
+      int CopyParams = (Params & spNoConfirmation) != 0 ? cpNoConfirmation : 0;
+
+      if (LocalFileList->Count > 0)
+      {
+        bool Result;
+        if ((Mode == smBoth) || (Mode == smRemote))
+        {
+          Result = CopyToRemote(LocalFileList, RemoteDirectory, &CopyParam, CopyParams);
+        }
+        else if ((Mode == smLocal) && Delete)
+        {
+          Result = DeleteLocalFiles(LocalFileList);
+        }
+        if (!Result)
+        {
+          Abort();
+        }
+      }
+
+      if ((Mode == smBoth) || (Mode == smLocal))
+      {
+        Data.ModifiedRemoteFileList->AddStrings(Data.NewRemoteFileList);
+        if (Data.ModifiedRemoteFileList->Count > 0)
+        {
+          if (!CopyToLocal(Data.ModifiedRemoteFileList, LocalDirectory,
+            &CopyParam, CopyParams))
+          {
+            Abort();
+          }
+        }
+      }
+      if ((Mode == smRemote) && Delete && (Data.NewRemoteFileList->Count > 0))
+      {
+        if (!DeleteFiles(Data.NewRemoteFileList))
+        {
+          Abort();
+        }
+      }
+    }
+  }
+  __finally
+  {
+    if (Data.LocalFileList != NULL)
+    {
+      for (int Index = 0; Index < Data.LocalFileList->Count; Index++)
+      {
+        delete reinterpret_cast<TSynchronizeFileData*>
+          (Data.LocalFileList->Objects[Index]);
+      }
+      delete Data.LocalFileList;
+    }
+    
+    TStringList * FileList = Data.NewRemoteFileList;
+    while (FileList != Data.ModifiedRemoteFileList)
+    {
+      if (FileList != NULL)
+      {
+        for (int Index = 0; Index < FileList->Count; Index++)
+        {
+          delete static_cast<TRemoteFile*>(FileList->Objects[Index]);
+        }
+        delete FileList;
+      }
+      FileList = Data.ModifiedRemoteFileList;
+    }
+
+    delete LocalFileList;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TTerminal::SynchronizeFile(const AnsiString FileName,
+  const TRemoteFile * File, /*TSynchronizeData*/ void * Param)
+{
+  TSynchronizeData * Data = static_cast<TSynchronizeData *>(Param);
+
+  bool Modified = false;
+  int Index = Data->LocalFileList->IndexOf(File->FileName);
+  bool New = (Index < 0);
+  if (!New)
+  {
+    TSynchronizeFileData * LocalData =
+      reinterpret_cast<TSynchronizeFileData *>(Data->LocalFileList->Objects[Index]);
+
+    LocalData->New = false;
+
+    bool LocalDirectory = (LocalData->Attr & faDirectory) != 0;
+    if (File->IsDirectory != LocalDirectory)
+    {
+      LogEvent(FORMAT("%s is directory on one side, but file on the another",
+        (File->FileName)));
+    }
+    else if (!File->IsDirectory)
+    {
+      FILETIME LocalLastWriteTime;
+      SYSTEMTIME SystemLastWriteTime;
+      FileTimeToLocalFileTime(&LocalData->LastWriteTime, &LocalLastWriteTime);
+      FileTimeToSystemTime(&LocalLastWriteTime, &SystemLastWriteTime);
+      TDateTime LocalTime = SystemTimeToDateTime(SystemLastWriteTime);
+      TDateTime RemoteTime = File->Modification;
+
+      UnifyDateTimePrecision(LocalTime, RemoteTime);
+
+      if (LocalTime < RemoteTime)
+      {
+        Modified = true;
+      }
+      else if (LocalTime > RemoteTime)
+      {
+        LocalData->Modified = true;
+      }
+    }
+    else
+    {
+      DoSynchronizeDirectory(
+        Data->LocalDirectory + File->FileName,
+        Data->RemoteDirectory + File->FileName,
+        Data->Mode, Data->Params, Data->OnSynchronizeDirectory);
+    }
+  }
+
+  if (New || Modified)
+  {
+    assert(!New || !Modified);
+    
+    TStringList * FileList = New ? Data->NewRemoteFileList :
+      Data->ModifiedRemoteFileList;
+    FileList->AddObject(FileName,
+      const_cast<TRemoteFile *>(File)->Duplicate());
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
   const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params)
 {
   assert(FFileSystem);
   assert(FilesToCopy);
 
+  bool Result = false;
   bool DisconnectWhenComplete = false;
 
   try
   {
+
     __int64 Size;
     if (CopyParam->CalculateSize)
     {
@@ -1247,7 +1800,7 @@ void __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
     TFileOperationProgressType OperationProgress(FOnProgress, FOnFinished);
     OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osLocal,
       FilesToCopy->Count, Params & cpDragDrop, TargetDir);
-      
+
     if (CopyParam->CalculateSize)
     {
       OperationProgress.SetTotalSize(Size);
@@ -1278,6 +1831,11 @@ void __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
           EndTransaction();
         }
       }
+      
+      if (OperationProgress.Cancel == csContinue)
+      {
+        Result = true;
+      }
     }
     __finally
     {
@@ -1292,15 +1850,18 @@ void __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
   }
 
   if (DisconnectWhenComplete) CloseOnCompletion();
+
+  return Result;
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::CopyToLocal(TStrings * FilesToCopy,
+bool __fastcall TTerminal::CopyToLocal(TStrings * FilesToCopy,
   const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params)
 {
   assert(FFileSystem);
 
   // see scp.c: sink(), tolocal()
 
+  bool Result = false;
   bool OwnsFileList = (FilesToCopy == NULL);
   bool DisconnectWhenComplete = false;
 
@@ -1365,7 +1926,11 @@ void __fastcall TTerminal::CopyToLocal(TStrings * FilesToCopy,
           CommandError(&E, LoadStr(TOLOCAL_COPY_ERROR));
           DisconnectWhenComplete = false;
         }
-
+        
+        if (OperationProgress.Cancel == csContinue)
+        {
+          Result = true;
+        }
       }
       __finally
       {
@@ -1388,6 +1953,8 @@ void __fastcall TTerminal::CopyToLocal(TStrings * FilesToCopy,
   }
 
   if (DisconnectWhenComplete) CloseOnCompletion();
+
+  return Result;
 }
 //---------------------------------------------------------------------------
 __fastcall TTerminalList::TTerminalList(TConfiguration * AConfiguration) :

+ 71 - 22
core/Terminal.h

@@ -14,29 +14,29 @@ class TRemoteDirectory;
 class TRemoteFile;
 class TCustomFileSystem;
 struct TCalculateSizeParams;
+struct TOverwriteFileParams;
 typedef TStringList TUserGroupsList;
 typedef void __fastcall (__closure *TReadDirectoryEvent)(System::TObject* Sender, Boolean ReloadOnly);
 typedef void __fastcall (__closure *TProcessFileEvent)
   (const AnsiString FileName, const TRemoteFile * File, void * Param);
 typedef int __fastcall (__closure *TFileOperationEvent)
   (void * Param1, void * Param2);
+typedef void __fastcall (__closure *TSynchronizeDirectory)
+  (const AnsiString LocalDirectory, const AnsiString RemoteDirectory, bool & Continue);
+typedef void __fastcall (__closure *TDeleteLocalFileEvent)(const AnsiString FileName);
 //---------------------------------------------------------------------------
-#define SUSPEND_OPERATION(Command)    \
-  {                                   \
-    OperationProgress->Suspend();     \
-    try {                             \
-      Command                         \
-    } __finally {                     \
-      OperationProgress->Resume();    \
-    }                                 \
+#define SUSPEND_OPERATION(Command)                            \
+  {                                                           \
+    TSuspendFileOperationProgress Suspend(OperationProgress); \
+    Command                                                   \
   }
 
+
 #define THROW_SKIP_FILE(EXCEPTION, MESSAGE) \
   throw EScpSkipFile(EXCEPTION, MESSAGE)
 
 /* TODO : Better user interface (query to user) */
-// FILENAME is no longer used
-#define FILE_OPERATION_LOOP_EX(FILENAME, ALLOW_SKIP, MESSAGE, OPERATION) { \
+#define FILE_OPERATION_LOOP_CUSTOM(TERMINAL, ALLOW_SKIP, MESSAGE, OPERATION) { \
   bool DoRepeat; \
   do { \
     DoRepeat = false; \
@@ -62,7 +62,7 @@ typedef int __fastcall (__closure *TFileOperationEvent)
       int Answer; \
       int Params = qpAllowContinueOnError | (!(ALLOW_SKIP) ? qpFatalAbort : 0); \
       SUSPEND_OPERATION ( \
-        Answer = FTerminal->DoQueryUser(MESSAGE, &E, Answers, Params); \
+        Answer = TERMINAL->DoQueryUser(MESSAGE, &E, Answers, Params); \
       ); \
       DoRepeat = (Answer == qaRetry); \
       if (Answer == qaAbort) OperationProgress->Cancel = csCancel; \
@@ -72,12 +72,13 @@ typedef int __fastcall (__closure *TFileOperationEvent)
     } \
   } while (DoRepeat); }
 
-#define FILE_OPERATION_LOOP(FILENAME, MESSAGE, OPERATION) \
-  FILE_OPERATION_LOOP_EX(FILENAME, True, MESSAGE, OPERATION)
+#define FILE_OPERATION_LOOP(MESSAGE, OPERATION) \
+  FILE_OPERATION_LOOP_EX(True, MESSAGE, OPERATION)
 //---------------------------------------------------------------------------
 enum TFSCapability { fcUserGroupListing, fcModeChanging, fcGroupChanging,
   fcOwnerChanging, fcAnyCommand, fcHardLink, fcSymbolicLink, fcResolveSymlink,
-  fcTextMode, fcRename };
+  fcTextMode, fcRename, fcNativeTextMode };
+enum TCurrentFSProtocol { cfsUnknown, cfsSCP, cfsSFTP };
 //---------------------------------------------------------------------------
 const cpDelete = 0x01;
 const cpDragDrop = 0x04;
@@ -91,11 +92,17 @@ const csIgnoreErrors = 0x01;
 //---------------------------------------------------------------------------
 class TTerminal : public TSecureShell
 {
+public:
+  enum TSynchronizeMode { smRemote, smLocal, smBoth };
+  static const spDelete = 0x01;
+  static const spNoConfirmation = 0x02;
+
 // for TranslateLockedPath()
 friend class TRemoteFile;
 // for ReactOnCommand()
 friend class TSCPFileSystem;
 friend class TSFTPFileSystem;
+
 private:
   AnsiString FCurrentDirectory;
   AnsiString FLockDirectory;
@@ -105,6 +112,7 @@ private:
   TNotifyEvent FOnChangeDirectory;
   TReadDirectoryEvent FOnReadDirectory;
   TNotifyEvent FOnStartReadDirectory;
+  TDeleteLocalFileEvent FOnDeleteLocalFile;
   bool FReadCurrentDirectoryPending;
   bool FReadDirectoryPending;
   TUserGroupsList * FUserGroups;
@@ -114,9 +122,14 @@ private:
   TFileOperationProgressType * FOperationProgress;
   bool FUseBusyCursor;
   TRemoteDirectoryCache * FDirectoryCache;
+  TRemoteDirectoryChangesCache * FDirectoryChangesCache;
   TCustomFileSystem * FFileSystem;
+  TStrings * FAdditionalInfo;
+  AnsiString FLastDirectoryChange;
+  TCurrentFSProtocol FFSProtocol;
   void __fastcall CommandError(Exception * E, const AnsiString Msg);
   int __fastcall CommandError(Exception * E, const AnsiString Msg, int Answers);
+  AnsiString __fastcall PeekCurrentDirectory();
   AnsiString __fastcall GetCurrentDirectory();
   bool __fastcall GetExceptionOnFail() const;
   AnsiString __fastcall GetProtocolName();
@@ -125,8 +138,10 @@ private:
   void __fastcall SetExceptionOnFail(bool value);
   void __fastcall ReactOnCommand(int /*TFSCommand*/ Cmd);
   AnsiString __fastcall GetUserName() const;
+  bool __fastcall GetAreCachesEmpty() const;
 
 protected:
+  virtual void __fastcall KeepAlive();
   void __fastcall DoStartReadDirectory();
   void __fastcall DoReadDirectory(bool ReloadOnly);
   void __fastcall DoCreateDirectory(const AnsiString DirName,
@@ -141,23 +156,24 @@ protected:
   void __fastcall DoChangeDirectory();
   void __fastcall EnsureNonExistence(const AnsiString FileName);
   void __fastcall LookupUserGroups();
-  void __fastcall FileModified(const TRemoteFile * File);
+  void __fastcall FileModified(const TRemoteFile * File, const AnsiString FileName);
   int __fastcall FileOperationLoop(TFileOperationEvent CallBackFunc,
     TFileOperationProgressType * OperationProgress, bool AllowSkip,
     const AnsiString Message, void * Param1 = NULL, void * Param2 = NULL);
   bool __fastcall GetIsCapable(TFSCapability Capability) const;
-  void __fastcall DirectoryModified(const AnsiString Path, bool SubDirs);
-  void __fastcall ProcessFiles(TStrings * FileList,
-    TFileOperation Operation, TProcessFileEvent ProcessFile, void * Param = NULL);
+  bool __fastcall ProcessFiles(TStrings * FileList, TFileOperation Operation,
+    TProcessFileEvent ProcessFile, void * Param = NULL, TOperationSide Side = osRemote);
   void __fastcall ProcessDirectory(const AnsiString DirName,
     TProcessFileEvent CallBackFunc, void * Param = NULL);
   AnsiString __fastcall TranslateLockedPath(AnsiString Path, bool Lock);
   void __fastcall ReadDirectory(TRemoteFileList * FileList);
   void __fastcall CustomReadDirectory(TRemoteFileList * FileList);
   void __fastcall DoCreateLink(const AnsiString FileName, const AnsiString PointTo, bool Symbolic);
+  bool __fastcall CreateLocalFile(const AnsiString FileName,
+    TFileOperationProgressType * OperationProgress, HANDLE * AHandle);
   void __fastcall OpenLocalFile(const AnsiString FileName, int Access,
     int * Attrs, HANDLE * Handle, unsigned long * ACTime, unsigned long * MTime,
-    unsigned long * ATime, __int64 * Size);
+    unsigned long * ATime, __int64 * Size, bool TryWriteReadOnly = true);
   TRemoteFileList * ReadDirectoryListing(AnsiString Directory);
   bool __fastcall HandleException(Exception * E);
   void __fastcall CalculateFileSize(AnsiString FileName,
@@ -167,6 +183,16 @@ protected:
   void __fastcall CalculateLocalFileSize(const AnsiString FileName,
     const TSearchRec Rec, /*__int64*/ void * Size);
   void __fastcall CalculateLocalFilesSize(TStrings * FileList, __int64 & Size);
+  TStrings * __fastcall GetAdditionalInfo();
+  int __fastcall ConfirmFileOverwrite(const AnsiString FileName,
+    const TOverwriteFileParams * FileParams, int Answers, int Params);
+  void __fastcall DoSynchronizeDirectory(const AnsiString LocalDirectory,
+    const AnsiString RemoteDirectory, TSynchronizeMode Mode, int Params,
+    TSynchronizeDirectory OnSynchronizeDirectory);
+  void __fastcall SynchronizeFile(const AnsiString FileName,
+    const TRemoteFile * File, /*TSynchronizeData*/ void * Param);
+  void __fastcall DeleteLocalFile(AnsiString FileName,
+    const TRemoteFile * File, void * Param);
 
   __property TFileOperationProgressType * OperationProgress = { read=FOperationProgress };
 
@@ -175,23 +201,26 @@ public:
   __fastcall ~TTerminal();
   virtual void __fastcall Open();
   virtual void __fastcall Close();
+  void __fastcall DirectoryModified(const AnsiString Path, bool SubDirs);
   void __fastcall AnyCommand(const AnsiString Command);
   void __fastcall CloseOnCompletion(const AnsiString Message = "");
+  AnsiString __fastcall AbsolutePath(AnsiString Path);
   void __fastcall BeginTransaction();
   void __fastcall ReadCurrentDirectory();
   void __fastcall ReadDirectory(bool ReloadOnly);
   void __fastcall ReadFile(const AnsiString FileName, TRemoteFile *& File);
   void __fastcall ReadSymlink(TRemoteFile * SymlinkFile, TRemoteFile *& File);
-  void __fastcall CopyToLocal(TStrings * FilesToCopy,
+  bool __fastcall CopyToLocal(TStrings * FilesToCopy,
     const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params);
-  void __fastcall CopyToRemote(TStrings * FilesToCopy,
+  bool __fastcall CopyToRemote(TStrings * FilesToCopy,
     const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params);
   void __fastcall CreateDirectory(const AnsiString DirName,
     const TRemoteProperties * Properties = NULL);
   void __fastcall CreateLink(const AnsiString FileName, const AnsiString PointTo, bool Symbolic);
   void __fastcall DeleteFile(AnsiString FileName,
     const TRemoteFile * File = NULL, void * Recursive = NULL);
-  void __fastcall DeleteFiles(TStrings * FilesToDelete, bool * Recursive = NULL);
+  bool __fastcall DeleteFiles(TStrings * FilesToDelete, bool * Recursive = NULL);
+  bool __fastcall DeleteLocalFiles(TStrings * FileList);
   void __fastcall CustomCommandOnFile(AnsiString FileName,
     const TRemoteFile * File, void * AParams);
   void __fastcall CustomCommandOnFiles(AnsiString Command, int Params, TStrings * Files);
@@ -209,6 +238,14 @@ public:
   void __fastcall RenameFile(const AnsiString FileName, const AnsiString NewName);
   void __fastcall RenameFile(const TRemoteFile * File, const AnsiString NewName, bool CheckExistence);
   void __fastcall CalculateFilesSize(TStrings * FileList, __int64 & Size, int Params);
+  void __fastcall ClearCaches();
+  void __fastcall Synchronize(const AnsiString LocalDirectory,
+    const AnsiString RemoteDirectory, TSynchronizeMode Mode, int Params,
+    TSynchronizeDirectory OnSynchronizeDirectory);
+
+  static bool __fastcall IsAbsolutePath(const AnsiString Path);
+  static AnsiString __fastcall ExpandFileName(AnsiString Path,
+    const AnsiString BasePath);
 
   __property AnsiString CurrentDirectory = { read = GetCurrentDirectory, write = SetCurrentDirectory };
   __property bool ExceptionOnFail = { read = GetExceptionOnFail, write = SetExceptionOnFail };
@@ -216,13 +253,17 @@ public:
   __property TNotifyEvent OnChangeDirectory = { read = FOnChangeDirectory, write = FOnChangeDirectory };
   __property TReadDirectoryEvent OnReadDirectory = { read = FOnReadDirectory, write = FOnReadDirectory };
   __property TNotifyEvent OnStartReadDirectory = { read = FOnStartReadDirectory, write = FOnStartReadDirectory };
+  __property TDeleteLocalFileEvent OnDeleteLocalFile = { read = FOnDeleteLocalFile, write = FOnDeleteLocalFile };
   __property TUserGroupsList * UserGroups = { read = GetUserGroups };
   __property TFileOperationProgressEvent OnProgress  = { read=FOnProgress, write=FOnProgress };
   __property TFileOperationFinished OnFinished  = { read=FOnFinished, write=FOnFinished };
+  __property TCurrentFSProtocol FSProtocol = { read = FFSProtocol };
   __property AnsiString ProtocolName = { read = GetProtocolName };
   __property bool UseBusyCursor = { read = FUseBusyCursor, write = FUseBusyCursor };
   __property AnsiString UserName  = { read=GetUserName };
   __property bool IsCapable[TFSCapability Capability] = { read = GetIsCapable };
+  __property TStrings * AdditionalInfo = { read = GetAdditionalInfo };
+  __property bool AreCachesEmpty = { read = GetAreCachesEmpty };
 };
 //---------------------------------------------------------------------------
 class TTerminalList : public TObjectList
@@ -256,4 +297,12 @@ struct TCalculateSizeParams
   int Params;
 };
 //---------------------------------------------------------------------------
+struct TOverwriteFileParams
+{
+  __int64 SourceSize;
+  __int64 DestSize;
+  TDateTime SourceTimestamp;
+  TDateTime DestTimestamp;
+};
+//---------------------------------------------------------------------------
 #endif

+ 10 - 1
forms/About.cpp

@@ -8,7 +8,6 @@
 #include <Common.h>
 #include "About.h"
 #include "WinInterface.h"
-#include "UserInterface.h"
 #include "TextsCore.h"
 #include "TextsWin.h"
 //---------------------------------------------------------------------
@@ -74,4 +73,14 @@ void __fastcall TAboutDialog::LicenceButtonClick(TObject * /*Sender*/)
   DoProductLicence();
 }
 //---------------------------------------------------------------------------
+bool __fastcall TAboutDialog::GetAllowLicence()
+{
+  return LicenceButton->Visible;
+}
+//---------------------------------------------------------------------------
+void __fastcall TAboutDialog::SetAllowLicence(bool value)
+{
+  LicenceButton->Visible = value;
+}
+//---------------------------------------------------------------------------
 

+ 3 - 0
forms/About.h

@@ -45,13 +45,16 @@ __published:
   void __fastcall EmailLabelClick(TObject *Sender);
   void __fastcall DisplayLicence(TObject *Sender);
   void __fastcall LicenceButtonClick(TObject *Sender);
+  bool __fastcall GetAllowLicence();
 private:
   TConfiguration * FConfiguration;
   void __fastcall SetConfiguration(TConfiguration * value);
+  void __fastcall SetAllowLicence(bool value);
 public:
   virtual __fastcall TAboutDialog(TComponent* AOwner);
   void __fastcall LoadData();
   __property TConfiguration * Configuration  = { read=FConfiguration, write=SetConfiguration };
+  __property bool AllowLicence = { read=GetAllowLicence, write=SetAllowLicence };
 protected:
   void __fastcall OpenAddress(const AnsiString Address);
 };

+ 64 - 43
forms/Console.cpp

@@ -11,19 +11,19 @@
 #include <ScpMain.h>
 
 #include <VCLCommon.h>
-#include "WinConfiguration.h"
-#include "TerminalManager.h"
+#include <CustomWinConfiguration.h>
 //---------------------------------------------------------------------
 #pragma link "HistoryComboBox"
 #pragma link "PathLabel"
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------
-void __fastcall DoConsoleDialog()
+void __fastcall DoConsoleDialog(TTerminal * Terminal, const AnsiString Command)
 {
   TConsoleDialog * Dialog = new TConsoleDialog(Application);
   try
   {
-    Dialog->Execute();
+    Dialog->Terminal = Terminal;
+    Dialog->Execute(Command);
   }
   __finally
   {
@@ -96,50 +96,53 @@ void __fastcall TConsoleDialog::UpdateControls()
   EnableControl(ExecuteButton, !CommandEdit->Text.IsEmpty());
 }
 //---------------------------------------------------------------------
-bool __fastcall TConsoleDialog::Execute()
+bool __fastcall TConsoleDialog::Execute(const AnsiString Command)
 {
-  TTerminalManager * Manager = TTerminalManager::Instance();
-  TNotifyEvent POnChangeTerminal = Manager->OnChangeTerminal;
-  Manager->OnChangeTerminal = TerminalManagerChangeTerminal;
+  FPrevTerminalClose = NULL;;
+  if (FTerminal)
+  {
+    FPrevTerminalClose = FTerminal->OnClose;
+    // used instead of previous TTerminalManager::OnChangeTerminal
+    FTerminal->OnClose = TerminalClose;
+  }
+  
   try
   {
-    Terminal = TTerminalManager::Instance()->ActiveTerminal;
-    if (FTerminal)
+    TStrings * CommandsHistory = CustomWinConfiguration->History["Commands"];
+    if ((CommandsHistory != NULL) && (CommandsHistory->Count > 0))
     {
-      if (WinConfiguration->CommandsHistory->Count)
-      {
-        CommandEdit->Items = WinConfiguration->CommandsHistory;
-      }
-      else
-      {
-        CommandEdit->Items->Clear();
-      }
+      CommandEdit->Items = CommandsHistory;
+    }
+    else
+    {
+      CommandEdit->Items->Clear();
+    }
+    if (!Command.IsEmpty())
+    {
+      CommandEdit->Text = Command;
+      DoExecuteCommand();
     }
     ShowModal();
   }
   __finally
   {
-    assert(Manager->OnChangeTerminal == TerminalManagerChangeTerminal);
-    Manager->OnChangeTerminal = POnChangeTerminal;
     if (FTerminal)
     {
-      WinConfiguration->CommandsHistory = CommandEdit->Items;
+      assert(FTerminal->OnClose == TerminalClose);
+      FTerminal->OnClose = FPrevTerminalClose;
+      CustomWinConfiguration->History["Commands"] = CommandEdit->Items;
     }
   }
   return true;
 }
 //---------------------------------------------------------------------------
-void __fastcall TConsoleDialog::TerminalManagerChangeTerminal(TObject * /*Sender*/)
+void __fastcall TConsoleDialog::TerminalClose(TObject * Sender)
 {
-  TTerminal * NewTerminal = TTerminalManager::Instance()->ActiveTerminal;
-  if (!NewTerminal || NewTerminal->IsCapable[fcAnyCommand])
-  {
-    Terminal = TTerminalManager::Instance()->ActiveTerminal;
-  }
-  else
+  Close();
+  Terminal = NULL;
+  if (FPrevTerminalClose)
   {
-    Terminal = NULL;
-    Close();
+    FPrevTerminalClose(Sender);
   }
 }
 //---------------------------------------------------------------------------
@@ -148,27 +151,37 @@ void __fastcall TConsoleDialog::ExecuteButtonClick(TObject * /*Sender*/)
   ExecuteCommand();
 }
 //---------------------------------------------------------------------------
-void __fastcall TConsoleDialog::ExecuteCommand()
+void __fastcall TConsoleDialog::DoExecuteCommand()
 {
-  if (!FTerminal) return;
   CommandEdit->SelectAll();
+  FTerminal->ExceptionOnFail = true;
   try
   {
-    FTerminal->ExceptionOnFail = true;
-    try
-    {
-      AnsiString Command = CommandEdit->Text;
-      OutputMemo->Lines->Add(FORMAT("$ %s", ((Command))));
-      FAddOutput = true;
-      FTerminal->AnyCommand(Command);
-    }
-    __finally
+    AnsiString Command = CommandEdit->Text;
+    OutputMemo->Lines->Add(FORMAT("$ %s", ((Command))));
+    FAddOutput = true;
+    FTerminal->AnyCommand(Command);
+  }
+  __finally
+  {
+    FAddOutput = false;
+    if (FTerminal)
     {
-      FAddOutput = false;
       FTerminal->ExceptionOnFail = false;
-      if (FTerminal->Active) FTerminal->ReadCurrentDirectory();
+      if (FTerminal->Active)
+      {
+        FTerminal->ReadCurrentDirectory();
+      }
     }
   }
+}
+//---------------------------------------------------------------------------
+void __fastcall TConsoleDialog::ExecuteCommand()
+{
+  try
+  {
+    DoExecuteCommand();
+  }
   catch(Exception & E)
   {
     ShowExtendedException(&E, this);
@@ -196,3 +209,11 @@ void __fastcall TConsoleDialog::DoLogAddLine(TObject* /*Sender*/,
     }
   }
 }
+//---------------------------------------------------------------------------
+void __fastcall TConsoleDialog::CreateParams(TCreateParams & Params)
+{
+  TForm::CreateParams(Params);
+  Params.Style = Params.Style & ~WS_SYSMENU;
+}
+//---------------------------------------------------------------------------
+

+ 3 - 4
forms/Console.dfm

@@ -1,14 +1,13 @@
 object ConsoleDialog: TConsoleDialog
   Left = 349
   Top = 169
-  AutoScroll = False
+  Width = 567
+  Height = 431
   BorderIcons = [biSystemMenu, biMaximize]
   Caption = 'Console'
-  ClientHeight = 397
-  ClientWidth = 559
   Color = clBtnFace
   Constraints.MinHeight = 250
-  Constraints.MinWidth = 300
+  Constraints.MinWidth = 380
   ParentFont = True
   OldCreateOrder = True
   Position = poMainFormCenter

+ 9 - 2
forms/Console.h

@@ -32,22 +32,29 @@ __published:
   TPathLabel *DirectoryLabel;
   void __fastcall ExecuteButtonClick(TObject *Sender);
   void __fastcall CommandEditChange(TObject *Sender);
+  
 private:
   TTerminal * FTerminal;
   TNotifyEvent FOldChangeDirectory;
   TLogAddLineEvent FOldLogAddLine;
   bool FAddOutput;
+  TNotifyEvent FPrevTerminalClose;
+  
+  void __fastcall DoExecuteCommand();
   void __fastcall ExecuteCommand();
   void __fastcall SetTerminal(TTerminal * value);
-  void __fastcall TerminalManagerChangeTerminal(TObject * Sender);
+  void __fastcall TerminalClose(TObject * Sender);
+
 protected:
   void __fastcall DoChangeDirectory(TObject * Sender);
   void __fastcall DoLogAddLine(System::TObject* Sender, const AnsiString AddedLine);
   void __fastcall UpdateControls();
+  virtual void __fastcall CreateParams(TCreateParams & Params);
+
 public:
   virtual __fastcall ~TConsoleDialog();
 	virtual __fastcall TConsoleDialog(TComponent* AOwner);
-  Boolean __fastcall Execute();
+  bool __fastcall Execute(const AnsiString Command = "");
   __property TTerminal * Terminal = { read = FTerminal, write = SetTerminal };
 };
 //----------------------------------------------------------------------------

+ 126 - 62
forms/Copy.cpp

@@ -2,28 +2,26 @@
 #include <vcl.h>
 #pragma hdrstop
 
-#include <UnixDirView.h>
-
 #include <Common.h>
 #include <WinInterface.h>
 #include <ScpMain.h>
 #include <TextsWin.h>
 #include <VCLCommon.h>
+#include <CustomWinConfiguration.h>
 
 #include "Copy.h"
-#include "WinConfiguration.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
-#pragma link "ComboEdit"
 #pragma link "MoreButton"
 #pragma link "Rights"
 #pragma link "CopyParams"
+#pragma link "HistoryComboBox"
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------------
-bool __fastcall DoCopyDialog(TTransferDirection Direction,
-  TTransferType Type, bool DragDrop, TStrings * FileList,
+bool __fastcall DoCopyDialog(bool ToRemote,
+  bool Move, bool DragDrop, TStrings * FileList,
   bool AllowTransferMode, AnsiString & TargetDirectory,
-  TCopyParamType * Params)
+  TCopyParamType * Params, bool AllowDirectory)
 {
   bool Result;
   TCopyDialog *CopyDialog = new TCopyDialog(Application);
@@ -36,12 +34,13 @@ bool __fastcall DoCopyDialog(TTransferDirection Direction,
       CopyDialog->AllowTransferMode = false; // Default is true
       Params->TransferMode = tmBinary;
     }
-    CopyDialog->Direction = Direction;
-    CopyDialog->DragDrop = DragDrop && (Direction == tdToLocal);
+    CopyDialog->ToRemote = ToRemote;
+    CopyDialog->DragDrop = DragDrop && !ToRemote;
     if (!CopyDialog->DragDrop) CopyDialog->Directory = TargetDirectory;
     CopyDialog->FileList = FileList;
     CopyDialog->Params = *Params;
-    CopyDialog->TransferType = Type;
+    CopyDialog->Move = Move;
+    CopyDialog->AllowDirectory = AllowDirectory;
     Result = CopyDialog->Execute();
     if (Result)
     {
@@ -60,65 +59,107 @@ __fastcall TCopyDialog::TCopyDialog(TComponent* Owner)
         : TForm(Owner)
 {
   // on start set different value than we want to allow property-setter to proceed
-  FDirection = tdToLocal;
-  FTransferType = ttMove;
+  FToRemote = false;
+  FMove = true;
 
-  Direction = tdToRemote;
-  TransferType = ttCopy;
-  AllowTransferMode = True;
+  ToRemote = true;
+  Move = false;
+  AllowTransferMode = true;
+  AllowDirectory = true;
 
   UseSystemSettings(this);
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyDialog::SetDirection(TTransferDirection value)
+void __fastcall TCopyDialog::SetToRemote(bool value)
 {
-  if (FDirection != value)
+  if (FToRemote != value)
   {
     AnsiString ADirectory = DirectoryEdit->Text;
-    FDirection = value;
+    FToRemote = value;
     DirectoryEdit->Text = ADirectory;
 
-    RemoteDirectoryEdit->Visible = False;
-    LocalDirectoryEdit->Visible = False;
+    RemoteDirectoryEdit->Visible = false;
+    LocalDirectoryEdit->Visible = false;
     DirectoryEdit->Visible = !DragDrop;
+    DirectoryEdit->Enabled = AllowDirectory;
     DirectoryLabel->FocusControl = DirectoryEdit;
     UpdateControls();
-    CopyParamsFrame->Direction = Direction == tdToLocal ? pdToLocal : pdToRemote;
+    CopyParamsFrame->Direction = !ToRemote ? pdToLocal : pdToRemote;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyDialog::SetAllowDirectory(bool value)
+{
+  if (AllowDirectory != value)
+  {
+    FAllowDirectory = value;
+    DirectoryEdit->Enabled = AllowDirectory;
   }
 }
 //---------------------------------------------------------------------------
-TCustomEdit * __fastcall TCopyDialog::GetDirectoryEdit()
+THistoryComboBox * __fastcall TCopyDialog::GetDirectoryEdit()
 {
-  assert((Direction == tdToRemote) || (Direction == tdToLocal));
-  return Direction == tdToRemote ? (TCustomEdit *)RemoteDirectoryEdit :
-    (TCustomEdit *)LocalDirectoryEdit;
+  return ToRemote ? RemoteDirectoryEdit : LocalDirectoryEdit;
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyDialog::SetFileMask(const AnsiString value)
+{
+  if (!DragDrop)
+  {
+    DirectoryEdit->Text = Directory + value;
+  }
+  else
+  {
+    FFileMask = value;
+  }
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall TCopyDialog::GetFileMask()
+{
+  if (!DragDrop)
+  {
+    return ToRemote ? UnixExtractFileName(DirectoryEdit->Text) :
+      ExtractFileName(DirectoryEdit->Text);
+  }
+  else
+  {
+    return FFileMask;
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::SetParams(TCopyParamType value)
 {
   CopyParamsFrame->Params = value;
+  SetFileMask(value.FileMask);
 }
 //---------------------------------------------------------------------------
 TCopyParamType __fastcall TCopyDialog::GetParams()
 {
-  TCopyParamType Params;
-  Params = CopyParamsFrame->Params;
+  TCopyParamType Params = CopyParamsFrame->Params;
+  Params.FileMask = GetFileMask();
   return Params;
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::SetDirectory(AnsiString value)
 {
-  DirectoryEdit->Text = value;
+  value = ToRemote ? UnixIncludeTrailingBackslash(value) :
+    IncludeTrailingBackslash(value);
+  DirectoryEdit->Text = value + GetFileMask();
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TCopyDialog::GetDirectory()
 {
-  assert(((Direction == tdToRemote) || (Direction == tdToLocal)) &&
-    DirectoryEdit && !DragDrop);
+  assert(DirectoryEdit && !DragDrop);
 
   AnsiString Result = DirectoryEdit->Text;
-  if (Direction == tdToRemote) Result = UnixIncludeTrailingBackslash(Result);
-    else Result = IncludeTrailingBackslash(Result);
+  if (ToRemote)
+  {
+    Result = UnixIncludeTrailingBackslash(UnixExtractFilePath(Result));
+  }
+  else
+  {
+    Result = IncludeTrailingBackslash(ExtractFilePath(Result));
+  }
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -135,18 +176,14 @@ void __fastcall TCopyDialog::UpdateControls()
 {
   if (FileList && FileList->Count)
   {
-    assert((Direction == tdToRemote) || (Direction == tdToLocal));
-
-    AnsiString TransferStr =
-      LoadStr(FTransferType == ttCopy ? COPY_COPY : COPY_MOVE);
+    AnsiString TransferStr = LoadStr(!Move ? COPY_COPY : COPY_MOVE);
     AnsiString DirectionStr =
-      LoadStr((DragDrop ? COPY_TODROP :
-         (FDirection == tdToLocal ? COPY_TOLOCAL : COPY_TOREMOTE)));
+      LoadStr((DragDrop ? COPY_TODROP : (!ToRemote ? COPY_TOLOCAL : COPY_TOREMOTE)));
 
     if (FileList->Count == 1)
     {
       AnsiString FileName;
-      if (FDirection == tdToLocal) FileName = UnixExtractFileName(FFileList->Strings[0]);
+      if (!ToRemote) FileName = UnixExtractFileName(FFileList->Strings[0]);
         else FileName = ExtractFileName(FFileList->Strings[0]);
       DirectoryLabel->Caption = FMTLOAD(COPY_FILE,
         (TransferStr, FileName, DirectionStr));
@@ -158,7 +195,7 @@ void __fastcall TCopyDialog::UpdateControls()
     }
   }
 
-  if (TransferType == ttCopy)
+  if (!Move)
   {
     Caption = LoadStr(COPY_COPY_CAPTION);
     CopyButton->Caption = LoadStr(COPY_COPY_BUTTON);
@@ -168,6 +205,8 @@ void __fastcall TCopyDialog::UpdateControls()
     Caption = LoadStr(COPY_MOVE_CAPTION);
     CopyButton->Caption = LoadStr(COPY_MOVE_BUTTON);
   }
+  
+  LocalDirectoryBrowseButton->Visible = !ToRemote && !DragDrop && AllowDirectory;
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::SetDragDrop(Boolean value)
@@ -177,28 +216,27 @@ void __fastcall TCopyDialog::SetDragDrop(Boolean value)
     FDragDrop = value;
     if (value)
     {
-      Direction = tdToLocal;
+      ToRemote = false;
       DirectoryEdit->Text = "";
     }
-    DirectoryEdit->Visible = !value || (Direction == tdToRemote);
+    DirectoryEdit->Visible = !value || ToRemote;
     UpdateControls();
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyDialog::SetTransferType(TTransferType value)
+void __fastcall TCopyDialog::SetMove(bool value)
 {
-  if (TransferType != value)
+  if (Move != value)
   {
-    FTransferType = value;
+    FMove = value;
     UpdateControls();
   }
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::FormShow(TObject * /*Sender*/)
 {
-  assert(FileList && (FileList->Count > 0) &&
-    ((Direction == tdToLocal) || !DragDrop));
-  if (!DragDrop) DirectoryEdit->SetFocus();
+  assert(FileList && (FileList->Count > 0) && (!ToRemote || !DragDrop));
+  if (!DragDrop && AllowDirectory) DirectoryEdit->SetFocus();
     else
   if (MoreButton->Expanded) MorePanel->SetFocus();
     else CopyButton->SetFocus();
@@ -206,10 +244,10 @@ void __fastcall TCopyDialog::FormShow(TObject * /*Sender*/)
 //---------------------------------------------------------------------------
 bool __fastcall TCopyDialog::Execute()
 {
+  DirectoryEdit->Items = CustomWinConfiguration->History[
+    ToRemote ? "RemoteTarget" : "LocalTarget"];
   SaveSettingsCheck->Checked = false;
-  MoreButton->Expanded =
-    WinConfiguration->CopyParamDialogExpanded && WinConfiguration->ExpertMode;
-  MoreButton->Visible = WinConfiguration->ExpertMode;
+  MoreButton->Expanded = GUIConfiguration->CopyParamDialogExpanded;
   CopyParamsFrame->BeforeExecute();
   bool Result = (ShowModal() == mrOk);
   if (Result)
@@ -218,11 +256,14 @@ bool __fastcall TCopyDialog::Execute()
     Configuration->BeginUpdate();
     try
     {
-      WinConfiguration->CopyParamDialogExpanded = MoreButton->Expanded;
+      GUIConfiguration->CopyParamDialogExpanded = MoreButton->Expanded;
       if (SaveSettingsCheck->Checked)
       {
         Configuration->CopyParam = Params;
       }
+      DirectoryEdit->SaveToHistory();
+      CustomWinConfiguration->History[ToRemote ?
+        "RemoteTarget" : "LocalTarget"] = DirectoryEdit->Items;
     }
     __finally
     {
@@ -237,20 +278,30 @@ void __fastcall TCopyDialog::FormCloseQuery(TObject * /*Sender*/,
 {
   if (ModalResult != mrCancel)
   {
-    if ((Direction == tdToLocal) && !DragDrop && !DirectoryExists(Directory))
+    if (!ToRemote && !DragDrop)
     {
-      if (MessageDialog(FMTLOAD(CREATE_LOCAL_DIRECTORY, (Directory)),
-            qtConfirmation, qaOK | qaCancel, 0) != qaCancel)
+      AnsiString Dir = Directory;
+      AnsiString Drive = ExtractFileDrive(Dir);
+      if (Drive.IsEmpty() || (Drive.Length() != 2) || (Drive[2] != ':'))
       {
-        if (!ForceDirectories(Directory))
-        {
-          SimpleErrorDialog(FMTLOAD(CREATE_LOCAL_DIR_ERROR, (Directory)));
-          CanClose = false;
-        }
+        SimpleErrorDialog(LoadStr(ABSOLUTE_PATH_REQUIRED));
+        CanClose = false;
       }
-      else
+      else if (!DirectoryExists(Dir))
       {
-        CanClose = False;
+        if (MessageDialog(FMTLOAD(CREATE_LOCAL_DIRECTORY, (Dir)),
+              qtConfirmation, qaOK | qaCancel, 0) != qaCancel)
+        {
+          if (!ForceDirectories(Dir))
+          {
+            SimpleErrorDialog(FMTLOAD(CREATE_LOCAL_DIR_ERROR, (Dir)));
+            CanClose = false;
+          }
+        }
+        else
+        {
+          CanClose = False;
+        }
       }
 
       if (!CanClose)
@@ -285,3 +336,16 @@ bool __fastcall TCopyDialog::GetAllowTransferMode()
 {
   return CopyParamsFrame->AllowTransferMode;
 }
+//---------------------------------------------------------------------------
+void __fastcall TCopyDialog::LocalDirectoryBrowseButtonClick(
+      TObject * /*Sender*/)
+{
+  assert(!ToRemote);
+  AnsiString Directory = LocalDirectoryEdit->Text;
+  if (SelectDirectory(Directory, LoadStr(SELECT_LOCAL_DIRECTORY), true))
+  {
+    LocalDirectoryEdit->Text = Directory;
+  }
+}
+//---------------------------------------------------------------------------
+

+ 23 - 11
forms/Copy.dfm

@@ -27,26 +27,26 @@ object CopyDialog: TCopyDialog
     Height = 13
     Caption = 'Copy 2 selected files to remote directory'
   end
-  object LocalDirectoryEdit: TDirectoryEdit
+  object LocalDirectoryEdit: THistoryComboBox
     Left = 8
     Top = 25
-    Width = 496
+    Width = 410
     Height = 21
-    AcceptFiles = True
-    DialogText = 'Select target local directory.'
-    ClickKey = 16397
     Anchors = [akLeft, akTop, akRight]
+    ItemHeight = 13
     TabOrder = 0
     Text = 'LocalDirectoryEdit'
   end
-  object RemoteDirectoryEdit: TEdit
+  object RemoteDirectoryEdit: THistoryComboBox
     Left = 8
     Top = 25
     Width = 494
     Height = 21
+    AutoComplete = False
     Anchors = [akLeft, akTop, akRight]
+    ItemHeight = 13
     MaxLength = 1000
-    TabOrder = 1
+    TabOrder = 2
     Text = 'RemoteDirectoryEdit'
   end
   object MoreButton: TMoreButton
@@ -56,7 +56,7 @@ object CopyDialog: TCopyDialog
     Height = 25
     Anchors = [akRight, akBottom]
     Caption = '<< &Less'
-    TabOrder = 3
+    TabOrder = 4
     Panel = MorePanel
     RepositionForm = True
   end
@@ -69,7 +69,7 @@ object CopyDialog: TCopyDialog
     Caption = 'Copy'
     Default = True
     ModalResult = 1
-    TabOrder = 4
+    TabOrder = 5
   end
   object CancelButton: TButton
     Left = 427
@@ -80,7 +80,7 @@ object CopyDialog: TCopyDialog
     Cancel = True
     Caption = 'Cancel'
     ModalResult = 2
-    TabOrder = 5
+    TabOrder = 6
   end
   object MorePanel: TPanel
     Left = 0
@@ -89,7 +89,7 @@ object CopyDialog: TCopyDialog
     Height = 170
     Anchors = [akLeft, akTop, akRight, akBottom]
     BevelOuter = bvNone
-    TabOrder = 2
+    TabOrder = 3
     object SaveSettingsCheck: TCheckBox
       Left = 8
       Top = 152
@@ -105,10 +105,22 @@ object CopyDialog: TCopyDialog
       Height = 149
       TabOrder = 0
       inherited RemotePropertiesGroup: TXPGroupBox
+        inherited RightsFrame: TRightsFrame
+          PopupMenu = CopyParamsFrame.RightsFrame.RightsPopup
+        end
         inherited PreserveRightsCheck: TCheckBox
           Left = 12
         end
       end
     end
   end
+  object LocalDirectoryBrowseButton: TButton
+    Left = 427
+    Top = 23
+    Width = 75
+    Height = 25
+    Caption = 'B&rowse...'
+    TabOrder = 1
+    OnClick = LocalDirectoryBrowseButtonClick
+  end
 end

+ 19 - 12
forms/Copy.h

@@ -6,11 +6,10 @@
 #include <Controls.hpp>
 #include <StdCtrls.hpp>
 #include <Forms.hpp>
-#include <ComboEdit.hpp>
 #include <Mask.hpp>
 #include <MoreButton.hpp>
 #include <ExtCtrls.hpp>
-#include <UnixDirView.h>
+#include <HistoryComboBox.hpp>
 
 #include "Rights.h"
 #include "CopyParams.h"
@@ -19,43 +18,51 @@ class TCopyDialog : public TForm
 {
 __published:
   TLabel *DirectoryLabel;
-  TDirectoryEdit *LocalDirectoryEdit;
-  TEdit *RemoteDirectoryEdit;
+  THistoryComboBox *LocalDirectoryEdit;
+  THistoryComboBox *RemoteDirectoryEdit;
   TMoreButton *MoreButton;
   TButton *CopyButton;
   TButton *CancelButton;
   TPanel *MorePanel;
   TCheckBox *SaveSettingsCheck;
   TCopyParamsFrame *CopyParamsFrame;
+  TButton *LocalDirectoryBrowseButton;
   void __fastcall FormShow(TObject *Sender);
   void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
+  void __fastcall LocalDirectoryBrowseButtonClick(TObject *Sender);
 private:
-  TTransferDirection FDirection;
+  bool FToRemote;
   bool FDragDrop;
   TStrings * FFileList;
-  TTransferType FTransferType;
+  bool FMove;
+  AnsiString FFileMask;
+  bool FAllowDirectory;
   bool __fastcall GetAllowTransferMode();
   AnsiString __fastcall GetDirectory();
-  void __fastcall SetDirection(TTransferDirection value);
-  TCustomEdit * __fastcall GetDirectoryEdit();
+  void __fastcall SetToRemote(bool value);
+  THistoryComboBox * __fastcall GetDirectoryEdit();
   void __fastcall SetParams(TCopyParamType value);
   TCopyParamType __fastcall GetParams();
   void __fastcall SetAllowTransferMode(Boolean value);
   void __fastcall SetDirectory(AnsiString value);
   void __fastcall SetDragDrop(Boolean value);
   void __fastcall SetFileList(TStrings * value);
-  void __fastcall SetTransferType(TTransferType value);
+  void __fastcall SetMove(bool value);
+  void __fastcall SetFileMask(const AnsiString value);
+  AnsiString __fastcall GetFileMask();
+  void __fastcall SetAllowDirectory(bool value);
 public:
   bool __fastcall Execute();
   __fastcall TCopyDialog(TComponent* Owner);
   __property bool AllowTransferMode = { read = GetAllowTransferMode, write = SetAllowTransferMode };
-  __property TTransferDirection Direction = { read = FDirection, write = SetDirection };
+  __property bool ToRemote = { read = FToRemote, write = SetToRemote };
   __property AnsiString Directory = { read = GetDirectory, write = SetDirectory };
-  __property TCustomEdit * DirectoryEdit = { read = GetDirectoryEdit };
+  __property THistoryComboBox * DirectoryEdit = { read = GetDirectoryEdit };
   __property bool DragDrop = { read = FDragDrop, write = SetDragDrop };
   __property TStrings * FileList = { read = FFileList, write = SetFileList };
   __property TCopyParamType Params = { read = GetParams, write = SetParams };
-  __property TTransferType TransferType = { read = FTransferType, write = SetTransferType };
+  __property bool Move = { read = FMove, write = SetMove };
+  __property bool AllowDirectory = { read = FAllowDirectory, write = SetAllowDirectory };
 protected:
   void __fastcall UpdateControls();
 };

+ 5 - 3
forms/CopyParams.cpp

@@ -7,7 +7,7 @@
 #include <Common.h>
 #include <VCLCommon.h>
 #include <ScpMain.h>
-#include "WinConfiguration.h"
+#include "CustomWinConfiguration.h"
 #include "TextsWin.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
@@ -156,13 +156,15 @@ void __fastcall TCopyParamsFrame::ControlChange(TObject * /*Sender*/)
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamsFrame::BeforeExecute()
 {
-  AsciiFileMaskCombo->Items->Text = WinConfiguration->MaskHistory;
+  assert(CustomWinConfiguration);
+  AsciiFileMaskCombo->Items = CustomWinConfiguration->History["Mask"];
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamsFrame::AfterExecute()
 {
+  assert(CustomWinConfiguration);
   AsciiFileMaskCombo->SaveToHistory();
-  WinConfiguration->MaskHistory = AsciiFileMaskCombo->Items->Text;
+  CustomWinConfiguration->History["Mask"] = AsciiFileMaskCombo->Items;
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamsFrame::SelectMask(Integer Start, Integer Length)

+ 1 - 1
forms/CopyParams.dfm

@@ -84,7 +84,7 @@ object CopyParamsFrame: TCopyParamsFrame
       Top = 36
       Width = 163
       Height = 85
-      PopupMenu = NonVisualDataModule.RightsPopup
+      PopupMenu = RightsFrame.RightsPopup
       TabOrder = 1
       inherited OthersButton: TSpeedButton
         Width = 56

+ 139 - 150
forms/CustomScpExplorer.cpp

@@ -15,11 +15,13 @@
 #include <VCLCommon.h>
 #include <Log.h>
 
+#include "GUITools.h"
 #include "NonVisual.h"
 #include "Tools.h"
 #include "WinConfiguration.h"
 #include "TerminalManager.h"
 #include <Progress.h>
+#include <SynchronizeProgress.h>
 #include <OperationStatus.h>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
@@ -68,15 +70,19 @@ __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
   FShowStatusBarHint = false;
   FIgnoreNextSysCommand = false;
   FErrorList = NULL;
+  FSynchronizeProgressForm = NULL;
+  FProgressForm = NULL;
 
   UseSystemSettings(this);
 
   TComboBox * SessionCombo = dynamic_cast<TComboBox*>(GetComponent(fcSessionCombo));
-  assert(SessionCombo);
-  SessionCombo->OnDrawItem = SessionComboDrawItem;
-  SessionCombo->OnDropDown = SessionComboDropDown;
-  SessionCombo->OnChange = SessionComboChange;
-  SessionCombo->Hint = NonVisualDataModule->OpenedSessionsAction->Hint;
+  if (SessionCombo != NULL)
+  {
+    SessionCombo->OnDrawItem = SessionComboDrawItem;
+    SessionCombo->OnDropDown = SessionComboDropDown;
+    SessionCombo->OnChange = SessionComboChange;
+    SessionCombo->Hint = NonVisualDataModule->OpenedSessionsAction->Hint;
+  }
 
   TToolBar * MenuToolBar = dynamic_cast<TToolBar*>(GetComponent(fcMenuToolBar));
   assert(MenuToolBar);
@@ -102,18 +108,9 @@ void __fastcall TCustomScpExplorerForm::SetTerminal(TTerminal * value)
   {
     if (FTerminal)
     {
-      /*assert(Terminal->OnProgress == OperationProgress);
-      Terminal->OnProgress = NULL;
-      assert(Terminal->OnFinished == OperationFinished);
-      Terminal->OnFinished = NULL;*/
       UpdateSessionData(Terminal->SessionData);
     }
     FTerminal = value;
-    if (Terminal)
-    {
-      /*Terminal->OnProgress = OperationProgress;
-      Terminal->OnFinished = OperationFinished;*/
-    }
     TerminalChanged();
   }
 }
@@ -159,8 +156,9 @@ bool __fastcall TCustomScpExplorerForm::CopyParamDialog(
   assert(Terminal && Terminal->Active);
   if (Confirm)
   {
-    return DoCopyDialog(Direction, Type, DragDrop, FileList,
-      Terminal->IsCapable[fcTextMode], TargetDirectory, &CopyParam);
+    return DoCopyDialog(Direction == tdToRemote, Type == ttMove,
+      DragDrop, FileList, Terminal->IsCapable[fcTextMode], TargetDirectory,
+      &CopyParam, true);
   }
   else
   {
@@ -206,6 +204,7 @@ void __fastcall TCustomScpExplorerForm::FileOperationProgress(
   {
     //assert(Screen && Screen->ActiveCustomForm);
     FProgressForm = new TProgressForm(Application);
+    FProgressForm->DeleteToRecycleBin = WinConfiguration->DeleteToRecycleBin;
     // When main window is hidden, we suppose "/upload" mode
     if (!Visible)
     {
@@ -215,14 +214,7 @@ void __fastcall TCustomScpExplorerForm::FileOperationProgress(
   // operation is finished (or terminated), so we hide progress form
   else if (!ProgressData.InProgress && FProgressForm)
   {
-    try
-    {
-      delete FProgressForm;
-    }
-    __finally
-    {
-      FProgressForm = NULL;
-    }
+    SAFE_DESTROY(FProgressForm);
   }
 
   if (FProgressForm)
@@ -306,11 +298,46 @@ void __fastcall TCustomScpExplorerForm::RemoteDirViewContextPopup(
     NonVisualDataModule->CurrentOpenMenuItem->Visible = WinConfiguration->ExpertMode;
     NonVisualDataModule->CurentEditMenuItem->Visible = WinConfiguration->ExpertMode;
 
-    NonVisualDataModule->RemoteDirViewPopup->Popup(ScreenPoint.x, ScreenPoint.y);
+    reinterpret_cast<TPopupMenu*>(GetComponent(fcRemotePopup))->Popup(
+      ScreenPoint.x, ScreenPoint.y);
   }
   Handled = true;
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::BatchStart(void *& Storage)
+{
+  assert(FErrorList == NULL);
+
+  Storage = new bool;
+  if (HasDirView[osLocal])
+  {
+    *static_cast<bool*>(Storage) = DirView(osLocal)->WatchForChanges;
+    DirView(osLocal)->WatchForChanges = false;
+  }
+
+  if (WinConfiguration->ContinueOnError)
+  {
+    FErrorList = new TStringList();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::BatchEnd(void * Storage)
+{
+  assert(Storage != NULL);
+
+  if (FErrorList)
+  {
+    HandleErrorList(FErrorList);
+  }
+
+  if (HasDirView[osLocal])
+  {
+    DirView(osLocal)->WatchForChanges = *static_cast<bool*>(Storage);
+  }
+
+  delete Storage;
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::ExecuteFileOperation(TFileOperation Operation,
   TOperationSide Side, bool OnFocused, bool NoConfirmation, void * Param)
 {
@@ -327,14 +354,12 @@ void __fastcall TCustomScpExplorerForm::ExecuteFileOperation(TFileOperation Oper
     }
   }
 
-  bool PrevWatchForChanges = (HasDirView[osLocal] ? DirView(osLocal)->WatchForChanges : false);
   TStrings * FileList = NULL;
+  void * BatchStorage;
+
+  BatchStart(BatchStorage);
   try
   {
-    if (WinConfiguration->ContinueOnError)
-    {
-      FErrorList = new TStringList();
-    }
     FileList = DirView(Side)->CreateFileList(OnFocused, (Side == osLocal), NULL);
 
     if ((Operation == foCopy) || (Operation == foMove))
@@ -353,11 +378,6 @@ void __fastcall TCustomScpExplorerForm::ExecuteFileOperation(TFileOperation Oper
 
         try
         {
-          if (HasDirView[osLocal])
-          {
-            DirView(osLocal)->WatchForChanges = false;
-          }
-
           if (Side == osLocal)
           {
             int Params = 0;
@@ -477,14 +497,7 @@ void __fastcall TCustomScpExplorerForm::ExecuteFileOperation(TFileOperation Oper
   }
   __finally
   {
-    if (FErrorList)
-    {
-      HandleErrorList(FErrorList);
-    }
-    if (HasDirView[osLocal])
-    {
-      DirView(osLocal)->WatchForChanges = PrevWatchForChanges;
-    }
+    BatchEnd(BatchStorage);
     delete FileList;
   }
 }
@@ -697,16 +710,16 @@ void __fastcall TCustomScpExplorerForm::ExecuteFile(TOperationSide Side,
       {
         bool Deleted;
         AnsiString DirName = ExtractFilePath(FileName);
-        
+
         if (WinConfiguration->ForceDeleteTempFolder)
         {
-          Deleted = FileOperatorDelete(ExcludeTrailingBackslash(DirName), false);
+          Deleted = RecursiveDeleteFile(ExcludeTrailingBackslash(DirName), false);
         }
         else
         {
           Deleted = DeleteFile(FileName) && RemoveDir(DirName);
         }
-        
+
         if (!Deleted)
         {
           throw Exception(FMTLOAD(DELETE_TEMP_EXECUTE_FILE_ERROR, (DirName)));
@@ -826,64 +839,13 @@ void __fastcall TCustomScpExplorerForm::DeleteFiles(TOperationSide Side,
     }
     else
     {
-      TFileOperationProgressType Progress(&OperationProgress, &OperationFinished);
-      bool DisconnectWhenComplete = false;
-
       try
       {
-        Progress.Start(foDelete, Side, FileList->Count);
-        try
-        {
-          int Index = 0;
-          while ((Index < FileList->Count) && (Progress.Cancel == csContinue))
-          {
-            Progress.SetFile(FileList->Strings[Index]);
-            AnsiString OnlyFileName = (Side == osLocal ?
-              ExtractFileName(Progress.FileName) : UnixExtractFileName(Progress.FileName));
-            try
-            {
-              if (!FileOperatorDelete(Progress.FileName, WinConfiguration->DeleteToRecycleBin))
-              {
-                throw Exception(FMTLOAD(DELETE_LOCAL_FILE_ERROR, (Progress.FileName)));
-              }
-              Progress.Finish(OnlyFileName, true, DisconnectWhenComplete);
-            }
-            catch (EAbort & E)
-            {
-              break;
-            }
-            catch (Exception & E)
-            {
-              int Result = ExceptionMessageDialog(&E, qtError, qaRetry | qaSkip | qaAbort);
-              if (Result == qaRetry)
-              {
-                Index--;
-              }
-              else
-              {
-                Progress.Finish(OnlyFileName, false, DisconnectWhenComplete);
-                if (Result == qaAbort)
-                {
-                  break;
-                }
-              }
-            }
-            Index++;
-          }
-        }
-        __finally
-        {
-          Progress.Stop();
-        }
+        Terminal->DeleteLocalFiles(FileList);
       }
       __finally
       {
-        DView->Reload(True);
-      }
-
-      if (DisconnectWhenComplete && (Progress.Cancel == csContinue))
-      {
-        Terminal->CloseOnCompletion();
+        DView->Reload(true);
       }
     }
   }
@@ -1133,8 +1095,7 @@ void __fastcall TCustomScpExplorerForm::SessionStatusBarMouseMove(
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::ApplicationHint(TObject * /*Sender*/)
 {
-  TStatusBar * SessionStatusBar = (TStatusBar *)GetComponent(fcStatusBar);
-  assert(SessionStatusBar && Application);
+  assert(GetComponent(fcStatusBar) && Application);
   AnsiString AHint = GetLongHint(Application->Hint);
   FShowStatusBarHint = Active && !AHint.IsEmpty() && (AHint != "X");
   if (FShowStatusBarHint)
@@ -1154,7 +1115,7 @@ void __fastcall TCustomScpExplorerForm::NewSession()
   try
   {
     Data->Assign(StoredSessions->DefaultSettings);
-    if (DoLoginDialog(StoredSessions, Data, false))
+    if (DoLoginDialog(StoredSessions, Data, loAddSession))
     {
       assert(Data->CanLogin);
       TTerminalManager * Manager = TTerminalManager::Instance();
@@ -1231,10 +1192,10 @@ void __fastcall TCustomScpExplorerForm::SetComponentVisible(Word Component, Bool
 {
   TControl * Control = GetComponent((Word)(Component & 0x00FF));
   assert(Control);
-  if (Control->InheritsFrom(__classid(TCoolBar)) && (Component & 0xFF00))
+  if ((dynamic_cast<TCoolBar*>(Control) != NULL) && (Component & 0xFF00))
   {
-    TCoolBand * Band = ((TCoolBand *)(((TCoolBar*)Control)->Bands->
-      FindItemID((Component & 0xFF00) >> 8)));
+    TCoolBand * Band = GetCoolBand(dynamic_cast<TCoolBar*>(Control),
+      (Component & 0xFF00) >> 8);
     assert(Band);
     Band->Visible = value;
   }
@@ -1247,12 +1208,15 @@ void __fastcall TCustomScpExplorerForm::SetComponentVisible(Word Component, Bool
 bool __fastcall TCustomScpExplorerForm::GetComponentVisible(Word Component)
 {
   TControl * Control = GetComponent((Word)(Component & 0x00FF));
-  assert(Control);
-  if (Control->InheritsFrom(__classid(TCoolBar)) && (Component & 0xFF00))
+  if (Control == NULL)
+  {
+    return false;
+  }
+  else if ((dynamic_cast<TCoolBar*>(Control) != NULL) && (Component & 0xFF00))
   {
-    TCoolBand * Band = ((TCoolBand *)(((TCoolBar*)Control)->Bands->
-      FindItemID((Component & 0xFF00) >> 8)));
-    return Band ? Band->Visible : false;
+    TCoolBand * Band = GetCoolBand(dynamic_cast<TCoolBar*>(Control),
+      (Component & 0xFF00) >> 8);
+    return Band != NULL ? Band->Visible : false;
   }
   else
   {
@@ -1260,11 +1224,17 @@ bool __fastcall TCustomScpExplorerForm::GetComponentVisible(Word Component)
   }
 }
 //---------------------------------------------------------------------------
+TCoolBand * __fastcall TCustomScpExplorerForm::GetCoolBand(TCoolBar * Coolbar, int ID)
+{
+  return dynamic_cast<TCoolBand *>(Coolbar->Bands->FindItemID(ID));
+}
+//---------------------------------------------------------------------------
 TControl * __fastcall TCustomScpExplorerForm::GetComponent(Byte Component)
 {
   switch (Component) {
     case fcStatusBar: return RemoteStatusBar;
     case fcCoolBar: return TopCoolBar;
+    case fcRemotePopup: return reinterpret_cast<TControl *>(NonVisualDataModule->RemoteDirViewPopup);
     default: return NULL;
   }
 }
@@ -1335,6 +1305,56 @@ void __fastcall TCustomScpExplorerForm::SynchronizeDirectories()
   assert(false);
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::FullSynchronizeDirectories()
+{
+  assert(false);
+}
+//---------------------------------------------------------------------------
+bool __fastcall TCustomScpExplorerForm::DoFullSynchronizeDirectories(
+  AnsiString & LocalDirectory, AnsiString & RemoteDirectory)
+{
+  bool Result;
+  TSynchronizeMode Mode = smRemote;
+  int Params = spDelete | spNoConfirmation;
+
+  Result = DoFullSynchronizeDialog(Mode, Params, LocalDirectory, RemoteDirectory);
+  if (Result)
+  {
+    assert(!FAutoOperation);
+    void * BatchStorage;
+    BatchStart(BatchStorage);
+    FAutoOperation = true;
+
+    try
+    {
+      FSynchronizeProgressForm = new TSynchronizeProgressForm(Application);
+      FSynchronizeProgressForm->Start();
+
+      Terminal->Synchronize(LocalDirectory, RemoteDirectory,
+        static_cast<TTerminal::TSynchronizeMode>(Mode),
+        Params, TerminalSynchronizeDirectory);
+    }
+    __finally
+    {
+      FAutoOperation = false;
+      SAFE_DESTROY(FSynchronizeProgressForm);
+      BatchEnd(BatchStorage);
+      if (HasDirView[osLocal])
+      {
+        DirView(osLocal)->Reload(true);
+      }
+    }
+  }
+
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::TerminalSynchronizeDirectory(
+  const AnsiString LocalDirectory, const AnsiString RemoteDirectory, bool & Continue)
+{
+  FSynchronizeProgressForm->SetData(LocalDirectory, RemoteDirectory, Continue);
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::ExploreLocalDirectory()
 {
   assert(false);
@@ -1465,7 +1485,7 @@ void __fastcall TCustomScpExplorerForm::DoOpenDirectoryDialog(
     try
     {
       AnsiString Name = DirView(Side)->PathName;
-      if (OpenDirectoryDialog(Mode, Side, Name, VisitedDirectories, Terminal))
+      if (::DoOpenDirectoryDialog(Mode, Side, Name, VisitedDirectories, Terminal))
       {
         DirView(Side)->Path = Name;
       }
@@ -1479,45 +1499,12 @@ void __fastcall TCustomScpExplorerForm::DoOpenDirectoryDialog(
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::OpenInPutty()
 {
-  if (FileExists(WinConfiguration->PuttyPath))
-  {
-    THierarchicalStorage * Storage = NULL;
-    TSessionData * ExportData = NULL;
-    try
-    {
-      ExportData = new TSessionData("");
-      ExportData->Assign(Terminal->SessionData);
-      ExportData->Modified = true;
-      ExportData->Name = WinConfiguration->PuttySession;
-      ExportData->Password = "";
-      Storage = new TRegistryStorage(Configuration->PuttySessionsKey);
-      Storage->AccessMode = smReadWrite;
-      if (Storage->OpenRootKey(true))
-      {
-        ExportData->Save(Storage, true);
-      }
-    }
-    __finally
-    {
-      delete Storage;
-      delete ExportData;
-    }
-
-    if (!ExecuteShell(WinConfiguration->PuttyPath,
-          FORMAT("-load \"%s\"", (WinConfiguration->PuttySession))))
-    {
-      throw Exception(FMTLOAD(EXECUTE_APP_ERROR, (WinConfiguration->PuttyPath)));
-    }
-  }
-  else
-  {
-    throw Exception(FMTLOAD(FILE_NOT_FOUND, (WinConfiguration->PuttyPath)));
-  }
+  OpenSessionInPutty(Terminal->SessionData);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::OpenConsole()
 {
-  DoConsoleDialog();
+  DoConsoleDialog(Terminal);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::DirViewDDDragEnter(
@@ -1530,6 +1517,7 @@ void __fastcall TCustomScpExplorerForm::DirViewDDDragEnter(
 void __fastcall TCustomScpExplorerForm::DirViewDDDragLeave(
       TObject *Sender)
 {
+  USEDPARAM(Sender);
   assert(FDDTargetDirView == Sender);
   FDDTargetDirView = NULL;
 }
@@ -1614,9 +1602,11 @@ void __fastcall TCustomScpExplorerForm::LastTerminalClosed(TObject * /*Sender*/)
 void __fastcall TCustomScpExplorerForm::TerminalListChanged(TObject * /*Sender*/)
 {
   TCustomCombo * SessionCombo = dynamic_cast<TCustomCombo *>(GetComponent(fcSessionCombo));
-  assert(SessionCombo);
-  SessionCombo->Items = TTerminalManager::Instance()->TerminalList;
-  SessionCombo->ItemIndex = TTerminalManager::Instance()->ActiveTerminalIndex;
+  if (SessionCombo != NULL)
+  {
+    SessionCombo->Items = TTerminalManager::Instance()->TerminalList;
+    SessionCombo->ItemIndex = TTerminalManager::Instance()->ActiveTerminalIndex;
+  }
   NonVisualDataModule->CreateOpenedSessionListMenu();
 }
 //---------------------------------------------------------------------------
@@ -1746,4 +1736,3 @@ int __fastcall TCustomScpExplorerForm::MoreMessageDialog(const AnsiString Messag
   }
 }
 //---------------------------------------------------------------------------
-

+ 10 - 0
forms/CustomScpExplorer.h

@@ -19,6 +19,7 @@
 #include <WinInterface.h>
 //---------------------------------------------------------------------------
 class TProgressForm;
+class TSynchronizeProgressForm;
 //---------------------------------------------------------------------------
 enum TActionAllowed { aaShortCut, aaUpdate, aaExecute };
 enum TActionFlag { afLocal = 1, afRemote = 2, afExplorer = 4 , afCommander = 8 };
@@ -87,6 +88,7 @@ protected:
   TCustomDirView * FDDTargetDirView;
   TProgressForm * FProgressForm;
   AnsiString FCustomCommandName;
+  TSynchronizeProgressForm * FSynchronizeProgressForm;
 
   virtual bool __fastcall CopyParamDialog(TTransferDirection Direction,
     TTransferType Type, bool DragDrop, TStrings * FileList,
@@ -95,6 +97,7 @@ protected:
   void __fastcall DeleteFiles(TOperationSide Side, TStrings * FileList);
   virtual void __fastcall DoDirViewExecFile(TObject * Sender, TListItem * Item, bool & AllowExec);
   virtual TControl * __fastcall GetComponent(Byte Component);
+  virtual TCoolBand * __fastcall GetCoolBand(TCoolBar * Coolbar, int ID);
   bool __fastcall GetComponentVisible(Word Component);
   virtual Boolean __fastcall GetHasDirView(TOperationSide Side);
   DYNAMIC void __fastcall KeyDown(Word & Key, Classes::TShiftState Shift);
@@ -115,6 +118,12 @@ protected:
   DYNAMIC void __fastcall DoShow();
   TStrings * __fastcall CreateVisitedDirectories(TOperationSide Side);
   void __fastcall HandleErrorList(TStringList *& ErrorList);
+  void __fastcall TerminalSynchronizeDirectory(const AnsiString LocalDirectory,
+    const AnsiString RemoteDirectory, bool & Continue);
+  bool __fastcall DoFullSynchronizeDirectories(AnsiString & LocalDirectory,
+    AnsiString & RemoteDirectory);
+  void __fastcall BatchStart(void *& Storage);
+  void __fastcall BatchEnd(void * Storage);
 
   #pragma warn -inl
   BEGIN_MESSAGE_MAP
@@ -147,6 +156,7 @@ public:
   void __fastcall OpenInPutty();
   virtual void __fastcall UpdateSessionData(TSessionData * Data = NULL);
   virtual void __fastcall SynchronizeDirectories();
+  virtual void __fastcall FullSynchronizeDirectories();
   virtual void __fastcall ExploreLocalDirectory();
   void __fastcall ExecuteFile(TOperationSide Side, TExecuteFileBy ExecuteFileBy);
   void __fastcall LastTerminalClosed(TObject * Sender);

+ 84 - 0
forms/FileSystemInfo.cpp

@@ -0,0 +1,84 @@
+//---------------------------------------------------------------------
+#include <vcl.h>
+#pragma hdrstop
+
+#include <Common.h>
+#include <Terminal.h>
+#include "FileSystemInfo.h"
+//---------------------------------------------------------------------
+#pragma link "XPGroupBox"
+#pragma resource "*.dfm"
+//---------------------------------------------------------------------
+void __fastcall DoFileSystemInfoDialog(TTerminal * Terminal)
+{
+  TFileSystemInfoDialog * Dialog = new TFileSystemInfoDialog(Application);
+  try
+  {
+    Dialog->Terminal = Terminal;
+    Dialog->ShowModal();
+  }
+  __finally
+  {
+    delete Dialog;
+  }
+} 
+//---------------------------------------------------------------------
+__fastcall TFileSystemInfoDialog::TFileSystemInfoDialog(TComponent* AOwner)
+	: TForm(AOwner)
+{
+}
+//---------------------------------------------------------------------
+AnsiString __fastcall TFileSystemInfoDialog::CapabilityStr(TFSCapability Capability)
+{
+  assert(FTerminal);
+  return BooleanToStr(FTerminal->IsCapable[Capability]);
+}
+//---------------------------------------------------------------------
+AnsiString __fastcall TFileSystemInfoDialog::CapabilityStr(TFSCapability Capability1,
+  TFSCapability Capability2)
+{
+  return FORMAT("%s/%s", (CapabilityStr(Capability1), CapabilityStr(Capability2)));
+}
+//---------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::UpdateControls()
+{
+  assert(Terminal);
+
+  SshVersionEdit->Text = IntToStr(Terminal->SshVersion);
+
+  AnsiString Str = CipherNames[Terminal->CSCipher];
+  if (Terminal->CSCipher != Terminal->SCCipher)
+  {
+    Str += FORMAT("/%s", (CipherNames[Terminal->SCCipher]));
+  }
+  CipherEdit->Text = Str;
+
+  Str = BooleanToStr(Terminal->CSCompression != ctNone);
+  if (Terminal->CSCompression != Terminal->SCCompression)
+  {
+    Str += FORMAT("/%s", (BooleanToStr(Terminal->SCCompression != ctNone)));
+  }
+  CompressionEdit->Text = Str;
+
+  FSProtocolEdit->Text = Terminal->ProtocolName;
+
+  ModeChangingEdit->Text = CapabilityStr(fcModeChanging);
+  OwnerGroupChangingEdit->Text = CapabilityStr(fcOwnerChanging, fcGroupChanging);
+  AnyCommandEdit->Text = CapabilityStr(fcAnyCommand);
+  SymbolicHardLinkEdit->Text = CapabilityStr(fcSymbolicLink, fcHardLink);
+  UserGroupListingEdit->Text = CapabilityStr(fcUserGroupListing);
+  NativeTextModeEdit->Text = CapabilityStr(fcNativeTextMode);
+
+  InfoMemo->Lines = Terminal->AdditionalInfo;
+}
+//---------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::SetTerminal(TTerminal * value)
+{
+  if (Terminal != value)
+  {
+    FTerminal = value;
+    UpdateControls();
+  }
+}
+//---------------------------------------------------------------------
+

+ 269 - 0
forms/FileSystemInfo.dfm

@@ -0,0 +1,269 @@
+object FileSystemInfoDialog: TFileSystemInfoDialog
+  Left = 345
+  Top = 178
+  BorderStyle = bsDialog
+  Caption = 'Server and protocol information'
+  ClientHeight = 372
+  ClientWidth = 367
+  Color = clBtnFace
+  ParentFont = True
+  OldCreateOrder = True
+  Position = poScreenCenter
+  DesignSize = (
+    367
+    372)
+  PixelsPerInch = 96
+  TextHeight = 13
+  object CloseButton: TButton
+    Left = 283
+    Top = 338
+    Width = 75
+    Height = 25
+    Anchors = [akRight, akBottom]
+    Cancel = True
+    Caption = 'Close'
+    Default = True
+    ModalResult = 1
+    TabOrder = 0
+  end
+  object ServerGroup: TXPGroupBox
+    Left = 8
+    Top = 8
+    Width = 351
+    Height = 89
+    Anchors = [akLeft, akTop, akRight]
+    Caption = 'Server information'
+    TabOrder = 1
+    DesignSize = (
+      351
+      89)
+    object Label1: TLabel
+      Left = 10
+      Top = 18
+      Width = 103
+      Height = 13
+      Caption = 'SSH protocol version:'
+    end
+    object Label2: TLabel
+      Left = 10
+      Top = 34
+      Width = 98
+      Height = 13
+      Caption = 'Encryption algorithm:'
+    end
+    object Label3: TLabel
+      Left = 10
+      Top = 50
+      Width = 63
+      Height = 13
+      Caption = 'Compression:'
+    end
+    object Label7: TLabel
+      Left = 10
+      Top = 66
+      Width = 98
+      Height = 13
+      Caption = 'File transfer protocol:'
+    end
+    object SshVersionEdit: TEdit
+      Left = 214
+      Top = 18
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 0
+      Text = 'SshVersionEdit'
+    end
+    object CipherEdit: TEdit
+      Left = 214
+      Top = 34
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 1
+      Text = 'CipherEdit'
+    end
+    object CompressionEdit: TEdit
+      Left = 214
+      Top = 50
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 2
+      Text = 'CompressionEdit'
+    end
+    object FSProtocolEdit: TEdit
+      Left = 214
+      Top = 66
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 3
+      Text = 'FSProtocolEdit'
+    end
+  end
+  object ProtocolGroup: TXPGroupBox
+    Left = 8
+    Top = 104
+    Width = 351
+    Height = 223
+    Anchors = [akLeft, akTop, akRight, akBottom]
+    Caption = 'Protocol capabilities/information'
+    TabOrder = 2
+    DesignSize = (
+      351
+      223)
+    object Label4: TLabel
+      Left = 10
+      Top = 18
+      Width = 118
+      Height = 13
+      Caption = 'Can change permissions:'
+    end
+    object Label5: TLabel
+      Left = 10
+      Top = 34
+      Width = 125
+      Height = 13
+      Caption = 'Can change owner/group:'
+    end
+    object Label6: TLabel
+      Left = 10
+      Top = 50
+      Width = 152
+      Height = 13
+      Caption = 'Can execute arbitrary command:'
+    end
+    object Label8: TLabel
+      Left = 10
+      Top = 66
+      Width = 134
+      Height = 13
+      Caption = 'Can create symlink/hardlink:'
+    end
+    object Label9: TLabel
+      Left = 10
+      Top = 98
+      Width = 162
+      Height = 13
+      Caption = 'Native text (ASCII) mode transfers:'
+    end
+    object Label10: TLabel
+      Left = 10
+      Top = 82
+      Width = 115
+      Height = 13
+      Caption = 'Can lookup user groups:'
+    end
+    object ModeChangingEdit: TEdit
+      Left = 214
+      Top = 18
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 0
+      Text = 'ModeChangingEdit'
+    end
+    object OwnerGroupChangingEdit: TEdit
+      Left = 214
+      Top = 34
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 1
+      Text = 'OwnerGroupChangingEdit'
+    end
+    object AnyCommandEdit: TEdit
+      Left = 214
+      Top = 50
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 2
+      Text = 'AnyCommandEdit'
+    end
+    object SymbolicHardLinkEdit: TEdit
+      Left = 214
+      Top = 66
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 3
+      Text = 'SymbolicHardLinkEdit'
+    end
+    object NativeTextModeEdit: TEdit
+      Left = 214
+      Top = 98
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 4
+      Text = 'NativeTextModeEdit'
+    end
+    object UserGroupListingEdit: TEdit
+      Left = 214
+      Top = 82
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 5
+      Text = 'UserGroupListingEdit'
+    end
+    object InfoMemo: TMemo
+      Left = 8
+      Top = 120
+      Width = 335
+      Height = 93
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight, akBottom]
+      Color = clBtnFace
+      Lines.Strings = (
+        'InfoMemo')
+      ReadOnly = True
+      ScrollBars = ssBoth
+      TabOrder = 6
+      WantReturns = False
+      WordWrap = False
+    end
+  end
+end

+ 61 - 0
forms/FileSystemInfo.h

@@ -0,0 +1,61 @@
+//----------------------------------------------------------------------------
+#ifndef FileSystemInfoH
+#define FileSystemInfoH
+//----------------------------------------------------------------------------
+#include <vcl\System.hpp>
+#include <vcl\Windows.hpp>
+#include <vcl\SysUtils.hpp>
+#include <vcl\Classes.hpp>
+#include <vcl\Graphics.hpp>
+#include <vcl\StdCtrls.hpp>
+#include <vcl\Forms.hpp>
+#include <vcl\Controls.hpp>
+#include <vcl\Buttons.hpp>
+#include <vcl\ExtCtrls.hpp>
+#include <XPGroupBox.hpp>
+//----------------------------------------------------------------------------
+class TTerminal;
+//----------------------------------------------------------------------------
+class TFileSystemInfoDialog : public TForm
+{
+__published:
+  TButton *CloseButton;
+  TXPGroupBox *ServerGroup;
+  TLabel *Label1;
+  TLabel *Label2;
+  TEdit *SshVersionEdit;
+  TEdit *CipherEdit;
+  TLabel *Label3;
+  TEdit *CompressionEdit;
+  TXPGroupBox *ProtocolGroup;
+  TLabel *Label4;
+  TLabel *Label5;
+  TLabel *Label6;
+  TEdit *ModeChangingEdit;
+  TEdit *OwnerGroupChangingEdit;
+  TEdit *AnyCommandEdit;
+  TLabel *Label7;
+  TEdit *FSProtocolEdit;
+  TLabel *Label8;
+  TEdit *SymbolicHardLinkEdit;
+  TLabel *Label9;
+  TEdit *NativeTextModeEdit;
+  TLabel *Label10;
+  TEdit *UserGroupListingEdit;
+  TMemo *InfoMemo;
+public:
+	virtual __fastcall TFileSystemInfoDialog(TComponent* AOwner);
+
+  __property TTerminal * Terminal = { read=FTerminal, write=SetTerminal };
+
+private:
+  TTerminal * FTerminal;
+
+  void __fastcall SetTerminal(TTerminal * value);
+  void __fastcall UpdateControls();
+  AnsiString __fastcall CapabilityStr(TFSCapability Capability);
+  AnsiString __fastcall CapabilityStr(TFSCapability Capability1,
+    TFSCapability Capability2);
+};
+//----------------------------------------------------------------------------
+#endif

+ 179 - 0
forms/FullSynchronize.cpp

@@ -0,0 +1,179 @@
+//---------------------------------------------------------------------------
+#include <vcl.h>
+#pragma hdrstop
+
+#include "FullSynchronize.h"
+#include "VCLCommon.h"
+
+#include <ScpMain.h>
+#include <Common.h>
+#include <Configuration.h>
+#include <TextsWin.h>
+#include <CustomWinConfiguration.h>
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma link "XPGroupBox"
+#pragma link "HistoryComboBox"
+#pragma resource "*.dfm"
+//---------------------------------------------------------------------------
+bool __fastcall DoFullSynchronizeDialog(TSynchronizeMode & Mode, int & Params,
+  AnsiString & LocalDirectory, AnsiString & RemoteDirectory)
+{
+  bool Result;
+  TFullSynchronizeDialog * Dialog = new TFullSynchronizeDialog(Application);
+  try
+  {
+    Dialog->Mode = Mode;
+    Dialog->Params = Params;
+    Dialog->LocalDirectory = LocalDirectory;
+    Dialog->RemoteDirectory = RemoteDirectory;
+    Result = Dialog->Execute();
+    if (Result)
+    {
+      Mode = Dialog->Mode;
+      Params = Dialog->Params;
+      LocalDirectory = Dialog->LocalDirectory;
+      RemoteDirectory = Dialog->RemoteDirectory;
+    }
+  }
+  __finally
+  {
+    delete Dialog;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+__fastcall TFullSynchronizeDialog::TFullSynchronizeDialog(TComponent* Owner)
+  : TForm(Owner)
+{
+  UseSystemSettings(this);
+  FParams = 0;
+}
+//---------------------------------------------------------------------------
+void __fastcall TFullSynchronizeDialog::UpdateControls()
+{
+  EnableControl(SynchronizeDeleteCheck, !SynchronizeBothButton->Checked);
+  EnableControl(OkButton, !LocalDirectoryEdit->Text.IsEmpty() &&
+    !RemoteDirectoryEdit->Text.IsEmpty());
+}
+//---------------------------------------------------------------------------
+void __fastcall TFullSynchronizeDialog::ControlChange(TObject * /*Sender*/)
+{
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
+bool __fastcall TFullSynchronizeDialog::Execute()
+{
+  LocalDirectoryEdit->Items = CustomWinConfiguration->History["LocalDirectory"];
+  RemoteDirectoryEdit->Items = CustomWinConfiguration->History["RemoteDirectory"];
+  bool Result = (ShowModal() == mrOk);
+  if (Result)
+  {
+    LocalDirectoryEdit->SaveToHistory();
+    CustomWinConfiguration->History["LocalDirectory"] = LocalDirectoryEdit->Items;
+    RemoteDirectoryEdit->SaveToHistory();
+    CustomWinConfiguration->History["RemoteDirectory"] = RemoteDirectoryEdit->Items;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TFullSynchronizeDialog::SetRemoteDirectory(const AnsiString value)
+{
+  RemoteDirectoryEdit->Text = value;
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall TFullSynchronizeDialog::GetRemoteDirectory()
+{
+  return RemoteDirectoryEdit->Text;
+}
+//---------------------------------------------------------------------------
+void __fastcall TFullSynchronizeDialog::SetLocalDirectory(const AnsiString value)
+{
+  LocalDirectoryEdit->Text = value;
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall TFullSynchronizeDialog::GetLocalDirectory()
+{
+  return LocalDirectoryEdit->Text;
+}
+//---------------------------------------------------------------------------
+void __fastcall TFullSynchronizeDialog::SetMode(TSynchronizeMode value)
+{
+  switch (value)
+  {
+    case smRemote:
+       SynchronizeRemoteButton->Checked = true;
+       break;
+
+    case smLocal:
+       SynchronizeLocalButton->Checked = true;
+       break;
+
+    case smBoth:
+       SynchronizeBothButton->Checked = true;
+       break;
+
+    default:
+      assert(false);
+  }
+}
+//---------------------------------------------------------------------------
+TSynchronizeMode __fastcall TFullSynchronizeDialog::GetMode()
+{
+  if (SynchronizeRemoteButton->Checked)
+  {
+    return smRemote;
+  }
+  else if (SynchronizeLocalButton->Checked)
+  {
+    return smLocal;
+  }
+  else
+  {
+    assert(SynchronizeBothButton->Checked);
+    return smBoth;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TFullSynchronizeDialog::SetParams(int value)
+{
+  FParams = value & ~(spDelete | spNoConfirmation);
+  SynchronizeDeleteCheck->Checked = (value & spDelete) != 0;
+  SynchronizeNoConfirmationCheck->Checked = (value & spNoConfirmation) != 0;
+}
+//---------------------------------------------------------------------------
+int __fastcall TFullSynchronizeDialog::GetParams()
+{
+  return FParams |
+    (SynchronizeDeleteCheck->Checked ? spDelete : 0) |
+    (SynchronizeNoConfirmationCheck->Checked ? spNoConfirmation : 0);
+}
+//---------------------------------------------------------------------------
+void __fastcall TFullSynchronizeDialog::LocalDirectoryBrowseButtonClick(
+      TObject * /*Sender*/)
+{
+  AnsiString Directory = LocalDirectoryEdit->Text;
+  if (SelectDirectory(Directory, LoadStr(SELECT_LOCAL_DIRECTORY), false))
+  {
+    LocalDirectoryEdit->Text = Directory;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TFullSynchronizeDialog::FormCloseQuery(TObject * /*Sender*/,
+  bool & CanClose)
+{
+  if (ModalResult != mrCancel)
+  {
+    AnsiString Dir = LocalDirectoryEdit->Text;
+    AnsiString Drive = ExtractFileDrive(Dir);
+    if (Drive.IsEmpty() || (Drive.Length() != 2) || (Drive[2] != ':'))
+    {
+      LocalDirectoryEdit->SetFocus();
+      LocalDirectoryEdit->SelectAll();
+      SimpleErrorDialog(LoadStr(ABSOLUTE_PATH_REQUIRED));
+      CanClose = false;
+    }
+  }
+}
+//---------------------------------------------------------------------------
+

+ 163 - 0
forms/FullSynchronize.dfm

@@ -0,0 +1,163 @@
+object FullSynchronizeDialog: TFullSynchronizeDialog
+  Left = 365
+  Top = 185
+  BorderStyle = bsDialog
+  Caption = 'Synchronize'
+  ClientHeight = 243
+  ClientWidth = 396
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  OnCloseQuery = FormCloseQuery
+  DesignSize = (
+    396
+    243)
+  PixelsPerInch = 96
+  TextHeight = 13
+  object DirectoriesGroup: TXPGroupBox
+    Left = 8
+    Top = 6
+    Width = 380
+    Height = 119
+    Anchors = [akLeft, akTop, akRight]
+    Caption = 'Directories'
+    TabOrder = 0
+    DesignSize = (
+      380
+      119)
+    object FileNameLabel: TLabel
+      Left = 11
+      Top = 19
+      Width = 72
+      Height = 13
+      Anchors = [akLeft, akTop, akRight]
+      Caption = 'Lo&cal directory:'
+      FocusControl = LocalDirectoryEdit
+    end
+    object Label1: TLabel
+      Left = 11
+      Top = 68
+      Width = 83
+      Height = 13
+      Anchors = [akLeft, akTop, akRight]
+      Caption = 'Remo&te directory:'
+      FocusControl = RemoteDirectoryEdit
+    end
+    object RemoteDirectoryEdit: THistoryComboBox
+      Left = 11
+      Top = 84
+      Width = 358
+      Height = 21
+      AutoComplete = False
+      Anchors = [akLeft, akTop, akRight]
+      ItemHeight = 13
+      MaxLength = 1000
+      TabOrder = 2
+      Text = 'RemoteDirectoryEdit'
+      OnChange = ControlChange
+    end
+    object LocalDirectoryEdit: THistoryComboBox
+      Left = 11
+      Top = 35
+      Width = 275
+      Height = 21
+      AutoComplete = False
+      Anchors = [akLeft, akTop, akRight]
+      ItemHeight = 13
+      MaxLength = 1000
+      TabOrder = 0
+      Text = 'LocalDirectoryEdit'
+      OnChange = ControlChange
+    end
+    object LocalDirectoryBrowseButton: TButton
+      Left = 293
+      Top = 33
+      Width = 75
+      Height = 25
+      Caption = 'B&rowse...'
+      TabOrder = 1
+      OnClick = LocalDirectoryBrowseButtonClick
+    end
+  end
+  object OkButton: TButton
+    Left = 228
+    Top = 210
+    Width = 75
+    Height = 25
+    Anchors = [akRight, akBottom]
+    Caption = 'OK'
+    Default = True
+    ModalResult = 1
+    TabOrder = 2
+  end
+  object CancelButton: TButton
+    Left = 312
+    Top = 210
+    Width = 75
+    Height = 25
+    Anchors = [akRight, akBottom]
+    Cancel = True
+    Caption = 'Cancel'
+    ModalResult = 2
+    TabOrder = 3
+  end
+  object OptionsGroup: TXPGroupBox
+    Left = 8
+    Top = 130
+    Width = 380
+    Height = 71
+    Anchors = [akLeft, akTop, akRight]
+    Caption = 'Synchronize options'
+    TabOrder = 1
+    object SynchronizeBothButton: TRadioButton
+      Left = 11
+      Top = 20
+      Width = 102
+      Height = 17
+      Caption = '&Both'
+      TabOrder = 0
+      OnClick = ControlChange
+    end
+    object SynchronizeRemoteButton: TRadioButton
+      Left = 123
+      Top = 20
+      Width = 102
+      Height = 17
+      Caption = '&Remote'
+      TabOrder = 1
+      OnClick = ControlChange
+    end
+    object SynchronizeLocalButton: TRadioButton
+      Left = 235
+      Top = 20
+      Width = 110
+      Height = 17
+      Caption = '&Local'
+      TabOrder = 2
+      OnClick = ControlChange
+    end
+    object SynchronizeDeleteCheck: TCheckBox
+      Left = 11
+      Top = 44
+      Width = 97
+      Height = 17
+      Caption = '&Delete files'
+      TabOrder = 3
+      OnClick = ControlChange
+    end
+    object SynchronizeNoConfirmationCheck: TCheckBox
+      Left = 123
+      Top = 44
+      Width = 158
+      Height = 17
+      Caption = '&No confirmations'
+      TabOrder = 4
+      OnClick = ControlChange
+    end
+  end
+end

+ 60 - 0
forms/FullSynchronize.h

@@ -0,0 +1,60 @@
+//---------------------------------------------------------------------------
+#ifndef FullSynchronizeH
+#define FullSynchronizeH
+//---------------------------------------------------------------------------
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <XPGroupBox.hpp>
+#include <HistoryComboBox.hpp>
+
+#include <WinInterface.h>
+//---------------------------------------------------------------------------
+class TFullSynchronizeDialog : public TForm
+{
+__published:
+  TXPGroupBox *DirectoriesGroup;
+  TButton *OkButton;
+  TButton *CancelButton;
+  TLabel *FileNameLabel;
+  TLabel *Label1;
+  THistoryComboBox *RemoteDirectoryEdit;
+  THistoryComboBox *LocalDirectoryEdit;
+  TXPGroupBox *OptionsGroup;
+  TRadioButton *SynchronizeBothButton;
+  TRadioButton *SynchronizeRemoteButton;
+  TRadioButton *SynchronizeLocalButton;
+  TCheckBox *SynchronizeDeleteCheck;
+  TCheckBox *SynchronizeNoConfirmationCheck;
+  TButton *LocalDirectoryBrowseButton;
+  void __fastcall ControlChange(TObject *Sender);
+  void __fastcall LocalDirectoryBrowseButtonClick(TObject *Sender);
+  void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
+  
+private:
+  int FParams;
+  void __fastcall SetRemoteDirectory(const AnsiString value);
+  AnsiString __fastcall GetRemoteDirectory();
+  void __fastcall SetLocalDirectory(const AnsiString value);
+  AnsiString __fastcall GetLocalDirectory();
+  void __fastcall SetMode(TSynchronizeMode value);
+  TSynchronizeMode __fastcall GetMode();
+  void __fastcall SetParams(int value);
+  int __fastcall GetParams();
+
+public:
+  __fastcall TFullSynchronizeDialog(TComponent* Owner);
+
+  bool __fastcall Execute();
+
+  __property AnsiString RemoteDirectory = { read = GetRemoteDirectory, write = SetRemoteDirectory };
+  __property AnsiString LocalDirectory = { read = GetLocalDirectory, write = SetLocalDirectory };
+  __property int Params = { read = GetParams, write = SetParams };
+  __property TSynchronizeMode Mode = { read = GetMode, write = SetMode };
+
+protected:
+  void __fastcall UpdateControls();
+};
+//---------------------------------------------------------------------------
+#endif

+ 6 - 3
forms/GeneralSettings.cpp

@@ -7,7 +7,7 @@
 #include <Common.h>
 #include <Configuration.h>
 #include <ScpMain.h>
-#include "WinConfiguration.h"
+#include "CustomWinConfiguration.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma link "XPGroupBox"
@@ -30,12 +30,15 @@ void __fastcall TGeneralSettingsFrame::ExplorerClick(TObject * /*Sender*/)
 //---------------------------------------------------------------------------
 void __fastcall TGeneralSettingsFrame::SaveConfiguration()
 {
-  WinConfiguration->Interface = CommanderInterfaceButton->Checked ? ifCommander : ifExplorer;
+  assert(CustomWinConfiguration);
+  CustomWinConfiguration->Interface = CommanderInterfaceButton->Checked ?
+    ifCommander : ifExplorer;
 }
 //---------------------------------------------------------------------------
 void __fastcall TGeneralSettingsFrame::LoadConfiguration()
 {
-  switch (WinConfiguration->Interface) {
+  assert(CustomWinConfiguration);
+  switch (CustomWinConfiguration->Interface) {
     case ifCommander: CommanderInterfaceButton->Checked = True; break;
     case ifExplorer: ExplorerInterfaceButton->Checked = True; break;
     default: assert(false); break;

+ 40 - 16
forms/LogSettings.cpp

@@ -8,7 +8,7 @@
 #include <ScpMain.h>
 
 #include <VCLCommon.h>
-#include "WinConfiguration.h"
+#include "CustomWinConfiguration.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma link "ComboEdit"
@@ -20,6 +20,7 @@ TLoggingFrame *LoggingFrame;
 __fastcall TLoggingFrame::TLoggingFrame(TComponent* Owner)
         : TFrame(Owner)
 {
+  FEnableLogWindow = true;
 }
 //---------------------------------------------------------------------------
 void __fastcall TLoggingFrame::LoadConfiguration()
@@ -32,7 +33,7 @@ void __fastcall TLoggingFrame::LoadConfiguration()
     LogFileAppendButton->Checked = True;
   else
     LogFileOverwriteButton->Checked = True;
-  LogShowWindowCheck->Checked = (WinConfiguration->LogView == lvWindow);
+  LogShowWindowCheck->Checked = (CustomWinConfiguration->LogView == lvWindow);
   if (Configuration->LogWindowComplete)
     LogWindowCompleteButton->Checked = True;
   else
@@ -46,17 +47,27 @@ void __fastcall TLoggingFrame::LoadConfiguration()
 void __fastcall TLoggingFrame::SaveConfiguration()
 {
   Configuration->BeginUpdate();
-  try {
+  try
+  {
     Configuration->Logging = LoggingCheck->Checked;
     Configuration->LogToFile = LogToFileCheck->Checked;
     if (LogToFileCheck->Checked)
+    {
       Configuration->LogFileName = LogFileNameEdit->Text;
+    }
     Configuration->LogFileAppend = LogFileAppendButton->Checked;
-    WinConfiguration->LogView = LogShowWindowCheck->Checked ? lvWindow : lvNone;
-    Configuration->LogWindowComplete = LogWindowCompleteButton->Checked;
-    if (!LogWindowCompleteButton->Checked)
-      Configuration->LogWindowLines = LogWindowLinesEdit->AsInteger;
-  } __finally {
+    if (EnableLogWindow)
+    {
+      CustomWinConfiguration->LogView = LogShowWindowCheck->Checked ? lvWindow : lvNone;
+      Configuration->LogWindowComplete = LogWindowCompleteButton->Checked;
+      if (!LogWindowCompleteButton->Checked)
+      {
+        Configuration->LogWindowLines = LogWindowLinesEdit->AsInteger;
+      }
+    }
+  }
+  __finally
+  {
     Configuration->EndUpdate();
   }
 }
@@ -64,8 +75,10 @@ void __fastcall TLoggingFrame::SaveConfiguration()
 void __fastcall TLoggingFrame::UpdateControls()
 {
   if (!LoggingCheck->Checked)
-      EnableControl(LoggingGroup, False);
-    else
+  {
+    EnableControl(LoggingGroup, False);
+  }
+  else
   {
     LoggingGroup->Enabled = True;
 
@@ -73,19 +86,21 @@ void __fastcall TLoggingFrame::UpdateControls()
     EnableControl(LogFileNameEdit, LogToFileCheck->Checked);
     EnableControl(LogFilePanel, LogToFileCheck->Checked);
 
-    EnableControl(LogShowWindowCheck, True);
-    EnableControl(LogWindowCompleteButton, LogShowWindowCheck->Checked);
-    EnableControl(LogWindowLinesButton, LogShowWindowCheck->Checked);
-    EnableControl(LogWindowLinesText, LogShowWindowCheck->Checked);
-    EnableControl(LogWindowLinesEdit,
-      LogShowWindowCheck->Checked && LogWindowLinesButton->Checked);
+    EnableControl(LogShowWindowCheck, True && EnableLogWindow);
+    EnableControl(LogWindowCompleteButton, LogShowWindowCheck->Checked && EnableLogWindow);
+    EnableControl(LogWindowLinesButton, LogShowWindowCheck->Checked && EnableLogWindow);
+    EnableControl(LogWindowLinesText, LogShowWindowCheck->Checked && EnableLogWindow);
+    EnableControl(LogWindowLinesEdit, LogShowWindowCheck->Checked &&
+      LogWindowLinesButton->Checked && EnableLogWindow);
   }
 }
 //---------------------------------------------------------------------------
 void __fastcall TLoggingFrame::LogToFileCheckChange(TObject *Sender)
 {
   if (LogToFileCheck->Checked && LogFileNameEdit->Text.IsEmpty())
+  {
     LogFileNameEdit->Text = DefaultLogFileName;
+  }
   DataChange(Sender);
 }
 //---------------------------------------------------------------------------
@@ -101,4 +116,13 @@ AnsiString __fastcall TLoggingFrame::GetDefaultLogFileName()
   FOnGetDefaultLogFileName(this, Result);
   return Result;
 }
+//---------------------------------------------------------------------------
+void __fastcall TLoggingFrame::SetEnableLogWindow(bool value)
+{
+  if (EnableLogWindow != value)
+  {
+    FEnableLogWindow = value;
+    UpdateControls();
+  }
+}
 

+ 4 - 0
forms/LogSettings.h

@@ -33,13 +33,17 @@ __published:
   void __fastcall DataChange(TObject *Sender);
 private:
   TGetDefaultLogFileName FOnGetDefaultLogFileName;
+  bool FEnableLogWindow;
+
   AnsiString __fastcall GetDefaultLogFileName();
+  void __fastcall SetEnableLogWindow(bool value);
 public:
   void __fastcall LoadConfiguration();
   void __fastcall SaveConfiguration();
   __fastcall TLoggingFrame(TComponent* Owner);
   __property AnsiString DefaultLogFileName = { read = GetDefaultLogFileName };
   __property TGetDefaultLogFileName OnGetDefaultLogFileName = { read = FOnGetDefaultLogFileName, write = FOnGetDefaultLogFileName };
+  __property bool EnableLogWindow = { read = FEnableLogWindow, write = SetEnableLogWindow };
 protected:
   void __fastcall UpdateControls();
 };

+ 91 - 43
forms/Login.cpp

@@ -9,9 +9,9 @@
 
 #include "Login.h"
 #include "WinInterface.h"
-#include "UserInterface.h"
+#include "GUITools.h"
 #include "Tools.h"
-#include "WinConfiguration.h"
+#include "CustomWinConfiguration.h"
 //---------------------------------------------------------------------
 #pragma link "ComboEdit"
 #pragma link "LogSettings"
@@ -22,7 +22,7 @@
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------------
 bool __fastcall DoLoginDialog(TStoredSessionList *SessionList,
-  TSessionData * Data, bool Initial)
+  TSessionData * Data, int Options)
 {
   assert(Data);
   TLoginDialog *LoginDialog = new TLoginDialog(Application);
@@ -31,7 +31,7 @@ bool __fastcall DoLoginDialog(TStoredSessionList *SessionList,
   {
     LoginDialog->StoredSessions = SessionList;
     LoginDialog->SessionData = Data;
-    LoginDialog->Initial = Initial;
+    LoginDialog->Options = Options;
     Result = LoginDialog->Execute();
     if (Result)
     {
@@ -54,7 +54,7 @@ __fastcall TLoginDialog::TLoginDialog(TComponent* AOwner)
   FInitialized = false;
   FSavedTab = NULL;
   FSavedSession = -1;
-  FInitial = true;
+  FOptions = loStartup;
   FLocaleChanging = false;
 }
 //---------------------------------------------------------------------
@@ -63,6 +63,8 @@ __fastcall TLoginDialog::~TLoginDialog()
   LoggingFrame->OnGetDefaultLogFileName = NULL;
   // SelectItem event is called after destructor! Why?
   SessionListView->Selected = NULL;
+  delete FSystemSettings;
+  FSystemSettings = NULL;
   delete FSessionData;
   delete FLanguagesPopupMenu;
 }
@@ -95,19 +97,19 @@ void __fastcall TLoginDialog::Init()
   PrepareNavigationTree(SimpleNavigationTree);
   PrepareNavigationTree(AdvancedNavigationTree);
 
-  if (!WinConfiguration->ExpertMode)
+  if ((Options & loLocalDirectory) == 0)
   {
-    Label9->Visible = false;
+    LocalDirectoryLabel->Visible = false;
     LocalDirectoryEdit->Visible = false;
-    Label16->Visible = false;
+    LocalDirectoryDescLabel->Visible = false;
     int PrevHeight = DirectoriesGroup->Height;
     DirectoriesGroup->Height = RemoteDirectoryEdit->Top + RemoteDirectoryEdit->Height + 12;
-    EOLTypeGroup->Top = EOLTypeGroup->Top - PrevHeight + RemoteDirectoryEdit->Height;
+    EOLTypeGroup->Top = EOLTypeGroup->Top - PrevHeight + DirectoriesGroup->Height;
   }
 
   ShowTabs(false);
 
-  if (StoredSessions->Count && StoredSessions &&
+  if (StoredSessions && StoredSessions->Count && 
       (FSessionData->Name == StoredSessions->DefaultSettings->Name))
   {
     ChangePage(SessionListSheet);
@@ -150,7 +152,8 @@ void __fastcall TLoginDialog::LoadSessions()
   {
     SessionListView->Items->EndUpdate();
   }
-  SelectedSession = NULL;
+  SelectedSession = StoredSessions->Count > 0 ?
+    dynamic_cast<TSessionData*>(StoredSessions->AtObject(0)) : NULL;
   UpdateControls();
 }
 //---------------------------------------------------------------------------
@@ -165,6 +168,7 @@ void __fastcall TLoginDialog::Default()
     FSessionData->Default();
   }
   LoadSession(FSessionData);
+  FCurrentSessionName = "";
 }
 //---------------------------------------------------------------------
 void __fastcall TLoginDialog::LoadSession(TSessionData * aSessionData)
@@ -191,6 +195,8 @@ void __fastcall TLoginDialog::LoadSession(TSessionData * aSessionData)
     RemoteDirectoryEdit->Text = aSessionData->RemoteDirectory;
     UpdateDirectoriesCheck->Checked = aSessionData->UpdateDirectories;
     CacheDirectoriesCheck->Checked = aSessionData->CacheDirectories;
+    CacheDirectoryChangesCheck->Checked = aSessionData->CacheDirectoryChanges;
+    PreserveDirectoryChangesCheck->Checked = aSessionData->PreserveDirectoryChanges;
     ResolveSymlinksCheck->Checked = aSessionData->ResolveSymlinks;
 
     if (aSessionData->EOLType == eolLF)
@@ -227,11 +233,21 @@ void __fastcall TLoginDialog::LoadSession(TSessionData * aSessionData)
     }
 
     // Connection tab
-    PingIntervalCheck->Checked = (aSessionData->PingInterval > 0);
-    if (aSessionData->PingEnabled)
-      PingIntervalSecEdit->AsInteger = aSessionData->PingInterval;
-    else
-      PingIntervalSecEdit->AsInteger = 60;
+    switch (aSessionData->PingType)
+    {
+      case ptNullPacket:
+        PingNullPacketButton->Checked = true;
+        break;
+
+      case ptDummyCommand:
+        PingDummyCommandButton->Checked = true;
+        break;
+
+      default:
+        PingOffButton->Checked = true;
+        break;
+    }
+    PingIntervalSecEdit->AsInteger = aSessionData->PingInterval;
     TimeoutEdit->AsInteger = aSessionData->Timeout;
 
     // Shell tab
@@ -291,11 +307,13 @@ void __fastcall TLoginDialog::LoadSession(TSessionData * aSessionData)
     NoUpdate--;
     UpdateControls();
   }
+
+  FCurrentSessionName = aSessionData->Name;
 }
 //---------------------------------------------------------------------
 void __fastcall TLoginDialog::SaveSession(TSessionData * aSessionData)
 {
-  aSessionData->Name = "";
+  aSessionData->Name = FCurrentSessionName;
   // Basic tab
   aSessionData->UserName = UserNameEdit->Text;
   aSessionData->PortNumber = PortNumberEdit->AsInteger;
@@ -331,9 +349,19 @@ void __fastcall TLoginDialog::SaveSession(TSessionData * aSessionData)
   aSessionData->AgentFwd = AgentFwdCheck->Checked;
 
   // Connection tab
-  aSessionData->PingEnabled = PingIntervalCheck->Checked;
-  if (PingIntervalCheck->Checked)
-    aSessionData->PingInterval = PingIntervalSecEdit->AsInteger;
+  if (PingNullPacketButton->Checked)
+  {
+    aSessionData->PingType = ptNullPacket;
+  }
+  else if (PingDummyCommandButton->Checked)
+  {
+    aSessionData->PingType = ptDummyCommand;
+  }
+  else
+  {
+    aSessionData->PingType = ptOff;
+  }
+  aSessionData->PingInterval = PingIntervalSecEdit->AsInteger;
   aSessionData->Timeout = TimeoutEdit->AsInteger;
 
   // Environment tab
@@ -341,6 +369,8 @@ void __fastcall TLoginDialog::SaveSession(TSessionData * aSessionData)
   aSessionData->RemoteDirectory = RemoteDirectoryEdit->Text;
   aSessionData->UpdateDirectories = UpdateDirectoriesCheck->Checked;
   aSessionData->CacheDirectories = CacheDirectoriesCheck->Checked;
+  aSessionData->CacheDirectoryChanges = CacheDirectoryChangesCheck->Checked;
+  aSessionData->PreserveDirectoryChanges = PreserveDirectoryChangesCheck->Checked;
   aSessionData->ResolveSymlinks = ResolveSymlinksCheck->Checked;
 
   // Shell tab
@@ -419,7 +449,7 @@ void __fastcall TLoginDialog::UpdateControls()
       if (!PasswordEdit->Text.IsEmpty()) PrivateKeyEdit->Clear();
       EnableControl(PrivateKeyEdit, PasswordEdit->Text.IsEmpty());
 
-      EnableControl(PingIntervalSecEdit, PingIntervalCheck->Checked);
+      EnableControl(PingIntervalSecEdit, !PingOffButton->Checked);
 
       EnableControl(SessionListView, SessionListView->Items->Count);
       AdjustListColumnsWidth(SessionListView);
@@ -450,6 +480,14 @@ void __fastcall TLoginDialog::UpdateControls()
       EnableControl(ProxyPasswordEdit, !ProxyNoneButton->Checked);
       EnableControl(ProxySettingsGroup, !ProxyNoneButton->Checked);
       EnableControl(ProxyTelnetCommandEdit, ProxyTelnetButton->Checked);
+
+      EnableControl(PreserveDirectoryChangesCheck, CacheDirectoryChangesCheck->Checked);
+
+      AboutButton->Visible = (Options & loAbout);
+      LanguagesButton->Visible = (Options & loLanguage);
+      ShellIconsButton->Visible = (Options & loTools);
+      ToolsMenuButton->Visible = (Options & loTools);
+      LoggingFrame->EnableLogWindow = (Options & loLogWindow);
     }
     __finally
     {
@@ -469,10 +507,8 @@ void __fastcall TLoginDialog::PrepareNavigationTree(TTreeView * Tree)
   int i = 0;
   while (i < Tree->Items->Count)
   {
-    if ((!WinConfiguration->ExpertMode &&
-         Tree->Items->Item[i]->SelectedIndex & 128) ||
-        (!Initial &&
-         Tree->Items->Item[i]->SelectedIndex & 256))
+    if ((Tree->Items->Item[i]->StateIndex > 0) &&
+        ((Options & Tree->Items->Item[i]->StateIndex) == 0))
     {
       Tree->Items->Delete(Tree->Items->Item[i]);
     }
@@ -480,7 +516,7 @@ void __fastcall TLoginDialog::PrepareNavigationTree(TTreeView * Tree)
     {
       for (int pi = 0; pi < PageControl->PageCount; pi++)
       {
-        if (PageControl->Pages[pi]->Tag == (Tree->Items->Item[i]->SelectedIndex & 127))
+        if (PageControl->Pages[pi]->Tag == Tree->Items->Item[i]->SelectedIndex)
         {
           Tree->Items->Item[i]->Text = PageControl->Pages[pi]->Hint;
           break;
@@ -489,7 +525,6 @@ void __fastcall TLoginDialog::PrepareNavigationTree(TTreeView * Tree)
       i++;
     }
   }
-  ToolsMenuButton->Visible = WinConfiguration->ExpertMode;
 }
 //---------------------------------------------------------------------------
 void __fastcall TLoginDialog::FormShow(TObject * /*Sender*/)
@@ -498,7 +533,15 @@ void __fastcall TLoginDialog::FormShow(TObject * /*Sender*/)
   {
     FInitialized = true;
     Init();
-    Default();
+    TSessionData * Data = GetSessionData();
+    if (Data == FSessionData)
+    {
+      LoadSession(Data);
+    }
+    else
+    {
+      Default();
+    }
   }
   if (FLocaleChanging)
   {
@@ -582,6 +625,7 @@ void __fastcall TLoginDialog::SetSelectedSession(TSessionData * value)
       TListItem *Item = SessionListView->Items->Item[Index];
       Item->Focused = true;
       Item->Selected = true;
+      Item->MakeVisible(false);
     }
   }
   else
@@ -642,7 +686,7 @@ void __fastcall TLoginDialog::SaveSessionActionExecute(TObject * /*Sender*/)
     SelectedSession = NewSession;
     SessionData = NewSession;
 
-    PageControl->ActivePage = SessionListSheet;
+    ChangePage(SessionListSheet);
   }
 }
 //---------------------------------------------------------------------------
@@ -650,7 +694,7 @@ void __fastcall TLoginDialog::DeleteSessionActionExecute(TObject * /*Sender*/)
 {
   if (SelectedSession)
   {
-    Integer PrevSelectedIndex = SessionListView->Selected->Index;
+    int PrevSelectedIndex = SessionListView->Selected->Index;
     SelectedSession->Remove();
     StoredSessions->Remove(SelectedSession);
     SessionListView->Selected->Delete();
@@ -731,24 +775,26 @@ bool __fastcall TLoginDialog::Execute()
 //---------------------------------------------------------------------------
 void __fastcall TLoginDialog::SaveConfiguration()
 {
-  WinConfiguration->BeginUpdate();
+  assert(CustomWinConfiguration);
+  CustomWinConfiguration->BeginUpdate();
   try
   {
     LoggingFrame->SaveConfiguration();
     GeneralSettingsFrame->SaveConfiguration();
-    WinConfiguration->ShowAdvancedLoginOptions = ShowAdvancedLoginOptionsCheck->Checked;
+    CustomWinConfiguration->ShowAdvancedLoginOptions = ShowAdvancedLoginOptionsCheck->Checked;
   }
   __finally
   {
-    WinConfiguration->EndUpdate();
+    CustomWinConfiguration->EndUpdate();
   }
 }
 //---------------------------------------------------------------------------
 void __fastcall TLoginDialog::LoadConfiguration()
 {
+  assert(CustomWinConfiguration);
   LoggingFrame->LoadConfiguration();
   GeneralSettingsFrame->LoadConfiguration();
-  ShowAdvancedLoginOptionsCheck->Checked = WinConfiguration->ShowAdvancedLoginOptions;
+  ShowAdvancedLoginOptionsCheck->Checked = CustomWinConfiguration->ShowAdvancedLoginOptions;
   UpdateControls();
 }
 //---------------------------------------------------------------------------
@@ -782,7 +828,7 @@ void __fastcall TLoginDialog::NavigationTreeChange(TObject * /*Sender*/,
   {
     for (Integer Index = 0; Index < PageControl->PageCount; Index++)
     {
-      if (PageControl->Pages[Index]->Tag == (Node->SelectedIndex & 127))
+      if (PageControl->Pages[Index]->Tag == Node->SelectedIndex)
       {
         PageControl->ActivePage = PageControl->Pages[Index];
         return;
@@ -805,7 +851,7 @@ void __fastcall TLoginDialog::PageControlChange(TObject *Sender)
   {
     for (int Index = 0; Index < NavigationTree->Items->Count; Index++)
     {
-      if ((NavigationTree->Items->Item[Index]->SelectedIndex & 127) ==
+      if (NavigationTree->Items->Item[Index]->SelectedIndex ==
             PageControl->ActivePage->Tag)
       {
         NavigationTree->Items->Item[Index]->Selected = true;
@@ -874,7 +920,9 @@ void __fastcall TLoginDialog::Dispatch(void *Message)
       FSavedTab = PageControl->ActivePage;
       FSavedSession = SessionListView->ItemIndex;
 
+      assert(FSystemSettings);
       RevokeSystemSettings(this, FSystemSettings);
+      FSystemSettings = NULL;
       ShowTabs(true);
 
       Hide();
@@ -1009,12 +1057,12 @@ void __fastcall TLoginDialog::CheckForUpdatesActionExecute(TObject * /*Sender*/)
   CheckForUpdates();
 }
 //---------------------------------------------------------------------------
-void __fastcall TLoginDialog::SetInitial(bool value)
+void __fastcall TLoginDialog::SetOptions(int value)
 {
-  if (Initial != value)
+  if (Options != value)
   {
-    FInitial = value;
-    LanguagesButton->Visible = Initial;
+    FOptions = value;
+    UpdateControls();
   }
 }
 //---------------------------------------------------------------------------
@@ -1024,7 +1072,7 @@ void __fastcall TLoginDialog::LanguagesButtonClick(TObject * /*Sender*/)
   delete FLanguagesPopupMenu;
   FLanguagesPopupMenu = new TPopupMenu(this);
 
-  TStrings * Locales = WinConfiguration->Locales;
+  TStrings * Locales = GUIConfiguration->Locales;
   for (int Index = 0; Index < Locales->Count; Index++)
   {
     TMenuItem * Item = new TMenuItem(FLanguagesPopupMenu);
@@ -1033,7 +1081,7 @@ void __fastcall TLoginDialog::LanguagesButtonClick(TObject * /*Sender*/)
     Item->Tag = reinterpret_cast<int>(Locales->Objects[Index]);
     Item->OnClick = LocaleClick;
     Item->Checked = (reinterpret_cast<LCID>(Locales->Objects[Index]) ==
-      WinConfiguration->Locale);
+      GUIConfiguration->Locale);
   }
 
   FLanguagesPopupMenu->Popup(PopupPoint.x, PopupPoint.y);
@@ -1042,7 +1090,7 @@ void __fastcall TLoginDialog::LanguagesButtonClick(TObject * /*Sender*/)
 void __fastcall TLoginDialog::LocaleClick(TObject * Sender)
 {
   assert(Sender);
-  WinConfiguration->Locale =
+  GUIConfiguration->Locale =
     static_cast<LCID>(dynamic_cast<TMenuItem*>(Sender)->Tag);
   LanguagesButton->SetFocus();
 }

+ 174 - 125
forms/Login.dfm

@@ -1,10 +1,10 @@
 object LoginDialog: TLoginDialog
-  Left = 353
-  Top = 185
+  Left = 351
+  Top = 167
   BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
   BorderStyle = bsDialog
   Caption = 'Login'
-  ClientHeight = 358
+  ClientHeight = 364
   ClientWidth = 522
   Color = clBtnFace
   ParentFont = True
@@ -14,12 +14,12 @@ object LoginDialog: TLoginDialog
   OnShow = FormShow
   DesignSize = (
     522
-    358)
+    364)
   PixelsPerInch = 96
   TextHeight = 13
   object SaveButton: TButton
     Left = 260
-    Top = 327
+    Top = 333
     Width = 75
     Height = 25
     Action = SaveSessionAction
@@ -28,7 +28,7 @@ object LoginDialog: TLoginDialog
   end
   object LoginButton: TButton
     Left = 348
-    Top = 327
+    Top = 333
     Width = 75
     Height = 25
     Action = LoginAction
@@ -39,7 +39,7 @@ object LoginDialog: TLoginDialog
   end
   object CloseButton: TButton
     Left = 436
-    Top = 327
+    Top = 333
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
@@ -50,7 +50,7 @@ object LoginDialog: TLoginDialog
   end
   object AboutButton: TButton
     Left = 11
-    Top = 327
+    Top = 333
     Width = 82
     Height = 25
     Action = AboutAction
@@ -60,7 +60,7 @@ object LoginDialog: TLoginDialog
   end
   object LanguagesButton: TButton
     Left = 105
-    Top = 327
+    Top = 333
     Width = 75
     Height = 25
     Anchors = [akLeft, akBottom]
@@ -72,7 +72,7 @@ object LoginDialog: TLoginDialog
     Left = 0
     Top = 0
     Width = 522
-    Height = 318
+    Height = 324
     Align = alTop
     Anchors = [akLeft, akTop, akRight, akBottom]
     BevelOuter = bvNone
@@ -82,12 +82,12 @@ object LoginDialog: TLoginDialog
       Left = 161
       Top = 0
       Width = 361
-      Height = 318
-      ActivePage = BugsSheet
+      Height = 324
+      ActivePage = EnvironmentSheet
       Align = alClient
       MultiLine = True
       Style = tsButtons
-      TabIndex = 9
+      TabIndex = 3
       TabOrder = 1
       OnChange = PageControlChange
       object SessionListSheet: TTabSheet
@@ -96,7 +96,7 @@ object LoginDialog: TLoginDialog
         Caption = 'StSe'
         DesignSize = (
           353
-          263)
+          269)
         object LoadButton: TButton
           Left = 258
           Top = 35
@@ -119,7 +119,7 @@ object LoginDialog: TLoginDialog
           Left = 2
           Top = 3
           Width = 247
-          Height = 258
+          Height = 264
           Anchors = [akLeft, akTop, akRight, akBottom]
           Columns = <
             item
@@ -158,7 +158,7 @@ object LoginDialog: TLoginDialog
         end
         object ToolsMenuButton: TButton
           Left = 258
-          Top = 236
+          Top = 242
           Width = 88
           Height = 25
           Anchors = [akRight, akBottom]
@@ -184,10 +184,10 @@ object LoginDialog: TLoginDialog
         ImageIndex = 1
         DesignSize = (
           353
-          263)
+          269)
         object BasicGroup: TXPGroupBox
           Left = 0
-          Top = 8
+          Top = 6
           Width = 345
           Height = 169
           Anchors = [akLeft, akTop, akRight]
@@ -298,7 +298,7 @@ object LoginDialog: TLoginDialog
         end
         object TransferProtocolGroup: TXPGroupBox
           Left = 0
-          Top = 184
+          Top = 182
           Width = 345
           Height = 48
           Anchors = [akLeft, akTop, akRight]
@@ -342,10 +342,10 @@ object LoginDialog: TLoginDialog
         ImageIndex = 2
         DesignSize = (
           353
-          263)
+          269)
         object ProtocolGroup: TXPGroupBox
           Left = 0
-          Top = 8
+          Top = 6
           Width = 345
           Height = 87
           Anchors = [akLeft, akTop, akRight]
@@ -413,7 +413,7 @@ object LoginDialog: TLoginDialog
         end
         object EncryptionGroup: TXPGroupBox
           Left = 0
-          Top = 102
+          Top = 100
           Width = 345
           Height = 149
           Anchors = [akLeft, akTop, akRight]
@@ -479,62 +479,62 @@ object LoginDialog: TLoginDialog
         ImageIndex = 6
         DesignSize = (
           353
-          263)
+          269)
         object DirectoriesGroup: TXPGroupBox
           Left = 0
-          Top = 8
+          Top = 6
           Width = 345
-          Height = 196
+          Height = 209
           Anchors = [akLeft, akTop, akRight]
           Caption = 'Directories'
           TabOrder = 0
           DesignSize = (
             345
-            196)
-          object Label9: TLabel
+            209)
+          object LocalDirectoryLabel: TLabel
             Left = 11
-            Top = 128
-            Width = 121
+            Top = 144
+            Width = 69
             Height = 13
-            Caption = '&Local directory (left panel)'
+            Caption = '&Local directory'
             FocusControl = LocalDirectoryEdit
           end
-          object Label10: TLabel
+          object RemoteDirectoryLabel: TLabel
             Left = 11
-            Top = 84
-            Width = 138
+            Top = 101
+            Width = 80
             Height = 13
-            Caption = '&Remote directory (right panel)'
+            Caption = '&Remote directory'
             FocusControl = RemoteDirectoryEdit
           end
-          object Label16: TLabel
+          object LocalDirectoryDescLabel: TLabel
             Left = 11
-            Top = 172
+            Top = 186
             Width = 251
             Height = 13
             Caption = 'Local directory is not used with explorer-like interface.'
           end
           object LocalDirectoryEdit: TDirectoryEdit
             Left = 11
-            Top = 145
+            Top = 161
             Width = 323
             Height = 21
             AcceptFiles = True
             DialogText = 'Select startup local directory.'
             ClickKey = 16397
             Anchors = [akLeft, akTop, akRight]
-            TabOrder = 4
+            TabOrder = 6
             Text = 'LocalDirectoryEdit'
             OnChange = DataChange
           end
           object RemoteDirectoryEdit: TEdit
             Left = 11
-            Top = 101
+            Top = 118
             Width = 323
             Height = 21
             Anchors = [akLeft, akTop, akRight]
             MaxLength = 1000
-            TabOrder = 3
+            TabOrder = 5
             Text = 'RemoteDirectoryEdit'
             OnChange = DataChange
           end
@@ -549,7 +549,7 @@ object LoginDialog: TLoginDialog
           end
           object CacheDirectoriesCheck: TCheckBox
             Left = 11
-            Top = 41
+            Top = 40
             Width = 321
             Height = 17
             Anchors = [akLeft, akTop, akRight]
@@ -558,19 +558,38 @@ object LoginDialog: TLoginDialog
           end
           object ResolveSymlinksCheck: TCheckBox
             Left = 11
-            Top = 62
+            Top = 80
             Width = 321
             Height = 17
             Anchors = [akLeft, akTop, akRight]
             Caption = 'Resolve symbolic li&nks'
+            TabOrder = 4
+          end
+          object CacheDirectoryChangesCheck: TCheckBox
+            Left = 11
+            Top = 60
+            Width = 182
+            Height = 17
+            Anchors = [akLeft, akTop, akRight]
+            Caption = 'Cache &directory changes'
             TabOrder = 2
+            OnClick = DataChange
+          end
+          object PreserveDirectoryChangesCheck: TCheckBox
+            Left = 202
+            Top = 60
+            Width = 139
+            Height = 17
+            Anchors = [akLeft, akTop, akRight]
+            Caption = '&Permanent cache'
+            TabOrder = 3
           end
         end
         object EOLTypeGroup: TXPGroupBox
           Left = 0
-          Top = 211
+          Top = 220
           Width = 345
-          Height = 45
+          Height = 43
           Anchors = [akLeft, akTop, akRight]
           Caption = 'EOL (end-of-line) characters (SCP and SFTP version < 4)'
           TabOrder = 1
@@ -601,10 +620,10 @@ object LoginDialog: TLoginDialog
         ImageIndex = 3
         DesignSize = (
           353
-          263)
+          269)
         object OtherShellOptionsGroup: TXPGroupBox
           Left = 0
-          Top = 108
+          Top = 106
           Width = 345
           Height = 113
           Anchors = [akLeft, akTop, akRight]
@@ -631,7 +650,7 @@ object LoginDialog: TLoginDialog
           end
           object LookupUserGroupsCheck: TCheckBox
             Left = 12
-            Top = 18
+            Top = 17
             Width = 140
             Height = 17
             Caption = 'Lookup &user groups'
@@ -700,7 +719,7 @@ object LoginDialog: TLoginDialog
         end
         object ReturnVarGroup: TXPGroupBox
           Left = 0
-          Top = 57
+          Top = 55
           Width = 345
           Height = 44
           Anchors = [akLeft, akTop, akRight]
@@ -744,7 +763,7 @@ object LoginDialog: TLoginDialog
         end
         object ShellGroup: TXPGroupBox
           Left = 0
-          Top = 8
+          Top = 6
           Width = 345
           Height = 44
           Anchors = [akLeft, akTop, akRight]
@@ -837,14 +856,14 @@ object LoginDialog: TLoginDialog
         ImageIndex = 5
         object Label13: TLabel
           Left = 16
-          Top = 226
+          Top = 224
           Width = 104
           Height = 13
           Caption = 'Other general options:'
         end
         object PreferencesButton: TButton
           Left = 184
-          Top = 220
+          Top = 218
           Width = 90
           Height = 25
           Caption = '&Preferences...'
@@ -853,7 +872,7 @@ object LoginDialog: TLoginDialog
         end
         inline GeneralSettingsFrame: TGeneralSettingsFrame
           Left = 0
-          Top = 8
+          Top = 6
           Width = 345
           Height = 202
           TabOrder = 0
@@ -875,25 +894,15 @@ object LoginDialog: TLoginDialog
         ImageIndex = 7
         DesignSize = (
           353
-          263)
+          269)
         object TimeoutGroup: TXPGroupBox
           Left = 0
-          Top = 8
+          Top = 6
           Width = 345
-          Height = 95
+          Height = 46
           Anchors = [akLeft, akTop, akRight]
           Caption = 'Timeouts'
           TabOrder = 0
-          DesignSize = (
-            345
-            95)
-          object Label6: TLabel
-            Left = 32
-            Top = 68
-            Width = 140
-            Height = 13
-            Caption = 'Seconds &between keepalives'
-          end
           object Label11: TLabel
             Left = 12
             Top = 19
@@ -910,41 +919,81 @@ object LoginDialog: TLoginDialog
             Caption = 'seconds'
             FocusControl = TimeoutEdit
           end
-          object PingIntervalCheck: TCheckBox
-            Left = 12
-            Top = 43
-            Width = 324
-            Height = 17
-            Anchors = [akLeft, akTop, akRight]
-            Caption = 'Sending of null packets to &keep session alive'
-            TabOrder = 1
-            OnClick = DataChange
-          end
-          object PingIntervalSecEdit: TUpDownEdit
+          object TimeoutEdit: TUpDownEdit
             Left = 208
-            Top = 63
+            Top = 14
             Width = 73
             Height = 21
             Alignment = taRightJustify
-            MaxValue = 60
-            MinValue = 1
+            Increment = 5
+            MaxValue = 300
+            MinValue = 5
             MaxLength = 2
-            TabOrder = 2
+            TabOrder = 0
             OnChange = DataChange
           end
-          object TimeoutEdit: TUpDownEdit
+        end
+        object PingGroup: TXPGroupBox
+          Left = 0
+          Top = 58
+          Width = 345
+          Height = 111
+          Anchors = [akLeft, akTop, akRight]
+          Caption = 'Keepalives'
+          TabOrder = 1
+          DesignSize = (
+            345
+            111)
+          object Label6: TLabel
+            Left = 12
+            Top = 84
+            Width = 140
+            Height = 13
+            Caption = 'Seconds &between keepalives'
+            FocusControl = PingIntervalSecEdit
+          end
+          object PingIntervalSecEdit: TUpDownEdit
             Left = 208
-            Top = 14
+            Top = 79
             Width = 73
             Height = 21
             Alignment = taRightJustify
-            Increment = 5
-            MaxValue = 300
-            MinValue = 5
+            MaxValue = 60
+            MinValue = 1
             MaxLength = 2
-            TabOrder = 0
+            TabOrder = 3
             OnChange = DataChange
           end
+          object PingOffButton: TRadioButton
+            Left = 12
+            Top = 19
+            Width = 317
+            Height = 17
+            Anchors = [akLeft, akTop, akRight]
+            Caption = '&Off'
+            TabOrder = 0
+            OnClick = DataChange
+          end
+          object PingNullPacketButton: TRadioButton
+            Left = 12
+            Top = 39
+            Width = 317
+            Height = 17
+            Anchors = [akLeft, akTop, akRight]
+            Caption = 'Sending of &null SSH packets'
+            TabOrder = 1
+            OnClick = DataChange
+          end
+          object PingDummyCommandButton: TRadioButton
+            Left = 12
+            Top = 59
+            Width = 317
+            Height = 17
+            Anchors = [akLeft, akTop, akRight]
+            Caption = 'Executing &dummy protocol commands'
+            TabOrder = 2
+            OnClick = DataChange
+          end
         end
       end
       object ProxySheet: TTabSheet
@@ -954,10 +1003,10 @@ object LoginDialog: TLoginDialog
         ImageIndex = 8
         DesignSize = (
           353
-          263)
+          269)
         object ProxyTypeGroup: TXPGroupBox
           Left = 0
-          Top = 8
+          Top = 6
           Width = 345
           Height = 136
           Anchors = [akLeft, akTop, akRight]
@@ -1090,7 +1139,7 @@ object LoginDialog: TLoginDialog
         end
         object ProxySettingsGroup: TXPGroupBox
           Left = 0
-          Top = 149
+          Top = 147
           Width = 345
           Height = 108
           Anchors = [akLeft, akTop, akRight]
@@ -1167,10 +1216,10 @@ object LoginDialog: TLoginDialog
         ImageIndex = 9
         DesignSize = (
           353
-          263)
+          269)
         object BugsGroupBox: TXPGroupBox
           Left = 0
-          Top = 8
+          Top = 6
           Width = 345
           Height = 217
           Anchors = [akLeft, akTop, akRight]
@@ -1250,7 +1299,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 0
           end
           object BugPlainPW1Combo: TComboBox
@@ -1260,7 +1309,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 1
           end
           object BugRSA1Combo: TComboBox
@@ -1270,7 +1319,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 2
           end
           object BugHMAC2Combo: TComboBox
@@ -1280,7 +1329,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 3
           end
           object BugDeriveKey2Combo: TComboBox
@@ -1290,7 +1339,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 4
           end
           object BugRSAPad2Combo: TComboBox
@@ -1300,7 +1349,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 5
           end
           object BugDHGEx2Combo: TComboBox
@@ -1310,7 +1359,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 6
           end
           object BugPKSessID2Combo: TComboBox
@@ -1320,7 +1369,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 7
           end
         end
@@ -1332,10 +1381,10 @@ object LoginDialog: TLoginDialog
         ImageIndex = 10
         DesignSize = (
           353
-          263)
+          269)
         object AuthenticationGroup: TXPGroupBox
           Left = 0
-          Top = 8
+          Top = 6
           Width = 345
           Height = 97
           Anchors = [akLeft, akTop, akRight]
@@ -1370,7 +1419,7 @@ object LoginDialog: TLoginDialog
             Width = 325
             Height = 17
             Anchors = [akLeft, akTop, akRight]
-            Caption = 'Attempt ''keyboard-&interactive'' authentication (SSH2)'
+            Caption = 'Attempt '#39'keyboard-&interactive'#39' authentication (SSH2)'
             TabOrder = 2
             OnClick = DataChange
           end
@@ -1381,18 +1430,18 @@ object LoginDialog: TLoginDialog
       Left = 0
       Top = 0
       Width = 161
-      Height = 318
+      Height = 324
       Align = alLeft
       BevelOuter = bvNone
       TabOrder = 0
       DesignSize = (
         161
-        318)
+        324)
       object SimpleNavigationTree: TTreeView
         Left = 8
         Top = 9
         Width = 145
-        Height = 282
+        Height = 288
         Anchors = [akLeft, akTop, akRight, akBottom]
         HideSelection = False
         HotTrack = True
@@ -1402,19 +1451,19 @@ object LoginDialog: TLoginDialog
         TabOrder = 0
         OnChange = NavigationTreeChange
         Items.Data = {
-          04000000210000000000000002000000FFFFFFFFFFFFFFFF0000000001000000
-          0853657373696F6E58290000000000000001000000FFFFFFFFFFFFFFFF000000
+          0400000021000000000000000200000000000000FFFFFFFF0000000001000000
+          0853657373696F6E5829000000000000000100000000000000FFFFFFFF000000
           00000000001053746F7265642073657373696F6E735825000000000000000400
-          0000FFFFFFFFFFFFFFFF00000000000000000C456E7669726F6E6D656E74581D
-          0000000000000003000000FFFFFFFFFFFFFFFF00000000000000000453534858
-          250000000000000087010000FFFFFFFFFFFFFFFF00000000000000000C507265
+          000000000000FFFFFFFF00000000000000000C456E7669726F6E6D656E74581D
+          000000000000000300000000000000FFFFFFFF00000000000000000453534858
+          25000000000000000700000020000000FFFFFFFF00000000000000000C507265
           666572656E63657358}
       end
       object AdvancedNavigationTree: TTreeView
         Left = 8
         Top = 9
         Width = 145
-        Height = 282
+        Height = 288
         Anchors = [akLeft, akTop, akRight, akBottom]
         HideSelection = False
         HotTrack = True
@@ -1423,24 +1472,24 @@ object LoginDialog: TLoginDialog
         TabOrder = 1
         OnChange = NavigationTreeChange
         Items.Data = {
-          05000000210000000000000002000000FFFFFFFFFFFFFFFF0000000002000000
-          0853657373696F6E58290000000000000001000000FFFFFFFFFFFFFFFF000000
+          0500000021000000000000000200000000000000FFFFFFFF0000000002000000
+          0853657373696F6E5829000000000000000100000000000000FFFFFFFF000000
           00000000001053746F7265642073657373696F6E735821000000000000000600
-          0000FFFFFFFFFFFFFFFF0000000000000000084C6F6767696E67582500000000
-          00000004000000FFFFFFFFFFFFFFFF00000000010000000C456E7669726F6E6D
-          656E74581D0000000000000005000000FFFFFFFFFFFFFFFF0000000000000000
-          0453435058240000000000000008000000FFFFFFFFFFFFFFFF00000000010000
-          000B436F6E6E656374696F6E581F0000000000000009000000FFFFFFFFFFFFFF
-          FF00000000000000000650726F7879581D0000000000000003000000FFFFFFFF
-          FFFFFFFF0000000002000000045353485828000000000000000B000000FFFFFF
-          FFFFFFFFFF00000000000000000F41757468656E7469636174696F6E581E0000
-          00000000000A000000FFFFFFFFFFFFFFFF000000000000000005427567735825
-          0000000000000087010000FFFFFFFFFFFFFFFF00000000000000000C50726566
+          000000000000FFFFFFFF0000000000000000084C6F6767696E67582500000000
+          0000000400000000000000FFFFFFFF00000000010000000C456E7669726F6E6D
+          656E74581D000000000000000500000000000000FFFFFFFF0000000000000000
+          045343505824000000000000000800000000000000FFFFFFFF00000000010000
+          000B436F6E6E656374696F6E581F000000000000000900000000000000FFFFFF
+          FF00000000000000000650726F7879581D000000000000000300000000000000
+          FFFFFFFF0000000002000000045353485828000000000000000B000000000000
+          00FFFFFFFF00000000000000000F41757468656E7469636174696F6E581E0000
+          00000000000A00000000000000FFFFFFFF000000000000000005427567735825
+          000000000000000700000020000000FFFFFFFF00000000000000000C50726566
           6572656E63657358}
       end
       object ShowAdvancedLoginOptionsCheck: TCheckBox
         Left = 16
-        Top = 298
+        Top = 304
         Width = 129
         Height = 17
         Anchors = [akLeft, akRight, akBottom]
@@ -1505,7 +1554,7 @@ object LoginDialog: TLoginDialog
     end
     object SendToHookAction: TAction
       Category = 'Sessions'
-      Caption = 'Explorer''s ''Send to'' shortcut'
+      Caption = 'Explorer'#39's '#39'Send to'#39' shortcut'
       OnExecute = SendToHookActionExecute
     end
     object CheckForUpdatesAction: TAction

+ 18 - 12
forms/Login.h

@@ -18,14 +18,14 @@
 #include <ActnList.hpp>
 #include <UpDownEdit.hpp>
 #include <XPGroupBox.hpp>
+#include <PasswordEdit.hpp>
+#include <Menus.hpp>
 //----------------------------------------------------------------------------
 #include <Configuration.h>
 #include <SessionData.h>
 
 #include "LogSettings.h"
 #include "GeneralSettings.h"
-#include <Menus.hpp>
-#include "PasswordEdit.hpp"
 //----------------------------------------------------------------------------
 class TLoginDialog : public TForm
 {
@@ -94,20 +94,17 @@ __published:
   TUpDownEdit *PortNumberEdit;
   TFilenameEdit *PrivateKeyEdit;
   TXPGroupBox *DirectoriesGroup;
-  TLabel *Label9;
-  TLabel *Label10;
-  TLabel *Label16;
+  TLabel *LocalDirectoryLabel;
+  TLabel *RemoteDirectoryLabel;
+  TLabel *LocalDirectoryDescLabel;
   TDirectoryEdit *LocalDirectoryEdit;
   TEdit *RemoteDirectoryEdit;
   TCheckBox *UpdateDirectoriesCheck;
   TTreeView *SimpleNavigationTree;
   TTabSheet *ConnSheet;
   TXPGroupBox *TimeoutGroup;
-  TLabel *Label6;
   TLabel *Label11;
   TLabel *Label12;
-  TCheckBox *PingIntervalCheck;
-  TUpDownEdit *PingIntervalSecEdit;
   TUpDownEdit *TimeoutEdit;
   TTabSheet *ProxySheet;
   TXPGroupBox *ProxyTypeGroup;
@@ -191,6 +188,14 @@ __published:
   TMenuItem *CheckForUpdates1;
   TButton *SaveButton;
   TButton *LanguagesButton;
+  TCheckBox *CacheDirectoryChangesCheck;
+  TCheckBox *PreserveDirectoryChangesCheck;
+  TXPGroupBox *PingGroup;
+  TLabel *Label6;
+  TUpDownEdit *PingIntervalSecEdit;
+  TRadioButton *PingOffButton;
+  TRadioButton *PingNullPacketButton;
+  TRadioButton *PingDummyCommandButton;
   void __fastcall DataChange(TObject *Sender);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall SessionListViewSelectItem(TObject *Sender,
@@ -234,14 +239,15 @@ private:
   TSessionData * FSessionData;
   TStoredSessionList * FStoredSessions;
   int FCipherDragSource, FCipherDragDest;
-  bool FInitial;
+  int FOptions;
   TPopupMenu * FLanguagesPopupMenu;
   AnsiString FOrigCaption;
   bool FInitialized;
   TTabSheet * FSavedTab;
   int FSavedSession;
   bool FLocaleChanging;
-  void * FSystemSettings; 
+  void * FSystemSettings;
+  AnsiString FCurrentSessionName;  
 
   void __fastcall LoadSession(TSessionData * aSessionData);
   void __fastcall UpdateControls();
@@ -270,7 +276,7 @@ protected:
   bool __fastcall AllowCipherDrag(int X, int Y);
   void __fastcall CipherMove(int Source, int Dest);
   void __fastcall PrepareNavigationTree(TTreeView * Tree);
-  void __fastcall SetInitial(bool value);
+  void __fastcall SetOptions(int value);
   void __fastcall LocaleClick(TObject * Sender);
   void __fastcall Init();
   void __fastcall ShowTabs(bool Show);
@@ -285,7 +291,7 @@ public:
   __property TSessionData * SessionData  = { read=GetSessionData, write=SetSessionData };
   __property TStoredSessionList * StoredSessions  = { read=FStoredSessions, write=SetStoredSessions };
   __property TSessionData * SelectedSession  = { read=GetSelectedSession, write=SetSelectedSession };
-  __property bool Initial = { read=FInitial, write=SetInitial };
+  __property int Options = { read=FOptions, write=SetOptions };
 };
 //----------------------------------------------------------------------------
 #endif

+ 7 - 33
forms/NonVisual.cpp

@@ -2,16 +2,14 @@
 #include <vcl.h>
 #pragma hdrstop
 
-#include "NonVisual.h"       
+#include "NonVisual.h"
 
 #include <Common.h>
 #include <ScpMain.h>
 #include <TextsWin.h>
 
 #include <Log.h>
-#include <Preferences.h>
 #include <Interface.h>
-#include <UserInterface.h>
 #include "WinConfiguration.h"
 #include "TerminalManager.h"
 //---------------------------------------------------------------------------
@@ -72,7 +70,6 @@ TNonVisualDataModule *NonVisualDataModule;
 __fastcall TNonVisualDataModule::TNonVisualDataModule(TComponent* Owner)
         : TDataModule(Owner)
 {
-  FRightsFrame = NULL;
   FListColumn = NULL;
   FSessionIdleTimerExecuting = false;
 }
@@ -104,35 +101,6 @@ void __fastcall TNonVisualDataModule::LogActionsExecute(
   ;
 }
 //---------------------------------------------------------------------------
-void __fastcall TNonVisualDataModule::RightsActionsExecute(
-      TBasicAction *Action, bool &Handled)
-{
-  assert(RightsFrame);
-  TRights Rights = RightsFrame->Rights;
-  Rights.Number = raNo;
-  EXE(NoRightsAction, Rights = raNo)
-  EXE(DefaultRightsAction, Rights = raDefault)
-  EXE(AllRightsAction, Rights = raAll)
-  EXE(AllRightsAction, Rights = raAll)
-  EXE(LeaveRightsAsIsAction, Rights.AllUndef())
-  ;
-  RightsFrame->Rights = Rights;
-}
-//---------------------------------------------------------------------------
-void __fastcall TNonVisualDataModule::RightsActionsUpdate(
-      TBasicAction *Action, bool &Handled)
-{
-  UPDEX(NoRightsAction, RightsFrame != NULL,
-    NoRightsAction->Checked = (!RightsFrame->Rights.IsUndef && RightsFrame->Rights.NumberSet == raNo),)
-  UPDEX(DefaultRightsAction, RightsFrame != NULL,
-    DefaultRightsAction->Checked = (!RightsFrame->Rights.IsUndef && RightsFrame->Rights.NumberSet == raDefault),)
-  UPDEX(AllRightsAction, RightsFrame != NULL,
-    AllRightsAction->Checked = (!RightsFrame->Rights.IsUndef && RightsFrame->Rights.NumberSet == raAll),)
-  UPDEX(LeaveRightsAsIsAction, RightsFrame != NULL && RightsFrame->Rights.AllowUndef,
-    LeaveRightsAsIsAction->Checked = (RightsFrame->Rights.NumberSet == raNo && RightsFrame->Rights.NumberUnset == raNo),)
-  ;
-}
-//---------------------------------------------------------------------------
 void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
       TBasicAction *Action, bool &Handled)
 {
@@ -315,10 +283,13 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
   // COMMAND
   UPD(CompareDirectoriesAction, true)
   UPD(SynchronizeAction, true)
+  UPD(FullSynchronizeAction, true)
   UPD(ConsoleAction, ScpExplorer->Terminal && ScpExplorer->Terminal->IsCapable[fcAnyCommand])
   UPD(PuttyAction, true)
   UPD(SynchorizeBrowsingAction, true)
   UPD(CloseApplicationAction, true)
+  UPD(FileSystemInfoAction, true)
+  UPD(ClearCachesAction, (ScpExplorer->Terminal != NULL) && !ScpExplorer->Terminal->AreCachesEmpty)
 
   // CUSTOM COMMANDS
   UPD(CustomCommandsAction,
@@ -486,10 +457,13 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
   // COMMAND
   EXE(CompareDirectoriesAction, ScpExplorer->CompareDirectories())
   EXE(SynchronizeAction, ScpExplorer->SynchronizeDirectories())
+  EXE(FullSynchronizeAction, ScpExplorer->FullSynchronizeDirectories())
   EXE(ConsoleAction, ScpExplorer->OpenConsole())
   EXE(PuttyAction, ScpExplorer->OpenInPutty())
   EXE(SynchorizeBrowsingAction, )
   EXE(CloseApplicationAction, ScpExplorer->Close())
+  EXE(FileSystemInfoAction, DoFileSystemInfoDialog(ScpExplorer->Terminal))
+  EXE(ClearCachesAction, ScpExplorer->Terminal->ClearCaches())
 
   // CUSTOM COMMANDS
   EXE(CustomCommandsAction, CreateCustomCommandsMenu(CustomCommandsAction))

+ 196 - 334
forms/NonVisual.dfm

@@ -867,197 +867,11 @@ object NonVisualDataModule: TNonVisualDataModule
       F80F8FFB03FFEDB7F81FFFFFFFFFFFFF00000000000000000000000000000000
       000000000000}
   end
-  object RightsActions: TActionList
-    Images = RightsImages
-    OnExecute = RightsActionsExecute
-    OnUpdate = RightsActionsUpdate
-    Left = 128
-    Top = 56
-    object NoRightsAction: TAction
-      Caption = '&No Rights'
-      ImageIndex = 0
-      ShortCut = 16462
-    end
-    object DefaultRightsAction: TAction
-      Caption = '&Default Rights'
-      ImageIndex = 1
-      ShortCut = 16452
-    end
-    object AllRightsAction: TAction
-      Caption = '&All Rights'
-      ImageIndex = 2
-      ShortCut = 16449
-    end
-    object LeaveRightsAsIsAction: TAction
-      Caption = '&Leave As Is'
-      ShortCut = 16460
-    end
-  end
-  object RightsImages: TImageList
-    Left = 128
-    Top = 8
-    Bitmap = {
-      494C010103000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
-      0000000000003600000028000000400000001000000001002000000000000010
-      0000000000000000000000000000000000000000000000000000000000007B7B
-      00007B7B00007B7B000039312100000000005A5A10007B7B0000000000003931
-      2100000000000000000000000000000000000000000000000000000000007B7B
-      00007B7B00007B7B000029291000000000005A5A10007B7B0000000000003929
-      4A00000000000000000000000000000000000000000073733900737339007373
-      39004A4A3900000000004A4A39007373390000000000292929006B086B000000
-      00006B086B00000000006B086B00000000000000000000000000000000000000
-      000000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000BDBD0000F7F7
-      0000F7F700007B7B0000BDBD00007B7B0000BDBD00007B7B00007B7B0000217B
-      9C000000000000008400FFFFFF00000000000000000000000000BDBD0000DEDE
-      0000FFFF00007B7B0000BDBD00007B7B0000BDBD00007B7B00007B7B0000217B
-      9C0000000000000000000000000000000000B5BD0000EFEF0000EFEF00007373
-      3900B5BD000073733900B5BD0000737339007373390018737B0018737B001873
-      7B006B086B006B086B006B086B0000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00000000000000000000000000000000005A5A10000000
-      8400FFFFFF009C9C0000F7F700005A5A100042424200393121007B7B00000000
-      00000000000000000000000000000000000000000000000000005A5A1000BDBD
-      00007B7B00009C9C0000FFFF00005A5A100042424200292910007B7B00000000
-      0000000000000000000000000000000000004A4A3900B5BD000073733900B5BD
-      0000EFEF0000737339004A4A39004A4A39007373390010ADAD0010ADAD0073AD
-      AD004A4A39000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000084000000
-      840000008400FFFFFF005A5A10008484840084848400424242005A5A5A000000
-      000000008400FFFFFF0000000000000000000000000000000000000000000000
-      00005A5A1000DEDE00005A5A1000848484008484840042424200635A63000000
-      00000000000000000000000000000000000000000000000000004A4A3900EFEF
-      000073733900737339008C8C8C004A4A39004A4A390010ADAD0073ADAD00EFF7
-      EF004A4A39000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000084000000
-      840000008400FFFFFF00848484006B6B6B004242420000000000393121000000
-      8400FFFFFF000000000000000000000000000000000000000000000000000000
-      0000292910002929100084848400635A63004242420000000000292910000000
-      0000000000000000000000000000000000000000000000000000292929002929
-      290073733900737339004A4A3900000000002929290010ADAD00EFF7EF008C8C
-      8C008C8C8C00737339002929290000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
-      84000000840000008400FFFFFF00848484008484840084848400000084000000
-      8400FFFFFF000000000000000000000000000000000000000000000000000000
-      00000000000029291000635A6300848484008484840084848400848484004242
-      4200000000000000000000000000000000000000000000000000000000002929
-      29004A4A39008C8C8C008C8C8C008C8C8C008C8C8C0029292900EFF7EF00EFF7
-      EF00EFF7EF00EFF7EF00737339000000000000008400FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF0000000000000000000000000000000000000000000000
-      0000000084000000840000008400FFFFFF00848484000000840000008400FFFF
-      FF00000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000042424200848484008484840084848400635A63004242
-      4200000000000000000000000000000000000000000000000000000000000000
-      00004A4A39008C8C8C00737339008C8C8C004A4A39004A4A3900EFF7EF00EFF7
-      EF00EFF7EF008C8C8C002929290000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF000000000000000000000000000000000000000000000000000000
-      0000000000002929290018737B0018737B000000000000000000000000000000
-      0000000000000000840000008400000084000000840000008400FFFFFF004242
-      4200000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000635A6300848484008484840084848400848484004242
-      4200000000000000000000000000000000000000000000000000000000000000
-      00004A4A39008C8C8C008C8C8C008C8C8C008C8C8C0029292900EFF7EF00EFF7
-      EF00EFF7EF0073ADAD008C8C8C0000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF007B7B00007B7B00007B7B0000393121000000
-      00005A5A10007B7B000000000000393121000000000000000000000000000000
-      00000000000042424200000084000000840000008400FFFFFF00848484004242
-      42006B6B6B000000000000000000000000000000000000000000000000000000
-      0000000000004242420084848400848484008484840084848400848484004242
-      42006B6B6B000000000000000000000000000000000000000000000000004A4A
-      39008C8C8C008C8C8C00737339008C8C8C008C8C8C002929290073733900EFF7
-      EF00FF7B7B00EFF7EF004A4A390000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
-      0000000000000000840000008400000084000000840000008400FFFFFF004242
-      4200000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000042424200848484008484840029291000848484004242
-      4200000000000000000000000000000000000000000000000000000000000000
-      0000292929008C8C8C008C8C8C00000000008C8C8C0029292900EFF7EF00EFF7
-      EF008C8C8C008C8C8C000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
-      0000000084000000840000008400FFFFFF008484840000008400FFFFFF000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000004242420084848400635A6300000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000004A4A39008C8C8C004A4A39000000000073ADAD0018737B00EFF7
-      EF0073ADAD00EFF7EF004A4A390000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF0000000000000000000000000042424200000084000000
-      840000008400FFFFFF0084848400424242000000000000000000000084000000
-      84000000840000008400FFFFFF00424242008484840084848400000084000000
-      8400FFFFFF000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000424242008484840084848400292910000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000292929008C8C8C008C8C8C002929290073ADAD0010ADAD0010AD
-      AD0008F7F70010ADAD0008F7F70000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000008400000084000000
-      840000008400FFFFFF0000000000000000000000000000000000000000000000
-      840000008400FFFFFF0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000073ADAD0063DEDE0008F7
-      F70008F7F70008F7F7002929290000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000840000008400FFFF
-      FF00000000000000000000000000000000000000000000000000000000000039
-      39000000840000008400FFFFFF00000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000039
-      3900000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000002929290018737B001873
-      7B0018737B00000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00424D3E000000000000003E000000
-      2800000040000000100000000100010000000000800000000000000000000000
-      000000000000000000000000FFFFFF00E00FE00F8001FF00C009C00F00000500
-      C01FC01F00030500C013E01F80070500C007F01FC001FF00E007E00F8001FF00
-      E00FE00F8001FF00C00FC00F0000FF00C007C0070001FF00C00FC00F0001FF00
-      C01FC01F0000FF00C007C01F0000FF008003C01F0001FF008001E00F8003FF00
-      F01FF01FC07FFF00FFFFFFFFFFFF000000000000000000000000000000000000
-      000000000000}
-  end
-  object RightsPopup: TPopupMenu
-    Images = RightsImages
-    Left = 128
-    Top = 104
-    object Norights1: TMenuItem
-      Action = NoRightsAction
-    end
-    object Defaultrights1: TMenuItem
-      Action = DefaultRightsAction
-    end
-    object Allrights1: TMenuItem
-      Action = AllRightsAction
-    end
-    object Leaveasis1: TMenuItem
-      Action = LeaveRightsAsIsAction
-    end
-  end
   object ExplorerImages: TImageList
     Left = 232
     Top = 24
     Bitmap = {
-      494C010141004500040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010143004500040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000002001000001002000000000000020
       0100000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -1192,119 +1006,119 @@ object NonVisualDataModule: TNonVisualDataModule
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000DDE0DE00CFBFB200CFBFB200DDE1DE00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000007F7F7F00C0C0C000C0C0C000C0C0
       C000C0C0C000808080006060600080808000A0A0A00060606000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000084000000840000008400000084848400000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000DDE0DE00B77C5A00AF4A0100BC570100AF4A010099340100AB623C00D8D5
+      CF00000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000003F3F3F00AFAFAF007F7F7F007F7F
       7F007F7F7F007F7F7F007F7F7F007F7F7F00CFCFCF0080808000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008484840084000000840000000000000084000000000000000000
+      000000000000000000000000000000000000000000000000000000000000DDE0
+      DF00B0602D00C6610100B9540100B77D5A00CFBFB200E0ECEC00D8D5CF00CFBF
+      B200000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000BFBFBF00BFBF
       BF00BFBFBF00BFBFBF00BFBFBF0090909000404040005F5F5F00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008400000084000000840000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000B66C
+      3D00D16C0100C6610100C0917800000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000000000000000000000000000007F7F7F00FF00
       00007F000000FF000000FF000000A0A0A0004040400000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008400000084000000840000008484840000000000000000000000
+      0000000000000000000000000000000000000000000000000000D7CBC200CA66
+      0100DC770100B6510100DBD6D10000000000000000000000000000000000E1E3
+      E000C09278000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000000000000000000000000000007F7F7F00FF00
       00003F3F3F003F3F3F00BF000000A0A0A0004040400000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008484840084000000840000008484840000000000000000000000
+      0000000000000000000000000000000000000000000000000000C0917800E983
+      0100E07B0100B75201000000000000000000000000000000000000000000AF66
+      3D00A33E0100BA856A0000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000000000000000000000000000007F7F7F00FF00
       0000FF0000003F3F3F0000BFBF00707070004040400000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008484840084000000840000008400000000000000000000000000
+      000000000000000000000000000000000000A33E0100B6643100B6643100F690
+      0100E47F0100B7520100A33E0100A33E01000000000000000000BA866A00A33E
+      0100CC670100A33E0100C8A89500000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000BFBFBF007F7F
       7F007F7F7F007F7F7F003F7F7F0000BFBF00003F3F0040404000404040004040
       4000404040004040400030303000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000084848400840000008400000084848400000000000000
+      000000000000000000000000000000000000E4EEEE00A33E0100F29B2C00F993
+      0100E9840100D9740100A33E0100C49C860000000000C8A89500A33E0100CC67
+      0100CC670100CC670100A33E0100D7CBC2000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000303030006060
       600060606000007F7F00007F7F0000BFBF0000FFFF00306F6F00808080006060
       600060606000B0B0B00080808000202020000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000840000008400000084000000000000000000
+      00000000000000000000000000000000000000000000E4E4E100A33E0100F791
+      0100ED880100D26D0100BA7E5B0000000000DACDC300A33E0100BF5A0100CC67
+      0100CC670100C9640100BF5A0100A33E01000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000BFBF0000FFFF00007F7F00007F7F00003F3F007F7F
       7F007F7F7F009F9F9F00AFAFAF00404040000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008400000000000000840000008400000084000000000000000000
+      0000000000000000000000000000000000000000000000000000DACDC300A33E
+      0100EC870100B1612E00E3E4E100000000000000000000000000C59D8700BF5A
+      0100CC670100B752010000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000007F7F0000BFBF007F7F7F00BFBFBF00BFBF
       BF00AFAFAF00606060005F5F5F00202020000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008484840084000000840000008400000084848400000000000000
+      000000000000000000000000000000000000000000000000000000000000D4C1
+      B400A3451000E3E4E10000000000000000000000000000000000D3C1B400BF5A
+      0100CC670100B752010000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000007F7F7F00003F3F0000BFBF00BF000000FF00
       0000DF6060008080800000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000BB866A00C964
+      0100C9640100B46A3D0000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000007F7F7F007F0000007F000000007F7F00BF00
       0000DF6060008080800000000000000000000000000000000000000000000000
+      0000000000000000000084848400840000008400000084848400000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000C69D8700B14C0100CC67
+      0100B1521000DACDC30000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000007F7F7F007F000000FF000000BF000000BF00
       0000DF6060008080800000000000000000000000000000000000000000000000
+      0000000000000000000084000000840000008400000084000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000BB866A00AD633D00C1784100BC5D1000D5710100CA650100AD55
+      1F00D9CDC3000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000007F7F7F007F7F7F007F7F7F007F7F7F007F7F
       7F00AFAFAF008080800000000000000000000000000000000000000000000000
+      0000000000000000000084848400840000008400000084848400000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000DACEC400C2937900C5814C00BC866A00CBAA97000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -3369,11 +3183,11 @@ object NonVisualDataModule: TNonVisualDataModule
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000003F000000000000001F000000000000
-      001F000000000000801F000000000000807F000000000000807F000000000000
-      807F0000000000008001000000000000C000000000000000F800000000000000
-      FC00000000000000FE01000000000000FE01000000000000FE01000000000000
-      FE01000000000000FE010000000000000003FFFFFFFFFE7F00030015FFFFF00F
+      00000000000000000000000000000000003FFFFFFC3F0000001FFC3FF00F0000
+      001FF8BFE00F0000801FF8FFE1FF0000807FF87FC1E70000807FF87FC3E30000
+      807FF87F00C100008001FC3F00800000C000FE3F81000000F800FA3FC1C30000
+      FC00F83FE3C30000FE01FFFFFFC30000FE01FC3FFF830000FE01FC3FF8070000
+      FE01FC3FFC1F0000FE01FFFFFFFF00000003FFFFFFFFFE7F00030015FFFFF00F
       00030000FFFFE00700030000FFFFC0030003E007E000C0030003E007E0008001
       0003E007600080018003E007200080018003E007200080018003E00760008001
       8003E007E00080018003E007E000C0038003FFFFE000C0038007F81FFFFFE001
@@ -3493,7 +3307,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ImageIndex = 3
     end
     object LocalSortAscendingAction: TAction
-      Tag = 8
+      Tag = 9
       Category = 'Sort'
       Caption = '&Ascending'
       Hint = 
@@ -3943,7 +3757,7 @@ object NonVisualDataModule: TNonVisualDataModule
       Hint = 'Hide/show remote panel status bar'
     end
     object LocalSortByNameAction: TAction
-      Tag = 8
+      Tag = 9
       Category = 'Sort'
       Caption = 'By &Name'
       Hint = 'Sort by name|Sort local panel by name'
@@ -3951,7 +3765,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16498
     end
     object LocalSortByExtAction: TAction
-      Tag = 8
+      Tag = 9
       Category = 'Sort'
       Caption = 'By &Extension'
       Hint = 'Sort by extension|Sort local panel by file name extension'
@@ -3959,7 +3773,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16499
     end
     object LocalSortBySizeAction: TAction
-      Tag = 8
+      Tag = 9
       Category = 'Sort'
       Caption = 'By &Size'
       Hint = 'Sort by size|Sort local panel by file size'
@@ -3967,7 +3781,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16501
     end
     object LocalSortByAttrAction: TAction
-      Tag = 8
+      Tag = 9
       Category = 'Sort'
       Caption = 'By A&ttributes'
       Hint = 'Sort by attributes|Sort local panel by attributes'
@@ -3975,14 +3789,14 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16502
     end
     object LocalSortByTypeAction: TAction
-      Tag = 8
+      Tag = 9
       Category = 'Sort'
       Caption = 'By &Type'
       Hint = 'Sort by type|Sort local panel by file type'
       ImageIndex = 34
     end
     object LocalSortByChangedAction: TAction
-      Tag = 8
+      Tag = 9
       Category = 'Sort'
       Caption = 'By &Modification'
       Hint = 'Sort by time|Sort local panel by last modification time'
@@ -3990,7 +3804,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16500
     end
     object RemoteSortAscendingAction: TAction
-      Tag = 12
+      Tag = 14
       Category = 'Sort'
       Caption = '&Ascending'
       Hint = 
@@ -3999,7 +3813,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ImageIndex = 37
     end
     object RemoteSortByNameAction: TAction
-      Tag = 12
+      Tag = 14
       Category = 'Sort'
       Caption = 'By &Name'
       Hint = 'Sort by name|Sort remote panel by name'
@@ -4007,7 +3821,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16498
     end
     object RemoteSortByExtAction: TAction
-      Tag = 12
+      Tag = 14
       Category = 'Sort'
       Caption = 'By &Extension'
       Hint = 'Sort by extension|Sort remote panel by file name extension'
@@ -4015,7 +3829,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16499
     end
     object RemoteSortBySizeAction: TAction
-      Tag = 12
+      Tag = 14
       Category = 'Sort'
       Caption = 'By &Size'
       Hint = 'Sort by size|Sort remote panel by file size'
@@ -4023,7 +3837,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16501
     end
     object RemoteSortByRightsAction: TAction
-      Tag = 12
+      Tag = 14
       Category = 'Sort'
       Caption = 'By &Permissions'
       Hint = 'Sort by permissions|Sort remote panel by permissions'
@@ -4031,7 +3845,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16502
     end
     object RemoteSortByChangedAction: TAction
-      Tag = 12
+      Tag = 14
       Category = 'Sort'
       Caption = 'By &Modification'
       Hint = 'Sort by time|Sort remote panel by last modification time'
@@ -4039,7 +3853,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16500
     end
     object RemoteSortByOwnerAction: TAction
-      Tag = 12
+      Tag = 14
       Category = 'Sort'
       Caption = 'By &Owner'
       Hint = 'Sort by owner|Sort remote panel by file owner'
@@ -4047,7 +3861,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16503
     end
     object RemoteSortByGroupAction: TAction
-      Tag = 12
+      Tag = 14
       Category = 'Sort'
       Caption = 'By &Group'
       Hint = 'Sort by group|Sort remote panel by file group'
@@ -4088,7 +3902,7 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16501
     end
     object CurrentSortByTypeAction: TAction
-      Tag = 13
+      Tag = 9
       Category = 'Sort'
       Caption = 'By &Type'
       Hint = 'Sort by type|Sort current panel by file type (local panel only)'
@@ -4133,14 +3947,14 @@ object NonVisualDataModule: TNonVisualDataModule
       ShortCut = 16504
     end
     object SortColumnAscendingAction: TAction
-      Tag = 12
+      Tag = 15
       Category = 'Sort'
       Caption = 'Sort &Ascending'
       Hint = 'Sort files ascending by selected column'
       ImageIndex = 41
     end
     object SortColumnDescendingAction: TAction
-      Tag = 12
+      Tag = 15
       Category = 'Sort'
       Caption = 'Sort &Descending'
       Hint = 'Sort files descending by selected column'
@@ -4416,12 +4230,33 @@ object NonVisualDataModule: TNonVisualDataModule
       Caption = '&Donate'
       Hint = 'Opens web browser and points it to program donation page'
     end
+    object FileSystemInfoAction: TAction
+      Tag = 15
+      Category = 'Command'
+      Caption = '&Server/protocol Information'
+      Hint = 'Display server/protocol information'
+      ImageIndex = 17
+    end
+    object ClearCachesAction: TAction
+      Tag = 15
+      Category = 'Command'
+      Caption = 'Clea&r Caches'
+      Hint = 'Clear directory listing and directory changes caches'
+    end
+    object FullSynchronizeAction: TAction
+      Tag = 15
+      Category = 'Command'
+      Caption = '&Synchronize'
+      Hint = 'Synchronize local directory with remote directory'
+      ImageIndex = 66
+      ShortCut = 16467
+    end
   end
   object ExplorerDisabledImages: TImageList
     Left = 336
     Top = 24
     Bitmap = {
-      494C010141004500040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010143004500040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000002001000001002000000000000020
       0100000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -4556,119 +4391,119 @@ object NonVisualDataModule: TNonVisualDataModule
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000DDE0DE00CFBFB200CFBFB200DDE1DE00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000007F7F7F00C0C0C000C0C0C000C0C0
       C000C0C0C000808080006060600080808000A0A0A00060606000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000084000000840000008400000084848400000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000DDE0DE00B77C5A00AF4A0100BC570100AF4A010099340100AB623C00D8D5
+      CF00000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000003F3F3F00AFAFAF007F7F7F007F7F
       7F007F7F7F007F7F7F007F7F7F007F7F7F00CFCFCF0080808000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008484840084000000840000000000000084000000000000000000
+      000000000000000000000000000000000000000000000000000000000000DDE0
+      DF00B0602D00C6610100B9540100B77D5A00CFBFB200E0ECEC00D8D5CF00CFBF
+      B200000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000BFBFBF00BFBF
       BF00BFBFBF00BFBFBF00BFBFBF0090909000404040005F5F5F00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008400000084000000840000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000B66C
+      3D00D16C0100C6610100C0917800000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000000000000000000000000000007F7F7F00FF00
       00007F000000FF000000FF000000A0A0A0004040400000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008400000084000000840000008484840000000000000000000000
+      0000000000000000000000000000000000000000000000000000D7CBC200CA66
+      0100DC770100B6510100DBD6D10000000000000000000000000000000000E1E3
+      E000C09278000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000000000000000000000000000007F7F7F00FF00
       00003F3F3F003F3F3F00BF000000A0A0A0004040400000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008484840084000000840000008484840000000000000000000000
+      0000000000000000000000000000000000000000000000000000C0917800E983
+      0100E07B0100B75201000000000000000000000000000000000000000000AF66
+      3D00A33E0100BA856A0000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000000000000000000000000000007F7F7F00FF00
       0000FF0000003F3F3F0000BFBF00707070004040400000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008484840084000000840000008400000000000000000000000000
+      000000000000000000000000000000000000A33E0100B6643100B6643100F690
+      0100E47F0100B7520100A33E0100A33E01000000000000000000BA866A00A33E
+      0100CC670100A33E0100C8A89500000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000BFBFBF007F7F
       7F007F7F7F007F7F7F003F7F7F0000BFBF00003F3F0040404000404040004040
       4000404040004040400030303000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000084848400840000008400000084848400000000000000
+      000000000000000000000000000000000000E4EEEE00A33E0100F29B2C00F993
+      0100E9840100D9740100A33E0100C49C860000000000C8A89500A33E0100CC67
+      0100CC670100CC670100A33E0100D7CBC2000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000303030006060
       600060606000007F7F00007F7F0000BFBF0000FFFF00306F6F00808080006060
       600060606000B0B0B00080808000202020000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000840000008400000084000000000000000000
+      00000000000000000000000000000000000000000000E4E4E100A33E0100F791
+      0100ED880100D26D0100BA7E5B0000000000DACDC300A33E0100BF5A0100CC67
+      0100CC670100C9640100BF5A0100A33E01000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000BFBF0000FFFF00007F7F00007F7F00003F3F007F7F
       7F007F7F7F009F9F9F00AFAFAF00404040000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008400000000000000840000008400000084000000000000000000
+      0000000000000000000000000000000000000000000000000000DACDC300A33E
+      0100EC870100B1612E00E3E4E100000000000000000000000000C59D8700BF5A
+      0100CC670100B752010000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000007F7F0000BFBF007F7F7F00BFBFBF00BFBF
       BF00AFAFAF00606060005F5F5F00202020000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008484840084000000840000008400000084848400000000000000
+      000000000000000000000000000000000000000000000000000000000000D4C1
+      B400A3451000E3E4E10000000000000000000000000000000000D3C1B400BF5A
+      0100CC670100B752010000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000007F7F7F00003F3F0000BFBF00BF000000FF00
       0000DF6060008080800000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000BB866A00C964
+      0100C9640100B46A3D0000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000007F7F7F007F0000007F000000007F7F00BF00
       0000DF6060008080800000000000000000000000000000000000000000000000
+      0000000000000000000084848400840000008400000084848400000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000C69D8700B14C0100CC67
+      0100B1521000DACDC30000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000007F7F7F007F000000FF000000BF000000BF00
       0000DF6060008080800000000000000000000000000000000000000000000000
+      0000000000000000000084000000840000008400000084000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000BB866A00AD633D00C1784100BC5D1000D5710100CA650100AD55
+      1F00D9CDC3000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000007F7F7F007F7F7F007F7F7F007F7F7F007F7F
       7F00AFAFAF008080800000000000000000000000000000000000000000000000
+      0000000000000000000084848400840000008400000084848400000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000DACEC400C2937900C5814C00BC866A00CBAA97000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -6733,11 +6568,11 @@ object NonVisualDataModule: TNonVisualDataModule
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000003F000000000000001F000000000000
-      001F000000000000801F000000000000807F000000000000807F000000000000
-      807F0000000000008001000000000000C000000000000000F800000000000000
-      FC00000000000000FE01000000000000FE01000000000000FE01000000000000
-      FE01000000000000FE010000000000000003800AFFFFFE7F7C030000FFFFF00F
+      00000000000000000000000000000000003FFFFFFC3F0000001FFC3FF00F0000
+      001FF8BFE00F0000801FF8FFE1FF0000807FF87FC1E70000807FF87FC3E30000
+      807FF87F00C100008001FC3F00800000C000FE3F81000000F800FA3FC1C30000
+      FC00F83FE3C30000FE01FFFFFFC30000FE01FC3FFF830000FE01FC3FF8070000
+      FE01FC3FFC1F0000FE01FFFFFFFF00000003800AFFFFFE7F7C030000FFFFF00F
       5DF30000FFFFE00745D30000FFFFC0036413E003E000C0037D53E003E0008001
       0193E00360008001A053E00320008001BFF3E00320008001A213E00360008001
       A3F3E003E0008001AA13E007E000C003ABC3FC0FE000C003A3D7F80FFFFFE001
@@ -6859,6 +6694,9 @@ object NonVisualDataModule: TNonVisualDataModule
       object Disconnect2: TMenuItem
         Action = CloseSessionAction
       end
+      object Quit2: TMenuItem
+        Action = CloseApplicationAction
+      end
     end
     object ExporerCommandsMenu: TMenuItem
       Caption = '&Commands'
@@ -6886,12 +6724,18 @@ object NonVisualDataModule: TNonVisualDataModule
       object OpeninPuTTY2: TMenuItem
         Action = PuttyAction
       end
-      object N47: TMenuItem
+      object N50: TMenuItem
         Caption = '-'
         Hint = 'E'
       end
-      object Quit2: TMenuItem
-        Action = CloseApplicationAction
+      object Serverprotocolinformation2: TMenuItem
+        Action = FileSystemInfoAction
+      end
+      object ClearCaches2: TMenuItem
+        Action = ClearCachesAction
+      end
+      object Synchronize2: TMenuItem
+        Action = FullSynchronizeAction
       end
     end
     object ExplorerViewMenu: TMenuItem
@@ -7689,6 +7533,7 @@ object NonVisualDataModule: TNonVisualDataModule
         object ByExtension2: TMenuItem
           Action = LocalSortByExtAction
           GroupIndex = 1
+          RadioItem = True
         end
         object ByType1: TMenuItem
           Action = LocalSortByTypeAction
@@ -7794,15 +7639,32 @@ object NonVisualDataModule: TNonVisualDataModule
       object Keepremotedirectoryuptodate1: TMenuItem
         Action = SynchronizeAction
       end
+      object Synchronize1: TMenuItem
+        Action = FullSynchronizeAction
+      end
+      object Synchronizebrowsing1: TMenuItem
+        Action = SynchorizeBrowsingAction
+        AutoCheck = True
+      end
+      object N47: TMenuItem
+        Caption = '-'
+        Hint = 'E'
+      end
       object OpenTerminal1: TMenuItem
         Action = ConsoleAction
       end
       object OpeninPuTTY1: TMenuItem
         Action = PuttyAction
       end
-      object Synchronizebrowsing1: TMenuItem
-        Action = SynchorizeBrowsingAction
-        AutoCheck = True
+      object N49: TMenuItem
+        Caption = '-'
+        Hint = 'E'
+      end
+      object Serverprotocolinformation1: TMenuItem
+        Action = FileSystemInfoAction
+      end
+      object ClearCaches1: TMenuItem
+        Action = ClearCachesAction
       end
       object N46: TMenuItem
         Caption = '-'
@@ -7960,6 +7822,7 @@ object NonVisualDataModule: TNonVisualDataModule
         object ByExtension3: TMenuItem
           Action = RemoteSortByExtAction
           GroupIndex = 1
+          RadioItem = True
         end
         object ByModification2: TMenuItem
           Action = RemoteSortByChangedAction
@@ -8196,7 +8059,7 @@ object NonVisualDataModule: TNonVisualDataModule
     Left = 168
     Top = 176
     Bitmap = {
-      494C010102000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010102000400040010001000FFFFFFFFFF00FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000001000000001002000000000000010
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -8239,26 +8102,26 @@ object NonVisualDataModule: TNonVisualDataModule
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000084848400FFFFFF0000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
       0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
       FF00000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000084848400FFFFFF0000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000848484000000000000000000FFFFFF00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       000084848400000000000000000000000000000000000000000000000000FFFF
       FF00000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000848484000000000000000000FFFFFF00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000848484000000000000000000FFFFFF00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000008484840000000000000000000000000000000000FFFFFF000000
       0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000848484000000000000000000FFFFFF00000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -8271,26 +8134,26 @@ object NonVisualDataModule: TNonVisualDataModule
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000848484000000000000000000FFFFFF00000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
       0000000000008484840000000000000000000000000000000000FFFFFF000000
       0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000848484000000000000000000FFFFFF00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000848484000000000000000000FFFFFF00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       000084848400000000000000000000000000000000000000000000000000FFFF
       FF00000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000848484000000000000000000FFFFFF00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000084848400FFFFFF0000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       000084848400848484008484840084848400848484008484840084848400FFFF
       FF00000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000084848400FFFFFF0000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -8329,10 +8192,9 @@ object NonVisualDataModule: TNonVisualDataModule
       000000000000000000000000000000000000424D3E000000000000003E000000
       2800000040000000100000000100010000000000800000000000000000000000
       000000000000000000000000FFFFFF00FFFFFFFF00000000FFFFFFFF00000000
-      FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FE7FF00F00000000
-      FDBFF7EF00000000FDBFFBDF00000000FBDFFBDF00000000FBDFFDBF00000000
-      F7EFFDBF00000000F00FFE7F00000000FFFFFFFF00000000FFFFFFFF00000000
-      FFFFFFFF00000000FFFFFFFF0000000000000000000000000000000000000000
-      000000000000}
+      FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000F00FFE7F00000000
+      F7EFFDBF00000000FBDFFDBF00000000FBDFFBDF00000000FDBFFBDF00000000
+      FDBFF7EF00000000FE7FF00F00000000FFFFFFFF00000000FFFFFFFF00000000
+      FFFFFFFF00000000FFFFFFFF00000000}
   end
 end

+ 13 - 16
forms/NonVisual.h

@@ -23,6 +23,7 @@
 #define fcRemoteStatusBar  0x14
 #define fcSessionCombo     0x15
 #define fcMenuToolBar      0x16
+#define fcRemotePopup      0x17
 
 #define fcExplorerMenuBand        0x0003
 #define fcExplorerAddressBand     0x0103
@@ -59,15 +60,6 @@ __published:	// IDE-managed Components
   TMenuItem *Selectall1;
   TImageList *LogImages;
   TImageList *LogDisabledImages;
-  TActionList *RightsActions;
-  TImageList *RightsImages;
-  TPopupMenu *RightsPopup;
-  TAction *NoRightsAction;
-  TAction *DefaultRightsAction;
-  TAction *AllRightsAction;
-  TMenuItem *Norights1;
-  TMenuItem *Defaultrights1;
-  TMenuItem *Allrights1;
   TImageList *ExplorerImages;
   TPopupMenu *RemoteDirViewPopup;
   TMenuItem *CurrentCopyMenuItem;
@@ -445,8 +437,6 @@ __published:	// IDE-managed Components
   TMenuItem *Openterminal2;
   TAction *LocalExploreDirectoryAction;
   TMenuItem *Exploredirectory1;
-  TAction *LeaveRightsAsIsAction;
-  TMenuItem *Leaveasis1;
   TAction *CurrentEditAction;
   TMenuItem *CurentEditMenuItem;
   TMenuItem *Edit2;
@@ -482,7 +472,6 @@ __published:	// IDE-managed Components
   TMenuItem *CheckForUpdates1;
   TMenuItem *N46;
   TMenuItem *Quit1;
-  TMenuItem *N47;
   TMenuItem *Quit2;
   TAction *PuttyAction;
   TMenuItem *OpeninPuTTY1;
@@ -490,15 +479,24 @@ __published:	// IDE-managed Components
   TMenuItem *N48;
   TAction *DonatePageAction;
   TMenuItem *Donate1;
+  TAction *FileSystemInfoAction;
+  TMenuItem *Serverprotocolinformation1;
+  TMenuItem *Serverprotocolinformation2;
+  TAction *ClearCachesAction;
+  TMenuItem *ClearCaches1;
+  TMenuItem *ClearCaches2;
+  TAction *FullSynchronizeAction;
+  TMenuItem *Synchronize1;
+  TMenuItem *Synchronize2;
+  TMenuItem *N47;
+  TMenuItem *N49;
+  TMenuItem *N50;
   void __fastcall LogActionsUpdate(TBasicAction *Action, bool &Handled);
   void __fastcall LogActionsExecute(TBasicAction *Action, bool &Handled);
-  void __fastcall RightsActionsExecute(TBasicAction *Action, bool &Handled);
-  void __fastcall RightsActionsUpdate(TBasicAction *Action, bool &Handled);
   void __fastcall ExplorerActionsUpdate(TBasicAction *Action, bool &Handled);
   void __fastcall ExplorerActionsExecute(TBasicAction *Action, bool &Handled);
   void __fastcall SessionIdleTimerTimer(TObject *Sender);
 private:
-  TRightsFrame * FRightsFrame;
   TListColumn * FListColumn;
   TCustomScpExplorerForm * FScpExplorer;
   bool FSessionIdleTimerExecuting;
@@ -520,7 +518,6 @@ public:
 
   __fastcall TNonVisualDataModule(TComponent * Owner);
   __property TListColumn * ListColumn = { read = FListColumn, write = FListColumn };
-  __property TRightsFrame * RightsFrame = { read = FRightsFrame, write = FRightsFrame };
   __property TCustomScpExplorerForm * ScpExplorer = { read = FScpExplorer, write = SetScpExplorer };
 };
 //---------------------------------------------------------------------------

+ 1 - 1
forms/OpenDirectory.cpp

@@ -16,7 +16,7 @@
 #pragma link "IEComboBox"
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------
-bool __fastcall OpenDirectoryDialog(TOpenDirectoryMode Mode, TOperationSide Side,
+bool __fastcall DoOpenDirectoryDialog(TOpenDirectoryMode Mode, TOperationSide Side,
   AnsiString & Directory, TStrings * Directories, TTerminal * Terminal)
 {
   bool Result;

+ 5 - 32
forms/OperationStatus.cpp

@@ -23,16 +23,14 @@ __fastcall TOperationStatusForm::TOperationStatusForm(TComponent* Owner)
 {
   FSecureShell = NULL;
   UseSystemSettings(this);
+  FShowAsModalStorage = NULL;
 }
 //---------------------------------------------------------------------------
 __fastcall TOperationStatusForm::~TOperationStatusForm()
 {
   SecureShell = NULL;
-    
-  if (FFormState.Contains(fsModal))
-  {
-    HideAsModal();
-  }
+
+  ReleaseAsModal(this, FShowAsModalStorage);
 }
 //---------------------------------------------------------------------------
 void __fastcall TOperationStatusForm::SecureShellUpdateStatus(TObject * /*Sender*/)
@@ -79,36 +77,11 @@ AnsiString __fastcall TOperationStatusForm::GetStatus()
 //---------------------------------------------------------------------------
 void __fastcall TOperationStatusForm::ShowAsModal()
 {
-  // method duplicated in TProgressForm
-  CancelDrag();
-  if (GetCapture() != 0) SendMessage(GetCapture(), WM_CANCELMODE, 0, 0);
-  ReleaseCapture();
-  FFormState << fsModal;
-  FFocusActiveWindow = GetActiveWindow();
-
-  FFocusWindowList = DisableTaskWindows(0);
-  Show();
-  SendMessage(Handle, CM_ACTIVATE, 0, 0);
+  ::ShowAsModal(this, FShowAsModalStorage);
 }
 //---------------------------------------------------------------------------
 void __fastcall TOperationStatusForm::HideAsModal()
 {
-  // method duplicated in TProgressForm
-  assert(FFormState.Contains(fsModal));
-  SendMessage(Handle, CM_DEACTIVATE, 0, 0);
-  if (GetActiveWindow() != Handle)
-  {
-    FFocusActiveWindow = 0;
-  }
-  Hide();
-
-  EnableTaskWindows(FFocusWindowList);
-
-  if (FFocusActiveWindow != 0)
-  {
-    SetActiveWindow(FFocusActiveWindow);
-  }
-
-  FFormState >> fsModal;
+  ::HideAsModal(this, FShowAsModalStorage);
 }
 

+ 1 - 2
forms/OperationStatus.h

@@ -17,8 +17,7 @@ __published:
   TBevel *Bevel1;
 private:
   TSecureShell * FSecureShell;
-  void * FFocusWindowList;
-  void * FFocusActiveWindow;
+  void * FShowAsModalStorage;
   TNotifyEvent FPrevOnUpdateStatus;
 
   void __fastcall SetSecureShell(TSecureShell * value);

+ 3 - 1
forms/Preferences.cpp

@@ -6,11 +6,13 @@
 
 #include <Common.h>
 #include <ScpMain.h>
+#include <Terminal.h>
 
 #include "VCLCommon.h"
+#include "GUITools.h"
 #include "Tools.h"
 #include "TextsWin.h"
-#include "UserInterface.h"
+#include "WinInterface.h"
 #include "WinConfiguration.h"
 //---------------------------------------------------------------------
 #pragma link "GeneralSettings"

+ 1 - 0
forms/Preferences.dfm

@@ -613,6 +613,7 @@ object PreferencesDialog: TPreferencesDialog
             Caption = 'Upload options'
             inherited RightsFrame: TRightsFrame
               Height = 88
+              PopupMenu = CopyParamsFrame.RightsFrame.RightsPopup
             end
             inherited RemotePreserveTimeCheck: TCheckBox
               Top = 161

+ 34 - 44
forms/Progress.cpp

@@ -11,7 +11,6 @@
 #include <WinInterface.h>
 
 #include "Progress.h"
-#include "WinConfiguration.h"
 //---------------------------------------------------------------------
 #pragma link "PathLabel"
 #pragma resource "*.dfm"
@@ -28,6 +27,7 @@ __fastcall TProgressForm::TProgressForm(TComponent* AOwner)
 	: FData(), TForm(AOwner)
 {
   FLastOperation = foNone;
+  FLastTotalSizeSet = false;
   FDataReceived = false;
   FAsciiTransferChanged = false;
   FResumeStatusChanged = false;
@@ -35,6 +35,8 @@ __fastcall TProgressForm::TProgressForm(TComponent* AOwner)
   FMinimizedByMe = false;
   FUpdateCounter = 0;
   FLastUpdate = 0;
+  FDeleteToRecycleBin = false;
+  FShowAsModalStorage = NULL;
   UseSystemSettings(this);
 }
 //---------------------------------------------------------------------------
@@ -44,11 +46,8 @@ __fastcall TProgressForm::~TProgressForm()
   FData.Clear();
   if (IsIconic(Application->Handle) && FMinimizedByMe)
     Application->Restore();
-    
-  if (FFormState.Contains(fsModal))
-  {
-    HideAsModal();
-  }
+
+  ReleaseAsModal(this, FShowAsModalStorage);
 }
 //---------------------------------------------------------------------
 void __fastcall TProgressForm::UpdateControls()
@@ -75,10 +74,8 @@ void __fastcall TProgressForm::UpdateControls()
           break;
 
         case foDelete:
-          if ((FData.Side == osLocal) && WinConfiguration->DeleteToRecycleBin)
-            Animate->CommonAVI = aviRecycleFile;
-          else
-            Animate->CommonAVI = aviDeleteFile;
+          Animate->CommonAVI = ((FData.Side == osLocal) && DeleteToRecycleBin) ?
+            aviRecycleFile : aviDeleteFile;
           break;
 
         case foSetProperties:
@@ -123,7 +120,7 @@ void __fastcall TProgressForm::UpdateControls()
       else
     if (!TransferOperation && TransferPanel->Visible) Delta += -TransferPanel->Height;
     TransferPanel->Visible = TransferOperation;
-    SpeedPanel->Visible = TransferOperation && WinConfiguration->ExpertMode;
+    SpeedPanel->Visible = TransferOperation;
 
     ClientHeight = ClientHeight + Delta;
     DisconnectWhenCompleteCheck->Top = DisconnectWhenCompleteCheck->Top + Delta;
@@ -135,13 +132,25 @@ void __fastcall TProgressForm::UpdateControls()
     TargetPathLabel->UnixPath = (FData.Side == osLocal);
 
     FileLabel->UnixPath = (FData.Side == osRemote);
-    
+
     FLastOperation = FData.Operation;
+    FLastTotalSizeSet = !FData.TotalSizeSet;
   };
 
+  if (FLastTotalSizeSet != FData.TotalSizeSet)
+  {
+    StartTimeLabelLabel->Visible = !FData.TotalSizeSet;
+    StartTimeLabel->Visible = !FData.TotalSizeSet;
+    TimeEstimatedLabelLabel->Visible = FData.TotalSizeSet;
+    TimeEstimatedLabel->Visible = FData.TotalSizeSet;
+    FLastTotalSizeSet = FData.TotalSizeSet; 
+  }
+
   FileLabel->Caption = FData.FileName;
-  OperationProgress->Position = FData.OverallProgress();
-  OperationProgress->Hint = FORMAT("%d%%", (OperationProgress->Position));
+  int OverallProgress = FData.OverallProgress();
+  OperationProgress->Position = OverallProgress;
+  OperationProgress->Hint = FORMAT("%d%%", (OverallProgress));
+  Caption = FORMAT("%d%% %s", (OverallProgress, OperationName(FData.Operation)));
 
   if (TransferOperation)
   {
@@ -153,7 +162,13 @@ void __fastcall TProgressForm::UpdateControls()
     {
       TargetPathLabel->Caption = LoadStr(PROGRESS_DRAGDROP_TARGET);
     }
+
     StartTimeLabel->Caption = FData.StartTime.TimeString();
+    if (FData.TotalSizeSet)
+    {
+      TimeEstimatedLabel->Caption = FormatDateTime(Configuration->TimeFormat,
+        FData.TotalTimeExpected());
+    }
     TimeElapsedLabel->Caption = FormatDateTime(Configuration->TimeFormat, FData.TimeElapsed());
     BytesTransferedLabel->Caption = FormatBytes(FData.TotalTransfered);
     CPSLabel->Caption = FORMAT("%s/s", (FormatBytes(FData.CPS())));
@@ -202,7 +217,7 @@ void __fastcall TProgressForm::SetProgressData(const TFileOperationProgressType
   if (!FDataReceived)
   {
     FDataReceived = true;
-    ShowAsModal(); 
+    ShowAsModal(this, FShowAsModalStorage);
   }
 
   if (InstantUpdate)
@@ -325,39 +340,14 @@ bool __fastcall TProgressForm::GetDisconnectWhenComplete()
   return DisconnectWhenCompleteCheck->Checked;
 }
 //---------------------------------------------------------------------------
-void __fastcall TProgressForm::ShowAsModal()
+bool __fastcall TProgressForm::GetAllowMinimize()
 {
-  // method duplicated in TOperationStatusForm
-  CancelDrag();
-  if (GetCapture() != 0) SendMessage(GetCapture(), WM_CANCELMODE, 0, 0);
-  ReleaseCapture();
-  FFormState << fsModal;
-  FFocusActiveWindow = GetActiveWindow();
-
-  FFocusWindowList = DisableTaskWindows(0);
-  Show();
-  SendMessage(Handle, CM_ACTIVATE, 0, 0);
+  return MinimizeButton->Visible;
 }
 //---------------------------------------------------------------------------
-void __fastcall TProgressForm::HideAsModal()
+void __fastcall TProgressForm::SetAllowMinimize(bool value)
 {
-  // method duplicated in TOperationStatusForm
-  assert(FFormState.Contains(fsModal));
-  SendMessage(Handle, CM_DEACTIVATE, 0, 0);
-  if (GetActiveWindow() != Handle)
-  {
-    FFocusActiveWindow = 0;
-  }
-  Hide();
-
-  EnableTaskWindows(FFocusWindowList);
-
-  if (FFocusActiveWindow != 0)
-  {
-    SetActiveWindow(FFocusActiveWindow);
-  }
-
-  FFormState >> fsModal;
+  MinimizeButton->Visible = value;
 }
 
 

+ 28 - 12
forms/Progress.dfm

@@ -1,6 +1,6 @@
 object ProgressForm: TProgressForm
-  Left = 462
-  Top = 188
+  Left = 356
+  Top = 204
   BorderStyle = bsDialog
   Caption = 'Operation'
   ClientHeight = 240
@@ -117,6 +117,31 @@ object ProgressForm: TProgressForm
     DesignSize = (
       299
       79)
+    object StartTimeLabel: TLabel
+      Left = 88
+      Top = 18
+      Width = 65
+      Height = 13
+      Alignment = taRightJustify
+      AutoSize = False
+      Caption = '00:00:00'
+    end
+    object TimeEstimatedLabel: TLabel
+      Left = 88
+      Top = 18
+      Width = 65
+      Height = 13
+      Alignment = taRightJustify
+      AutoSize = False
+      Caption = '00:00:00'
+    end
+    object TimeEstimatedLabelLabel: TLabel
+      Left = 0
+      Top = 18
+      Width = 74
+      Height = 13
+      Caption = 'Time estimated:'
+    end
     object CPSLabel: TLabel
       Left = 234
       Top = 34
@@ -165,15 +190,6 @@ object ProgressForm: TProgressForm
       AutoSize = False
       Caption = '0 KB'
     end
-    object StartTimeLabel: TLabel
-      Left = 88
-      Top = 18
-      Width = 65
-      Height = 13
-      Alignment = taRightJustify
-      AutoSize = False
-      Caption = '00:00:00'
-    end
     object Label3: TLabel
       Left = 162
       Top = 18
@@ -182,7 +198,7 @@ object ProgressForm: TProgressForm
       Anchors = [akTop, akRight]
       Caption = 'Time elapsed:'
     end
-    object Label5: TLabel
+    object StartTimeLabelLabel: TLabel
       Left = 0
       Top = 18
       Width = 47

+ 10 - 5
forms/Progress.h

@@ -32,7 +32,7 @@ __published:
   TPanel *TransferPanel;
   TLabel *Label3;
   TLabel *TimeElapsedLabel;
-  TLabel *Label5;
+  TLabel *StartTimeLabelLabel;
   TLabel *StartTimeLabel;
   TLabel *Label4;
   TLabel *BytesTransferedLabel;
@@ -50,6 +50,8 @@ __published:
   TTrackBar *SpeedBar;
   TLabel *SpeedLowLabel;
   TLabel *SpeedHighLabel;
+  TLabel *TimeEstimatedLabelLabel;
+  TLabel *TimeEstimatedLabel;
   void __fastcall UpdateTimerTimer(TObject *Sender);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall FormHide(TObject *Sender);
@@ -60,23 +62,24 @@ private:
   TFileOperationProgressType FData;
   bool FDataReceived;
   TFileOperation FLastOperation;
+  bool FLastTotalSizeSet;
   bool FMinimizedByMe;
   int FUpdateCounter;
   bool FAsciiTransferChanged;
   bool FResumeStatusChanged;
-  void * FFocusWindowList;
-  void * FFocusActiveWindow;
+  void * FShowAsModalStorage;
   TDateTime FLastUpdate;
+  bool FDeleteToRecycleBin;
 
   void __fastcall SetDisconnectWhenComplete(bool value);
   bool __fastcall GetDisconnectWhenComplete();
+  void __fastcall SetAllowMinimize(bool value);
+  bool __fastcall GetAllowMinimize();
 
 protected:
   void __fastcall CancelOperation();
   void __fastcall MinimizeApp();
   void __fastcall UpdateControls();
-  void __fastcall HideAsModal();
-  void __fastcall ShowAsModal();
 
 public:
   static AnsiString __fastcall OperationName(TFileOperation Operation);
@@ -86,6 +89,8 @@ public:
   virtual __fastcall TProgressForm(TComponent * AOwner);
   __property TCancelStatus Cancel = { read = FCancel };
   __property bool DisconnectWhenComplete = { read=GetDisconnectWhenComplete, write=SetDisconnectWhenComplete };
+  __property bool AllowMinimize = { read=GetAllowMinimize, write=SetAllowMinimize };
+  __property bool DeleteToRecycleBin = { read=FDeleteToRecycleBin, write=FDeleteToRecycleBin };
 };
 //----------------------------------------------------------------------------
 #endif

+ 20 - 7
forms/Properties.cpp

@@ -12,7 +12,6 @@
 #include <TextsWin.h>
 
 #include "WinInterface.h"
-#include "TerminalManager.h"
 //---------------------------------------------------------------------
 #pragma link "PathLabel"
 #pragma link "Rights"
@@ -78,9 +77,15 @@ __fastcall TPropertiesDialog::~TPropertiesDialog()
 bool __fastcall TPropertiesDialog::Execute()
 {
   bool Result;
-  TTerminalManager * Manager = TTerminalManager::Instance();
-  TNotifyEvent POnChangeTerminal = Manager->OnChangeTerminal;
-  Manager->OnChangeTerminal = TerminalManagerChangeTerminal;
+
+  FPrevTerminalClose = NULL;;
+  if (FTerminal)
+  {
+    FPrevTerminalClose = FTerminal->OnClose;
+    // used instead of previous TTerminalManager::OnChangeTerminal
+    FTerminal->OnClose = TerminalClose;
+  }
+  
   try
   {
     if (AllowedChanges & cpGroup) ActiveControl = GroupComboBox;
@@ -95,15 +100,23 @@ bool __fastcall TPropertiesDialog::Execute()
   }
   __finally
   {
-    assert(Manager->OnChangeTerminal == TerminalManagerChangeTerminal);
-    Manager->OnChangeTerminal = POnChangeTerminal;
+    if (FTerminal)
+    {
+      assert(FTerminal->OnClose == TerminalClose);
+      FTerminal->OnClose = FPrevTerminalClose;
+    }
   }
   return Result;
 }
 //---------------------------------------------------------------------------
-void __fastcall TPropertiesDialog::TerminalManagerChangeTerminal(TObject * /*Sender*/)
+void __fastcall TPropertiesDialog::TerminalClose(TObject * Sender)
 {
   Close();
+  Terminal = NULL;
+  if (FPrevTerminalClose)
+  {
+    FPrevTerminalClose(Sender);
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TPropertiesDialog::SetFileList(TStrings * value)

+ 1 - 1
forms/Properties.dfm

@@ -209,7 +209,7 @@ object PropertiesDialog: TPropertiesDialog
         Top = 200
         Width = 163
         Height = 109
-        PopupMenu = NonVisualDataModule.RightsPopup
+        PopupMenu = RightsFrame.RightsPopup
         TabOrder = 3
       end
       object GroupComboBox: TComboBox

+ 2 - 1
forms/Properties.h

@@ -60,6 +60,7 @@ private:
   bool FAllowCalculateSize;
   bool FSizeNotCalculated;
   TTerminal * FTerminal;
+  TNotifyEvent FPrevTerminalClose;
 
   void __fastcall SetDirectory(const AnsiString value);
   AnsiString __fastcall GetDirectory();
@@ -70,7 +71,7 @@ private:
   void __fastcall SetFileList(TStrings * value);
   void __fastcall SetFileProperties(TRemoteProperties value);
   void __fastcall SetGroupList(TStrings * value);
-  void __fastcall TerminalManagerChangeTerminal(TObject * /*Sender*/);
+  void __fastcall TerminalClose(TObject * /*Sender*/);
 
 protected:
   void __fastcall LoadInfo();

+ 59 - 17
forms/Rights.cpp

@@ -3,7 +3,6 @@
 #pragma hdrstop
 
 #include "Rights.h"
-#include "NonVisual.h"
 
 #include <Common.h>
 
@@ -21,10 +20,6 @@ __fastcall TRightsFrame::TRightsFrame(TComponent* Owner)
 //---------------------------------------------------------------------------
 __fastcall TRightsFrame::~TRightsFrame()
 {
-  if (NonVisualDataModule->RightsFrame == this)
-  {
-    NonVisualDataModule->RightsFrame = NULL;
-  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TRightsFrame::SetStates(TRightsFlag Flag, TRightState value)
@@ -147,18 +142,6 @@ void __fastcall TRightsFrame::UpdateControls()
   DoChange();
 }
 //---------------------------------------------------------------------------
-void __fastcall TRightsFrame::FrameContextPopup(TObject * /*Sender*/,
-      TPoint & /*MousePos*/, bool & /*Handled*/)
-{
-  NonVisualDataModule->RightsFrame = this;
-}
-//---------------------------------------------------------------------------
-void __fastcall TRightsFrame::FrameEnter(TObject * /*Sender*/)
-{
-  // allow keyboard shortcuts
-  NonVisualDataModule->RightsFrame = this;
-}
-//---------------------------------------------------------------------------
 void __fastcall TRightsFrame::CycleRights(int Group)
 {
   TRightState State;
@@ -263,4 +246,63 @@ void __fastcall TRightsFrame::OctalEditChange(TObject * /*Sender*/)
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TRightsFrame::RightsActionsExecute(TBasicAction * Action,
+  bool & Handled)
+{
+  TRights R = Rights;
+  R.Number = raNo;
+
+  Handled = true;
+  if (Action == NoRightsAction)
+  {
+    R = raNo;
+  }
+  else if (Action == DefaultRightsAction)
+  {
+    R = raDefault;
+  }
+  else if (Action == AllRightsAction)
+  {
+    R = raAll;
+  }
+  else if (Action == LeaveRightsAsIsAction)
+  {
+    R.AllUndef();
+  }
+  else
+  {
+    Handled = false;
+  }
+  Rights = R;
+}
+//---------------------------------------------------------------------------
+void __fastcall TRightsFrame::RightsActionsUpdate(TBasicAction *Action,
+      bool &Handled)
+{
+  TRights R = Rights;
+
+  Handled = true;
+  if (Action == NoRightsAction)
+  {
+    NoRightsAction->Checked = !R.IsUndef && (R.NumberSet == raNo);
+  }
+  else if (Action == DefaultRightsAction)
+  {
+    DefaultRightsAction->Checked = !R.IsUndef && (R.NumberSet == raDefault);
+  }
+  else if (Action == AllRightsAction)
+  {
+    AllRightsAction->Checked = !R.IsUndef && (R.NumberSet == raAll);
+  }
+  else if (Action == LeaveRightsAsIsAction)
+  {
+    LeaveRightsAsIsAction->Enabled = R.AllowUndef;
+    LeaveRightsAsIsAction->Checked = (R.NumberSet == raNo) && (R.NumberUnset == raNo);
+  }
+  else
+  {
+    Handled = false;
+  }
+}
+//---------------------------------------------------------------------------
 

+ 186 - 3
forms/Rights.dfm

@@ -3,10 +3,8 @@ object RightsFrame: TRightsFrame
   Top = 0
   Width = 163
   Height = 109
-  PopupMenu = NonVisualDataModule.RightsPopup
+  PopupMenu = RightsPopup
   TabOrder = 0
-  OnContextPopup = FrameContextPopup
-  OnEnter = FrameEnter
   object OwnerLabel: TLabel
     Left = 4
     Top = 4
@@ -176,4 +174,189 @@ object RightsFrame: TRightsFrame
     TabOrder = 10
     OnClick = ControlChange
   end
+  object RightsPopup: TPopupMenu
+    Images = RightsImages
+    Left = 128
+    Top = 64
+    object Norights1: TMenuItem
+      Action = NoRightsAction
+    end
+    object Defaultrights1: TMenuItem
+      Action = DefaultRightsAction
+    end
+    object Allrights1: TMenuItem
+      Action = AllRightsAction
+    end
+    object Leaveasis1: TMenuItem
+      Action = LeaveRightsAsIsAction
+    end
+  end
+  object RightsActions: TActionList
+    Images = RightsImages
+    OnExecute = RightsActionsExecute
+    OnUpdate = RightsActionsUpdate
+    Left = 128
+    Top = 32
+    object NoRightsAction: TAction
+      Caption = '&No Rights'
+      ImageIndex = 0
+      ShortCut = 16462
+    end
+    object DefaultRightsAction: TAction
+      Caption = '&Default Rights'
+      ImageIndex = 1
+      ShortCut = 16452
+    end
+    object AllRightsAction: TAction
+      Caption = '&All Rights'
+      ImageIndex = 2
+      ShortCut = 16449
+    end
+    object LeaveRightsAsIsAction: TAction
+      Caption = '&Leave As Is'
+      ShortCut = 16460
+    end
+  end
+  object RightsImages: TImageList
+    Left = 128
+    Bitmap = {
+      494C010103000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      0000000000003600000028000000400000001000000001002000000000000010
+      0000000000000000000000000000000000000000000000000000000000007B7B
+      00007B7B00007B7B000039312100000000005A5A10007B7B0000000000003931
+      2100000000000000000000000000000000000000000000000000000000007B7B
+      00007B7B00007B7B000029291000000000005A5A10007B7B0000000000003929
+      4A00000000000000000000000000000000000000000073733900737339007373
+      39004A4A3900000000004A4A39007373390000000000292929006B086B000000
+      00006B086B00000000006B086B00000000000000000000000000000000000000
+      000000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000BDBD0000F7F7
+      0000F7F700007B7B0000BDBD00007B7B0000BDBD00007B7B00007B7B0000217B
+      9C000000000000008400FFFFFF00000000000000000000000000BDBD0000DEDE
+      0000FFFF00007B7B0000BDBD00007B7B0000BDBD00007B7B00007B7B0000217B
+      9C0000000000000000000000000000000000B5BD0000EFEF0000EFEF00007373
+      3900B5BD000073733900B5BD0000737339007373390018737B0018737B001873
+      7B006B086B006B086B006B086B0000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00000000000000000000000000000000005A5A10000000
+      8400FFFFFF009C9C0000F7F700005A5A100042424200393121007B7B00000000
+      00000000000000000000000000000000000000000000000000005A5A1000BDBD
+      00007B7B00009C9C0000FFFF00005A5A100042424200292910007B7B00000000
+      0000000000000000000000000000000000004A4A3900B5BD000073733900B5BD
+      0000EFEF0000737339004A4A39004A4A39007373390010ADAD0010ADAD0073AD
+      AD004A4A39000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000084000000
+      840000008400FFFFFF005A5A10008484840084848400424242005A5A5A000000
+      000000008400FFFFFF0000000000000000000000000000000000000000000000
+      00005A5A1000DEDE00005A5A1000848484008484840042424200635A63000000
+      00000000000000000000000000000000000000000000000000004A4A3900EFEF
+      000073733900737339008C8C8C004A4A39004A4A390010ADAD0073ADAD00EFF7
+      EF004A4A39000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000084000000
+      840000008400FFFFFF00848484006B6B6B004242420000000000393121000000
+      8400FFFFFF000000000000000000000000000000000000000000000000000000
+      0000292910002929100084848400635A63004242420000000000292910000000
+      0000000000000000000000000000000000000000000000000000292929002929
+      290073733900737339004A4A3900000000002929290010ADAD00EFF7EF008C8C
+      8C008C8C8C00737339002929290000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
+      84000000840000008400FFFFFF00848484008484840084848400000084000000
+      8400FFFFFF000000000000000000000000000000000000000000000000000000
+      00000000000029291000635A6300848484008484840084848400848484004242
+      4200000000000000000000000000000000000000000000000000000000002929
+      29004A4A39008C8C8C008C8C8C008C8C8C008C8C8C0029292900EFF7EF00EFF7
+      EF00EFF7EF00EFF7EF00737339000000000000008400FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000000000000000000000000000000000000000000000
+      0000000084000000840000008400FFFFFF00848484000000840000008400FFFF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000042424200848484008484840084848400635A63004242
+      4200000000000000000000000000000000000000000000000000000000000000
+      00004A4A39008C8C8C00737339008C8C8C004A4A39004A4A3900EFF7EF00EFF7
+      EF00EFF7EF008C8C8C002929290000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF000000000000000000000000000000000000000000000000000000
+      0000000000002929290018737B0018737B000000000000000000000000000000
+      0000000000000000840000008400000084000000840000008400FFFFFF004242
+      4200000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000635A6300848484008484840084848400848484004242
+      4200000000000000000000000000000000000000000000000000000000000000
+      00004A4A39008C8C8C008C8C8C008C8C8C008C8C8C0029292900EFF7EF00EFF7
+      EF00EFF7EF0073ADAD008C8C8C0000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF007B7B00007B7B00007B7B0000393121000000
+      00005A5A10007B7B000000000000393121000000000000000000000000000000
+      00000000000042424200000084000000840000008400FFFFFF00848484004242
+      42006B6B6B000000000000000000000000000000000000000000000000000000
+      0000000000004242420084848400848484008484840084848400848484004242
+      42006B6B6B000000000000000000000000000000000000000000000000004A4A
+      39008C8C8C008C8C8C00737339008C8C8C008C8C8C002929290073733900EFF7
+      EF00FF7B7B00EFF7EF004A4A390000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
+      0000000000000000840000008400000084000000840000008400FFFFFF004242
+      4200000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000042424200848484008484840029291000848484004242
+      4200000000000000000000000000000000000000000000000000000000000000
+      0000292929008C8C8C008C8C8C00000000008C8C8C0029292900EFF7EF00EFF7
+      EF008C8C8C008C8C8C000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
+      0000000084000000840000008400FFFFFF008484840000008400FFFFFF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000004242420084848400635A6300000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000004A4A39008C8C8C004A4A39000000000073ADAD0018737B00EFF7
+      EF0073ADAD00EFF7EF004A4A390000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000000000000000000000000042424200000084000000
+      840000008400FFFFFF0084848400424242000000000000000000000084000000
+      84000000840000008400FFFFFF00424242008484840084848400000084000000
+      8400FFFFFF000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000424242008484840084848400292910000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000292929008C8C8C008C8C8C002929290073ADAD0010ADAD0010AD
+      AD0008F7F70010ADAD0008F7F70000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000008400000084000000
+      840000008400FFFFFF0000000000000000000000000000000000000000000000
+      840000008400FFFFFF0000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000073ADAD0063DEDE0008F7
+      F70008F7F70008F7F7002929290000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000840000008400FFFF
+      FF00000000000000000000000000000000000000000000000000000000000039
+      39000000840000008400FFFFFF00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000039
+      3900000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000002929290018737B001873
+      7B0018737B00000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00424D3E000000000000003E000000
+      2800000040000000100000000100010000000000800000000000000000000000
+      000000000000000000000000FFFFFF00E00FE00F8001FF00C009C00F00000500
+      C01FC01F00030500C013E01F80070500C007F01FC001FF00E007E00F8001FF00
+      E00FE00F8001FF00C00FC00F0000FF00C007C0070001FF00C00FC00F0001FF00
+      C01FC01F0000FF00C007C01F0000FF008003C01F0001FF008001E00F8003FF00
+      F01FF01FC07FFF00FFFFFFFFFFFF000000000000000000000000000000000000
+      000000000000}
+  end
 end

+ 17 - 3
forms/Rights.h

@@ -9,6 +9,9 @@
 #include <Buttons.hpp>
 
 #include <RemoteFiles.h>
+#include <ActnList.hpp>
+#include <ImgList.hpp>
+#include <Menus.hpp>
 //---------------------------------------------------------------------------
 class TRightsFrame : public TFrame
 {
@@ -31,13 +34,24 @@ __published:
   TSpeedButton *OthersButton;
   TLabel *OctalLabel;
   TEdit *OctalEdit;
+  TPopupMenu *RightsPopup;
+  TMenuItem *Norights1;
+  TMenuItem *Defaultrights1;
+  TMenuItem *Allrights1;
+  TMenuItem *Leaveasis1;
+  TActionList *RightsActions;
+  TAction *NoRightsAction;
+  TAction *DefaultRightsAction;
+  TAction *AllRightsAction;
+  TAction *LeaveRightsAsIsAction;
+  TImageList *RightsImages;
   void __fastcall ControlChange(TObject *Sender);
-  void __fastcall FrameContextPopup(TObject *Sender,
-    TPoint &MousePos, bool &Handled);
   void __fastcall RightsButtonsClick(TObject *Sender);
-  void __fastcall FrameEnter(TObject *Sender);
   void __fastcall OctalEditExit(TObject *Sender);
   void __fastcall OctalEditChange(TObject *Sender);
+  void __fastcall RightsActionsExecute(TBasicAction *Action,
+          bool &Handled);
+  void __fastcall RightsActionsUpdate(TBasicAction *Action, bool &Handled);
 private:
   bool FAllowAddXToDirectories;
   TNotifyEvent FOnChange;

+ 17 - 2
forms/ScpCommander.cpp

@@ -278,8 +278,16 @@ void __fastcall TScpCommanderForm::TerminalChanged()
 
       if (DocumentsDir)
       {
-        LocalDirView->HomeDirectory = "";
-        LocalDirView->ExecuteHomeDirectory();
+        try
+        {
+          LocalDirView->HomeDirectory = "";
+          LocalDirView->ExecuteHomeDirectory();
+        }
+        catch(Exception & E)
+        {
+          ShowExtendedException(&E, this);
+          LocalDirView->Path = ExtractFilePath(Application->ExeName);
+        }
       }
 
       if (Configuration->DefaultDirIsHome &&
@@ -470,6 +478,13 @@ void __fastcall TScpCommanderForm::SynchronizeStartStop(System::TObject* Sender,
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TScpCommanderForm::FullSynchronizeDirectories()
+{
+  AnsiString LocalDirectory = LocalDirView->PathName;
+  AnsiString RemoteDirectory = RemoteDirView->PathName;
+  DoFullSynchronizeDirectories(LocalDirectory, RemoteDirectory);
+}
+//---------------------------------------------------------------------------
 void __fastcall TScpCommanderForm::LocalDirViewChangeDetected(
       TObject * /*Sender*/)
 {

+ 10 - 5
forms/ScpCommander.dfm

@@ -494,7 +494,7 @@ inherited ScpCommanderForm: TScpCommanderForm
     object CommandsToolbar: TToolBar
       Left = 9
       Top = 144
-      Width = 108
+      Width = 131
       Height = 22
       Hint = '|E'
       Align = alLeft
@@ -519,9 +519,14 @@ inherited ScpCommanderForm: TScpCommanderForm
         Top = 0
         Action = NonVisualDataModule.SynchronizeAction
       end
-      object ToolButton41: TToolButton
+      object ToolButton51: TToolButton
         Left = 46
         Top = 0
+        Action = NonVisualDataModule.FullSynchronizeAction
+      end
+      object ToolButton41: TToolButton
+        Left = 69
+        Top = 0
         Width = 8
         Hint = 'E'
         Caption = 'ToolButton41'
@@ -529,12 +534,12 @@ inherited ScpCommanderForm: TScpCommanderForm
         Style = tbsSeparator
       end
       object ToolButton42: TToolButton
-        Left = 54
+        Left = 77
         Top = 0
         Action = NonVisualDataModule.ConsoleAction
       end
       object ToolButton45: TToolButton
-        Left = 77
+        Left = 100
         Top = 0
         Width = 8
         Hint = 'E'
@@ -543,7 +548,7 @@ inherited ScpCommanderForm: TScpCommanderForm
         Style = tbsSeparator
       end
       object ToolButton46: TToolButton
-        Left = 85
+        Left = 108
         Top = 0
         Action = NonVisualDataModule.SynchorizeBrowsingAction
         Style = tbsCheck

+ 2 - 0
forms/ScpCommander.h

@@ -124,6 +124,7 @@ __published:
   TToolButton *ToolButton48;
   TComboBox *SessionCombo;
   TToolButton *ToolButton49;
+  TToolButton *ToolButton51;
   void __fastcall FormShow(TObject *Sender);
   void __fastcall SplitterMoved(TObject *Sender);
   void __fastcall SplitterCanResize(TObject *Sender, int &NewSize,
@@ -189,6 +190,7 @@ public:
   virtual void __fastcall CompareDirectories();
   virtual void __fastcall UpdateSessionData(TSessionData * Data = NULL);
   virtual void __fastcall SynchronizeDirectories();
+  virtual void __fastcall FullSynchronizeDirectories();
   virtual void __fastcall StoreParams();
   virtual void __fastcall ExploreLocalDirectory();
   __property float LocalPanelWidth = { read = GetLocalPanelWidth, write = SetLocalPanelWidth };

+ 10 - 0
forms/ScpExplorer.cpp

@@ -135,6 +135,16 @@ TControl * __fastcall TScpExplorerForm::GetComponent(Byte Component)
     default: return TCustomScpExplorerForm::GetComponent(Component);
   }
 }
+//---------------------------------------------------------------------------
+void __fastcall TScpExplorerForm::FullSynchronizeDirectories()
+{
+  AnsiString LocalDirectory = WinConfiguration->ScpExplorer.LastLocalTargetDirectory;
+  AnsiString RemoteDirectory = RemoteDirView->PathName;
+  if (DoFullSynchronizeDirectories(LocalDirectory, RemoteDirectory))
+  {
+    WinConfiguration->ScpExplorer.LastLocalTargetDirectory = LocalDirectory; 
+  }
+}
 
 
 

+ 15 - 1
forms/ScpExplorer.dfm

@@ -85,6 +85,7 @@ inherited ScpExplorerForm: TScpExplorerForm
       object ToolButton42: TToolButton
         Left = 27
         Top = 0
+        Hint = 'Other commands'
         AutoSize = True
         Caption = '&Commands'
         Grouped = True
@@ -130,7 +131,7 @@ inherited ScpExplorerForm: TScpExplorerForm
     object ButtonsToolBar: TToolBar
       Left = 9
       Top = 47
-      Width = 403
+      Width = 434
       Height = 22
       Hint = '|E'
       Align = alLeft
@@ -258,6 +259,19 @@ inherited ScpExplorerForm: TScpExplorerForm
         Top = 0
         Action = NonVisualDataModule.ConsoleAction
       end
+      object ToolButton48: TToolButton
+        Left = 403
+        Top = 0
+        Width = 8
+        Caption = 'ToolButton48'
+        ImageIndex = 56
+        Style = tbsSeparator
+      end
+      object ToolButton49: TToolButton
+        Left = 411
+        Top = 0
+        Action = NonVisualDataModule.FullSynchronizeAction
+      end
     end
     object SelectionToolbar: TToolBar
       Left = 9

+ 3 - 0
forms/ScpExplorer.h

@@ -85,6 +85,8 @@ __published:
   TToolButton *ToolButton46;
   TToolButton *ToolButton47;
   TComboBox *SessionCombo;
+  TToolButton *ToolButton48;
+  TToolButton *ToolButton49;
   void __fastcall FormShow(TObject *Sender);
 private:
 protected:
@@ -100,6 +102,7 @@ public:
   __fastcall TScpExplorerForm(TComponent* Owner);
   virtual Boolean __fastcall AllowedAction(TAction * Action, TActionAllowed Allowed);
   virtual void __fastcall StoreParams();
+  virtual void __fastcall FullSynchronizeDirectories();
 };
 //---------------------------------------------------------------------------
 #endif

+ 2 - 2
forms/SelectMask.cpp

@@ -74,13 +74,13 @@ void __fastcall TSelectMaskDialog::FormCloseQuery(TObject * /*Sender*/,
 //---------------------------------------------------------------------------
 bool __fastcall TSelectMaskDialog::Execute()
 {
-  MaskEdit->Items->Text = WinConfiguration->MaskHistory;
+  MaskEdit->Items = WinConfiguration->History["Mask"];
   ActiveControl = MaskEdit;
   bool Result = (ShowModal() == mrOk);
   if (Result)
   {
     MaskEdit->SaveToHistory();
-    WinConfiguration->MaskHistory = MaskEdit->Items->Text;
+    WinConfiguration->History["Mask"] = MaskEdit->Items;
   }
   return Result;
 } /* TSelectMaskDialog::Execute */

+ 82 - 0
forms/SynchronizeProgress.cpp

@@ -0,0 +1,82 @@
+//---------------------------------------------------------------------------
+#include <vcl.h>
+#pragma hdrstop
+
+#include "SynchronizeProgress.h"
+#include <Common.h>
+#include <Configuration.h>
+#include <ScpMain.h>
+#include <TextsWin.h>
+#include <WinInterface.h>
+#include <VCLCommon.h>
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma link "PathLabel"
+#pragma resource "*.dfm"
+//---------------------------------------------------------------------------
+__fastcall TSynchronizeProgressForm::TSynchronizeProgressForm(TComponent* Owner)
+  : TForm(Owner)
+{
+  FStarted = false;
+  FCanceled = false;
+  FElapsed = EncodeTime(0, 0, 0, 0);
+  FShowAsModalStorage = NULL;
+}
+//---------------------------------------------------------------------------
+__fastcall TSynchronizeProgressForm::~TSynchronizeProgressForm()
+{
+  ReleaseAsModal(this, FShowAsModalStorage);
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeProgressForm::Start()
+{
+  FStarted = true;
+  FStartTime = Now();
+  UpdateTimer->Enabled = true;
+  StartTimeLabel->Caption = FStartTime.TimeString();
+  ShowAsModal(this, FShowAsModalStorage);
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeProgressForm::Stop()
+{
+  HideAsModal(this, FShowAsModalStorage);
+  FStarted = false;
+  UpdateTimer->Enabled = false;
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeProgressForm::SetData(const AnsiString LocalDirectory,
+  const AnsiString RemoteDirectory, bool & Continue)
+{
+  assert(FStarted);
+  LocalDirectoryLabel->Caption = LocalDirectory;
+  RemoteDirectoryLabel->Caption = RemoteDirectory;
+  Continue = !FCanceled;
+  
+  UpdateControls();
+  Application->ProcessMessages();
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeProgressForm::UpdateControls()
+{
+  if (FStarted)
+  {
+    FElapsed = Now() - FStartTime;
+  }
+  TimeElapsedLabel->Caption = FormatDateTime(Configuration->TimeFormat, FElapsed);
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeProgressForm::CancelButtonClick(TObject * /*Sender*/)
+{
+  if (!FCanceled && (MessageDialog(LoadStr(CANCEL_OPERATION), qtConfirmation,
+       qaOK | qaCancel, 0) == qaOK))
+  {
+    FCanceled = true;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeProgressForm::UpdateTimerTimer(TObject * /*Sender*/)
+{
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
+

+ 100 - 0
forms/SynchronizeProgress.dfm

@@ -0,0 +1,100 @@
+object SynchronizeProgressForm: TSynchronizeProgressForm
+  Left = 335
+  Top = 260
+  BorderStyle = bsDialog
+  Caption = 'Synchronization'
+  ClientHeight = 127
+  ClientWidth = 370
+  Color = clBtnFace
+  ParentFont = True
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  DesignSize = (
+    370
+    127)
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Label1: TLabel
+    Left = 8
+    Top = 9
+    Width = 29
+    Height = 13
+    Caption = 'Local:'
+  end
+  object Label2: TLabel
+    Left = 8
+    Top = 29
+    Width = 40
+    Height = 13
+    Caption = 'Remote:'
+  end
+  object RemoteDirectoryLabel: TPathLabel
+    Left = 88
+    Top = 29
+    Width = 273
+    Height = 13
+    UnixPath = True
+    IndentHorizontal = 0
+    IndentVertical = 0
+    Align = alNone
+    Anchors = [akLeft, akTop, akRight]
+    AutoSize = False
+  end
+  object LocalDirectoryLabel: TPathLabel
+    Left = 88
+    Top = 9
+    Width = 273
+    Height = 13
+    IndentHorizontal = 0
+    IndentVertical = 0
+    Align = alNone
+    Anchors = [akLeft, akTop, akRight]
+    AutoSize = False
+  end
+  object StartTimeLabel: TLabel
+    Left = 88
+    Top = 49
+    Width = 81
+    Height = 13
+    AutoSize = False
+    Caption = '00:00:00'
+  end
+  object Label4: TLabel
+    Left = 8
+    Top = 49
+    Width = 47
+    Height = 13
+    Caption = 'Start time:'
+  end
+  object Label3: TLabel
+    Left = 8
+    Top = 69
+    Width = 66
+    Height = 13
+    Caption = 'Time elapsed:'
+  end
+  object TimeElapsedLabel: TLabel
+    Left = 88
+    Top = 69
+    Width = 79
+    Height = 13
+    AutoSize = False
+    Caption = '00:00:00'
+  end
+  object CancelButton: TButton
+    Left = 149
+    Top = 93
+    Width = 73
+    Height = 25
+    Anchors = [akLeft, akBottom]
+    Caption = 'Cancel'
+    TabOrder = 0
+    OnClick = CancelButtonClick
+  end
+  object UpdateTimer: TTimer
+    Enabled = False
+    OnTimer = UpdateTimerTimer
+    Left = 41
+    Top = 89
+  end
+end

+ 47 - 0
forms/SynchronizeProgress.h

@@ -0,0 +1,47 @@
+//---------------------------------------------------------------------------
+#ifndef SynchronizeProgressH
+#define SynchronizeProgressH
+//---------------------------------------------------------------------------
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include "PathLabel.hpp"
+#include <ExtCtrls.hpp>
+//---------------------------------------------------------------------------
+class TSynchronizeProgressForm : public TForm
+{
+__published:
+  TLabel *Label1;
+  TLabel *Label2;
+  TPathLabel *RemoteDirectoryLabel;
+  TPathLabel *LocalDirectoryLabel;
+  TLabel *StartTimeLabel;
+  TLabel *Label4;
+  TLabel *Label3;
+  TLabel *TimeElapsedLabel;
+  TButton *CancelButton;
+  TTimer *UpdateTimer;
+  void __fastcall CancelButtonClick(TObject *Sender);
+  void __fastcall UpdateTimerTimer(TObject *Sender);
+
+public:
+  __fastcall TSynchronizeProgressForm(TComponent* Owner);
+  virtual __fastcall ~TSynchronizeProgressForm();
+
+  void __fastcall Start();
+  void __fastcall Stop();
+  void __fastcall SetData(const AnsiString LocalDirectory,
+    const AnsiString RemoteDirectory, bool & Continue);
+
+private:
+  TDateTime FStartTime;
+  TDateTime FElapsed;
+  bool FStarted;
+  bool FCanceled;
+  void * FShowAsModalStorage;
+
+  void __fastcall UpdateControls();
+};
+//---------------------------------------------------------------------------
+#endif

+ 3 - 3
general/DragDrop_B5.bpk

@@ -35,7 +35,7 @@
     <RELEASELIBPATH value="$(BCB)\lib\release"/>
     <LINKER value="ilink32"/>
     <USERDEFINES value=""/>
-    <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+    <SYSDEFINES value="NO_STRICT;USEPACKAGES"/>
     <MAINSOURCE value="DragDrop_B5.cpp"/>
     <INCLUDEPATH value="&quot;Drag and Drop Components&quot;;$(BCB)\include;$(BCB)\include\vcl"/>
     <LIBPATH value="..\lib\;&quot;Drag and Drop Components&quot;;$(BCB)\lib\obj;$(BCB)\lib"/>
@@ -52,9 +52,9 @@
     <OTHERFILES value=""/>
   </OPTIONS>
   <LINKER>
-    <ALLOBJ value="c0pkg32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+    <ALLOBJ value="c0pkg32.obj $(PACKAGES) sysinit.obj $(OBJFILES)"/>
     <ALLRES value="$(RESFILES)"/>
-    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib"/>
     <OTHERFILES value=""/>
   </LINKER>
   <FILELIST>

+ 3 - 3
general/DriveDir_B5.bpk

@@ -39,7 +39,7 @@
     <RELEASELIBPATH value="$(BCB)\lib\release"/>
     <LINKER value="ilink32"/>
     <USERDEFINES value="OLD_DND;NORTON_LIKE"/>
-    <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+    <SYSDEFINES value="NO_STRICT;USEPACKAGES"/>
     <MAINSOURCE value="DriveDir_B5.cpp"/>
     <INCLUDEPATH value="&quot;Moje komponenty\TNortonLikeListView&quot;;&quot;Filemanager Toolset&quot;;&quot;Drag and Drop Components&quot;;&quot;Moje komponenty&quot;;&quot;Moje komponenty\Filemanager Toolset&quot;;$(BCB)\include;$(BCB)\include\vcl"/>
     <LIBPATH value="..\lib\;;&quot;Moje komponenty\TNortonLikeListView&quot;;&quot;Filemanager Toolset&quot;;&quot;Drag and Drop Components&quot;;&quot;Moje komponenty&quot;;&quot;Moje komponenty\Filemanager Toolset&quot;;$(BCB)\lib\obj;$(BCB)\lib;$(BCB)\Source\ToolsAPI"/>
@@ -56,9 +56,9 @@
     <OTHERFILES value=""/>
   </OPTIONS>
   <LINKER>
-    <ALLOBJ value="c0pkg32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+    <ALLOBJ value="c0pkg32.obj $(PACKAGES) sysinit.obj $(OBJFILES)"/>
     <ALLRES value="$(RESFILES)"/>
-    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib"/>
     <OTHERFILES value=""/>
   </LINKER>
   <FILELIST>

+ 3 - 3
general/Moje_B5.bpk

@@ -35,7 +35,7 @@
     <RELEASELIBPATH value="$(BCB)\lib\release"/>
     <LINKER value="ilink32"/>
     <USERDEFINES value=""/>
-    <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+    <SYSDEFINES value="NO_STRICT;USEPACKAGES"/>
     <MAINSOURCE value="Moje_B5.cpp"/>
     <INCLUDEPATH value="&quot;Moje komponenty&quot;;$(BCB)\include;$(BCB)\include\vcl"/>
     <LIBPATH value="..\lib\;&quot;Moje komponenty&quot;;$(BCB)\lib\obj;$(BCB)\lib;$(BCB)\Source\ToolsAPI"/>
@@ -52,9 +52,9 @@
     <OTHERFILES value=""/>
   </OPTIONS>
   <LINKER>
-    <ALLOBJ value="c0pkg32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+    <ALLOBJ value="c0pkg32.obj $(PACKAGES) sysinit.obj $(OBJFILES)"/>
     <ALLRES value="$(RESFILES)"/>
-    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib"/>
     <OTHERFILES value=""/>
   </LINKER>
   <FILELIST>

+ 11 - 8
general/filemanager toolset/BaseUtils.pas

@@ -307,15 +307,18 @@ var
   Y2, M2, D2, H2, N2, S2, MS2: Word;
   Changed: Boolean;
 begin
-  DecodeDateTime(DateTime1, Y1, M1, D1, H1, N1, S1, MS1);
-  DecodeDateTime(DateTime2, Y2, M2, D2, H2, N2, S2, MS2);
-  Changed := Unify(MS1, MS2);
-  if Changed and Unify(S1, S2) and Unify(N1, N2) and Unify(H1, H2) and
-     Unify(D1, D2) and Unify(M1, M2) then Unify(Y1, Y2);
-  if Changed then
+  if DateTime1 <> DateTime2 then
   begin
-    DateTime1 := EncodeDate(Y1, M1, D1) + EncodeTime(H1, N1, S1, MS1);
-    DateTime2 := EncodeDate(Y2, M2, D2) + EncodeTime(H2, N2, S2, MS2);
+    DecodeDateTime(DateTime1, Y1, M1, D1, H1, N1, S1, MS1);
+    DecodeDateTime(DateTime2, Y2, M2, D2, H2, N2, S2, MS2);
+    Changed := Unify(MS1, MS2);
+    if Changed and Unify(S1, S2) and Unify(N1, N2) and Unify(H1, H2) and
+       Unify(D1, D2) and Unify(M1, M2) then Unify(Y1, Y2);
+    if Changed then
+    begin
+      DateTime1 := EncodeDate(Y1, M1, D1) + EncodeTime(H1, N1, S1, MS1);
+      DateTime2 := EncodeDate(Y2, M2, D2) + EncodeTime(H2, N2, S2, MS2);
+    end;
   end;
 end;
 

+ 2 - 6
general/moje komponenty/filemanager toolset/CustomDirView.pas

@@ -2,6 +2,8 @@ unit CustomDirView;
 
 interface
 
+{$R DirImg.res}
+
 {$WARN UNIT_PLATFORM OFF}
 
 uses
@@ -473,14 +475,8 @@ uses
 const
   Space = ' ';
   ResDirUp = 'DIRUP%2.2d';
-  ResDirUp16 = 'DIRUP16';
-  ResDirUp32 = 'DIRUP32';
   ResLink = 'LINK%2.2d';
-  ResLink16 = 'LINK16';
-  ResLink32 = 'LINK32';
   ResBrokenLink = 'BROKEN%2.2d';
-  ResBrokenLink16 = 'BROKEN16';
-  ResBrokenLink32 = 'BROKEN32';
 
 var
   WinDir: string;

+ 8 - 0
putty/CMDLINE.C

@@ -51,6 +51,14 @@ static void cmdline_save_param(char *p, char *value, int pri)
     saves[pri].nsaved++;
 }
 
+void cmdline_cleanup(void)
+{
+    int pri;
+
+    for (pri = 0; pri < NPRIORITIES; pri++)
+	sfree(saves[pri].params);
+}
+
 #define SAVEABLE(pri) do { \
     if (need_save) { cmdline_save_param(p, value, pri); return ret; } \
 } while (0)

+ 5 - 8
putty/CONFIG.C

@@ -1149,7 +1149,7 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
 		  'r', 100, HELPCTX(translation_codepage),
 		  codepage_handler, P(NULL), P(NULL));
 
-    str = dupprintf("Adjust how %s displays line drawing characters", appname);
+    str = dupprintf("Adjust how %s handles line drawing characters", appname);
     s = ctrl_getset(b, "Window/Translation", "linedraw", str);
     sfree(str);
     ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
@@ -1159,17 +1159,14 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
 		      "Use Unicode line drawing code points",'u',I(VT_UNICODE),
 		      "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
 		      NULL);
+    ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
+		  HELPCTX(selection_linedraw),
+		  dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
 
     /*
      * The Window/Selection panel.
      */
     ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
-
-    s = ctrl_getset(b, "Window/Selection", "trans",
-		    "Translation of pasted characters");
-    ctrl_checkbox(s, "Paste VT100 line drawing chars as lqqqk",'d',
-		  HELPCTX(selection_linedraw),
-		  dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
 	
     s = ctrl_getset(b, "Window/Selection", "mouse",
 		    "Control use of mouse");
@@ -1494,7 +1491,7 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
 			  cipherlist_handler, P(NULL));
 	c->listbox.height = 6;
 	
-	ctrl_checkbox(s, "Enable non-standard use of single-DES in SSH 2", 'i',
+	ctrl_checkbox(s, "Enable legacy use of single-DES in SSH 2", 'i',
 		      HELPCTX(ssh_ciphers),
 		      dlg_stdcheckbox_handler,
 		      I(offsetof(Config,ssh2_des_cbc)));

Some files were not shown because too many files changed in this diff