Martin Prikryl 20 years ago
parent
commit
cb93661770
100 changed files with 5822 additions and 2110 deletions
  1. 4 4
      Console.bpr
  2. BIN
      Console.res
  3. 4 4
      DragExt.bpr
  4. BIN
      DragExt.res
  5. 3 2
      ScpForms.bpf
  6. 24 22
      ScpForms.bpr
  7. 6 6
      WinSCP3.bpr
  8. 94 92
      WinSCP3.drc
  9. BIN
      WinSCP3.res
  10. 32 8
      components/UnixDirView.cpp
  11. 4 0
      components/UnixDirView.h
  12. 11 2
      console/Main.cpp
  13. 41 3
      core/Common.cpp
  14. 4 0
      core/Common.h
  15. 50 20
      core/Configuration.cpp
  16. 19 3
      core/Configuration.h
  17. 96 59
      core/CopyParam.cpp
  18. 18 2
      core/CopyParam.h
  19. 16 2
      core/FileMasks.cpp
  20. 2 0
      core/FileMasks.h
  21. 18 2
      core/FileOperationProgress.cpp
  22. 4 1
      core/FileOperationProgress.h
  23. 4 0
      core/FileSystems.h
  24. 4 4
      core/HierarchicalStorage.cpp
  25. 3 3
      core/HierarchicalStorage.h
  26. 2 0
      core/Interface.h
  27. 4 2
      core/Net.cpp
  28. 3 3
      core/PuttyIntf.c
  29. 2 2
      core/PuttyIntf.h
  30. 103 30
      core/Queue.cpp
  31. 106 32
      core/RemoteFiles.cpp
  32. 14 2
      core/RemoteFiles.h
  33. 41 22
      core/ScpFileSystem.cpp
  34. 3 0
      core/ScpFileSystem.h
  35. 5 2
      core/ScpMain.cpp
  36. 67 36
      core/Script.cpp
  37. 3 4
      core/Script.h
  38. 278 74
      core/SecureShell.cpp
  39. 24 10
      core/SecureShell.h
  40. 64 8
      core/SessionData.cpp
  41. 5 2
      core/SessionData.h
  42. 448 131
      core/SftpFileSystem.cpp
  43. 15 1
      core/SftpFileSystem.h
  44. 601 217
      core/Terminal.cpp
  45. 109 24
      core/Terminal.h
  46. 1 1
      dragext/DragExt.cpp
  47. 63 23
      forms/About.cpp
  48. 86 31
      forms/About.dfm
  49. 9 7
      forms/About.h
  50. 302 0
      forms/Authenticate.cpp
  51. 210 0
      forms/Authenticate.dfm
  52. 66 0
      forms/Authenticate.h
  53. 0 54
      forms/Banner.cpp
  54. 0 64
      forms/Banner.dfm
  55. 0 28
      forms/Banner.h
  56. 92 11
      forms/Console.cpp
  57. 189 4
      forms/Console.dfm
  58. 20 1
      forms/Console.h
  59. 22 15
      forms/Copy.cpp
  60. 14 1
      forms/Copy.dfm
  61. 4 0
      forms/Copy.h
  62. 7 8
      forms/CopyParamCustom.cpp
  63. 0 3
      forms/CopyParamCustom.dfm
  64. 0 2
      forms/CopyParamPreset.cpp
  65. 0 3
      forms/CopyParamPreset.dfm
  66. 121 31
      forms/CopyParams.cpp
  67. 26 8
      forms/CopyParams.dfm
  68. 14 12
      forms/CopyParams.h
  69. 128 0
      forms/CreateDirectory.cpp
  70. 133 0
      forms/CreateDirectory.dfm
  71. 52 0
      forms/CreateDirectory.h
  72. 434 119
      forms/CustomScpExplorer.cpp
  73. 4 1
      forms/CustomScpExplorer.dfm
  74. 28 10
      forms/CustomScpExplorer.h
  75. 5 4
      forms/Editor.cpp
  76. 5 0
      forms/Editor.dfm
  77. 2 0
      forms/Editor.h
  78. 9 45
      forms/EditorPreferences.cpp
  79. 1 1
      forms/EditorPreferences.dfm
  80. 0 1
      forms/EditorPreferences.h
  81. 243 35
      forms/FileSystemInfo.cpp
  82. 227 315
      forms/FileSystemInfo.dfm
  83. 45 33
      forms/FileSystemInfo.h
  84. 36 13
      forms/FullSynchronize.cpp
  85. 1 1
      forms/FullSynchronize.dfm
  86. 4 0
      forms/FullSynchronize.h
  87. 182 50
      forms/Glyphs.dfm
  88. 12 10
      forms/Licence.cpp
  89. 3 2
      forms/Log.cpp
  90. 6 2
      forms/LogSettings.cpp
  91. 75 17
      forms/Login.cpp
  92. 207 21
      forms/Login.dfm
  93. 13 3
      forms/Login.h
  94. 24 7
      forms/MessageDlg.cpp
  95. 151 45
      forms/NonVisual.cpp
  96. 133 9
      forms/NonVisual.dfm
  97. 54 24
      forms/NonVisual.h
  98. 1 39
      forms/OperationStatus.cpp
  99. 0 7
      forms/OperationStatus.h
  100. 0 148
      forms/Password.cpp

+ 4 - 4
Console.bpr

@@ -55,8 +55,8 @@ IncludeVerInfo=1
 AutoIncBuild=1
 MajorVer=1
 MinorVer=3
-Release=0
-Build=61
+Release=1
+Build=63
 Debug=0
 PreRelease=0
 Special=0
@@ -68,13 +68,13 @@ CodePage=1252
 [Version Info Keys]
 CompanyName=Martin Prikryl
 FileDescription=Console interface for WinSCP
-FileVersion=1.3.0.61
+FileVersion=1.3.1.63
 InternalName=console
 LegalCopyright=(c) 2004-2005 Martin Prikryl
 LegalTrademarks=
 OriginalFilename=winscp3.com
 ProductName=WinSCP
-ProductVersion=3.7.6.0
+ProductVersion=3.8.0.0
 Comments=
 
 [Compiler]

BIN
Console.res


+ 4 - 4
DragExt.bpr

@@ -56,8 +56,8 @@ IncludeVerInfo=1
 AutoIncBuild=1
 MajorVer=1
 MinorVer=1
-Release=4
-Build=63
+Release=5
+Build=65
 Debug=0
 PreRelease=0
 Special=0
@@ -69,13 +69,13 @@ CodePage=1252
 [Version Info Keys]
 CompanyName=Martin Prikryl
 FileDescription=Drag&Drop shell extension for WinSCP
-FileVersion=1.1.4.63
+FileVersion=1.1.5.65
 InternalName=dragext
 LegalCopyright=(c) 2004-2005 Martin Prikryl
 LegalTrademarks=
 OriginalFilename=dragext.dll
 ProductName=WinSCP
-ProductVersion=3.7.6.0
+ProductVersion=3.8.0.0
 Comments=
 WWW=http://winscp.net/
 

BIN
DragExt.res


+ 3 - 2
ScpForms.bpf

@@ -3,7 +3,7 @@
 #include <vcl.h>
 #pragma hdrstop
 USEFORM("forms\About.cpp", AboutDialog);
-USEFORM("forms\Banner.cpp", BannerDialog);
+USEFORM("forms\Authenticate.cpp", AuthenticateForm);
 USEFORM("forms\Cleanup.cpp", CleanupDialog);
 USEFORM("forms\ComboInput.cpp", ComboInputDialog);
 USEFORM("forms\Console.cpp", ConsoleDialog);
@@ -11,6 +11,7 @@ USEFORM("forms\Copy.cpp", CopyDialog);
 USEFORM("forms\CopyParams.cpp", CopyParamsFrame); /* TFrame: File Type */
 USEFORM("forms\CopyParamCustom.cpp", CopyParamCustomDialog);
 USEFORM("forms\CopyParamPreset.cpp", CopyParamPresetDialog);
+USEFORM("forms\CreateDirectory.cpp", CreateDirectoryDialog);
 USEFORM("forms\CustomCommand.cpp", CustomCommandDialog);
 USEFORM("forms\Editor.cpp", EditorForm);
 USEFORM("forms\EditorPreferences.cpp", EditorPreferencesDialog);
@@ -26,7 +27,6 @@ USEFORM("forms\Login.cpp", LoginDialog);
 USEFORM("forms\LogSettings.cpp", LoggingFrame); /* TFrame: File Type */
 USEFORM("forms\OpenDirectory.cpp", OpenDirectoryDialog);
 USEFORM("forms\OperationStatus.cpp", OperationStatusForm);
-USEFORM("forms\Password.cpp", PasswordDialog);
 USEFORM("forms\Preferences.cpp", PreferencesDialog);
 USEFORM("forms\Progress.cpp", ProgressForm);
 USEFORM("forms\Properties.cpp", PropertiesDialog);
@@ -35,6 +35,7 @@ USEFORM("forms\RightsExt.cpp", RightsExtFrame); /* TFrame: File Type */
 USEFORM("forms\SelectMask.cpp", SelectMaskDialog);
 USEFORM("forms\Symlink.cpp", SymlinkDialog);
 USEFORM("forms\Synchronize.cpp", SynchronizeDialog);
+USEFORM("forms\SynchronizeChecklist.cpp", SynchronizeChecklistDialog);
 USEFORM("forms\SynchronizeProgress.cpp", SynchronizeProgressForm);
 //---------------------------------------------------------------------------
 #define Library

+ 24 - 22
ScpForms.bpr

@@ -5,32 +5,33 @@
     <VERSION value="BCB.06.00"/>
     <PROJECT value="lib\ScpForms.lib"/>
     <OBJFILES value="forms\InputDlg.obj forms\MessageDlg.obj windows\VCLCommon.obj 
-      forms\About.obj forms\Banner.obj forms\Cleanup.obj 
+      forms\About.obj forms\Authenticate.obj forms\Cleanup.obj 
       forms\ComboInput.obj forms\Console.obj forms\Copy.obj 
       forms\CopyParams.obj forms\CopyParamCustom.obj 
-      forms\CopyParamPreset.obj forms\CustomCommand.obj forms\Editor.obj 
-      forms\EditorPreferences.obj forms\FileSystemInfo.obj 
-      forms\FullSynchronize.obj forms\GeneralSettings.obj forms\Glyphs.obj 
-      forms\ImportSessions.obj forms\Licence.obj 
-      forms\LocationProfiles.obj forms\Log.obj forms\Login.obj 
-      forms\LogSettings.obj forms\OpenDirectory.obj 
-      forms\OperationStatus.obj forms\Password.obj forms\Preferences.obj 
-      forms\Progress.obj forms\Properties.obj forms\Rights.obj 
-      forms\RightsExt.obj forms\SelectMask.obj forms\Symlink.obj 
-      forms\Synchronize.obj forms\SynchronizeProgress.obj"/>
+      forms\CopyParamPreset.obj forms\CreateDirectory.obj 
+      forms\CustomCommand.obj forms\Editor.obj forms\EditorPreferences.obj 
+      forms\FileSystemInfo.obj forms\FullSynchronize.obj 
+      forms\GeneralSettings.obj forms\Glyphs.obj forms\ImportSessions.obj 
+      forms\Licence.obj forms\LocationProfiles.obj forms\Log.obj 
+      forms\Login.obj forms\LogSettings.obj forms\OpenDirectory.obj 
+      forms\OperationStatus.obj forms\Preferences.obj forms\Progress.obj 
+      forms\Properties.obj forms\Rights.obj forms\RightsExt.obj 
+      forms\SelectMask.obj forms\Symlink.obj forms\Synchronize.obj 
+      forms\SynchronizeChecklist.obj forms\SynchronizeProgress.obj"/>
     <RESFILES value=""/>
     <DEFFILE value=""/>
-    <RESDEPEN value="$(RESFILES) forms\About.dfm forms\Banner.dfm forms\Cleanup.dfm 
+    <RESDEPEN value="$(RESFILES) forms\About.dfm forms\Authenticate.dfm forms\Cleanup.dfm 
       forms\ComboInput.dfm forms\Console.dfm forms\Copy.dfm forms\CopyParams.dfm 
       forms\CopyParamCustom.dfm forms\CopyParamPreset.dfm 
-      forms\CustomCommand.dfm forms\Editor.dfm forms\EditorPreferences.dfm 
-      forms\FileSystemInfo.dfm forms\FullSynchronize.dfm 
-      forms\GeneralSettings.dfm forms\Glyphs.dfm forms\ImportSessions.dfm 
-      forms\Licence.dfm forms\LocationProfiles.dfm forms\Log.dfm forms\Login.dfm 
-      forms\LogSettings.dfm forms\OpenDirectory.dfm forms\OperationStatus.dfm 
-      forms\Password.dfm forms\Preferences.dfm forms\Progress.dfm 
-      forms\Properties.dfm forms\Rights.dfm forms\RightsExt.dfm 
-      forms\SelectMask.dfm forms\Symlink.dfm forms\Synchronize.dfm 
+      forms\CreateDirectory.dfm forms\CustomCommand.dfm forms\Editor.dfm 
+      forms\EditorPreferences.dfm forms\FileSystemInfo.dfm 
+      forms\FullSynchronize.dfm forms\GeneralSettings.dfm forms\Glyphs.dfm 
+      forms\ImportSessions.dfm forms\Licence.dfm forms\LocationProfiles.dfm 
+      forms\Log.dfm forms\Login.dfm forms\LogSettings.dfm 
+      forms\OpenDirectory.dfm forms\OperationStatus.dfm forms\Preferences.dfm 
+      forms\Progress.dfm forms\Properties.dfm forms\Rights.dfm 
+      forms\RightsExt.dfm forms\SelectMask.dfm forms\Symlink.dfm 
+      forms\Synchronize.dfm forms\SynchronizeChecklist.dfm 
       forms\SynchronizeProgress.dfm"/>
     <LIBFILES value=""/>
     <LIBRARIES value=""/>
@@ -71,7 +72,7 @@
       <FILE FILENAME="forms\MessageDlg.cpp" FORMNAME="" UNITNAME="MessageDlg" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="windows\VCLCommon.cpp" FORMNAME="" UNITNAME="VCLCommon" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\About.cpp" FORMNAME="AboutDialog" UNITNAME="About" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="forms\Banner.cpp" FORMNAME="BannerDialog" UNITNAME="Banner" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="forms\Authenticate.cpp" FORMNAME="AuthenticateForm" UNITNAME="Authenticate" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Cleanup.cpp" FORMNAME="CleanupDialog" UNITNAME="Cleanup" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\ComboInput.cpp" FORMNAME="ComboInputDialog" UNITNAME="ComboInput" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Console.cpp" FORMNAME="ConsoleDialog" UNITNAME="Console" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
@@ -79,6 +80,7 @@
       <FILE FILENAME="forms\CopyParams.cpp" FORMNAME="CopyParamsFrame" UNITNAME="CopyParams" CONTAINERID="CCompiler" DESIGNCLASS="TFrame" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\CopyParamCustom.cpp" FORMNAME="CopyParamCustomDialog" UNITNAME="CopyParamCustom" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\CopyParamPreset.cpp" FORMNAME="CopyParamPresetDialog" UNITNAME="CopyParamPreset" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="forms\CreateDirectory.cpp" FORMNAME="CreateDirectoryDialog" UNITNAME="CreateDirectory" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\CustomCommand.cpp" FORMNAME="CustomCommandDialog" UNITNAME="CustomCommand" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Editor.cpp" FORMNAME="EditorForm" UNITNAME="Editor" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\EditorPreferences.cpp" FORMNAME="EditorPreferencesDialog" UNITNAME="EditorPreferences" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
@@ -94,7 +96,6 @@
       <FILE FILENAME="forms\LogSettings.cpp" FORMNAME="LoggingFrame" UNITNAME="LogSettings" CONTAINERID="CCompiler" DESIGNCLASS="TFrame" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\OpenDirectory.cpp" FORMNAME="OpenDirectoryDialog" UNITNAME="OpenDirectory" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\OperationStatus.cpp" FORMNAME="OperationStatusForm" UNITNAME="OperationStatus" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="forms\Password.cpp" FORMNAME="PasswordDialog" UNITNAME="Password" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Preferences.cpp" FORMNAME="PreferencesDialog" UNITNAME="Preferences" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Progress.cpp" FORMNAME="ProgressForm" UNITNAME="Progress" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Properties.cpp" FORMNAME="PropertiesDialog" UNITNAME="Properties" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
@@ -103,6 +104,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\SynchronizeChecklist.cpp" FORMNAME="SynchronizeChecklistDialog" UNITNAME="SynchronizeChecklist" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\SynchronizeProgress.cpp" FORMNAME="SynchronizeProgressForm" UNITNAME="SynchronizeProgress" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
   </FILELIST>
   <BUILDTOOLS>

+ 6 - 6
WinSCP3.bpr

@@ -93,9 +93,9 @@
 IncludeVerInfo=1
 AutoIncBuild=1
 MajorVer=3
-MinorVer=7
-Release=6
-Build=305
+MinorVer=8
+Release=0
+Build=312
 Debug=0
 PreRelease=0
 Special=0
@@ -107,13 +107,13 @@ CodePage=1252
 [Version Info Keys]
 CompanyName=Martin Prikryl
 FileDescription=Windows SFTP/SCP client
-FileVersion=3.7.6.305
+FileVersion=3.8.0.312
 InternalName=winscp3
 LegalCopyright=(c) 2000-2005 Martin Prikryl
 LegalTrademarks=
-OriginalFilename=winscp376.exe
+OriginalFilename=winscp380.exe
 ProductName=WinSCP
-ProductVersion=3.7.6.0
+ProductVersion=3.8.0.0
 WWW=http://winscp.net/
 
 [Compiler]

+ 94 - 92
WinSCP3.drc

@@ -7,94 +7,95 @@
   produced executable.
 */
 
-#define Consts_SDockedCtlNeedsName 65200
-#define Consts_SDockTreeRemoveError 65201
-#define Consts_SDockZoneNotFound 65202
-#define Consts_SDockZoneHasNoCtl 65203
-#define Consts_SMultiSelectRequired 65204
-#define Consts_SSeparator 65205
-#define Consts_SErrorSettingCount 65206
-#define Consts_SListBoxMustBeVirtual 65207
-#define Consts_SmkcCtrl 65216
-#define Consts_SmkcAlt 65217
-#define Consts_srNone 65218
-#define Consts_SOutOfRange 65219
-#define Consts_sAllFilter 65220
-#define Consts_SInsertLineError 65221
-#define Consts_SInvalidClipFmt 65222
-#define Consts_SIconToClipboard 65223
-#define Consts_SCannotOpenClipboard 65224
-#define Consts_SInvalidMemoSize 65225
-#define Consts_SNoDefaultPrinter 65226
-#define Consts_SDuplicateMenus 65227
-#define Consts_SPictureLabel 65228
-#define Consts_SPictureDesc 65229
-#define Consts_SPreviewLabel 65230
-#define Consts_SCannotOpenAVI 65231
-#define Consts_SmkcBkSp 65232
-#define Consts_SmkcTab 65233
-#define Consts_SmkcEsc 65234
-#define Consts_SmkcEnter 65235
-#define Consts_SmkcSpace 65236
-#define Consts_SmkcPgUp 65237
-#define Consts_SmkcPgDn 65238
-#define Consts_SmkcEnd 65239
-#define Consts_SmkcHome 65240
-#define Consts_SmkcLeft 65241
-#define Consts_SmkcUp 65242
-#define Consts_SmkcRight 65243
-#define Consts_SmkcDown 65244
-#define Consts_SmkcIns 65245
-#define Consts_SmkcDel 65246
-#define Consts_SmkcShift 65247
-#define Consts_SMaskEditErr 65248
-#define Consts_SMsgDlgWarning 65249
-#define Consts_SMsgDlgError 65250
-#define Consts_SMsgDlgInformation 65251
-#define Consts_SMsgDlgConfirm 65252
-#define Consts_SMsgDlgYes 65253
-#define Consts_SMsgDlgNo 65254
-#define Consts_SMsgDlgOK 65255
-#define Consts_SMsgDlgCancel 65256
-#define Consts_SMsgDlgHelp 65257
-#define Consts_SMsgDlgAbort 65258
-#define Consts_SMsgDlgRetry 65259
-#define Consts_SMsgDlgIgnore 65260
-#define Consts_SMsgDlgAll 65261
-#define Consts_SMsgDlgNoToAll 65262
-#define Consts_SMsgDlgYesToAll 65263
-#define Consts_SOKButton 65264
-#define Consts_SCancelButton 65265
-#define Consts_SYesButton 65266
-#define Consts_SNoButton 65267
-#define Consts_SHelpButton 65268
-#define Consts_SCloseButton 65269
-#define Consts_SIgnoreButton 65270
-#define Consts_SRetryButton 65271
-#define Consts_SAbortButton 65272
-#define Consts_SAllButton 65273
-#define Consts_SCannotDragForm 65274
-#define Consts_SVMetafiles 65275
-#define Consts_SVEnhMetafiles 65276
-#define Consts_SVIcons 65277
-#define Consts_SVBitmaps 65278
-#define Consts_SMaskErr 65279
+#define Consts_SCannotOpenAVI 65200
+#define Consts_SDockedCtlNeedsName 65201
+#define Consts_SDockTreeRemoveError 65202
+#define Consts_SDockZoneNotFound 65203
+#define Consts_SDockZoneHasNoCtl 65204
+#define Consts_SMultiSelectRequired 65205
+#define Consts_SSeparator 65206
+#define Consts_SErrorSettingCount 65207
+#define Consts_SListBoxMustBeVirtual 65208
+#define Consts_SmkcShift 65216
+#define Consts_SmkcCtrl 65217
+#define Consts_SmkcAlt 65218
+#define Consts_srNone 65219
+#define Consts_SOutOfRange 65220
+#define Consts_sAllFilter 65221
+#define Consts_SInsertLineError 65222
+#define Consts_SInvalidClipFmt 65223
+#define Consts_SIconToClipboard 65224
+#define Consts_SCannotOpenClipboard 65225
+#define Consts_SInvalidMemoSize 65226
+#define Consts_SNoDefaultPrinter 65227
+#define Consts_SDuplicateMenus 65228
+#define Consts_SPictureLabel 65229
+#define Consts_SPictureDesc 65230
+#define Consts_SPreviewLabel 65231
+#define Consts_SMsgDlgYesToAll 65232
+#define Consts_SmkcBkSp 65233
+#define Consts_SmkcTab 65234
+#define Consts_SmkcEsc 65235
+#define Consts_SmkcEnter 65236
+#define Consts_SmkcSpace 65237
+#define Consts_SmkcPgUp 65238
+#define Consts_SmkcPgDn 65239
+#define Consts_SmkcEnd 65240
+#define Consts_SmkcHome 65241
+#define Consts_SmkcLeft 65242
+#define Consts_SmkcUp 65243
+#define Consts_SmkcRight 65244
+#define Consts_SmkcDown 65245
+#define Consts_SmkcIns 65246
+#define Consts_SmkcDel 65247
+#define Consts_SMaskErr 65248
+#define Consts_SMaskEditErr 65249
+#define Consts_SMsgDlgWarning 65250
+#define Consts_SMsgDlgError 65251
+#define Consts_SMsgDlgInformation 65252
+#define Consts_SMsgDlgConfirm 65253
+#define Consts_SMsgDlgYes 65254
+#define Consts_SMsgDlgNo 65255
+#define Consts_SMsgDlgOK 65256
+#define Consts_SMsgDlgCancel 65257
+#define Consts_SMsgDlgHelp 65258
+#define Consts_SMsgDlgAbort 65259
+#define Consts_SMsgDlgRetry 65260
+#define Consts_SMsgDlgIgnore 65261
+#define Consts_SMsgDlgAll 65262
+#define Consts_SMsgDlgNoToAll 65263
+#define Consts_SControlParentSetToSelf 65264
+#define Consts_SOKButton 65265
+#define Consts_SCancelButton 65266
+#define Consts_SYesButton 65267
+#define Consts_SNoButton 65268
+#define Consts_SHelpButton 65269
+#define Consts_SCloseButton 65270
+#define Consts_SIgnoreButton 65271
+#define Consts_SRetryButton 65272
+#define Consts_SAbortButton 65273
+#define Consts_SAllButton 65274
+#define Consts_SCannotDragForm 65275
+#define Consts_SVMetafiles 65276
+#define Consts_SVEnhMetafiles 65277
+#define Consts_SVIcons 65278
+#define Consts_SVBitmaps 65279
 #define Consts_SParentRequired 65280
-#define Consts_SMDIChildNotVisible 65281
-#define Consts_SVisibleChanged 65282
-#define Consts_SCannotShowModal 65283
-#define Consts_SPropertyOutOfRange 65284
-#define Consts_SMenuIndexError 65285
-#define Consts_SMenuReinserted 65286
-#define Consts_SMenuNotFound 65287
-#define Consts_SNoTimers 65288
-#define Consts_SNotPrinting 65289
-#define Consts_SPrinting 65290
-#define Consts_SInvalidPrinter 65291
-#define Consts_SDeviceOnPort 65292
-#define Consts_SGroupIndexTooLow 65293
-#define Consts_SNoMDIForm 65294
-#define Consts_SControlParentSetToSelf 65295
+#define Consts_SParentGivenNotAParent 65281
+#define Consts_SMDIChildNotVisible 65282
+#define Consts_SVisibleChanged 65283
+#define Consts_SCannotShowModal 65284
+#define Consts_SPropertyOutOfRange 65285
+#define Consts_SMenuIndexError 65286
+#define Consts_SMenuReinserted 65287
+#define Consts_SMenuNotFound 65288
+#define Consts_SNoTimers 65289
+#define Consts_SNotPrinting 65290
+#define Consts_SPrinting 65291
+#define Consts_SInvalidPrinter 65292
+#define Consts_SDeviceOnPort 65293
+#define Consts_SGroupIndexTooLow 65294
+#define Consts_SNoMDIForm 65295
 #define Consts_SInvalidImage 65296
 #define Consts_SScanLine 65297
 #define Consts_SChangeIconSize 65298
@@ -337,6 +338,7 @@
 #define Driveview_coFileOperatorTitle 65535
 STRINGTABLE
 BEGIN
+	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"
@@ -345,6 +347,7 @@ BEGIN
 	Consts_SSeparator,	"Separator"
 	Consts_SErrorSettingCount,	"Error setting %s.Count"
 	Consts_SListBoxMustBeVirtual,	"Listbox (%s) style must be virtual in order to set Count"
+	Consts_SmkcShift,	"Shift+"
 	Consts_SmkcCtrl,	"Ctrl+"
 	Consts_SmkcAlt,	"Alt+"
 	Consts_srNone,	"(None)"
@@ -360,7 +363,7 @@ BEGIN
 	Consts_SPictureLabel,	"Picture:"
 	Consts_SPictureDesc,	" (%dx%d)"
 	Consts_SPreviewLabel,	"Preview"
-	Consts_SCannotOpenAVI,	"Cannot open AVI"
+	Consts_SMsgDlgYesToAll,	"Yes to &All"
 	Consts_SmkcBkSp,	"BkSp"
 	Consts_SmkcTab,	"Tab"
 	Consts_SmkcEsc,	"Esc"
@@ -376,7 +379,7 @@ BEGIN
 	Consts_SmkcDown,	"Down"
 	Consts_SmkcIns,	"Ins"
 	Consts_SmkcDel,	"Del"
-	Consts_SmkcShift,	"Shift+"
+	Consts_SMaskErr,	"Invalid input value"
 	Consts_SMaskEditErr,	"Invalid input value.  Use escape key to abandon changes"
 	Consts_SMsgDlgWarning,	"Warning"
 	Consts_SMsgDlgError,	"Error"
@@ -392,7 +395,7 @@ BEGIN
 	Consts_SMsgDlgIgnore,	"&Ignore"
 	Consts_SMsgDlgAll,	"&All"
 	Consts_SMsgDlgNoToAll,	"N&o to All"
-	Consts_SMsgDlgYesToAll,	"Yes to &All"
+	Consts_SControlParentSetToSelf,	"A control cannot have itself as its parent"
 	Consts_SOKButton,	"OK"
 	Consts_SCancelButton,	"Cancel"
 	Consts_SYesButton,	"&Yes"
@@ -408,8 +411,8 @@ BEGIN
 	Consts_SVEnhMetafiles,	"Enhanced Metafiles"
 	Consts_SVIcons,	"Icons"
 	Consts_SVBitmaps,	"Bitmaps"
-	Consts_SMaskErr,	"Invalid input value"
 	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"
@@ -424,7 +427,6 @@ BEGIN
 	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_SInvalidImage,	"Invalid image"
 	Consts_SScanLine,	"Scan line index out of range"
 	Consts_SChangeIconSize,	"Cannot change the size of an icon"

BIN
WinSCP3.res


+ 32 - 8
components/UnixDirView.cpp

@@ -56,15 +56,27 @@ int __stdcall CompareDirectories(TListItem *Item1, TListItem *Item2, TUnixDirVie
   return 0;
 }
 //---------------------------------------------------------------------------
-#define DEFINE_COMPARE_FUNC(Property, CompareFunc) \
-  int __stdcall Compare ## Property(TListItem *Item1, TListItem *Item2, TUnixDirView *DirView) \
-  { int Result = CompareDirectories(Item1, Item2, DirView); \
-    if (!Result) { Result = CompareFunc(RFILE(1)->Property, RFILE(2)->Property); \
-      if (!DirView->UnixColProperties->SortAscending) Result = -Result; }\
-    return Result; }
+#define DEFINE_COMPARE_FUNC_EX(PROPERTY, COMPAREFUNC, FALLBACK) \
+  int __stdcall Compare ## PROPERTY(TListItem *Item1, TListItem *Item2, TUnixDirView *DirView) \
+  { \
+    int Result = CompareDirectories(Item1, Item2, DirView); \
+    if (!Result) \
+    { \
+      Result = COMPAREFUNC(RFILE(1)->PROPERTY, RFILE(2)->PROPERTY); \
+      if (Result == 0) \
+      { \
+        Result = FALLBACK(RFILE(1)->FileName, RFILE(2)->FileName); \
+      } \
+      if (!DirView->UnixColProperties->SortAscending) Result = -Result; \
+    } \
+    return Result; \
+  }
+#define DEFINE_COMPARE_FUNC(PROPERTY, COMPAREFUNC) \
+  DEFINE_COMPARE_FUNC_EX(PROPERTY, COMPAREFUNC, AnsiCompareText)
 #define COMPARE_NUMBER(Num1, Num2) ( Num1 < Num2 ? -1 : ( Num1 > Num2 ? 1 : 0) )
+#define COMPARE_DUMMY(X1, X2) 0
 //---------------------------------------------------------------------------
-DEFINE_COMPARE_FUNC(FileName, AnsiCompareText);
+DEFINE_COMPARE_FUNC_EX(FileName, AnsiCompareText, COMPARE_DUMMY);
 DEFINE_COMPARE_FUNC(Size, COMPARE_NUMBER);
 DEFINE_COMPARE_FUNC(Modification, COMPARE_NUMBER);
 DEFINE_COMPARE_FUNC(RightsStr, AnsiCompareText);
@@ -345,6 +357,8 @@ void __fastcall TUnixDirView::LoadFiles()
         Item->Caption = File->FileName;
         if (FFullLoad)
         {
+          // this is out of date
+          // (missing columns and does not update then file properties are loaded)
           Item->ImageIndex = File->IconIndex;
           Item->SubItems->Add((!File->IsDirectory ? FormatFloat("#,##0", File->Size) : AnsiString()));
           Item->SubItems->Add(File->UserModificationStr);
@@ -749,7 +763,17 @@ void __fastcall TUnixDirView::InternalEdit(const tagLVITEMA & HItem)
 #endif
 }
 //---------------------------------------------------------------------------
+int __fastcall TUnixDirView::SecondaryColumnHeader(int Index)
+{
+  return ((Index == uvName) ? uvExt : -1);
+}
+//---------------------------------------------------------------------------
 void __fastcall TUnixDirView::CreateDirectory(AnsiString DirName)
+{
+  CreateDirectoryEx(DirName, NULL);
+}
+//---------------------------------------------------------------------------
+void __fastcall TUnixDirView::CreateDirectoryEx(AnsiString DirName, const TRemoteProperties * Properties)
 {
 #ifndef DESIGN_ONLY
   assert(Terminal);
@@ -758,7 +782,7 @@ void __fastcall TUnixDirView::CreateDirectory(AnsiString DirName)
   {
     FSelectFile = DirName;
   }
-  Terminal->CreateDirectory(DirName);
+  Terminal->CreateDirectory(DirName, Properties);
 #endif
 }
 //---------------------------------------------------------------------------

+ 4 - 0
components/UnixDirView.h

@@ -12,6 +12,7 @@ class TTerminal;
 class TUnixDirView;
 class TCustomUnixDriveView;
 class TRemoteFile;
+class TRemoteProperties;
 //---------------------------------------------------------------------------
 enum TTransferDirection { tdToRemote, tdToLocal };
 enum TTransferType { ttCopy, ttMove };
@@ -72,6 +73,7 @@ protected:
     TDateTimePrecision & Precision);
   DYNAMIC bool __fastcall CanEdit(TListItem* Item);
   void __fastcall SetDriveView(TCustomUnixDriveView * Value);
+  virtual int __fastcall SecondaryColumnHeader(int Index);
 
   __property TCustomUnixDriveView * DriveView = { read = FDriveView, write = SetDriveView };
 
@@ -79,6 +81,7 @@ public:
   __fastcall TUnixDirView(TComponent* Owner);
   virtual __fastcall ~TUnixDirView();
   virtual void __fastcall CreateDirectory(AnsiString DirName);
+  void __fastcall CreateDirectoryEx(AnsiString DirName, const TRemoteProperties * Properties);
   virtual void __fastcall DisplayPropertiesMenu();
   virtual void __fastcall ExecuteHomeDirectory();
   virtual void __fastcall ExecuteParentDirectory();
@@ -88,6 +91,7 @@ public:
   virtual bool __fastcall ItemIsParentDirectory(TListItem * Item);
   virtual AnsiString __fastcall ItemFullFileName(TListItem * Item);
   virtual bool __fastcall PasteFromClipBoard(AnsiString TargetPath = "");
+  void __fastcall UpdateFiles();
 
   __property bool Active = { read = GetActive };
   __property TTerminal *Terminal = { read = FTerminal, write = SetTerminal };

+ 11 - 2
console/Main.cpp

@@ -200,7 +200,7 @@ inline void Print(bool FromBeginning, const char * Message)
 {
   if (((OutputType == FILE_TYPE_DISK) || (OutputType == FILE_TYPE_PIPE)))
   {
-    if (FromBeginning)
+    if (FromBeginning && (Message[0] != '\n'))
     {
       strcpy(LastFromBeginning, Message);
     }
@@ -211,7 +211,16 @@ inline void Print(bool FromBeginning, const char * Message)
         printf("%s", LastFromBeginning);
         LastFromBeginning[0] = '\0';
       }
-      printf("%s", Message);
+
+      if (FromBeginning && (Message[0] == '\n'))
+      {
+        printf("\n");
+        strcpy(LastFromBeginning, Message + 1);
+      }
+      else
+      {
+        printf("%s", Message);
+      }
     }
   }
   else

+ 41 - 3
core/Common.cpp

@@ -6,6 +6,7 @@
 #include "Exceptions.h"
 #include "TextsCore.h"
 #include "Interface.h"
+#include <StrUtils.hpp>
 #include <math.h>
 #include <shellapi.h>
 //---------------------------------------------------------------------------
@@ -126,7 +127,7 @@ AnsiString MakeValidFileName(AnsiString FileName)
   AnsiString IllegalChars = ";,=+<>|\"[] \\/?*";
   for (int Index = 0; Index < IllegalChars.Length(); Index++)
   {
-    ReplaceChar(FileName, IllegalChars[Index+1], '-');
+    FileName = ReplaceChar(FileName, IllegalChars[Index+1], '-');
   }
   return FileName;
 }
@@ -356,6 +357,26 @@ AnsiString __fastcall FormatCommand(AnsiString Program, AnsiString Params)
   return Program + Params;
 }
 //---------------------------------------------------------------------------
+const char ShellCommandFileNamePattern[] = "!.!";
+//---------------------------------------------------------------------------
+void __fastcall ReformatFileNameCommand(AnsiString & Command)
+{
+  AnsiString Program, Params, Dir;
+  SplitCommand(Command, Program, Params, Dir);
+  if (Params.Pos(ShellCommandFileNamePattern) == 0)
+  {
+    Params = Params + (Params.IsEmpty() ? "" : " ") + ShellCommandFileNamePattern;
+  }
+  Command = FormatCommand(Program, Params);
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall ExpandFileNameCommand(const AnsiString Command,
+  const AnsiString FileName)
+{
+  return AnsiReplaceStr(Command, ShellCommandFileNamePattern,
+    AddPathQuotes(FileName));
+}
+//---------------------------------------------------------------------------
 bool __fastcall IsDisplayableStr(const AnsiString Str)
 {
   bool Displayable = true;
@@ -639,8 +660,6 @@ static bool __fastcall IsDateInDST(const TDateTime & DateTime)
 
       EncodeDSTMargin(Params->StandardDate, Year, NewCache.StandardDate);
       EncodeDSTMargin(Params->DaylightDate, Year, NewCache.DaylightDate);
-      AnsiString SD = FormatDateTime("dddddd tt", NewCache.StandardDate);
-      AnsiString DD = FormatDateTime("dddddd tt", NewCache.DaylightDate);
       if (DSTCacheCount < LENOF(DSTCache))
       {
         TGuard Guard(&Section);
@@ -999,6 +1018,25 @@ AnsiString __fastcall DecodeUrlChars(AnsiString S)
   return S;
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall EncodeUrlChars(AnsiString S, AnsiString Ignore)
+{
+  AnsiString Encode = "/ ";
+  int i = 1;
+  while (i <= S.Length())
+  {
+    if ((Encode.Pos(S[i]) > 0) &&
+        (Ignore.Pos(S[i]) == 0))
+    {
+      AnsiString H = CharToHex(S[i]);
+      S.Insert(H, i + 1);
+      S[i] = '%';
+      i += H.Length();
+    }
+    i++;
+  }
+  return S;
+}
+//---------------------------------------------------------------------------
 void __fastcall OemToAnsi(AnsiString & Str)
 {
   if (!Str.IsEmpty())

+ 4 - 0
core/Common.h

@@ -44,12 +44,16 @@ void __fastcall SplitCommand(AnsiString Command, AnsiString &Program,
   AnsiString & Params, AnsiString & Dir);
 AnsiString __fastcall ExtractProgram(AnsiString Command);
 AnsiString __fastcall FormatCommand(AnsiString Program, AnsiString Params);
+AnsiString __fastcall ExpandFileNameCommand(const AnsiString Command,
+  const AnsiString FileName);
+void __fastcall ReformatFileNameCommand(AnsiString & Command);
 bool __fastcall IsDisplayableStr(const AnsiString Str);
 AnsiString __fastcall CharToHex(char Ch);
 AnsiString __fastcall StrToHex(const AnsiString Str);
 AnsiString __fastcall HexToStr(const AnsiString Hex);
 unsigned int __fastcall HexToInt(const AnsiString Hex, int MinChars = 0);
 AnsiString __fastcall DecodeUrlChars(AnsiString S);
+AnsiString __fastcall EncodeUrlChars(AnsiString S, AnsiString Ignore = "");
 bool __fastcall RecursiveDeleteFile(const AnsiString FileName, bool ToRecycleBin);
 int __fastcall CancelAnswer(int Answers);
 int __fastcall AbortAnswer(int Answers);

+ 50 - 20
core/Configuration.cpp

@@ -23,7 +23,7 @@ __fastcall TConfiguration::TConfiguration()
   FRandomSeedSave = true;
   FApplicationInfo = NULL;
   FGSSAPIInstalled = -1;
-  // make sure random generator is initialised, so random_save_seed() 
+  // make sure random generator is initialised, so random_save_seed()
   // in destructor can proceed
   random_ref();
 }
@@ -40,14 +40,20 @@ void __fastcall TConfiguration::Default()
     TReplaceFlags() << rfReplaceAll);
   FConfirmOverwriting = true;
   FConfirmResume = true;
+  FSessionReopenAuto = 5000;
+  FSessionReopenNoConfirmation = 2000;
 
   FLogging = false;
+  FPermanentLogging = false;
   FLogFileName = "";
+  FPermanentLogFileName = "";
   FLogFileAppend = true;
   FLogWindowLines = 100;
   FLogProtocol = 0;
 
   FDisablePasswordStoring = false;
+  FForceBanners = false;
+  FDisableAcceptingHostKeys = false;
 
   Changed();
 }
@@ -77,6 +83,7 @@ THierarchicalStorage * TConfiguration::CreateScpStorage(bool /*SessionList*/)
   ELEM.SubString(ELEM.LastDelimiter(".>")+1, ELEM.Length() - ELEM.LastDelimiter(".>"))
 #define BLOCK(KEY, CANCREATE, BLOCK) \
   if (Storage->OpenSubKey(KEY, CANCREATE)) try { BLOCK } __finally { Storage->CloseSubKey(); }
+#define KEY(TYPE, VAR) KEYEX(TYPE, VAR, VAR)
 #define REGCONFIG(ACCESS, CANCREATE, ADDON) \
   THierarchicalStorage * Storage = CreateScpStorage(false); \
   try { \
@@ -86,10 +93,12 @@ THierarchicalStorage * TConfiguration::CreateScpStorage(bool /*SessionList*/)
         KEY(String,   RandomSeedFile); \
         KEY(Bool,     ConfirmOverwriting); \
         KEY(Bool,     ConfirmResume); \
+        KEY(Integer,  SessionReopenAuto); \
+        KEY(Integer,  SessionReopenNoConfirmation); \
       ); \
       BLOCK("Logging", CANCREATE, \
-        KEY(Bool,    Logging); \
-        KEY(String,  LogFileName); \
+        KEYEX(Bool,  PermanentLogging, Logging); \
+        KEYEX(String,PermanentLogFileName, LogFileName); \
         KEY(Bool,    LogFileAppend); \
         KEY(Integer, LogWindowLines); \
         KEY(Integer, LogProtocol); \
@@ -110,9 +119,9 @@ void __fastcall TConfiguration::Save()
 
   if (Storage == stRegistry) CleanupIniFile();
 
-  #define KEY(TYPE, VAR) Storage->Write ## TYPE(LASTELEM(AnsiString(#VAR)), VAR)
+  #define KEYEX(TYPE, VAR, NAME) Storage->Write ## TYPE(LASTELEM(AnsiString(#NAME)), VAR)
   REGCONFIG(smReadWrite, true, SaveSpecial);
-  #undef KEY
+  #undef KEYEX
 }
 //---------------------------------------------------------------------------
 void __fastcall TConfiguration::LoadSpecial(THierarchicalStorage * /*Storage*/)
@@ -122,17 +131,19 @@ void __fastcall TConfiguration::LoadSpecial(THierarchicalStorage * /*Storage*/)
 void __fastcall TConfiguration::LoadAdmin(THierarchicalStorage * Storage)
 {
   FDisablePasswordStoring = Storage->ReadBool("DisablePasswordStoring", FDisablePasswordStoring);
+  FForceBanners = Storage->ReadBool("ForceBanners", FForceBanners);
+  FDisableAcceptingHostKeys = Storage->ReadBool("DisableAcceptingHostKeys", FDisableAcceptingHostKeys);
 }
 //---------------------------------------------------------------------------
 void __fastcall TConfiguration::Load()
 {
   TGuard Guard(FCriticalSection);
 
-  #define KEY(TYPE, VAR) VAR = Storage->Read ## TYPE(LASTELEM(AnsiString(#VAR)), VAR)
+  #define KEYEX(TYPE, VAR, NAME) VAR = Storage->Read ## TYPE(LASTELEM(AnsiString(#NAME)), VAR)
   #pragma warn -eas
   REGCONFIG(smRead, false, LoadSpecial);
   #pragma warn +eas
-  #undef KEY
+  #undef KEYEX
 
   TRegistryStorage * AdminStorage;
   AdminStorage = new TRegistryStorage(RegistryStorageKey, HKEY_LOCAL_MACHINE);
@@ -153,7 +164,7 @@ void __fastcall TConfiguration::Load()
 void __fastcall TConfiguration::LoadDirectoryChangesCache(const AnsiString SessionKey,
   TRemoteDirectoryChangesCache * DirectoryChangesCache)
 {
-  THierarchicalStorage * Storage = CreateScpStorage(false); 
+  THierarchicalStorage * Storage = CreateScpStorage(false);
   try
   {
     Storage->AccessMode = smRead;
@@ -173,7 +184,7 @@ void __fastcall TConfiguration::LoadDirectoryChangesCache(const AnsiString Sessi
 void __fastcall TConfiguration::SaveDirectoryChangesCache(const AnsiString SessionKey,
   TRemoteDirectoryChangesCache * DirectoryChangesCache)
 {
-  THierarchicalStorage * Storage = CreateScpStorage(false); 
+  THierarchicalStorage * Storage = CreateScpStorage(false);
   try
   {
     Storage->AccessMode = smReadWrite;
@@ -509,7 +520,7 @@ AnsiString __fastcall TConfiguration::GetFileFileInfoString(const AnsiString Key
 AnsiString __fastcall TConfiguration::GetFileInfoString(const AnsiString Key)
 {
   return GetFileFileInfoString(Key, "");
-} 
+}
 //---------------------------------------------------------------------------
 AnsiString __fastcall TConfiguration::GetRegistryStorageKey()
 {
@@ -518,10 +529,6 @@ AnsiString __fastcall TConfiguration::GetRegistryStorageKey()
 //---------------------------------------------------------------------------
 void __fastcall TConfiguration::SetIniFileStorageName(AnsiString value)
 {
-  if (!value.IsEmpty() && !FileExists(value))
-  {
-    throw Exception(FMTLOAD(FILE_NOT_EXISTS, (value)));
-  }
   FIniFileStorageName = value;
   FStorage = stIniFile;
 }
@@ -549,7 +556,7 @@ AnsiString __fastcall TConfiguration::GetPuttySessionsKey()
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TConfiguration::GetStoredSessionsSubKey()
-{   
+{
   return "Sessions";
 }
 //---------------------------------------------------------------------------
@@ -623,14 +630,30 @@ TEOLType __fastcall TConfiguration::GetLocalEOLType()
   return eolCRLF;
 }
 //---------------------------------------------------------------------
+void __fastcall TConfiguration::TemporaryLogging(const AnsiString ALogFileName)
+{
+  FLogging = true;
+  FLogFileName = ALogFileName;
+}
+//---------------------------------------------------------------------
 void __fastcall TConfiguration::SetLogging(bool value)
 {
-  SET_CONFIG_PROPERTY(Logging);
+  if (Logging != value)
+  {
+    FPermanentLogging = value;
+    FLogging = value;
+    Changed();
+  }
 }
 //---------------------------------------------------------------------
 void __fastcall TConfiguration::SetLogFileName(AnsiString value)
 {
-  SET_CONFIG_PROPERTY(LogFileName);
+  if (LogFileName != value)
+  {
+    FPermanentLogFileName = value;
+    FLogFileName = value;
+    Changed();
+  }
 }
 //---------------------------------------------------------------------
 void __fastcall TConfiguration::SetLogToFile(bool value)
@@ -729,6 +752,13 @@ bool __fastcall TConfiguration::GetRememberPassword()
 {
   return false;
 }
-
-
-
+//---------------------------------------------------------------------------
+void __fastcall TConfiguration::SetSessionReopenAuto(int value)
+{
+  SET_CONFIG_PROPERTY(SessionReopenAuto);
+}
+//---------------------------------------------------------------------------
+void __fastcall TConfiguration::SetSessionReopenNoConfirmation(int value)
+{
+  SET_CONFIG_PROPERTY(SessionReopenNoConfirmation);
+}

+ 19 - 3
core/Configuration.h

@@ -19,19 +19,25 @@ private:
   int FUpdating;
   TNotifyEvent FOnChange;
   bool FRandomSeedSave;
-  
+
   void * FApplicationInfo;
   bool FLogging;
+  bool FPermanentLogging;
   AnsiString FLogFileName;
+  AnsiString FPermanentLogFileName;
   int FLogWindowLines;
   bool FLogFileAppend;
   int FLogProtocol;
   bool FConfirmOverwriting;
   bool FConfirmResume;
+  int FSessionReopenAuto;
+  int FSessionReopenNoConfirmation;
   AnsiString FIniFileStorageName;
 
   bool FDisablePasswordStoring;
-  int FGSSAPIInstalled; 
+  bool FForceBanners;
+  bool FDisableAcceptingHostKeys;
+  int FGSSAPIInstalled;
 
   AnsiString __fastcall GetOSVersionStr();
   TVSFixedFileInfo *__fastcall GetFixedApplicationInfo();
@@ -70,6 +76,8 @@ private:
   AnsiString __fastcall GetFileInfoString(const AnsiString Key);
   AnsiString __fastcall GetLocalInvalidChars();
   bool __fastcall GetGSSAPIInstalled();
+  void __fastcall SetSessionReopenAuto(int value);
+  void __fastcall SetSessionReopenNoConfirmation(int value);
 
 protected:
   TStorage FStorage;
@@ -100,6 +108,9 @@ protected:
   AnsiString __fastcall GetFileProductName(const AnsiString FileName);
   AnsiString __fastcall GetFileCompanyName(const AnsiString FileName);
 
+  __property bool PermanentLogging  = { read=FPermanentLogging, write=SetLogging };
+  __property AnsiString PermanentLogFileName  = { read=FPermanentLogFileName, write=SetLogFileName };
+
 public:
   __fastcall TConfiguration();
   virtual __fastcall ~TConfiguration();
@@ -113,12 +124,13 @@ public:
   void __fastcall BeginUpdate();
   void __fastcall EndUpdate();
   void __fastcall LoadDirectoryChangesCache(const AnsiString SessionKey,
-    TRemoteDirectoryChangesCache * DirectoryChangesCache);   
+    TRemoteDirectoryChangesCache * DirectoryChangesCache);
   void __fastcall SaveDirectoryChangesCache(const AnsiString SessionKey,
     TRemoteDirectoryChangesCache * DirectoryChangesCache);
   bool __fastcall ShowBanner(const AnsiString SessionKey, const AnsiString & Banner);
   void __fastcall NeverShowBanner(const AnsiString SessionKey, const AnsiString & Banner);
   virtual THierarchicalStorage * CreateScpStorage(bool SessionList);
+  void __fastcall TemporaryLogging(const AnsiString ALogFileName);
 
   __property TVSFixedFileInfo *FixedApplicationInfo  = { read=GetFixedApplicationInfo };
   __property void * ApplicationInfo  = { read=GetApplicationInfo };
@@ -150,6 +162,8 @@ public:
   __property bool ConfirmResume = { read = GetConfirmResume, write = SetConfirmResume};
   __property bool RememberPassword = { read = GetRememberPassword };
   __property AnsiString PartialExt = {read=GetPartialExt};
+  __property int SessionReopenAuto = { read = FSessionReopenAuto, write = SetSessionReopenAuto };
+  __property int SessionReopenNoConfirmation = { read = FSessionReopenNoConfirmation, write = SetSessionReopenNoConfirmation };
 
   __property AnsiString TimeFormat = { read = GetTimeFormat };
   __property TStorage Storage  = { read=GetStorage, write=SetStorage };
@@ -159,6 +173,8 @@ public:
   __property AnsiString LocalInvalidChars = { read = GetLocalInvalidChars };
 
   __property bool DisablePasswordStoring = { read = FDisablePasswordStoring };
+  __property bool ForceBanners = { read = FForceBanners };
+  __property bool DisableAcceptingHostKeys = { read = FDisableAcceptingHostKeys };
   __property bool GSSAPIInstalled = { read = GetGSSAPIInstalled };
 };
 //---------------------------------------------------------------------------

+ 96 - 59
core/CopyParam.cpp

@@ -29,6 +29,7 @@ void __fastcall TCopyParamType::Default()
   PreserveTime = true;
   Rights.Number = TRights::rfDefault;
   PreserveRights = false; // Was True until #106
+  IgnorePermErrors = false;
   AsciiFileMask.Masks = "*.*html; *.htm; *.txt; *.php*; *.cgi; *.c; *.cpp; *.h; *.pas; "
     "*.bas; *.tex; *.pl; .htaccess; *.xtml; *.css; *.cfg; *.ini; *.sh; *.xml";
   TransferMode = tmAutomatic;
@@ -49,84 +50,108 @@ AnsiString __fastcall TCopyParamType::GetInfoStr(AnsiString Separator, int Optio
   TCopyParamType Defaults;
   AnsiString Result;
 
-  #define ADD(STR) Result += (Result.IsEmpty() ? AnsiString() : Separator) + (STR)
-  if (FLAGCLEAR(Options, cpiExcludeMaskOnly))
-  {
-    if ((TransferMode != Defaults.TransferMode) ||
-        ((TransferMode == tmAutomatic) && !(AsciiFileMask == Defaults.AsciiFileMask)))
-    {
-      AnsiString S = FORMAT(LoadStrPart(COPY_INFO_TRANSFER_TYPE, 1),
-        (LoadStrPart(COPY_INFO_TRANSFER_TYPE, TransferMode + 2)));
-      if (TransferMode == tmAutomatic)
-      {
-        S = FORMAT(S, (AsciiFileMask.Masks));
-      }
-      ADD(S);
+  bool SomeAttrExcluded = false;
+  #define ADD(STR, EXCEPT) \
+    if (FLAGCLEAR(Options, EXCEPT)) \
+    { \
+      Result += (Result.IsEmpty() ? AnsiString() : Separator) + (STR); \
+    } \
+    else \
+    { \
+      SomeAttrExcluded = true; \
     }
 
-    if (FileNameCase != Defaults.FileNameCase)
+  if ((TransferMode != Defaults.TransferMode) ||
+      ((TransferMode == tmAutomatic) && !(AsciiFileMask == Defaults.AsciiFileMask)))
+  {
+    AnsiString S = FORMAT(LoadStrPart(COPY_INFO_TRANSFER_TYPE, 1),
+      (LoadStrPart(COPY_INFO_TRANSFER_TYPE, TransferMode + 2)));
+    if (TransferMode == tmAutomatic)
     {
-      ADD(FORMAT(LoadStrPart(COPY_INFO_FILENAME, 1),
-        (LoadStrPart(COPY_INFO_FILENAME, FileNameCase + 2))));
+      S = FORMAT(S, (AsciiFileMask.Masks));
     }
+    ADD(S, cpaExcludeMaskOnly | cpaNoTransferMode);
+  }
 
-    if ((InvalidCharsReplacement == NoReplacement) !=
-          (Defaults.InvalidCharsReplacement == NoReplacement))
+  if (FileNameCase != Defaults.FileNameCase)
+  {
+    ADD(FORMAT(LoadStrPart(COPY_INFO_FILENAME, 1),
+      (LoadStrPart(COPY_INFO_FILENAME, FileNameCase + 2))),
+      cpaExcludeMaskOnly);
+  }
+
+  if ((InvalidCharsReplacement == NoReplacement) !=
+        (Defaults.InvalidCharsReplacement == NoReplacement))
+  {
+    assert(InvalidCharsReplacement == NoReplacement);
+    if (InvalidCharsReplacement == NoReplacement)
     {
-      assert(InvalidCharsReplacement == NoReplacement);
-      if (InvalidCharsReplacement == NoReplacement)
-      {
-        ADD(LoadStr(COPY_INFO_DONT_REPLACE_INV_CHARS));
-      }
+      ADD(LoadStr(COPY_INFO_DONT_REPLACE_INV_CHARS), cpaExcludeMaskOnly);
     }
+  }
+
+  if ((PreserveRights != Defaults.PreserveRights) ||
+      (PreserveRights &&
+       ((Rights != Defaults.Rights) || (AddXToDirectories != Defaults.AddXToDirectories))))
+  {
+    assert(PreserveRights);
 
-    if ((PreserveRights != Defaults.PreserveRights) ||
-        (PreserveRights && 
-         ((Rights != Defaults.Rights) || (AddXToDirectories != Defaults.AddXToDirectories))))
+    if (PreserveRights)
     {
-      assert(PreserveRights);
-    
-      if (PreserveRights)
+      AnsiString RightsStr = Rights.Text;
+      if (AddXToDirectories)
       {
-        AnsiString RightsStr = Rights.Text;
-        if (AddXToDirectories)
-        {
-          RightsStr += ", " + LoadStr(COPY_INFO_ADD_X_TO_DIRS);
-        }
-        ADD(FORMAT(LoadStr(COPY_INFO_PERMISSIONS), (RightsStr)));
+        RightsStr += ", " + LoadStr(COPY_INFO_ADD_X_TO_DIRS);
       }
+      ADD(FORMAT(LoadStr(COPY_INFO_PERMISSIONS), (RightsStr)),
+        cpaExcludeMaskOnly | cpaNoRights);
     }
+  }
 
-    if (PreserveReadOnly != Defaults.PreserveReadOnly)
+  if (PreserveTime != Defaults.PreserveTime)
+  {
+    ADD(LoadStr(PreserveTime ? COPY_INFO_TIMESTAMP : COPY_INFO_DONT_PRESERVE_TIME),
+      cpaExcludeMaskOnly | cpaNoPreserveTime);
+  }
+
+  if ((PreserveRights || PreserveTime) &&
+      (IgnorePermErrors != Defaults.IgnorePermErrors))
+  {
+    assert(IgnorePermErrors);
+
+    if (IgnorePermErrors)
     {
-      assert(!PreserveReadOnly);
-      if (!PreserveReadOnly)
-      {
-        ADD(LoadStr(COPY_INFO_DONT_PRESERVE_READONLY));
-      }
+      ADD(LoadStr(COPY_INFO_IGNORE_PERM_ERRORS),
+        cpaExcludeMaskOnly | cpaNoIgnorePermErrors);
     }
+  }
 
-    if (PreserveTime != Defaults.PreserveTime)
+  if (PreserveReadOnly != Defaults.PreserveReadOnly)
+  {
+    assert(!PreserveReadOnly);
+    if (!PreserveReadOnly)
     {
-      ADD(LoadStr(PreserveTime ? COPY_INFO_TIMESTAMP : COPY_INFO_DONT_PRESERVE_TIME));
+      ADD(LoadStr(COPY_INFO_DONT_PRESERVE_READONLY),
+        cpaExcludeMaskOnly | cpaNoPreserveReadOnly);
     }
+  }
 
-    if (CalculateSize != Defaults.CalculateSize)
+  if (CalculateSize != Defaults.CalculateSize)
+  {
+    assert(!CalculateSize);
+    if (!CalculateSize)
     {
-      assert(!CalculateSize);
-      if (!CalculateSize)
-      {
-        ADD(LoadStr(COPY_INFO_DONT_CALCULATE_SIZE));
-      }
+      ADD(LoadStr(COPY_INFO_DONT_CALCULATE_SIZE), cpaExcludeMaskOnly);
     }
+  }
 
-    if (ClearArchive != Defaults.ClearArchive)
+  if (ClearArchive != Defaults.ClearArchive)
+  {
+    assert(ClearArchive);
+    if (ClearArchive)
     {
-      assert(ClearArchive);
-      if (ClearArchive)
-      {
-        ADD(LoadStr(COPY_INFO_CLEAR_ARCHIVE));
-      }
+      ADD(LoadStr(COPY_INFO_CLEAR_ARCHIVE),
+        cpaExcludeMaskOnly | cpaNoClearArchive);
     }
   }
 
@@ -134,14 +159,21 @@ AnsiString __fastcall TCopyParamType::GetInfoStr(AnsiString Separator, int Optio
       !(ExcludeFileMask == Defaults.ExcludeFileMask))
   {
     ADD(FORMAT(LoadStr(NegativeExclude ? COPY_INFO_INCLUDE_MASK : COPY_INFO_EXCLUDE_MASK),
-      (ExcludeFileMask.Masks)));
+      (ExcludeFileMask.Masks)),
+      cpaNoExcludeMask);
   }
-  #undef ADD
 
-  if (Result.IsEmpty())
+  if (SomeAttrExcluded)
+  {
+    Result += (Result.IsEmpty() ? AnsiString() : Separator) +
+      FORMAT(LoadStrPart(COPY_INFO_NOT_USABLE, 1),
+        (LoadStrPart(COPY_INFO_NOT_USABLE, (Result.IsEmpty() ? 3 : 2))));
+  }
+  else if (Result.IsEmpty())
   {
     Result = LoadStr(COPY_INFO_DEFAULT);
   }
+  #undef ADD
 
   return Result;
 }
@@ -158,6 +190,7 @@ void __fastcall TCopyParamType::Assign(const TCopyParamType * Source)
   COPY(TransferMode);
   COPY(AddXToDirectories);
   COPY(PreserveRights);
+  COPY(IgnorePermErrors);
   COPY(ResumeSupport);
   COPY(ResumeThreshold);
   COPY(InvalidCharsReplacement);
@@ -321,7 +354,7 @@ AnsiString __fastcall TCopyParamType::GetLogStr() const
   char ModeC[] = "BAM";
   char ResumeC[] = "YSN";
   return FORMAT(
-    "  PrTime: %s; PrRO: %s; Rght: %s; PrR: %s; FnCs: %s; RIC: %s; "
+    "  PrTime: %s; PrRO: %s; Rght: %s; PrR: %s (%s); FnCs: %s; RIC: %s; "
       "Resume: %s (%d); CalcS: %s; Mask: %s\n"
     "  TM: %s; ClAr: %s; ExclM(%s): %s\n"
     "  AscM: %s\n",
@@ -329,6 +362,7 @@ AnsiString __fastcall TCopyParamType::GetLogStr() const
      BooleanToEngStr(PreserveReadOnly),
      Rights.Text,
      BooleanToEngStr(PreserveRights),
+     BooleanToEngStr(IgnorePermErrors),
      CaseC[FileNameCase],
      CharToHex(InvalidCharsReplacement),
      ResumeC[ResumeSupport],
@@ -382,6 +416,7 @@ void __fastcall TCopyParamType::Load(THierarchicalStorage * Storage)
   PreserveReadOnly = Storage->ReadBool("PreserveReadOnly", PreserveReadOnly);
   PreserveTime = Storage->ReadBool("PreserveTime", PreserveTime);
   PreserveRights = Storage->ReadBool("PreserveRights", PreserveRights);
+  IgnorePermErrors = Storage->ReadBool("IgnorePermErrors", IgnorePermErrors);
   Rights.Text = Storage->ReadString("Text", Rights.Text);
   TransferMode = (TTransferMode)Storage->ReadInteger("TransferMode", TransferMode);
   ResumeSupport = (TResumeSupport)Storage->ReadInteger("ResumeSupport", ResumeSupport);
@@ -403,6 +438,7 @@ void __fastcall TCopyParamType::Save(THierarchicalStorage * Storage) const
   Storage->WriteBool("PreserveReadOnly", PreserveReadOnly);
   Storage->WriteBool("PreserveTime", PreserveTime);
   Storage->WriteBool("PreserveRights", PreserveRights);
+  Storage->WriteBool("IgnorePermErrors", IgnorePermErrors);
   Storage->WriteString("Text", Rights.Text);
   Storage->WriteInteger("TransferMode", TransferMode);
   Storage->WriteInteger("ResumeSupport", ResumeSupport);
@@ -425,6 +461,7 @@ bool __fastcall TCopyParamType::operator==(const TCopyParamType & rhp) const
     C(PreserveReadOnly) &&
     C(PreserveTime) &&
     C(PreserveRights) &&
+    C(IgnorePermErrors) &&
     C(Rights) &&
     C(TransferMode) &&
     C(ResumeSupport) &&

+ 18 - 2
core/CopyParam.h

@@ -12,6 +12,21 @@ enum TFileNameCase { ncNoChange, ncUpperCase, ncLowerCase, ncFirstUpperCase, ncL
 enum TTransferMode { tmBinary, tmAscii, tmAutomatic };
 enum TResumeSupport { rsOn, rsSmart, rsOff };
 class THierarchicalStorage;
+const int cpaExcludeMaskOnly = 0x01;
+const int cpaNoTransferMode =  0x02;
+const int cpaNoExcludeMask =   0x04;
+const int cpaNoClearArchive =  0x08;
+const int cpaNoPreserveTime =  0x10;
+const int cpaNoRights =        0x20;
+const int cpaNoPreserveReadOnly = 0x40;
+const int cpaNoIgnorePermErrors = 0x80;
+//---------------------------------------------------------------------------
+struct TUsableCopyParamAttrs
+{
+  int General;
+  int Upload;
+  int Download;
+};
 //---------------------------------------------------------------------------
 class TCopyParamType {
 private:
@@ -23,6 +38,7 @@ private:
   TTransferMode FTransferMode;
   bool FAddXToDirectories;
   bool FPreserveRights;
+  bool FIgnorePermErrors;
   TResumeSupport FResumeSupport;
   __int64 FResumeThreshold;
   AnsiString __fastcall GetLogStr() const;
@@ -62,8 +78,7 @@ public:
 
   void __fastcall Load(THierarchicalStorage * Storage);
   void __fastcall Save(THierarchicalStorage * Storage) const;
-  static const int cpiExcludeMaskOnly = 0x01;
-  AnsiString __fastcall GetInfoStr(AnsiString Separator, int Options = 0) const;
+  AnsiString __fastcall GetInfoStr(AnsiString Separator, int Attrs) const;
 
   bool __fastcall operator==(const TCopyParamType & rhp) const;
 
@@ -76,6 +91,7 @@ public:
   __property AnsiString LogStr  = { read=GetLogStr };
   __property bool AddXToDirectories  = { read=FAddXToDirectories, write=FAddXToDirectories };
   __property bool PreserveRights = { read = FPreserveRights, write = FPreserveRights };
+  __property bool IgnorePermErrors = { read = FIgnorePermErrors, write = FIgnorePermErrors };
   __property TResumeSupport ResumeSupport = { read = FResumeSupport, write = FResumeSupport };
   __property __int64 ResumeThreshold = { read = FResumeThreshold, write = FResumeThreshold };
   __property char InvalidCharsReplacement = { read = FInvalidCharsReplacement, write = FInvalidCharsReplacement };

+ 16 - 2
core/FileMasks.cpp

@@ -122,7 +122,7 @@ bool __fastcall TFileMasks::IsMask(const AnsiString Mask)
 //---------------------------------------------------------------------------
 bool __fastcall TFileMasks::SingleMaskMatch(const AnsiString Mask, const AnsiString FileName)
 {
-  return MatchesMask(FileName, Mask);
+  return MatchesFileMask(FileName, Mask);
 }
 //---------------------------------------------------------------------------
 __fastcall TFileMasks::TFileMasks()
@@ -140,6 +140,20 @@ __fastcall TFileMasks::TFileMasks(const AnsiString AMasks)
   FMasks = AMasks;
 }
 //---------------------------------------------------------------------------
+bool __fastcall TFileMasks::MatchesFileMask(const AnsiString & Filename, const AnsiString & Mask)
+{
+  bool Result;
+  if (Mask == "*.*")
+  {
+    Result = true;
+  }
+  else
+  {
+    Result = MatchesMask(Filename, Mask);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 bool __fastcall TFileMasks::Matches(AnsiString FileName, bool Directory,
   AnsiString Path) const
 {
@@ -169,7 +183,7 @@ bool __fastcall TFileMasks::Matches(AnsiString FileName, bool Directory,
         M = M.SubString(D + 1, M.Length() - D);
       }
 
-      if (PathMatch && MatchesMask(FileName, M)) return true;
+      if (PathMatch && MatchesFileMask(FileName, M)) return true;
     }
   }
   return false;

+ 2 - 0
core/FileMasks.h

@@ -25,6 +25,8 @@ public:
 
 private:
   AnsiString FMasks;
+
+  static inline bool __fastcall MatchesFileMask(const AnsiString & Filename, const AnsiString & Mask);
 };
 //---------------------------------------------------------------------------
 AnsiString __fastcall MaskFileName(AnsiString FileName, const AnsiString Mask);

+ 18 - 2
core/FileOperationProgress.cpp

@@ -43,6 +43,7 @@ void __fastcall TFileOperationProgressType::Clear()
   TotalTransfered = 0;
   TotalSkipped = 0;
   TotalSize = 0;
+  SkippedSize = 0;
   TotalSizeSet = false;
   Operation = foNone;
   Temp = false;
@@ -60,12 +61,13 @@ void __fastcall TFileOperationProgressType::ClearTransfer()
 {
   if ((TransferSize > 0) && (TransferedSize < TransferSize))
   {
-    __int64 RemainingSide = (TransferSize - TransferedSize);
-    TotalSkipped += RemainingSide;
+    __int64 RemainingSize = (TransferSize - TransferedSize);
+    TotalSkipped += RemainingSize;
   }
   LocalSize = 0;
   TransferSize = 0;
   LocalyUsed = 0;
+  SkippedSize = 0;
   TransferedSize = 0;
   TransferingFile = false;
   FFileStopped = 0;
@@ -233,6 +235,19 @@ void __fastcall TFileOperationProgressType::ChangeTransferSize(__int64 ASize)
   DoProgress();
 }
 //---------------------------------------------------------------------------
+void __fastcall TFileOperationProgressType::RollbackTransfer()
+{
+  TransferedSize -= SkippedSize;
+  assert(TransferedSize <= TotalTransfered);
+  TotalTransfered -= TransferedSize;
+  assert(SkippedSize <= TotalSkipped);
+  TotalSkipped -= SkippedSize;
+  SkippedSize = 0;
+  TransferedSize = 0;
+  TransferSize = 0;
+  LocalyUsed = 0;
+}
+//---------------------------------------------------------------------------
 void __fastcall TFileOperationProgressType::AddTransfered(__int64 ASize,
   bool AddToTotals)
 {
@@ -257,6 +272,7 @@ void __fastcall TFileOperationProgressType::AddTransfered(__int64 ASize,
 void __fastcall TFileOperationProgressType::AddResumed(__int64 ASize)
 {
   TotalSkipped += ASize;
+  SkippedSize += ASize;
   AddTransfered(ASize, false);
   AddLocalyUsed(ASize);
 }

+ 4 - 1
core/FileOperationProgress.h

@@ -7,7 +7,8 @@
 //---------------------------------------------------------------------------
 class TFileOperationProgressType;
 enum TFileOperation { foNone, foCopy, foMove, foDelete, foSetProperties,
-  foRename, foCustomCommand, foCalculateSize, foRemoteMove, foRemoteCopy };
+  foRename, foCustomCommand, foCalculateSize, foRemoteMove, foRemoteCopy,
+  foGetProperties };
 enum TCancelStatus { csContinue = 0, csCancel, csCancelTransfer, csRemoteAbort };
 enum TResumeStatus { rsNotAvailable, rsEnabled, rsDisabled };
 typedef void __fastcall (__closure *TFileOperationProgressEvent)
@@ -52,6 +53,7 @@ public:
   __int64 LocalyUsed;
   __int64 TransferSize;
   __int64 TransferedSize;
+  __int64 SkippedSize;
   TResumeStatus ResumeStatus;
   bool InProgress;
   TCancelStatus Cancel;
@@ -97,6 +99,7 @@ public:
   void __fastcall SetResumeStatus(TResumeStatus AResumeStatus);
   void __fastcall SetTransferSize(__int64 ASize);
   void __fastcall ChangeTransferSize(__int64 ASize);
+  void __fastcall RollbackTransfer();
   void __fastcall SetTotalSize(__int64 ASize);
   void __fastcall Start(TFileOperation AOperation,
     TOperationSide ASide, int ACount, bool ATemp = false,

+ 4 - 0
core/FileSystems.h

@@ -9,6 +9,7 @@ class TRights;
 class TRemoteFile;
 class TRemoteFileList;
 struct TCopyParamType;
+struct TSpaceAvailable;
 class TFileOperationProgressType;
 class TRemoteProperties;
 //---------------------------------------------------------------------------
@@ -35,6 +36,7 @@ public:
   virtual void __fastcall CachedChangeDirectory(const AnsiString Directory) = 0;
   virtual void __fastcall ChangeFileProperties(const AnsiString FileName,
     const TRemoteFile * File, const TRemoteProperties * Properties) = 0;
+  virtual bool __fastcall LoadFilesProperties(TStrings * FileList) = 0;
   virtual void __fastcall CopyToLocal(TStrings * FilesToCopy,
     const AnsiString TargetDir, const TCopyParamType * CopyParam,
     int Params, TFileOperationProgressType * OperationProgress,
@@ -67,6 +69,8 @@ public:
     const AnsiString NewName) = 0;
   virtual AnsiString __fastcall FileUrl(const AnsiString FileName) = 0;
   virtual TStrings * __fastcall GetFixedPaths() = 0;
+  virtual void __fastcall SpaceAvailable(const AnsiString Path,
+    TSpaceAvailable & ASpaceAvailable) = 0;
 
   __property AnsiString CurrentDirectory = { read = GetCurrentDirectory, write = SetCurrentDirectory };
   __property AnsiString ProtocolName = { read = GetProtocolName };

+ 4 - 4
core/HierarchicalStorage.cpp

@@ -448,11 +448,11 @@ void __fastcall TRegistryStorage::WriteInt64(const AnsiString Name, __int64 Valu
 }
 //---------------------------------------------------------------------------
 void __fastcall TRegistryStorage::WriteBinaryData(const AnsiString Name,
-  void * Buffer, int Size)
+  const void * Buffer, int Size)
 {
   try
   {
-    FRegistry->WriteBinaryData(Name, Buffer, Size);
+    FRegistry->WriteBinaryData(Name, const_cast<void *>(Buffer), Size);
   }
   catch(...)
   {
@@ -695,7 +695,7 @@ void __fastcall TIniFileStorage::WriteStringRaw(const AnsiString Name, const Ans
 }
 //---------------------------------------------------------------------------
 void __fastcall TIniFileStorage::WriteBinaryData(const AnsiString Name,
-  void * Buffer, int Size)
+  const void * Buffer, int Size)
 {
-  WriteStringRaw(Name, StrToHex(AnsiString(static_cast<char*>(Buffer), Size)));
+  WriteStringRaw(Name, StrToHex(AnsiString(static_cast<const char*>(Buffer), Size)));
 }

+ 3 - 3
core/HierarchicalStorage.h

@@ -48,7 +48,7 @@ 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 WriteBinaryData(const AnsiString Name, const void * Buffer, int Size) = 0;
 
   virtual void __fastcall WriteString(const AnsiString Name, const AnsiString Value);
   void __fastcall WriteBinaryData(const AnsiString Name, const AnsiString Value);
@@ -99,7 +99,7 @@ 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 WriteBinaryData(const AnsiString Name, const void * Buffer, int Size);
 
   virtual void __fastcall GetValueNames(Classes::TStrings* Strings);
 
@@ -145,7 +145,7 @@ 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 WriteBinaryData(const AnsiString Name, const void * Buffer, int Size);
 
   virtual void __fastcall GetValueNames(Classes::TStrings* Strings);
 

+ 2 - 0
core/Interface.h

@@ -52,6 +52,8 @@ struct TQueryParams
   TQueryParamsTimerEvent TimerEvent;
   AnsiString TimerMessage;
   unsigned int TimerAnswers;
+  unsigned int Timeout;
+  unsigned int TimeoutAnswer;
   AnsiString HelpKeyword;
 };
 

+ 4 - 2
core/Net.cpp

@@ -145,10 +145,12 @@ void SSHOldKeyfileWarning(void)
   // no reference to TSecureShell instace available
 }
 //---------------------------------------------------------------------------
-void SSHDisplayBanner(void * frontend, const char * banner, int size)
+void SSHDisplayBanner(void * frontend, const char * banner, int size, int * log)
 {
   assert(frontend);
   AnsiString Banner(banner, size);
-  ((TSecureShell *)frontend)->DisplayBanner(Banner);
+  bool Log = (*log != 0);
+  ((TSecureShell *)frontend)->DisplayBanner(Banner, Log);
+  *log = (Log ? 1 : 0);
 }
 

+ 3 - 3
core/PuttyIntf.c

@@ -28,7 +28,7 @@ void SSHConnectionFatal(void * frontend, char * string);
 void SSHVerifyHostKey(void * frontend, char *host, int port, char * keytype,
   char * keystr, char * fingerprint);
 void SSHOldKeyfileWarning(void);
-void SSHDisplayBanner(void * frontend, const char * banner, int size);
+void SSHDisplayBanner(void * frontend, const char * banner, int size, int * log);
 void SSHAskAlg(void * frontend, const char * AlgType, const char * AlgName);
 long RegOpenWinSCPKey(HKEY hKey, const char * lpSubKey, HKEY * phkResult);
 long RegCreateWinSCPKey(HKEY hKey, const char * lpSubKey, HKEY * phkResult);
@@ -196,9 +196,9 @@ void set_busy_status(void * frontend, int status)
   // nothing
 }
 //---------------------------------------------------------------------------
-void display_banner(void * frontend, const char * banner, int size)
+void display_banner(void * frontend, const char * banner, int size, int * log)
 {
-  SSHDisplayBanner(frontend, banner, size);
+  SSHDisplayBanner(frontend, banner, size, log);
 }
 //---------------------------------------------------------------------------
 #pragma option pop // -w-par

+ 2 - 2
core/PuttyIntf.h

@@ -22,7 +22,7 @@ extern "C"
   void random_save_seed(void);
   int verify_host_key(char * hostname, int port, char * keytype, char * key);
   void store_host_key(char * hostname, int port, char * keytype, char * key);
-  void display_banner(void * frontend, const char * banner, int size);
+  void display_banner(void * frontend, const char * banner, int size, int * log);
   void md5checksum(const char * buffer, int len, unsigned char output[16]);
   void * saferealloc(void * ptr, size_t n, size_t size);
   void * safemalloc(size_t n, size_t size);
@@ -87,7 +87,7 @@ extern "C"
   void SSHFatalError(char * string);
   void SSHAskAlg(void * frontend, const char * AlgType, const char * AlgName);
   void SSHOldKeyfileWarning(void);
-  void SSHDisplayBanner(void * frontend, const char * banner, int size);
+  void SSHDisplayBanner(void * frontend, const char * banner, int size, int * log);
   long RegOpenWinSCPKey(HKEY hKey, const char * lpSubKey, HKEY * phkResult);
   long RegCreateWinSCPKey(HKEY hKey, const char * lpSubKey, HKEY * phkResult);
   long RegQueryWinSCPValueEx(HKEY Key, const char * ValueName, unsigned long * Reserved,

+ 103 - 30
core/Queue.cpp

@@ -8,9 +8,12 @@
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
+class TBackgroundTerminal;
+//---------------------------------------------------------------------------
 class TTerminalItem : public TSignalThread
 {
 friend class TQueueItem;
+friend class TBackgroundTerminal;
 
 public:
   __fastcall TTerminalItem(TTerminalQueue * Queue);
@@ -51,7 +54,7 @@ protected:
   };
 
   TTerminalQueue * FQueue;
-  TTerminal * FTerminal;
+  TBackgroundTerminal * FTerminal;
   TQueueItem * FItem;
   TCriticalSection * FCriticalSection;
   void * FUserActionParams;
@@ -61,6 +64,7 @@ protected:
   virtual void __fastcall ProcessEvent();
   virtual void __fastcall Finished();
   bool __fastcall WaitForUserAction(TQueueItem::TStatus ItemStatus, void * Params);
+  bool __fastcall OverrideItemStatus(TQueueItem::TStatus & ItemStatus);
 
   void __fastcall TerminalClose(TObject * Sender);
   void __fastcall TerminalQueryUser(TObject * Sender,
@@ -756,6 +760,41 @@ bool __fastcall TTerminalQueue::GetIsEmpty()
   return (FItems->Count == 0);
 }
 //---------------------------------------------------------------------------
+// TBackgroundItem
+//---------------------------------------------------------------------------
+class TBackgroundTerminal : public TSecondaryTerminal
+{
+public:
+  __fastcall TBackgroundTerminal(TTerminal * MainTerminal, TTerminalItem * Item);
+
+protected:
+  virtual bool __fastcall DoQueryReopen(Exception * E, int Params);
+  
+private:
+  TTerminalItem * FItem;
+};
+//---------------------------------------------------------------------------
+__fastcall TBackgroundTerminal::TBackgroundTerminal(TTerminal * MainTerminal,
+    TTerminalItem * Item) :
+  TSecondaryTerminal(MainTerminal), FItem(Item)
+{
+}
+//---------------------------------------------------------------------------
+bool __fastcall TBackgroundTerminal::DoQueryReopen(Exception * E, int Params)
+{
+  bool Result;
+  if (FItem->FTerminated || FItem->FCancel)
+  {
+    // avoid reconnection if we are closing
+    Result = false;
+  }
+  else
+  {
+    Result = TSecondaryTerminal::DoQueryReopen(E, Params);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 // TTerminalItem
 //---------------------------------------------------------------------------
 __fastcall TTerminalItem::TTerminalItem(TTerminalQueue * Queue) :
@@ -764,7 +803,7 @@ __fastcall TTerminalItem::TTerminalItem(TTerminalQueue * Queue) :
 {
   FCriticalSection = new TCriticalSection();
 
-  FTerminal = new TSecondaryTerminal(FQueue->FTerminal);
+  FTerminal = new TBackgroundTerminal(FQueue->FTerminal, this);
   try
   {
     FTerminal->UseBusyCursor = false;
@@ -829,7 +868,6 @@ void __fastcall TTerminalItem::ProcessEvent()
 
       FTerminal->SessionData->RemoteDirectory = FItem->StartupDirectory();
       FTerminal->Open();
-      FTerminal->DoStartup();
     }
 
     Retry = false;
@@ -843,7 +881,12 @@ void __fastcall TTerminalItem::ProcessEvent()
   }
   catch(Exception & E)
   {
-    FTerminal->DoShowExtendedException(&E);
+    // do not show error messages, if task was canceled anyway
+    // (for example if transfer is cancelled during reconnection attempts)
+    if (!FCancel)
+    {
+      FTerminal->DoShowExtendedException(&E);
+    }
   }
 
   FItem->SetStatus(TQueueItem::qsDone);
@@ -1012,21 +1055,26 @@ void __fastcall TTerminalItem::TerminalQueryUser(TObject * Sender,
   const AnsiString Query, TStrings * MoreMessages, int Answers,
   const TQueryParams * Params, int & Answer, TQueryType Type, void * Arg)
 {
-  USEDPARAM(Arg);
-  assert(Arg == NULL);
+  // so far query without queue item can occur only for key cofirmation
+  // on re-key with non-cached host key. make it fail.
+  if (FItem != NULL)
+  {
+    USEDPARAM(Arg);
+    assert(Arg == NULL);
 
-  TQueryUserRec QueryUserRec;
-  QueryUserRec.Sender = Sender;
-  QueryUserRec.Query = Query;
-  QueryUserRec.MoreMessages = MoreMessages;
-  QueryUserRec.Answers = Answers;
-  QueryUserRec.Params = Params;
-  QueryUserRec.Answer = Answer;
-  QueryUserRec.Type = Type;
+    TQueryUserRec QueryUserRec;
+    QueryUserRec.Sender = Sender;
+    QueryUserRec.Query = Query;
+    QueryUserRec.MoreMessages = MoreMessages;
+    QueryUserRec.Answers = Answers;
+    QueryUserRec.Params = Params;
+    QueryUserRec.Answer = Answer;
+    QueryUserRec.Type = Type;
 
-  if (WaitForUserAction(TQueueItem::qsQuery, &QueryUserRec))
-  {
-    Answer = QueryUserRec.Answer;
+    if (WaitForUserAction(TQueueItem::qsQuery, &QueryUserRec))
+    {
+      Answer = QueryUserRec.Answer;
+    }
   }
 }
 //---------------------------------------------------------------------------
@@ -1034,20 +1082,29 @@ void __fastcall TTerminalItem::TerminalPromptUser(TSecureShell * SecureShell,
   AnsiString Prompt, TPromptKind Kind, AnsiString & Response, bool & Result, 
   void * Arg)
 {
-  USEDPARAM(Arg);
-  assert(Arg == NULL);
+  if (FItem == NULL)
+  {
+    // sanity, should not occur
+    assert(false);
+    Result = false;
+  }
+  else
+  {
+    USEDPARAM(Arg);
+    assert(Arg == NULL);
 
-  TPromptUserRec PromptUserRec;
-  PromptUserRec.SecureShell = SecureShell;
-  PromptUserRec.Prompt = Prompt;
-  PromptUserRec.Kind = Kind;
-  PromptUserRec.Response = Response.c_str();
-  PromptUserRec.Result = Result;
+    TPromptUserRec PromptUserRec;
+    PromptUserRec.SecureShell = SecureShell;
+    PromptUserRec.Prompt = Prompt;
+    PromptUserRec.Kind = Kind;
+    PromptUserRec.Response = Response.c_str();
+    PromptUserRec.Result = Result;
 
-  if (WaitForUserAction(TQueueItem::qsPrompt, &PromptUserRec))
-  {
-    Response = PromptUserRec.Response.c_str();
-    Result = PromptUserRec.Result;
+    if (WaitForUserAction(TQueueItem::qsPrompt, &PromptUserRec))
+    {
+      Response = PromptUserRec.Response.c_str();
+      Result = PromptUserRec.Result;
+    }
   }
 }
 //---------------------------------------------------------------------------
@@ -1057,7 +1114,8 @@ void __fastcall TTerminalItem::TerminalShowExtendedException(
   USEDPARAM(Arg);
   assert(Arg == NULL);
 
-  if (!E->Message.IsEmpty() &&
+  if ((FItem != NULL) &&
+      !E->Message.IsEmpty() &&
       (dynamic_cast<EAbort*>(E) == NULL))
   {
     TShowExtendedExceptionRec ShowExtendedExceptionRec;
@@ -1116,6 +1174,17 @@ void __fastcall TTerminalItem::OperationProgress(
   FItem->SetProgress(ProgressData);
 }
 //---------------------------------------------------------------------------
+bool __fastcall TTerminalItem::OverrideItemStatus(TQueueItem::TStatus & ItemStatus)
+{
+  assert(FTerminal != NULL);
+  bool Result = (FTerminal->Status < sshReady) && (ItemStatus == TQueueItem::qsProcessing);
+  if (Result)
+  {
+    ItemStatus = TQueueItem::qsConnecting;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 // TQueueItem
 //---------------------------------------------------------------------------
 __fastcall TQueueItem::TQueueItem() :
@@ -1192,6 +1261,10 @@ void __fastcall TQueueItem::GetData(TQueueItemProxy * Proxy)
   }
   *Proxy->FInfo = *FInfo;
   Proxy->FStatus = FStatus;
+  if (FTerminalItem != NULL)
+  {
+    FTerminalItem->OverrideItemStatus(Proxy->FStatus);
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TQueueItem::Execute(TTerminalItem * TerminalItem)

+ 106 - 32
core/RemoteFiles.cpp

@@ -303,6 +303,50 @@ void __fastcall ReduceDateTimePrecision(TDateTime & DateTime,
     DateTime = EncodeDate(Y, M, D) + EncodeTime(H, N, S, MS);
   }
 }
+//---------------------------------------------------------------------------
+AnsiString __fastcall UserModificationStr(TDateTime DateTime,
+  TModificationFmt Precision)
+{
+  switch (Precision)
+  {
+    case mfMDY:
+      return FormatDateTime("ddddd", DateTime);
+    case mfMDHM:
+      return FormatDateTime("ddddd t", DateTime);
+    case mfFull:
+    default:
+      return FormatDateTime("ddddd tt", DateTime);
+  }
+}
+//---------------------------------------------------------------------------
+int __fastcall FakeFileImageIndex(AnsiString FileName, unsigned long Attrs,
+  AnsiString * TypeName)
+{
+  Attrs |= FILE_ATTRIBUTE_NORMAL;
+
+  TSHFileInfo SHFileInfo;
+  // On Win2k we get icon of "ZIP drive" for ".." (parent directory)
+  if (FileName == "..")
+  {
+    FileName = "dumb";
+  }
+  // this should be somewhere else, probably in TUnixDirView,
+  // as the "partial" overlay is added there too
+  if (AnsiSameText(UnixExtractFileExt(FileName), PARTIAL_EXT))
+  {
+    static const size_t PartialExtLen = sizeof(PARTIAL_EXT) - 1;
+    FileName.SetLength(FileName.Length() - PartialExtLen);
+  }
+
+  SHGetFileInfo(FileName.c_str(),
+    Attrs, &SHFileInfo, sizeof(SHFileInfo),
+    SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME);
+  if (TypeName != NULL)
+  {
+    *TypeName = SHFileInfo.szTypeName;
+  }
+  return SHFileInfo.iIcon;
+}
 //- TRemoteFiles ------------------------------------------------------------
 __fastcall TRemoteFile::TRemoteFile(TRemoteFile * ALinkedByFile):
   TPersistent()
@@ -324,7 +368,7 @@ __fastcall TRemoteFile::~TRemoteFile()
   delete FLinkedFile;
 }
 //---------------------------------------------------------------------------
-TRemoteFile * __fastcall TRemoteFile::Duplicate(bool Standalone)
+TRemoteFile * __fastcall TRemoteFile::Duplicate(bool Standalone) const
 {
   TRemoteFile * Result;
   Result = new TRemoteFile();
@@ -370,35 +414,21 @@ TRemoteFile * __fastcall TRemoteFile::Duplicate(bool Standalone)
 void __fastcall TRemoteFile::LoadTypeInfo()
 {
   /* TODO : If file is link: Should be attributes taken from linked file? */
-  unsigned long Attrs = FILE_ATTRIBUTE_NORMAL;
+  unsigned long Attrs = 0;
   if (IsDirectory) Attrs |= FILE_ATTRIBUTE_DIRECTORY;
   if (IsHidden) Attrs |= FILE_ATTRIBUTE_HIDDEN;
 
-  TSHFileInfo SHFileInfo;
   AnsiString DumbFileName = (IsSymLink && !LinkTo.IsEmpty() ? LinkTo : FileName);
-  // On Win2k we get icon of "ZIP drive" for ".." (parent directory)
-  if (DumbFileName == "..") DumbFileName = "dumb";
-  // this should be somewhere else, probably in TUnixDirView,
-  // as the "partial" overlay is added there too
-  if (AnsiSameText(UnixExtractFileExt(DumbFileName), PARTIAL_EXT))
-  {
-    static const size_t PartialExtLen = sizeof(PARTIAL_EXT) - 1;
-    DumbFileName.SetLength(DumbFileName.Length() - PartialExtLen);
-  }
 
-  SHGetFileInfo(DumbFileName.c_str(),
-    Attrs, &SHFileInfo, sizeof(SHFileInfo),
-    SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME);
-  FIconIndex = SHFileInfo.iIcon;
-  FTypeName = SHFileInfo.szTypeName;
+  FIconIndex = FakeFileImageIndex(DumbFileName, Attrs, &FTypeName);
 }
 //---------------------------------------------------------------------------
-Integer __fastcall TRemoteFile::GetIconIndex()
+Integer __fastcall TRemoteFile::GetIconIndex() const
 {
   assert(FIconIndex >= -1);
   if (FIconIndex < 0)
   {
-    LoadTypeInfo();
+    const_cast<TRemoteFile *>(this)->LoadTypeInfo();
   }
   return FIconIndex;
 }
@@ -533,16 +563,7 @@ void __fastcall TRemoteFile::SetModification(const TDateTime & value)
 //---------------------------------------------------------------------------
 AnsiString __fastcall TRemoteFile::GetUserModificationStr()
 {
-  switch (FModificationFmt)
-  {
-    case mfMDY:
-      return FormatDateTime("ddddd", Modification);
-    case mfMDHM:
-      return FormatDateTime("ddddd t", Modification);
-    case mfFull:
-    default:
-      return FormatDateTime("ddddd tt", Modification);
-  }
+  return ::UserModificationStr(Modification, FModificationFmt);
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TRemoteFile::GetModificationStr()
@@ -581,7 +602,7 @@ void __fastcall TRemoteFile::SetRights(TRights * value)
 //---------------------------------------------------------------------------
 AnsiString __fastcall TRemoteFile::GetRightsStr()
 {
-  return FRights->Text;
+  return FRights->Unknown ? AnsiString() : FRights->Text;
 }
 //---------------------------------------------------------------------------
 void __fastcall TRemoteFile::SetListingStr(AnsiString value)
@@ -910,6 +931,11 @@ AnsiString __fastcall TRemoteFile::GetFullFileName() const
   }
 }
 //---------------------------------------------------------------------------
+bool __fastcall TRemoteFile::GetHaveFullFileName() const
+{
+  return !FFullFileName.IsEmpty() || (Directory != NULL);
+}
+//---------------------------------------------------------------------------
 Integer __fastcall TRemoteFile::GetAttr()
 {
   Integer Result = 0;
@@ -1308,11 +1334,17 @@ void __fastcall TRemoteDirectoryChangesCache::ClearDirectoryChange(
 void __fastcall TRemoteDirectoryChangesCache::ClearDirectoryChangeTarget(
   AnsiString TargetDir)
 {
+  AnsiString Key;
+  // hack to clear at least local sym-link change in case symlink is deleted
+  DirectoryChangeKey(UnixExcludeTrailingBackslash(UnixExtractFilePath(TargetDir)),
+    UnixExtractFileName(TargetDir), Key);
+
   for (int Index = 0; Index < Count; Index++)
   {
     AnsiString Name = Names[Index];
     if ((Name.SubString(1, TargetDir.Length()) == TargetDir) ||
-        (Values[Name].SubString(1, TargetDir.Length()) == TargetDir))
+        (Values[Name].SubString(1, TargetDir.Length()) == TargetDir) ||
+        (!Key.IsEmpty() && (Name == Key)))
     {
       Delete(Index);
       Index--;
@@ -1396,6 +1428,7 @@ __fastcall TRights::TRights()
   FSet = 0;
   FUnset = 0;
   Number = 0;
+  FUnknown = true;
 }
 //---------------------------------------------------------------------------
 __fastcall TRights::TRights(unsigned short ANumber)
@@ -1417,6 +1450,7 @@ void __fastcall TRights::Assign(const TRights * Source)
   FSet = Source->FSet;
   FUnset = Source->FUnset;
   FText = Source->FText;
+  FUnknown = Source->FUnknown;
 }
 //---------------------------------------------------------------------------
 TRights::TFlag __fastcall TRights::RightToFlag(TRights::TRight Right)
@@ -1601,6 +1635,7 @@ void __fastcall TRights::SetText(const AnsiString & value)
 
     FText = KeepText ? value : AnsiString();
   }
+  FUnknown = false;
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TRights::GetText() const
@@ -1688,6 +1723,7 @@ void __fastcall TRights::SetOctal(AnsiString value)
       ((AValue[3] - '0') << 3) +
       ((AValue[4] - '0') << 0));
   }
+  FUnknown = false;
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TRights::GetOctal() const
@@ -1711,6 +1747,7 @@ void __fastcall TRights::SetNumber(unsigned short value)
     FUnset = static_cast<unsigned short>(rfAllSpecials & ~FSet);
     FText = "";
   }
+  FUnknown = false;
 }
 //---------------------------------------------------------------------------
 unsigned short __fastcall TRights::GetNumber() const
@@ -1760,6 +1797,7 @@ void __fastcall TRights::SetRightUndef(TRight Right, TState value)
 
     FText = "";
   }
+  FUnknown = false;
 }
 //---------------------------------------------------------------------------
 TRights::TState __fastcall TRights::GetRightUndef(TRight Right) const
@@ -1869,6 +1907,7 @@ void __fastcall TRights::AddExecute()
       Right[static_cast<TRight>(rrUserExec + (Group * 3))] = true;
     }
   }
+  FUnknown = false;
 }
 //---------------------------------------------------------------------------
 void __fastcall TRights::AllUndef()
@@ -1879,6 +1918,7 @@ void __fastcall TRights::AllUndef()
     FUnset = 0;
     FText = "";
   }
+  FUnknown = false;
 }
 //---------------------------------------------------------------------------
 bool __fastcall TRights::GetIsUndef() const
@@ -1897,6 +1937,11 @@ __fastcall TRights::operator unsigned long() const
 }
 //=== TRemoteProperties -------------------------------------------------------
 __fastcall TRemoteProperties::TRemoteProperties()
+{
+  Default();
+}
+//---------------------------------------------------------------------------
+void __fastcall TRemoteProperties::Default()
 {
   Valid.Clear();
   AddXToDirectories = false;
@@ -1905,7 +1950,7 @@ __fastcall TRemoteProperties::TRemoteProperties()
   Group = "";
   Owner = "";
   Recursive = false;
-};
+}
 //---------------------------------------------------------------------------
 bool __fastcall TRemoteProperties::operator ==(const TRemoteProperties & rhp) const
 {
@@ -2001,4 +2046,33 @@ TRemoteProperties __fastcall TRemoteProperties::ChangedProperties(
   }
   return NewProperties;
 }
+//---------------------------------------------------------------------------
+void __fastcall TRemoteProperties::Load(THierarchicalStorage * Storage)
+{
+  unsigned char Buf[sizeof(Valid)];
+  if (Storage->ReadBinaryData("Valid", &Buf, sizeof(Buf)) == sizeof(Buf))
+  {
+    memcpy(&Valid, Buf, sizeof(Valid));
+  }
+
+  if (Valid.Contains(vpRights))
+  {
+    Rights.Text = Storage->ReadString("Rights", Rights.Text);
+  }
+
+  // TODO
+}
+//---------------------------------------------------------------------------
+void __fastcall TRemoteProperties::Save(THierarchicalStorage * Storage) const
+{
+  Storage->WriteBinaryData(AnsiString("Valid"),
+    static_cast<const void *>(&Valid), sizeof(Valid));
+  
+  if (Valid.Contains(vpRights))
+  {
+    Storage->WriteString("Rights", Rights.Text);
+  }
+
+  // TODO
+}
 

+ 14 - 2
core/RemoteFiles.h

@@ -15,6 +15,7 @@ enum TModificationFmt { mfMDHM, mfMDY, mfFull };
 class TTerminal;
 class TRights;
 class TRemoteFileList;
+class THierarchicalStorage;
 //---------------------------------------------------------------------------
 class TRemoteFile : public TPersistent
 {
@@ -56,7 +57,8 @@ private:
   void __fastcall SetTerminal(TTerminal * value);
   void __fastcall SetRights(TRights * value);
   AnsiString __fastcall GetFullFileName() const;
-  int __fastcall GetIconIndex();
+  bool __fastcall GetHaveFullFileName() const;
+  int __fastcall GetIconIndex() const;
   AnsiString __fastcall GetTypeName();
   bool __fastcall GetIsHidden();
   void __fastcall SetIsHidden(bool value);
@@ -73,7 +75,7 @@ protected:
 public:
   __fastcall TRemoteFile(TRemoteFile * ALinkedByFile = NULL);
   virtual __fastcall ~TRemoteFile();
-  TRemoteFile * __fastcall Duplicate(bool Standalone = true);
+  TRemoteFile * __fastcall Duplicate(bool Standalone = true) const;
 
   void __fastcall ShiftTime(const TDateTime & Difference);
   void __fastcall Complete();
@@ -102,6 +104,7 @@ public:
   __property Char Type = { read = GetType, write = SetType };
   __property bool Selected  = { read=FSelected, write=FSelected };
   __property AnsiString FullFileName  = { read = GetFullFileName, write = FFullFileName };
+  __property bool HaveFullFileName  = { read = GetHaveFullFileName };
   __property int IconIndex = { read = GetIconIndex };
   __property AnsiString TypeName = { read = GetTypeName };
   __property bool IsHidden = { read = GetIsHidden, write = SetIsHidden };
@@ -298,12 +301,14 @@ public:
   __property bool Right[TRight Right] = { read = GetRight, write = SetRight };
   __property TState RightUndef[TRight Right] = { read = GetRightUndef, write = SetRightUndef };
   __property AnsiString Text = { read = GetText, write = SetText };
+  __property bool Unknown = { read = FUnknown };
 
 private:
   bool FAllowUndef;
   unsigned short FSet;
   unsigned short FUnset;
   AnsiString FText;
+  bool FUnknown;
 
   bool __fastcall GetIsUndef() const;
   AnsiString __fastcall GetModeStr() const;
@@ -342,6 +347,9 @@ public:
   __fastcall TRemoteProperties();
   bool __fastcall operator ==(const TRemoteProperties & rhp) const;
   bool __fastcall operator !=(const TRemoteProperties & rhp) const;
+  void __fastcall Default();
+  void __fastcall Load(THierarchicalStorage * Storage);
+  void __fastcall Save(THierarchicalStorage * Storage) const;
 
   static TRemoteProperties __fastcall CommonProperties(TStrings * FileList);
   static TRemoteProperties __fastcall ChangedProperties(
@@ -366,5 +374,9 @@ AnsiString __fastcall MinimizeName(const AnsiString FileName, int MaxLen, bool U
 AnsiString __fastcall MakeFileList(TStrings * FileList);
 void __fastcall ReduceDateTimePrecision(TDateTime & DateTime,
   TModificationFmt Precision);
+AnsiString __fastcall UserModificationStr(TDateTime DateTime,
+  TModificationFmt Precision);
+int __fastcall FakeFileImageIndex(AnsiString FileName, unsigned long Attrs = 0,
+  AnsiString * TypeName = NULL);
 //---------------------------------------------------------------------------
 #endif

+ 41 - 22
core/ScpFileSystem.cpp

@@ -104,7 +104,7 @@ const char FullTimeOption[] = "--full-time";
 //---------------------------------------------------------------------------
 #define F false
 #define T true
-// TODO: remove "mf" and "cd", it is implemented in TTerminal already 
+// TODO: remove "mf" and "cd", it is implemented in TTerminal already
 const TCommandType DefaultCommandSet[ShellCommandCount] = {
 //                       min max mf cd ia  command
 /*Null*/                { -1, -1, F, F, F, "" },
@@ -308,11 +308,11 @@ AnsiString __fastcall TSCPFileSystem::AbsolutePath(AnsiString Path)
     {
       int P2 = Result.SubString(1, P-1).LastDelimiter("/");
       assert(P2 > 0);
-      Result.Delete(P2, P - P2 + 3); 
+      Result.Delete(P2, P - P2 + 3);
     }
     while ((P = Result.Pos("/./")) > 0)
     {
-      Result.Delete(P, 2); 
+      Result.Delete(P, 2);
     }
     Result = UnixExcludeTrailingBackslash(Result);
   }
@@ -342,6 +342,9 @@ bool __fastcall TSCPFileSystem::IsCapable(int Capability) const
     case fcNativeTextMode:
     case fcNewerOnlyUpload:
     case fcTimestampChanging:
+    case fcLoadingAdditionalProperties:
+    case fcCheckingSpaceAvailable:
+    case fcIgnorePermErrors:
       return false;
 
     default:
@@ -529,13 +532,13 @@ void __fastcall TSCPFileSystem::ReadCommandOutput(int Params)
       {
         Line = FTerminal->ReceiveLine();
         IsLast = IsLastLine(Line);
-        if (!IsLast || !Line.IsEmpty()) 
+        if (!IsLast || !Line.IsEmpty())
         {
           FOutput->Add(Line);
           if (FLAGSET(Params, coReadProgress))
           {
             Total++;
-          
+
             if (Total % 10 == 0)
             {
               FTerminal->DoReadDirectoryProgress(Total);
@@ -1054,8 +1057,11 @@ void __fastcall TSCPFileSystem::CreateDirectory(const AnsiString DirName,
   const TRemoteProperties * Properties)
 {
   USEDPARAM(Properties);
-  assert(!Properties); // not implemented yet
   ExecCommand(fsCreateDirectory, ARRAYOFCONST((DelimitStr(DirName))));
+  if (Properties != NULL)
+  {
+    ChangeFileProperties(DirName, NULL, Properties);
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::CreateLink(const AnsiString FileName,
@@ -1074,6 +1080,17 @@ void __fastcall TSCPFileSystem::ChangeFileProperties(const AnsiString FileName,
   AnsiString RecursiveStr = Recursive ? "-R" : "";
 
   AnsiString DelimitedName = DelimitStr(FileName);
+  // change group before permissions as chgrp change permissions
+  if (Properties->Valid.Contains(vpGroup))
+  {
+    ExecCommand(fsChangeGroup,
+      ARRAYOFCONST((RecursiveStr, Properties->Group, DelimitedName)));
+  }
+  if (Properties->Valid.Contains(vpOwner))
+  {
+    ExecCommand(fsChangeOwner,
+      ARRAYOFCONST((RecursiveStr, DelimitStr(Properties->Owner), DelimitedName)));
+  }
   if (Properties->Valid.Contains(vpRights))
   {
     TRights Rights = Properties->Rights;
@@ -1095,22 +1112,18 @@ void __fastcall TSCPFileSystem::ChangeFileProperties(const AnsiString FileName,
         ARRAYOFCONST(("", Rights.SimplestStr, DelimitedName)));
     }
   }
-  if (Properties->Valid.Contains(vpGroup))
-  {
-    ExecCommand(fsChangeGroup,
-      ARRAYOFCONST((RecursiveStr, Properties->Group, DelimitedName)));
-  }
-  if (Properties->Valid.Contains(vpOwner))
-  {
-    ExecCommand(fsChangeOwner,
-      ARRAYOFCONST((RecursiveStr, DelimitStr(Properties->Owner), DelimitedName)));
-  }
   assert(!Properties->Valid.Contains(vpLastAccess));
   assert(!Properties->Valid.Contains(vpModification));
 }
 //---------------------------------------------------------------------------
+bool __fastcall TSCPFileSystem::LoadFilesProperties(TStrings * /*FileList*/ )
+{
+  assert(false);
+  return false;
+}
+//---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::CustomCommandOnFile(const AnsiString FileName,
-    const TRemoteFile * File, AnsiString Command, int Params, 
+    const TRemoteFile * File, AnsiString Command, int Params,
     TLogAddLineEvent OutputEvent)
 {
   assert(File);
@@ -1173,8 +1186,8 @@ void __fastcall TSCPFileSystem::AnyCommand(const AnsiString Command,
 AnsiString __fastcall TSCPFileSystem::FileUrl(const AnsiString FileName)
 {
   assert(FileName.Length() > 0);
-  return AnsiString("scp://") + FTerminal->SessionData->SessionName + 
-    (FileName[1] == '/' ? "" : "/") + FileName;
+  return AnsiString("scp://") + EncodeUrlChars(FTerminal->SessionData->SessionName) +
+    (FileName[1] == '/' ? "" : "/") + EncodeUrlChars(FileName, "/");
 }
 //---------------------------------------------------------------------------
 TStrings * __fastcall TSCPFileSystem::GetFixedPaths()
@@ -1182,6 +1195,12 @@ TStrings * __fastcall TSCPFileSystem::GetFixedPaths()
   return NULL;
 }
 //---------------------------------------------------------------------------
+void __fastcall TSCPFileSystem::SpaceAvailable(const AnsiString Path,
+  TSpaceAvailable & /*ASpaceAvailable*/)
+{
+  assert(false);
+}
+//---------------------------------------------------------------------------
 // transfer protocol
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::SCPResponse(bool * GotLastLine)
@@ -1505,7 +1524,7 @@ void __fastcall TSCPFileSystem::SCPSource(const AnsiString FileName,
   try
   {
     assert(File);
-    
+
     // File is regular file (not directory)
     FTerminal->LogEvent(FORMAT("Copying \"%s\" to remote directory started.", (FileName)));
 
@@ -1699,7 +1718,7 @@ void __fastcall TSCPFileSystem::SCPSource(const AnsiString FileName,
 
   /* TODO : Delete also read-only files. */
   /* TODO : Show error message on failure. */
-  if (FLAGSET(Params, cpDelete)) 
+  if (FLAGSET(Params, cpDelete))
   {
     Sysutils::DeleteFile(FileName);
   }
@@ -1796,7 +1815,7 @@ void __fastcall TSCPFileSystem::SCPDirectorySource(const AnsiString DirectoryNam
     /* TODO : Show error message on failure. */
     if (!OperationProgress->Cancel)
     {
-      if (FLAGSET(Params, cpDelete)) 
+      if (FLAGSET(Params, cpDelete))
       {
         RemoveDir(DirectoryName);
       }

+ 3 - 0
core/ScpFileSystem.h

@@ -20,6 +20,7 @@ public:
   virtual void __fastcall CachedChangeDirectory(const AnsiString Directory);
   virtual void __fastcall ChangeFileProperties(const AnsiString FileName,
     const TRemoteFile * File, const TRemoteProperties * Properties);
+  virtual bool __fastcall LoadFilesProperties(TStrings * FileList);
   virtual void __fastcall CopyToLocal(TStrings * FilesToCopy,
     const AnsiString TargetDir, const TCopyParamType * CopyParam,
     int Params, TFileOperationProgressType * OperationProgress,
@@ -52,6 +53,8 @@ public:
     const AnsiString NewName);
   virtual AnsiString __fastcall FileUrl(const AnsiString FileName);
   virtual TStrings * __fastcall GetFixedPaths();
+  virtual void __fastcall SpaceAvailable(const AnsiString Path,
+    TSpaceAvailable & ASpaceAvailable);
 
 protected:
   __property TStrings * Output = { read = FOutput };

+ 5 - 2
core/ScpMain.cpp

@@ -66,9 +66,12 @@ TQueryParams::TQueryParams(unsigned int AParams, AnsiString AHelpKeyword)
   Params = AParams;
   Aliases = NULL;
   AliasesCount = 0;
-  Timer = NULL;
+  Timer = 0;
   TimerEvent = NULL;
+  TimerMessage = "";
   TimerAnswers = 0;
+  Timeout = 0;
+  TimeoutAnswer = 0;
   HelpKeyword = AHelpKeyword;
 }
 //---------------------------------------------------------------------------
@@ -137,7 +140,7 @@ static long OpenWinSCPKey(HKEY Key, const char * SubKey, HKEY * Result, bool Can
     }
     // we expect this to be called only from verify_host_key() or store_host_key()
     assert(RegKey == "SshHostKeys");
-    
+
     THierarchicalStorage * Storage = Configuration->CreateScpStorage(false);
     Storage->AccessMode = (CanCreate ? smReadWrite : smRead);
     if (Storage->OpenSubKey(RegKey, CanCreate))

+ 67 - 36
core/Script.cpp

@@ -466,7 +466,7 @@ TStrings * __fastcall TScript::CreateFileList(TScriptProcParams * Parameters, in
           AnsiString FileDirectory = UnixExtractFilePath(FileName);
           AnsiString Directory = FileDirectory;
           if (Directory.IsEmpty())
-          {               
+          {
             Directory = UnixIncludeTrailingBackslash(FTerminal->CurrentDirectory);
           }
           TRemoteFileList * FileList = NULL;
@@ -495,7 +495,7 @@ TStrings * __fastcall TScript::CreateFileList(TScriptProcParams * Parameters, in
             if (!File->IsThisDirectory && !File->IsParentDirectory &&
                 TFileMasks::SingleMaskMatch(Mask, File->FileName))
             {
-              Result->AddObject(FileDirectory + File->FileName, 
+              Result->AddObject(FileDirectory + File->FileName,
                 FLAGSET(ListType, fltQueryServer) ? File->Duplicate() : NULL);
             }
           }
@@ -509,6 +509,10 @@ TStrings * __fastcall TScript::CreateFileList(TScriptProcParams * Parameters, in
             try
             {
               FTerminal->ReadFile(FileName, File);
+              if (!File->HaveFullFileName)
+              {
+                File->FullFileName = FileName;
+              }
             }
             __finally
             {
@@ -535,11 +539,11 @@ TStrings * __fastcall TScript::CreateFileList(TScriptProcParams * Parameters, in
       }
       delete FileLists;
     }
-  }  
+  }
   return Result;
 }
 //---------------------------------------------------------------------------
-TStrings * __fastcall TScript::CreateLocalFileList(TScriptProcParams * Parameters, 
+TStrings * __fastcall TScript::CreateLocalFileList(TScriptProcParams * Parameters,
   int Start, int End, TFileListType ListType)
 {
   TStrings * Result = new TStringList();
@@ -569,14 +573,14 @@ TStrings * __fastcall TScript::CreateLocalFileList(TScriptProcParams * Parameter
           __finally
           {
             FindClose(SearchRec);
-          }  
+          }
         }
         else
         {
           // not match, let it fail latter however
           Result->Add(FileName);
         }
-      }  
+      }
       else
       {
         Result->Add(FileName);
@@ -607,7 +611,6 @@ void __fastcall TScript::FreeFileList(TStrings * FileList)
 void __fastcall TScript::ConnectTerminal(TTerminal * Terminal)
 {
   Terminal->Open();
-  Terminal->DoStartup();
 }
 //---------------------------------------------------------------------------
 void __fastcall TScript::Print(const AnsiString Str)
@@ -1191,10 +1194,29 @@ void __fastcall TScript::SynchronizeProc(TScriptProcParams * Parameters)
     TCopyParamType CopyParam = FCopyParam;
     CopyParam.CalculateSize = false;
 
-    FTerminal->Synchronize(LocalDirectory, RemoteDirectory,
-      static_cast<TTerminal::TSynchronizeMode>(FSynchronizeMode),
-      &CopyParam, FSynchronizeParams | TTerminal::spNoConfirmation,
-      OnTerminalSynchronizeDirectory, NULL, NULL);
+    int SynchronizeParams = FSynchronizeParams | TTerminal::spNoConfirmation;
+
+    PrintLine(FMTLOAD(SCRIPT_SYNCHRONIZE_COLLECT,
+      (ExcludeTrailingBackslash(LocalDirectory),
+       UnixExcludeTrailingBackslash(RemoteDirectory))));
+
+    TSynchronizeChecklist * Checklist =
+      FTerminal->SynchronizeCollect(LocalDirectory, RemoteDirectory,
+        static_cast<TTerminal::TSynchronizeMode>(FSynchronizeMode),
+        &CopyParam, SynchronizeParams, NULL, NULL);
+    try
+    {
+      if (Checklist->Count > 0)
+      {
+        FTerminal->SynchronizeApply(Checklist, LocalDirectory, RemoteDirectory,
+          &CopyParam, SynchronizeParams, OnTerminalSynchronizeDirectory);
+      }
+    }
+    __finally
+    {
+      delete Checklist;
+    }
+
   }
   __finally
   {
@@ -1204,7 +1226,7 @@ void __fastcall TScript::SynchronizeProc(TScriptProcParams * Parameters)
 //---------------------------------------------------------------------------
 void __fastcall TScript::Synchronize(const AnsiString LocalDirectory,
   const AnsiString RemoteDirectory, const TCopyParamType & ACopyParam,
-  TSynchronizeStats * /*Stats*/)
+  TSynchronizeChecklist ** Checklist)
 {
   try
   {
@@ -1213,13 +1235,35 @@ void __fastcall TScript::Synchronize(const AnsiString LocalDirectory,
     TCopyParamType CopyParam = ACopyParam;
     CopyParam.CalculateSize = false;
 
-    FTerminal->Synchronize(LocalDirectory, RemoteDirectory, TTerminal::smRemote, &CopyParam,
-      FSynchronizeParams | TTerminal::spNoConfirmation | TTerminal::spNoRecurse |
-      TTerminal::spUseCache | TTerminal::spDelayProgress | TTerminal::spSubDirs,
-      OnTerminalSynchronizeDirectory, NULL, NULL);
+    int SynchronizeParams = FSynchronizeParams | TTerminal::spNoConfirmation |
+      TTerminal::spNoRecurse | TTerminal::spUseCache | TTerminal::spDelayProgress |
+      TTerminal::spSubDirs;
+
+    TSynchronizeChecklist * AChecklist =
+      FTerminal->SynchronizeCollect(LocalDirectory, RemoteDirectory, TTerminal::smRemote,
+        &CopyParam, SynchronizeParams, NULL, NULL);
+    try
+    {
+      if (AChecklist->Count > 0)
+      {
+        FTerminal->SynchronizeApply(AChecklist, LocalDirectory, RemoteDirectory,
+          &CopyParam, SynchronizeParams, OnTerminalSynchronizeDirectory);
+      }
+    }
+    __finally
+    {
+      if (Checklist == NULL)
+      {
+        delete AChecklist;
+      }
+      else
+      {
+        *Checklist = AChecklist;
+      }
+    }
 
-    // to break line after the last transfer (if any); 
-    Print("");    
+    // to break line after the last transfer (if any);
+    Print("");
 
     FKeepingUpToDate = false;
   }
@@ -1277,7 +1321,7 @@ __fastcall TManagementScript::TManagementScript(TStoredSessionList * StoredSessi
   FCommands->Register("lpwd", SCRIPT_LPWD_DESC, SCRIPT_LPWD_HELP, &LPwdProc, 0, 0);
   FCommands->Register("lcd", SCRIPT_LCD_DESC, SCRIPT_LCD_HELP, &LCdProc, 1, 1);
   FCommands->Register("lls", SCRIPT_LLS_DESC, SCRIPT_LLS_HELP, &LLsProc, 0, 1);
-}       
+}
 //---------------------------------------------------------------------------
 __fastcall TManagementScript::~TManagementScript()
 {
@@ -1312,7 +1356,7 @@ void __fastcall TManagementScript::FreeTerminal(TTerminal * Terminal)
       }
     }
   }
-  
+
   FTerminalList->FreeTerminal(Terminal);
 }
 //---------------------------------------------------------------------------
@@ -1620,6 +1664,7 @@ void __fastcall TManagementScript::DoConnect(const AnsiString Session)
       Terminal->OnQueryUser = OnTerminalQueryUser;
       Terminal->OnProgress = TerminalOperationProgress;
       Terminal->OnFinished = TerminalOperationFinished;
+      Terminal->OnUpdateStatus = OnTerminalUpdateStatus;
 
       ConnectTerminal(Terminal);
     }
@@ -1639,20 +1684,6 @@ void __fastcall TManagementScript::DoConnect(const AnsiString Session)
   PrintActiveSession();
 }
 //---------------------------------------------------------------------------
-void __fastcall TManagementScript::ConnectTerminal(TTerminal * Terminal)
-{
-  Terminal->OnUpdateStatus = OnTerminalUpdateStatus;
-
-  try
-  {
-    TScript::ConnectTerminal(Terminal);
-  }
-  __finally
-  {
-    Terminal->OnUpdateStatus = NULL;
-  }
-}
-//---------------------------------------------------------------------------
 void __fastcall TManagementScript::DoClose(TTerminal * Terminal)
 {
   int Index = FTerminalList->IndexOf(Terminal);
@@ -1673,7 +1704,7 @@ void __fastcall TManagementScript::DoClose(TTerminal * Terminal)
     {
       if (Index < FTerminalList->Count)
       {
-        FTerminal = FTerminalList->Terminals[Index]; 
+        FTerminal = FTerminalList->Terminals[Index];
       }
       else
       {
@@ -1773,7 +1804,7 @@ void __fastcall TManagementScript::LLsProc(TScriptProcParams * Parameters)
       Mask = "";
     }
   }
-  
+
   if (Directory.IsEmpty())
   {
     Directory = GetCurrentDir();

+ 3 - 4
core/Script.h

@@ -50,7 +50,7 @@ public:
 
   void __fastcall Synchronize(const AnsiString LocalDirectory,
     const AnsiString RemoteDirectory, const TCopyParamType & CopyParam,
-    TSynchronizeStats * Stats);
+    TSynchronizeChecklist ** Checklist);
 
   __property TScriptPrintEvent OnPrint = { read = FOnPrint, write = FOnPrint };
   __property TExtendedExceptionEvent OnShowExtendedException = { read = FOnShowExtendedException, write = FOnShowExtendedException };
@@ -146,7 +146,7 @@ public:
 
   __property TScriptInputEvent OnInput = { read = FOnInput, write = FOnInput };
   __property TScriptQueryCancelEvent OnQueryCancel = { read = FOnQueryCancel, write = FOnQueryCancel };
-  __property TNotifyEvent OnTerminalUpdateStatus = { read = FOnTerminalUpdateStatus, write = FOnTerminalUpdateStatus };
+  __property TUpdateStatusEvent OnTerminalUpdateStatus = { read = FOnTerminalUpdateStatus, write = FOnTerminalUpdateStatus };
   __property TPromptUserEvent OnTerminalPromptUser = { read = FOnTerminalPromptUser, write = FOnTerminalPromptUser };
   __property TQueryUserEvent OnTerminalQueryUser = { read = FOnTerminalQueryUser, write = FOnTerminalQueryUser };
   __property TScriptPrintProgressEvent OnPrintProgress = { read = FOnPrintProgress, write = FOnPrintProgress };
@@ -155,7 +155,7 @@ public:
 protected:
   TScriptInputEvent FOnInput;
   TScriptQueryCancelEvent FOnQueryCancel;
-  TNotifyEvent FOnTerminalUpdateStatus;
+  TUpdateStatusEvent FOnTerminalUpdateStatus;
   TPromptUserEvent FOnTerminalPromptUser;
   TQueryUserEvent FOnTerminalQueryUser;
   TScriptPrintProgressEvent FOnPrintProgress;
@@ -167,7 +167,6 @@ protected:
   bool FContinue;
 
   virtual void __fastcall ResetTransfer();
-  virtual void __fastcall ConnectTerminal(TTerminal * Terminal);
   void __fastcall Input(const AnsiString Prompt, AnsiString & Str, bool AllowEmpty);
   void __fastcall TerminalOnStdError(TObject * Sender, TLogLineType Type,
     const AnsiString AddedLine);

+ 278 - 74
core/SecureShell.cpp

@@ -28,11 +28,7 @@ __fastcall TSecureShell::TSecureShell()
 {
   FSessionData = new TSessionData("");
   FActive = False;
-  PendLen = 0;
-  PendSize = 0;
-  FStdErrorTemp = "";
-  FBytesSent = 0;
-  FBytesReceived = 0;
+  ResetConnection();
   FLog = new TSessionLog(this);
   FOnQueryUser = NULL;
   FOnPromptUser = NULL;
@@ -42,14 +38,8 @@ __fastcall TSecureShell::TSecureShell()
   FOnStdError = NULL;
   FOnCaptureOutput = NULL;
   FOnClose = NULL;
-  FCSCipher = cipWarn; // = not detected yet
-  FSCCipher = cipWarn;
-  FReachedStatus = 0;
-  UpdateStatus(sshClosed);
   FConfig = new Config();
   FSocket = new SOCKET;
-  FMaxPacketSize = NULL;
-  FBufSize = 0;
 }
 //---------------------------------------------------------------------------
 __fastcall TSecureShell::~TSecureShell()
@@ -65,7 +55,35 @@ __fastcall TSecureShell::~TSecureShell()
   FSocket = NULL;
 }
 //---------------------------------------------------------------------------
+void __fastcall TSecureShell::ResetConnection()
+{
+  PendLen = 0;
+  PendSize = 0;
+  Pending = NULL;
+  FStdErrorTemp = "";
+  FBytesSent = 0;
+  FBytesReceived = 0;
+  FCSCipher = cipWarn; // = not detected yet
+  FSCCipher = cipWarn;
+  FReachedStatus = 0;
+  UpdateStatus(sshClosed);
+  FMaxPacketSize = NULL;
+  FBufSize = 0;
+}
+//---------------------------------------------------------------------------
 void __fastcall TSecureShell::Open()
+{
+  try
+  {
+    DoOpen();
+  }
+  __finally
+  {
+    UpdateStatus(-1, false);
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TSecureShell::DoOpen()
 {
   const char * InitError;
   char * RealHost;
@@ -119,6 +137,18 @@ void __fastcall TSecureShell::Open()
   UpdateStatus(sshAuthenticated);
 }
 //---------------------------------------------------------------------------
+void __fastcall TSecureShell::Reopen(int /*Params*/)
+{
+  if (Active)
+  {
+    Close();
+  }
+
+  ResetConnection();
+
+  Open();
+}
+//---------------------------------------------------------------------------
 void __fastcall TSecureShell::Init()
 {
   try
@@ -178,12 +208,12 @@ AnsiString __fastcall TSecureShell::GetSshImplementation()
   {
     Ptr = strchr(Ptr + 1, '-');
   }
-  return (Ptr != NULL) ? AnsiString(Ptr + 1) : AnsiString(); 
+  return (Ptr != NULL) ? AnsiString(Ptr + 1) : AnsiString();
 }
 //---------------------------------------------------------------------
 AnsiString __fastcall TSecureShell::GetPassword()
 {
-  return (FPassword.IsEmpty() ? AnsiString() : 
+  return (FPassword.IsEmpty() ? AnsiString() :
     DecryptPassword(FPassword, SessionData->SessionName));
 }
 //---------------------------------------------------------------------
@@ -278,7 +308,7 @@ bool __fastcall TSecureShell::PromptUser(const AnsiString Prompt,
   {
     FPassword = EncryptPassword(Response, SessionData->SessionName);
   }
-  
+
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -310,7 +340,7 @@ void __fastcall TSecureShell::FromBackend(Boolean IsStdErr, char * Data, Integer
 
   if (IsStdErr)
   {
-    AddStdError(AnsiString(Data, Length));
+    AddStdError(AnsiString(Data, Length), false);
   }
   else
   {
@@ -440,7 +470,7 @@ AnsiString __fastcall TSecureShell::ReceiveLine()
 
   // We don't want end-of-line character
   Line.SetLength(Line.Length()-1);
-  CaptureOutput(llOutput, Line);
+  CaptureOutput(llOutput, Line, false);
   return Line;
 }
 //---------------------------------------------------------------------------
@@ -508,7 +538,58 @@ void __fastcall TSecureShell::SendLine(AnsiString Line)
   Log->Add(llInput, Line);
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::AddStdError(AnsiString Str)
+void __fastcall TSecureShell::TranslateAuthenticationMessage(AnsiString & Message)
+{
+  struct TMapping
+  {
+    const char * Original;
+    const char * Additional;
+    int Translation;
+  };
+
+  TMapping Mapping[] = {
+    { "Using username \"", NULL, AUTH_TRANSL_USERNAME },
+    { "Using keyboard-interactive authentication.", NULL, AUTH_TRANSL_KEYB_INTER },
+    { "Authenticating with public key \"", "from agent", AUTH_TRANSL_PUBLIC_KEY_AGENT },
+    { "Authenticating with public key \"", NULL, AUTH_TRANSL_PUBLIC_KEY },
+    { "Authenticated using RSA key \"", NULL, AUTH_TRANSL_PUBLIC_KEY_AGENT },
+    { "Wrong passphrase", NULL, AUTH_TRANSL_WRONG_PASSPHRASE },
+    { "Access denied", NULL, AUTH_TRANSL_ACCESS_DENIED },
+    { "Trying public key authentication", NULL, AUTH_TRANSL_TRY_PUBLIC_KEY }
+  };
+
+  for (int Index = 0; Index < LENOF(Mapping); Index++)
+  {
+    const char * Original = Mapping[Index].Original;
+    size_t OriginalLen = strlen(Original);
+    if (strncmp(Message.c_str(), Original, OriginalLen) == 0)
+    {
+      if (Original[OriginalLen - 1] == '"')
+      {
+        AnsiString MessageRest =
+          Message.SubString(OriginalLen + 1, Message.Length() - OriginalLen);
+        int P = MessageRest.Pos("\"");
+        if (P > 0)
+        {
+          const char * Additional = Mapping[Index].Additional;
+          if ((Additional == NULL) || (MessageRest.Pos(Additional) > 0))
+          {
+            MessageRest.SetLength(P - 1);
+            Message = FMTLOAD(Mapping[Index].Translation, (MessageRest));
+            break;
+          }
+        }
+      }
+      else
+      {
+        Message = LoadStr(Mapping[Index].Translation);
+        break;
+      }
+    }
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TSecureShell::AddStdError(AnsiString Str, bool LogOnly)
 {
   StdError += Str;
 
@@ -523,24 +604,22 @@ void __fastcall TSecureShell::AddStdError(AnsiString Str)
   {
     Line = FStdErrorTemp.SubString(1, P-1);
     FStdErrorTemp.Delete(1, P);
-    AddStdErrorLine(Line);
+    AddStdErrorLine(Line, LogOnly);
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::AddStdErrorLine(const AnsiString Str)
+void __fastcall TSecureShell::AddStdErrorLine(AnsiString Str, bool LogOnly)
 {
-  if (OnStdError == NULL)
+  if (Status == sshAuthenticate)
   {
-    if (Status == sshAuthenticate)
-    {
-      FAuthenticationLog += (FAuthenticationLog.IsEmpty() ? "" : "\n") + Str;
-    }
+    TranslateAuthenticationMessage(Str);
+    FAuthenticationLog += (FAuthenticationLog.IsEmpty() ? "" : "\n") + Str;
   }
-  else
+  if (!LogOnly && (OnStdError != NULL))
   {
     OnStdError(this, llStdError, Str);
   }
-  CaptureOutput(llStdError, Str);
+  CaptureOutput(llStdError, Str, LogOnly);
 }
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::ClearStdError()
@@ -553,16 +632,16 @@ void __fastcall TSecureShell::ClearStdError()
       FAuthenticationLog +=
         (FAuthenticationLog.IsEmpty() ? "" : "\n") + FStdErrorTemp;
     }
-    CaptureOutput(llStdError, FStdErrorTemp);
+    CaptureOutput(llStdError, FStdErrorTemp, false);
     FStdErrorTemp = "";
   }
   StdError = "";
 }
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::CaptureOutput(TLogLineType Type,
-  const AnsiString & Line)
+  const AnsiString & Line, bool LogOnly)
 {
-  if (FOnCaptureOutput != NULL)
+  if (!LogOnly && (FOnCaptureOutput != NULL))
   {
     FOnCaptureOutput(this, Type, Line);
   }
@@ -657,7 +736,7 @@ void __fastcall TSecureShell::Discard()
       OnClose(this);
     }
   }
-  
+
   FStatus = sshClosed;
 }
 //---------------------------------------------------------------------------
@@ -748,8 +827,8 @@ void __fastcall TSecureShell::WaitForData(bool Sending)
     int NewBufSize = FBackend->send(FBackendHandle, "", 0);
     if ((NewBufSize < FBufSize) && Sending)
     {
-      NeedToWait = false;  
-    } 
+      NeedToWait = false;
+    }
     FBufSize = NewBufSize;
     if (Configuration->LogProtocol >= 1)
     {
@@ -961,7 +1040,7 @@ TCipher __fastcall TSecureShell::FuncToSsh2Cipher(const void * Cipher) const
   return Result;
 }
 //---------------------------------------------------------------------------
-TCipher __fastcall TSecureShell::GetCSCipher() 
+TCipher __fastcall TSecureShell::GetCSCipher()
 {
   assert(Active);
 
@@ -1015,7 +1094,7 @@ int __fastcall TSecureShell::DoQueryUser(const AnsiString Query,
   TStrings * MoreMessages, int Answers, const TQueryParams * Params, TQueryType Type)
 {
   LogEvent(FORMAT("Asking user:\n%s (%s)", (Query, (MoreMessages ? MoreMessages->CommaText : AnsiString() ))));
-  int Answer = qaCancel;
+  int Answer = AbortAnswer(Answers);
   if (FOnQueryUser)
   {
     FOnQueryUser(this, Query, MoreMessages, Answers, Params, Answer, Type, NULL);
@@ -1042,7 +1121,7 @@ int __fastcall TSecureShell::DoQueryUser(const AnsiString Query,
   int Answers, const TQueryParams * Params, TQueryType Type)
 {
   return DoQueryUser(Query, "", Answers, Params, Type);
-} 
+}
 //---------------------------------------------------------------------------
 int __fastcall TSecureShell::DoQueryUser(const AnsiString Query,
   Exception * E, int Answers, const TQueryParams * Params, TQueryType Type)
@@ -1079,27 +1158,34 @@ void __fastcall TSecureShell::VerifyHostKey(const AnsiString Host, int Port,
 
   // Verify the key against the registry.
   Result = verify_host_key(Host.c_str(), Port, KeyType.c_str(), KeyStr.c_str());
-  
+
   if (Result != 0)
   {
-    TQueryParams Params;
-    Params.HelpKeyword = (Result == 1 ? HELP_UNKNOWN_KEY : HELP_DIFFERENT_KEY);
-    int R = DoQueryUser(
-      FMTLOAD((Result == 1 ? UNKNOWN_KEY2 : DIFFERENT_KEY2), (KeyType, Fingerprint)),
-      qaYes | qaNo | qaCancel, &Params, qtWarning);
-
-    switch (R) {
-      case qaYes:
-        store_host_key(Host.c_str(), Port, KeyType.c_str(), KeyStr.c_str());
-        break;
-
-      case qaCancel:
-        SSH_FATAL_ERROR(LoadStr(KEY_NOT_VERIFIED));
+    if (Configuration->DisableAcceptingHostKeys)
+    {
+      FatalError(LoadStr(KEY_NOT_VERIFIED));
+    }
+    else
+    {
+      TQueryParams Params;
+      Params.HelpKeyword = (Result == 1 ? HELP_UNKNOWN_KEY : HELP_DIFFERENT_KEY);
+      int R = DoQueryUser(
+        FMTLOAD((Result == 1 ? UNKNOWN_KEY2 : DIFFERENT_KEY2), (KeyType, Fingerprint)),
+        qaYes | qaNo | qaCancel, &Params, qtWarning);
+
+      switch (R) {
+        case qaYes:
+          store_host_key(Host.c_str(), Port, KeyType.c_str(), KeyStr.c_str());
+          break;
+
+        case qaCancel:
+          FatalError(LoadStr(KEY_NOT_VERIFIED));
+      }
     }
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::AskAlg(const AnsiString AlgType, 
+void __fastcall TSecureShell::AskAlg(const AnsiString AlgType,
   const AnsiString AlgName)
 {
   AnsiString Msg;
@@ -1107,7 +1193,7 @@ void __fastcall TSecureShell::AskAlg(const AnsiString AlgType,
   {
     Msg = FMTLOAD(KEX_BELOW_TRESHOLD, (AlgName));
   }
-  else 
+  else
   {
     int CipherType;
     if (AlgType == "cipher")
@@ -1122,7 +1208,7 @@ void __fastcall TSecureShell::AskAlg(const AnsiString AlgType,
     {
       CipherType = CIPHER_TYPE_SC;
     }
-    else 
+    else
     {
       assert(false);
     }
@@ -1136,23 +1222,34 @@ void __fastcall TSecureShell::AskAlg(const AnsiString AlgType,
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::DoDisplayBanner(const AnsiString & Banner)
+void __fastcall TSecureShell::DoDisplayBanner(const AnsiString & Banner,
+  bool & Log)
 {
-  if ((OnDisplayBanner != NULL) &&
-      Configuration->ShowBanner(SessionData->SessionKey, Banner))
+  if (OnDisplayBanner != NULL)
   {
-    bool NeverShowAgain = false;
-    OnDisplayBanner(this, SessionData->SessionName, Banner, NeverShowAgain);
-    if (NeverShowAgain)
+    Log = false;
+    AddStdError(Banner, true);
+
+    if (Configuration->ForceBanners ||
+        Configuration->ShowBanner(SessionData->SessionKey, Banner))
     {
-      Configuration->NeverShowBanner(SessionData->SessionKey, Banner);
+      bool NeverShowAgain = false;
+      int Options =
+        FLAGMASK(Configuration->ForceBanners, boDisableNeverShowAgain);
+      OnDisplayBanner(this, SessionData->SessionName, Banner,
+        NeverShowAgain, Options);
+      if (!Configuration->ForceBanners && NeverShowAgain)
+      {
+        Configuration->NeverShowBanner(SessionData->SessionKey, Banner);
+      }
     }
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::DisplayBanner(const AnsiString & Banner)
+void __fastcall TSecureShell::DisplayBanner(const AnsiString & Banner,
+  bool & Log)
 {
-  DoDisplayBanner(Banner);
+  DoDisplayBanner(Banner, Log);
 }
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::OldKeyfileWarning()
@@ -1160,18 +1257,82 @@ void __fastcall TSecureShell::OldKeyfileWarning()
   DoQueryUser(LoadStr(OLD_KEY), qaOK, NULL, qtWarning);
 }
 //---------------------------------------------------------------------------
+bool __fastcall TSecureShell::DoQueryReopen(Exception * E, int Params)
+{
+  bool Result;
+
+  if (FLAGSET(Params, ropNoConfirmation))
+  {
+    Result = true;
+  }
+  else
+  {
+    LogEvent("Connection was lost, asking what to do.");
+
+    TQueryParams Params(qpAllowContinueOnError);
+    Params.Timeout = Configuration->SessionReopenAuto;
+    Params.TimeoutAnswer = qaRetry;
+    TQueryButtonAlias Aliases[1];
+    Aliases[0].Button = qaRetry;
+    Aliases[0].Alias = LoadStr(RECONNECT_BUTTON);
+    Params.Aliases = Aliases;
+    Params.AliasesCount = LENOF(Aliases);
+    Result = (DoQueryUser("", E, qaRetry | qaAbort, &Params, qtError) == qaRetry);
+  }
+
+  return Result;
+}
+//---------------------------------------------------------------------------
+bool __fastcall TSecureShell::QueryReopen(Exception * E, int Params)
+{
+  bool Result = DoQueryReopen(E, Params);
+
+  if (Result)
+  {
+    do
+    {
+      try
+      {
+        if (FLAGSET(Params, ropNoConfirmation))
+        {
+          Sleep(Configuration->SessionReopenNoConfirmation);
+        }
+        Reopen(Params);
+      }
+      catch(Exception & E)
+      {
+        if (!Active)
+        {
+          Result = DoQueryReopen(&E, Params);
+        }
+        else
+        {
+          throw;
+        }
+      }
+    }
+    while (!Active && Result);
+  }
+
+  return Result;
+}
+//---------------------------------------------------------------------------
 int __fastcall TSecureShell::GetStatus() const
 {
   return FStatus;
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::UpdateStatus(int Value)
+void __fastcall TSecureShell::UpdateStatus(int Value, bool Active)
 {
-  if (FStatus != Value)
+  bool Update = (FStatus != Value) && Active;
+  if (Update)
   {
     FStatus = Value;
     if (FStatus > FReachedStatus) FReachedStatus = FStatus;
-    if (FOnUpdateStatus) FOnUpdateStatus(this);
+  }
+  if ((Update || !Active) && (FOnUpdateStatus != NULL))
+  {
+    FOnUpdateStatus(this, Active);
   }
 }
 //---------------------------------------------------------------------------
@@ -1269,11 +1430,14 @@ void __fastcall TSessionLog::DoAdd(TLogLineType aType, AnsiString aLine)
           if (Configuration->Logging && Configuration->LogToFile)
           {
             if (!FFile) OpenLogFile();
-            if (FFile) 
+            if (FFile)
             {
               AnsiString Timestamp = FormatDateTime(" yyyy-mm-dd hh:nn:ss.zzz ", Now());
-              fprintf((FILE *)FFile, "%s\n",
-                (MarkStr + Timestamp + NewStr).c_str());
+              AnsiString Buf = MarkStr + Timestamp + NewStr;
+              // use fwrite instead of fprintf to make sure that even
+              // non-ascii data (unicode) gets in.
+              fwrite(Buf.c_str(), Buf.Length(), 1, (FILE *)FFile);
+              fputc('\n', (FILE *)FFile);
             }
           }
         }
@@ -1378,9 +1542,54 @@ void TSessionLog::OpenLogFile()
       assert(!FFile);
       assert(Configuration);
       AnsiString NewFileName = LogFileName;
+      TDateTime N = Now();
+      for (int Index = 1; Index < NewFileName.Length(); Index++)
+      {
+        if (NewFileName[Index] == '&')
+        {
+          AnsiString Replacement;
+          switch (tolower(NewFileName[Index + 1]))
+          {
+            case 'y':
+              Replacement = FormatDateTime("yyyy", N);
+              break;
+
+            case 'm':
+              Replacement = FormatDateTime("mm", N);
+              break;
+
+            case 'd':
+              Replacement = FormatDateTime("dd", N);
+              break;
+
+            case 't':
+              Replacement = FormatDateTime("hhnnss", N);
+              break;
+
+            case 'h':
+              Replacement = MakeValidFileName(FOwner->SessionData->HostName);
+              break;
+
+            case 's':
+              Replacement = MakeValidFileName(FOwner->SessionData->SessionName);
+              break;
+
+            case '&':
+              Replacement = "&";
+              break;
+
+            default:
+              Replacement = AnsiString("&") + NewFileName[Index + 1];
+              break;
+          }
+          NewFileName.Delete(Index, 2);
+          NewFileName.Insert(Replacement, Index);
+          Index += Replacement.Length() - 1;
+        }
+      }
       if (Id != 0)
       {
-        NewFileName = FORMAT("%s%s.%.8x%s", (ExtractFilePath(NewFileName), 
+        NewFileName = FORMAT("%s%s.%.8x%s", (ExtractFilePath(NewFileName),
           ExtractFileName(NewFileName), static_cast<int>(FId), ExtractFileExt(NewFileName)));
       }
       FFile = fopen(NewFileName.c_str(), (Configuration->LogFileAppend ? "a" : "w"));
@@ -1521,7 +1730,7 @@ void __fastcall TSessionLog::AddStartupInfo()
          BooleanToEngStr(Data->ResolveSymlinks)));
       ADF("Alias LS: %s, Ign LS warn: %s, Scp1 Comp: %s",
         (BooleanToEngStr(Data->AliasGroupList),
-         BooleanToEngStr(Data->IgnoreLsWarnings), 
+         BooleanToEngStr(Data->IgnoreLsWarnings),
          BooleanToEngStr(Data->Scp1Compatibility)));
 
       AddSeparator();
@@ -1571,8 +1780,3 @@ void __fastcall TSessionLog::Clear()
   FTopIndex += Count;
   TStringList::Clear();
 }
-
-
-
-
-

+ 24 - 10
core/SecureShell.h

@@ -21,6 +21,11 @@
 #define sshOpenDirectory 7
 #define sshReady 8
 //---------------------------------------------------------------------------
+const ropNoConfirmation = 0x01;
+const ropNoReadDirectory = 0x02;
+//---------------------------------------------------------------------------
+const boDisableNeverShowAgain = 0x01;
+//---------------------------------------------------------------------------
 class TSecureShell;
 class TConfiguration;
 enum TCompressionType { ctNone, ctZLib };
@@ -33,9 +38,11 @@ typedef void __fastcall (__closure *TPromptUserEvent)
    AnsiString & Response, bool & Result, void * Arg);
 typedef void __fastcall (__closure *TDisplayBannerEvent)
   (TSecureShell * SecureShell, AnsiString SessionName, const AnsiString & Banner,
-   bool & NeverShowAgain);
+   bool & NeverShowAgain, int Options);
 typedef void __fastcall (__closure *TExtendedExceptionEvent)
   (TSecureShell * SecureShell, Exception * E, void * Arg);
+typedef void __fastcall (__closure *TUpdateStatusEvent)
+  (TSecureShell * SecureShell, bool Active);
 //---------------------------------------------------------------------------
 typedef Set<TLogLineType, llOutput, llException> TLogLineTypes;
 extern const TColor LogLineColors[];
@@ -77,7 +84,7 @@ public:
   void __fastcall AddStartupInfo();
   void __fastcall AddException(Exception * E);
   void __fastcall AddSeparator();
-  void __fastcall AddFromOtherLog(TObject * Sender, TLogLineType aType, 
+  void __fastcall AddFromOtherLog(TObject * Sender, TLogLineType aType,
     const AnsiString AddedLine);
   virtual void __fastcall Clear();
   void __fastcall ReflectSettings();
@@ -145,7 +152,7 @@ private:
   TSessionLog * FLog;
   TConfiguration *FConfiguration;
   TDateTime FLoginTime;
-  TNotifyEvent FOnUpdateStatus;
+  TUpdateStatusEvent FOnUpdateStatus;
   TNotifyEvent FOnClose;
   int FStatus;
   int FReachedStatus;
@@ -181,27 +188,33 @@ private:
   void __fastcall PoolForData(unsigned int & Result);
   TDateTime __fastcall GetIdleInterval();
   bool __fastcall GetStoredPasswordTried();
-  inline void __fastcall CaptureOutput(TLogLineType Type, const AnsiString & Line);
+  inline void __fastcall CaptureOutput(TLogLineType Type,
+    const AnsiString & Line, bool LogOnly);
+  void __fastcall ResetConnection();
 
 protected:
   AnsiString StdError;
   TLogAddLineEvent FOnCaptureOutput;
 
   void __fastcall Error(const AnsiString Error) const;
-  virtual void __fastcall UpdateStatus(int Value);
+  virtual void __fastcall UpdateStatus(int Value, bool Active = true);
   bool __fastcall SshFallbackCmd() const;
   void __fastcall GotHostKey();
   unsigned long __fastcall MaxPacketSize();
   int __fastcall RemainingSendBuffer();
   virtual void __fastcall KeepAlive();
   virtual void __fastcall SetSessionData(TSessionData * value);
-  virtual void __fastcall DoDisplayBanner(const AnsiString & Banner);
+  virtual void __fastcall DoDisplayBanner(const AnsiString & Banner, bool & Log);
+  virtual void __fastcall DoOpen();
+  void __fastcall TranslateAuthenticationMessage(AnsiString & Message);
+  virtual bool __fastcall DoQueryReopen(Exception * E, int Params);
 
 public:
   __fastcall TSecureShell();
   __fastcall ~TSecureShell();
   virtual void __fastcall Open();
   virtual void __fastcall Close();
+  virtual void __fastcall Reopen(int Params);
   bool __fastcall PromptUser(const AnsiString Prompt, AnsiString & Response,
     bool IsPassword);
   int __fastcall Receive(char * Buf, int Len);
@@ -209,8 +222,8 @@ public:
   void __fastcall Send(const char * Buf, int Len);
   void __fastcall SendStr(AnsiString Str);
   void __fastcall SendSpecial(int Code);
-  void __fastcall AddStdError(AnsiString Str);
-  void __fastcall AddStdErrorLine(const AnsiString Str);
+  void __fastcall AddStdError(AnsiString Str, bool LogOnly);
+  void __fastcall AddStdErrorLine(AnsiString Str, bool LogOnly);
   void __fastcall ClearStdError();
   virtual void __fastcall Idle();
   void __fastcall SendEOF();
@@ -224,8 +237,9 @@ public:
   void __fastcall VerifyHostKey(const AnsiString Host, int Port,
     const AnsiString KeyType, const AnsiString KeyStr, const AnsiString Fingerprint);
   void __fastcall AskAlg(const AnsiString AlgType, const AnsiString AlgName);
-  void __fastcall DisplayBanner(const AnsiString & Banner);
+  void __fastcall DisplayBanner(const AnsiString & Banner, bool & Log);
   void __fastcall OldKeyfileWarning();
+  bool __fastcall QueryReopen(Exception * E, int Params);
 
   virtual int __fastcall DoQueryUser(const AnsiString Query, TStrings * MoreMessages,
     int Answers, const TQueryParams * Params, TQueryType Type = qtConfirmation);
@@ -271,7 +285,7 @@ public:
   __property TPromptUserEvent OnPromptUser = { read = FOnPromptUser, write = FOnPromptUser };
   __property TDisplayBannerEvent OnDisplayBanner = { read = FOnDisplayBanner, write = FOnDisplayBanner };
   __property TExtendedExceptionEvent OnShowExtendedException = { read = FOnShowExtendedException, write = FOnShowExtendedException };
-  __property TNotifyEvent OnUpdateStatus = { read = FOnUpdateStatus, write = FOnUpdateStatus };
+  __property TUpdateStatusEvent OnUpdateStatus = { read = FOnUpdateStatus, write = FOnUpdateStatus };
   __property TLogAddLineEvent OnStdError = { read = FOnStdError, write = FOnStdError };
   __property TNotifyEvent OnClose = { read = FOnClose, write = FOnClose };
   __property int Status = { read = GetStatus };

+ 64 - 8
core/SessionData.cpp

@@ -25,7 +25,7 @@ const TCipher DefaultCipherList[CIPHER_COUNT] =
   { cipAES, cipBlowfish, cip3DES, cipWarn, cipDES };
 const TKex DefaultKexList[KEX_COUNT] =
   { kexDHGEx, kexDHGroup14, kexDHGroup1, kexWarn };
-const char FSProtocolNames[FSPROTOCOL_COUNT][11] = { "SCP", "SFTP (SCP)", "SFTP" };
+const char FSProtocolNames[FSPROTOCOL_COUNT][11] = { "SCP", "SFTP (SCP)", "SFTP", "SSH", "SFTP" };
 //--- TSessionData ----------------------------------------------------
 AnsiString TSessionData::FInvalidChars("/\\[]");
 //---------------------------------------------------------------------
@@ -99,6 +99,7 @@ void __fastcall TSessionData::Default()
   DeleteToRecycleBin = false;
   OverwrittenToRecycleBin = false;
   RecycleBinPath = "/tmp";
+  Color = 0;
 
   // SCP
   ReturnVar = "";
@@ -227,6 +228,8 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
       DUPL(SFTPBug[(TSftpBug)Index]);
     }
 
+    DUPL(Color);
+
     DUPL(CustomParam1);
     DUPL(CustomParam2);
 
@@ -342,12 +345,18 @@ void __fastcall TSessionData::StoreToConfig(void * config)
     if (FSProtocol != fsSFTPonly)
     {
       cfg->ssh_subsys2 = FALSE;
-      if (!Shell.IsEmpty())
+      if (Shell.IsEmpty())
+      {
+        // Following forces Putty to open default shell
+        // see ssh.c: do_ssh2_authconn() and ssh1_protocol()
+        cfg->remote_cmd2[0] = '\0';
+      }
+      else
       {
         ASCOPY(cfg->remote_cmd2, Shell);
-        // Putty reads only "ptr" member for fallback
-        cfg->remote_cmd_ptr2 = cfg->remote_cmd2;
       }
+      // Putty reads only "ptr" member for fallback
+      cfg->remote_cmd_ptr2 = cfg->remote_cmd2;
     }
     else
     {
@@ -367,6 +376,7 @@ void __fastcall TSessionData::StoreToConfig(void * config)
 //---------------------------------------------------------------------
 void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
 {
+  bool RewritePassword = false;
   if (Storage->OpenSubKey(StorageKey, False))
   {
     PortNumber = Storage->ReadInteger("PortNumber", PortNumber);
@@ -376,7 +386,15 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
 
     if (!Configuration->DisablePasswordStoring)
     {
-      FPassword = Storage->ReadString("Password", FPassword);
+      if (Storage->ValueExists("PasswordPlain"))
+      {
+        Password = Storage->ReadString("PasswordPlain", Password);
+        RewritePassword = true;
+      }
+      else
+      {
+        FPassword = Storage->ReadString("Password", FPassword);
+      }
     }
     // Putty uses PingIntervalSecs
     int PingIntervalSecs = Storage->ReadInteger("PingIntervalSecs", -1);
@@ -510,6 +528,8 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
     SFTPMaxVersion = Storage->ReadInteger("SFTPMaxVersion", SFTPMaxVersion);
     SFTPMaxPacketSize = Storage->ReadInteger("SFTPMaxPacketSize", SFTPMaxPacketSize);
 
+    Color = Storage->ReadInteger("Color", Color);
+
     // read only (used only on Import from Putty dialog)
     ProtocolStr = Storage->ReadString("Protocol", ProtocolStr);
 
@@ -518,6 +538,32 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
 
     Storage->CloseSubKey();
   };
+
+  if (RewritePassword)
+  {
+    TStorageAccessMode AccessMode = Storage->AccessMode;
+    Storage->AccessMode = smReadWrite;
+
+    try
+    {
+      if (Storage->OpenSubKey(StorageKey, true))
+      {
+        Storage->DeleteValue("PasswordPlain");
+        if (!Password.IsEmpty())
+        {
+          Storage->WriteString("Password", FPassword);
+        }
+        Storage->CloseSubKey();
+      }
+    }
+    catch(...)
+    {
+      // ignore errors (like read-only INI file)
+    }
+
+    Storage->AccessMode = AccessMode;
+  }
+
   FModified = false;
 }
 //---------------------------------------------------------------------
@@ -540,7 +586,6 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
 
     WRITE_DATA(String, HostName);
     WRITE_DATA(Integer, PortNumber);
-    WRITE_DATA(String, UserName);
     if (!Configuration->DisablePasswordStoring && !PuttyExport && !Password.IsEmpty())
     {
       WRITE_DATA_EX(String, "Password", FPassword, );
@@ -549,6 +594,7 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
     {
       Storage->DeleteValue("Password");
     }
+    Storage->DeleteValue("PasswordPlain");
     WRITE_DATA_EX(Integer, "PingInterval", PingInterval / 60, );
     WRITE_DATA_EX(Integer, "PingIntervalSecs", PingInterval % 60, );
     Storage->DeleteValue("PingIntervalSec"); // obsolete
@@ -573,10 +619,12 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
 
     if (PuttyExport)
     {
+      WRITE_DATA(StringRaw, UserName);
       WRITE_DATA(StringRaw, PublicKeyFile);
     }
     else
     {
+      WRITE_DATA(String, UserName);
       WRITE_DATA(Bool, AuthGSSAPI);
       WRITE_DATA(String, PublicKeyFile);
       WRITE_DATA(Integer, FSProtocol);
@@ -703,6 +751,8 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
       WRITE_DATA(Integer, SFTPMaxVersion);
       WRITE_DATA(Integer, SFTPMaxPacketSize);
 
+      WRITE_DATA(Integer, Color);
+
       WRITE_DATA(String, CustomParam1);
       WRITE_DATA(String, CustomParam2);
     }
@@ -744,7 +794,7 @@ bool __fastcall TSessionData::ParseUrl(AnsiString Url, int Params,
   AnsiString AConnectInfo;
   AConnectInfo = Url.SubString(1, PSlash - 1);
 
-  int P = AConnectInfo.Pos("@");
+  int P = AConnectInfo.LastDelimiter("@");
   bool Result = (P > 0) || ((Params & puRequireUsername) == 0);
   if (Result)
   {
@@ -776,7 +826,7 @@ bool __fastcall TSessionData::ParseUrl(AnsiString Url, int Params,
 
     if (ConnectInfo != NULL)
     {
-      *ConnectInfo = AConnectInfo;
+      *ConnectInfo = DECODE(AConnectInfo);
     }
 
     AnsiString UserInfo;
@@ -1116,6 +1166,7 @@ void __fastcall TSessionData::SetPublicKeyFile(AnsiString value)
 //---------------------------------------------------------------------
 AnsiString __fastcall TSessionData::GetDefaultLogFileName()
 {
+  // not used anymore
   return IncludeTrailingBackslash(SystemTemporaryDirectory()) +
     MakeValidFileName(SessionName) + ".log";
 }
@@ -1445,6 +1496,11 @@ void __fastcall TSessionData::SetSCPLsFullTime(TAutoSwitch value)
 {
   SET_SESSION_PROPERTY(SCPLsFullTime);
 }
+//---------------------------------------------------------------------------
+void __fastcall TSessionData::SetColor(int value)
+{
+  SET_SESSION_PROPERTY(Color);
+}
 //---------------------------------------------------------------------
 AnsiString __fastcall TSessionData::GetInfoTip()
 {

+ 5 - 2
core/SessionData.h

@@ -12,8 +12,8 @@
 enum TCipher { cipWarn, cip3DES, cipBlowfish, cipAES, cipDES };
 #define CIPHER_COUNT (cipDES+1)
 enum TProtocol { ptRaw, ptTelnet, ptRLogin, ptSSH };
-enum TFSProtocol { fsSCPonly, fsSFTP, fsSFTPonly };
-#define FSPROTOCOL_COUNT (fsSFTPonly+1)
+enum TFSProtocol { fsSCPonly, fsSFTP, fsSFTPonly, fsExternalSSH, fsExternalSFTP };
+#define FSPROTOCOL_COUNT (fsExternalSFTP+1)
 enum TProxyType { pxNone, pxHTTP, pxSocks, pxTelnet }; // 0.53b and older
 enum TProxyMethod { pmNone, pmSocks4, pmSocks5, pmHTTP, pmTelnet, pmCmd }; // after 0.53b
 enum TSshProt { ssh1only, ssh1, ssh2, ssh2only };
@@ -112,6 +112,7 @@ private:
   TAddressFamily FAddressFamily;
   AnsiString FRekeyData;
   unsigned int FRekeyTime;
+  int FColor;
 
   void __fastcall SetHostName(AnsiString value);
   void __fastcall SetPortNumber(int value);
@@ -205,6 +206,7 @@ private:
   void __fastcall SetAddressFamily(TAddressFamily value);
   void __fastcall SetRekeyData(AnsiString value);
   void __fastcall SetRekeyTime(unsigned int value);
+  void __fastcall SetColor(int value);
 
 public:
   __fastcall TSessionData(AnsiString aName);
@@ -304,6 +306,7 @@ public:
   __property TAddressFamily AddressFamily = { read = FAddressFamily, write = SetAddressFamily };
   __property AnsiString RekeyData = { read = FRekeyData, write = SetRekeyData };
   __property unsigned int RekeyTime = { read = FRekeyTime, write = SetRekeyTime };
+  __property int Color = { read = FColor, write = SetColor };
   __property AnsiString StorageKey = { read = GetStorageKey };
 };
 //---------------------------------------------------------------------------

File diff suppressed because it is too large
+ 448 - 131
core/SftpFileSystem.cpp


+ 15 - 1
core/SftpFileSystem.h

@@ -16,6 +16,7 @@ friend class TSFTPPacket;
 friend class TSFTPQueue;
 friend class TSFTPUploadQueue;
 friend class TSFTPDownloadQueue;
+friend class TSFTPLoadFilesPropertiesQueue;
 friend class TSFTPBusy;
 public:
   __fastcall TSFTPFileSystem(TTerminal * ATerminal);
@@ -29,6 +30,7 @@ public:
   virtual void __fastcall CachedChangeDirectory(const AnsiString Directory);
   virtual void __fastcall ChangeFileProperties(const AnsiString FileName,
     const TRemoteFile * File, const TRemoteProperties * Properties);
+  virtual bool __fastcall LoadFilesProperties(TStrings * FileList);
   virtual void __fastcall CopyToLocal(TStrings * FilesToCopy,
     const AnsiString TargetDir, const TCopyParamType * CopyParam,
     int Params, TFileOperationProgressType * OperationProgress,
@@ -61,6 +63,8 @@ public:
     const AnsiString NewName);
   virtual AnsiString __fastcall FileUrl(const AnsiString FileName);
   virtual TStrings * __fastcall GetFixedPaths();
+  virtual void __fastcall SpaceAvailable(const AnsiString Path,
+    TSpaceAvailable & ASpaceAvailable);
 
 protected:
   int FVersion;
@@ -91,7 +95,9 @@ protected:
   bool __fastcall inline IsAbsolutePath(const AnsiString Path);
   bool __fastcall RemoteFileExists(const AnsiString FullPath, TRemoteFile ** File = NULL);
   TRemoteFile * __fastcall LoadFile(TSFTPPacket * Packet,
-    TRemoteFile * ALinkedByFile, const AnsiString FileName);
+    TRemoteFile * ALinkedByFile, const AnsiString FileName,
+    TRemoteFileList * TempFileList = NULL);
+  void __fastcall LoadFile(TRemoteFile * File, TSFTPPacket * Packet);
   AnsiString __fastcall LocalCanonify(const AnsiString & Path);
   AnsiString __fastcall Canonify(AnsiString Path);
   AnsiString __fastcall RealPath(const AnsiString Path);
@@ -111,7 +117,11 @@ protected:
   void __fastcall UnreserveResponse(TSFTPPacket * Response);
   void __fastcall TryOpenDirectory(const AnsiString Directory);
   bool __fastcall SupportsExtension(const AnsiString & Extension) const;
+  void __fastcall ResetConnection();
 
+  void __fastcall SFTPSourceRobust(const AnsiString FileName,
+    const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params,
+    TFileOperationProgressType * OperationProgress, unsigned int Flags);
   void __fastcall SFTPSource(const AnsiString FileName,
     const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params,
     TFileOperationProgressType * OperationProgress, unsigned int Flags);
@@ -129,6 +139,10 @@ protected:
     TSFTPOverwriteMode & Mode, const TOverwriteFileParams * FileParams);
   bool SFTPConfirmResume(const AnsiString DestFileName, bool PartialBiggerThanSource,
     TFileOperationProgressType * OperationProgress);
+  void __fastcall SFTPSinkRobust(const AnsiString FileName,
+    const TRemoteFile * File, const AnsiString TargetDir,
+    const TCopyParamType * CopyParam, int Params,
+    TFileOperationProgressType * OperationProgress, unsigned int Flags);
   void __fastcall SFTPSink(const AnsiString FileName,
     const TRemoteFile * File, const AnsiString TargetDir,
     const TCopyParamType * CopyParam, int Params,

File diff suppressed because it is too large
+ 601 - 217
core/Terminal.cpp


+ 109 - 24
core/Terminal.h

@@ -16,9 +16,10 @@ class TCustomFileSystem;
 struct TCalculateSizeParams;
 struct TOverwriteFileParams;
 struct TSynchronizeData;
-struct TSynchronizeStats;
 struct TSynchronizeOptions;
+class TSynchronizeChecklist;
 struct TCalculateSizeStats;
+struct TFileSystemInfo;
 typedef TStringList TUsersGroupsList;
 typedef void __fastcall (__closure *TReadDirectoryEvent)(System::TObject* Sender, Boolean ReloadOnly);
 typedef void __fastcall (__closure *TReadDirectoryProgressEvent)(
@@ -79,7 +80,8 @@ typedef int __fastcall (__closure *TDirectoryModifiedEvent)
 enum TFSCapability { fcUserGroupListing, fcModeChanging, fcGroupChanging,
   fcOwnerChanging, fcAnyCommand, fcHardLink, fcSymbolicLink, fcResolveSymlink,
   fcTextMode, fcRename, fcNativeTextMode, fcNewerOnlyUpload, fcRemoteCopy,
-  fcTimestampChanging, fcRemoteMove };
+  fcTimestampChanging, fcRemoteMove, fcLoadingAdditionalProperties,
+  fcCheckingSpaceAvailable, fcIgnorePermErrors, fcCount };
 enum TCurrentFSProtocol { cfsUnknown, cfsSCP, cfsSFTP };
 //---------------------------------------------------------------------------
 const cpDelete = 0x01;
@@ -104,7 +106,7 @@ public:
   static const spNoRecurse = 0x08;
   static const spUseCache = 0x10; // cannot be combined with spTimestamp
   static const spDelayProgress = 0x20; // cannot be combined with spTimestamp
-  static const spPreviewChanges = 0x40; // has no effect for spTimestamp
+  // 0x40 was spPreviewChanges
   static const spSubDirs = 0x80; // cannot be combined with spTimestamp
   static const spTimestamp = 0x100;
   static const spNotByTime = 0x200; // cannot be combined with spTimestamp and smBoth
@@ -223,31 +225,33 @@ protected:
   int __fastcall ConfirmFileOverwrite(const AnsiString FileName,
     const TOverwriteFileParams * FileParams, int Answers, const TQueryParams * Params,
     TOperationSide Side, TFileOperationProgressType * OperationProgress);
-  void __fastcall DoSynchronizeDirectory(const AnsiString LocalDirectory,
+  void __fastcall DoSynchronizeCollectDirectory(const AnsiString LocalDirectory,
     const AnsiString RemoteDirectory, TSynchronizeMode Mode,
     const TCopyParamType * CopyParam, int Params,
-    TSynchronizeDirectory OnSynchronizeDirectory, TSynchronizeStats * Stats,
-    TSynchronizeOptions * Options, int Level);
-  void __fastcall SynchronizeFile(const AnsiString FileName,
+    TSynchronizeDirectory OnSynchronizeDirectory,
+    TSynchronizeOptions * Options, int Level, TSynchronizeChecklist * Checklist);
+  void __fastcall SynchronizeCollectFile(const AnsiString FileName,
     const TRemoteFile * File, /*TSynchronizeData*/ void * Param);
   void __fastcall SynchronizeRemoteTimestamp(const AnsiString FileName,
     const TRemoteFile * File, void * Param);
   void __fastcall SynchronizeLocalTimestamp(const AnsiString FileName,
-    const TRemoteFile * File, void * Param, int Index);
+    const TRemoteFile * File, void * Param);
   void __fastcall DoSynchronizeProgress(const TSynchronizeData & Data);
   void __fastcall DeleteLocalFile(AnsiString FileName,
     const TRemoteFile * File, void * Param);
   void __fastcall RecycleFile(AnsiString FileName, const TRemoteFile * File);
   bool __fastcall IsRecycledFile(AnsiString FileName);
   TStrings * __fastcall GetFixedPaths();
+  void __fastcall DoStartup();
+  virtual void __fastcall DoOpen();
 
   __property TFileOperationProgressType * OperationProgress = { read=FOperationProgress };
 
 public:
   __fastcall TTerminal();
   __fastcall ~TTerminal();
-  virtual void __fastcall Open();
   virtual void __fastcall Close();
+  virtual void __fastcall Reopen(int Params);
   virtual void __fastcall DirectoryModified(const AnsiString Path, bool SubDirs);
   virtual void __fastcall DirectoryLoaded(TRemoteFileList * FileList);
   virtual void __fastcall Idle();
@@ -277,13 +281,13 @@ public:
   void __fastcall CustomCommandOnFiles(AnsiString Command, int Params,
     TStrings * Files, TLogAddLineEvent OutputEvent);
   void __fastcall ChangeDirectory(const AnsiString Directory);
-  void __fastcall DoStartup();
   void __fastcall EndTransaction();
   void __fastcall HomeDirectory();
   void __fastcall ChangeFileProperties(AnsiString FileName,
     const TRemoteFile * File, /*const TRemoteProperties */ void * Properties);
   void __fastcall ChangeFilesProperties(TStrings * FileList,
     const TRemoteProperties * Properties);
+  bool __fastcall LoadFilesProperties(TStrings * FileList);
   void __fastcall TerminalError(AnsiString Msg);
   void __fastcall TerminalError(Exception * E, AnsiString Msg);
   void __fastcall ReloadDirectory();
@@ -301,11 +305,16 @@ public:
   void __fastcall CalculateFilesSize(TStrings * FileList, __int64 & Size,
     int Params, const TCopyParamType * CopyParam = NULL, TCalculateSizeStats * Stats = NULL);
   void __fastcall ClearCaches();
-  void __fastcall Synchronize(const AnsiString LocalDirectory,
+  TSynchronizeChecklist * __fastcall SynchronizeCollect(const AnsiString LocalDirectory,
     const AnsiString RemoteDirectory, TSynchronizeMode Mode,
     const TCopyParamType * CopyParam, int Params,
-    TSynchronizeDirectory OnSynchronizeDirectory, TSynchronizeStats * Stats,
-    TSynchronizeOptions * Options);
+    TSynchronizeDirectory OnSynchronizeDirectory, TSynchronizeOptions * Options);
+  void __fastcall SynchronizeApply(TSynchronizeChecklist * Checklist,
+    const AnsiString LocalDirectory, const AnsiString RemoteDirectory,
+    const TCopyParamType * CopyParam, int Params,
+    TSynchronizeDirectory OnSynchronizeDirectory);
+  void __fastcall SpaceAvailable(const AnsiString Path, TSpaceAvailable & ASpaceAvailable);
+  void __fastcall FileSystemInfo(TFileSystemInfo & AFileSystemInfo);
   bool __fastcall DirectoryFileList(const AnsiString Path,
     TRemoteFileList *& FileList, bool CanLoad);
   void __fastcall MakeLocalFileList(const AnsiString FileName,
@@ -314,6 +323,9 @@ public:
   bool __fastcall FileOperationLoopQuery(Exception & E,
     TFileOperationProgressType * OperationProgress, const AnsiString Message,
     bool AllowSkip, AnsiString SpecialRetry = "");
+  TUsableCopyParamAttrs __fastcall UsableCopyParamAttrs(int Params);
+  bool __fastcall QueryReopen(Exception * E, int Params,
+    TFileOperationProgressType * OperationProgress);
 
   static bool __fastcall IsAbsolutePath(const AnsiString Path);
   static AnsiString __fastcall ExpandFileName(AnsiString Path,
@@ -424,17 +436,6 @@ struct TMakeLocalFileListParams
   bool Recursive;
 };
 //---------------------------------------------------------------------------
-struct TSynchronizeStats
-{
-  TSynchronizeStats();
-
-  // currently we do not need any other stats
-  // (these are for keep remote directory up to date)
-  int NewDirectories;
-  int RemovedDirectories;
-  int ObsoleteDirectories;
-};
-//---------------------------------------------------------------------------
 struct TSynchronizeOptions
 {
   TSynchronizeOptions();
@@ -443,4 +444,88 @@ struct TSynchronizeOptions
   TStringList * Filter;
 };
 //---------------------------------------------------------------------------
+class TSynchronizeChecklist
+{
+friend class TTerminal;
+
+public:
+  enum TAction { saNone, saUploadNew, saDownloadNew, saUploadUpdate,
+    saDownloadUpdate, saDeleteRemote, saDeleteLocal };
+  static const int ActionCount = saDeleteLocal;
+
+  class TItem
+  {
+  friend class TTerminal;
+
+  public:
+    struct TFileInfo
+    {
+      AnsiString Directory;
+      TDateTime Modification;
+      TModificationFmt ModificationFmt;
+      __int64 Size;
+    };
+
+    TAction Action;
+    AnsiString FileName;
+    bool IsDirectory;
+    TFileInfo Local;
+    TFileInfo Remote;
+    int ImageIndex;
+    bool Checked;
+
+    ~TItem();
+
+  private:
+    TRemoteFile * FRemoteFile;
+    FILETIME FLocalLastWriteTime;
+
+    TItem();
+  };
+
+  ~TSynchronizeChecklist();
+
+  __property int Count = { read = GetCount };
+  __property const TItem * Item[int Index] = { read = GetItem };
+
+protected:
+  TSynchronizeChecklist();
+
+  void Sort();
+  void Add(TItem * Item);
+
+  int GetCount() const;
+  const TItem * GetItem(int Index) const;
+
+private:
+  TList * FList;
+
+  static int __fastcall Compare(void * Item1, void * Item2);
+};
+//---------------------------------------------------------------------------
+struct TSpaceAvailable
+{
+  TSpaceAvailable();
+
+  __int64 BytesOnDevice;
+  __int64 UnusedBytesOnDevice;
+  __int64 BytesAvailableToUser;
+  __int64 UnusedBytesAvailableToUser;
+  unsigned long BytesPerAllocationUnit;
+};
+//---------------------------------------------------------------------------
+struct TFileSystemInfo
+{
+  int SshVersion;
+  AnsiString SshImplementation;
+  TCipher CSCipher;
+  TCipher SCCipher;
+  TCompressionType CSCompression;
+  TCompressionType SCCompression;
+  AnsiString ProtocolName;
+  AnsiString HostKeyFingerprint;
+  AnsiString AdditionalInfo;
+  bool IsCapable[fcCount];
+};
+//---------------------------------------------------------------------------
 #endif

+ 1 - 1
dragext/DragExt.cpp

@@ -194,7 +194,7 @@ DllMain(HINSTANCE HInstance, DWORD Reason, LPVOID Reserved)
   {
     GLogMutex = CreateMutex(NULL, false, "WinSCPDragExtLogMutex");
 
-    for (int Root = 0; Root < 3; Root++)
+    for (int Root = 0; Root <= 1; Root++)
     {
       HKEY Key;
       if (RegOpenKeyEx(Root == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,

+ 63 - 23
forms/About.cpp

@@ -14,9 +14,27 @@
 //---------------------------------------------------------------------
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------------
-__fastcall TAboutDialog::TAboutDialog(TComponent* AOwner)
+void __fastcall DoAboutDialog(TConfiguration * Configuration,
+  bool AllowLicence, TRegistration * Registration)
+{
+  TAboutDialog * AboutDialog = NULL;
+  try
+  {
+    AboutDialog = new TAboutDialog(Application, Configuration, AllowLicence,
+      Registration);
+    AboutDialog->ShowModal();
+  }
+  __finally
+  {
+    delete AboutDialog;
+  }
+}
+//---------------------------------------------------------------------------
+__fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
+  TConfiguration * Configuration, bool AllowLicence, TRegistration * Registration)
   : TForm(AOwner)
 {
+  FConfiguration = Configuration;
   ThirdPartyBox->VertScrollBar->Position = 0;
   UseSystemSettings(this);
   LinkLabel(HomepageLabel, LoadStr(HOMEPAGE_URL));
@@ -32,6 +50,45 @@ __fastcall TAboutDialog::TAboutDialog(TComponent* AOwner)
   PuttyCopyrightLabel->Caption = LoadStr(PUTTY_COPYRIGHT);
   WinSCPCopyrightLabel->Caption = LoadStr(WINSCP_COPYRIGHT);
   AnsiString Translator = LoadStr(TRANSLATOR_INFO);
+
+  if (Registration == NULL)
+  {
+    RegistrationLabel->Visible = false;
+    RegistrationBox->Visible = false;
+    ClientHeight = ClientHeight -
+      (ThirdPartyBox->Top - RegistrationBox->Top);
+  }
+  else
+  {
+    RegistrationSubjectLabel->Caption = Registration->Subject;
+    if (Registration->Registered)
+    {
+      AnsiString Text;
+      Text = FORMAT(LoadStrPart(ABOUT_REGISTRATION_LICENCES, 1),
+        (Registration->Licences >= 0 ? IntToStr(Registration->Licences) :
+          LoadStrPart(ABOUT_REGISTRATION_LICENCES, 2)));
+      if (!Registration->NeverExpires)
+      {
+        Text = FMTLOAD(ABOUT_REGISTRATION_EXPIRES,
+          (Text, FormatDateTime("ddddd", Registration->Expiration)));
+      }
+      RegistrationLicencesLabel->Caption = Text;
+      Text = FMTLOAD(ABOUT_REGISTRATION_PRODUCTID, (Registration->ProductId));
+      if (Registration->EduLicense)
+      {
+        Text = FMTLOAD(ABOUT_REGISTRATION_EDULICENCE, (Text));
+      }
+      RegistrationProductIdLabel->Caption = Text;
+      RegistrationProductIdLabel->Font->Style =
+        RegistrationProductIdLabel->Font->Style << fsBold;
+    }
+    else
+    {
+      RegistrationLicencesLabel->Visible = false;
+      RegistrationProductIdLabel->Visible = false;
+    }
+  }
+
   if (Translator.IsEmpty())
   {
     TranslatorLabel->Visible = false;
@@ -44,24 +101,17 @@ __fastcall TAboutDialog::TAboutDialog(TComponent* AOwner)
     TranslatorLabel->Caption = LoadStr(TRANSLATOR_INFO);
     LinkLabel(TranslatorUrlLabel, LoadStr(TRANSLATOR_URL));
   }
-}
-//---------------------------------------------------------------------------
-void __fastcall TAboutDialog::SetConfiguration(TConfiguration * value)
-{
-  if (FConfiguration != value)
-  {
-    FConfiguration = value;
-    LoadData();
-  }
+  LicenceButton->Visible = AllowLicence;
+  LoadData();
 }
 //---------------------------------------------------------------------------
 void __fastcall TAboutDialog::LoadData()
 {
-  AnsiString Version = Configuration->VersionStr;
-  if (Configuration->Version != Configuration->ProductVersion)
+  AnsiString Version = FConfiguration->VersionStr;
+  if (FConfiguration->Version != FConfiguration->ProductVersion)
   {
     Version = FMTLOAD(ABOUT_BASED_ON_PRODUCT,
-      (Configuration->ProductName, Configuration->ProductVersion));
+      (Version, FConfiguration->ProductName, FConfiguration->ProductVersion));
   }
   VersionLabel->Caption = Version;
 }
@@ -76,16 +126,6 @@ void __fastcall TAboutDialog::LicenceButtonClick(TObject * /*Sender*/)
   DoProductLicence();
 }
 //---------------------------------------------------------------------------
-bool __fastcall TAboutDialog::GetAllowLicence()
-{
-  return LicenceButton->Visible;
-}
-//---------------------------------------------------------------------------
-void __fastcall TAboutDialog::SetAllowLicence(bool value)
-{
-  LicenceButton->Visible = value;
-}
-//---------------------------------------------------------------------------
 void __fastcall TAboutDialog::HelpButtonClick(TObject * /*Sender*/)
 {
   FormHelp(this);

+ 86 - 31
forms/About.dfm

@@ -1,12 +1,12 @@
 object AboutDialog: TAboutDialog
   Left = 373
-  Top = 184
+  Top = 123
   HelpType = htKeyword
   HelpKeyword = 'ui_about'
   BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
   BorderStyle = bsDialog
   Caption = 'About application'
-  ClientHeight = 372
+  ClientHeight = 476
   ClientWidth = 388
   Color = clBtnFace
   Font.Charset = DEFAULT_CHARSET
@@ -18,7 +18,7 @@ object AboutDialog: TAboutDialog
   Position = poOwnerFormCenter
   DesignSize = (
     388
-    372)
+    476)
   PixelsPerInch = 96
   TextHeight = 13
   object ApplicationLabel: TLabel
@@ -159,6 +159,22 @@ object AboutDialog: TAboutDialog
       8001FFFF800FFFFF8003FFFF8003FFFFC003FFFFE003FFFFFFFFFFFF}
     Transparent = True
   end
+  object Label3: TLabel
+    Left = 72
+    Top = 295
+    Width = 87
+    Height = 13
+    Anchors = [akLeft, akBottom]
+    Caption = 'Portions copyright:'
+  end
+  object RegistrationLabel: TLabel
+    Left = 72
+    Top = 188
+    Width = 126
+    Height = 13
+    Anchors = [akLeft, akBottom]
+    Caption = 'This product is licensed to:'
+  end
   object HomepageLabel: TStaticText
     Left = 72
     Top = 72
@@ -188,12 +204,12 @@ object AboutDialog: TAboutDialog
   end
   object ThirdPartyBox: TScrollBox
     Left = 72
-    Top = 185
+    Top = 313
     Width = 306
-    Height = 145
+    Height = 121
     HorzScrollBar.Range = 289
     HorzScrollBar.Visible = False
-    VertScrollBar.Range = 309
+    VertScrollBar.Range = 285
     VertScrollBar.Smooth = True
     VertScrollBar.Tracking = True
     Anchors = [akLeft, akRight, akBottom]
@@ -201,17 +217,10 @@ object AboutDialog: TAboutDialog
     TabOrder = 5
     DesignSize = (
       285
-      141)
-    object Label3: TLabel
-      Left = 8
-      Top = 8
-      Width = 87
-      Height = 13
-      Caption = 'Portions copyright:'
-    end
+      117)
     object Label7: TLabel
       Left = 8
-      Top = 32
+      Top = 8
       Width = 272
       Height = 41
       Anchors = [akLeft, akTop, akRight]
@@ -221,58 +230,66 @@ object AboutDialog: TAboutDialog
         't of application license agreement.'
       WordWrap = True
     end
+    object Label4: TLabel
+      Left = 8
+      Top = 24
+      Width = 32
+      Height = 13
+      Caption = 'Label4'
+      Visible = False
+    end
     object PuttyVersionLabel: TLabel
       Left = 8
-      Top = 72
+      Top = 48
       Width = 196
       Height = 13
       Caption = 'SSH and SCP code based on PuTTY xxx'
     end
     object PuttyCopyrightLabel: TLabel
       Left = 8
-      Top = 88
+      Top = 64
       Width = 145
       Height = 13
       Caption = 'Copyright '#169' xxx Simon Tatham'
     end
     object Label8: TLabel
       Left = 8
-      Top = 264
+      Top = 240
       Width = 181
       Height = 13
       Caption = 'Filemanager Toolset library Version 2.6'
     end
     object Label10: TLabel
       Left = 8
-      Top = 280
+      Top = 256
       Width = 137
       Height = 13
       Caption = 'Copyright '#169' 1999 Ingo Eckel'
     end
     object Label1: TLabel
       Left = 8
-      Top = 152
+      Top = 128
       Width = 117
       Height = 13
-      Caption = 'Toolbar2000 library 2.1.5'
+      Caption = 'Toolbar2000 library 2.1.6'
     end
     object Label2: TLabel
       Left = 8
-      Top = 168
+      Top = 144
       Width = 182
       Height = 13
       Caption = 'Copyright '#169' 1998-2005 Jordan Russell'
     end
     object Label5: TLabel
       Left = 8
-      Top = 208
+      Top = 184
       Width = 69
       Height = 13
       Caption = 'TBX library 2.1'
     end
     object Label6: TLabel
       Left = 8
-      Top = 224
+      Top = 200
       Width = 188
       Height = 13
       Caption = 'Copyright '#169' 2001-2005 Alex A. Denisov'
@@ -280,7 +297,7 @@ object AboutDialog: TAboutDialog
     object PuttyLicenceLabel: TStaticText
       Tag = 1
       Left = 8
-      Top = 104
+      Top = 80
       Width = 75
       Height = 17
       Caption = 'Display licence'
@@ -290,7 +307,7 @@ object AboutDialog: TAboutDialog
     end
     object PuttyHomepageLabel: TStaticText
       Left = 8
-      Top = 120
+      Top = 96
       Width = 281
       Height = 17
       Caption = 'http://XXXwww.chiark.greenend.org.uk/~sgtatham/putty/'
@@ -299,7 +316,7 @@ object AboutDialog: TAboutDialog
     end
     object Toolbar2000HomepageLabel: TStaticText
       Left = 8
-      Top = 184
+      Top = 160
       Width = 180
       Height = 17
       Caption = 'http://www.jrsoftware.org/tb2kdl.php'
@@ -308,7 +325,7 @@ object AboutDialog: TAboutDialog
     end
     object TBXHomepageLabel: TStaticText
       Left = 8
-      Top = 240
+      Top = 216
       Width = 122
       Height = 17
       Caption = 'http://www.g32.org/tbx/'
@@ -318,7 +335,7 @@ object AboutDialog: TAboutDialog
   end
   object OKButton: TButton
     Left = 221
-    Top = 339
+    Top = 443
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
@@ -330,7 +347,7 @@ object AboutDialog: TAboutDialog
   end
   object LicenceButton: TButton
     Left = 72
-    Top = 339
+    Top = 443
     Width = 75
     Height = 25
     Anchors = [akLeft, akBottom]
@@ -340,7 +357,7 @@ object AboutDialog: TAboutDialog
   end
   object HelpButton: TButton
     Left = 303
-    Top = 339
+    Top = 443
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
@@ -348,4 +365,42 @@ object AboutDialog: TAboutDialog
     TabOrder = 1
     OnClick = HelpButtonClick
   end
+  object RegistrationBox: TScrollBox
+    Left = 72
+    Top = 206
+    Width = 306
+    Height = 81
+    HorzScrollBar.Visible = False
+    VertScrollBar.Smooth = True
+    VertScrollBar.Tracking = True
+    Anchors = [akLeft, akRight, akBottom]
+    TabOrder = 7
+    DesignSize = (
+      302
+      77)
+    object RegistrationSubjectLabel: TLabel
+      Left = 8
+      Top = 8
+      Width = 289
+      Height = 65
+      Anchors = [akLeft, akTop, akRight]
+      AutoSize = False
+      Caption = 'Someone'#13#10'Somewhere, some city'
+      WordWrap = True
+    end
+    object RegistrationLicencesLabel: TLabel
+      Left = 8
+      Top = 39
+      Width = 108
+      Height = 13
+      Caption = 'Number of Licences: X'
+    end
+    object RegistrationProductIdLabel: TLabel
+      Left = 8
+      Top = 57
+      Width = 128
+      Height = 13
+      Caption = 'Product ID: xxxx-xxxx-xxxxx'
+    end
+  end
 end

+ 9 - 7
forms/About.h

@@ -25,7 +25,6 @@ __published:
   TLabel *ProductSpecificMessageLabel;
   TStaticText *ForumUrlLabel;
   TScrollBox *ThirdPartyBox;
-  TLabel *Label3;
   TLabel *PuttyVersionLabel;
   TLabel *PuttyCopyrightLabel;
   TStaticText *PuttyHomepageLabel;
@@ -45,21 +44,24 @@ __published:
   TButton *HelpButton;
   TImage *Image;
   TStaticText *TranslatorUrlLabel;
+  TLabel *Label3;
+  TLabel *RegistrationLabel;
+  TScrollBox *RegistrationBox;
+  TLabel *RegistrationLicencesLabel;
+  TLabel *RegistrationProductIdLabel;
+  TLabel *RegistrationSubjectLabel;
+  TLabel *Label4;
   void __fastcall DisplayLicence(TObject *Sender);
   void __fastcall LicenceButtonClick(TObject *Sender);
-  bool __fastcall GetAllowLicence();
   void __fastcall HelpButtonClick(TObject *Sender);
 private:
   TConfiguration * FConfiguration;
-  void __fastcall SetConfiguration(TConfiguration * value);
-  void __fastcall SetAllowLicence(bool value);
   void __fastcall FirstScrollingControlEnter(TObject * Sender);
   void __fastcall LastScrollingControlEnter(TObject * Sender);
 public:
-  virtual __fastcall TAboutDialog(TComponent* AOwner);
+  virtual __fastcall TAboutDialog(TComponent * AOwner,
+    TConfiguration * Configuration, bool AllowLicence, TRegistration * Registration);
   void __fastcall LoadData();
-  __property TConfiguration * Configuration  = { read=FConfiguration, write=SetConfiguration };
-  __property bool AllowLicence = { read=GetAllowLicence, write=SetAllowLicence };
 };
 //----------------------------------------------------------------------------
 #endif

+ 302 - 0
forms/Authenticate.cpp

@@ -0,0 +1,302 @@
+//---------------------------------------------------------------------------
+#include <vcl.h>
+#pragma hdrstop
+
+#include <Common.h>
+
+#include "Authenticate.h"
+
+#include <VCLCommon.h>
+#include <TextsWin.h>
+#include <SecureShell.h>
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma link "PasswordEdit"
+#pragma resource "*.dfm"
+//---------------------------------------------------------------------------
+__fastcall TAuthenticateForm::TAuthenticateForm(TComponent * Owner,
+  AnsiString SessionName)
+  : TForm(Owner), FSessionName(SessionName)
+{
+  UseSystemSettings(this);
+  FShowAsModalStorage = NULL;
+  FFocusControl = NULL;
+}
+//---------------------------------------------------------------------------
+__fastcall TAuthenticateForm::~TAuthenticateForm()
+{
+  ReleaseAsModal(this, FShowAsModalStorage);
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::ShowAsModal()
+{
+  ::ShowAsModal(this, FShowAsModalStorage);
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::HideAsModal()
+{
+  ::HideAsModal(this, FShowAsModalStorage);
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::FormShow(TObject * /*Sender*/)
+{
+  ClearLog();
+  AdjustControls();
+
+  if (FFocusControl != NULL)
+  {
+    FFocusControl->SetFocus();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::ClearLog()
+{
+  // TListItems::Clear() does nothing without allocated handle
+  LogView->HandleNeeded();
+  LogView->Items->Clear();
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::Log(const AnsiString Message)
+{
+  TListItem * Item = LogView->Items->Add();
+  Item->Caption = Message;
+  Item->MakeVisible(false);
+  LogView->Repaint();
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::ChangeStatus(const AnsiString Status)
+{
+  Log(Status);
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::UpdateControls()
+{
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::AdjustControls()
+{
+  AnsiString PasswordCaption = PasswordLabel->Hint;
+  bool MultiLine = false;
+  int P = PasswordCaption.Pos("\n");
+  if (P > 0)
+  {
+    MultiLine = true;
+    PasswordCaption.SetLength(P - 1);
+  }
+  P = PasswordCaption.Pos("\r");
+  if (P > 0)
+  {
+    MultiLine = true;
+    PasswordCaption.SetLength(P - 1);
+  }
+
+  bool NeedTrim;
+  TControlCanvas * PasswordLabelCanvas = new TControlCanvas();
+  try
+  {
+    PasswordLabelCanvas->Control = PasswordLabel;
+
+    NeedTrim = MultiLine ||
+      (PasswordLabelCanvas->TextWidth(PasswordCaption) > PasswordLabel->Width);
+    if (NeedTrim)
+    {
+      static AnsiString Ellipsis(" ...");
+      while (PasswordLabelCanvas->TextWidth(PasswordCaption + Ellipsis) >
+          PasswordLabel->Width)
+      {
+        PasswordCaption.SetLength(PasswordCaption.Length() - 1);
+      }
+      PasswordCaption = PasswordCaption + Ellipsis;
+    }
+  }
+  __finally
+  {
+    delete PasswordLabelCanvas;
+  }
+
+  PasswordLabel->Caption = PasswordCaption;
+  if (NeedTrim)
+  {
+    HintLabel(PasswordLabel, Hint);
+    PasswordLabel->TabStop = true;
+  }
+  else
+  {
+    HintLabelRestore(PasswordLabel);
+    PasswordLabel->TabStop = false;
+  }
+
+  if (FStatus.IsEmpty())
+  {
+    Caption = FSessionName;
+  }
+  else
+  {
+    Caption = FORMAT("%s - %s", (FStatus, FSessionName));
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TAuthenticateForm::PromptUser(AnsiString Caption,
+  TPromptKind Kind, AnsiString &Password)
+{
+  PasswordLabel->Hint = Caption;
+
+  int Title;
+  switch (Kind)
+  {
+    case pkPassword: Title = PASSWORD_TITLE; break;
+    case pkPassphrase: Title = PASSPHRASE_TITLE; break;
+    case pkServerPrompt: Title = SERVER_PASSWORD_TITLE; break;
+    default: assert(false);
+  }
+
+  bool ShowServerPanel = (Kind == pkServerPrompt);
+  if (ShowServerPanel != ServerPromptPanel->Visible)
+  {
+    ServerPromptPanel->Visible = ShowServerPanel;
+    PasswordPanel->Height += (ShowServerPanel ? 1 : -1) * ServerPromptPanel->Height;
+  }
+
+  PasswordEdit->Text = Password;
+  bool Result = Execute(LoadStr(Title), PasswordPanel, PasswordEdit,
+    PasswordOKButton, PasswordCancelButton, true, false);
+  if (Result)
+  {
+    Password = PasswordEdit->Text;
+  }
+
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::Banner(const AnsiString & Banner,
+  bool & NeverShowAgain, int Options)
+{
+  BannerMemo->Lines->Text = Banner;
+  NeverShowAgainCheck->Visible = FLAGCLEAR(Options, boDisableNeverShowAgain);
+  NeverShowAgainCheck->Checked = NeverShowAgain;
+  bool Result = Execute(LoadStr(AUTHENTICATION_BANNER), BannerPanel, BannerCloseButton,
+    BannerCloseButton, BannerCloseButton, false, true);
+  if (Result)
+  {
+    NeverShowAgain = NeverShowAgainCheck->Checked;
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TAuthenticateForm::Execute(AnsiString Status, TControl * Control,
+  TWinControl * FocusControl, TButton * DefaultButton, TButton * CancelButton,
+  bool FixHeight, bool Zoom)
+{
+  TAlign Align = Control->Align;
+  try
+  {
+    assert(FStatus.IsEmpty());
+    FStatus = Status;
+    DefaultButton->Default = true;
+    CancelButton->Cancel = true;
+
+    if (Zoom)
+    {
+      Control->Align = alClient;
+    }
+
+    if (Visible)
+    {
+      Control->Show();
+      TCursor PrevCursor = Screen->Cursor;
+      try
+      {
+        if (Zoom)
+        {
+          LogView->Hide();
+        }
+        else
+        {
+          if (LogView->Items->Count > 0)
+          {
+            TListItem * Item = LogView->ItemFocused;
+            if (Item == NULL)
+            {
+              Item = LogView->Items->Item[LogView->Items->Count - 1];
+            }
+            Item->MakeVisible(false);
+          }
+        }
+        Screen->Cursor = crDefault;
+        FocusControl->SetFocus();
+        ModalResult = mrNone;
+        AdjustControls();
+        do
+        {
+          Application->ProcessMessages();
+        }
+        while (!Application->Terminated && (ModalResult == mrNone));
+      }
+      __finally
+      {
+        Control->Hide();
+        Screen->Cursor = PrevCursor;
+        if (Zoom)
+        {
+          LogView->Show();
+        }
+        Repaint();
+      }
+    }
+    else
+    {
+      int PrevHeight = ClientHeight;
+      int PrevMinHeight = Constraints->MinHeight;
+      int PrevMaxHeight = Constraints->MaxHeight;
+      try
+      {
+        Constraints->MinHeight = 0;
+        ClientHeight = Control->Height;
+        if (FixHeight)
+        {
+          Constraints->MinHeight = Height;
+          Constraints->MaxHeight = Height;
+        }
+        LogView->Hide();
+        Control->Show();
+        FFocusControl = FocusControl;
+
+        ShowModal();
+      }
+      __finally
+      {
+        FFocusControl = NULL;
+        ClientHeight = PrevHeight;
+        Constraints->MinHeight = PrevMinHeight;
+        Constraints->MaxHeight = PrevMaxHeight;
+        Control->Hide();
+        LogView->Show();
+      }
+    }
+  }
+  __finally
+  {
+    Control->Align = Align;
+    DefaultButton->Default = false;
+    CancelButton->Cancel = false;
+    FStatus = "";
+    AdjustControls();
+  }
+
+  return (ModalResult != mrCancel);
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::FormResize(TObject * /*Sender*/)
+{
+  AdjustControls();
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::HelpButtonClick(TObject * /*Sender*/)
+{
+  FormHelp(this);
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::HideTypingCheckClick(TObject * /*Sender*/)
+{
+  PasswordEdit->Password = HideTypingCheck->Checked;
+}
+//---------------------------------------------------------------------------

+ 210 - 0
forms/Authenticate.dfm

@@ -0,0 +1,210 @@
+object AuthenticateForm: TAuthenticateForm
+  Left = 304
+  Top = 113
+  HelpType = htKeyword
+  HelpKeyword = 'ui_authenticate'
+  AutoScroll = False
+  BorderIcons = [biSystemMenu]
+  Caption = 'AuthenticateForm'
+  ClientHeight = 270
+  ClientWidth = 375
+  Color = clBtnFace
+  Constraints.MinHeight = 200
+  Constraints.MinWidth = 280
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  OnResize = FormResize
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object LogView: TListView
+    Left = 0
+    Top = 0
+    Width = 375
+    Height = 35
+    Align = alClient
+    Columns = <
+      item
+        Width = -1
+        WidthType = (
+          -1)
+      end>
+    Items.Data = {
+      2E0000000100000000000000FFFFFFFFFFFFFFFF000000000000000011417574
+      686E657469636174696E672E2E2E}
+    ReadOnly = True
+    RowSelect = True
+    ShowColumnHeaders = False
+    TabOrder = 0
+    ViewStyle = vsReport
+  end
+  object PasswordPanel: TPanel
+    Left = 0
+    Top = 35
+    Width = 375
+    Height = 153
+    Align = alBottom
+    BevelOuter = bvNone
+    TabOrder = 1
+    Visible = False
+    DesignSize = (
+      375
+      153)
+    object PasswordEditPanel: TPanel
+      Left = 0
+      Top = 0
+      Width = 375
+      Height = 50
+      Align = alTop
+      BevelOuter = bvNone
+      TabOrder = 0
+      DesignSize = (
+        375
+        50)
+      object PasswordLabel: TStaticText
+        Left = 8
+        Top = 8
+        Width = 360
+        Height = 13
+        Anchors = [akLeft, akTop, akRight]
+        AutoSize = False
+        Caption = '&PasswordX:'
+        FocusControl = PasswordEdit
+        TabOrder = 0
+      end
+      object PasswordEdit: TPasswordEdit
+        Left = 8
+        Top = 24
+        Width = 361
+        Height = 21
+        Anchors = [akLeft, akTop, akRight]
+        MaxLength = 250
+        TabOrder = 1
+      end
+    end
+    object ServerPromptPanel: TPanel
+      Left = 0
+      Top = 50
+      Width = 375
+      Height = 69
+      Align = alTop
+      BevelOuter = bvNone
+      TabOrder = 1
+      DesignSize = (
+        375
+        69)
+      object ServerPromptLabel: TLabel
+        Left = 8
+        Top = 24
+        Width = 359
+        Height = 44
+        Anchors = [akLeft, akTop, akRight, akBottom]
+        AutoSize = False
+        Caption = 
+          'Note: This prompt is issued by the server. It is part of either ' +
+          'keyboard-interactive, TIS or Cryptocard authentication.'
+        WordWrap = True
+      end
+      object HideTypingCheck: TCheckBox
+        Left = 14
+        Top = 2
+        Width = 275
+        Height = 17
+        Caption = 'Hide &typing'
+        Checked = True
+        State = cbChecked
+        TabOrder = 0
+        OnClick = HideTypingCheckClick
+      end
+    end
+    object PasswordOKButton: TButton
+      Left = 118
+      Top = 119
+      Width = 75
+      Height = 25
+      Anchors = [akRight, akBottom]
+      Caption = 'OK'
+      ModalResult = 1
+      TabOrder = 2
+    end
+    object PasswordCancelButton: TButton
+      Left = 206
+      Top = 119
+      Width = 75
+      Height = 25
+      Anchors = [akRight, akBottom]
+      Caption = 'Cancel'
+      ModalResult = 2
+      TabOrder = 3
+    end
+    object PasswordHelpButton: TButton
+      Left = 294
+      Top = 119
+      Width = 75
+      Height = 25
+      Anchors = [akRight, akBottom]
+      Caption = '&Help'
+      TabOrder = 4
+      OnClick = HelpButtonClick
+    end
+  end
+  object BannerPanel: TPanel
+    Left = 0
+    Top = 188
+    Width = 375
+    Height = 82
+    Align = alBottom
+    BevelOuter = bvNone
+    TabOrder = 2
+    Visible = False
+    DesignSize = (
+      375
+      82)
+    object BannerMemo: TMemo
+      Left = 8
+      Top = 8
+      Width = 360
+      Height = 34
+      Anchors = [akLeft, akTop, akRight, akBottom]
+      Color = clBtnFace
+      ReadOnly = True
+      ScrollBars = ssVertical
+      TabOrder = 0
+      WantReturns = False
+    end
+    object NeverShowAgainCheck: TCheckBox
+      Left = 15
+      Top = 53
+      Width = 188
+      Height = 17
+      Anchors = [akLeft, akRight, akBottom]
+      Caption = '&Never show this banner again'
+      TabOrder = 1
+    end
+    object BannerCloseButton: TButton
+      Left = 206
+      Top = 47
+      Width = 75
+      Height = 25
+      Anchors = [akRight, akBottom]
+      Caption = 'Continue'
+      ModalResult = 1
+      TabOrder = 2
+    end
+    object BannerHelpButton: TButton
+      Left = 292
+      Top = 47
+      Width = 75
+      Height = 25
+      Anchors = [akRight, akBottom]
+      Caption = '&Help'
+      TabOrder = 3
+      OnClick = HelpButtonClick
+    end
+  end
+end

+ 66 - 0
forms/Authenticate.h

@@ -0,0 +1,66 @@
+//---------------------------------------------------------------------------
+#ifndef AuthenticateH
+#define AuthenticateH
+//---------------------------------------------------------------------------
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <ComCtrls.hpp>
+#include <ExtCtrls.hpp>
+#include "PasswordEdit.hpp"
+#include "WinInterface.h"
+//---------------------------------------------------------------------------
+class TAuthenticateForm : public TForm
+{
+__published:
+  TListView *LogView;
+  TPanel *PasswordPanel;
+  TPanel *PasswordEditPanel;
+  TStaticText *PasswordLabel;
+  TPasswordEdit *PasswordEdit;
+  TPanel *ServerPromptPanel;
+  TLabel *ServerPromptLabel;
+  TCheckBox *HideTypingCheck;
+  TButton *PasswordOKButton;
+  TButton *PasswordCancelButton;
+  TButton *PasswordHelpButton;
+  TPanel *BannerPanel;
+  TMemo *BannerMemo;
+  TCheckBox *NeverShowAgainCheck;
+  TButton *BannerCloseButton;
+  TButton *BannerHelpButton;
+  void __fastcall FormShow(TObject *Sender);
+  void __fastcall FormResize(TObject *Sender);
+  void __fastcall HelpButtonClick(TObject *Sender);
+  void __fastcall HideTypingCheckClick(TObject *Sender);
+
+public:
+  __fastcall TAuthenticateForm(TComponent * Owner, AnsiString SessionName);
+  virtual __fastcall ~TAuthenticateForm();
+
+  void __fastcall ShowAsModal();
+  void __fastcall HideAsModal();
+  void __fastcall Log(const AnsiString Message);
+  void __fastcall ChangeStatus(const AnsiString Status);
+  bool __fastcall PromptUser(AnsiString Caption,
+    TPromptKind Kind, AnsiString &Password);
+  void __fastcall Banner(const AnsiString & Banner, bool & NeverShowAgain,
+    int Options);
+
+protected:
+  void __fastcall ClearLog();
+  void __fastcall AdjustControls();
+  void __fastcall UpdateControls();
+  bool __fastcall Execute(AnsiString Status, TControl * Control,
+    TWinControl * FocusControl, TButton * DefaultButton, TButton * CancelButton,
+    bool FixHeight, bool Zoom);
+
+private:
+  void * FShowAsModalStorage;
+  TWinControl * FFocusControl;
+  AnsiString FSessionName;
+  AnsiString FStatus;
+};
+//---------------------------------------------------------------------------
+#endif

+ 0 - 54
forms/Banner.cpp

@@ -1,54 +0,0 @@
-//---------------------------------------------------------------------------
-#include <vcl.h>
-#pragma hdrstop
-
-#include <Common.h>
-
-#include <VCLCommon.h>
-#include "WinInterface.h"
-#include "Banner.h"
-//---------------------------------------------------------------------------
-#pragma package(smart_init)
-#pragma resource "*.dfm"
-//---------------------------------------------------------------------------
-void __fastcall DoBannerDialog(AnsiString SessionName, const AnsiString & Banner,
-  bool & NeverShowAgain)
-{
-  TBannerDialog * BannerDialog = NULL;
-  try
-  {
-    BannerDialog = new TBannerDialog(Application, SessionName, Banner);
-    BannerDialog->Execute(NeverShowAgain);
-  }
-  __finally
-  {
-    delete BannerDialog;
-  }
-}
-//---------------------------------------------------------------------------
-__fastcall TBannerDialog::TBannerDialog(TComponent * Owner,
-  AnsiString SessionName, const AnsiString & Banner)
-  : TForm(Owner)
-{
-  UseSystemSettings(this);
-  Caption = FORMAT("%s - %s", (Caption, SessionName));
-  BannerMemo->Lines->Text = Banner;
-}
-//---------------------------------------------------------------------------
-bool __fastcall TBannerDialog::Execute(bool & NeverShowAgain)
-{
-  NeverShowAgainCheck->Checked = NeverShowAgain;
-  bool Result = (ShowModal() == mrOk);
-  if (Result)
-  {
-    NeverShowAgain = NeverShowAgainCheck->Checked;
-  }
-  return Result;
-}
-//---------------------------------------------------------------------------
-void __fastcall TBannerDialog::HelpButtonClick(TObject * /*Sender*/)
-{
-  FormHelp(this);
-}
-//---------------------------------------------------------------------------
-

+ 0 - 64
forms/Banner.dfm

@@ -1,64 +0,0 @@
-object BannerDialog: TBannerDialog
-  Left = 413
-  Top = 230
-  HelpType = htKeyword
-  HelpKeyword = 'ui_banner'
-  ActiveControl = CloseButton
-  BorderIcons = [biSystemMenu]
-  BorderStyle = bsDialog
-  Caption = 'Authentication Banner'
-  ClientHeight = 291
-  ClientWidth = 440
-  Color = clBtnFace
-  ParentFont = True
-  OldCreateOrder = True
-  Position = poOwnerFormCenter
-  DesignSize = (
-    440
-    291)
-  PixelsPerInch = 96
-  TextHeight = 13
-  object CloseButton: TButton
-    Left = 273
-    Top = 256
-    Width = 75
-    Height = 25
-    Anchors = [akRight, akBottom]
-    Cancel = True
-    Caption = 'Close'
-    Default = True
-    ModalResult = 1
-    TabOrder = 0
-  end
-  object BannerMemo: TMemo
-    Left = 8
-    Top = 8
-    Width = 425
-    Height = 244
-    Anchors = [akLeft, akTop, akRight, akBottom]
-    Color = clBtnFace
-    ReadOnly = True
-    ScrollBars = ssVertical
-    TabOrder = 2
-    WantReturns = False
-  end
-  object NeverShowAgainCheck: TCheckBox
-    Left = 15
-    Top = 262
-    Width = 250
-    Height = 17
-    Anchors = [akLeft, akRight, akBottom]
-    Caption = '&Never show this banner again'
-    TabOrder = 3
-  end
-  object HelpButton: TButton
-    Left = 357
-    Top = 256
-    Width = 75
-    Height = 25
-    Anchors = [akRight, akBottom]
-    Caption = '&Help'
-    TabOrder = 1
-    OnClick = HelpButtonClick
-  end
-end

+ 0 - 28
forms/Banner.h

@@ -1,28 +0,0 @@
-//---------------------------------------------------------------------------
-#ifndef BannerH
-#define BannerH
-//---------------------------------------------------------------------------
-#include <Classes.hpp>
-#include <Controls.hpp>
-#include <StdCtrls.hpp>
-#include <Forms.hpp>
-#include <Mask.hpp>
-
-#include "WinInterface.h"
-//---------------------------------------------------------------------------
-class TBannerDialog : public TForm
-{
-__published:
-  TButton *CloseButton;
-  TMemo *BannerMemo;
-  TCheckBox *NeverShowAgainCheck;
-  TButton *HelpButton;
-  void __fastcall HelpButtonClick(TObject *Sender);
-
-public:
-  __fastcall TBannerDialog(TComponent * Owner, AnsiString SessionName,
-    const AnsiString & Banner);
-  bool __fastcall Execute(bool & NeverShowAgain);
-};
-//---------------------------------------------------------------------------
-#endif

+ 92 - 11
forms/Console.cpp

@@ -38,6 +38,7 @@ __fastcall TConsoleDialog::TConsoleDialog(TComponent* AOwner)
 {
   FTerminal = NULL;
   FOldChangeDirectory = NULL;
+  FPrevTerminalClose = NULL;;
   FLastTerminal = NULL;
   OutputMemo->Color = clBlack;
   OutputMemo->Font->Color = (TColor)0x00BBBBBB; //clGray;
@@ -62,6 +63,8 @@ void __fastcall TConsoleDialog::SetTerminal(TTerminal * value)
   {
     if (FTerminal)
     {
+      assert(FTerminal->OnClose == TerminalClose);
+      FTerminal->OnClose = FPrevTerminalClose;
       assert(FTerminal->OnChangeDirectory == DoChangeDirectory);
       FTerminal->OnChangeDirectory = FOldChangeDirectory;
       FOldChangeDirectory = NULL;
@@ -76,6 +79,9 @@ void __fastcall TConsoleDialog::SetTerminal(TTerminal * value)
       // avoid reloading directory after each change of current directory from console
       FTerminal->BeginTransaction();
       FLastTerminal = FTerminal;
+      FPrevTerminalClose = FTerminal->OnClose;
+      // used instead of previous TTerminalManager::OnChangeTerminal
+      FTerminal->OnClose = TerminalClose;
     }
     UpdateControls();
   }
@@ -97,14 +103,6 @@ void __fastcall TConsoleDialog::UpdateControls()
 bool __fastcall TConsoleDialog::Execute(const AnsiString Command,
   const TStrings * Log)
 {
-  FPrevTerminalClose = NULL;;
-  if (FTerminal)
-  {
-    FPrevTerminalClose = FTerminal->OnClose;
-    // used instead of previous TTerminalManager::OnChangeTerminal
-    FTerminal->OnClose = TerminalClose;
-  }
-  
   try
   {
     CommandEdit->Items = CustomWinConfiguration->History["Commands"];
@@ -132,13 +130,19 @@ bool __fastcall TConsoleDialog::Execute(const AnsiString Command,
       DoExecuteCommand();
     }
     ShowModal();
+
+    TConsoleWinConfiguration ConsoleWin = CustomWinConfiguration->ConsoleWin;
+    if ((FAutoBounds.Width() != Width) ||
+        (FAutoBounds.Height() != Height))
+    {
+      ConsoleWin.WindowSize = FORMAT("%d,%d", (Width, Height));
+    }
+    CustomWinConfiguration->ConsoleWin = ConsoleWin;
   }
   __finally
   {
     if (FTerminal)
     {
-      assert(FTerminal->OnClose == TerminalClose);
-      FTerminal->OnClose = FPrevTerminalClose;
       CommandEdit->SaveToHistory();
       CustomWinConfiguration->History["Commands"] = CommandEdit->Items;
     }
@@ -220,7 +224,8 @@ void __fastcall TConsoleDialog::AddLine(TLogLineType Type, const AnsiString & Li
 void __fastcall TConsoleDialog::CreateParams(TCreateParams & Params)
 {
   TForm::CreateParams(Params);
-  Params.Style = Params.Style & ~WS_SYSMENU;
+  // we no longer exclude WS_SYSMENU, was there any reason for that, apart from
+  // hidding the window icon?
 }
 //---------------------------------------------------------------------------
 void __fastcall TConsoleDialog::HelpButtonClick(TObject * /*Sender*/)
@@ -228,4 +233,80 @@ void __fastcall TConsoleDialog::HelpButtonClick(TObject * /*Sender*/)
   FormHelp(this);
 }
 //---------------------------------------------------------------------------
+void __fastcall TConsoleDialog::DoAdjustWindow()
+{
+  HFONT OldFont;
+  void * DC;
+  TTextMetric TM;
+  TRect Rect;
+
+  DC = GetDC(OutputMemo->Handle);
+  OldFont = SelectObject(DC, OutputMemo->Font->Handle);
+
+  try
+  {
+    GetTextMetrics(DC, &TM);
+
+    OutputMemo->Perform(EM_GETRECT, 0, ((int)&Rect));
+  }
+  __finally
+  {
+    SelectObject(DC, OldFont);
+    ReleaseDC(OutputMemo->Handle, DC);
+  }
+
+  int Rows = OutputMemo->Lines->Count;
+  int Columns = 0;
+  for (int Index = 0; Index < Rows; Index++)
+  {
+    int Len = OutputMemo->Lines->Strings[Index].Length();
+    if (Columns < Len)
+    {
+      Columns = Len;
+    }
+  }
+
+  // 10 is surplus to cover any borders, etc.
+  int RequiredWidth = (TM.tmAveCharWidth * Columns) + 10;
+  // thre is always one line more
+  int RequiredHeight = (TM.tmHeight + TM.tmExternalLeading) * (Rows + 1) + 10;
+
+  int CurrentWidth = (Rect.Right - Rect.Left);
+  int CurrentHeight = (Rect.Bottom - Rect.Top);
+
+  ResizeForm(this,
+    Width + (RequiredWidth - CurrentWidth),
+    Height + (RequiredHeight - CurrentHeight));
+  FAutoBounds = BoundsRect;
+}
+//---------------------------------------------------------------------------
+void __fastcall TConsoleDialog::ActionListExecute(TBasicAction * Action,
+  bool & Handled)
+{
+  if (Action == AdjustWindow)
+  {
+    DoAdjustWindow();
+    Handled = true;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TConsoleDialog::ActionListUpdate(TBasicAction * Action,
+  bool & Handled)
+{
+  if (Action == AdjustWindow)
+  {
+    Handled = true;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TConsoleDialog::FormShow(TObject * /*Sender*/)
+{
+  UpdateFormPosition(this, poMainFormCenter);
+  AnsiString WindowSize = CustomWinConfiguration->ConsoleWin.WindowSize;
+  int Width = StrToIntDef(CutToChar(WindowSize, ',', true), Width);
+  int Height = StrToIntDef(CutToChar(WindowSize, ',', true), Height);
+  ResizeForm(this, Width, Height);
+  FAutoBounds = BoundsRect;
+}
+//---------------------------------------------------------------------------
 

+ 189 - 4
forms/Console.dfm

@@ -12,10 +12,10 @@ object ConsoleDialog: TConsoleDialog
   Constraints.MinWidth = 380
   ParentFont = True
   OldCreateOrder = True
-  Position = poMainFormCenter
+  OnShow = FormShow
   DesignSize = (
     559
-    404)
+    397)
   PixelsPerInch = 96
   TextHeight = 13
   object Bevel1: TBevel
@@ -44,8 +44,10 @@ object ConsoleDialog: TConsoleDialog
   object Label4: TLabel
     Left = 13
     Top = 34
-    Width = 286
+    Width = 452
     Height = 13
+    Anchors = [akLeft, akTop, akRight]
+    AutoSize = False
     Caption = 'Warning: Do NOT execute commands that require user-input'
   end
   object DirectoryLabel: TPathLabel
@@ -63,10 +65,11 @@ object ConsoleDialog: TConsoleDialog
     Left = 0
     Top = 78
     Width = 559
-    Height = 326
+    Height = 319
     TabStop = False
     Align = alClient
     Color = clBtnFace
+    PopupMenu = PopupMenu
     ReadOnly = True
     ScrollBars = ssBoth
     TabOrder = 4
@@ -116,4 +119,186 @@ object ConsoleDialog: TConsoleDialog
     TabOrder = 3
     OnClick = HelpButtonClick
   end
+  object Images: TImageList
+    Left = 456
+    Top = 160
+    Bitmap = {
+      494C010103000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      0000000000003600000028000000400000001000000001002000000000000010
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000008080800080808000808080008080
+      8000808080008080800080808000808080008080800080808000808080008080
+      8000808080008080800080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000840000008400000084000000840000008400
+      000084000000840000008400000084000000000000000000000000000000BD00
+      00000000000000000000BD0000000000000000000000BD000000000000000000
+      0000BD0000000000000000000000000000008080800000000000000000000000
+      0000000000000000000000000000800000000000000000000000000000000000
+      0000000000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000084000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF008400000000000000BD000000000000000000
+      0000BD0000000000000000000000BD0000000000000000000000BD0000000000
+      000000000000BD00000000000000000000008080800000000000000000000000
+      0000000000000000000080000000800000008000000000000000000000000000
+      0000000000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000084000000FFFFFF0000000000000000000000
+      00000000000000000000FFFFFF00840000000000000000000000BD0000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000BD000000000000008080800000000000000000000000
+      0000000000008000000080000000800000008000000080000000000000000000
+      0000000000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000084000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF0084000000000000000000000000000000BD00
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000BD0000000000000000000000000000008080800000000000000000000000
+      0000000000000000000000000000800000000000000000000000000000000000
+      0000000000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF0084000000FFFFFF0000000000000000000000
+      00000000000000000000FFFFFF008400000000000000BD000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000BD00000000000000000000008080800000000000000000008000
+      0000000000000000000000000000800000000000000000000000000000008000
+      0000000000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF000000
+      000000000000000000000000000084000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00840000000000000000000000BD0000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000BD000000000000008080800000000000800000008000
+      0000000000000000000000000000000000000000000000000000000000008000
+      0000800000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF0084000000FFFFFF000000000000000000FFFF
+      FF0084000000840000008400000084000000000000000000000000000000BD00
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000BD0000000000000000000000000000008080800080000000800000008000
+      0000800000008000000000000000000000000000000080000000800000008000
+      0000800000008000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF000000
+      000000000000000000000000000084000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF0084000000FFFFFF00840000000000000000000000BD000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000BD00000000000000000000008080800000000000800000008000
+      0000000000000000000000000000000000000000000000000000000000008000
+      0000800000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF0084000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00840000008400000000000000000000000000000000000000BD0000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000BD000000000000008080800000000000000000008000
+      0000000000000000000000000000800000000000000000000000000000008000
+      0000000000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF000000
+      000000000000FFFFFF0000000000840000008400000084000000840000008400
+      000084000000000000000000000000000000000000000000000000000000BD00
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000BD0000000000000000000000000000008080800000000000000000000000
+      0000000000000000000000000000800000000000000000000000000000000000
+      0000000000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000000000FFFFFF000000000000000000000000000000
+      00000000000000000000000000000000000000000000BD000000000000000000
+      0000BD0000000000000000000000000000000000000000000000000000000000
+      000000000000BD00000000000000000000008080800000000000000000000000
+      0000000000008000000080000000800000008000000080000000000000000000
+      0000000000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000BD0000000000
+      000000000000BD0000000000000000000000BD0000000000000000000000BD00
+      00000000000000000000BD000000000000008080800000000000000000000000
+      0000000000000000000080000000800000008000000000000000000000000000
+      0000000000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000BD00
+      00000000000000000000BD0000000000000000000000BD000000000000000000
+      0000BD0000000000000000000000000000008080800000000000000000000000
+      0000000000000000000000000000800000000000000000000000000000000000
+      0000000000000000000080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000008080800080808000808080008080
+      8000808080008080800080808000808080008080800080808000808080008080
+      8000808080008080800080808000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000424D3E000000000000003E000000
+      2800000040000000100000000100010000000000800000000000000000000000
+      000000000000000000000000FFFFFF00FFFFFFFFFFFF0000FFFFFFFF00010000
+      FE00EDB77EFD0000FE00B6DB7C7D0000FE00DFFD783D00008000EC177EFD0000
+      8000B99B6EED00008000D99D4FE500008000EC97038100008001BE1B4FE50000
+      8003DB9D6EED00008007EC377EFD0000807FB7FB783D000080FFDB6D7C7D0000
+      81FFEDB77EFD0000FFFFFFFF0001000000000000000000000000000000000000
+      000000000000}
+  end
+  object PopupMenu: TPopupMenu
+    Images = Images
+    Left = 456
+    Top = 224
+    object CopyItem: TMenuItem
+      Action = EditCopy
+    end
+    object SelectAllItem: TMenuItem
+      Action = EditSelectAll
+    end
+    object N1: TMenuItem
+      Caption = '-'
+    end
+    object AdjustWindowItem: TMenuItem
+      Action = AdjustWindow
+    end
+  end
+  object ActionList: TActionList
+    Images = Images
+    OnExecute = ActionListExecute
+    OnUpdate = ActionListUpdate
+    Left = 456
+    Top = 192
+    object EditCopy: TEditCopy
+      Caption = '&Copy'
+      ImageIndex = 0
+      ShortCut = 16451
+    end
+    object EditSelectAll: TEditSelectAll
+      Caption = 'Select &All'
+      ImageIndex = 1
+      ShortCut = 16449
+    end
+    object AdjustWindow: TAction
+      Caption = 'Adjust &Window'
+      ImageIndex = 2
+      ShortCut = 16458
+    end
+  end
 end

+ 20 - 1
forms/Console.h

@@ -17,6 +17,10 @@
 #include <PathLabel.hpp>
 
 #include <Terminal.h>
+#include <ImgList.hpp>
+#include <Menus.hpp>
+#include <ActnList.hpp>
+#include <StdActns.hpp>
 //----------------------------------------------------------------------------
 class TConsoleDialog : public TForm
 {
@@ -31,16 +35,30 @@ __published:
   TButton *ExecuteButton;
   TPathLabel *DirectoryLabel;
   TButton *HelpButton;
+  TImageList *Images;
+  TPopupMenu *PopupMenu;
+  TMenuItem *SelectAllItem;
+  TMenuItem *CopyItem;
+  TMenuItem *N1;
+  TMenuItem *AdjustWindowItem;
+  TActionList *ActionList;
+  TEditCopy *EditCopy;
+  TEditSelectAll *EditSelectAll;
+  TAction *AdjustWindow;
   void __fastcall ExecuteButtonClick(TObject *Sender);
   void __fastcall CommandEditChange(TObject *Sender);
   void __fastcall HelpButtonClick(TObject *Sender);
+  void __fastcall ActionListExecute(TBasicAction *Action, bool &Handled);
+  void __fastcall ActionListUpdate(TBasicAction *Action, bool &Handled);
+  void __fastcall FormShow(TObject *Sender);
   
 private:
   TTerminal * FTerminal;
   TTerminal * FLastTerminal;
   TNotifyEvent FOldChangeDirectory;
   TNotifyEvent FPrevTerminalClose;
-  
+  TRect FAutoBounds;
+
   void __fastcall DoExecuteCommand();
   void __fastcall ExecuteCommand();
   void __fastcall SetTerminal(TTerminal * value);
@@ -53,6 +71,7 @@ protected:
     const AnsiString AddedLine);
   void __fastcall UpdateControls();
   virtual void __fastcall CreateParams(TCreateParams & Params);
+  void __fastcall DoAdjustWindow();
 
 public:
   virtual __fastcall ~TConsoleDialog();

+ 22 - 15
forms/Copy.cpp

@@ -8,6 +8,7 @@
 #include <TextsWin.h>
 #include <VCLCommon.h>
 #include <CustomWinConfiguration.h>
+#include <Tools.h>
 
 #include "Copy.h"
 //---------------------------------------------------------------------------
@@ -20,13 +21,13 @@
 //---------------------------------------------------------------------------
 bool __fastcall DoCopyDialog(bool ToRemote,
   bool Move, TStrings * FileList, AnsiString & TargetDirectory,
-  TGUICopyParamType * Params, int Options, int * OutputOptions)
+  TGUICopyParamType * Params, int Options, int CopyParamAttrs, int * OutputOptions)
 {
   bool Result;
   TCopyDialog *CopyDialog = new TCopyDialog(Application);
   try
   {
-    if ((Options & coDisableTransferMode) != 0)
+    if (FLAGSET(CopyParamAttrs, cpaNoTransferMode))
     {
       // If local and remote EOL types are the same, there is no need
       // for ASCII (or Automatic) mode
@@ -34,6 +35,7 @@ bool __fastcall DoCopyDialog(bool ToRemote,
     }
     CopyDialog->ToRemote = ToRemote;
     CopyDialog->Options = Options;
+    CopyDialog->CopyParamAttrs = CopyParamAttrs;
     if (OutputOptions != NULL)
     {
       CopyDialog->OutputOptions = *OutputOptions;
@@ -163,10 +165,7 @@ void __fastcall TCopyDialog::AdjustTransferControls()
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::AdjustControls()
 {
-  if (FLAGSET(Options, coDoNotShowAgain))
-  {
-    SaveSettingsCheck->Caption = LoadStr(NEVER_SHOW_DIALOG_AGAIN);
-  }
+  NeverShowAgainCheck->Visible = FLAGSET(Options, coDoNotShowAgain);
   RemoteDirectoryEdit->Visible = false;
   LocalDirectoryEdit->Visible = false;
   DirectoryEdit->Visible = FLAGCLEAR(Options, coTemp);
@@ -175,10 +174,6 @@ void __fastcall TCopyDialog::AdjustControls()
   EnableControl(LocalDirectoryBrowseButton, DirectoryEdit->Enabled);
   DirectoryLabel->FocusControl = DirectoryEdit;
   CopyParamsFrame->Direction = !ToRemote ? pdToLocal : pdToRemote;
-  CopyParamsFrame->Options =
-    FLAGMASK(FLAGCLEAR(Options, coDisableTransferMode), cfAllowTransferMode) |
-    FLAGMASK(!Move, cfAllowExcludeMask) |
-    FLAGMASK(!Move && ToRemote, cfAllowClearArchive);
   PresetsButton->Visible = FLAGCLEAR(Options, coDoNotUsePresets);
 
   AdjustTransferControls();
@@ -215,15 +210,27 @@ void __fastcall TCopyDialog::SetOutputOptions(int value)
 {
   if (OutputOptions != value)
   {
-    SaveSettingsCheck->Checked = FLAGSET(FOutputOptions, cooDoNotShowAgain);
-    FOutputOptions = (value & ~cooDoNotShowAgain);
+    SaveSettingsCheck->Checked = FLAGSET(FOutputOptions, cooSaveSettings);
+    NeverShowAgainCheck->Checked = FLAGSET(FOutputOptions, cooDoNotShowAgain);
+    FOutputOptions = (value & ~(cooDoNotShowAgain | cooSaveSettings));
   }
 }
 //---------------------------------------------------------------------------
 int __fastcall TCopyDialog::GetOutputOptions()
 {
   return FOutputOptions |
-    FLAGMASK(SaveSettingsCheck->Checked, cooDoNotShowAgain);
+    FLAGMASK(SaveSettingsCheck->Checked, cooSaveSettings) |
+    FLAGMASK(NeverShowAgainCheck->Checked, cooDoNotShowAgain);
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyDialog::SetCopyParamAttrs(int value)
+{
+  CopyParamsFrame->CopyParamAttrs = value;
+}
+//---------------------------------------------------------------------------
+int __fastcall TCopyDialog::GetCopyParamAttrs()
+{
+  return CopyParamsFrame->CopyParamAttrs;
 }
 //---------------------------------------------------------------------------
 THistoryComboBox * __fastcall TCopyDialog::GetDirectoryEdit()
@@ -430,7 +437,7 @@ void __fastcall TCopyDialog::FormCloseQuery(TObject * /*Sender*/,
 
     if (CanClose)
     {
-      CopyParamsFrame->Validate();
+      ExitActiveControl(this);
     }
   }
 }
@@ -470,7 +477,7 @@ void __fastcall TCopyDialog::PresetsButtonClick(TObject * /*Sender*/)
 void __fastcall TCopyDialog::CopyParamClick(TObject * Sender)
 {
   TCopyParamType Param = Params;
-  if (CopyParamListPopupClick(Sender, Param, FPreset))
+  if (CopyParamListPopupClick(Sender, Param, FPreset, CopyParamAttrs))
   {
     Params = Param;
   }

+ 14 - 1
forms/Copy.dfm

@@ -96,10 +96,13 @@ object CopyDialog: TCopyDialog
     Anchors = [akLeft, akTop, akRight, akBottom]
     BevelOuter = bvNone
     TabOrder = 3
+    DesignSize = (
+      511
+      253)
     object SaveSettingsCheck: TCheckBox
       Left = 8
       Top = 235
-      Width = 377
+      Width = 301
       Height = 17
       Caption = 'Use &same settings next time'
       TabOrder = 2
@@ -119,6 +122,16 @@ object CopyDialog: TCopyDialog
       Caption = 'N&ew and updated file(s) only'
       TabOrder = 1
     end
+    object NeverShowAgainCheck: TCheckBox
+      Left = 312
+      Top = 235
+      Width = 193
+      Height = 17
+      Anchors = [akLeft, akBottom]
+      Caption = 'Do not show this dialog box again'
+      TabOrder = 3
+      OnClick = ControlChange
+    end
   end
   object LocalDirectoryBrowseButton: TButton
     Left = 427

+ 4 - 0
forms/Copy.h

@@ -33,6 +33,7 @@ __published:
   TCheckBox *NewerOnlyCheck;
   TButton *PresetsButton;
   TButton *HelpButton;
+  TCheckBox *NeverShowAgainCheck;
   void __fastcall FormShow(TObject *Sender);
   void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
   void __fastcall LocalDirectoryBrowseButtonClick(TObject *Sender);
@@ -61,6 +62,8 @@ private:
   void __fastcall SetOptions(int value);
   void __fastcall SetOutputOptions(int value);
   int __fastcall GetOutputOptions();
+  void __fastcall SetCopyParamAttrs(int value);
+  int __fastcall GetCopyParamAttrs();
   void __fastcall CopyParamClick(TObject * Sender);
 protected:
   void __fastcall UpdateControls();
@@ -79,6 +82,7 @@ public:
   __property TGUICopyParamType Params = { read = GetParams, write = SetParams };
   __property bool Move = { read = FMove, write = SetMove };
   __property int Options = { read = FOptions, write = SetOptions };
+  __property int CopyParamAttrs = { read = GetCopyParamAttrs, write = SetCopyParamAttrs };
   __property int OutputOptions = { read = GetOutputOptions, write = SetOutputOptions };
 };
 //---------------------------------------------------------------------------

+ 7 - 8
forms/CopyParamCustom.cpp

@@ -6,6 +6,7 @@
 #include <TextsWin.h>
 #include <GUIConfiguration.h>
 #include <GUITools.h>
+#include <Tools.h>
 #include "CopyParamCustom.h"
 #include "VCLCommon.h"
 //---------------------------------------------------------------------------
@@ -14,11 +15,12 @@
 #pragma link "CopyParams"
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------------
-bool __fastcall DoCopyParamCustomDialog(TCopyParamType & CopyParam, int Options)
+bool __fastcall DoCopyParamCustomDialog(TCopyParamType & CopyParam,
+  int CopyParamAttrs)
 {
   bool Result;
   TCopyParamCustomDialog * Dialog = new TCopyParamCustomDialog(
-    Application, Options, 0);
+    Application, CopyParamAttrs, 0);
   try
   {
     Result = Dialog->Execute(CopyParam);
@@ -32,15 +34,12 @@ bool __fastcall DoCopyParamCustomDialog(TCopyParamType & CopyParam, int Options)
 //---------------------------------------------------------------------------
 // Dummy parameter distinguishes the constructor from Object Pascals TForm::CreateNew
 __fastcall TCopyParamCustomDialog::TCopyParamCustomDialog(TComponent * Owner,
-  int Options, int /*Dummy*/)
+  int CopyParamAttrs, int /*Dummy*/)
   : TForm(Owner)
 {
   UseSystemSettings(this);
   CopyParamsFrame->Direction = pdAll;
-  if (Options >= 0)
-  {
-    CopyParamsFrame->Options = Options;
-  }
+  CopyParamsFrame->CopyParamAttrs = CopyParamAttrs;
 }
 //---------------------------------------------------------------------------
 bool __fastcall TCopyParamCustomDialog::Execute(TCopyParamType & CopyParam)
@@ -65,7 +64,7 @@ void __fastcall TCopyParamCustomDialog::FormCloseQuery(TObject * /*Sender*/,
 {
   if (ModalResult != mrCancel)
   {
-    CopyParamsFrame->Validate();
+    ExitActiveControl(this);
   }
 }
 //---------------------------------------------------------------------------

+ 0 - 3
forms/CopyParamCustom.dfm

@@ -84,9 +84,6 @@ object CopyParamCustomDialog: TCopyParamCustomDialog
       Width = 182
       Height = 126
       Caption = 'Upload options'
-      inherited RemotePreserveTimeCheck: TCheckBox
-        Top = 161
-      end
     end
     inherited ChangeCaseGroup: TXPGroupBox
       Left = 247

+ 0 - 2
forms/CopyParamPreset.cpp

@@ -168,8 +168,6 @@ void __fastcall TCopyParamPresetDialog::FormCloseQuery(TObject * /*Sender*/,
 {
   if (ModalResult != mrCancel)
   {
-    CopyParamsFrame->Validate();
-
     AnsiString Description = DescriptionEdit->Text;
     TCopyParamList::ValidateName(Description);
 

+ 0 - 3
forms/CopyParamPreset.dfm

@@ -101,9 +101,6 @@ object CopyParamPresetDialog: TCopyParamPresetDialog
       Width = 182
       Height = 126
       Caption = 'Upload options'
-      inherited RemotePreserveTimeCheck: TCheckBox
-        Top = 161
-      end
     end
     inherited ChangeCaseGroup: TXPGroupBox
       Left = 247

+ 121 - 31
forms/CopyParams.cpp

@@ -16,17 +16,28 @@
 #pragma link "Rights"
 #pragma link "HistoryComboBox"
 #pragma link "XPThemes"
+#pragma link "ComboEdit"
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------------
 __fastcall TCopyParamsFrame::TCopyParamsFrame(TComponent* Owner)
         : TFrame(Owner)
 {
+  FAddXToDirectoriesSuffix = "+x";
+
+  FRightsFrame = new TRightsExtFrame(this);
+  FRightsFrame->TabStop = false;
+  FRightsFrame->Parent = this;
+  FRightsFrame->TabOrder = 1000;
+  FRightsFrame->AllowAddXToDirectories = True;
+  FRightsFrame->Popup = true;
+  FRightsFrame->PopupParent = RightsEdit;
+  FRightsFrame->OnChange = RightsFrameChange;
+
   // on start set different value than we want to allow property-setter to proceed
   FDirection = pdToLocal;
   Direction = pdToRemote;
 
-  FOptions = cfAllowTransferMode | cfAllowExcludeMask | cfAllowClearArchive;
-  RightsFrame->AllowAddXToDirectories = True;
+  FCopyParamAttrs = 0;
   FParams = new TCopyParamType();
   TCopyParamType DefParams;
   Params = DefParams;
@@ -65,9 +76,10 @@ void __fastcall TCopyParamsFrame::SetParams(TCopyParamType value)
   ReplaceInvalidCharsCheck->Checked =
     (value.InvalidCharsReplacement != TCopyParamType::NoReplacement);
 
-  RightsFrame->AddXToDirectories = value.AddXToDirectories;
-  RightsFrame->Rights = value.Rights;
+  FRightsFrame->AddXToDirectories = value.AddXToDirectories;
+  FRightsFrame->Rights = value.Rights;
   PreserveRightsCheck->Checked = value.PreserveRights;
+  IgnorePermErrorsCheck->Checked = value.IgnorePermErrors;
   PreserveReadOnlyCheck->Checked = value.PreserveReadOnly;
 
   assert(PreserveTimeCheck);
@@ -108,9 +120,10 @@ TCopyParamType __fastcall TCopyParamsFrame::GetParams()
 
   Result.ReplaceInvalidChars = ReplaceInvalidCharsCheck->Checked;
 
-  Result.AddXToDirectories = RightsFrame->AddXToDirectories;
-  Result.Rights = RightsFrame->Rights;
+  Result.AddXToDirectories = FRightsFrame->AddXToDirectories;
+  Result.Rights = FRightsFrame->Rights;
   Result.PreserveRights = PreserveRightsCheck->Checked;
+  Result.IgnorePermErrors = IgnorePermErrorsCheck->Checked;
   Result.PreserveReadOnly = PreserveReadOnlyCheck->Checked;
 
   assert(PreserveTimeCheck);
@@ -138,29 +151,39 @@ TCheckBox * __fastcall TCopyParamsFrame::GetPreserveTimeCheck()
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamsFrame::UpdateControls()
 {
-  EnableControl(CommonPropertiesGroup, FLAGCLEAR(Options, cfAllowExcludeMaskOnly) && Enabled);
-  EnableControl(LocalPropertiesGroup, FLAGCLEAR(Options, cfAllowExcludeMaskOnly) && Enabled);
-  EnableControl(RemotePropertiesGroup, FLAGCLEAR(Options, cfAllowExcludeMaskOnly) && Enabled);
+  EnableControl(CommonPropertiesGroup, FLAGCLEAR(CopyParamAttrs, cpaExcludeMaskOnly) && Enabled);
+  EnableControl(LocalPropertiesGroup, FLAGCLEAR(CopyParamAttrs, cpaExcludeMaskOnly) && Enabled);
+  EnableControl(RemotePropertiesGroup, FLAGCLEAR(CopyParamAttrs, cpaExcludeMaskOnly) && Enabled);
   EnableControl(TransferModeGroup,
-    FLAGSET(Options, cfAllowTransferMode) &&
-    FLAGCLEAR(Options, cfAllowExcludeMaskOnly) && Enabled);
+    FLAGCLEAR(CopyParamAttrs, cpaNoTransferMode) &&
+    FLAGCLEAR(CopyParamAttrs, cpaExcludeMaskOnly) && Enabled);
   EnableControl(AsciiFileMaskLabel,
     TransferModeGroup->Enabled && TMAutomaticButton->Checked);
   EnableControl(AsciiFileMaskCombo,
     TransferModeGroup->Enabled && TMAutomaticButton->Checked);
-  EnableControl(PreserveRightsCheck, FLAGCLEAR(Options, cfAllowExcludeMaskOnly) && Enabled);
-  EnableControl(RightsFrame, PreserveRightsCheck->Checked &&
+  EnableControl(PreserveRightsCheck, FLAGCLEAR(CopyParamAttrs, cpaExcludeMaskOnly) &&
+    FLAGCLEAR(CopyParamAttrs, cpaNoRights) && Enabled);
+  EnableControl(RightsEdit, PreserveRightsCheck->Checked &&
     PreserveRightsCheck->Enabled);
+  EnableControl(FRightsFrame, RightsEdit->Enabled);
+  EnableControl(PreserveReadOnlyCheck, FLAGCLEAR(CopyParamAttrs, cpaExcludeMaskOnly) &&
+    FLAGCLEAR(CopyParamAttrs, cpaNoPreserveReadOnly) && Enabled);
   EnableControl(ExcludeFileMaskCombo,
-    (FLAGSET(Options, cfAllowExcludeMask) || FLAGSET(Options, cfAllowExcludeMaskOnly)) &&
+    (FLAGCLEAR(CopyParamAttrs, cpaNoExcludeMask) ||
+     FLAGSET(CopyParamAttrs, cpaExcludeMaskOnly)) &&
     Enabled);
   EnableControl(ExclusionFileMaskLabel, ExcludeFileMaskCombo->Enabled);
   EnableControl(NegativeExcludeCombo, ExcludeFileMaskCombo->Enabled);
-  EnableControl(ClearArchiveCheck, FLAGSET(Options, cfAllowClearArchive) &&
-    FLAGCLEAR(Options, cfAllowExcludeMaskOnly) && Enabled);
-  EnableControl(PreserveTimeCheck, FLAGCLEAR(Options, cfDisablePreserveTime) &&
-    FLAGCLEAR(Options, cfAllowExcludeMaskOnly) && Enabled);
-  EnableControl(ChangeCaseGroup, FLAGCLEAR(Options, cfAllowExcludeMaskOnly) && Enabled);
+  EnableControl(ClearArchiveCheck, FLAGCLEAR(CopyParamAttrs, cpaNoClearArchive) &&
+    FLAGCLEAR(CopyParamAttrs, cpaExcludeMaskOnly) && Enabled);
+  EnableControl(PreserveTimeCheck, FLAGCLEAR(CopyParamAttrs, cpaNoPreserveTime) &&
+    FLAGCLEAR(CopyParamAttrs, cpaExcludeMaskOnly) && Enabled);
+  EnableControl(ChangeCaseGroup, FLAGCLEAR(CopyParamAttrs, cpaExcludeMaskOnly) && Enabled);
+  EnableControl(IgnorePermErrorsCheck,
+    ((PreserveRightsCheck->Enabled && PreserveRightsCheck->Checked) ||
+     (PreserveTimeCheck->Enabled && PreserveTimeCheck->Checked)) &&
+    FLAGCLEAR(CopyParamAttrs, cpaNoIgnorePermErrors) &&
+    FLAGCLEAR(CopyParamAttrs, cpaExcludeMaskOnly));
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamsFrame::SetDirection(TParamsForDirection value)
@@ -185,10 +208,12 @@ void __fastcall TCopyParamsFrame::SetDirection(TParamsForDirection value)
     if (Direction == pdBoth || Direction == pdAll)
     {
       CCLowerCaseShortButton->Top = CCFirstUpperCaseButton->Top;
+      IgnorePermErrorsCheck->Top = RemotePreserveTimeCheck->Top;
     }
     else
     {
       CCLowerCaseShortButton->Top = ReplaceInvalidCharsCheck->Top;
+      IgnorePermErrorsCheck->Top = CCFirstUpperCaseButton->Top;
     }
     UpdateControls();
   }
@@ -201,6 +226,8 @@ void __fastcall TCopyParamsFrame::ControlChange(TObject * /*Sender*/)
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamsFrame::BeforeExecute()
 {
+  // adding TRightsFrame on run-time corrupts the tab order, fix it
+  TransferModeGroup->TabOrder = 0;
   assert(CustomWinConfiguration);
   AsciiFileMaskCombo->Items = CustomWinConfiguration->History["Mask"];
   ExcludeFileMaskCombo->Items = CustomWinConfiguration->History["ExcludeMask"];
@@ -215,33 +242,96 @@ void __fastcall TCopyParamsFrame::AfterExecute()
   CustomWinConfiguration->History["ExcludeMask"] = ExcludeFileMaskCombo->Items;
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyParamsFrame::Validate()
+void __fastcall TCopyParamsFrame::SetCopyParamAttrs(int value)
 {
-  if (AsciiFileMaskCombo->Focused())
+  FCopyParamAttrs = value;
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyParamsFrame::SetEnabled(Boolean Value)
+{
+  TFrame::SetEnabled(Value);
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyParamsFrame::ValidateMaskComboExit(TObject * Sender)
+{
+  ValidateMaskEdit(dynamic_cast<TComboBox*>(Sender));
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyParamsFrame::RightsEditButtonClick(TObject * Sender)
+{
+  if (!FRightsFrame->Visible)
   {
-    ValidateMaskEdit(AsciiFileMaskCombo);
+    // validate input before showing the popup
+    RightsEditExit(Sender);
+    FRightsFrame->DropDown();
   }
-  if (ExcludeFileMaskCombo->Focused())
+  else
   {
-    ValidateMaskEdit(ExcludeFileMaskCombo);
+    FRightsFrame->CloseUp();
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyParamsFrame::SetOptions(int value)
+void __fastcall TCopyParamsFrame::RightsFrameChange(TObject * /*Sender*/)
 {
-  FOptions = value;
-  UpdateControls();
+  AnsiString RightsStr = FRightsFrame->Rights.Text;
+  if (FRightsFrame->AddXToDirectories)
+  {
+    RightsStr = FORMAT("%s (%s)", (RightsStr, FAddXToDirectoriesSuffix));
+  }
+  RightsEdit->Text = RightsStr;
+  RightsEdit->Modified = false;
+  RightsEdit->SelectAll();
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyParamsFrame::SetEnabled(Boolean Value)
+void __fastcall TCopyParamsFrame::UpdateRightsByStr()
 {
-  TFrame::SetEnabled(Value);
+  if (!RightsEdit->Text.IsEmpty())
+  {
+    AnsiString RightsStr = RightsEdit->Text;
+
+    int P = RightsStr.LowerCase().Pos(FAddXToDirectoriesSuffix);
+    bool AddXToDirectories = (P > 0);
+    if (AddXToDirectories)
+    {
+      RightsStr.Delete(P, FAddXToDirectoriesSuffix.Length());
+    }
+    RightsStr = DeleteChar(DeleteChar(RightsStr, '('), ')').Trim();
+    TRights R = FRightsFrame->Rights;
+    int Dummy;
+    if (((RightsStr.Length() == 3) || (RightsStr.Length() == 4)) &&
+        TryStrToInt(RightsStr, Dummy))
+    {
+      R.Octal = RightsStr;
+    }
+    else
+    {
+      R.Text = RightsStr;
+    }
+
+    FRightsFrame->Rights = R;
+    FRightsFrame->AddXToDirectories = AddXToDirectories;
+  }
   UpdateControls();
+  RightsEdit->Modified = false;
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyParamsFrame::ValidateMaskComboExit(TObject * Sender)
+void __fastcall TCopyParamsFrame::RightsEditExit(TObject * /*Sender*/)
 {
-  ValidateMaskEdit(dynamic_cast<TComboBox*>(Sender));
+  if (RightsEdit->Modified)
+  {
+    try
+    {
+      UpdateRightsByStr();
+    }
+    catch(...)
+    {
+      RightsEdit->SelectAll();
+      RightsEdit->SetFocus();
+      throw;
+    }
+  }
 }
 //---------------------------------------------------------------------------
 

+ 26 - 8
forms/CopyParams.dfm

@@ -79,13 +79,6 @@ object CopyParamsFrame: TCopyParamsFrame
     Height = 146
     Caption = 'Attributes'
     TabOrder = 2
-    inline RightsFrame: TRightsFrame
-      Left = 7
-      Top = 36
-      Width = 163
-      Height = 87
-      TabOrder = 1
-    end
     object PreserveRightsCheck: TCheckBox
       Left = 12
       Top = 16
@@ -99,7 +92,7 @@ object CopyParamsFrame: TCopyParamsFrame
     end
     object RemotePreserveTimeCheck: TCheckBox
       Left = 12
-      Top = 121
+      Top = 69
       Width = 156
       Height = 17
       Caption = 'Preserve timesta&mp'
@@ -108,6 +101,31 @@ object CopyParamsFrame: TCopyParamsFrame
       TabOrder = 2
       OnClick = ControlChange
     end
+    object RightsEdit: TComboEdit
+      Left = 30
+      Top = 36
+      Width = 109
+      Height = 21
+      ButtonHint = 'Configure permissions'
+      ClickKey = 16397
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 1
+      Text = 'RightsEdit'
+      OnButtonClick = RightsEditButtonClick
+      OnExit = RightsEditExit
+    end
+    object IgnorePermErrorsCheck: TCheckBox
+      Left = 12
+      Top = 94
+      Width = 156
+      Height = 17
+      Caption = 'Ign&ore permission errors'
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 3
+      OnClick = ControlChange
+    end
   end
   object ChangeCaseGroup: TXPGroupBox
     Left = 206

+ 14 - 12
forms/CopyParams.h

@@ -12,13 +12,9 @@
 
 #include <WinInterface.h>
 
-#include "Rights.h"
-//---------------------------------------------------------------------------
-const int cfAllowTransferMode = 0x01;
-const int cfAllowExcludeMask =  0x02;
-const int cfAllowClearArchive = 0x04;
-const int cfDisablePreserveTime = 0x08;
-const int cfAllowExcludeMaskOnly = 0x10;
+#include "RightsExt.h"
+#include "ComboEdit.hpp"
+#include <Mask.hpp>
 //---------------------------------------------------------------------------
 class TCopyParamsFrame : public TFrame
 {
@@ -30,7 +26,6 @@ __published:
   TRadioButton *TMAutomaticButton;
   THistoryComboBox *AsciiFileMaskCombo;
   TXPGroupBox *RemotePropertiesGroup;
-  TRightsFrame *RightsFrame;
   TCheckBox *RemotePreserveTimeCheck;
   TXPGroupBox *LocalPropertiesGroup;
   TCheckBox *PreserveReadOnlyCheck;
@@ -52,21 +47,29 @@ __published:
   TCheckBox *ClearArchiveCheck;
   TComboBox *NegativeExcludeCombo;
   TStaticText *ExcludeFileMaskHintText;
+  TComboEdit *RightsEdit;
+  TCheckBox *IgnorePermErrorsCheck;
   void __fastcall ControlChange(TObject *Sender);
   void __fastcall ValidateMaskComboExit(TObject *Sender);
+  void __fastcall RightsEditButtonClick(TObject *Sender);
+  void __fastcall RightsEditExit(TObject *Sender);
 private:
   TParamsForDirection FDirection;
   AnsiString FOrigMasks;
   TCopyParamType * FParams;
-  int FOptions;
+  int FCopyParamAttrs;
+  TRightsExtFrame * FRightsFrame;
+  AnsiString FAddXToDirectoriesSuffix;
   void __fastcall SetParams(TCopyParamType value);
   TCopyParamType __fastcall GetParams();
   void __fastcall SetDirection(TParamsForDirection value);
   TCheckBox * __fastcall GetPreserveTimeCheck();
-  void __fastcall SetOptions(int value);
+  void __fastcall SetCopyParamAttrs(int value);
+  void __fastcall RightsFrameChange(TObject * Sender);
 protected:
   void __fastcall UpdateControls();
   virtual void __fastcall SetEnabled(Boolean Value);
+  void __fastcall UpdateRightsByStr();
 
   __property TCheckBox * PreserveTimeCheck = { read = GetPreserveTimeCheck };
 public:
@@ -75,9 +78,8 @@ public:
 
   void __fastcall BeforeExecute();
   void __fastcall AfterExecute();
-  void __fastcall Validate();
 
-  __property int Options = { read = FOptions, write = SetOptions }; 
+  __property int CopyParamAttrs = { read = FCopyParamAttrs, write = SetCopyParamAttrs }; 
   __property TParamsForDirection Direction = { read = FDirection, write = SetDirection };
   __property TCopyParamType Params = { read = GetParams, write = SetParams };
 };

+ 128 - 0
forms/CreateDirectory.cpp

@@ -0,0 +1,128 @@
+//---------------------------------------------------------------------
+#include <vcl.h>
+#pragma hdrstop
+
+#include <ScpMain.h>
+#include <Configuration.h>
+#include <RemoteFiles.h>
+#include <VCLCommon.h>
+#include <TextsWin.h>
+#include <Common.h>
+#include <WinInterface.h>
+#include <Tools.h>
+
+#include "CreateDirectory.h"
+#include "WinConfiguration.h"
+//---------------------------------------------------------------------
+#pragma link "XPThemes"
+#pragma link "MoreButton"
+#pragma link "RightsExt"
+#pragma link "Rights"
+#pragma resource "*.dfm"
+//---------------------------------------------------------------------
+bool __fastcall DoCreateDirectoryDialog(AnsiString & Directory,
+  TRemoteProperties * Properties, bool & SaveSettings)
+{
+  bool Result;
+  TCreateDirectoryDialog * Dialog = new TCreateDirectoryDialog(Application);
+  try
+  {
+    Result = Dialog->Execute(Directory, Properties, SaveSettings);
+  }
+  __finally
+  {
+    delete Dialog;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------
+__fastcall TCreateDirectoryDialog::TCreateDirectoryDialog(TComponent * AOwner):
+  TForm(AOwner)
+{
+  UseSystemSettings(this);
+
+  InstallPathWordBreakProc(DirectoryEdit);
+
+  RightsFrame->AllowAddXToDirectories = false;
+}
+//---------------------------------------------------------------------
+__fastcall TCreateDirectoryDialog::~TCreateDirectoryDialog()
+{
+}
+//---------------------------------------------------------------------------
+void __fastcall TCreateDirectoryDialog::ControlChange(TObject * /*Sender*/)
+{
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
+void __fastcall TCreateDirectoryDialog::UpdateControls()
+{
+  EnableControl(OKBtn, !DirectoryEdit->Text.Trim().IsEmpty());
+  EnableControl(RightsFrame, SetRightsCheck->Checked);
+}
+//---------------------------------------------------------------------------
+bool __fastcall TCreateDirectoryDialog::Execute(AnsiString & Directory,
+  TRemoteProperties * Properties, bool & SaveSettings)
+{
+  DirectoryEdit->Text = Directory;
+  SaveSettingsCheck->Checked = SaveSettings;
+  if (Properties != NULL)
+  {
+    bool SetRights = Properties->Valid.Contains(vpRights);
+    SetRightsCheck->Checked = SetRights;
+    // expect sensible value even if rights are not set valid
+    RightsFrame->Rights = Properties->Rights;
+    MoreButton->Expanded = GUIConfiguration->CopyParamDialogExpanded;
+  }
+  else
+  {
+    MoreButton->Expanded = false;
+    MoreButton->Visible = false;
+  }
+
+  bool Result = (ShowModal() != mrCancel);
+  if (Result)
+  {
+    Directory = DirectoryEdit->Text;
+    SaveSettings = SaveSettingsCheck->Checked;
+    if (Properties != NULL)
+    {
+      if (SetRightsCheck->Checked)
+      {
+        Properties->Valid = Properties->Valid << vpRights;
+        Properties->Rights = RightsFrame->Rights;
+      }
+      else
+      {
+        Properties->Valid = Properties->Valid >> vpRights;
+      }
+      GUIConfiguration->CopyParamDialogExpanded = MoreButton->Expanded;
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TCreateDirectoryDialog::DirectoryEditChange(TObject * /*Sender*/)
+{
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
+void __fastcall TCreateDirectoryDialog::FormShow(TObject * /*Sender*/)
+{
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
+void __fastcall TCreateDirectoryDialog::HelpButtonClick(TObject * /*Sender*/)
+{
+  FormHelp(this);
+}
+//---------------------------------------------------------------------------
+void __fastcall TCreateDirectoryDialog::FormCloseQuery(TObject * /*Sender*/,
+  bool & /*CanClose*/)
+{
+  if (ModalResult != mrCancel)
+  {
+    ExitActiveControl(this);
+  }
+}
+//---------------------------------------------------------------------------

+ 133 - 0
forms/CreateDirectory.dfm

@@ -0,0 +1,133 @@
+object CreateDirectoryDialog: TCreateDirectoryDialog
+  Left = 408
+  Top = 195
+  HelpType = htKeyword
+  HelpKeyword = 'ui_create_directory'
+  BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
+  BorderStyle = bsDialog
+  Caption = 'Create folder'
+  ClientHeight = 253
+  ClientWidth = 337
+  Color = clBtnFace
+  ParentFont = True
+  OldCreateOrder = True
+  Position = poMainFormCenter
+  OnCloseQuery = FormCloseQuery
+  OnShow = FormShow
+  DesignSize = (
+    337
+    253)
+  PixelsPerInch = 96
+  TextHeight = 13
+  object EditLabel: TLabel
+    Left = 8
+    Top = 8
+    Width = 83
+    Height = 13
+    Caption = 'New &folder name:'
+  end
+  object DirectoryEdit: TEdit
+    Left = 8
+    Top = 25
+    Width = 321
+    Height = 21
+    Anchors = [akLeft, akTop, akRight]
+    MaxLength = 1000
+    TabOrder = 0
+    Text = 'DirectoryEdit'
+    OnChange = DirectoryEditChange
+  end
+  object MorePanel: TPanel
+    Left = 0
+    Top = 50
+    Width = 337
+    Height = 169
+    Anchors = [akLeft, akTop, akRight, akBottom]
+    BevelOuter = bvNone
+    TabOrder = 1
+    DesignSize = (
+      337
+      169)
+    object AttributesGroup: TXPGroupBox
+      Left = 8
+      Top = 3
+      Width = 322
+      Height = 157
+      Anchors = [akLeft, akTop, akRight, akBottom]
+      Caption = 'Attributes'
+      TabOrder = 0
+      inline RightsFrame: TRightsExtFrame
+        Left = 7
+        Top = 36
+        Width = 239
+        Height = 87
+        TabOrder = 1
+        inherited DirectoriesXCheck: TCheckBox
+          Visible = False
+        end
+      end
+      object SetRightsCheck: TCheckBox
+        Left = 12
+        Top = 16
+        Width = 156
+        Height = 17
+        Caption = 'Set pe&rmissions'
+        ParentShowHint = False
+        ShowHint = True
+        TabOrder = 0
+        OnClick = ControlChange
+      end
+      object SaveSettingsCheck: TCheckBox
+        Left = 12
+        Top = 129
+        Width = 301
+        Height = 17
+        Caption = 'Use &same settings next time'
+        TabOrder = 2
+      end
+    end
+  end
+  object MoreButton: TMoreButton
+    Left = 11
+    Top = 219
+    Width = 75
+    Height = 25
+    Anchors = [akRight, akBottom]
+    Caption = '<< &Less'
+    TabOrder = 2
+    Panel = AttributesGroup
+    RepositionForm = True
+  end
+  object OKBtn: TButton
+    Left = 91
+    Top = 219
+    Width = 75
+    Height = 25
+    Anchors = [akRight, akBottom]
+    Caption = 'OK'
+    Default = True
+    ModalResult = 1
+    TabOrder = 3
+  end
+  object CancelBtn: TButton
+    Left = 171
+    Top = 219
+    Width = 75
+    Height = 25
+    Anchors = [akRight, akBottom]
+    Cancel = True
+    Caption = 'Cancel'
+    ModalResult = 2
+    TabOrder = 4
+  end
+  object HelpButton: TButton
+    Left = 252
+    Top = 219
+    Width = 75
+    Height = 25
+    Anchors = [akRight, akBottom]
+    Caption = '&Help'
+    TabOrder = 5
+    OnClick = HelpButtonClick
+  end
+end

+ 52 - 0
forms/CreateDirectory.h

@@ -0,0 +1,52 @@
+//----------------------------------------------------------------------------
+#ifndef CreateDirectoryH
+#define CreateDirectoryH
+//----------------------------------------------------------------------------
+#include <vcl\System.hpp>
+#include <vcl\Windows.hpp>
+#include <vcl\SysUtils.hpp>
+#include <vcl\Classes.hpp>
+#include <vcl\StdCtrls.hpp>
+#include <vcl\Forms.hpp>
+#include <vcl\Controls.hpp>
+#include <vcl\Buttons.hpp>
+#include <XPThemes.hpp>
+#include <ExtCtrls.hpp>
+
+#include <Bookmarks.h>
+#include "MoreButton.hpp"
+#include "RightsExt.h"
+#include "Rights.h"
+//----------------------------------------------------------------------------
+class TCreateDirectoryDialog : public TForm
+{
+__published:
+  TButton *OKBtn;
+  TButton *CancelBtn;
+  TEdit *DirectoryEdit;
+  TLabel *EditLabel;
+  TButton *HelpButton;
+  TMoreButton *MoreButton;
+  TPanel *MorePanel;
+  TXPGroupBox *AttributesGroup;
+  TRightsExtFrame *RightsFrame;
+  TCheckBox *SetRightsCheck;
+  TCheckBox *SaveSettingsCheck;
+  void __fastcall ControlChange(TObject *Sender);
+  void __fastcall DirectoryEditChange(TObject *Sender);
+  void __fastcall FormShow(TObject *Sender);
+  void __fastcall HelpButtonClick(TObject *Sender);
+  void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
+
+public:
+  __fastcall TCreateDirectoryDialog(TComponent* AOwner);
+  virtual __fastcall ~TCreateDirectoryDialog();
+
+  bool __fastcall Execute(AnsiString & Directory, TRemoteProperties * Properties,
+    bool & SaveSettings);
+
+protected:
+  void __fastcall UpdateControls();
+};
+//----------------------------------------------------------------------------
+#endif

+ 434 - 119
forms/CustomScpExplorer.cpp

@@ -99,10 +99,19 @@ private:
 //---------------------------------------------------------------------------
 struct TTransferOperationParam
 {
+  TTransferOperationParam();
+
   AnsiString TargetDirectory;
   bool Temp;
+  bool DragDrop;
 };
 //---------------------------------------------------------------------------
+TTransferOperationParam::TTransferOperationParam()
+{
+  Temp = false;
+  DragDrop = false;
+}
+//---------------------------------------------------------------------------
 __fastcall TExporerState::TExporerState()
 {
   Local = NULL;
@@ -122,6 +131,7 @@ __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
   FCurrentSide = osRemote;
   FDocks = new TList();
   RestoreParams();
+  ConfigurationChanged();
   RemoteDirView->Invalidate();
   assert(NonVisualDataModule && !NonVisualDataModule->ScpExplorer);
   NonVisualDataModule->ScpExplorer = this;
@@ -191,6 +201,14 @@ __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
     TransferCombo->OnChange = TransferComboChange;
   }
 
+  class TTBXPublicItem : public TTBXCustomItem
+  {
+  public:
+    __property ItemStyle;
+  };
+  TTBXPublicItem * ColorMenu = reinterpret_cast<TTBXPublicItem *>(GetComponent(fcColorMenu));
+  ColorMenu->ItemStyle = ColorMenu->ItemStyle << tbisSubmenu;
+
   RemoteDirView->Font = Screen->IconFont;
 
   reinterpret_cast<TLabel*>(QueueSplitter)->OnDblClick = QueueSplitterDblClick;
@@ -297,6 +315,7 @@ void __fastcall TCustomScpExplorerForm::TerminalChanged()
 {
   RemoteDirView->Terminal = Terminal;
   Caption = Application->Title;
+  NonVisualDataModule->QueueDisconnectOnceEmptyAction->Checked = false;
   if (Terminal)
   {
     if (Terminal->Active)
@@ -312,9 +331,12 @@ void __fastcall TCustomScpExplorerForm::TerminalChanged()
       RemoteDirView->RestoreState(ExplorerState->Remote);
     }
 
+    SessionColor = (TColor)Terminal->SessionData->Color;
+
     InitStatusBar();
   }
   TerminalListChanged(NULL);
+  UpdateTransferCombo();
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::SetQueue(TTerminalQueue * value)
@@ -358,7 +380,7 @@ void __fastcall TCustomScpExplorerForm::QueueViewDeletion(TObject * /*Sender*/,
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::UpdateQueueStatus()
+void __fastcall TCustomScpExplorerForm::UpdateQueueStatus(bool AppIdle)
 {
   {
     TGuard Guard(FQueueStatusSection);
@@ -374,6 +396,17 @@ void __fastcall TCustomScpExplorerForm::UpdateQueueStatus()
   FQueueController->UpdateQueueStatus(FQueueStatus);
 
   UpdateQueueView();
+
+  if (NonVisualDataModule->QueueDisconnectOnceEmptyAction->Checked &&
+      FQueueController->Empty &&
+      (Terminal != NULL))
+  {
+    NonVisualDataModule->QueueDisconnectOnceEmptyAction->Checked = false;
+    if (AppIdle)
+    {
+      Terminal->CloseOnCompletion(LoadStr(CLOSED_ON_QUEUE_EMPTY));
+    }
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::UpdateQueueView()
@@ -391,7 +424,7 @@ void __fastcall TCustomScpExplorerForm::QueueChanged()
     delete FQueueStatus;
     FQueueStatus = NULL;
   }
-  UpdateQueueStatus();
+  UpdateQueueStatus(false);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::QueueListUpdate(TTerminalQueue * Queue)
@@ -485,21 +518,8 @@ void __fastcall TCustomScpExplorerForm::RefreshQueueItems(bool AppIdle)
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::ConfigurationChanged()
+void __fastcall TCustomScpExplorerForm::UpdateTransferCombo()
 {
-  assert(Configuration && RemoteDirView);
-  RemoteDirView->DDAllowMove = WinConfiguration->DDAllowMoveInit;
-  RemoteDirView->DimmHiddenFiles = WinConfiguration->DimmHiddenFiles;
-  RemoteDirView->ShowHiddenFiles = WinConfiguration->ShowHiddenFiles;
-  RemoteDirView->ShowInaccesibleDirectories = WinConfiguration->ShowInaccesibleDirectories;
-
-  RemoteDriveView->DDAllowMove = WinConfiguration->DDAllowMoveInit;
-  RemoteDriveView->DimmHiddenDirs = WinConfiguration->DimmHiddenFiles;
-  RemoteDriveView->ShowHiddenDirs = WinConfiguration->ShowHiddenFiles;
-  RemoteDriveView->ShowInaccesibleDirectories = WinConfiguration->ShowInaccesibleDirectories;
-
-  SetDockAllowDrag(!WinConfiguration->LockToolbars);
-
   TTBXComboBoxItem * TransferCombo = dynamic_cast<TTBXComboBoxItem*>(
     static_cast<TComponent*>(GetComponent(fcTransferCombo)));
   TransferCombo->Strings->BeginUpdate();
@@ -512,14 +532,52 @@ void __fastcall TCustomScpExplorerForm::ConfigurationChanged()
     {
       FTransferComboHint = TransferCombo->Hint;
     }
-    TransferCombo->Hint = FORMAT("%s\n \n%s:\n%s",
+    TransferCombo->Hint = FORMAT("%s\n \n%s:\n%s|%s",
       (FTransferComboHint, TransferCombo->Strings->Strings[TransferCombo->ItemIndex],
-       GUIConfiguration->CurrentCopyParam.GetInfoStr("; ")));
+       GUIConfiguration->CurrentCopyParam.GetInfoStr("; ",
+         FLAGMASK(Terminal != NULL, Terminal->UsableCopyParamAttrs(0).General)),
+       FTransferComboHint));
   }
   __finally
   {
     TransferCombo->Strings->EndUpdate();
   }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::UpdateCustomCommandsToolbar()
+{
+  TTBXToolbar * Toolbar = dynamic_cast<TTBXToolbar *>(GetComponent(fcCustomCommandsBand));
+  assert(Toolbar != NULL);
+
+  NonVisualDataModule->UpdateCustomCommandsToolbar(Toolbar);
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::UpdateActions()
+{
+  TForm::UpdateActions();
+
+  if (ComponentVisible[fcCustomCommandsBand])
+  {
+    UpdateCustomCommandsToolbar();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::ConfigurationChanged()
+{
+  assert(Configuration && RemoteDirView);
+  RemoteDirView->DDAllowMove = WinConfiguration->DDAllowMoveInit;
+  RemoteDirView->DimmHiddenFiles = WinConfiguration->DimmHiddenFiles;
+  RemoteDirView->ShowHiddenFiles = WinConfiguration->ShowHiddenFiles;
+  RemoteDirView->ShowInaccesibleDirectories = WinConfiguration->ShowInaccesibleDirectories;
+
+  RemoteDriveView->DDAllowMove = WinConfiguration->DDAllowMoveInit;
+  RemoteDriveView->DimmHiddenDirs = WinConfiguration->DimmHiddenFiles;
+  RemoteDriveView->ShowHiddenDirs = WinConfiguration->ShowHiddenFiles;
+  RemoteDriveView->ShowInaccesibleDirectories = WinConfiguration->ShowInaccesibleDirectories;
+
+  SetDockAllowDrag(!WinConfiguration->LockToolbars);
+
+  UpdateTransferCombo();
 
   if (Terminal != NULL)
   {
@@ -535,6 +593,11 @@ void __fastcall TCustomScpExplorerForm::ConfigurationChanged()
   {
     FEditorManager->ProcessFiles(FileConfigurationChanged, NULL);
   }
+
+  if (ComponentVisible[fcCustomCommandsBand])
+  {
+    UpdateCustomCommandsToolbar();
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::FileConfigurationChanged(
@@ -552,7 +615,7 @@ void __fastcall TCustomScpExplorerForm::FileConfigurationChanged(
 bool __fastcall TCustomScpExplorerForm::CopyParamDialog(
   TTransferDirection Direction, TTransferType Type, bool Temp,
   TStrings * FileList, AnsiString & TargetDirectory, TGUICopyParamType & CopyParam,
-  bool Confirm)
+  bool Confirm, bool DragDrop)
 {
   bool Result = true;
   assert(Terminal && Terminal->Active);
@@ -573,6 +636,9 @@ bool __fastcall TCustomScpExplorerForm::CopyParamDialog(
     }
   }
 
+  // these parameters are known in advance
+  int Params =
+    FLAGMASK(Type == ttMove, cpDelete);
   bool ToTemp = (Temp && (Direction == tdToLocal));
   if (Result && Confirm)
   {
@@ -580,19 +646,28 @@ bool __fastcall TCustomScpExplorerForm::CopyParamDialog(
       (!Terminal->IsCapable[fcNewerOnlyUpload] && (Direction == tdToRemote)) ||
       ToTemp;
     int Options =
-      (!Terminal->IsCapable[fcTextMode] ? coDisableTransferMode : 0) |
-      (DisableNewerOnly ? coDisableNewerOnly : 0) |
-      (ToTemp ? coTemp : 0);
+      FLAGMASK(DisableNewerOnly, coDisableNewerOnly) |
+      FLAGMASK(ToTemp, coTemp) |
+      FLAGMASK(DragDrop, coDoNotShowAgain);
+    TUsableCopyParamAttrs UsableCopyParamAttrs = Terminal->UsableCopyParamAttrs(Params);
+    int CopyParamAttrs = (Direction == tdToRemote ?
+      UsableCopyParamAttrs.Upload : UsableCopyParamAttrs.Download);
+    int OutputOptions = 0;
     Result = DoCopyDialog(Direction == tdToRemote, Type == ttMove,
-      FileList, TargetDirectory, &CopyParam, Options);
+      FileList, TargetDirectory, &CopyParam, Options, CopyParamAttrs, &OutputOptions);
+
+    if (Result && DragDrop && FLAGSET(OutputOptions, cooDoNotShowAgain))
+    {
+      WinConfiguration->DDTransferConfirmation = false;
+    }
   }
 
   if (Result && CopyParam.Queue && !ToTemp)
   {
     assert(Queue != NULL);
 
-    int Params =
-      ((Type == ttMove) ? cpDelete : 0) |
+    // these parameter are known only after transfer dialog
+    Params |=
       (CopyParam.QueueNoConfirmation ? cpNoConfirmation : 0) |
       (CopyParam.NewerOnly ? cpNewerOnly : 0);
     TQueueItem * QueueItem;
@@ -774,7 +849,8 @@ void __fastcall TCustomScpExplorerForm::DoOperationFinished(
     // no selection on "/upload", form servers only as event handler
     // (it is not displayed)
     if (PanelOperation(Side, FDragDropOperation) &&
-        Visible && (Operation != foCalculateSize))
+        Visible && (Operation != foCalculateSize) &&
+        (Operation != foGetProperties))
     {
       TCustomDirView * DView = DirView(Side);
       AnsiString FileNameOnly = (Side == osRemote) ?
@@ -833,14 +909,16 @@ TCustomDirView * __fastcall TCustomScpExplorerForm::DirView(TOperationSide Side)
   return RemoteDirView;
 }
 //---------------------------------------------------------------------------
-bool __fastcall TCustomScpExplorerForm::GetEnableFocusedOperation(TOperationSide Side)
+bool __fastcall TCustomScpExplorerForm::GetEnableFocusedOperation(
+  TOperationSide Side, int FilesOnly)
 {
-  return DirView(Side)->AnyFileSelected(true);
+  return DirView(Side)->AnyFileSelected(true, (FilesOnly != 0));
 }
 //---------------------------------------------------------------------------
-bool __fastcall TCustomScpExplorerForm::GetEnableSelectedOperation(TOperationSide Side)
+bool __fastcall TCustomScpExplorerForm::GetEnableSelectedOperation(
+  TOperationSide Side, int FilesOnly)
 {
-  return DirView(Side)->AnyFileSelected(false);
+  return DirView(Side)->AnyFileSelected(false, (FilesOnly != 0));
 }
 //---------------------------------------------------------------------------
 struct THistoryItemData
@@ -1192,7 +1270,7 @@ void __fastcall TCustomScpExplorerForm::RemoteDirViewContextPopup(
 {
   TListItem * Item = RemoteDirView->ItemFocused;
   if ((RemoteDirView->GetItemAt(MousePos.x, MousePos.y) == Item) &&
-      RemoteDirView->AnyFileSelected(true))
+      RemoteDirView->AnyFileSelected(true, false))
   {
     TPoint ScreenPoint, ClientPoint;
     ClientPoint = ((MousePos.x < 0) && (MousePos.y < 0)) ?
@@ -1257,16 +1335,18 @@ void __fastcall TCustomScpExplorerForm::ExecuteFileOperation(TFileOperation Oper
       TTransferType Type = (Operation == foCopy ? ttCopy : ttMove);
       AnsiString TargetDirectory;
       bool Temp = false;
+      bool DragDrop = false;
       if (Param != NULL)
       {
         TTransferOperationParam& TParam =
           *static_cast<TTransferOperationParam*>(Param);
         TargetDirectory = TParam.TargetDirectory;
         Temp = TParam.Temp;
+        DragDrop = TParam.DragDrop;
       }
       TGUICopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;
       if (CopyParamDialog(Direction, Type, Temp, FileList, TargetDirectory,
-          CopyParam, !NoConfirmation))
+          CopyParam, !NoConfirmation, DragDrop))
       {
         assert(Terminal);
         bool SelectionRestored = false;
@@ -1377,6 +1457,7 @@ void __fastcall TCustomScpExplorerForm::ExecuteFileOperation(TFileOperation Oper
     }
     else if (Operation == foSetProperties)
     {
+      RemoteDirView->SaveSelectedNames();
       SetProperties(Side, FileList);
     }
     else if (Operation == foCustomCommand)
@@ -1623,11 +1704,9 @@ void __fastcall TCustomScpExplorerForm::CustomExecuteFile(TOperationSide Side,
       {
         AnsiString Program, Params, Dir;
         Data.Command = ExternalEditor->Data.ExternalEditor;
-        TWinConfiguration::ReformatFileNameCommand(Data.Command);
+        ReformatFileNameCommand(Data.Command);
         SplitCommand(Data.Command, Program, Params, Dir);
-        assert(Params.Pos(ShellCommandFileNamePattern) > 0);
-        Params = StringReplace(Params, ShellCommandFileNamePattern,
-          AddPathQuotes(FileName), TReplaceFlags() << rfReplaceAll);
+        Params = ExpandFileNameCommand(Params, FileName);
         if (!ExecuteShell(Program, Params, Process))
         {
           throw Exception(FMTLOAD(EDITOR_ERROR, (Program)));
@@ -1773,7 +1852,8 @@ void __fastcall TCustomScpExplorerForm::ExecuteFileNormalize(
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::ExecuteFile(TOperationSide Side,
-  TExecuteFileBy ExecuteFileBy, const TEditorPreferences * ExternalEditor)
+  TExecuteFileBy ExecuteFileBy, const TEditorPreferences * ExternalEditor,
+  bool AllSelected, bool OnFocused)
 {
   assert(!WinConfiguration->DisableOpenEdit);
   assert((ExecuteFileBy == efExternalEditor) ==
@@ -1781,62 +1861,88 @@ void __fastcall TCustomScpExplorerForm::ExecuteFile(TOperationSide Side,
 
   Side = GetSide(Side);
 
-  AnsiString OriginalFileName;
-  AnsiString FullFileName;
-  AnsiString FileName;
-
-  TStrings * FileList = DirView(Side)->CreateFocusedFileList(Side == osLocal);
+  TCustomDirView * DView = DirView(Side);
+  if (WinConfiguration->Editor.SingleEditor)
+  {
+    AllSelected = false;
+  }
+  TStrings * FileList = AllSelected ?
+    DView->CreateFileList(OnFocused, Side == osLocal) :
+    DView->CreateFocusedFileList(Side == osLocal);
   try
   {
-    assert(FileList->Count == 1);
-    if (Side == osRemote)
+    assert(AllSelected || (FileList->Count == 1));
+    for (int i = 0; i < FileList->Count; i++)
     {
-      OriginalFileName = FileList->Strings[0];
-      FullFileName = RemoteDirView->Path + FileList->Strings[0];
-    }
-    else
-    {
-      OriginalFileName = ExtractFileName(FileList->Strings[0]);
-      FullFileName = FileList->Strings[0];
-    }
+      AnsiString ListFileName = FileList->Strings[i];
+      AnsiString FileNameOnly = (Side == osRemote) ?
+        UnixExtractFileName(ListFileName) : ExtractFileName(ListFileName);
+      TListItem * Item = DView->FindFileItem(FileNameOnly);
+      if (!DView->ItemIsDirectory(Item))
+      {
+        AnsiString OriginalFileName;
+        AnsiString FullFileName;
+        AnsiString FileName;
+
+        if (Side == osRemote)
+        {
+          OriginalFileName = ListFileName;
+          FullFileName = RemoteDirView->Path + ListFileName;
+        }
+        else
+        {
+          OriginalFileName = ExtractFileName(ListFileName);
+          FullFileName = ListFileName;
+        }
 
-    ExecuteFileNormalize(ExecuteFileBy, ExternalEditor, FullFileName,
-      (Side == osLocal));
+        ExecuteFileNormalize(ExecuteFileBy, ExternalEditor, FullFileName,
+          (Side == osLocal));
 
-    if (Side == osRemote)
-    {
-      TObject * Token = NULL;
-      AnsiString TempDir; // path to already edited file in MDI editor
-      if (!FEditorManager->CanAddFile(RemoteDirView->PathName, OriginalFileName,
-             Token, TempDir))
-      {
-        if (Token != NULL)
+        if (Side == osRemote)
         {
-          TForm * Form = dynamic_cast<TForm *>(Token);
-          Form->SetFocus();
-          Abort();
+          TObject * Token = NULL;
+          AnsiString TempDir; // path to already edited file in MDI editor
+          if (!FEditorManager->CanAddFile(RemoteDirView->PathName, OriginalFileName,
+                 Terminal->SessionData->SessionName, Token, TempDir))
+          {
+            if (Token != NULL)
+            {
+              TForm * Form = dynamic_cast<TForm *>(Token);
+              Form->SetFocus();
+              Abort();
+            }
+            else
+            {
+              throw Exception(FMTLOAD(ALREADY_EDITED_EXTERNALLY, (OriginalFileName)));
+            }
+          }
+
+          TStringList * FileList1 = new TStringList();
+          try
+          {
+            FileList1->AddObject(ListFileName, FileList->Objects[i]);
+            TemporarilyDownloadFiles(FileList1,
+              RemoteExecuteForceText(ExecuteFileBy, ExternalEditor), TempDir, true, true);
+          }
+          __finally
+          {
+            delete FileList1;
+          }
+          FileName = TempDir + FileList->Strings[i];
         }
         else
         {
-          throw Exception(FMTLOAD(ALREADY_EDITED_EXTERNALLY, (OriginalFileName)));
+          FileName = FileList->Strings[i];
         }
-      }
 
-      TemporarilyDownloadFiles(FileList,
-        RemoteExecuteForceText(ExecuteFileBy, ExternalEditor), TempDir, true, true);
-      FileName = TempDir + FileList->Strings[0];
-    }
-    else
-    {
-      FileName = FileList->Strings[0];
+        CustomExecuteFile(Side, ExecuteFileBy, FileName, OriginalFileName, ExternalEditor);
+      }
     }
   }
   __finally
   {
     delete FileList;
   }
-
-  CustomExecuteFile(Side, ExecuteFileBy, FileName, OriginalFileName, ExternalEditor);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::ExecutedFileChanged(const AnsiString FileName,
@@ -1958,7 +2064,7 @@ void __fastcall TCustomScpExplorerForm::ExecutedFileEarlyClosed(
         {
           KeepOpen = true;
           if (AnyNonMDI)
-          { 
+          {
             // there is at least one instance of the editor with MDI support enabled,
             // and one with disabled, enable it for all instances
             EnableMDI = true;
@@ -2150,11 +2256,26 @@ void __fastcall TCustomScpExplorerForm::RemoteTransferFiles(
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::CreateDirectory(TOperationSide Side)
 {
+  Side = GetSide(Side);
+  TRemoteProperties Properties = GUIConfiguration->NewDirectoryProperties;
+  TRemoteProperties * AProperties = (Side == osRemote ? &Properties : NULL);
   AnsiString Name = LoadStr(NEW_FOLDER);
-  if (InputDialog(LoadStr(CREATE_FOLDER_CAPTION), LoadStr(CREATE_FOLDER_PROMPT),
-        Name, HELP_CREATE_DIRECTORY))
+  bool SaveSettings = false;
+  
+  if (DoCreateDirectoryDialog(Name, AProperties, SaveSettings))
   {
-    DirView(Side)->CreateDirectory(Name);
+    if (Side == osRemote)
+    {
+      if (SaveSettings)
+      {
+        GUIConfiguration->NewDirectoryProperties = Properties;
+      }
+      RemoteDirView->CreateDirectoryEx(Name, &Properties);
+    }
+    else
+    {
+      DirView(Side)->CreateDirectory(Name);
+    }
   }
 }
 //---------------------------------------------------------------------------
@@ -2176,6 +2297,10 @@ void __fastcall TCustomScpExplorerForm::SetProperties(TOperationSide Side, TStri
   {
     TRemoteProperties CurrentProperties;
 
+    if (Terminal->LoadFilesProperties(FileList))
+    {
+      RemoteDirView->Invalidate();
+    }
     CurrentProperties = TRemoteProperties::CommonProperties(FileList);
 
     int Flags = 0;
@@ -2346,7 +2471,7 @@ void __fastcall TCustomScpExplorerForm::Idle(bool AppIdle)
 
   if (FQueueStatusInvalidated)
   {
-    UpdateQueueStatus();
+    UpdateQueueStatus(AppIdle);
   }
 
   RefreshQueueItems(AppIdle);
@@ -2392,23 +2517,7 @@ void __fastcall TCustomScpExplorerForm::ApplicationHint(TObject * /*Sender*/)
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::NewSession()
 {
-  TSessionData * Data = new TSessionData("");
-  try
-  {
-    Data->Assign(StoredSessions->DefaultSettings);
-    if (DoLoginDialog(StoredSessions, Data, loAddSession))
-    {
-      assert(Data->CanLogin);
-      TTerminalManager * Manager = TTerminalManager::Instance();
-      TTerminal * Terminal = Manager->NewTerminal(Data);
-      Manager->ActiveTerminal = Terminal;
-      Manager->ConnectActiveTerminal();
-    }
-  }
-  __finally
-  {
-    delete Data;
-  }
+  TTerminalManager::Instance()->NewSession();
 }
 //---------------------------------------------------------------------------
 bool __fastcall TCustomScpExplorerForm::CanCloseQueue()
@@ -2502,6 +2611,17 @@ void __fastcall TCustomScpExplorerForm::RemoteDirViewDisplayProperties(
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::ComponentShowing(Word Component, bool value)
+{
+  if (value)
+  {
+    if (Component == fcCustomCommandsBand)
+    {
+      UpdateCustomCommandsToolbar();
+    }
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::SetComponentVisible(Word Component, Boolean value)
 {
   TControl * Control = GetComponent(Component);
@@ -2509,6 +2629,8 @@ void __fastcall TCustomScpExplorerForm::SetComponentVisible(Word Component, Bool
   bool Changed = (Control->Visible != value);
   if (Changed)
   {
+    ComponentShowing(Component, value);
+
     TWinControl * WinControl = dynamic_cast<TWinControl*>(Control);
     bool WasFocused = (WinControl != NULL) && (ActiveControl != NULL) &&
       ((ActiveControl == WinControl) || (ActiveControl->Parent == WinControl));
@@ -2549,7 +2671,7 @@ void __fastcall TCustomScpExplorerForm::SetComponentVisible(Word Component, Bool
       }
     }
     Control->Visible = value;
-    if (WasFocused)
+    if (WasFocused && Visible)
     {
       DirView(osCurrent)->SetFocus();
     }
@@ -2709,10 +2831,11 @@ bool __fastcall TCustomScpExplorerForm::DoSynchronizeDirectories(
   try
   {
     TCopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;
+    int CopyParamAttrs = Terminal->UsableCopyParamAttrs(0).Upload;
     int Options =
       FLAGMASK(SynchronizeAllowSelectedOnly(), soAllowSelectedOnly);
     Result = DoSynchronizeDialog(Params, &CopyParam, Controller.StartStop,
-      SaveSettings, Options, GetSynchronizeOptions);
+      SaveSettings, Options, CopyParamAttrs, GetSynchronizeOptions);
     if (Result)
     {
       if (SaveSettings)
@@ -2734,7 +2857,7 @@ bool __fastcall TCustomScpExplorerForm::DoSynchronizeDirectories(
 void __fastcall TCustomScpExplorerForm::DoSynchronize(
   TSynchronizeController * /*Sender*/, const AnsiString LocalDirectory,
   const AnsiString RemoteDirectory, const TCopyParamType & CopyParam,
-  const TSynchronizeParamType & Params, TSynchronizeStats * Stats,
+  const TSynchronizeParamType & Params, TSynchronizeChecklist ** Checklist,
   TSynchronizeOptions * Options, bool Full)
 {
   try
@@ -2746,7 +2869,7 @@ void __fastcall TCustomScpExplorerForm::DoSynchronize(
         TTerminal::spDelayProgress | TTerminal::spSubDirs;
     }
     Synchronize(LocalDirectory, RemoteDirectory, smRemote, CopyParam,
-      PParams, Stats, Options);
+      PParams, Checklist, Options);
   }
   catch(Exception & E)
   {
@@ -2800,7 +2923,7 @@ void __fastcall TCustomScpExplorerForm::DoSynchronizeTooManyDirectories(
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::Synchronize(const AnsiString LocalDirectory,
   const AnsiString RemoteDirectory, TSynchronizeMode Mode,
-  const TCopyParamType & CopyParam, int Params, TSynchronizeStats * Stats,
+  const TCopyParamType & CopyParam, int Params, TSynchronizeChecklist ** Checklist,
   TSynchronizeOptions * Options)
 {
   assert(!FAutoOperation);
@@ -2808,21 +2931,42 @@ void __fastcall TCustomScpExplorerForm::Synchronize(const AnsiString LocalDirect
   BatchStart(BatchStorage);
   FAutoOperation = true;
 
+  TSynchronizeChecklist * AChecklist = NULL;
   try
   {
-    FSynchronizeProgressForm = new TSynchronizeProgressForm(Application, true);
+    FSynchronizeProgressForm = new TSynchronizeProgressForm(Application, true, true);
     if (FLAGCLEAR(Params, TTerminal::spDelayProgress))
     {
       FSynchronizeProgressForm->Start();
     }
 
-    Terminal->Synchronize(LocalDirectory, RemoteDirectory,
+    AChecklist = Terminal->SynchronizeCollect(LocalDirectory, RemoteDirectory,
       static_cast<TTerminal::TSynchronizeMode>(Mode),
       &CopyParam, Params | spNoConfirmation, TerminalSynchronizeDirectory,
-      Stats, Options);
+      Options);
+
+    SAFE_DESTROY(FSynchronizeProgressForm);
+
+    FSynchronizeProgressForm = new TSynchronizeProgressForm(Application, true, false);
+    if (FLAGCLEAR(Params, TTerminal::spDelayProgress))
+    {
+      FSynchronizeProgressForm->Start();
+    }
+
+    Terminal->SynchronizeApply(AChecklist, LocalDirectory, RemoteDirectory,
+      &CopyParam, Params | spNoConfirmation, TerminalSynchronizeDirectory);
   }
   __finally
   {
+    if (Checklist == NULL)
+    {
+      delete AChecklist;
+    }
+    else
+    {
+      *Checklist = AChecklist;
+    }
+
     FAutoOperation = false;
     SAFE_DESTROY(FSynchronizeProgressForm);
     BatchEnd(BatchStorage);
@@ -2871,8 +3015,9 @@ bool __fastcall TCustomScpExplorerForm::DoFullSynchronizeDirectories(
     FLAGMASK(!Terminal->IsCapable[fcTimestampChanging], fsoDisableTimestamp) |
     FLAGMASK(SynchronizeAllowSelectedOnly(), fsoAllowSelectedOnly);
   TCopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;
+  TUsableCopyParamAttrs CopyParamAttrs = Terminal->UsableCopyParamAttrs(0);
   Result = DoFullSynchronizeDialog(Mode, Params, LocalDirectory, RemoteDirectory,
-    &CopyParam, SaveSettings, SaveMode, Options);
+    &CopyParam, SaveSettings, SaveMode, Options, CopyParamAttrs);
   if (Result)
   {
     TSynchronizeOptions SynchronizeOptions;
@@ -2888,8 +3033,69 @@ bool __fastcall TCustomScpExplorerForm::DoFullSynchronizeDirectories(
     }
 
     TDateTime StartTime = Now();
-    Synchronize(LocalDirectory, RemoteDirectory, Mode,
-      CopyParam, Params, NULL, &SynchronizeOptions);
+
+    TSynchronizeChecklist * Checklist = NULL;
+    try
+    {
+      assert(!FAutoOperation);
+      FAutoOperation = true;
+
+      try
+      {
+        FSynchronizeProgressForm = new TSynchronizeProgressForm(Application, true, true);
+        FSynchronizeProgressForm->Start();
+
+        Checklist = Terminal->SynchronizeCollect(LocalDirectory, RemoteDirectory,
+          static_cast<TTerminal::TSynchronizeMode>(Mode),
+          &CopyParam, Params | spNoConfirmation, TerminalSynchronizeDirectory,
+          &SynchronizeOptions);
+      }
+      __finally
+      {
+        FAutoOperation = false;
+        SAFE_DESTROY(FSynchronizeProgressForm);
+      }
+
+      if (Checklist->Count == 0)
+      {
+        MessageDialog(LoadStr(COMPARE_NO_DIFFERENCES), qtInformation, qaOK,
+          HELP_SYNCHRONIZE_NO_DIFFERENCES);
+      }
+      else if (FLAGCLEAR(Params, spPreviewChanges) ||
+               DoSynchronizeChecklistDialog(Checklist, Mode, Params,
+                 LocalDirectory, RemoteDirectory))
+      {
+        assert(!FAutoOperation);
+        void * BatchStorage;
+        BatchStart(BatchStorage);
+        FAutoOperation = true;
+
+        if (FLAGSET(Params, spPreviewChanges))
+        {
+          StartTime = Now();
+        }
+
+        try
+        {
+          FSynchronizeProgressForm = new TSynchronizeProgressForm(Application, true, false);
+          FSynchronizeProgressForm->Start();
+
+          Terminal->SynchronizeApply(Checklist, LocalDirectory, RemoteDirectory,
+            &CopyParam, Params | spNoConfirmation, TerminalSynchronizeDirectory);
+        }
+        __finally
+        {
+          FAutoOperation = false;
+          SAFE_DESTROY(FSynchronizeProgressForm);
+          BatchEnd(BatchStorage);
+          ReloadLocalDirectory();
+        }
+      }
+    }
+    __finally
+    {
+      delete Checklist;
+    }
 
     OperationComplete(StartTime);
   }
@@ -2946,6 +3152,7 @@ void __fastcall TCustomScpExplorerForm::UpdateSessionData(TSessionData * Data)
   // cannot use RemoteDirView->Path, because it is empty if connection
   // was already closed
   Data->RemoteDirectory = Terminal->CurrentDirectory;
+  Data->Color = SessionColor;
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::ToolBarResize(TObject *Sender)
@@ -3145,7 +3352,7 @@ bool __fastcall TCustomScpExplorerForm::EnsureCommandSessionFallback(TFSCapabili
     {
       try
       {
-        TTerminalManager::ConnectTerminal(FTerminal->CommandSession);
+        TTerminalManager::ConnectTerminal(FTerminal->CommandSession, false);
       }
       catch(Exception & E)
       {
@@ -3188,7 +3395,7 @@ void __fastcall TCustomScpExplorerForm::FileControlDDDragLeave(
   FDDTargetControl = NULL;
 }
 //---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::AddEditLink()
+void __fastcall TCustomScpExplorerForm::AddEditLink(bool Add)
 {
   assert(FCurrentSide == osRemote);
 
@@ -3203,7 +3410,7 @@ void __fastcall TCustomScpExplorerForm::AddEditLink()
     assert(RemoteDirView->ItemFocused->Data);
     File = (TRemoteFile *)RemoteDirView->ItemFocused->Data;
 
-    Edit = File->IsSymLink && Terminal->SessionData->ResolveSymlinks;
+    Edit = !Add && File->IsSymLink && Terminal->SessionData->ResolveSymlinks;
     if (Edit)
     {
       FileName = File->FileName;
@@ -3344,7 +3551,7 @@ void __fastcall TCustomScpExplorerForm::SessionComboPopup(TTBCustomItem * Sender
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::SessionComboDrawItem(
   TTBXCustomList * Sender, TCanvas * Canvas, const TRect & ARect, int Index,
-  int /*AHoverIndex*/, bool & DrawDefault)
+  int AHoverIndex, bool & DrawDefault)
 {
   TTBXStringList * SessionCombo = dynamic_cast<TTBXStringList *>(Sender);
   assert(SessionCombo);
@@ -3360,6 +3567,22 @@ void __fastcall TCustomScpExplorerForm::SessionComboDrawItem(
       ShortCutWidth = Canvas->TextExtent(ShortCutStr).cx;
     }
 
+    if (Index != AHoverIndex)
+    {
+      TTerminal * Terminal =
+        dynamic_cast<TTerminal *>(SessionCombo->Strings->Objects[Index]);
+      assert(Terminal != NULL);
+
+      TColor Color =
+        TColor(Terminal == this->Terminal ? SessionColor : Terminal->SessionData->Color);
+      if (Color != 0)
+      {
+        Canvas->Brush->Color = Color;
+        Canvas->Brush->Style = bsSolid;
+        Canvas->FillRect(ARect);
+      }
+    }
+
     TRect R = ARect;
     InflateRect(&R, -4, 1);
     R.Right -= ShortCutWidth + 2;
@@ -3626,6 +3849,7 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDEnd(TObject * Sender)
         DDGetTarget(Param.TargetDirectory);
         // download using ddext
         Param.Temp = false;
+        Param.DragDrop = true;
 
         RemoteFileControlFileOperation(Sender, Operation,
           !WinConfiguration->DDTransferConfirmation, &Param);
@@ -3757,6 +3981,8 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDTargetDrop()
 {
   if (IsFileControl(FDDTargetControl, osRemote))
   {
+    TTransferOperationParam Param;
+    Param.DragDrop = true;
     // when move from remote side is disabled, we allow coying inside the remote
     // panel, but we interpret is as moving (we also slip in the move cursor)
     if ((FLastDropEffect == DROPEFFECT_MOVE) ||
@@ -3764,12 +3990,12 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDTargetDrop()
          FDDMoveSlipped))
     {
       RemoteFileControlFileOperation(DropSourceControl,
-        foRemoteMove, !WinConfiguration->DDTransferConfirmation, NULL);
+        foRemoteMove, !WinConfiguration->DDTransferConfirmation, &Param);
     }
     else if (FLastDropEffect == DROPEFFECT_COPY)
     {
       RemoteFileControlFileOperation(DropSourceControl,
-        foRemoteCopy, !WinConfiguration->DDTransferConfirmation, NULL);
+        foRemoteCopy, !WinConfiguration->DDTransferConfirmation, &Param);
     }
     // abort drag&drop
     Abort();
@@ -3789,7 +4015,7 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDTargetDrop()
     AnsiString TargetDir = "";
 
     if (!CopyParamDialog(tdToLocal, Type, true, FDDFileList,
-          TargetDir, CopyParams, WinConfiguration->DDTransferConfirmation))
+          TargetDir, CopyParams, WinConfiguration->DDTransferConfirmation, true))
     {
       Abort();
     }
@@ -3968,6 +4194,9 @@ bool __fastcall TCustomScpExplorerForm::AllowQueueOperation(
     case qoGoTo:
       return ComponentVisible[fcQueueView];
 
+    case qoDisconnectOnceEmpty:
+      return !FQueueController->Empty;
+
     default:
       return FQueueController->AllowOperation(Operation);
   }
@@ -4137,6 +4366,7 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDFileOperation(
     Param.TargetDirectory = TargetPath;
     // upload, no temp dirs
     Param.Temp = false;
+    Param.DragDrop = true;
     ExecuteFileOperation(Operation, osLocal, FileList,
       !WinConfiguration->DDTransferConfirmation, &Param);
   }
@@ -4398,6 +4628,8 @@ void __fastcall TCustomScpExplorerForm::UpdateControls()
   // see in window title. we rely here on fact that this should be never called
   // during operation
   Caption = TTerminalManager::Instance()->UpdateAppTitle();
+  RemoteDirView->Color = (FSessionColor != 0 ? FSessionColor : clWindow);
+  RemoteDriveView->Color = RemoteDirView->Color;
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::DoDirViewLoaded(TCustomDirView * /*Sender*/)
@@ -4444,6 +4676,7 @@ void __fastcall TCustomScpExplorerForm::TransferPresetAutoSelect()
 {
   if (!FNoTransferPresetAutoSelect)
   {
+    assert(Terminal != NULL);
     TCopyParamRuleData Data;
     GetTransferPresetAutoSelectData(Data);
 
@@ -4486,7 +4719,9 @@ void __fastcall TCustomScpExplorerForm::TransferPresetAutoSelect()
       TStrings * More = new TStringList();
       try
       {
-        AnsiString Info = GUIConfiguration->CurrentCopyParam.GetInfoStr("\n");
+        int CopyParamAttrs = Terminal->UsableCopyParamAttrs(0).General;
+        AnsiString Info = GUIConfiguration->CurrentCopyParam.GetInfoStr("\n",
+          CopyParamAttrs);
         if (CopyParamIndex >= 0)
         {
           assert(GUIConfiguration->CopyParamList->Rules[CopyParamIndex] != NULL);
@@ -4545,7 +4780,7 @@ void __fastcall TCustomScpExplorerForm::AdHocCustomCommand(bool OnFocused)
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::WhatsThis()
 {
-  SendMessage(Handle, WM_SYSCOMMAND, SC_CONTEXTHELP, 0); 
+  SendMessage(Handle, WM_SYSCOMMAND, SC_CONTEXTHELP, 0);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::BeforeAction()
@@ -4617,7 +4852,7 @@ void __fastcall TCustomScpExplorerForm::FormConstrainedResize(
   int & MaxHeight)
 {
   // workaround for bug in TWinControl.CalcConstraints
-  // Check for empty rect (restore from iconinc state) is done there only after 
+  // Check for empty rect (restore from iconinc state) is done there only after
   // call to AdjustClientRect, which enlarges the rect (for forms).
   TRect R = GetClientRect();
   // when restoring from iconic state, place no restrictions
@@ -4630,4 +4865,84 @@ void __fastcall TCustomScpExplorerForm::FormConstrainedResize(
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::GetSpaceAvailable(const AnsiString Path,
+  TSpaceAvailable & ASpaceAvailable, bool & Close)
+{
+  // terminal can be already closed (e.g. dropped connection)
+  if ((Terminal != NULL) && Terminal->IsCapable[fcCheckingSpaceAvailable])
+  {
+    try
+    {
+      Terminal->SpaceAvailable(Path, ASpaceAvailable);
+    }
+    catch(...)
+    {
+      if (!Terminal->Active)
+      {
+        Close = true;
+      }
+      throw;
+    }
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::FileSystemInfo()
+{
+  TFileSystemInfo FileSystemInfo;
+  TGetSpaceAvailable OnGetSpaceAvailable = NULL;
+  Terminal->FileSystemInfo(FileSystemInfo);
+  if (Terminal->IsCapable[fcCheckingSpaceAvailable])
+  {
+    OnGetSpaceAvailable = GetSpaceAvailable;
+  }
+  DoFileSystemInfoDialog(FileSystemInfo, Terminal->CurrentDirectory, OnGetSpaceAvailable);
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::SetSessionColor(TColor value)
+{
+  if (value != FSessionColor)
+  {
+    FSessionColor = value;
+
+    TColor C = (value != 0 ? value : clNone);
+    TTBXColorPalette * ColorPalette = dynamic_cast<TTBXColorPalette *>(
+      static_cast<TObject *>(GetComponent(fcColorPalette)));
+    assert(ColorPalette != NULL);
+    ColorPalette->Color = C;
+
+    TTBXColorItem * ColorItem = dynamic_cast<TTBXColorItem *>(
+      static_cast<TObject *>(GetComponent(fcColorMenu)));
+    assert(ColorItem != NULL);
+    ColorItem->Color = C;
+
+    UpdateControls();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::SessionColorPick()
+{
+  TColorDialog * Dialog = new TColorDialog(this);
+  try
+  {
+    Dialog->Options = Dialog->Options << cdFullOpen;
+    Dialog->Color = (FSessionColor != 0 ? FSessionColor : clSkyBlue);
+    if (Dialog->Execute())
+    {
+      SessionColor = Dialog->Color;
+    }
+  }
+  __finally
+  {
+    delete Dialog;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::SessionColorPaletteChange(
+  TObject * Sender)
+{
+  TTBXColorPalette * ColorPalette = dynamic_cast<TTBXColorPalette *>(Sender);
+  assert(ColorPalette != NULL);
+  SessionColor = (ColorPalette->Color != clNone ? ColorPalette->Color : (TColor)0);
+}
+//---------------------------------------------------------------------------
 

+ 4 - 1
forms/CustomScpExplorer.dfm

@@ -153,7 +153,7 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
         end
         item
           Alignment = taRightJustify
-          Caption = 'Transfered'
+          Caption = 'Transferred'
           Width = 80
         end
         item
@@ -229,6 +229,9 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
         end
         object TBXSeparatorItem202: TTBXSeparatorItem
         end
+        object TBXItem210: TTBXItem
+          Action = NonVisualDataModule.QueueDisconnectOnceEmptyAction
+        end
         object TBXItem208: TTBXItem
           Action = NonVisualDataModule.QueuePreferencesAction
         end

+ 28 - 10
forms/CustomScpExplorer.h

@@ -26,6 +26,7 @@
 #include "TBXStatusBars.hpp"
 #include "TB2Item.hpp"
 #include "TB2Toolbar.hpp"
+#include "TBXToolPals.hpp"
 //---------------------------------------------------------------------------
 class TProgressForm;
 class TSynchronizeProgressForm;
@@ -71,6 +72,7 @@ __published:
   TSplitter *RemotePanelSplitter;
   TTBXItem *TBXItem194;
   TTBXItem *TBXItem195;
+  TTBXItem *TBXItem210;
   void __fastcall RemoteDirViewContextPopup(TObject *Sender,
     const TPoint &MousePos, bool &Handled);
   void __fastcall RemoteDirViewGetSelectFilter(
@@ -131,6 +133,7 @@ __published:
   void __fastcall AddressToolbarGetBaseSize(TTBCustomToolbar * Toolbar, TPoint & ASize);
   void __fastcall FormConstrainedResize(TObject * Sender, int & MinWidth,
     int  &MinHeight, int  &MaxWidth, int  &MaxHeight);
+  void __fastcall SessionColorPaletteChange(TObject * Sender);
 
 private:
   TTerminal * FTerminal;
@@ -171,9 +174,10 @@ private:
   TList * FDocks;
   TSynchronizeController * FSynchronizeController;
   AnsiString FTransferComboHint;
+  TColor FSessionColor;
 
-  bool __fastcall GetEnableFocusedOperation(TOperationSide Side);
-  bool __fastcall GetEnableSelectedOperation(TOperationSide Side);
+  bool __fastcall GetEnableFocusedOperation(TOperationSide Side, int FilesOnly);
+  bool __fastcall GetEnableSelectedOperation(TOperationSide Side, int FilesOnly);
   void __fastcall SetTerminal(TTerminal * value);
   void __fastcall SetQueue(TTerminalQueue * value);
   void __fastcall SessionComboPopup(TTBCustomItem * Sender, bool FromLink);
@@ -206,7 +210,8 @@ protected:
 
   virtual bool __fastcall CopyParamDialog(TTransferDirection Direction,
     TTransferType Type, bool Temp, TStrings * FileList,
-    AnsiString & TargetDirectory, TGUICopyParamType & CopyParam, bool Confirm);
+    AnsiString & TargetDirectory, TGUICopyParamType & CopyParam, bool Confirm,
+    bool DragDrop);
   virtual bool __fastcall RemoteTransferDialog(TStrings * FileList,
     AnsiString & Target, AnsiString & FileMask, bool NoConfirmation, bool Move);
   virtual void __fastcall CreateParams(TCreateParams & Params);
@@ -220,6 +225,7 @@ protected:
   virtual void __fastcall RestoreFormParams();
   virtual void __fastcall RestoreParams();
   virtual void __fastcall SetComponentVisible(Word Component, bool value);
+  virtual void __fastcall ComponentShowing(Word Component, bool value);
   virtual void __fastcall FixControlsPlacement();
   void __fastcall SetProperties(TOperationSide Side, TStrings * FileList);
   void __fastcall CustomCommand(TStrings * FileList, AnsiString Name,
@@ -252,14 +258,14 @@ protected:
   void __fastcall DoSynchronize(TSynchronizeController * Sender,
     const AnsiString LocalDirectory, const AnsiString RemoteDirectory,
     const TCopyParamType & CopyParam, const TSynchronizeParamType & Params,
-    TSynchronizeStats * Stats, TSynchronizeOptions * Options, bool Full);
+    TSynchronizeChecklist ** Checklist, TSynchronizeOptions * Options, bool Full);
   void __fastcall DoSynchronizeInvalid(TSynchronizeController * Sender,
     const AnsiString Directory, const AnsiString ErrorStr);
   void __fastcall DoSynchronizeTooManyDirectories(TSynchronizeController * Sender,
     int & MaxDirectories);
   void __fastcall Synchronize(const AnsiString LocalDirectory,
     const AnsiString RemoteDirectory, TSynchronizeMode Mode,
-    const TCopyParamType & CopyParam, int Params, TSynchronizeStats * Stats,
+    const TCopyParamType & CopyParam, int Params, TSynchronizeChecklist ** Checklist,
     TSynchronizeOptions * Options);
   void __fastcall GetSynchronizeOptions(int Params, TSynchronizeOptions & Options);
   bool __fastcall SynchronizeAllowSelectedOnly();
@@ -276,7 +282,7 @@ protected:
     TStringList * ExportData);
   void __fastcall QueueListUpdate(TTerminalQueue * Queue);
   void __fastcall QueueItemUpdate(TTerminalQueue * Queue, TQueueItem * Item);
-  void __fastcall UpdateQueueStatus();
+  void __fastcall UpdateQueueStatus(bool AppIdle);
   void __fastcall RefreshQueueItems(bool AppIdle);
   virtual int __fastcall GetStaticComponentsHeight();
   void __fastcall FillQueueViewItem(TListItem * Item,
@@ -316,6 +322,7 @@ protected:
     const TStatusFileInfo & FileInfo, int Panel);
   virtual void __fastcall DoDirViewLoaded(TCustomDirView * Sender);
   virtual void __fastcall UpdateControls();
+  void __fastcall UpdateTransferCombo();
   void __fastcall StartUpdates();
   void __fastcall TransferPresetAutoSelect();
   virtual void __fastcall GetTransferPresetAutoSelectData(TCopyParamRuleData & Data);
@@ -324,11 +331,16 @@ protected:
   AnsiString __fastcall GetToolbarsLayoutStr();
   virtual void __fastcall Dispatch(void * Message);
   void __fastcall PostComponentHide(unsigned short Component);
+  void __fastcall GetSpaceAvailable(const AnsiString Path,
+    TSpaceAvailable & ASpaceAvailable, bool & Close);
+  void __fastcall UpdateCustomCommandsToolbar();
+  virtual void __fastcall UpdateActions();
+  void __fastcall SetSessionColor(TColor value);
 
 public:
   virtual __fastcall ~TCustomScpExplorerForm();
   void __fastcall AddBookmark(TOperationSide Side);
-  virtual void __fastcall AddEditLink();
+  virtual void __fastcall AddEditLink(bool Add);
   virtual Boolean __fastcall AllowedAction(TAction * Action, TActionAllowed Allowed) = 0;
   virtual void __fastcall ConfigurationChanged();
   void __fastcall CreateDirectory(TOperationSide Side);
@@ -358,7 +370,8 @@ public:
   virtual void __fastcall PanelExport(TOperationSide Side, TPanelExport Export,
     TPanelExportDestination Destination, bool OnFocused = false);
   void __fastcall ExecuteFile(TOperationSide Side, TExecuteFileBy ExecuteFileBy,
-    const TEditorPreferences * ExternalEditor = NULL);
+    const TEditorPreferences * ExternalEditor = NULL, bool AllSelected = false,
+    bool OnFocused = false);
   void __fastcall EditNew(TOperationSide Side);
   bool __fastcall AllowQueueOperation(TQueueOperation Operation);
   void __fastcall ExecuteQueueOperation(TQueueOperation Operation);
@@ -384,13 +397,18 @@ public:
   void __fastcall PreferencesDialog(TPreferencesMode APreferencesMode);
   void __fastcall WhatsThis();
   virtual void __fastcall BeforeAction();
+  void __fastcall FileSystemInfo();
+  void __fastcall SessionColorPick();
 
   __property bool ComponentVisible[Word Component] = { read = GetComponentVisible, write = SetComponentVisible };
-  __property bool EnableFocusedOperation[TOperationSide Side] = { read = GetEnableFocusedOperation };
-  __property bool EnableSelectedOperation[TOperationSide Side] = { read = GetEnableSelectedOperation };
+  __property bool EnableFocusedOperation[TOperationSide Side] = { read = GetEnableFocusedOperation, index = 0 };
+  __property bool EnableSelectedOperation[TOperationSide Side] = { read = GetEnableSelectedOperation, index = 0 };
+  __property bool EnableFocusedFileOperation[TOperationSide Side] = { read = GetEnableFocusedOperation, index = 1 };
+  __property bool EnableSelectedFileOperation[TOperationSide Side] = { read = GetEnableSelectedOperation, index = 1 };
   __property bool HasDirView[TOperationSide Side] = { read = GetHasDirView };
   __property TTerminal * Terminal = { read = FTerminal, write = SetTerminal };
   __property TTerminalQueue * Queue = { read = FQueue, write = SetQueue };
+  __property TColor SessionColor = { read = FSessionColor, write = SetSessionColor };
 };
 //---------------------------------------------------------------------------
 class TExporerState : public TObject

+ 5 - 4
forms/Editor.cpp

@@ -55,11 +55,11 @@ void __fastcall ReconfigureEditorForm(TForm * Form)
 class TFindDialogEx : public TFindDialog
 {
 public:
-    __fastcall virtual TFindDialogEx(TComponent * AOwner) : TFindDialog(AOwner)
+  __fastcall virtual TFindDialogEx(TComponent * AOwner) : TFindDialog(AOwner)
   {
     FHelpMsg = RegisterWindowMessage(HELPMSGSTRING);
   }
-  
+
 protected:
   unsigned int FHelpMsg;
 
@@ -84,11 +84,11 @@ protected:
 class TReplaceDialogEx : public TReplaceDialog
 {
 public:
-    __fastcall virtual TReplaceDialogEx(TComponent * AOwner) : TReplaceDialog(AOwner)
+  __fastcall virtual TReplaceDialogEx(TComponent * AOwner) : TReplaceDialog(AOwner)
   {
     FHelpMsg = RegisterWindowMessage(HELPMSGSTRING);
   }
-  
+
 protected:
   unsigned int FHelpMsg;
 
@@ -248,6 +248,7 @@ void __fastcall TEditorForm::FormCloseQuery(TObject * /*Sender*/,
 {
   if (EditorMemo->Modified)
   {
+    SetFocus();
     int Answer = MessageDialog(LoadStr(SAVE_CHANGES), qtConfirmation,
       qaYes | qaNo | qaCancel);
     CanClose = (Answer != qaCancel);

+ 5 - 0
forms/Editor.dfm

@@ -958,5 +958,10 @@ object EditorForm: TEditorForm
     object Gotolinenumber1: TTBXItem
       Action = GoToLineAction
     end
+    object TBXSeparatorItem6: TTBXSeparatorItem
+    end
+    object TBXItem15: TTBXItem
+      Action = PreferencesAction
+    end
   end
 end

+ 2 - 0
forms/Editor.h

@@ -76,6 +76,8 @@ __published:
   TTBXSeparatorItem *TBXSeparatorItem5;
   TTBXItem *TBXItem14;
   TAction *HelpAction;
+  TTBXSeparatorItem *TBXSeparatorItem6;
+  TTBXItem *TBXItem15;
   void __fastcall EditorActionsUpdate(TBasicAction *Action, bool &Handled);
   void __fastcall EditorActionsExecute(TBasicAction *Action,
           bool &Handled);

+ 9 - 45
forms/EditorPreferences.cpp

@@ -33,7 +33,7 @@ bool __fastcall DoEditorPreferencesDialog(TEditorPreferences * Editor,
 }
 //---------------------------------------------------------------------------
 __fastcall TEditorPreferencesDialog::TEditorPreferencesDialog(
-  TComponent * Owner, TEditorPreferencesMode Mode) : 
+  TComponent * Owner, TEditorPreferencesMode Mode) :
   TForm(Owner)
 {
   UseSystemSettings(this);
@@ -52,7 +52,7 @@ bool __fastcall TEditorPreferencesDialog::Execute(TEditorPreferences * Editor)
   AnsiString ExternalEditor = Editor->Data.ExternalEditor;
   if (!ExternalEditor.IsEmpty())
   {
-    TWinConfiguration::ReformatFileNameCommand(ExternalEditor);
+    ReformatFileNameCommand(ExternalEditor);
   }
   ExternalEditorEdit->Text = ExternalEditor;
   ExternalEditorEdit->Items = CustomWinConfiguration->History["ExternalEditor"];
@@ -79,21 +79,6 @@ bool __fastcall TEditorPreferencesDialog::Execute(TEditorPreferences * Editor)
   return Result;
 }
 //---------------------------------------------------------------------------
-void __fastcall TEditorPreferencesDialog::ExternalEditorEditChange(
-  TObject * Sender)
-{
-  // duplicated in TPreferencesDialog::FilenameEditChange
-  if (FAfterFilenameEditDialog)
-  {
-    FAfterFilenameEditDialog = false;
-    ExternalEditorEditExit(Sender);
-  }
-  else
-  {
-    ControlChange(Sender);
-  }
-}
-//---------------------------------------------------------------------------
 void __fastcall TEditorPreferencesDialog::ExternalEditorEditExit(
   TObject * Sender)
 {
@@ -104,7 +89,7 @@ void __fastcall TEditorPreferencesDialog::ExternalEditorEditExit(
     AnsiString Filename = FilenameEdit->Text;
     if (!Filename.IsEmpty())
     {
-      TWinConfiguration::ReformatFileNameCommand(Filename);
+      ReformatFileNameCommand(Filename);
       FilenameEdit->Text = Filename;
     }
     ControlChange(Sender);
@@ -120,30 +105,9 @@ void __fastcall TEditorPreferencesDialog::ExternalEditorEditExit(
 void __fastcall TEditorPreferencesDialog::ExternalEditorBrowseButtonClick(
   TObject * /*Sender*/)
 {
-  AnsiString ExternalEditor, Program, Params, Dir;
-  ExternalEditor = ExternalEditorEdit->Text;
-  TWinConfiguration::ReformatFileNameCommand(ExternalEditor);
-  SplitCommand(ExternalEditor, Program, Params, Dir);
-
-  TOpenDialog * FileDialog = new TOpenDialog(this);
-  try
-  {
-    FileDialog->FileName = Program;
-    FileDialog->Filter = LoadStr(PREFERENCES_EXTERNAL_EDITOR_FILTER);
-    FileDialog->Title = LoadStr(PREFERENCES_SELECT_EXTERNAL_EDITOR);
-
-    if (FileDialog->Execute())
-    {
-      FAfterFilenameEditDialog = true;
-      ExternalEditorEdit->Text = FormatCommand(FileDialog->FileName, Params);
-      FAfterFilenameEditDialog = false;
-      ExternalEditorEditExit(ExternalEditorEdit);
-    }
-  }
-  __finally
-  {
-    delete FileDialog;
-  }
+  BrowseForExecutable(ExternalEditorEdit,
+    LoadStr(PREFERENCES_SELECT_EXTERNAL_EDITOR),
+    LoadStr(PREFERENCES_EXTERNAL_EDITOR_FILTER), true);
 }
 //---------------------------------------------------------------------------
 void __fastcall TEditorPreferencesDialog::HelpButtonClick(TObject * /*Sender*/)
@@ -160,9 +124,9 @@ void __fastcall TEditorPreferencesDialog::UpdateControls()
 {
   EnableControl(OkButton,
     EditorInternalButton->Checked || !ExternalEditorEdit->Text.IsEmpty());
-  EnableControl(ExternalEditorEdit, EditorExternalButton->Checked);  
-  EnableControl(ExternalEditorBrowseButton, EditorExternalButton->Checked);  
-  EnableControl(ExternalEditorGroup, EditorExternalButton->Checked);  
+  EnableControl(ExternalEditorEdit, EditorExternalButton->Checked);
+  EnableControl(ExternalEditorBrowseButton, EditorExternalButton->Checked);
+  EnableControl(ExternalEditorGroup, EditorExternalButton->Checked);
 }
 //---------------------------------------------------------------------------
 void __fastcall TEditorPreferencesDialog::FormCloseQuery(TObject * /*Sender*/,

+ 1 - 1
forms/EditorPreferences.dfm

@@ -85,7 +85,7 @@ object EditorPreferencesDialog: TEditorPreferencesDialog
       ItemHeight = 13
       TabOrder = 2
       Text = 'ExternalEditorEdit'
-      OnChange = ExternalEditorEditChange
+      OnChange = ControlChange
       OnExit = ExternalEditorEditExit
     end
     object ExternalEditorBrowseButton: TButton

+ 0 - 1
forms/EditorPreferences.h

@@ -26,7 +26,6 @@ __published:
   TButton *OkButton;
   TButton *CancelButton;
   TButton *HelpButton;
-  void __fastcall ExternalEditorEditChange(TObject *Sender);
   void __fastcall ExternalEditorEditExit(TObject *Sender);
   void __fastcall ExternalEditorBrowseButtonClick(TObject *Sender);
   void __fastcall HelpButtonClick(TObject *Sender);

+ 243 - 35
forms/FileSystemInfo.cpp

@@ -7,17 +7,21 @@
 #include <VCLCommon.h>
 #include "WinInterface.h"
 #include "FileSystemInfo.h"
+#include "TextsWin.h"
+#include "GUITools.h"
 //---------------------------------------------------------------------
 #pragma link "XPThemes"
+#pragma link "HistoryComboBox"
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------
-void __fastcall DoFileSystemInfoDialog(TTerminal * Terminal)
+void __fastcall DoFileSystemInfoDialog(const TFileSystemInfo & FileSystemInfo,
+  AnsiString SpaceAvailablePath, TGetSpaceAvailable OnGetSpaceAvailable)
 {
-  TFileSystemInfoDialog * Dialog = new TFileSystemInfoDialog(Application);
+  TFileSystemInfoDialog * Dialog = new TFileSystemInfoDialog(Application,
+    OnGetSpaceAvailable);
   try
   {
-    Dialog->Terminal = Terminal;
-    Dialog->ShowModal();
+    Dialog->Execute(FileSystemInfo, SpaceAvailablePath);
   }
   __finally
   {
@@ -25,16 +29,30 @@ void __fastcall DoFileSystemInfoDialog(TTerminal * Terminal)
   }
 } 
 //---------------------------------------------------------------------
-__fastcall TFileSystemInfoDialog::TFileSystemInfoDialog(TComponent* AOwner)
-    : TForm(AOwner)
+__fastcall TFileSystemInfoDialog::TFileSystemInfoDialog(TComponent * AOwner,
+  TGetSpaceAvailable OnGetSpaceAvailable)
+  : TForm(AOwner)
 {
   UseSystemSettings(this);
+  FOnGetSpaceAvailable = OnGetSpaceAvailable;
+  FSpaceAvailableLoaded = false;
+  FLastListItem = 0;
+
+  InstallPathWordBreakProc(SpaceAvailablePathEdit);
+}
+//---------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::Execute(const TFileSystemInfo & FileSystemInfo,
+  AnsiString SpaceAvailablePath)
+{
+  FFileSystemInfo = FileSystemInfo;
+  SpaceAvailablePathEdit->Text = SpaceAvailablePath;
+  UpdateControls();
+  ShowModal();
 }
 //---------------------------------------------------------------------
 AnsiString __fastcall TFileSystemInfoDialog::CapabilityStr(TFSCapability Capability)
 {
-  assert(FTerminal);
-  return BooleanToStr(FTerminal->IsCapable[Capability]);
+  return BooleanToStr(FFileSystemInfo.IsCapable[Capability]);
 }
 //---------------------------------------------------------------------
 AnsiString __fastcall TFileSystemInfoDialog::CapabilityStr(TFSCapability Capability1,
@@ -43,54 +61,244 @@ AnsiString __fastcall TFileSystemInfoDialog::CapabilityStr(TFSCapability Capabil
   return FORMAT("%s/%s", (CapabilityStr(Capability1), CapabilityStr(Capability2)));
 }
 //---------------------------------------------------------------------
-void __fastcall TFileSystemInfoDialog::UpdateControls()
+AnsiString __fastcall TFileSystemInfoDialog::SpaceStr(__int64 Bytes)
 {
-  assert(Terminal);
-
-  SshVersionEdit->Text = FORMAT("SSH-%d", (Terminal->SshVersion));
-  SshImplementationEdit->Text = Terminal->SshImplementation;
+  AnsiString Result;
+  if (Bytes == 0)
+  {
+    Result = LoadStr(FSINFO_BYTES_UNKNOWN);
+  }
+  else
+  {
+    Result = FormatBytes(Bytes);
+    AnsiString SizeUnorderedStr = FormatBytes(Bytes, false);
+    if (Result != SizeUnorderedStr)
+    {
+      Result = FORMAT("%s (%s)", (Result, SizeUnorderedStr));
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::Feed(TFeedFileSystemData AddItem)
+{
+  AddItem(ServerView, FSINFO_SSH_VERSION, FORMAT("SSH-%d", (FFileSystemInfo.SshVersion)));
+  AddItem(ServerView, FSINFO_SSH_IMPLEMENTATION, FFileSystemInfo.SshImplementation);
 
-  AnsiString Str = CipherNames[Terminal->CSCipher];
-  if (Terminal->CSCipher != Terminal->SCCipher)
+  AnsiString Str = CipherNames[FFileSystemInfo.CSCipher];
+  if (FFileSystemInfo.CSCipher != FFileSystemInfo.SCCipher)
   {
-    Str += FORMAT("/%s", (CipherNames[Terminal->SCCipher]));
+    Str += FORMAT("/%s", (CipherNames[FFileSystemInfo.SCCipher]));
   }
-  CipherEdit->Text = Str;
+  AddItem(ServerView, FSINFO_CIPHER, Str);
 
-  Str = BooleanToStr(Terminal->CSCompression != ctNone);
-  if (Terminal->CSCompression != Terminal->SCCompression)
+  Str = BooleanToStr(FFileSystemInfo.CSCompression != ctNone);
+  if (FFileSystemInfo.CSCompression != FFileSystemInfo.SCCompression)
   {
-    Str += FORMAT("/%s", (BooleanToStr(Terminal->SCCompression != ctNone)));
+    Str += FORMAT("/%s", (BooleanToStr(FFileSystemInfo.SCCompression != ctNone)));
   }
-  CompressionEdit->Text = Str;
+  AddItem(ServerView, FSINFO_COMPRESSION, Str);
+  AddItem(ServerView, FSINFO_FS_PROTOCOL, FFileSystemInfo.ProtocolName);
 
-  HostKeyFingerprintEdit->Text = Terminal->HostKeyFingerprint;
+  AddItem(HostKeyFingerprintEdit, 0, FFileSystemInfo.HostKeyFingerprint);
 
-  FSProtocolEdit->Text = Terminal->ProtocolName;
+  AddItem(ProtocolView, FSINFO_MODE_CHANGING, CapabilityStr(fcModeChanging));
+  AddItem(ProtocolView, FSINFO_OWNER_GROUP_CHANGING, CapabilityStr(fcGroupChanging));
+  AddItem(ProtocolView, FSINFO_ANY_COMMAND, CapabilityStr(fcAnyCommand));
+  AddItem(ProtocolView, FSINFO_SYMBOLIC_HARD_LINK, CapabilityStr(fcSymbolicLink, fcHardLink));
+  AddItem(ProtocolView, FSINFO_USER_GROUP_LISTING, CapabilityStr(fcUserGroupListing));
+  AddItem(ProtocolView, FSINFO_REMOTE_COPY, CapabilityStr(fcRemoteCopy));
+  AddItem(ProtocolView, FSINFO_CHECKING_SPACE_AVAILABLE, CapabilityStr(fcCheckingSpaceAvailable));
+  AddItem(ProtocolView, FSINFO_NATIVE_TEXT_MODE, CapabilityStr(fcNativeTextMode));
 
-  ModeChangingEdit->Text = CapabilityStr(fcModeChanging);
-  OwnerGroupChangingEdit->Text = CapabilityStr(fcOwnerChanging, fcGroupChanging);
-  AnyCommandEdit->Text = CapabilityStr(fcAnyCommand);
-  SymbolicHardLinkEdit->Text = CapabilityStr(fcSymbolicLink, fcHardLink);
-  UserGroupListingEdit->Text = CapabilityStr(fcUserGroupListing);
-  RemoteCopyEdit->Text = CapabilityStr(fcRemoteCopy);
-  NativeTextModeEdit->Text = CapabilityStr(fcNativeTextMode);
+  AddItem(InfoMemo, 0, FFileSystemInfo.AdditionalInfo);
 
-  InfoMemo->Lines = Terminal->AdditionalInfo;
+  AddItem(SpaceAvailableView, FSINFO_BYTES_ON_DEVICE, SpaceStr(FSpaceAvailable.BytesOnDevice));
+  AddItem(SpaceAvailableView, FSINFO_UNUSED_BYTES_ON_DEVICE, SpaceStr(FSpaceAvailable.UnusedBytesOnDevice));
+  AddItem(SpaceAvailableView, FSINFO_BYTES_AVAILABLE_TO_USER, SpaceStr(FSpaceAvailable.BytesAvailableToUser));
+  AddItem(SpaceAvailableView, FSINFO_UNUSED_BYTES_AVAILABLE_TO_USER, SpaceStr(FSpaceAvailable.UnusedBytesAvailableToUser));
+  AddItem(SpaceAvailableView, FSINFO_BYTES_PER_ALLOCATION_UNIT, SpaceStr(FSpaceAvailable.BytesPerAllocationUnit));
 }
 //---------------------------------------------------------------------
-void __fastcall TFileSystemInfoDialog::SetTerminal(TTerminal * value)
+void __fastcall TFileSystemInfoDialog::ControlsAddItem(TControl * Control,
+  int Label, AnsiString Value)
 {
-  if (Terminal != value)
+  if (FLastFeededControl != Control)
+  {
+    FLastFeededControl = Control;
+    FLastListItem = 0;
+  }
+
+  if (Control == HostKeyFingerprintEdit)
+  {
+    HostKeyFingerprintEdit->Text = Value;
+  }
+  else if (Control == InfoMemo)
+  {
+    InfoMemo->Lines->Text = Value;
+  }
+  else
   {
-    FTerminal = value;
-    UpdateControls();
+    TListView * ListView = dynamic_cast<TListView *>(Control);
+    assert(ListView != NULL);
+    TListItem * Item;
+    if (ListView->Items->Count > FLastListItem)
+    {
+      Item = ListView->Items->Item[FLastListItem];
+    }
+    else
+    {
+      Item = ListView->Items->Add();
+    }
+    FLastListItem++;
+
+    Item->Caption = LoadStr(Label);
+    if (Item->SubItems->Count > 0)
+    {
+      Item->SubItems->Strings[0] = Value;
+    }
+    else
+    {
+      Item->SubItems->Add(Value);
+    }
   }
 }
 //---------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::FeedControls()
+{
+  FLastFeededControl = NULL;
+  Feed(ControlsAddItem);
+}
+//---------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::UpdateControls()
+{
+  EnableControl(SpaceAvailableSheet, SpaceAvailableSupported());
+  EnableControl(SpaceAvailableButton, SpaceAvailableSheet->Enabled &&
+    !SpaceAvailablePathEdit->Text.IsEmpty());
+}
+//---------------------------------------------------------------------
 void __fastcall TFileSystemInfoDialog::HelpButtonClick(TObject * /*Sender*/)
 {
   FormHelp(this);
 }
+//---------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::ClipboardAddItem(TControl * Control,
+  int Label, AnsiString Value)
+{
+  if (Control->Enabled)
+  {
+    if (FLastFeededControl != Control)
+    {
+      if (FLastFeededControl != NULL)
+      {
+        FClipboard += AnsiString::StringOfChar('-', 60) + "\r\n";
+      }
+      FLastFeededControl = Control;
+    }
+
+    if (dynamic_cast<TListView *>(Control) == NULL)
+    {
+      TXPGroupBox * Group = dynamic_cast<TXPGroupBox *>(Control->Parent);
+      assert(Group != NULL);
+      if ((Value.Length() >= 2) && (Value.SubString(Value.Length() - 1, 2) == "\r\n"))
+      {
+        Value.SetLength(Value.Length() - 2);
+      }
+      FClipboard += FORMAT("%s\r\n%s\r\n", (Group->Caption, Value));
+    }
+    else
+    {
+      assert(dynamic_cast<TListView *>(Control) != NULL);
+      FClipboard += FORMAT("%s = %s\r\n", (LoadStr(Label), Value));
+    }
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::ClipboardButtonClick(
+  TObject * /*Sender*/)
+{
+  NeedSpaceAvailable();
+  FLastFeededControl = NULL;
+  FClipboard = "";
+  Feed(ClipboardAddItem);
+  CopyToClipboard(FClipboard);
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::CopyClick(TObject * /*Sender*/)
+{
+  TListView * ListView = dynamic_cast<TListView *>(ListViewMenu->PopupComponent);
+  assert(ListView != NULL);
+
+  AnsiString Text;
+  for (int Index = 0; Index < ListView->Items->Count; Index++)
+  {
+    TListItem * Item = ListView->Items->Item[Index];
+    if (Item->Selected)
+    {
+      Text += FORMAT("%s = %s\r\n", (Item->Caption, Item->SubItems->Strings[0]));
+    }
+  }
+  CopyToClipboard(Text);
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::FormShow(TObject * /*Sender*/)
+{
+  PageControl->ActivePage = SshSheet;
+  FeedControls();
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::SpaceAvailableButtonClick(
+  TObject * /*Sender*/)
+{
+  CheckSpaceAvailable();
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::CheckSpaceAvailable()
+{
+  assert(FOnGetSpaceAvailable != NULL);
+  assert(!SpaceAvailablePathEdit->Text.IsEmpty());
+
+  FSpaceAvailableLoaded = true;
+
+  bool DoClose = false;
+  try
+  {
+    FOnGetSpaceAvailable(SpaceAvailablePathEdit->Text, FSpaceAvailable, DoClose);
+  }
+  __finally
+  {
+    FeedControls();
+    if (DoClose)
+    {
+      Close();
+    }
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::NeedSpaceAvailable()
+{
+  if (!FSpaceAvailableLoaded && SpaceAvailableSupported())
+  {
+    CheckSpaceAvailable();
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TFileSystemInfoDialog::SpaceAvailableSupported()
+{
+  return (FOnGetSpaceAvailable != NULL);
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::PageControlChange(TObject * /*Sender*/)
+{
+  if (PageControl->ActivePage == SpaceAvailableSheet)
+  {
+    NeedSpaceAvailable();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileSystemInfoDialog::ControlChange(TObject * /*Sender*/)
+{
+  UpdateControls();
+}
 //---------------------------------------------------------------------------
 

+ 227 - 315
forms/FileSystemInfo.dfm

@@ -1,25 +1,26 @@
 object FileSystemInfoDialog: TFileSystemInfoDialog
-  Left = 345
-  Top = 178
+  Left = 320
+  Top = 130
   HelpType = htKeyword
   HelpKeyword = 'ui_fsinfo'
   BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
   BorderStyle = bsDialog
   Caption = 'Server and protocol information'
-  ClientHeight = 430
-  ClientWidth = 367
+  ClientHeight = 357
+  ClientWidth = 371
   Color = clBtnFace
   ParentFont = True
   OldCreateOrder = True
   Position = poMainFormCenter
+  OnShow = FormShow
   DesignSize = (
-    367
-    430)
+    371
+    357)
   PixelsPerInch = 96
   TextHeight = 13
   object CloseButton: TButton
-    Left = 200
-    Top = 396
+    Left = 204
+    Top = 323
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
@@ -27,321 +28,232 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
     Caption = 'Close'
     Default = True
     ModalResult = 1
-    TabOrder = 0
+    TabOrder = 2
   end
-  object ServerGroup: TXPGroupBox
-    Left = 8
-    Top = 8
-    Width = 351
-    Height = 105
-    Anchors = [akLeft, akTop, akRight]
-    Caption = 'Server information'
-    TabOrder = 1
-    DesignSize = (
-      351
-      105)
-    object Label1: TLabel
-      Left = 10
-      Top = 18
-      Width = 103
-      Height = 13
-      Caption = 'SSH protocol version:'
-    end
-    object Label2: TLabel
-      Left = 10
-      Top = 50
-      Width = 98
-      Height = 13
-      Caption = 'Encryption algorithm:'
-    end
-    object Label3: TLabel
-      Left = 10
-      Top = 66
-      Width = 63
-      Height = 13
-      Caption = 'Compression:'
-    end
-    object Label7: TLabel
-      Left = 10
-      Top = 82
-      Width = 98
-      Height = 13
-      Caption = 'File transfer protocol:'
-    end
-    object Label11: TLabel
-      Left = 10
-      Top = 34
-      Width = 98
-      Height = 13
-      Caption = 'SSH implementation:'
-    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 = 50
-      Width = 129
-      Height = 17
-      TabStop = False
-      Anchors = [akLeft, akTop, akRight]
-      BorderStyle = bsNone
-      Color = clBtnFace
-      ReadOnly = True
-      TabOrder = 2
-      Text = 'CipherEdit'
-    end
-    object CompressionEdit: TEdit
-      Left = 214
-      Top = 66
-      Width = 129
-      Height = 17
-      TabStop = False
-      Anchors = [akLeft, akTop, akRight]
-      BorderStyle = bsNone
-      Color = clBtnFace
-      ReadOnly = True
-      TabOrder = 3
-      Text = 'CompressionEdit'
-    end
-    object FSProtocolEdit: TEdit
-      Left = 214
-      Top = 82
-      Width = 129
-      Height = 17
-      TabStop = False
-      Anchors = [akLeft, akTop, akRight]
-      BorderStyle = bsNone
-      Color = clBtnFace
-      ReadOnly = True
-      TabOrder = 4
-      Text = 'FSProtocolEdit'
-    end
-    object SshImplementationEdit: TEdit
-      Left = 214
-      Top = 34
-      Width = 129
-      Height = 17
-      TabStop = False
-      Anchors = [akLeft, akTop, akRight]
-      BorderStyle = bsNone
-      Color = clBtnFace
-      ReadOnly = True
-      TabOrder = 1
-      Text = 'SshImplementationEdit'
-    end
+  object HelpButton: TButton
+    Left = 287
+    Top = 323
+    Width = 75
+    Height = 25
+    Anchors = [akRight, akBottom]
+    Caption = '&Help'
+    TabOrder = 3
+    OnClick = HelpButtonClick
   end
-  object ProtocolGroup: TXPGroupBox
-    Left = 8
-    Top = 156
-    Width = 351
-    Height = 233
-    Anchors = [akLeft, akTop, akRight]
-    Caption = 'Protocol capabilities/information'
-    TabOrder = 2
-    DesignSize = (
-      351
-      233)
-    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 = 114
-      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 Label12: TLabel
-      Left = 10
-      Top = 98
-      Width = 124
-      Height = 13
-      Caption = 'Can duplicate remote files:'
-    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 = 114
-      Width = 129
-      Height = 17
-      TabStop = False
-      Anchors = [akLeft, akTop, akRight]
-      BorderStyle = bsNone
-      Color = clBtnFace
-      ReadOnly = True
-      TabOrder = 6
-      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 = 4
-      Text = 'UserGroupListingEdit'
+  object PageControl: TPageControl
+    Left = 0
+    Top = 0
+    Width = 371
+    Height = 311
+    ActivePage = SshSheet
+    Align = alTop
+    Anchors = [akLeft, akTop, akRight, akBottom]
+    TabIndex = 0
+    TabOrder = 0
+    OnChange = PageControlChange
+    object SshSheet: TTabSheet
+      Caption = 'SSH'
+      DesignSize = (
+        363
+        283)
+      object HostKeyGroup: TXPGroupBox
+        Left = 6
+        Top = 161
+        Width = 351
+        Height = 41
+        Anchors = [akLeft, akRight, akBottom]
+        Caption = 'Server host key fingerprint'
+        TabOrder = 0
+        DesignSize = (
+          351
+          41)
+        object HostKeyFingerprintEdit: TEdit
+          Left = 10
+          Top = 18
+          Width = 334
+          Height = 17
+          TabStop = False
+          Anchors = [akLeft, akTop, akRight]
+          BorderStyle = bsNone
+          Color = clBtnFace
+          ReadOnly = True
+          TabOrder = 0
+          Text = 'HostKeyFingerprintEdit'
+        end
+      end
+      object ServerView: TListView
+        Left = 6
+        Top = 8
+        Width = 351
+        Height = 146
+        Anchors = [akLeft, akTop, akRight, akBottom]
+        Columns = <
+          item
+            Caption = 'Item'
+            Width = -2
+            WidthType = (
+              -2)
+          end
+          item
+            Caption = 'Value'
+            Width = -2
+            WidthType = (
+              -2)
+          end>
+        ColumnClick = False
+        MultiSelect = True
+        ReadOnly = True
+        RowSelect = True
+        PopupMenu = ListViewMenu
+        TabOrder = 1
+        ViewStyle = vsReport
+      end
     end
-    object InfoMemo: TMemo
-      Left = 8
-      Top = 136
-      Width = 335
-      Height = 89
-      TabStop = False
-      Anchors = [akLeft, akTop, akRight, akBottom]
-      Color = clBtnFace
-      Lines.Strings = (
-        'InfoMemo')
-      ReadOnly = True
-      ScrollBars = ssBoth
-      TabOrder = 7
-      WantReturns = False
-      WordWrap = False
+    object ProtocolSheet: TTabSheet
+      Caption = 'Protocol'
+      ImageIndex = 1
+      DesignSize = (
+        363
+        283)
+      object InfoGroup: TXPGroupBox
+        Left = 6
+        Top = 161
+        Width = 351
+        Height = 114
+        Anchors = [akLeft, akRight, akBottom]
+        Caption = 'Additional protocol information'
+        TabOrder = 0
+        DesignSize = (
+          351
+          114)
+        object InfoMemo: TMemo
+          Left = 9
+          Top = 17
+          Width = 333
+          Height = 87
+          TabStop = False
+          Anchors = [akLeft, akTop, akRight]
+          BevelInner = bvNone
+          BevelOuter = bvNone
+          BorderStyle = bsNone
+          Color = clBtnFace
+          Lines.Strings = (
+            'InfoMemo')
+          ReadOnly = True
+          ScrollBars = ssBoth
+          TabOrder = 0
+          WantReturns = False
+          WordWrap = False
+        end
+      end
+      object ProtocolView: TListView
+        Left = 6
+        Top = 8
+        Width = 351
+        Height = 146
+        Anchors = [akLeft, akTop, akRight, akBottom]
+        Columns = <
+          item
+            Caption = 'Item'
+            Width = -2
+            WidthType = (
+              -2)
+          end
+          item
+            Caption = 'Value'
+            Width = -2
+            WidthType = (
+              -2)
+          end>
+        ColumnClick = False
+        MultiSelect = True
+        ReadOnly = True
+        RowSelect = True
+        PopupMenu = ListViewMenu
+        TabOrder = 1
+        ViewStyle = vsReport
+      end
     end
-    object RemoteCopyEdit: TEdit
-      Left = 214
-      Top = 98
-      Width = 129
-      Height = 17
-      TabStop = False
-      Anchors = [akLeft, akTop, akRight]
-      BorderStyle = bsNone
-      Color = clBtnFace
-      ReadOnly = True
-      TabOrder = 5
-      Text = 'RemoteCopyEdit'
+    object SpaceAvailableSheet: TTabSheet
+      Caption = 'Space available'
+      ImageIndex = 2
+      DesignSize = (
+        363
+        283)
+      object Label1: TLabel
+        Left = 13
+        Top = 13
+        Width = 22
+        Height = 13
+        Caption = '&Path'
+        FocusControl = SpaceAvailablePathEdit
+      end
+      object SpaceAvailableView: TListView
+        Left = 6
+        Top = 40
+        Width = 351
+        Height = 113
+        Anchors = [akLeft, akTop, akRight, akBottom]
+        Columns = <
+          item
+            Caption = 'Item'
+            Width = -2
+            WidthType = (
+              -2)
+          end
+          item
+            Caption = 'Value'
+            Width = -2
+            WidthType = (
+              -2)
+          end>
+        ColumnClick = False
+        MultiSelect = True
+        ReadOnly = True
+        RowSelect = True
+        PopupMenu = ListViewMenu
+        TabOrder = 2
+        ViewStyle = vsReport
+      end
+      object SpaceAvailablePathEdit: TEdit
+        Left = 56
+        Top = 9
+        Width = 193
+        Height = 21
+        Anchors = [akLeft, akTop, akRight]
+        MaxLength = 250
+        TabOrder = 0
+        OnChange = ControlChange
+      end
+      object SpaceAvailableButton: TButton
+        Left = 256
+        Top = 7
+        Width = 99
+        Height = 25
+        Anchors = [akTop, akRight]
+        Caption = 'Check &space'
+        Default = True
+        TabOrder = 1
+        OnClick = SpaceAvailableButtonClick
+      end
     end
   end
-  object HostKeyGroup: TXPGroupBox
+  object ClipboardButton: TButton
     Left = 8
-    Top = 116
-    Width = 351
-    Height = 37
-    Anchors = [akLeft, akTop, akRight]
-    Caption = 'Server host key fingerprint'
-    TabOrder = 3
-    DesignSize = (
-      351
-      37)
-    object HostKeyFingerprintEdit: TEdit
-      Left = 10
-      Top = 16
-      Width = 334
-      Height = 17
-      TabStop = False
-      Anchors = [akLeft, akTop, akRight]
-      BorderStyle = bsNone
-      Color = clBtnFace
-      ReadOnly = True
-      TabOrder = 0
-      Text = 'HostKeyFingerprintEdit'
-    end
-  end
-  object HelpButton: TButton
-    Left = 283
-    Top = 396
-    Width = 75
+    Top = 323
+    Width = 121
     Height = 25
     Anchors = [akRight, akBottom]
-    Caption = '&Help'
-    TabOrder = 4
-    OnClick = HelpButtonClick
+    Caption = '&Copy to Clipboard'
+    TabOrder = 1
+    OnClick = ClipboardButtonClick
+  end
+  object ListViewMenu: TPopupMenu
+    Left = 144
+    Top = 320
+    object Copy: TMenuItem
+      Caption = '&Copy'
+      OnClick = CopyClick
+    end
   end
 end

+ 45 - 33
forms/FileSystemInfo.h

@@ -13,57 +13,69 @@
 #include <vcl\Buttons.hpp>
 #include <vcl\ExtCtrls.hpp>
 #include <XPThemes.hpp>
+#include <ComCtrls.hpp>
+#include <Menus.hpp>
 //----------------------------------------------------------------------------
-class TTerminal;
+typedef void __fastcall (__closure *TFeedFileSystemData)
+  (TControl * Control, int Label, AnsiString Value);
 //----------------------------------------------------------------------------
 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;
-  TEdit *SshImplementationEdit;
-  TLabel *Label11;
-  TLabel *Label12;
-  TEdit *RemoteCopyEdit;
+  TButton *HelpButton;
+  TPageControl *PageControl;
+  TTabSheet *SshSheet;
   TXPGroupBox *HostKeyGroup;
   TEdit *HostKeyFingerprintEdit;
-  TButton *HelpButton;
+  TTabSheet *ProtocolSheet;
+  TXPGroupBox *InfoGroup;
+  TMemo *InfoMemo;
+  TListView *ServerView;
+  TListView *ProtocolView;
+  TButton *ClipboardButton;
+  TPopupMenu *ListViewMenu;
+  TMenuItem *Copy;
+  TTabSheet *SpaceAvailableSheet;
+  TListView *SpaceAvailableView;
+  TLabel *Label1;
+  TEdit *SpaceAvailablePathEdit;
+  TButton *SpaceAvailableButton;
   void __fastcall HelpButtonClick(TObject *Sender);
+  void __fastcall ClipboardButtonClick(TObject *Sender);
+  void __fastcall CopyClick(TObject *Sender);
+  void __fastcall FormShow(TObject *Sender);
+  void __fastcall SpaceAvailableButtonClick(TObject *Sender);
+  void __fastcall PageControlChange(TObject *Sender);
+  void __fastcall ControlChange(TObject *Sender);
 public:
-	virtual __fastcall TFileSystemInfoDialog(TComponent* AOwner);
+    virtual __fastcall TFileSystemInfoDialog(TComponent * AOwner,
+    TGetSpaceAvailable OnGetSpaceAvailable);
 
-  __property TTerminal * Terminal = { read=FTerminal, write=SetTerminal };
+  void __fastcall Execute(const TFileSystemInfo & FileSystemInfo,
+    AnsiString SpaceAvailablePath);
 
 private:
-  TTerminal * FTerminal;
+  TControl * FLastFeededControl;
+  AnsiString FClipboard;
+  TGetSpaceAvailable FOnGetSpaceAvailable;
+  bool FSpaceAvailableLoaded;
+  TSpaceAvailable FSpaceAvailable;
+  int FLastListItem;
+  TFileSystemInfo FFileSystemInfo;
 
-  void __fastcall SetTerminal(TTerminal * value);
+  void __fastcall Feed(TFeedFileSystemData AddItem);
   void __fastcall UpdateControls();
   AnsiString __fastcall CapabilityStr(TFSCapability Capability);
   AnsiString __fastcall CapabilityStr(TFSCapability Capability1,
     TFSCapability Capability2);
+  AnsiString __fastcall SpaceStr(__int64 Bytes);
+  void __fastcall ControlsAddItem(TControl * Control, int Label, AnsiString Value);
+  void __fastcall ClipboardAddItem(TControl * Control, int Label, AnsiString Value);
+  void __fastcall CheckSpaceAvailable();
+  void __fastcall NeedSpaceAvailable();
+  bool __fastcall SpaceAvailableSupported();
+  void __fastcall FeedControls();
 };
 //----------------------------------------------------------------------------
 #endif

+ 36 - 13
forms/FullSynchronize.cpp

@@ -22,7 +22,8 @@
 //---------------------------------------------------------------------------
 bool __fastcall DoFullSynchronizeDialog(TSynchronizeMode & Mode, int & Params,
   AnsiString & LocalDirectory, AnsiString & RemoteDirectory,
-  TCopyParamType * CopyParams, bool & SaveSettings, bool & SaveMode, int Options)
+  TCopyParamType * CopyParams, bool & SaveSettings, bool & SaveMode, int Options,
+  const TUsableCopyParamAttrs & CopyParamAttrs)
 {
   bool Result;
   TFullSynchronizeDialog * Dialog = new TFullSynchronizeDialog(Application);
@@ -36,6 +37,7 @@ bool __fastcall DoFullSynchronizeDialog(TSynchronizeMode & Mode, int & Params,
     Dialog->CopyParams = *CopyParams;
     Dialog->SaveSettings = SaveSettings;
     Dialog->SaveMode = SaveMode;
+    Dialog->CopyParamAttrs = CopyParamAttrs;
     Result = Dialog->Execute();
     if (Result)
     {
@@ -79,10 +81,6 @@ void __fastcall TFullSynchronizeDialog::UpdateControls()
   if (SynchronizeTimestampCheck->Checked)
   {
     SynchronizeExistingOnlyCheck->Checked = true;
-    SynchronizePreviewChangesCheck->Checked = false;
-  }
-  if (SynchronizeTimestampCheck->Checked)
-  {
     SynchronizeDeleteCheck->Checked = false;
     SynchronizeByTimeCheck->Checked = true;
   }
@@ -93,18 +91,14 @@ void __fastcall TFullSynchronizeDialog::UpdateControls()
   EnableControl(SynchronizeDeleteCheck, !SynchronizeBothButton->Checked && 
     !SynchronizeTimestampCheck->Checked);
   EnableControl(SynchronizeExistingOnlyCheck, !SynchronizeTimestampCheck->Checked);
-  EnableControl(SynchronizePreviewChangesCheck, !SynchronizeTimestampCheck->Checked);
   EnableControl(SynchronizeByTimeCheck, !SynchronizeBothButton->Checked && 
     !SynchronizeTimestampCheck->Checked);
-  EnableControl(SynchronizeBySizeCheck, !SynchronizeBothButton->Checked && 
-    !SynchronizeTimestampCheck->Checked);
   EnableControl(SynchronizeBySizeCheck, !SynchronizeBothButton->Checked);
   EnableControl(SynchronizeSelectedOnlyCheck, FLAGSET(FOptions, fsoAllowSelectedOnly));
   EnableControl(OkButton, !LocalDirectoryEdit->Text.IsEmpty() &&
     !RemoteDirectoryEdit->Text.IsEmpty());
 
-  AnsiString InfoStr = FCopyParams.GetInfoStr("; ",
-    FLAGMASK(SynchronizeTimestampCheck->Checked, TCopyParamType::cpiExcludeMaskOnly));
+  AnsiString InfoStr = FCopyParams.GetInfoStr("; ", ActualCopyParamAttrs());
   CopyParamLabel->Caption = InfoStr;
   CopyParamLabel->Hint = InfoStr;
   CopyParamLabel->ShowHint =
@@ -113,6 +107,36 @@ void __fastcall TFullSynchronizeDialog::UpdateControls()
     LoadStr(SYNCHRONIZE_SAME_SIZE) : FSynchronizeBySizeCaption;
 }
 //---------------------------------------------------------------------------
+int __fastcall TFullSynchronizeDialog::ActualCopyParamAttrs()
+{
+  int Result;
+  if (SynchronizeTimestampCheck->Checked)
+  {
+    Result = cpaExcludeMaskOnly;
+  }
+  else
+  {
+    switch (Mode)
+    {
+      case smRemote:
+        Result = CopyParamAttrs.Upload;
+        break;
+
+      case smLocal:
+        Result = CopyParamAttrs.Download;
+        break;
+
+      default:
+        assert(false);
+        //fallthru
+      case smBoth:
+        Result = CopyParamAttrs.General;
+        break;
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall TFullSynchronizeDialog::ControlChange(TObject * /*Sender*/)
 {
   UpdateControls();
@@ -273,7 +297,7 @@ void __fastcall TFullSynchronizeDialog::TransferSettingsButtonClick(
 void __fastcall TFullSynchronizeDialog::CopyParamClick(TObject * Sender)
 {
   assert(FLAGCLEAR(FOptions, fsoDoNotUsePresets));
-  if (CopyParamListPopupClick(Sender, FCopyParams, FPreset))
+  if (CopyParamListPopupClick(Sender, FCopyParams, FPreset, ActualCopyParamAttrs()))
   {
     UpdateControls();
   }
@@ -335,8 +359,7 @@ void __fastcall TFullSynchronizeDialog::CopyParamGroupContextPopup(
 void __fastcall TFullSynchronizeDialog::CopyParamGroupDblClick(
   TObject * /*Sender*/)
 {
-  if (DoCopyParamCustomDialog(FCopyParams,
-       (SynchronizeTimestampCheck->Checked ? cfAllowExcludeMaskOnly : -1)))
+  if (DoCopyParamCustomDialog(FCopyParams, ActualCopyParamAttrs()))
   {
     UpdateControls();
   }

+ 1 - 1
forms/FullSynchronize.dfm

@@ -132,7 +132,7 @@ object FullSynchronizeDialog: TFullSynchronizeDialog
       Top = 68
       Width = 123
       Height = 17
-      Caption = 'S&elected files only'
+      Caption = 'Selected files o&nly'
       TabOrder = 4
       OnClick = ControlChange
     end

+ 4 - 0
forms/FullSynchronize.h

@@ -10,6 +10,7 @@
 #include <HistoryComboBox.hpp>
 
 #include <WinInterface.h>
+#include <CopyParam.h>
 //---------------------------------------------------------------------------
 class TFullSynchronizeDialog : public TForm
 {
@@ -56,6 +57,7 @@ private:
   bool FSaveMode;
   TSynchronizeMode FOrigMode;
   int FOptions;
+  TUsableCopyParamAttrs FCopyParamAttrs;
   TCopyParamType FCopyParams;
   TPopupMenu * FPresetsMenu;
   AnsiString FPreset;
@@ -74,6 +76,7 @@ private:
   void __fastcall SetCopyParams(const TCopyParamType & value);
   TCopyParamType __fastcall GetCopyParams();
   void __fastcall CopyParamClick(TObject * Sender);
+   int __fastcall ActualCopyParamAttrs();
 
 public:
   __fastcall TFullSynchronizeDialog(TComponent* Owner);
@@ -88,6 +91,7 @@ public:
   __property bool SaveSettings = { read = GetSaveSettings, write = SetSaveSettings };
   __property bool SaveMode = { read = FSaveMode, write = FSaveMode };
   __property int Options = { read = FOptions, write = SetOptions };
+  __property TUsableCopyParamAttrs CopyParamAttrs = { read = FCopyParamAttrs, write = FCopyParamAttrs };
   __property TCopyParamType CopyParams = { read = FCopyParams, write = SetCopyParams };
 
 protected:

+ 182 - 50
forms/Glyphs.dfm

@@ -8,8 +8,8 @@ object GlyphsModule: TGlyphsModule
     Left = 32
     Top = 16
     Bitmap = {
-      494C010157005900040010001000FFFFFFFFFF00FFFFFFFFFFFFFFFF424D3600
-      0000000000003600000028000000400000007001000001002000000000000070
+      494C01015B005E00040010001000FFFFFFFFFF00FFFFFFFFFFFFFFFF424D3600
+      0000000000003600000028000000400000008001000001002000000000000080
       0100000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -146,127 +146,255 @@ object GlyphsModule: TGlyphsModule
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000CC330000CC330000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000008000000080000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000CC330000CC330000800000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000800000008000000080000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000008484840000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000CC330000CC3300000000
+      0000CC330000CC330000CC33000000000000CC330000CC330000CC3300008000
+      0000000000000000000000000000000000000000000000000000000000008000
+      0000800000008000000080000000000000008000000080000000800000000000
+      0000800000008000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000084848400000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000CC330000CC3300000000
+      0000CC330000CC330000CC33000000000000CC330000CC330000CC330000CC33
+      0000800000000000000000000000000000000000000000000000800000009933
+      0000993300009933000099330000000000009933000099330000993300000000
+      0000993300009933000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000848484000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000099330000993300000000
+      0000993300009933000099330000000000009933000099330000993300009933
+      0000993300008000000000000000000000000000000080000000993300009933
+      0000993300009933000099330000000000009933000099330000993300000000
+      0000993300009933000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000FFFF0000FFFF0000000000008484
+      8400000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000099330000993300000000
+      0000993300009933000099330000000000009933000099330000993300009933
+      000080000000000000000000000000000000000000000000000080000000CC33
+      0000CC330000CC330000CC33000000000000CC330000CC330000CC3300000000
+      0000CC330000CC33000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000FFFF0000FFFF0000000000008484
+      8400848484000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000080000000800000000000
+      0000800000008000000080000000000000008000000080000000800000008000
+      0000000000000000000000000000000000000000000000000000000000008000
+      0000CC330000CC330000CC33000000000000CC330000CC330000CC3300000000
+      0000CC330000CC33000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000FFFF0000FFFF00000000
+      0000848484008484840000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000008000000080000000800000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000080000000CC330000CC330000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000FFFF0000000000000000
+      0000848484008484840000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000008000000080000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000CC330000CC330000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000084000000
+      8400000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000008484840084848400848484008484
+      8400848484008484840084848400848484008484840084848400000000000000
       0000000000000000000000000000000000000000000000000000000000004C4C
       4C004C4C4C004C4C4C004C4C4C004C4C4C0000000000000000004C4C4C004C4C
       4C004C4C4C004C4C4C004C4C4C00000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       000000000000000000000000000000000000FF00000000000000FF0000000000
       0000FF00000000000000FF00000000000000FF00000000000000FF0000000000
-      0000FF00000000000000FF000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000FF00000000000000FF00000000000000C0C0C000C0C0C000C0C0C000C0C0
+      C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C00084848400000000000000
       0000000000000000000000000000000000000000000000000000000000004C4C
       4C009F705B009A705B009F705B004C4C4C0000000000000000004C4C4C009F70
       5B009A705B009F705B004C4C4C00000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C004C4C4C004C4C
+      000000000000000000000000000000000000C0C0C0009CFFFF00848484008484
+      840084848400848484008484840084848400C0C0C00084848400848484008484
+      840084848400000000000000000000000000000000004C4C4C004C4C4C004C4C
       4C00A4705B00A4705B00A4705B004C4C4C004C4C4C004C4C4C004C4C4C00A470
       5B00A4705B00A4705B004C4C4C00000000000000000000000000000000000000
       0000000000000000000066CC3300000000000000000000000000000000000000
       000000000000000000000000000000000000FF00000000000000000000000000
       0000000000000000000000008000000080000000800000000000000000000000
-      00000000000000000000FF000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C009F705B004C4C
+      00000000000000000000FF00000000000000C0C0C000FFFFFF009CFFFF009CFF
+      FF00FFFFFF009CFFFF00FFFFFF009CFFFF00C0C0C00084848400C0C0C000C0C0
+      C00084848400000000000000000000000000000000004C4C4C009F705B004C4C
       4C00AF755B00AF755B00AF755B004C4C4C004C4C4C009F705B004C4C4C00AF75
       5B00AF755B00AF755B004C4C4C00000000000000000000000000000000000000
       0000000000000066330066FF330066CC33000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000080000000800000000000000000000000000000008000000080000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00A4705B004C4C
+      000000000000000000000000000000000000C0C0C000FFFFFF00848484008484
+      840084848400848484008484840084848400C0C0C00084848400FFFFFF00C0C0
+      C00084848400848484008484840084848400000000004C4C4C00A4705B004C4C
       4C00BA7A5B00BA7A5B00BA7A5B004C4C4C004C4C4C00A4705B004C4C4C00BA7A
       5B00BA7A5B00BA7A5B004C4C4C00000000000000000000000000000000000000
       000066CC33000066330066FF330066FF330066CC330000000000000000000000
       000000000000000000000000000000000000FF00000000000000000000000000
       8000000000000000000000000000000000000000000000000000000000000000
-      80000000000000000000FF000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00AF755B004C4C
+      80000000000000000000FF00000000000000C0C0C000FFFFFF009CFFFF009CFF
+      FF00FFFFFF009CFFFF00FFFFFF00FFFFFF00C0C0C00084848400FFFFFF00C0C0
+      C00084848400C0C0C000C0C0C00084848400000000004C4C4C00AF755B004C4C
       4C00BA7A5B00BF7A5B00BA7A5B004C4C4C004C4C4C00AF755B004C4C4C00BA7A
       5B00BF7A5B00BA7A5B004C4C4C00000000000000000000000000000000000066
       330066FF33000066330066FF330066FF330066FF330066CC3300000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       8000000000000000000000000000000000000000000000000000000000000000
-      8000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00BA7A5B004C4C
+      800000000000000000000000000000000000C0C0C000FFFFFF00848484008484
+      8400848484008484840084848400FFFFFF00C0C0C00084848400FFFFFF00C0C0
+      C00084848400FFFFFF00C0C0C00084848400000000004C4C4C00BA7A5B004C4C
       4C00BA7A5B00BF7A5B00BA7A5B004C4C4C004C4C4C00BA7A5B004C4C4C00BA7A
       5B00BF7A5B00BA7A5B004C4C4C00000000000000000000000000000000000066
       330066FF33000066330099FFCC0066FF330066FF330066FF330066CC33000000
       000000000000000000000000000000000000FF00000000000000000080000000
       0000000000000000000000000000000000000000000000000000000000000000
-      00000000800000000000FF000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00BA7A5B004C4C
+      00000000800000000000FF00000000000000C0C0C000FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C0C0C00084848400FFFFFF00C0C0
+      C00084848400FFFFFF00C0C0C00084848400000000004C4C4C00BA7A5B004C4C
       4C00BF7F6000BF7F6000BF7F60004C4C4C004C4C4C00BA7A5B004C4C4C00BF7F
       6000BF7F6000BF7F60004C4C4C00000000000000000000000000000000000066
       330066FF33000066330099FFCC0099FFCC0066FF330066FF3300000000000000
       0000000000000000000000000000000000000000000000000000000080000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000080000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00BA7A5B004C4C
+      000000008000000000000000000000000000C0C0C000FFFFFF00848484008484
+      8400848484009CFFFF0084848400848484008484840084848400FFFFFF00C0C0
+      C00084848400FFFFFF00C0C0C00084848400000000004C4C4C00BA7A5B004C4C
       4C00C58A6A00C58A7000C58A6A004C4C4C004C4C4C00BA7A5B004C4C4C00C58A
       6A00C58A7000C58A6A004C4C4C00000000000000000000000000000000000066
       330099FFCC0000663300FFFFFF0099FFCC0099FFCC0000000000000000000000
       000000000000000000000000000000000000FF00000000000000000080000000
       0000000000000000000000000000000000000000000000008000000000000000
-      00000000800000000000FF000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00BF7F60004C4C
+      00000000800000000000FF00000000000000C0C0C000FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00C0C0C000FFFFFF0084848400FFFFFF00FFFFFF00C0C0
+      C00084848400FFFFFF00C0C0C00084848400000000004C4C4C00BF7F60004C4C
       4C00CA947500CF9A7F00CA947A004C4C4C004C4C4C00BF7F60004C4C4C00CA94
       7500CF9A7F00CA947A004C4C4C00000000000000000000000000000000000066
       330099FFCC0000663300FFFFFF00FFFFFF000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       8000000000000000000000000000000000000000000000008000000080000000
-      8000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00C58A6A004C4C
+      8000000000000000000000000000000000000000FF0000009C00FFFFFF00FFFF
+      FF000000FF0000009C00C0C0C00084848400FFFFFF0084848400848484008484
+      840084848400FFFFFF00C0C0C00084848400000000004C4C4C00C58A6A004C4C
       4C00CF9F8500CF9F8500CF9F85004C4C4C004C4C4C00C58A6A004C4C4C00CF9F
       8500CF9F8500CF9F85004C4C4C00000000000000000000000000000000000066
       3300FFFFFF0000663300FFFFFF00000000000000000000000000000000000000
       000000000000000000000000000000000000FF00000000000000000000000000
       8000000000000000000000000000000000000000000000008000000080000000
-      80000000000000000000FF000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00CA9475004C4C
+      80000000000000000000FF00000000000000C0C0C0000000FF0000009C000000
+      FF0000009C00C0C0C000C0C0C000FFFFFF00FFFFFF00C0C0C000FFFFFF008484
+      8400FFFFFF00FFFFFF00C0C0C00084848400000000004C4C4C00CA9475004C4C
       4C00CF9F8500CF9F8500CF9F85004C4C4C004C4C4C00CA9475004C4C4C00CF9F
       8500CF9F8500CF9F85004C4C4C00000000000000000000000000000000000066
       3300FFFFFF000066330000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000080000000800000000000000000000000000000008000000080000000
-      8000000080000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00CF9F85004C4C
+      80000000800000000000000000000000000000000000000000000000FF000000
+      9C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C0C0C00084848400FFFF
+      FF0084848400848484008484840084848400000000004C4C4C00CF9F85004C4C
       4C004C4C4C004C4C4C004C4C4C004C4C4C004C4C4C00CF9F85004C4C4C004C4C
       4C004C4C4C004C4C4C004C4C4C00000000000000000000000000000000000066
       3300FFFFFF000066330000000000000000000000000000000000000000000000
       000000000000000000000000000000000000FF00000000000000000000000000
       0000000000000000000000008000000080000000000000000000000000000000
-      00000000000000000000FF000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00CF9F8500CF9F
+      00000000000000000000FF00000000000000000000000000FF0000009C000000
+      FF0000009C00C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000FFFFFF00FFFF
+      FF00C0C0C000FFFFFF008484840000000000000000004C4C4C00CF9F8500CF9F
       8500CF9F85004C4C4C0000000000000000004C4C4C00CF9F8500CF9F8500CF9F
       85004C4C4C000000000000000000000000000000000000000000000000000066
       3300000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C004C4C4C004C4C
+      0000000000000000000000000000000000000000FF0000009C00000000000000
+      00000000FF0000009C00C0C0C000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00C0C0C000848484000000000000000000000000004C4C4C004C4C4C004C4C
       4C004C4C4C004C4C4C0000000000000000004C4C4C004C4C4C004C4C4C004C4C
       4C004C4C4C000000000000000000000000000000000000000000000000000066
       3300000000000000000000000000000000000000000000000000000000000000
       000000000000000000000000000000000000FF00000000000000FF0000000000
       0000FF00000000000000FF00000000000000FF00000000000000FF0000000000
       0000FF00000000000000FF000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0
+      C000C0C0C0000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000008080800000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000008080800000000000000000000000
@@ -2955,16 +3083,20 @@ object GlyphsModule: TGlyphsModule
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       000000000000000000000000000000000000424D3E000000000000003E000000
-      2800000040000000700100000100010000000000800B00000000000000000000
+      2800000040000000800100000100010000000000000C00000000000000000000
       000000000000000000000000FFFFFF0000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000FFFFFFFFFFFF0000E0C1FBFF55550000
-      E0C1F9FFFFFF00008001E8FF7C7D00008001E07FF39F00008001E03F6FED0000
+      00000000000000000000000000000000FFFFFFFFFFFF0000FFFFFFFFFFFF0000
+      FFFFFFFFFEAB0000FF3FF9FFEFFF0000FF1FF1FFC67F0000910FE113AA3F0000
+      9107C113EA1F000091038113E60F00009107C113CE070000910FE113AF030000
+      FF1FF1FFAB030000FF3FF9FFC7870000FFFFFFFFEF8F0000FFFFFFFFFFFF0000
+      FFFFFFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF003FE0C1FBFF5555003F
+      E0C1F9FFFFFF00078001E8FF7C7D00078001E07FF39F00008001E03F6FED0000
       8001E01FEFEF00008001E00F5FF500008001E01FDFF700008001E03F5FB50000
-      8001E07FEF8F00008001E0FF6F8D00008001E1FFF38700008001E3FF7CFD0000
-      8307E7FFFFFF00008307EFFF55550000FE7FFE7F0003FFFFF00FF00F0003C183
+      8001E07FEF8F00008001E0FF6F8D00008001E1FFF387C0008001E3FF7CFD8001
+      8307E7FFFFFF30038307EFFF5555FC07FE7FFE7F0003FFFFF00FF00F0003C183
       E007E0070003C183C003C0030003C183C003C0030003C183800180010003C183
       800180010003C183800180018003C183800180018003C183800180018003C183
       800180018003C183C003C0038003C183C003C0038003C183E001E0018007C183

+ 12 - 10
forms/Licence.cpp

@@ -8,12 +8,12 @@
 #include <VCLCommon.h>
 #include "WinInterface.h"
 #include "Licence.h"
+#include "Tools.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------------
-int LicenceStr[2] = { LICENCE, LICENCE_PUTTY };
-int LicenceCount[2] = { 17, 2 };
+AnsiString LicenceStr[2] = { "LICENCE", "LICENCE_PUTTY" };
 //---------------------------------------------------------------------------
 void __fastcall DoLicenceDialog(TLicence Licence)
 {
@@ -58,16 +58,18 @@ void __fastcall TLicenceDialog::SetLicence(TLicence value)
   {
     FLicence = value;
     TStrings * LicenceList = new TStringList();
-    AnsiString ALicence = LoadStr(LicenceStr[FLicence]);
-    for (Integer i = 1; i < LicenceCount[FLicence]; i++)
+    try
     {
-      ALicence += LoadStr(LicenceStr[FLicence] + i);
+      LicenceList->Text = ReadResource(LicenceStr[FLicence]);
+      assert(LicenceList->Count > 0);
+      Caption = FMTLOAD(LICENCE_CAPTION, (LicenceList->Strings[0]));
+      LicenceList->Delete(0);
+      LicenceText = LicenceList->Text;
+    }
+    __finally
+    {
+      delete LicenceList;
     }
-    LicenceList->Text = ALicence;
-    assert(LicenceList->Count > 0);
-    Caption = FMTLOAD(LICENCE_CAPTION, (LicenceList->Strings[0]));
-    LicenceList->Delete(0);
-    LicenceText = LicenceList->Text;
   }
 }
 //---------------------------------------------------------------------------

+ 3 - 2
forms/Log.cpp

@@ -13,6 +13,7 @@
 #include "Glyphs.h"
 #include "NonVisual.h"
 #include "WinConfiguration.h"
+#include "Tools.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma link "LogMemo"
@@ -137,7 +138,7 @@ void __fastcall TLogForm::FormClose(TObject * /*Sender*/, TCloseAction & Action)
     WinConfiguration->LogView = lvNone;
     Action = caFree;
   }
-  WinConfiguration->LogWindowParams = WinConfiguration->StoreForm(this);
+  WinConfiguration->LogWindowParams = StoreForm(this);
 }
 //---------------------------------------------------------------------------
 void __fastcall TLogForm::SetSessionLog(TSessionLog * value)
@@ -180,7 +181,7 @@ void __fastcall TLogForm::CreateParams(TCreateParams & Params)
   {
     FFormRestored = True;
     assert(Configuration);
-    WinConfiguration->RestoreForm(WinConfiguration->LogWindowParams, this);
+    RestoreForm(WinConfiguration->LogWindowParams, this);
   }
   TForm::CreateParams(Params);
   Params.WndParent = GetDesktopWindow();

+ 6 - 2
forms/LogSettings.cpp

@@ -119,9 +119,13 @@ void __fastcall TLoggingFrame::DataChange(TObject * /*Sender*/)
 //---------------------------------------------------------------------------
 AnsiString __fastcall TLoggingFrame::GetDefaultLogFileName()
 {
-  assert(FOnGetDefaultLogFileName);
   AnsiString Result;
-  FOnGetDefaultLogFileName(this, Result);
+  Result = IncludeTrailingBackslash(SystemTemporaryDirectory()) + "&s.log";
+
+  if (FOnGetDefaultLogFileName)
+  {
+    FOnGetDefaultLogFileName(this, Result);
+  }
   return Result;
 }
 //---------------------------------------------------------------------------

+ 75 - 17
forms/Login.cpp

@@ -59,12 +59,12 @@ __fastcall TLoginDialog::TLoginDialog(TComponent* AOwner)
   FSavedSession = -1;
   FOptions = loStartup;
   FLocaleChanging = false;
+  FColor = (TColor)0;
   InitControls();
 }
 //---------------------------------------------------------------------
 __fastcall TLoginDialog::~TLoginDialog()
 {
-  LoggingFrame->OnGetDefaultLogFileName = NULL;
   // SelectItem event is called after destructor! Why?
   SessionListView->Selected = NULL;
   delete FSystemSettings;
@@ -106,7 +106,6 @@ void __fastcall TLoginDialog::InitControls()
 //---------------------------------------------------------------------
 void __fastcall TLoginDialog::Init()
 {
-  LoggingFrame->OnGetDefaultLogFileName = LoggingGetDefaultLogFileName;
   UseSystemSettings(this, &FSystemSettings);
   Caption = FORMAT("%s %s", (AppName, Caption));
 
@@ -123,6 +122,14 @@ void __fastcall TLoginDialog::Init()
     DirectoriesGroup->Height = RemoteDirectoryEdit->Top + RemoteDirectoryEdit->Height + 12;
   }
 
+  if (FLAGCLEAR(Options, loExternalProtocols))
+  {
+    ExternalSSHButton->Visible = false;
+    ExternalSFTPButton->Visible = false;
+    TransferProtocolGroup->Height = TransferProtocolGroup->Height -
+       (ExternalSSHButton->Top - SFTPonlyButton->Top);
+  }
+
   ShowTabs(false);
 
   if (StoredSessions && StoredSessions->Count && 
@@ -207,10 +214,13 @@ void __fastcall TLoginDialog::LoadSession(TSessionData * aSessionData)
     HostNameEdit->Text = aSessionData->HostName;
     PasswordEdit->Text = aSessionData->Password;
     PrivateKeyEdit->Text = aSessionData->PublicKeyFile;
+    FColor = (TColor)aSessionData->Color;
 
     switch (aSessionData->FSProtocol) {
       case fsSCPonly: SCPonlyButton->Checked = true; break;
       case fsSFTP: SFTPButton->Checked = true; break;
+      case fsExternalSFTP: ExternalSFTPButton->Checked = true; break;
+      case fsExternalSSH: ExternalSSHButton->Checked = true; break;
       case fsSFTPonly:
       default: SFTPonlyButton->Checked = true; break;
     }
@@ -405,10 +415,15 @@ void __fastcall TLoginDialog::SaveSession(TSessionData * aSessionData)
   aSessionData->HostName = HostNameEdit->Text.Trim();
   aSessionData->Password = PasswordEdit->Text;
   aSessionData->PublicKeyFile = PrivateKeyEdit->Text;
+  aSessionData->Color = FColor;
 
   if (SCPonlyButton->Checked) aSessionData->FSProtocol = fsSCPonly;
     else
   if (SFTPButton->Checked) aSessionData->FSProtocol = fsSFTP;
+    else
+  if (ExternalSFTPButton->Checked) aSessionData->FSProtocol = fsExternalSFTP;
+    else
+  if (ExternalSSHButton->Checked) aSessionData->FSProtocol = fsExternalSSH;
     else aSessionData->FSProtocol = fsSFTPonly;
 
   // SSH tab
@@ -559,12 +574,19 @@ void __fastcall TLoginDialog::UpdateControls()
     NoUpdate++;
     try
     {
+      bool ExternalProtocol = ExternalSSHButton->Checked || ExternalSFTPButton->Checked;
+
       #define SHOW_NAVIGATION(TREE, SHOW) if ((TREE)->Visible != (SHOW)) { \
         (TREE)->Visible = (SHOW); PageControlChange(PageControl); }
       SHOW_NAVIGATION(SimpleNavigationTree, !ShowAdvancedLoginOptionsCheck->Checked);
       SHOW_NAVIGATION(AdvancedNavigationTree, ShowAdvancedLoginOptionsCheck->Checked);
       #undef SHOW_NAVIGATION
 
+      EnableControl(ExternalSSHButton,
+        !GUIConfiguration->PuttyPath.Trim().IsEmpty());
+      EnableControl(ExternalSFTPButton,
+        !GUIConfiguration->PSftpPath.Trim().IsEmpty());
+
       EnableControl(ShellIconsButton, SessionListView->Selected);
 
       EnableControl(PingIntervalSecEdit, !PingOffButton->Checked);
@@ -597,8 +619,9 @@ void __fastcall TLoginDialog::UpdateControls()
       EnableControl(BugPKSessID2Combo, !SshProt1onlyButton->Checked);
       EnableControl(BugRekey2Combo, !SshProt1onlyButton->Checked);
 
-      EnableControl(ShellEdit, ShellEnterButton->Checked);
-      EnableControl(ReturnVarEdit, ReturnVarEnterButton->Checked);
+      EnableControl(ScpSheet, !ExternalProtocol);
+      EnableControl(ShellEdit, ShellEnterButton->Checked && ScpSheet->Enabled);
+      EnableControl(ReturnVarEdit, ReturnVarEnterButton->Checked && ScpSheet->Enabled);
 
       EnableControl(ProxyHostEdit, !ProxyNoneButton->Checked);
       EnableControl(ProxyPortEdit, !ProxyNoneButton->Checked);
@@ -608,18 +631,24 @@ void __fastcall TLoginDialog::UpdateControls()
       EnableControl(ProxySettingsGroup, !ProxyNoneButton->Checked);
       EnableControl(ProxyTelnetCommandEdit, ProxyTelnetButton->Checked);
 
+      EnableControl(DirectoriesSheet, !ExternalProtocol);
       EnableControl(CacheDirectoryChangesCheck,
-        !SCPonlyButton->Checked || CacheDirectoriesCheck->Checked);
+        (!SCPonlyButton->Checked || CacheDirectoriesCheck->Checked) && DirectoriesSheet->Enabled);
       EnableControl(PreserveDirectoryChangesCheck,
-        CacheDirectoryChangesCheck->Enabled && CacheDirectoryChangesCheck->Checked);
+        CacheDirectoryChangesCheck->Enabled && CacheDirectoryChangesCheck->Checked &&
+        DirectoriesSheet->Enabled);
 
-      EnableControl(OverwrittenToRecycleBinCheck, !SCPonlyButton->Checked);
+      EnableControl(EnvironmentSheet, !ExternalProtocol);
+      EnableControl(OverwrittenToRecycleBinCheck, !SCPonlyButton->Checked &&
+        EnvironmentSheet->Enabled);
       EnableControl(RecycleBinPathEdit,
         (DeleteToRecycleBinCheck->Enabled && DeleteToRecycleBinCheck->Checked) ||
-        (OverwrittenToRecycleBinCheck->Enabled && OverwrittenToRecycleBinCheck->Checked));
-      EnableControl(RecycleBinPathLabel, RecycleBinPathEdit->Enabled);
+        (OverwrittenToRecycleBinCheck->Enabled && OverwrittenToRecycleBinCheck->Checked) &&
+        EnvironmentSheet->Enabled);
+      EnableControl(RecycleBinPathLabel, RecycleBinPathEdit->Enabled &&
+        EnvironmentSheet->Enabled);
 
-      EnableControl(SftpSheet, !SCPonlyButton->Checked);
+      EnableControl(SftpSheet, !SCPonlyButton->Checked && !ExternalProtocol);
 
       EnableControl(KexSheet, !SshProt1onlyButton->Checked);
 
@@ -812,6 +841,7 @@ void __fastcall TLoginDialog::SaveSessionActionExecute(TObject * /*Sender*/)
   AnsiString SessionName;
   SaveSession(FSessionData);
   if (FSessionData->Password.IsEmpty() ||
+      Configuration->DisablePasswordStoring ||
       (MessageDialog(LoadStr(SAVE_PASSWORD), qtWarning, qaOK | qaCancel,
          HELP_SESSION_SAVE_PASSWORD) == qaOK))
   {
@@ -950,16 +980,10 @@ void __fastcall TLoginDialog::LoadConfiguration()
   UpdateControls();
 }
 //---------------------------------------------------------------------------
-void __fastcall TLoginDialog::LoggingGetDefaultLogFileName(
-  TObject* /*Sender*/, AnsiString & DefaultLogFileName)
-{
-  assert(FSessionData);
-  DefaultLogFileName = FSessionData->DefaultLogFileName;
-}
-//---------------------------------------------------------------------------
 void __fastcall TLoginDialog::PreferencesButtonClick(TObject * /*Sender*/)
 {
   ShowPreferencesDialog();
+  UpdateControls();
 }
 //---------------------------------------------------------------------------
 void __fastcall TLoginDialog::ShowPreferencesDialog()
@@ -1373,4 +1397,38 @@ void __fastcall TLoginDialog::FormCloseQuery(TObject * /*Sender*/,
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TLoginDialog::ColorButtonClick(TObject * /*Sender*/)
+{
+  ColorDefaultItem->Checked = (FColor == 0);
+  PickColorItem->Checked = (FColor != 0);
+  PickColorItem->ImageIndex = (FColor != 0 ? 0 : -1);
+  ColorImageList->BkColor = FColor;
+
+  TPoint PopupPoint = ColorButton->ClientToScreen(TPoint(0, ColorButton->Height));
+  ColorPopupMenu->Popup(PopupPoint.x, PopupPoint.y);
+}
+//---------------------------------------------------------------------------
+void __fastcall TLoginDialog::ColorDefaultItemClick(TObject * /*Sender*/)
+{
+  FColor = (TColor)0;
+}
+//---------------------------------------------------------------------------
+void __fastcall TLoginDialog::PickColorItemClick(TObject * /*Sender*/)
+{
+  TColorDialog * Dialog = new TColorDialog(this);
+  try
+  {
+    Dialog->Options = Dialog->Options << cdFullOpen;
+    Dialog->Color = (FColor != 0 ? FColor : clSkyBlue);
+    if (Dialog->Execute())
+    {
+      FColor = Dialog->Color;
+    }
+  }
+  __finally
+  {
+    delete Dialog;
+  }
+}
+//---------------------------------------------------------------------------
 

+ 207 - 21
forms/Login.dfm

@@ -7,7 +7,7 @@ object LoginDialog: TLoginDialog
   BorderStyle = bsDialog
   Caption = 'Login'
   ClientHeight = 364
-  ClientWidth = 522
+  ClientWidth = 532
   Color = clBtnFace
   ParentFont = True
   KeyPreview = True
@@ -17,12 +17,12 @@ object LoginDialog: TLoginDialog
   OnKeyDown = FormKeyDown
   OnShow = FormShow
   DesignSize = (
-    522
+    532
     364)
   PixelsPerInch = 96
   TextHeight = 13
   object SaveButton: TButton
-    Left = 260
+    Left = 270
     Top = 333
     Width = 75
     Height = 25
@@ -32,7 +32,7 @@ object LoginDialog: TLoginDialog
     TabOrder = 2
   end
   object LoginButton: TButton
-    Left = 348
+    Left = 358
     Top = 333
     Width = 75
     Height = 25
@@ -43,7 +43,7 @@ object LoginDialog: TLoginDialog
     TabOrder = 3
   end
   object CloseButton: TButton
-    Left = 436
+    Left = 446
     Top = 333
     Width = 75
     Height = 25
@@ -77,7 +77,7 @@ object LoginDialog: TLoginDialog
   object MainPanel: TPanel
     Left = 0
     Top = 0
-    Width = 522
+    Width = 532
     Height = 324
     Align = alTop
     Anchors = [akLeft, akTop, akRight, akBottom]
@@ -85,7 +85,7 @@ object LoginDialog: TLoginDialog
     TabOrder = 6
     object PageControl: TPageControl
       Tag = 6
-      Left = 161
+      Left = 171
       Top = 0
       Width = 361
       Height = 324
@@ -313,7 +313,7 @@ object LoginDialog: TLoginDialog
           Left = 0
           Top = 182
           Width = 345
-          Height = 48
+          Height = 71
           Anchors = [akLeft, akTop, akRight]
           Caption = 'Protocol'
           TabOrder = 1
@@ -346,6 +346,33 @@ object LoginDialog: TLoginDialog
             TabOrder = 0
             OnClick = DataChange
           end
+          object ExternalSSHButton: TRadioButton
+            Left = 16
+            Top = 42
+            Width = 129
+            Height = 17
+            Caption = 'SSH &Terminal'
+            TabOrder = 3
+            OnClick = DataChange
+          end
+          object ExternalSFTPButton: TRadioButton
+            Left = 168
+            Top = 42
+            Width = 129
+            Height = 17
+            Caption = 'SFTP Ter&minal'
+            TabOrder = 4
+            OnClick = DataChange
+          end
+        end
+        object ColorButton: TButton
+          Left = 271
+          Top = 238
+          Width = 75
+          Height = 25
+          Caption = 'Select c&olor'
+          TabOrder = 2
+          OnClick = ColorButtonClick
         end
       end
       object AdvancedSheet: TTabSheet
@@ -1197,9 +1224,9 @@ object LoginDialog: TLoginDialog
             Height = 21
             Alignment = taRightJustify
             Increment = 5
-            MaxValue = 300
+            MaxValue = 6000
             MinValue = 5
-            MaxLength = 3
+            MaxLength = 4
             TabOrder = 0
             OnChange = DataChange
           end
@@ -1875,18 +1902,18 @@ object LoginDialog: TLoginDialog
     object LeftPanel: TPanel
       Left = 0
       Top = 0
-      Width = 161
+      Width = 171
       Height = 324
       Align = alLeft
       BevelOuter = bvNone
       TabOrder = 0
       DesignSize = (
-        161
+        171
         324)
       object SimpleNavigationTree: TTreeView
         Left = 8
         Top = 9
-        Width = 145
+        Width = 155
         Height = 288
         Anchors = [akLeft, akTop, akRight, akBottom]
         HideSelection = False
@@ -1909,7 +1936,7 @@ object LoginDialog: TLoginDialog
       object AdvancedNavigationTree: TTreeView
         Left = 8
         Top = 9
-        Width = 145
+        Width = 155
         Height = 288
         Anchors = [akLeft, akTop, akRight, akBottom]
         HideSelection = False
@@ -1940,7 +1967,7 @@ object LoginDialog: TLoginDialog
       object ShowAdvancedLoginOptionsCheck: TCheckBox
         Left = 16
         Top = 304
-        Width = 129
+        Width = 139
         Height = 17
         Anchors = [akLeft, akRight, akBottom]
         Caption = '&Advanced options'
@@ -1950,7 +1977,7 @@ object LoginDialog: TLoginDialog
     end
   end
   object HelpButton: TButton
-    Left = 436
+    Left = 446
     Top = 333
     Width = 75
     Height = 25
@@ -1961,7 +1988,7 @@ object LoginDialog: TLoginDialog
   end
   object ActionList: TActionList
     OnUpdate = ActionListUpdate
-    Left = 20
+    Left = 12
     Top = 257
     object LoadSessionAction: TAction
       Category = 'Sessions'
@@ -2026,8 +2053,8 @@ object LoginDialog: TLoginDialog
     end
   end
   object ToolsPopupMenu: TPopupMenu
-    Left = 64
-    Top = 256
+    Left = 48
+    Top = 257
     object Import1: TMenuItem
       Action = ImportSessionsAction
     end
@@ -2039,8 +2066,8 @@ object LoginDialog: TLoginDialog
     end
   end
   object IconsPopupMenu: TPopupMenu
-    Left = 104
-    Top = 256
+    Left = 80
+    Top = 257
     object Desktopicon1: TMenuItem
       Action = DesktopIconAction
     end
@@ -2048,4 +2075,163 @@ object LoginDialog: TLoginDialog
       Action = SendToHookAction
     end
   end
+  object ColorPopupMenu: TPopupMenu
+    Images = ColorImageList
+    Left = 112
+    Top = 257
+    object ColorDefaultItem: TMenuItem
+      Caption = '&Default'
+      OnClick = ColorDefaultItemClick
+    end
+    object PickColorItem: TMenuItem
+      Caption = '&Pick Color...'
+      ImageIndex = 0
+      OnClick = PickColorItemClick
+    end
+  end
+  object ColorImageList: TImageList
+    BkColor = clRed
+    AllocBy = 1
+    Left = 144
+    Top = 257
+    Bitmap = {
+      494C010101000400040010001000FF000000FF10FFFFFFFFFFFFFFFF424D3600
+      0000000000003600000028000000400000001000000001002000000000000010
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000424D3E000000000000003E000000
+      2800000040000000100000000100010000000000800000000000000000000000
+      000000000000000000000000FFFFFF00FFFF000000000000FFFF000000000000
+      FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000
+      FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000
+      FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000
+      FFFF000000000000FFFF00000000000000000000000000000000000000000000
+      000000000000}
+  end
 end

+ 13 - 3
forms/Login.h

@@ -26,6 +26,7 @@
 
 #include "LogSettings.h"
 #include "GeneralSettings.h"
+#include <ImgList.hpp>
 //----------------------------------------------------------------------------
 class TLoginDialog : public TForm
 {
@@ -238,6 +239,13 @@ __published:
   TComboBox *SFTPBugUtfCombo;
   TComboBox *SFTPBugSignedTSCombo;
   TButton *HelpButton;
+  TRadioButton *ExternalSSHButton;
+  TRadioButton *ExternalSFTPButton;
+  TButton *ColorButton;
+  TPopupMenu *ColorPopupMenu;
+  TMenuItem *ColorDefaultItem;
+  TMenuItem *PickColorItem;
+  TImageList *ColorImageList;
   void __fastcall DataChange(TObject *Sender);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall SessionListViewSelectItem(TObject *Sender,
@@ -283,6 +291,9 @@ __published:
   void __fastcall PrivateKeyEditAfterDialog(TObject *Sender,
           AnsiString &Name, bool &Action);
   void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
+  void __fastcall ColorButtonClick(TObject *Sender);
+  void __fastcall ColorDefaultItemClick(TObject *Sender);
+  void __fastcall PickColorItemClick(TObject *Sender);
 
 private:
   int NoUpdate;
@@ -297,7 +308,8 @@ private:
   int FSavedSession;
   bool FLocaleChanging;
   void * FSystemSettings;
-  AnsiString FCurrentSessionName;  
+  AnsiString FCurrentSessionName;
+  TColor FColor;
 
   void __fastcall LoadSession(TSessionData * aSessionData);
   void __fastcall UpdateControls();
@@ -317,8 +329,6 @@ private:
 protected:
   void __fastcall Default();
   void __fastcall LoadConfiguration();
-  void __fastcall LoggingGetDefaultLogFileName(System::TObject* Sender,
-    AnsiString & DefaultLogFileName);
   void __fastcall SaveConfiguration();
   void __fastcall ShowPreferencesDialog();
   void __fastcall ChangePage(TTabSheet * Tab);

+ 24 - 7
forms/MessageDlg.cpp

@@ -9,6 +9,7 @@
 #include <Common.h>
 #include <VCLCommon.h>
 #include <WinInterface.h>
+#include <TextsWin.h>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
@@ -17,7 +18,8 @@ class TMessageForm : public TForm
 public:
   static TForm * __fastcall Create(const AnsiString & Msg, TStrings * MoreMessages,
     TMsgDlgType DlgType, TMsgDlgButtons Buttons,
-    TQueryButtonAlias * Aliases, unsigned int AliasesCount);
+    TQueryButtonAlias * Aliases, unsigned int AliasesCount,
+    TMsgDlgBtn TimeoutResult, TButton ** TimeoutButton);
 
 protected:
   __fastcall TMessageForm(TComponent * AOwner);
@@ -103,7 +105,7 @@ void __fastcall TMessageForm::CreateParams(TCreateParams & Params)
 void __fastcall TMessageForm::DoShow()
 {
   UseSystemSettingsPost(this);
-  
+
   TForm::DoShow();
 }
 //---------------------------------------------------------------------------
@@ -134,7 +136,8 @@ const int mcMoreMessageHeight = 80;
 //---------------------------------------------------------------------------
 TForm * __fastcall TMessageForm::Create(const AnsiString & Msg,
   TStrings * MoreMessages, TMsgDlgType DlgType, TMsgDlgButtons Buttons,
-  TQueryButtonAlias * Aliases, unsigned int AliasesCount)
+  TQueryButtonAlias * Aliases, unsigned int AliasesCount,
+  TMsgDlgBtn TimeoutResult, TButton ** TimeoutButton)
 {
   TRect TextRect;
 
@@ -169,6 +172,11 @@ TForm * __fastcall TMessageForm::Create(const AnsiString & Msg,
     CancelButton = mbOK;
   }
 
+  if (TimeoutButton != NULL)
+  {
+    *TimeoutButton = NULL;
+  }
+
   TMessageForm * Result = new TMessageForm(Application);
 
   Result->BiDiMode = Application->BiDiMode;
@@ -214,8 +222,17 @@ TForm * __fastcall TMessageForm::Create(const AnsiString & Msg,
         }
       }
 
+      TButton * Button = new TButton(Result);
+
+      AnsiString MeasureCaption = Caption;
+      if ((TimeoutButton != NULL) && (B == TimeoutResult))
+      {
+        MeasureCaption = FMTLOAD(TIMEOUT_BUTTON, (MeasureCaption, 99));
+        *TimeoutButton = Button;
+      }
+
       DrawText(Result->Canvas->Handle,
-        Caption.c_str(), -1,
+        MeasureCaption.c_str(), -1,
         &TextRect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE |
         Result->DrawTextBiDiModeFlagsReadingOnly());
       int CurButtonWidth = TextRect.Right - TextRect.Left + 8;
@@ -224,7 +241,6 @@ TForm * __fastcall TMessageForm::Create(const AnsiString & Msg,
         ButtonWidth = CurButtonWidth;
       }
 
-      TButton * Button = new TButton(Result);
       Button->Name = ButtonNames[TMsgDlgBtn(B)];
       Button->Parent = Result;
       Button->Caption = Caption;
@@ -369,9 +385,10 @@ TForm * __fastcall TMessageForm::Create(const AnsiString & Msg,
 //---------------------------------------------------------------------------
 TForm * __fastcall CreateMoreMessageDialog(const AnsiString & Msg,
   TStrings * MoreMessages, TMsgDlgType DlgType, TMsgDlgButtons Buttons,
-  TQueryButtonAlias * Aliases, unsigned int AliasesCount)
+  TQueryButtonAlias * Aliases, unsigned int AliasesCount,
+  TMsgDlgBtn TimeoutResult, TButton ** TimeoutButton)
 {
   return TMessageForm::Create(Msg, MoreMessages, DlgType, Buttons,
-    Aliases, AliasesCount);
+    Aliases, AliasesCount, TimeoutResult, TimeoutButton);
 }
 

+ 151 - 45
forms/NonVisual.cpp

@@ -138,6 +138,8 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
   // CURRENT DIRVIEW
   bool EnableSelectedOperation = ScpExplorer->EnableSelectedOperation[osCurrent];
   bool EnableFocusedOperation = ScpExplorer->EnableFocusedOperation[osCurrent];
+  bool EnableSelectedFileOperation = ScpExplorer->EnableSelectedFileOperation[osCurrent];
+  bool EnableFocusedFileOperation = ScpExplorer->EnableFocusedFileOperation[osCurrent];
   // focused operation
   UPD(CurrentCopyFocusedAction, EnableFocusedOperation)
   UPD(CurrentMoveFocusedAction, EnableFocusedOperation)
@@ -147,16 +149,16 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
     (DirView(osRemote) == DirView(osCurrent)) &&
     ScpExplorer->Terminal->IsCapable[fcRemoteMove])
   UPD(RemoteCopyToFocusedAction, EnableFocusedOperation && (DirView(osRemote) == DirView(osCurrent)))
+  UPD(CurrentEditFocusedAction, EnableFocusedFileOperation &&
+    !WinConfiguration->DisableOpenEdit)
   // file operation
   UPD(CurrentRenameAction, EnableFocusedOperation &&
     ((ScpExplorer->HasDirView[osLocal] && DirView(osLocal) == DirView(osCurrent)) ||
       ScpExplorer->Terminal->IsCapable[fcRename]))
-  UPD(CurrentEditAction, EnableFocusedOperation &&
-    !WinConfiguration->DisableOpenEdit &&
-    !DirView(osCurrent)->ItemIsDirectory(DirView(osCurrent)->ItemFocused))
-  UPD(CurrentEditAlternativeAction, EnableFocusedOperation &&
-    !WinConfiguration->DisableOpenEdit &&
-    !DirView(osCurrent)->ItemIsDirectory(DirView(osCurrent)->ItemFocused))
+  UPD(CurrentEditAction, EnableSelectedFileOperation &&
+    !WinConfiguration->DisableOpenEdit)
+  UPD(CurrentEditAlternativeAction, EnableSelectedFileOperation &&
+    !WinConfiguration->DisableOpenEdit)
   UPD(CurrentOpenAction, EnableFocusedOperation &&
     !WinConfiguration->DisableOpenEdit &&
     !DirView(osCurrent)->ItemIsDirectory(DirView(osCurrent)->ItemFocused))
@@ -164,8 +166,14 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
     (DirView(osCurrent) != DirView(osRemote) ||
      (ScpExplorer->Terminal->ResolvingSymlinks &&
       ScpExplorer->Terminal->IsCapable[fcSymbolicLink])))
+  UPD(NewLinkAction, ScpExplorer->Terminal &&
+    (DirView(osCurrent) != DirView(osRemote) ||
+     (ScpExplorer->Terminal->ResolvingSymlinks &&
+      ScpExplorer->Terminal->IsCapable[fcSymbolicLink])))
   // selected operaton
   UPD(CurrentCopyAction, EnableSelectedOperation)
+  UPD(RemoteCopyAction, ScpExplorer->EnableSelectedOperation[osRemote])
+  UPD(LocalCopyAction, ScpExplorer->HasDirView[osLocal] && ScpExplorer->EnableSelectedOperation[osLocal])
   UPD(CurrentMoveAction, EnableSelectedOperation)
   UPD(CurrentDeleteAction, EnableSelectedOperation)
   UPD(CurrentPropertiesAction, EnableSelectedOperation)
@@ -180,6 +188,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
   UPD(FileListFromClipboardAction, IsFormatInClipboard(CF_TEXT));
   // directory
   UPD(CurrentCreateDirAction, true)
+  UPD(NewDirAction, true)
   // selection
   UPD(SelectOneAction, DirView(osCurrent)->FilesCount)
   UPD(SelectAction, DirView(osCurrent)->FilesCount)
@@ -255,6 +264,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
   UPDCOMP(ExplorerSortBand)
   UPDCOMP(ExplorerUpdatesBand)
   UPDCOMP(ExplorerTransferBand)
+  UPDCOMP(ExplorerCustomCommandsBand)
   UPDCOMP(CommanderMenuBand)
   UPDCOMP(CommanderSessionBand)
   UPDCOMP(CommanderPreferencesBand)
@@ -264,6 +274,8 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
   UPDCOMP(CommanderCommandsBand)
   UPDCOMP(CommanderUpdatesBand)
   UPDCOMP(CommanderTransferBand)
+  UPDCOMP(CommanderUploadDownloadBand)
+  UPDCOMP(CommanderCustomCommandsBand)
   UPDCOMP(CommanderLocalHistoryBand)
   UPDCOMP(CommanderLocalNavigationBand)
   UPDCOMP(CommanderRemoteHistoryBand)
@@ -280,6 +292,11 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
   UPD(PresetsPreferencesAction, true)
   UPDEX(LockToolbarsAction, true,
     LockToolbarsAction->Checked = WinConfiguration->LockToolbars, )
+  UPDCOMP(CustomCommandsBand)
+  UPD(ColorMenuAction, true)
+  UPDACT(ColorDefaultAction,
+    ColorDefaultAction->Checked = (ScpExplorer->SessionColor == 0));
+  UPD(ColorPickAction, true);
 
   // SORT
   UPDSORTA(Local)
@@ -350,7 +367,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
   UPD(CloseApplicationAction, true)
   UPD(FileSystemInfoAction, true)
   UPD(ClearCachesAction, (ScpExplorer->Terminal != NULL) && !ScpExplorer->Terminal->AreCachesEmpty)
-  UPD(EditNewAction, !WinConfiguration->DisableOpenEdit)
+  UPD(NewFileAction, !WinConfiguration->DisableOpenEdit)
   UPD(EditorListCustomizeAction, true)
 
   // CUSTOM COMMANDS
@@ -391,6 +408,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
   QUEUEACTION(HideWhenEmpty)
   QUEUEACTION(Hide)
   #undef QUEUEACTION
+  UPD(QueueDisconnectOnceEmptyAction, ScpExplorer->AllowQueueOperation(qoDisconnectOnceEmpty))
   UPDCOMP(CommanderPreferencesBand)
   UPDACT(QueueToolbarAction,
     ((TAction *)Action)->Enabled = ScpExplorer->ComponentVisible[fcQueueView];
@@ -419,13 +437,17 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
     EXE(CurrentPropertiesFocusedAction, ScpExplorer->ExecuteFileOperation(foSetProperties, osCurrent, true))
     EXE(RemoteMoveToFocusedAction, ScpExplorer->ExecuteFileOperation(foRemoteMove, osCurrent, true))
     EXE(RemoteCopyToFocusedAction, ScpExplorer->ExecuteFileOperation(foRemoteCopy, osCurrent, true))
+    EXE(CurrentEditFocusedAction, ScpExplorer->ExecuteFile(osCurrent, efDefaultEditor, NULL, true, true))
     // operation
     EXE(CurrentCopyAction, ScpExplorer->ExecuteFileOperation(foCopy, osCurrent, false))
+    EXE(RemoteCopyAction, ScpExplorer->ExecuteFileOperation(foCopy, osRemote, false))
+    EXE(LocalCopyAction, ScpExplorer->ExecuteFileOperation(foCopy, osLocal, false))
     EXE(CurrentMoveAction, ScpExplorer->ExecuteFileOperation(foMove, osCurrent, false))
-    EXE(CurrentEditAction, ScpExplorer->ExecuteFile(osCurrent, efDefaultEditor))
+    EXE(CurrentEditAction, ScpExplorer->ExecuteFile(osCurrent, efDefaultEditor, NULL, true, false))
     EXE(CurrentEditAlternativeAction, CreateEditorListMenu(CurrentEditAlternativeAction))
     EXE(CurrentOpenAction, ScpExplorer->ExecuteCurrentFile())
-    EXE(AddEditLinkAction, ScpExplorer->AddEditLink())
+    EXE(AddEditLinkAction, ScpExplorer->AddEditLink(false))
+    EXE(NewLinkAction, ScpExplorer->AddEditLink(true))
     EXE(CurrentRenameAction, ScpExplorer->ExecuteFileOperation(foRename, osCurrent, false))
     EXE(CurrentDeleteAction, ScpExplorer->ExecuteFileOperation(foDelete, osCurrent, false))
     EXE(CurrentPropertiesAction, ScpExplorer->ExecuteFileOperation(foSetProperties, osCurrent, false))
@@ -438,6 +460,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
     EXE(FileListFromClipboardAction, ScpExplorer->FileListFromClipboard())
     // directory
     EXE(CurrentCreateDirAction, ScpExplorer->CreateDirectory(osCurrent))
+    EXE(NewDirAction, ScpExplorer->CreateDirectory(osCurrent))
     //selection
     EXE(SelectOneAction, DirView(osCurrent)->SelectCurrentItem(DirView(osCurrent)->NortonLike))
     EXE(SelectAction, DirView(osCurrent)->DoSelectByMask(true))
@@ -503,6 +526,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
     EXECOMP(ExplorerSortBand)
     EXECOMP(ExplorerUpdatesBand)
     EXECOMP(ExplorerTransferBand)
+    EXECOMP(ExplorerCustomCommandsBand)
     EXECOMP(CommanderMenuBand)
     EXECOMP(CommanderSessionBand)
     EXECOMP(CommanderPreferencesBand)
@@ -512,6 +536,8 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
     EXECOMP(CommanderCommandsBand)
     EXECOMP(CommanderUpdatesBand)
     EXECOMP(CommanderTransferBand)
+    EXECOMP(CommanderUploadDownloadBand)
+    EXECOMP(CommanderCustomCommandsBand)
     EXECOMP(CommanderLocalHistoryBand)
     EXECOMP(CommanderLocalNavigationBand)
     EXECOMP(CommanderRemoteHistoryBand)
@@ -528,6 +554,10 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
     EXE(PreferencesAction, PreferencesDialog(pmDefault) )
     EXE(PresetsPreferencesAction, PreferencesDialog(pmPresets) )
     EXE(LockToolbarsAction, WinConfiguration->LockToolbars = !WinConfiguration->LockToolbars)
+    EXECOMP(CustomCommandsBand)
+    EXE(ColorMenuAction, );
+    EXE(ColorDefaultAction, ScpExplorer->SessionColor = (TColor)0);
+    EXE(ColorPickAction, ScpExplorer->SessionColorPick());
 
     #define COLVIEWPROPS ((TCustomDirViewColProperties*)(((TCustomDirView*)(((TListColumns*)(ListColumn->Collection))->Owner()))->ColProperties))
     // SORT
@@ -597,9 +627,9 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
     EXE(PuttyAction, TTerminalManager::Instance()->OpenInPutty())
     EXE(SynchronizeBrowsingAction, )
     EXE(CloseApplicationAction, ScpExplorer->Close())
-    EXE(FileSystemInfoAction, DoFileSystemInfoDialog(ScpExplorer->Terminal))
+    EXE(FileSystemInfoAction, ScpExplorer->FileSystemInfo())
     EXE(ClearCachesAction, ScpExplorer->Terminal->ClearCaches())
-    EXE(EditNewAction, ScpExplorer->EditNew(osCurrent))
+    EXE(NewFileAction, ScpExplorer->EditNew(osCurrent))
     EXE(EditorListCustomizeAction, PreferencesDialog(pmEditor))
 
     // CUSTOM COMMANDS
@@ -635,6 +665,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
     QUEUEACTION(HideWhenEmpty)
     QUEUEACTION(Hide)
     #undef QUEUEACTION
+    EXE(QueueDisconnectOnceEmptyAction, )
     EXECOMP(QueueToolbar);
     ;
   }
@@ -666,10 +697,12 @@ void __fastcall TNonVisualDataModule::ExplorerShortcuts()
 {
   // Directory
   CurrentCreateDirAction->ShortCut = ShortCut('D', CTRL);
+  NewDirAction->ShortCut = CurrentCreateDirAction->ShortCut;
   // File operation
   CurrentRenameAction->ShortCut = ShortCut(VK_F2, NONE);
   CurrentEditAction->ShortCut = ShortCut('E', CTRL);
   AddEditLinkAction->ShortCut = ShortCut('L', CTRLALT);
+  NewLinkAction->ShortCut = AddEditLinkAction->ShortCut;
   // Focused operation
   CurrentCopyFocusedAction->ShortCut = ShortCut('C', CTRL);
   CurrentMoveFocusedAction->ShortCut = ShortCut('M', CTRL);
@@ -694,7 +727,7 @@ void __fastcall TNonVisualDataModule::ExplorerShortcuts()
   ClearSelectionAction->ShortCut = ShortCut('L', CTRL);
   RestoreSelectionAction->ShortCut = ShortCut('R', CTRLALT);
   // commands
-  EditNewAction->ShortCut = ShortCut('E', CTRLSHIFT);
+  NewFileAction->ShortCut = ShortCut('E', CTRLSHIFT);
 
   CloseApplicationAction->ShortCut = ShortCut(VK_F4, ALT);
 }
@@ -703,10 +736,12 @@ void __fastcall TNonVisualDataModule::CommanderShortcuts()
 {
   // Directory
   CurrentCreateDirAction->ShortCut = ShortCut(VK_F7, NONE);
+  NewDirAction->ShortCut = CurrentCreateDirAction->ShortCut;
   // File operation
   CurrentRenameAction->ShortCut = ShortCut(VK_F2, NONE);
   CurrentEditAction->ShortCut = ShortCut(VK_F4, NONE);
   AddEditLinkAction->ShortCut = ShortCut(VK_F6, ALT);
+  NewLinkAction->ShortCut = AddEditLinkAction->ShortCut;
   // Focused operation
   CurrentCopyFocusedAction->ShortCut = ShortCut(VK_F5, NONE);
   CurrentMoveFocusedAction->ShortCut = ShortCut(VK_F6, NONE);
@@ -742,9 +777,9 @@ void __fastcall TNonVisualDataModule::CommanderShortcuts()
   ClearSelectionAction->ShortCut = ShortCut('L', CTRL);
   RestoreSelectionAction->ShortCut = ShortCut('R', CTRLALT);
   // commands
-  EditNewAction->ShortCut = ShortCut(VK_F4, SHIFT);
+  NewFileAction->ShortCut = ShortCut(VK_F4, SHIFT);
   // legacy shortcut (can be removed when necessary)
-  EditNewAction->SecondaryShortCuts->Add(ShortCutToText(ShortCut(VK_F4, CTRLSHIFT)));
+  NewFileAction->SecondaryShortCuts->Add(ShortCutToText(ShortCut(VK_F4, CTRLSHIFT)));
 
   CloseApplicationAction->ShortCut = ShortCut(VK_F10, NONE);
 }
@@ -781,46 +816,64 @@ void __fastcall TNonVisualDataModule::DoIdle()
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TNonVisualDataModule::CreateCustomCommandsMenu(TAction * Action)
+void __fastcall TNonVisualDataModule::CreateCustomCommandsMenu(
+  TTBCustomItem * Menu, bool OnFocused, bool Toolbar)
 {
-  assert(Action);
-  TTBCustomItem * Menu = dynamic_cast<TTBCustomItem *>(Action->ActionComponent);
-  if (Menu)
+  for (int Index = 0; Index < WinConfiguration->CustomCommands->Count; Index++)
   {
-    int PrevCount = Menu->Count;
-    bool OnFocused = (Menu == RemoteDirViewCustomCommandsMenu);
-    for (int Index = 0; Index < WinConfiguration->CustomCommands->Count; Index++)
-    {
-      AnsiString Description = WinConfiguration->CustomCommands->Names[Index];
-      AnsiString Command = WinConfiguration->CustomCommands->Values[Description];
-      int State = ScpExplorer->CustomCommandState(Description, OnFocused);
+    AnsiString Description = WinConfiguration->CustomCommands->Names[Index];
+    int State = ScpExplorer->CustomCommandState(Description, OnFocused);
 
-      if (State >= 0)
+    if (State >= 0)
+    {
+      TTBCustomItem * Item = new TTBXItem(Owner);
+      Item->Caption = Description;
+      if (Toolbar)
       {
-        TTBCustomItem * Item = new TTBXItem(Menu);
-        Item->Caption = Description;
-        Item->Tag = Index;
-        Item->Enabled = (State > 0);
-        if (OnFocused)
-        {
-          Item->Tag = Item->Tag | 0x0100;
-        }
-        Item->Hint = FMTLOAD(CUSTOM_COMMAND_HINT, (StripHotkey(Description)));
-        Item->OnClick = CustomCommandClick;
-        Menu->Add(Item);
+        Item->Caption = StripHotkey(Item->Caption);
       }
+      Item->Tag = Index;
+      Item->Enabled = (State > 0);
+      if (OnFocused)
+      {
+        Item->Tag = Item->Tag | 0x0100;
+      }
+      Item->Hint = FMTLOAD(CUSTOM_COMMAND_HINT, (StripHotkey(Description)));
+      Item->OnClick = CustomCommandClick;
+
+      Menu->Add(Item);
     }
+  }
 
-    TTBCustomItem * Item;
-    Item = new TTBXItem(Menu);
-    Item->Action = CustomCommandsEnterAction;
-    Menu->Add(Item);
+  TTBCustomItem * Item;
+  Item = new TTBXItem(Menu);
+  Item->Action = CustomCommandsEnterAction;
+  Menu->Add(Item);
 
-    AddMenuSeparator(Menu);
+  AddMenuSeparator(Menu);
 
+  if (!Toolbar)
+  {
     Item = new TTBXItem(Menu);
-    Item->Action = CustomCommandsCustomizeAction;
+    Item->Action = CustomCommandsBandAction;
     Menu->Add(Item);
+  }
+
+  Item = new TTBXItem(Menu);
+  Item->Action = CustomCommandsCustomizeAction;
+  Menu->Add(Item);
+}
+//---------------------------------------------------------------------------
+void __fastcall TNonVisualDataModule::CreateCustomCommandsMenu(TAction * Action)
+{
+  assert(Action);
+  TTBCustomItem * Menu = dynamic_cast<TTBCustomItem *>(Action->ActionComponent);
+  if (Menu)
+  {
+    int PrevCount = Menu->Count;
+    bool OnFocused = (Menu == RemoteDirViewCustomCommandsMenu);
+
+    CreateCustomCommandsMenu(Menu, OnFocused, false);
 
     for (int Index = 0; Index < PrevCount; Index++)
     {
@@ -829,6 +882,58 @@ void __fastcall TNonVisualDataModule::CreateCustomCommandsMenu(TAction * Action)
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TNonVisualDataModule::UpdateCustomCommandsToolbar(TTBXToolbar * Toolbar)
+{
+  // can be called while explorer is being created
+  if (ScpExplorer == NULL)
+  {
+    return;
+  }
+
+  int AdditionalCommands = 3;
+  TCustomCommands * CustomCommands = WinConfiguration->CustomCommands;
+  bool Changed = (CustomCommands->Count != (Toolbar->Items->Count - AdditionalCommands));
+  if (!Changed)
+  {
+    int Index = 0;
+    while (!Changed && (Index < CustomCommands->Count))
+    {
+      Changed =
+        (Toolbar->Items->Items[Index]->Caption !=
+          StripHotkey(CustomCommands->Names[Index]));
+      Index++;
+    }
+  }
+
+  if (Changed)
+  {
+    Toolbar->BeginUpdate();
+    try
+    {
+      Toolbar->Items->Clear();
+      CreateCustomCommandsMenu(Toolbar->Items, false, true);
+      assert(CustomCommands->Count == (Toolbar->Items->Count - AdditionalCommands));
+    }
+    __finally
+    {
+      Toolbar->EndUpdate();
+    }
+  }
+  else
+  {
+    for (int Index = 0; Index < Toolbar->Items->Count - AdditionalCommands; Index++)
+    {
+      TTBCustomItem * Item = Toolbar->Items->Items[Index];
+      int CommandIndex = (Item->Tag & 0x00FF);
+      assert(CommandIndex == Index);
+      AnsiString Description = WinConfiguration->CustomCommands->Names[CommandIndex];
+      int State = ScpExplorer->CustomCommandState(Description, false);
+      assert(State >= 0);
+      Item->Enabled = (State > 0);
+    }
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TNonVisualDataModule::CustomCommandClick(TObject * Sender)
 {
   TTBCustomItem * Item = dynamic_cast<TTBCustomItem *>(Sender);
@@ -984,7 +1089,7 @@ void __fastcall TNonVisualDataModule::EditorItemClick(TObject * Sender)
   int Tag = dynamic_cast<TTBXItem*>(Sender)->Tag;
   if (Tag < 0)
   {
-    ScpExplorer->ExecuteFile(osCurrent, efInternalEditor);
+    ScpExplorer->ExecuteFile(osCurrent, efInternalEditor, NULL, true, false);
   }
   else
   {
@@ -992,7 +1097,8 @@ void __fastcall TNonVisualDataModule::EditorItemClick(TObject * Sender)
     // sanity check
     if (Tag < EditorList->Count)
     {
-      ScpExplorer->ExecuteFile(osCurrent, efExternalEditor, EditorList->Editors[Tag]);
+      ScpExplorer->ExecuteFile(osCurrent, efExternalEditor, EditorList->Editors[Tag],
+        true, false);
     }
   }
 }

+ 133 - 9
forms/NonVisual.dfm

@@ -67,7 +67,7 @@ object NonVisualDataModule: TNonVisualDataModule
       Action = CurrentOpenAction
     end
     object CurrentEditMenuItem: TTBXItem
-      Action = CurrentEditAction
+      Action = CurrentEditFocusedAction
     end
     object CurrentCopyMenuItem: TTBXItem
       Action = CurrentCopyFocusedAction
@@ -238,7 +238,7 @@ object NonVisualDataModule: TNonVisualDataModule
       Category = 'Toolbar Operation (selected + rename + mkdir + close)'
       Caption = '&Edit'
       HelpKeyword = 'task_edit'
-      Hint = 'Edit|Edit selected file'
+      Hint = 'Edit|Edit selected file(s)'
       ImageIndex = 57
     end
     object HideColumnAction: TAction
@@ -558,6 +558,13 @@ object NonVisualDataModule: TNonVisualDataModule
       HelpKeyword = 'ui_toolbars'
       Hint = 'Hide/show transfer settings toolbar'
     end
+    object ExplorerCustomCommandsBandAction: TAction
+      Tag = 7
+      Category = 'View'
+      Caption = 'Custom Co&mmand Buttons'
+      HelpKeyword = 'ui_toolbars'
+      Hint = 'Hide/show custom commands toolbar'
+    end
     object ViewLogAction: TAction
       Tag = 15
       Category = 'View'
@@ -738,6 +745,20 @@ object NonVisualDataModule: TNonVisualDataModule
       HelpKeyword = 'ui_toolbars'
       Hint = 'Hide/show commands toolbar'
     end
+    object CommanderUploadDownloadBandAction: TAction
+      Tag = 11
+      Category = 'View'
+      Caption = 'Upload/&Download Buttons'
+      HelpKeyword = 'ui_toolbars'
+      Hint = 'Hide/show upload/download toolbar'
+    end
+    object CommanderCustomCommandsBandAction: TAction
+      Tag = 11
+      Category = 'View'
+      Caption = 'Custom Co&mmand Buttons'
+      HelpKeyword = 'ui_toolbars'
+      Hint = 'Hide/show custom commands toolbar'
+    end
     object CommanderLocalHistoryBandAction: TAction
       Tag = 11
       Category = 'View'
@@ -1245,7 +1266,9 @@ object NonVisualDataModule: TNonVisualDataModule
       Category = 'Focused Operation'
       Caption = 'Ed&it (alternative)'
       HelpKeyword = 'task_edit'
-      Hint = 'Edit (alternative)|Edit selected file using alternative editor'
+      Hint = 
+        'Edit (alternative)|Edit selected file(s) using alternative edito' +
+        'r'
     end
     object CurrentOpenAction: TAction
       Tag = 15
@@ -1272,7 +1295,7 @@ object NonVisualDataModule: TNonVisualDataModule
     object AddEditLinkAction: TAction
       Tag = 15
       Category = 'Command'
-      Caption = 'Add/Edit &Link...'
+      Caption = 'Edit &Link...'
       HelpKeyword = 'task_link'
       Hint = 
         'Add/edit link|Add new link/shortcut or edit selected link/shortc' +
@@ -1296,6 +1319,14 @@ object NonVisualDataModule: TNonVisualDataModule
       Hint = 'Select session|Select opened session to activate'
       ImageIndex = 62
     end
+    object NewLinkAction: TAction
+      Tag = 12
+      Category = 'Command'
+      Caption = '&Link...'
+      HelpKeyword = 'task_link'
+      Hint = 'Create link|Create new link/shortcut'
+      ImageIndex = 60
+    end
     object CustomCommandsAction: TAction
       Tag = 14
       Category = 'Command'
@@ -1317,6 +1348,7 @@ object NonVisualDataModule: TNonVisualDataModule
       Caption = '&Enter...'
       HelpKeyword = 'remote_command#executing_and_configuring_custom_commands'
       Hint = 'Enter ad hoc custom command'
+      ImageIndex = 90
     end
     object CheckForUpdatesAction: TAction
       Tag = 15
@@ -1485,12 +1517,12 @@ object NonVisualDataModule: TNonVisualDataModule
       ImageIndex = 75
       ShortCut = 16470
     end
-    object EditNewAction: TAction
+    object NewFileAction: TAction
       Tag = 15
       Category = 'Command'
-      Caption = 'Edit &New File...'
+      Caption = '&File...'
       HelpKeyword = 'task_edit'
-      Hint = 'Edit new file|Create new file and open it in editor'
+      Hint = 'Create file|Create new file and open it in editor'
       ImageIndex = 77
     end
     object EditorListCustomizeAction: TAction
@@ -1540,6 +1572,22 @@ object NonVisualDataModule: TNonVisualDataModule
       Caption = '&Transfer Files in Clipboard'
       Hint = 'Transfer files whose names are in clipboard'
     end
+    object RemoteCopyAction: TAction
+      Tag = 15
+      Category = 'Selected Operation'
+      Caption = '&Download...'
+      HelpKeyword = 'task_download'
+      Hint = 'Download|Download selected file(s)'
+      ImageIndex = 89
+    end
+    object LocalCopyAction: TAction
+      Tag = 15
+      Category = 'Selected Operation'
+      Caption = '&Upload...'
+      HelpKeyword = 'task_upload'
+      Hint = 'Upload|Upload selected file(s)'
+      ImageIndex = 88
+    end
     object DownloadPageAction: TAction
       Tag = 15
       Category = 'Help'
@@ -1580,6 +1628,34 @@ object NonVisualDataModule: TNonVisualDataModule
       HelpKeyword = 'ui_toolbars'
       Hint = 'Prevents moving and (un)docking of all toolbars'
     end
+    object CustomCommandsBandAction: TAction
+      Tag = 15
+      Category = 'View'
+      Caption = 'Custom Co&mmand Buttons'
+      HelpKeyword = 'ui_toolbars'
+      Hint = 'Hide/show custom commands toolbar'
+    end
+    object ColorMenuAction: TAction
+      Tag = 15
+      Category = 'View'
+      Caption = 'C&olor'
+      HelpKeyword = 'task_connections#session_color'
+      Hint = 'Change color of current session'
+    end
+    object ColorDefaultAction: TAction
+      Tag = 15
+      Category = 'View'
+      Caption = '&Default'
+      HelpKeyword = 'task_connections#session_color'
+      Hint = 'Reset session (panel) color to system default'
+    end
+    object ColorPickAction: TAction
+      Tag = 15
+      Category = 'View'
+      Caption = '&More Colors...'
+      HelpKeyword = 'task_connections#session_color'
+      Hint = 'Choose any session (panel) color'
+    end
     object QueueItemPauseAction: TAction
       Tag = 12
       Category = 'Queue'
@@ -1612,6 +1688,15 @@ object NonVisualDataModule: TNonVisualDataModule
       Hint = 'Resume all suspended queue items'
       ImageIndex = 85
     end
+    object QueueDisconnectOnceEmptyAction: TAction
+      Tag = 12
+      Category = 'Queue'
+      AutoCheck = True
+      Caption = '&Disconnect Once Empty'
+      HelpKeyword = 'ui_queue'
+      Hint = 'Disconnect the session once the queue is empty'
+      ImageIndex = 87
+    end
     object RestoreSelectionAction: TAction
       Tag = 15
       Category = 'Selection'
@@ -1620,6 +1705,22 @@ object NonVisualDataModule: TNonVisualDataModule
       Hint = 'Restore previous selection'
       ImageIndex = 86
     end
+    object CurrentEditFocusedAction: TAction
+      Tag = 15
+      Category = 'Focused Operation'
+      Caption = '&Edit'
+      HelpKeyword = 'task_edit'
+      Hint = 'Edit|Edit selected file(s)'
+      ImageIndex = 57
+    end
+    object NewDirAction: TAction
+      Tag = 12
+      Category = 'Command'
+      Caption = '&Directory...'
+      HelpKeyword = 'task_create_directory'
+      Hint = 'Create directory|Create new directory'
+      ImageIndex = 5
+    end
   end
   object ExplorerBarPopup: TTBXPopupMenu
     Images = GlyphsModule.ExplorerImages
@@ -1649,6 +1750,9 @@ object NonVisualDataModule: TNonVisualDataModule
     object TBXItem4: TTBXItem
       Action = ExplorerTransferBandAction
     end
+    object TBXItem16: TTBXItem
+      Action = ExplorerCustomCommandsBandAction
+    end
     object TBXItem7: TTBXItem
       Action = LockToolbarsAction
     end
@@ -1729,6 +1833,12 @@ object NonVisualDataModule: TNonVisualDataModule
     object TBXItem5: TTBXItem
       Action = CommanderTransferBandAction
     end
+    object TBXItem14: TTBXItem
+      Action = CommanderUploadDownloadBandAction
+    end
+    object TBXItem15: TTBXItem
+      Action = CommanderCustomCommandsBandAction
+    end
     object TBXItem6: TTBXItem
       Action = LockToolbarsAction
     end
@@ -2055,6 +2165,9 @@ object NonVisualDataModule: TNonVisualDataModule
       object N65: TTBXSeparatorItem
         Hint = 'E'
       end
+      object TBXItem13: TTBXItem
+        Action = QueueDisconnectOnceEmptyAction
+      end
       object Customize3: TTBXItem
         Action = QueuePreferencesAction
       end
@@ -2105,8 +2218,19 @@ object NonVisualDataModule: TNonVisualDataModule
     object N79: TTBXSeparatorItem
       Hint = 'E'
     end
-    object CreateDirectory3: TTBXItem
-      Action = CurrentCreateDirAction
+    object TBXSubmenuItem26: TTBXSubmenuItem
+      Caption = '&New'
+      HelpKeyword = 'task_index'
+      Hint = 'Create object|Create new object'
+      object TBXItem135: TTBXItem
+        Action = NewFileAction
+      end
+      object TBXItem136: TTBXItem
+        Action = NewDirAction
+      end
+      object TBXItem209: TTBXItem
+        Action = NewLinkAction
+      end
     end
   end
   object LocalDirViewPopup: TTBXPopupMenu

+ 54 - 24
forms/NonVisual.h

@@ -29,31 +29,37 @@
 #define fcRemoteTree       0x1C
 #define fcTransferCombo    0x1D
 #define fcSessionToolbar   0x1E
+#define fcCustomCommandsBand 0x1F
+#define fcColorMenu        0x20
+#define fcColorPalette     0x21
 
-#define fcExplorerMenuBand        0x21
-#define fcExplorerAddressBand     0x22
-#define fcExplorerToolbarBand     0x23
-#define fcExplorerSelectionBand   0x24
-#define fcExplorerSessionBand     0x25
-#define fcExplorerPreferencesBand 0x26
-#define fcExplorerSortBand        0x27
-#define fcExplorerUpdatesBand     0x28
-#define fcExplorerTransferBand    0x29
+#define fcExplorerMenuBand        0x31
+#define fcExplorerAddressBand     0x32
+#define fcExplorerToolbarBand     0x33
+#define fcExplorerSelectionBand   0x34
+#define fcExplorerSessionBand     0x35
+#define fcExplorerPreferencesBand 0x36
+#define fcExplorerSortBand        0x37
+#define fcExplorerUpdatesBand     0x38
+#define fcExplorerTransferBand    0x39
+#define fcExplorerCustomCommandsBand 0x40
 
-#define fcCommanderMenuBand             0x31
-#define fcCommanderSessionBand          0x32
-#define fcCommanderPreferencesBand      0x33
-#define fcCommanderSelectionBand        0x34
-#define fcCommanderToolbarBand          0x35
-#define fcCommanderSortBand             0x36
-#define fcCommanderCommandsBand         0x37
-#define fcCommanderUpdatesBand          0x38
-#define fcCommanderTransferBand         0x39
+#define fcCommanderMenuBand             0x51
+#define fcCommanderSessionBand          0x52
+#define fcCommanderPreferencesBand      0x53
+#define fcCommanderSelectionBand        0x54
+#define fcCommanderToolbarBand          0x55
+#define fcCommanderSortBand             0x56
+#define fcCommanderCommandsBand         0x57
+#define fcCommanderUpdatesBand          0x58
+#define fcCommanderTransferBand         0x59
+#define fcCommanderUploadDownloadBand   0x60
+#define fcCommanderCustomCommandsBand   0x61
 
-#define fcCommanderLocalHistoryBand     0x41
-#define fcCommanderLocalNavigationBand  0x42
-#define fcCommanderRemoteHistoryBand    0x43
-#define fcCommanderRemoteNavigationBand 0x44
+#define fcCommanderLocalHistoryBand     0x71
+#define fcCommanderLocalNavigationBand  0x72
+#define fcCommanderRemoteHistoryBand    0x73
+#define fcCommanderRemoteNavigationBand 0x74
 //---------------------------------------------------------------------------
 class TNonVisualDataModule : public TDataModule
 {
@@ -228,7 +234,7 @@ __published:    // IDE-managed Components
   TAction *RemoteTreeAction;
   TAction *LocalTreeAction;
   TAction *GoToTreeAction;
-  TAction *EditNewAction;
+  TAction *NewFileAction;
   TAction *RemoteCopyToFocusedAction;
   TAction *RemoteCopyToAction;
   TAction *UrlToClipboardAction;
@@ -319,7 +325,6 @@ __published:    // IDE-managed Components
   TTBXItem *AddToBookmarks4;
   TTBXItem *CopyPathtoClipboard6;
   TTBXSeparatorItem *N79;
-  TTBXItem *CreateDirectory3;
   TTBXPopupMenu *LocalDirViewPopup;
   TTBXSubmenuItem *GoTo5;
   TTBXItem *OpenDirectoryBookmark4;
@@ -433,6 +438,27 @@ __published:    // IDE-managed Components
   TTBXItem *TBXItem12;
   TAction *EditorListCustomizeAction;
   TAction *RestoreSelectionAction;
+  TAction *CurrentEditFocusedAction;
+  TAction *NewLinkAction;
+  TAction *NewDirAction;
+  TTBXSubmenuItem *TBXSubmenuItem26;
+  TTBXItem *TBXItem135;
+  TTBXItem *TBXItem136;
+  TTBXItem *TBXItem209;
+  TAction *QueueDisconnectOnceEmptyAction;
+  TTBXItem *TBXItem13;
+  TAction *LocalCopyAction;
+  TAction *RemoteCopyAction;
+  TAction *CommanderUploadDownloadBandAction;
+  TTBXItem *TBXItem14;
+  TAction *ExplorerCustomCommandsBandAction;
+  TAction *CommanderCustomCommandsBandAction;
+  TTBXItem *TBXItem15;
+  TTBXItem *TBXItem16;
+  TAction *CustomCommandsBandAction;
+  TAction *ColorPickAction;
+  TAction *ColorDefaultAction;
+  TAction *ColorMenuAction;
   void __fastcall LogActionsUpdate(TBasicAction *Action, bool &Handled);
   void __fastcall LogActionsExecute(TBasicAction *Action, bool &Handled);
   void __fastcall ExplorerActionsUpdate(TBasicAction *Action, bool &Handled);
@@ -449,6 +475,8 @@ private:
 protected:
   void __fastcall CreateSessionListMenu(TAction * Action);
   void __fastcall CreateCustomCommandsMenu(TAction * Action);
+  void __fastcall CreateCustomCommandsMenu(TTBCustomItem * Menu, bool OnFocused,
+    bool Toolbar);
   void __fastcall CreateOpenedSessionListMenu(TAction * Action);
   TCustomDirView * __fastcall DirView(TOperationSide Side) { return ScpExplorer->DirView(Side); }
   void __fastcall SessionItemClick(TObject * Sender);
@@ -459,6 +487,7 @@ protected:
   void __fastcall DoIdle();
   inline void __fastcall ShowUpdatesUpdate();
   void __fastcall PreferencesDialog(TPreferencesMode APreferencesMode);
+
 public:
   __fastcall TNonVisualDataModule(TComponent * Owner);
   virtual __fastcall ~TNonVisualDataModule();
@@ -467,6 +496,7 @@ public:
   void __fastcall ExplorerShortcuts();
   TShortCut __fastcall OpenSessionShortCut(int Index);
   void __fastcall UpdateNonVisibleActions();
+  void __fastcall UpdateCustomCommandsToolbar(TTBXToolbar * Toolbar);
 
   __property TListColumn * ListColumn = { read = FListColumn, write = FListColumn };
   __property TCustomScpExplorerForm * ScpExplorer = { read = FScpExplorer, write = SetScpExplorer };

+ 1 - 39
forms/OperationStatus.cpp

@@ -6,62 +6,24 @@
 
 #include "OperationStatus.h"
 
-#include <TextsWin.h>
-
 #include <VCLCommon.h>
 //---------------------------------------------------------------------------
-const int ConnectionStatusStrings[] =
-  { STATUS_CLOSED, STATUS_INITWINSOCK, STATUS_LOOKUPHOST, STATUS_CONNECT,
-    STATUS_AUTHENTICATE, STATUS_AUTHENTICATED, STATUS_STARTUP,
-    STATUS_OPEN_DIRECTORY, STATUS_READY };
-#define ConnectionStatusStringsCount (sizeof(ConnectionStatusStrings) / sizeof(int))
-//---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------------
 __fastcall TOperationStatusForm::TOperationStatusForm(TComponent* Owner)
         : TForm(Owner)
 {
-  FSecureShell = NULL;
   UseSystemSettings(this);
   FShowAsModalStorage = NULL;
+  StatusLabel->Caption = "";
 }
 //---------------------------------------------------------------------------
 __fastcall TOperationStatusForm::~TOperationStatusForm()
 {
-  SecureShell = NULL;
-
   ReleaseAsModal(this, FShowAsModalStorage);
 }
 //---------------------------------------------------------------------------
-void __fastcall TOperationStatusForm::SecureShellUpdateStatus(TObject * /*Sender*/)
-{
-  assert(FSecureShell && (FSecureShell->Status >= 0) &&
-    (FSecureShell->Status < ConnectionStatusStringsCount) && Application);
-  Status = LoadStr((int)ConnectionStatusStrings[FSecureShell->Status]);
-}
-//---------------------------------------------------------------------------
-void __fastcall TOperationStatusForm::SetSecureShell(TSecureShell * value)
-{
-  if (SecureShell != value)
-  {
-    if (SecureShell)
-    {
-      if (SecureShell->OnUpdateStatus == SecureShellUpdateStatus)
-      {
-        SecureShell->OnUpdateStatus = FPrevOnUpdateStatus;
-      }
-    }
-    FSecureShell = value;
-    if (SecureShell)
-    {
-      FPrevOnUpdateStatus = SecureShell->OnUpdateStatus;
-      SecureShell->OnUpdateStatus = SecureShellUpdateStatus;
-      SecureShellUpdateStatus(SecureShell);
-    }
-  }
-}
-//---------------------------------------------------------------------------
 void __fastcall TOperationStatusForm::SetStatus(const AnsiString value)
 {
   if (StatusLabel->Caption != value)

+ 0 - 7
forms/OperationStatus.h

@@ -7,8 +7,6 @@
 #include <StdCtrls.hpp>
 #include <Forms.hpp>
 #include <ExtCtrls.hpp>
-
-#include <SecureShell.h>
 //---------------------------------------------------------------------------
 class TOperationStatusForm : public TForm
 {
@@ -16,11 +14,8 @@ __published:
   TLabel *StatusLabel;
   TBevel *Bevel1;
 private:
-  TSecureShell * FSecureShell;
   void * FShowAsModalStorage;
-  TNotifyEvent FPrevOnUpdateStatus;
 
-  void __fastcall SetSecureShell(TSecureShell * value);
   void __fastcall SetStatus(const AnsiString value);
   AnsiString __fastcall GetStatus();
 public:
@@ -29,8 +24,6 @@ public:
   void __fastcall HideAsModal();
   void __fastcall ShowAsModal();
   
-  void __fastcall SecureShellUpdateStatus(TObject * Sender);
-  __property TSecureShell * SecureShell = { read = FSecureShell, write = SetSecureShell };
   __property AnsiString Status = { read = GetStatus, write = SetStatus };
 };
 //---------------------------------------------------------------------------

+ 0 - 148
forms/Password.cpp

@@ -1,148 +0,0 @@
-//---------------------------------------------------------------------
-#include <vcl.h>
-#pragma hdrstop
-
-#include <Common.h>
-#include <VCLCommon.h>
-#include <TextsWin.h>
-
-#include "WinInterface.h"
-#include "Password.h"
-//---------------------------------------------------------------------
-#pragma link "PasswordEdit"
-#pragma resource "*.dfm"
-//---------------------------------------------------------------------
-bool __fastcall DoPasswordDialog(const AnsiString Caption,
-  TPromptKind Kind, AnsiString &Password)
-{
-  bool Result = false;
-  TPasswordDialog * PasswordDialog = new TPasswordDialog(Application);
-  try
-  {
-    PasswordDialog->PasswordCaption = Caption;
-    PasswordDialog->Password = "";
-    PasswordDialog->Kind = Kind;
-    Result = (bool)(PasswordDialog->ShowModal() == mrOk);
-
-    if (Result)
-    {
-      Password = PasswordDialog->Password;
-    }
-  }
-  __finally
-  {
-    delete PasswordDialog;
-  }
-  return Result;
-}
-//---------------------------------------------------------------------
-__fastcall TPasswordDialog::TPasswordDialog(TComponent* AOwner)
-    : TForm(AOwner)
-{
-  UseSystemSettings(this);
-  Kind = pkPassword;
-}
-//---------------------------------------------------------------------
-__fastcall TPasswordDialog::~TPasswordDialog()
-{
-}
-//---------------------------------------------------------------------
-void __fastcall TPasswordDialog::SetPasswordCaption(const AnsiString value)
-{
-  AnsiString Caption = value;
-  bool MultiLine = false;
-  int P = Caption.Pos("\n");
-  if (P > 0)
-  {
-    MultiLine = true;
-    Caption.SetLength(P - 1);
-  }
-  P = Caption.Pos("\r");
-  if (P > 0)
-  {
-    MultiLine = true;
-    Caption.SetLength(P - 1);
-  }
-
-  bool NeedTrim;
-  TControlCanvas * PasswordLabelCanvas = new TControlCanvas();
-  try
-  {
-    PasswordLabelCanvas->Control = PasswordLabel;
-
-    NeedTrim = MultiLine ||
-      (PasswordLabelCanvas->TextWidth(Caption) > PasswordLabel->Width);
-    if (NeedTrim)
-    {
-      static AnsiString Ellipsis(" ...");
-      while (PasswordLabelCanvas->TextWidth(Caption + Ellipsis) >
-          PasswordLabel->Width)
-      {
-        Caption.SetLength(Caption.Length() - 1);
-      }
-      Caption = Caption + Ellipsis;
-    }
-  }
-  __finally
-  {
-    delete PasswordLabelCanvas;
-  }
-
-  PasswordLabel->Caption = Caption;
-  if (NeedTrim)
-  {
-    HintLabel(PasswordLabel, value);
-    PasswordLabel->TabStop = true;
-  }
-  else
-  {
-    // just to make GetPasswordCaption(), i.e. useless
-    PasswordLabel->Hint = value;
-  }
-}
-//---------------------------------------------------------------------
-AnsiString __fastcall TPasswordDialog::GetPasswordCaption()
-{
-  return PasswordLabel->Hint;
-}
-//---------------------------------------------------------------------
-void __fastcall TPasswordDialog::SetPassword(const AnsiString value)
-{
-  PasswordEdit->Text = value;
-}
-//---------------------------------------------------------------------
-AnsiString __fastcall TPasswordDialog::GetPassword()
-{
-  return PasswordEdit->Text;
-}
-//---------------------------------------------------------------------
-void __fastcall TPasswordDialog::SetKind(TPromptKind value)
-{
-  FKind = value;
-  int Title;
-  switch (Kind) {
-    case pkPassword: Title = PASSWORD_TITLE; break;
-    case pkPassphrase: Title = PASSPHRASE_TITLE; break;
-    case pkServerPrompt: Title = SERVER_PASSWORD_TITLE; break;
-    default: assert(false);
-  }
-  Caption = LoadStr(Title);
-
-  bool ShowServerPanel = (Kind == pkServerPrompt);
-  if (ShowServerPanel != ServerPromptPanel->Visible)
-  {
-    ServerPromptPanel->Visible = ShowServerPanel;
-    ClientHeight += (ShowServerPanel ? 1 : -1) * ServerPromptPanel->Height;
-  }
-}
-//---------------------------------------------------------------------------
-void __fastcall TPasswordDialog::HideTypingCheckClick(TObject * /*Sender*/)
-{
-  PasswordEdit->Password = HideTypingCheck->Checked;
-}
-//---------------------------------------------------------------------------
-void __fastcall TPasswordDialog::HelpButtonClick(TObject * /*Sender*/)
-{
-  FormHelp(this);
-}
-//---------------------------------------------------------------------------

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