Martin Prikryl 17 years ago
parent
commit
26c05f9b33
100 changed files with 4768 additions and 3094 deletions
  1. 4 4
      Console.rc
  2. 1 2
      DScpComp.bpk
  3. 4 4
      DragExt.rc
  4. 4 4
      DragExt64.rc
  5. 17 18
      Putty.bpr
  6. 1 2
      RScpComp.bpr
  7. 3 2
      ScpCore.bpr
  8. 3 2
      ScpForms.bpf
  9. 13 12
      ScpForms.bpr
  10. 313 315
      WinSCP.drc
  11. 6 6
      WinSCP.rc
  12. 1 1
      components/UnixDirView.h
  13. 0 129
      components/UnixPathComboBox.cpp
  14. 0 74
      components/UnixPathComboBox.h
  15. 10 7
      console/Console.h
  16. 23 16
      console/Main.cpp
  17. 95 4
      core/Common.cpp
  18. 4 0
      core/Common.h
  19. 61 33
      core/Configuration.cpp
  20. 5 4
      core/Configuration.h
  21. 72 7
      core/CopyParam.cpp
  22. 4 0
      core/CopyParam.h
  23. 25 14
      core/CoreMain.cpp
  24. 18 15
      core/FileBuffer.cpp
  25. 1 0
      core/FileBuffer.h
  26. 52 6
      core/FileMasks.cpp
  27. 16 1
      core/FileMasks.h
  28. 106 14
      core/FileOperationProgress.cpp
  29. 11 7
      core/FileOperationProgress.h
  30. 5 2
      core/FileSystems.h
  31. 103 27
      core/FtpFileSystem.cpp
  32. 3 1
      core/FtpFileSystem.h
  33. 21 1
      core/Interface.h
  34. 2 0
      core/NamedObjs.h
  35. 229 0
      core/Option.cpp
  36. 54 0
      core/Option.h
  37. 118 78
      core/PuttyIntf.cpp
  38. 169 101
      core/Queue.cpp
  39. 15 6
      core/Queue.h
  40. 62 9
      core/RemoteFiles.cpp
  41. 6 2
      core/RemoteFiles.h
  42. 102 109
      core/ScpFileSystem.cpp
  43. 1 2
      core/ScpFileSystem.h
  44. 317 263
      core/Script.cpp
  45. 18 26
      core/Script.h
  46. 313 150
      core/SecureShell.cpp
  47. 10 9
      core/SecureShell.h
  48. 274 28
      core/SessionData.cpp
  49. 52 12
      core/SessionData.h
  50. 17 10
      core/SessionInfo.cpp
  51. 3 2
      core/SessionInfo.h
  52. 33 27
      core/SftpFileSystem.cpp
  53. 1 1
      core/SftpFileSystem.h
  54. 107 57
      core/Terminal.cpp
  55. 21 18
      core/Terminal.h
  56. 7 7
      dragext/DragExt64.def
  57. 14 5
      filezilla/ControlSocket.cpp
  58. 3 1
      filezilla/ControlSocket.h
  59. 1 0
      filezilla/Crypt.cpp
  60. 1 1
      filezilla/FileZillaOpt.h
  61. 334 334
      filezilla/MainThread.cpp
  62. 2 2
      filezilla/Options.h
  63. 29 5
      filezilla/stdafx.h
  64. 27 16
      forms/About.cpp
  65. 33 31
      forms/About.dfm
  66. 9 7
      forms/About.h
  67. 162 94
      forms/Authenticate.cpp
  68. 94 67
      forms/Authenticate.dfm
  69. 28 19
      forms/Authenticate.h
  70. 1 1
      forms/Cleanup.dfm
  71. 1 82
      forms/ComboInput.cpp
  72. 4 5
      forms/ComboInput.dfm
  73. 0 6
      forms/ComboInput.h
  74. 2 2
      forms/Console.dfm
  75. 58 38
      forms/Copy.cpp
  76. 64 82
      forms/Copy.dfm
  77. 12 7
      forms/Copy.h
  78. 10 10
      forms/CopyParamPreset.dfm
  79. 0 2
      forms/CopyParamPreset.h
  80. 7 5
      forms/CopyParams.dfm
  81. 1 1
      forms/CustomCommand.cpp
  82. 364 275
      forms/CustomScpExplorer.cpp
  83. 11 10
      forms/CustomScpExplorer.dfm
  84. 45 19
      forms/CustomScpExplorer.h
  85. 249 50
      forms/Editor.cpp
  86. 35 39
      forms/Editor.dfm
  87. 6 4
      forms/Editor.h
  88. 2 2
      forms/EditorPreferences.cpp
  89. 2 1
      forms/EditorPreferences.dfm
  90. 2 2
      forms/FileSystemInfo.dfm
  91. 22 3
      forms/FullSynchronize.cpp
  92. 1 1
      forms/FullSynchronize.h
  93. 95 95
      forms/Glyphs.dfm
  94. 1 1
      forms/ImportSessions.dfm
  95. 23 1
      forms/InputDlg.cpp
  96. 0 84
      forms/Licence.cpp
  97. 0 29
      forms/Licence.h
  98. 50 0
      forms/License.cpp
  99. 4 4
      forms/License.dfm
  100. 23 0
      forms/License.h

+ 4 - 4
Console.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 2,0,0,84
-PRODUCTVERSION 2,0,0,84
+FILEVERSION 2,0,0,85
+PRODUCTVERSION 2,0,0,85
 FILEOS 0x4
 FILETYPE 0x1
 {
@@ -10,13 +10,13 @@ FILETYPE 0x1
         {
             VALUE "CompanyName", "Martin Prikryl\0"
             VALUE "FileDescription", "Console interface for WinSCP\0"
-            VALUE "FileVersion", "2.0.0.84\0"
+            VALUE "FileVersion", "2.0.0.85\0"
             VALUE "InternalName", "console\0"
             VALUE "LegalCopyright", "(c) 2000-2008 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "winscp.com\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.0.7.0\0"
+            VALUE "ProductVersion", "4.1.0.0\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
     }

+ 1 - 2
DScpComp.bpk

@@ -4,7 +4,7 @@
   <MACROS>
     <VERSION value="BCB.06.00"/>
     <PROJECT value="DScpComp.bpl"/>
-    <OBJFILES value="DScpComp.obj components\UnixDirView.obj components\UnixPathComboBox.obj 
+    <OBJFILES value="DScpComp.obj components\UnixDirView.obj
       components\LogMemo.obj components\UnixDriveView.obj"/>
     <RESFILES value=""/>
     <DEFFILE value=""/>
@@ -51,7 +51,6 @@
       <FILE FILENAME="DriveDir_B5.bpi" FORMNAME="" UNITNAME="DriveDir_B5" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="DragDrop_B5.bpi" FORMNAME="" UNITNAME="DragDrop_B5" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="components\UnixDirView.cpp" FORMNAME="" UNITNAME="UnixDirView" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="components\UnixPathComboBox.cpp" FORMNAME="" UNITNAME="UnixPathComboBox" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="rtl.bpi" FORMNAME="" UNITNAME="rtl" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="vcl.bpi" FORMNAME="" UNITNAME="vcl" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="vclx.bpi" FORMNAME="" UNITNAME="vclx" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>

+ 4 - 4
DragExt.rc

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

+ 4 - 4
DragExt64.rc

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

+ 17 - 18
Putty.bpr

@@ -5,16 +5,16 @@
     <VERSION value="BCB.06.00"/>
     <PROJECT value="lib\Putty.lib"/>
     <OBJFILES value="putty\BE_NONE.obj putty\CPROXY.obj putty\INT64.obj
-      putty\LOGGING.obj putty\MISC.obj putty\PORTFWD_.obj putty\PPROXY.obj
-      putty\PROXY.obj putty\SSH_.obj putty\SSHAES.obj putty\SSHBLOWF.obj
+      putty\LOGGING.obj putty\MISC.obj putty\PORTFWD_.obj putty\PROXY.obj
+      putty\SSH_.obj putty\SSHAES.obj putty\SSHARCF.obj putty\SSHBLOWF.obj
       putty\SSHBN.obj putty\SSHCRC.obj putty\SSHCRCDA.obj putty\SSHDES.obj
-      putty\SSHDH.obj putty\SSHDSS.obj putty\SSHGSS.obj putty\SSHGSSC.obj
-      putty\SSHMD5.obj putty\SSHPUBK.obj putty\SSHRAND.obj putty\SSHRSA.obj
-      putty\SSHSH512.obj putty\SSHSHA.obj putty\SSHZLIB.obj putty\TREE234.obj
-      putty\CHARSET\UTF8.obj putty\WILDCARD.obj putty\WINDOWS\WINDL.obj
-      putty\WINDOWS\WINGSS.obj putty\WINDOWS\WINMISC.obj
-      putty\WINDOWS\WINNET.obj putty\WINDOWS\WINNOISE.obj
-      putty\WINDOWS\WINPGNTC.obj putty\WINDOWS\WINSTORE_.obj
+      putty\SSHDH.obj putty\SSHDSS.obj putty\SSHMD5.obj putty\SSHPUBK.obj
+      putty\SSHRAND.obj putty\SSHRSA.obj putty\SSHSH256.obj putty\SSHSH512.obj
+      putty\SSHSHA.obj putty\SSHZLIB.obj putty\TREE234.obj
+      putty\CHARSET\UTF8.obj putty\WILDCARD.obj putty\WINDOWS\WINHANDL.obj
+      putty\WINDOWS\WINMISC.obj putty\WINDOWS\WINNET.obj
+      putty\WINDOWS\WINNOISE.obj putty\WINDOWS\WINPGNTC.obj
+      putty\WINDOWS\WINPROXY.obj putty\WINDOWS\WINSTORE_.obj
       putty\WINDOWS\WINTIME.obj putty\X11FWD.obj"/>
     <RESFILES value=""/>
     <DEFFILE value=""/>
@@ -27,14 +27,14 @@
     <PATHRC value=".;"/>
     <PATHASM value=".;"/>
     <LINKER value="TLib"/>
-    <USERDEFINES value="GSSAPI;MPEXT;_WINDOWS;_MSC_VER=1000"/>
+    <USERDEFINES value="SSPI_MECH;MPEXT;_WINDOWS"/>
     <SYSDEFINES value="_RTLDLL;NO_STRICT"/>
     <MAINSOURCE value="Putty.bpf"/>
     <INCLUDEPATH value="putty;putty\CHARSET;putty\WINDOWS;$(BCB)\include;$(BCB)\include\vcl"/>
     <LIBPATH value="putty;putty\CHARSET;putty\WINDOWS;$(BCB)\lib\obj;$(BCB)\lib"/>
     <WARNINGS value="-w8092 -w8091 -w8090 -w8089 -w8087 -w-sus -wstv -wstu -w-rvl -w-rch -w-pia 
-      -w-pck -w-pch -w-par -wnod -wnak -w-8027 -w-eff -w-csu -wcln -wbbf -w-aus 
-      -wasm -wamp -wamb"/>
+      -w-pck -w-pch -w-par -wnod -wnak -w-8027 -w-eff -w-csu -wcln -w-ccc -wbbf 
+      -w-aus -wasm -wamp -wamb"/>
     <LISTFILE value=""/>
     <OTHERFILES value=""/>
   </MACROS>
@@ -58,10 +58,10 @@
       <FILE FILENAME="putty\LOGGING.C" FORMNAME="" UNITNAME="LOGGING.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\MISC.C" FORMNAME="" UNITNAME="MISC.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\PORTFWD_.C" FORMNAME="" UNITNAME="PORTFWD_.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="putty\PPROXY.C" FORMNAME="" UNITNAME="PPROXY.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\PROXY.C" FORMNAME="" UNITNAME="PROXY.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSH_.C" FORMNAME="" UNITNAME="SSH_.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHAES.C" FORMNAME="" UNITNAME="SSHAES.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="putty\SSHARCF.C" FORMNAME="" UNITNAME="SSHARCF" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHBLOWF.C" FORMNAME="" UNITNAME="SSHBLOWF.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHBN.C" FORMNAME="" UNITNAME="SSHBN.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHCRC.C" FORMNAME="" UNITNAME="SSHCRC.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
@@ -69,24 +69,23 @@
       <FILE FILENAME="putty\SSHDES.C" FORMNAME="" UNITNAME="SSHDES.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHDH.C" FORMNAME="" UNITNAME="SSHDH.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHDSS.C" FORMNAME="" UNITNAME="SSHDSS.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="putty\SSHGSS.C" FORMNAME="" UNITNAME="SSHGSS.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="putty\SSHGSSC.C" FORMNAME="" UNITNAME="SSHGSSC.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHMD5.C" FORMNAME="" UNITNAME="SSHMD5.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHPUBK.C" FORMNAME="" UNITNAME="SSHPUBK.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHRAND.C" FORMNAME="" UNITNAME="SSHRAND.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHRSA.C" FORMNAME="" UNITNAME="SSHRSA.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="putty\SSHSH256.C" FORMNAME="" UNITNAME="SSHSH256.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHSH512.C" FORMNAME="" UNITNAME="SSHSH512.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHSHA.C" FORMNAME="" UNITNAME="SSHSHA.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\SSHZLIB.C" FORMNAME="" UNITNAME="SSHZLIB.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\TREE234.C" FORMNAME="" UNITNAME="TREE234.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="putty\CHARSET\UTF8.C" FORMNAME="" UNITNAME="UTF8" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="putty\CHARSET\UTF8.C" FORMNAME="" UNITNAME="UTF8.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\WILDCARD.C" FORMNAME="" UNITNAME="WILDCARD.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="putty\WINDOWS\WINDL.C" FORMNAME="" UNITNAME="WINDL" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="putty\WINDOWS\WINGSS.C" FORMNAME="" UNITNAME="WINGSS" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="putty\WINDOWS\WINHANDL.C" FORMNAME="" UNITNAME="WINHANDL.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\WINDOWS\WINMISC.C" FORMNAME="" UNITNAME="WINMISC.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\WINDOWS\WINNET.C" FORMNAME="" UNITNAME="WINNET.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\WINDOWS\WINNOISE.C" FORMNAME="" UNITNAME="WINNOISE.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\WINDOWS\WINPGNTC.C" FORMNAME="" UNITNAME="WINPGNTC.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="putty\WINDOWS\WINPROXY.C" FORMNAME="" UNITNAME="WINPROXY.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\WINDOWS\WINSTORE_.C" FORMNAME="" UNITNAME="WINSTORE_.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\WINDOWS\WINTIME.C" FORMNAME="" UNITNAME="WINTIME.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\X11FWD.C" FORMNAME="" UNITNAME="X11FWD.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>

+ 1 - 2
RScpComp.bpr

@@ -5,7 +5,7 @@
     <VERSION value="BCB.06.00"/>
     <PROJECT value="lib\RScpComp.lib"/>
     <OBJFILES value="components\LogMemo.obj components\UnixDirView.obj
-      components\UnixDriveView.obj components\UnixPathComboBox.obj"/>
+      components\UnixDriveView.obj"/>
     <RESFILES value=""/>
     <DEFFILE value=""/>
     <RESDEPEN value="$(RESFILES)"/>
@@ -45,7 +45,6 @@
       <FILE FILENAME="components\LogMemo.cpp" FORMNAME="" UNITNAME="LogMemo" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="components\UnixDirView.cpp" FORMNAME="" UNITNAME="UnixDirView" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="components\UnixDriveView.cpp" FORMNAME="" UNITNAME="UnixDriveView" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="components\UnixPathComboBox.cpp" FORMNAME="" UNITNAME="UnixPathComboBox" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
   </FILELIST>
   <BUILDTOOLS>
   </BUILDTOOLS>

+ 3 - 2
ScpCore.bpr

@@ -9,7 +9,7 @@
       core\Exceptions.obj core\FileBuffer.obj core\FileInfo.obj
       core\FileMasks.obj core\FileOperationProgress.obj core\FileSystems.obj
       core\FtpFileSystem.obj core\HierarchicalStorage.obj core\NamedObjs.obj
-      core\PuttyIntf.obj core\Queue.obj core\RemoteFiles.obj
+      core\Option.obj core\PuttyIntf.obj core\Queue.obj core\RemoteFiles.obj
       core\ScpFileSystem.obj core\Script.obj core\SecureShell.obj
       core\Security.obj core\SessionData.obj core\SessionInfo.obj
       core\SftpFileSystem.obj core\Terminal.obj"/>
@@ -24,7 +24,7 @@
     <PATHRC value=".;"/>
     <PATHASM value=".;"/>
     <LINKER value="TLib"/>
-    <USERDEFINES value="USE_COMPATIBLE_THREAD;GSSAPI;_WINDOWS"/>
+    <USERDEFINES value="USE_COMPATIBLE_THREAD;SSPI_MECH;_WINDOWS"/>
     <SYSDEFINES value="NO_STRICT"/>
     <MAINSOURCE value="ScpCore.bpf"/>
     <INCLUDEPATH value="windows;core;putty;putty\windows;filezilla;resource;$(BCB)\include;$(BCB)\include\vcl;$(BCB)\include\mfc"/>
@@ -62,6 +62,7 @@
       <FILE FILENAME="core\FtpFileSystem.cpp" FORMNAME="" UNITNAME="FtpFileSystem" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\HierarchicalStorage.cpp" FORMNAME="" UNITNAME="HierarchicalStorage.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\NamedObjs.cpp" FORMNAME="" UNITNAME="NamedObjs.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="core\Option.cpp" FORMNAME="" UNITNAME="Option" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\PuttyIntf.cpp" FORMNAME="" UNITNAME="PuttyIntf" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\Queue.cpp" FORMNAME="" UNITNAME="Queue" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="core\RemoteFiles.cpp" FORMNAME="" UNITNAME="RemoteFiles.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>

+ 3 - 2
ScpForms.bpf

@@ -20,18 +20,19 @@ USEFORM("forms\FullSynchronize.cpp", FullSynchronizeDialog);
 USEFORM("forms\GeneralSettings.cpp", GeneralSettingsFrame); /* TFrame: File Type */
 USEFORM("forms\Glyphs.cpp", GlyphsModule); /* TDataModule: File Type */
 USEFORM("forms\ImportSessions.cpp", ImportSessionsDialog);
-USEFORM("forms\Licence.cpp", LicenceDialog);
+USEFORM("forms\License.cpp", LicenseDialog);
 USEFORM("forms\LocationProfiles.cpp", LocationProfilesDialog);
 USEFORM("forms\Log.cpp", LogForm);
 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\Preferences.cpp", PreferencesDialog);
 USEFORM("forms\Progress.cpp", ProgressForm);
 USEFORM("forms\Properties.cpp", PropertiesDialog);
+USEFORM("forms\RemoteTransfer.cpp", RemoteTransferDialog);
 USEFORM("forms\Rights.cpp", RightsFrame); /* TFrame: File Type */
 USEFORM("forms\RightsExt.cpp", RightsExtFrame); /* TFrame: File Type */
+USEFORM("forms\SaveSession.cpp", SaveSessionDialog);
 USEFORM("forms\SelectMask.cpp", SelectMaskDialog);
 USEFORM("forms\Symlink.cpp", SymlinkDialog);
 USEFORM("forms\Synchronize.cpp", SynchronizeDialog);

+ 13 - 12
ScpForms.bpr

@@ -11,12 +11,12 @@
       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\ImportSessions.obj forms\License.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\OpenDirectory.obj forms\Preferences.obj forms\Progress.obj
+      forms\Properties.obj forms\RemoteTransfer.obj forms\Rights.obj
+      forms\RightsExt.obj forms\SaveSession.obj forms\SelectMask.obj
+      forms\Symlink.obj forms\Synchronize.obj forms\SynchronizeChecklist.obj
       forms\SynchronizeProgress.obj"/>
     <RESFILES value=""/>
     <DEFFILE value=""/>
@@ -26,12 +26,12 @@
       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\ImportSessions.dfm forms\License.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\OpenDirectory.dfm forms\Preferences.dfm forms\Progress.dfm 
+      forms\Properties.dfm forms\RemoteTransfer.dfm forms\Rights.dfm 
+      forms\RightsExt.dfm forms\SaveSession.dfm forms\SelectMask.dfm 
+      forms\Symlink.dfm forms\Synchronize.dfm forms\SynchronizeChecklist.dfm 
       forms\SynchronizeProgress.dfm"/>
     <LIBFILES value=""/>
     <LIBRARIES value=""/>
@@ -88,18 +88,19 @@
       <FILE FILENAME="forms\GeneralSettings.cpp" FORMNAME="GeneralSettingsFrame" UNITNAME="GeneralSettings" CONTAINERID="CCompiler" DESIGNCLASS="TFrame" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Glyphs.cpp" FORMNAME="GlyphsModule" UNITNAME="Glyphs" CONTAINERID="CCompiler" DESIGNCLASS="TDataModule" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\ImportSessions.cpp" FORMNAME="ImportSessionsDialog" UNITNAME="ImportSessions" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
-      <FILE FILENAME="forms\Licence.cpp" FORMNAME="LicenceDialog" UNITNAME="Licence" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="forms\License.cpp" FORMNAME="LicenseDialog" UNITNAME="License" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\LocationProfiles.cpp" FORMNAME="LocationProfilesDialog" UNITNAME="LocationProfiles" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Log.cpp" FORMNAME="LogForm" UNITNAME="Log" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Login.cpp" FORMNAME="LoginDialog" UNITNAME="Login" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <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\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=""/>
+      <FILE FILENAME="forms\RemoteTransfer.cpp" FORMNAME="RemoteTransferDialog" UNITNAME="RemoteTransfer" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\Rights.cpp" FORMNAME="RightsFrame" UNITNAME="Rights" CONTAINERID="CCompiler" DESIGNCLASS="TFrame" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\RightsExt.cpp" FORMNAME="RightsExtFrame" UNITNAME="RightsExt" CONTAINERID="CCompiler" DESIGNCLASS="TFrame" LOCALCOMMAND=""/>
+      <FILE FILENAME="forms\SaveSession.cpp" FORMNAME="SaveSessionDialog" UNITNAME="SaveSession" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <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=""/>

+ 313 - 315
WinSCP.drc

@@ -7,292 +7,291 @@
   produced executable.
 */
 
-#define Consts_SNoDefaultPrinter 65200
-#define Consts_SDuplicateMenus 65201
-#define Consts_SPictureLabel 65202
-#define Consts_SPictureDesc 65203
-#define Consts_SPreviewLabel 65204
-#define Consts_SCannotOpenAVI 65205
-#define Consts_SDockedCtlNeedsName 65206
-#define Consts_SDockTreeRemoveError 65207
-#define Consts_SDockZoneNotFound 65208
-#define Consts_SDockZoneHasNoCtl 65209
-#define Consts_SMultiSelectRequired 65210
-#define Consts_SSeparator 65211
-#define Consts_SErrorSettingCount 65212
-#define Consts_SListBoxMustBeVirtual 65213
-#define Consts_SmkcUp 65216
-#define Consts_SmkcRight 65217
-#define Consts_SmkcDown 65218
-#define Consts_SmkcIns 65219
-#define Consts_SmkcDel 65220
-#define Consts_SmkcShift 65221
-#define Consts_SmkcCtrl 65222
-#define Consts_SmkcAlt 65223
-#define Consts_srNone 65224
-#define Consts_SOutOfRange 65225
-#define Consts_sAllFilter 65226
-#define Consts_SInsertLineError 65227
-#define Consts_SInvalidClipFmt 65228
-#define Consts_SIconToClipboard 65229
-#define Consts_SCannotOpenClipboard 65230
-#define Consts_SInvalidMemoSize 65231
-#define Consts_SMsgDlgAbort 65232
-#define Consts_SMsgDlgRetry 65233
-#define Consts_SMsgDlgIgnore 65234
-#define Consts_SMsgDlgAll 65235
-#define Consts_SMsgDlgNoToAll 65236
-#define Consts_SMsgDlgYesToAll 65237
-#define Consts_SmkcBkSp 65238
-#define Consts_SmkcTab 65239
-#define Consts_SmkcEsc 65240
-#define Consts_SmkcEnter 65241
-#define Consts_SmkcSpace 65242
-#define Consts_SmkcPgUp 65243
-#define Consts_SmkcPgDn 65244
-#define Consts_SmkcEnd 65245
-#define Consts_SmkcHome 65246
-#define Consts_SmkcLeft 65247
-#define Consts_SCannotDragForm 65248
-#define Consts_SVMetafiles 65249
-#define Consts_SVEnhMetafiles 65250
-#define Consts_SVIcons 65251
-#define Consts_SVBitmaps 65252
-#define Consts_SMaskErr 65253
-#define Consts_SMaskEditErr 65254
-#define Consts_SMsgDlgWarning 65255
-#define Consts_SMsgDlgError 65256
-#define Consts_SMsgDlgInformation 65257
-#define Consts_SMsgDlgConfirm 65258
-#define Consts_SMsgDlgYes 65259
-#define Consts_SMsgDlgNo 65260
-#define Consts_SMsgDlgOK 65261
-#define Consts_SMsgDlgCancel 65262
-#define Consts_SMsgDlgHelp 65263
-#define Consts_SPrinting 65264
-#define Consts_SInvalidPrinter 65265
-#define Consts_SDeviceOnPort 65266
-#define Consts_SGroupIndexTooLow 65267
-#define Consts_SNoMDIForm 65268
-#define Consts_SControlParentSetToSelf 65269
-#define Consts_SOKButton 65270
-#define Consts_SCancelButton 65271
-#define Consts_SYesButton 65272
-#define Consts_SNoButton 65273
-#define Consts_SHelpButton 65274
-#define Consts_SCloseButton 65275
-#define Consts_SIgnoreButton 65276
-#define Consts_SRetryButton 65277
-#define Consts_SAbortButton 65278
-#define Consts_SAllButton 65279
-#define Consts_SImageReadFail 65280
-#define Consts_SImageWriteFail 65281
-#define Consts_SWindowDCError 65282
-#define Consts_SWindowClass 65283
-#define Consts_SCannotFocus 65284
-#define Consts_SParentRequired 65285
-#define Consts_SParentGivenNotAParent 65286
-#define Consts_SMDIChildNotVisible 65287
-#define Consts_SVisibleChanged 65288
-#define Consts_SCannotShowModal 65289
-#define Consts_SPropertyOutOfRange 65290
-#define Consts_SMenuIndexError 65291
-#define Consts_SMenuReinserted 65292
-#define Consts_SMenuNotFound 65293
-#define Consts_SNoTimers 65294
-#define Consts_SNotPrinting 65295
-#define Consts_SInvalidTabStyle 65296
-#define Consts_SInvalidBitmap 65297
-#define Consts_SInvalidIcon 65298
-#define Consts_SInvalidMetafile 65299
-#define Consts_SInvalidPixelFormat 65300
-#define Consts_SInvalidImage 65301
-#define Consts_SScanLine 65302
-#define Consts_SChangeIconSize 65303
-#define Consts_SUnknownExtension 65304
-#define Consts_SUnknownClipboardFormat 65305
-#define Consts_SOutOfResources 65306
-#define Consts_SNoCanvasHandle 65307
-#define Consts_SInvalidImageSize 65308
-#define Consts_SInvalidImageList 65309
-#define Consts_SReplaceImage 65310
-#define Consts_SImageIndexError 65311
-#define Comstrs_sTabFailClear 65312
-#define Comstrs_sTabFailDelete 65313
-#define Comstrs_sTabFailRetrieve 65314
-#define Comstrs_sTabFailGetObject 65315
-#define Comstrs_sTabFailSet 65316
-#define Comstrs_sTabFailSetObject 65317
-#define Comstrs_sTabMustBeMultiLine 65318
-#define Comstrs_sInvalidIndex 65319
-#define Comstrs_sInsertError 65320
-#define Comstrs_sInvalidOwner 65321
-#define Comstrs_sRichEditInsertError 65322
-#define Comstrs_sRichEditLoadFail 65323
-#define Comstrs_sRichEditSaveFail 65324
-#define Comstrs_sPageIndexError 65325
-#define Comstrs_sInvalidComCtl32 65326
-#define Consts_SInvalidTabPosition 65327
-#define Sysconst_SLongDayNameSun 65328
-#define Sysconst_SLongDayNameMon 65329
-#define Sysconst_SLongDayNameTue 65330
-#define Sysconst_SLongDayNameWed 65331
-#define Sysconst_SLongDayNameThu 65332
-#define Sysconst_SLongDayNameFri 65333
-#define Sysconst_SLongDayNameSat 65334
-#define Sysconst_SCannotCreateDir 65335
-#define Tb2consts_STBToolbarIndexOutOfBounds 65336
-#define Tb2consts_STBToolbarItemReinserted 65337
-#define Tb2consts_STBViewerNotFound 65338
-#define Tb2consts_STBChevronItemMoreButtonsHint 65339
-#define Tb2consts_STBDockParentNotAllowed 65340
-#define Tb2consts_STBDockCannotChangePosition 65341
-#define Tb2consts_STBToolwinNameNotSet 65342
-#define Tb2consts_STBToolwinDockedToNameNotSet 65343
-#define Sysconst_SLongMonthNameApr 65344
-#define Sysconst_SLongMonthNameMay 65345
-#define Sysconst_SLongMonthNameJun 65346
-#define Sysconst_SLongMonthNameJul 65347
-#define Sysconst_SLongMonthNameAug 65348
-#define Sysconst_SLongMonthNameSep 65349
-#define Sysconst_SLongMonthNameOct 65350
-#define Sysconst_SLongMonthNameNov 65351
-#define Sysconst_SLongMonthNameDec 65352
-#define Sysconst_SShortDayNameSun 65353
-#define Sysconst_SShortDayNameMon 65354
-#define Sysconst_SShortDayNameTue 65355
-#define Sysconst_SShortDayNameWed 65356
-#define Sysconst_SShortDayNameThu 65357
-#define Sysconst_SShortDayNameFri 65358
-#define Sysconst_SShortDayNameSat 65359
-#define Sysconst_SUnkOSError 65360
-#define Sysconst_SShortMonthNameJan 65361
-#define Sysconst_SShortMonthNameFeb 65362
-#define Sysconst_SShortMonthNameMar 65363
-#define Sysconst_SShortMonthNameApr 65364
-#define Sysconst_SShortMonthNameMay 65365
-#define Sysconst_SShortMonthNameJun 65366
-#define Sysconst_SShortMonthNameJul 65367
-#define Sysconst_SShortMonthNameAug 65368
-#define Sysconst_SShortMonthNameSep 65369
-#define Sysconst_SShortMonthNameOct 65370
-#define Sysconst_SShortMonthNameNov 65371
-#define Sysconst_SShortMonthNameDec 65372
-#define Sysconst_SLongMonthNameJan 65373
-#define Sysconst_SLongMonthNameFeb 65374
-#define Sysconst_SLongMonthNameMar 65375
-#define Sysconst_SInvalidVarNullOp 65376
-#define Sysconst_SVarTypeCouldNotConvert 65377
-#define Sysconst_SVarTypeConvertOverflow 65378
-#define Sysconst_SVarOverflow 65379
-#define Sysconst_SVarInvalid 65380
-#define Sysconst_SVarBadType 65381
-#define Sysconst_SVarNotImplemented 65382
-#define Sysconst_SVarUnexpected 65383
-#define Sysconst_SExternalException 65384
-#define Sysconst_SAssertionFailed 65385
-#define Sysconst_SIntfCastError 65386
-#define Sysconst_SSafecallException 65387
-#define Sysconst_SAssertError 65388
-#define Sysconst_SAbstractError 65389
-#define Sysconst_SModuleAccessViolation 65390
-#define Sysconst_SOSError 65391
-#define Sysconst_SOperationAborted 65392
-#define Sysconst_SException 65393
-#define Sysconst_SExceptTitle 65394
-#define Sysconst_SInvalidFormat 65395
-#define Sysconst_SArgumentMissing 65396
-#define Sysconst_SDispatchError 65397
-#define Sysconst_SReadAccess 65398
-#define Sysconst_SWriteAccess 65399
-#define Sysconst_SFormatTooLong 65400
-#define Sysconst_SVarArrayCreate 65401
-#define Sysconst_SVarArrayBounds 65402
-#define Sysconst_SVarArrayLocked 65403
-#define Sysconst_SInvalidVarCast 65404
-#define Sysconst_SInvalidVarOp 65405
-#define Sysconst_SInvalidVarOpWithHResult 65406
-#define Sysconst_SVarNotArray 65407
-#define Sysconst_SEndOfFile 65408
-#define Sysconst_SDiskFull 65409
-#define Sysconst_SInvalidInput 65410
-#define Sysconst_SDivByZero 65411
-#define Sysconst_SRangeError 65412
-#define Sysconst_SIntOverflow 65413
-#define Sysconst_SInvalidOp 65414
-#define Sysconst_SZeroDivide 65415
-#define Sysconst_SOverflow 65416
-#define Sysconst_SUnderflow 65417
-#define Sysconst_SInvalidPointer 65418
-#define Sysconst_SInvalidCast 65419
-#define Sysconst_SAccessViolation 65420
-#define Sysconst_SStackOverflow 65421
-#define Sysconst_SControlC 65422
-#define Sysconst_SPrivilege 65423
-#define Comconst_SNoMethod 65424
-#define Comconst_SVarNotObject 65425
-#define Comconst_STooManyParams 65426
-#define Sysconst_SInvalidInteger 65427
-#define Sysconst_SInvalidFloat 65428
-#define Sysconst_SInvalidDate 65429
-#define Sysconst_SInvalidTime 65430
-#define Sysconst_SInvalidDateTime 65431
-#define Sysconst_STimeEncodeError 65432
-#define Sysconst_SDateEncodeError 65433
-#define Sysconst_SOutOfMemory 65434
-#define Sysconst_SInOutError 65435
-#define Sysconst_SFileNotFound 65436
-#define Sysconst_SInvalidFilename 65437
-#define Sysconst_STooManyOpenFiles 65438
-#define Sysconst_SAccessDenied 65439
-#define Rtlconsts_SMemoryStreamError 65440
-#define Rtlconsts_SPropertyException 65441
-#define Rtlconsts_SReadError 65442
-#define Rtlconsts_SReadOnlyProperty 65443
-#define Rtlconsts_SRegCreateFailed 65444
-#define Rtlconsts_SRegGetDataFailed 65445
-#define Rtlconsts_SRegisterError 65446
-#define Rtlconsts_SRegSetDataFailed 65447
-#define Rtlconsts_SResNotFound 65448
-#define Rtlconsts_SSeekNotImplemented 65449
-#define Rtlconsts_SSortedListError 65450
-#define Rtlconsts_STooManyDeleted 65451
-#define Rtlconsts_SUnknownGroup 65452
-#define Rtlconsts_SUnknownProperty 65453
-#define Rtlconsts_SWriteError 65454
-#define Comconst_SOleError 65455
-#define Rtlconsts_SFixedColTooBig 65456
-#define Rtlconsts_SFixedRowTooBig 65457
-#define Rtlconsts_SFOpenError 65458
-#define Rtlconsts_SGridTooLarge 65459
-#define Rtlconsts_SIndexOutOfRange 65460
-#define Rtlconsts_SIniFileWriteError 65461
-#define Rtlconsts_SInvalidImage 65462
-#define Rtlconsts_SInvalidMask 65463
-#define Rtlconsts_SInvalidName 65464
-#define Rtlconsts_SInvalidProperty 65465
-#define Rtlconsts_SInvalidPropertyPath 65466
-#define Rtlconsts_SInvalidPropertyValue 65467
-#define Rtlconsts_SInvalidRegType 65468
-#define Rtlconsts_SListCapacityError 65469
-#define Rtlconsts_SListCountError 65470
-#define Rtlconsts_SListIndexError 65471
-#define Tcpip_SUnknownSockError 65472
-#define HelpIntfs_16398 65473
-#define HelpIntfs_16400 65474
-#define HelpIntfs_16402 65475
-#define HelpIntfs_16404 65476
-#define Rtlconsts_SAncestorNotFound 65477
-#define Rtlconsts_SAssignError 65478
-#define Rtlconsts_SBitsIndexError 65479
-#define Rtlconsts_SCantWriteResourceStreamError 65480
-#define Rtlconsts_SCheckSynchronizeError 65481
-#define Rtlconsts_SClassNotFound 65482
-#define Rtlconsts_SDuplicateClass 65483
-#define Rtlconsts_SDuplicateItem 65484
-#define Rtlconsts_SDuplicateName 65485
-#define Rtlconsts_SDuplicateString 65486
-#define Rtlconsts_SFCreateError 65487
+#define Consts_SDuplicateMenus 65200
+#define Consts_SPictureLabel 65201
+#define Consts_SPictureDesc 65202
+#define Consts_SPreviewLabel 65203
+#define Consts_SCannotOpenAVI 65204
+#define Consts_SDockedCtlNeedsName 65205
+#define Consts_SDockTreeRemoveError 65206
+#define Consts_SDockZoneNotFound 65207
+#define Consts_SDockZoneHasNoCtl 65208
+#define Consts_SMultiSelectRequired 65209
+#define Consts_SSeparator 65210
+#define Consts_SErrorSettingCount 65211
+#define Consts_SListBoxMustBeVirtual 65212
+#define Consts_SmkcRight 65216
+#define Consts_SmkcDown 65217
+#define Consts_SmkcIns 65218
+#define Consts_SmkcDel 65219
+#define Consts_SmkcShift 65220
+#define Consts_SmkcCtrl 65221
+#define Consts_SmkcAlt 65222
+#define Consts_srNone 65223
+#define Consts_SOutOfRange 65224
+#define Consts_sAllFilter 65225
+#define Consts_SInsertLineError 65226
+#define Consts_SInvalidClipFmt 65227
+#define Consts_SIconToClipboard 65228
+#define Consts_SCannotOpenClipboard 65229
+#define Consts_SInvalidMemoSize 65230
+#define Consts_SNoDefaultPrinter 65231
+#define Consts_SMsgDlgRetry 65232
+#define Consts_SMsgDlgIgnore 65233
+#define Consts_SMsgDlgAll 65234
+#define Consts_SMsgDlgNoToAll 65235
+#define Consts_SMsgDlgYesToAll 65236
+#define Consts_SmkcBkSp 65237
+#define Consts_SmkcTab 65238
+#define Consts_SmkcEsc 65239
+#define Consts_SmkcEnter 65240
+#define Consts_SmkcSpace 65241
+#define Consts_SmkcPgUp 65242
+#define Consts_SmkcPgDn 65243
+#define Consts_SmkcEnd 65244
+#define Consts_SmkcHome 65245
+#define Consts_SmkcLeft 65246
+#define Consts_SmkcUp 65247
+#define Consts_SVMetafiles 65248
+#define Consts_SVEnhMetafiles 65249
+#define Consts_SVIcons 65250
+#define Consts_SVBitmaps 65251
+#define Consts_SMaskErr 65252
+#define Consts_SMaskEditErr 65253
+#define Consts_SMsgDlgWarning 65254
+#define Consts_SMsgDlgError 65255
+#define Consts_SMsgDlgInformation 65256
+#define Consts_SMsgDlgConfirm 65257
+#define Consts_SMsgDlgYes 65258
+#define Consts_SMsgDlgNo 65259
+#define Consts_SMsgDlgOK 65260
+#define Consts_SMsgDlgCancel 65261
+#define Consts_SMsgDlgHelp 65262
+#define Consts_SMsgDlgAbort 65263
+#define Consts_SInvalidPrinter 65264
+#define Consts_SDeviceOnPort 65265
+#define Consts_SGroupIndexTooLow 65266
+#define Consts_SNoMDIForm 65267
+#define Consts_SControlParentSetToSelf 65268
+#define Consts_SOKButton 65269
+#define Consts_SCancelButton 65270
+#define Consts_SYesButton 65271
+#define Consts_SNoButton 65272
+#define Consts_SHelpButton 65273
+#define Consts_SCloseButton 65274
+#define Consts_SIgnoreButton 65275
+#define Consts_SRetryButton 65276
+#define Consts_SAbortButton 65277
+#define Consts_SAllButton 65278
+#define Consts_SCannotDragForm 65279
+#define Consts_SImageWriteFail 65280
+#define Consts_SWindowDCError 65281
+#define Consts_SWindowClass 65282
+#define Consts_SCannotFocus 65283
+#define Consts_SParentRequired 65284
+#define Consts_SParentGivenNotAParent 65285
+#define Consts_SMDIChildNotVisible 65286
+#define Consts_SVisibleChanged 65287
+#define Consts_SCannotShowModal 65288
+#define Consts_SPropertyOutOfRange 65289
+#define Consts_SMenuIndexError 65290
+#define Consts_SMenuReinserted 65291
+#define Consts_SMenuNotFound 65292
+#define Consts_SNoTimers 65293
+#define Consts_SNotPrinting 65294
+#define Consts_SPrinting 65295
+#define Consts_SInvalidBitmap 65296
+#define Consts_SInvalidIcon 65297
+#define Consts_SInvalidMetafile 65298
+#define Consts_SInvalidPixelFormat 65299
+#define Consts_SInvalidImage 65300
+#define Consts_SScanLine 65301
+#define Consts_SChangeIconSize 65302
+#define Consts_SUnknownExtension 65303
+#define Consts_SUnknownClipboardFormat 65304
+#define Consts_SOutOfResources 65305
+#define Consts_SNoCanvasHandle 65306
+#define Consts_SInvalidImageSize 65307
+#define Consts_SInvalidImageList 65308
+#define Consts_SReplaceImage 65309
+#define Consts_SImageIndexError 65310
+#define Consts_SImageReadFail 65311
+#define Comstrs_sTabFailDelete 65312
+#define Comstrs_sTabFailRetrieve 65313
+#define Comstrs_sTabFailGetObject 65314
+#define Comstrs_sTabFailSet 65315
+#define Comstrs_sTabFailSetObject 65316
+#define Comstrs_sTabMustBeMultiLine 65317
+#define Comstrs_sInvalidIndex 65318
+#define Comstrs_sInsertError 65319
+#define Comstrs_sInvalidOwner 65320
+#define Comstrs_sRichEditInsertError 65321
+#define Comstrs_sRichEditLoadFail 65322
+#define Comstrs_sRichEditSaveFail 65323
+#define Comstrs_sPageIndexError 65324
+#define Comstrs_sInvalidComCtl32 65325
+#define Consts_SInvalidTabPosition 65326
+#define Consts_SInvalidTabStyle 65327
+#define Sysconst_SLongDayNameMon 65328
+#define Sysconst_SLongDayNameTue 65329
+#define Sysconst_SLongDayNameWed 65330
+#define Sysconst_SLongDayNameThu 65331
+#define Sysconst_SLongDayNameFri 65332
+#define Sysconst_SLongDayNameSat 65333
+#define Sysconst_SCannotCreateDir 65334
+#define Tb2consts_STBToolbarIndexOutOfBounds 65335
+#define Tb2consts_STBToolbarItemReinserted 65336
+#define Tb2consts_STBViewerNotFound 65337
+#define Tb2consts_STBChevronItemMoreButtonsHint 65338
+#define Tb2consts_STBDockParentNotAllowed 65339
+#define Tb2consts_STBDockCannotChangePosition 65340
+#define Tb2consts_STBToolwinNameNotSet 65341
+#define Tb2consts_STBToolwinDockedToNameNotSet 65342
+#define Comstrs_sTabFailClear 65343
+#define Sysconst_SLongMonthNameMay 65344
+#define Sysconst_SLongMonthNameJun 65345
+#define Sysconst_SLongMonthNameJul 65346
+#define Sysconst_SLongMonthNameAug 65347
+#define Sysconst_SLongMonthNameSep 65348
+#define Sysconst_SLongMonthNameOct 65349
+#define Sysconst_SLongMonthNameNov 65350
+#define Sysconst_SLongMonthNameDec 65351
+#define Sysconst_SShortDayNameSun 65352
+#define Sysconst_SShortDayNameMon 65353
+#define Sysconst_SShortDayNameTue 65354
+#define Sysconst_SShortDayNameWed 65355
+#define Sysconst_SShortDayNameThu 65356
+#define Sysconst_SShortDayNameFri 65357
+#define Sysconst_SShortDayNameSat 65358
+#define Sysconst_SLongDayNameSun 65359
+#define Sysconst_SShortMonthNameJan 65360
+#define Sysconst_SShortMonthNameFeb 65361
+#define Sysconst_SShortMonthNameMar 65362
+#define Sysconst_SShortMonthNameApr 65363
+#define Sysconst_SShortMonthNameMay 65364
+#define Sysconst_SShortMonthNameJun 65365
+#define Sysconst_SShortMonthNameJul 65366
+#define Sysconst_SShortMonthNameAug 65367
+#define Sysconst_SShortMonthNameSep 65368
+#define Sysconst_SShortMonthNameOct 65369
+#define Sysconst_SShortMonthNameNov 65370
+#define Sysconst_SShortMonthNameDec 65371
+#define Sysconst_SLongMonthNameJan 65372
+#define Sysconst_SLongMonthNameFeb 65373
+#define Sysconst_SLongMonthNameMar 65374
+#define Sysconst_SLongMonthNameApr 65375
+#define Sysconst_SVarTypeCouldNotConvert 65376
+#define Sysconst_SVarTypeConvertOverflow 65377
+#define Sysconst_SVarOverflow 65378
+#define Sysconst_SVarInvalid 65379
+#define Sysconst_SVarBadType 65380
+#define Sysconst_SVarNotImplemented 65381
+#define Sysconst_SVarUnexpected 65382
+#define Sysconst_SExternalException 65383
+#define Sysconst_SAssertionFailed 65384
+#define Sysconst_SIntfCastError 65385
+#define Sysconst_SSafecallException 65386
+#define Sysconst_SAssertError 65387
+#define Sysconst_SAbstractError 65388
+#define Sysconst_SModuleAccessViolation 65389
+#define Sysconst_SOSError 65390
+#define Sysconst_SUnkOSError 65391
+#define Sysconst_SException 65392
+#define Sysconst_SExceptTitle 65393
+#define Sysconst_SInvalidFormat 65394
+#define Sysconst_SArgumentMissing 65395
+#define Sysconst_SDispatchError 65396
+#define Sysconst_SReadAccess 65397
+#define Sysconst_SWriteAccess 65398
+#define Sysconst_SFormatTooLong 65399
+#define Sysconst_SVarArrayCreate 65400
+#define Sysconst_SVarArrayBounds 65401
+#define Sysconst_SVarArrayLocked 65402
+#define Sysconst_SInvalidVarCast 65403
+#define Sysconst_SInvalidVarOp 65404
+#define Sysconst_SInvalidVarOpWithHResult 65405
+#define Sysconst_SVarNotArray 65406
+#define Sysconst_SInvalidVarNullOp 65407
+#define Sysconst_SDiskFull 65408
+#define Sysconst_SInvalidInput 65409
+#define Sysconst_SDivByZero 65410
+#define Sysconst_SRangeError 65411
+#define Sysconst_SIntOverflow 65412
+#define Sysconst_SInvalidOp 65413
+#define Sysconst_SZeroDivide 65414
+#define Sysconst_SOverflow 65415
+#define Sysconst_SUnderflow 65416
+#define Sysconst_SInvalidPointer 65417
+#define Sysconst_SInvalidCast 65418
+#define Sysconst_SAccessViolation 65419
+#define Sysconst_SStackOverflow 65420
+#define Sysconst_SControlC 65421
+#define Sysconst_SPrivilege 65422
+#define Sysconst_SOperationAborted 65423
+#define Comconst_SVarNotObject 65424
+#define Comconst_STooManyParams 65425
+#define Sysconst_SInvalidInteger 65426
+#define Sysconst_SInvalidFloat 65427
+#define Sysconst_SInvalidDate 65428
+#define Sysconst_SInvalidTime 65429
+#define Sysconst_SInvalidDateTime 65430
+#define Sysconst_STimeEncodeError 65431
+#define Sysconst_SDateEncodeError 65432
+#define Sysconst_SOutOfMemory 65433
+#define Sysconst_SInOutError 65434
+#define Sysconst_SFileNotFound 65435
+#define Sysconst_SInvalidFilename 65436
+#define Sysconst_STooManyOpenFiles 65437
+#define Sysconst_SAccessDenied 65438
+#define Sysconst_SEndOfFile 65439
+#define Rtlconsts_SPropertyException 65440
+#define Rtlconsts_SReadError 65441
+#define Rtlconsts_SReadOnlyProperty 65442
+#define Rtlconsts_SRegCreateFailed 65443
+#define Rtlconsts_SRegGetDataFailed 65444
+#define Rtlconsts_SRegisterError 65445
+#define Rtlconsts_SRegSetDataFailed 65446
+#define Rtlconsts_SResNotFound 65447
+#define Rtlconsts_SSeekNotImplemented 65448
+#define Rtlconsts_SSortedListError 65449
+#define Rtlconsts_STooManyDeleted 65450
+#define Rtlconsts_SUnknownGroup 65451
+#define Rtlconsts_SUnknownProperty 65452
+#define Rtlconsts_SWriteError 65453
+#define Comconst_SOleError 65454
+#define Comconst_SNoMethod 65455
+#define Rtlconsts_SFixedRowTooBig 65456
+#define Rtlconsts_SFOpenError 65457
+#define Rtlconsts_SGridTooLarge 65458
+#define Rtlconsts_SIndexOutOfRange 65459
+#define Rtlconsts_SIniFileWriteError 65460
+#define Rtlconsts_SInvalidImage 65461
+#define Rtlconsts_SInvalidMask 65462
+#define Rtlconsts_SInvalidName 65463
+#define Rtlconsts_SInvalidProperty 65464
+#define Rtlconsts_SInvalidPropertyPath 65465
+#define Rtlconsts_SInvalidPropertyValue 65466
+#define Rtlconsts_SInvalidRegType 65467
+#define Rtlconsts_SListCapacityError 65468
+#define Rtlconsts_SListCountError 65469
+#define Rtlconsts_SListIndexError 65470
+#define Rtlconsts_SMemoryStreamError 65471
+#define HelpIntfs_16398 65472
+#define HelpIntfs_16400 65473
+#define HelpIntfs_16402 65474
+#define HelpIntfs_16404 65475
+#define Rtlconsts_SAncestorNotFound 65476
+#define Rtlconsts_SAssignError 65477
+#define Rtlconsts_SBitsIndexError 65478
+#define Rtlconsts_SCantWriteResourceStreamError 65479
+#define Rtlconsts_SCheckSynchronizeError 65480
+#define Rtlconsts_SClassNotFound 65481
+#define Rtlconsts_SDuplicateClass 65482
+#define Rtlconsts_SDuplicateItem 65483
+#define Rtlconsts_SDuplicateName 65484
+#define Rtlconsts_SDuplicateString 65485
+#define Rtlconsts_SFCreateError 65486
+#define Rtlconsts_SFixedColTooBig 65487
 #define Customdirview_SDirNotExists 65488
 #define Customunixdirview_SUnixDefaultRootName 65489
 #define Unixdirviewcolproperties_SUnixDirViewRightsCol 65490
@@ -300,15 +299,15 @@
 #define Unixdirviewcolproperties_SUnixDirViewGroupCol 65492
 #define Unixdirviewcolproperties_SUnixDirViewLinkTargetCol 65493
 #define Unixdirviewcolproperties_SUnixDirViewTypeCol 65494
-#define Iepathcombobox_SSpecialFolderMyDocuments 65495
-#define Iepathcombobox_SSpecialFolderDesktop 65496
-#define Customdriveview_SDragDropError 65497
-#define Morebutton_SDefaultExpandedCaption 65498
-#define Morebutton_SDefaultCollapsedCaption 65499
-#define Comboedit_SBrowse 65500
-#define Comboedit_SDefaultFilter 65501
-#define Comboedit_SInvalidFileName 65502
-#define Tcpip_SSocketError 65503
+#define Customdriveview_SDragDropError 65495
+#define Morebutton_SDefaultExpandedCaption 65496
+#define Morebutton_SDefaultCollapsedCaption 65497
+#define Comboedit_SBrowse 65498
+#define Comboedit_SDefaultFilter 65499
+#define Comboedit_SInvalidFileName 65500
+#define Tcpip_SSocketError 65501
+#define Tcpip_SUnknownSockError 65502
+#define Tcpip_SHttpError 65503
 #define Dirviewcolproperties_SDirViewSizeCol 65504
 #define Dirviewcolproperties_SDirViewTypeCol 65505
 #define Dirviewcolproperties_SDirViewChangedCol 65506
@@ -343,7 +342,6 @@
 #define Dirviewcolproperties_SDirViewNameCol 65535
 STRINGTABLE
 BEGIN
-	Consts_SNoDefaultPrinter,	"There is no default printer currently selected"
 	Consts_SDuplicateMenus,	"Menu '%s' is already being used by another form"
 	Consts_SPictureLabel,	"Picture:"
 	Consts_SPictureDesc,	" (%dx%d)"
@@ -357,7 +355,6 @@ BEGIN
 	Consts_SSeparator,	"Separator"
 	Consts_SErrorSettingCount,	"Error setting %s.Count"
 	Consts_SListBoxMustBeVirtual,	"Listbox (%s) style must be virtual in order to set Count"
-	Consts_SmkcUp,	"Up"
 	Consts_SmkcRight,	"Right"
 	Consts_SmkcDown,	"Down"
 	Consts_SmkcIns,	"Ins"
@@ -373,7 +370,7 @@ BEGIN
 	Consts_SIconToClipboard,	"Clipboard does not support Icons"
 	Consts_SCannotOpenClipboard,	"Cannot open clipboard"
 	Consts_SInvalidMemoSize,	"Text exceeds memo capacity"
-	Consts_SMsgDlgAbort,	"&Abort"
+	Consts_SNoDefaultPrinter,	"There is no default printer currently selected"
 	Consts_SMsgDlgRetry,	"&Retry"
 	Consts_SMsgDlgIgnore,	"&Ignore"
 	Consts_SMsgDlgAll,	"&All"
@@ -389,7 +386,7 @@ BEGIN
 	Consts_SmkcEnd,	"End"
 	Consts_SmkcHome,	"Home"
 	Consts_SmkcLeft,	"Left"
-	Consts_SCannotDragForm,	"Cannot drag a form"
+	Consts_SmkcUp,	"Up"
 	Consts_SVMetafiles,	"Metafiles"
 	Consts_SVEnhMetafiles,	"Enhanced Metafiles"
 	Consts_SVIcons,	"Icons"
@@ -405,7 +402,7 @@ BEGIN
 	Consts_SMsgDlgOK,	"OK"
 	Consts_SMsgDlgCancel,	"Cancel"
 	Consts_SMsgDlgHelp,	"&Help"
-	Consts_SPrinting,	"Printing in progress"
+	Consts_SMsgDlgAbort,	"&Abort"
 	Consts_SInvalidPrinter,	"Printer selected is not valid"
 	Consts_SDeviceOnPort,	"%s on %s"
 	Consts_SGroupIndexTooLow,	"GroupIndex cannot be less than a previous menu item's GroupIndex"
@@ -421,7 +418,7 @@ BEGIN
 	Consts_SRetryButton,	"&Retry"
 	Consts_SAbortButton,	"Abort"
 	Consts_SAllButton,	"&All"
-	Consts_SImageReadFail,	"Failed to read ImageList data from stream"
+	Consts_SCannotDragForm,	"Cannot drag a form"
 	Consts_SImageWriteFail,	"Failed to write ImageList data to stream"
 	Consts_SWindowDCError,	"Error creating window device context"
 	Consts_SWindowClass,	"Error creating window class"
@@ -437,7 +434,7 @@ BEGIN
 	Consts_SMenuNotFound,	"Sub-menu is not in menu"
 	Consts_SNoTimers,	"Not enough timers available"
 	Consts_SNotPrinting,	"Printer is not currently printing"
-	Consts_SInvalidTabStyle,	"Tab style incompatible with current tab position"
+	Consts_SPrinting,	"Printing in progress"
 	Consts_SInvalidBitmap,	"Bitmap image is not valid"
 	Consts_SInvalidIcon,	"Icon image is not valid"
 	Consts_SInvalidMetafile,	"Metafile is not valid"
@@ -453,7 +450,7 @@ BEGIN
 	Consts_SInvalidImageList,	"Invalid ImageList"
 	Consts_SReplaceImage,	"Unable to Replace Image"
 	Consts_SImageIndexError,	"Invalid ImageList Index"
-	Comstrs_sTabFailClear,	"Failed to clear tab control"
+	Consts_SImageReadFail,	"Failed to read ImageList data from stream"
 	Comstrs_sTabFailDelete,	"Failed to delete tab at index %d"
 	Comstrs_sTabFailRetrieve,	"Failed to retrieve tab at index %d"
 	Comstrs_sTabFailGetObject,	"Failed to get object at index %d"
@@ -469,7 +466,7 @@ BEGIN
 	Comstrs_sPageIndexError,	"%d is an invalid PageIndex value.  PageIndex must be between 0 and %d"
 	Comstrs_sInvalidComCtl32,	"This control requires version 4.70 or greater of COMCTL32.DLL"
 	Consts_SInvalidTabPosition,	"Tab position incompatible with current tab style"
-	Sysconst_SLongDayNameSun,	"Sunday"
+	Consts_SInvalidTabStyle,	"Tab style incompatible with current tab position"
 	Sysconst_SLongDayNameMon,	"Monday"
 	Sysconst_SLongDayNameTue,	"Tuesday"
 	Sysconst_SLongDayNameWed,	"Wednesday"
@@ -485,7 +482,7 @@ BEGIN
 	Tb2consts_STBDockCannotChangePosition,	"Cannot change Position of a TTBDock if it already contains controls"
 	Tb2consts_STBToolwinNameNotSet,	"Cannot save dockable window's position because Name property is not set"
 	Tb2consts_STBToolwinDockedToNameNotSet,	"Cannot save dockable window's position because DockedTo's Name property not set"
-	Sysconst_SLongMonthNameApr,	"April"
+	Comstrs_sTabFailClear,	"Failed to clear tab control"
 	Sysconst_SLongMonthNameMay,	"May"
 	Sysconst_SLongMonthNameJun,	"June"
 	Sysconst_SLongMonthNameJul,	"July"
@@ -501,7 +498,7 @@ BEGIN
 	Sysconst_SShortDayNameThu,	"Thu"
 	Sysconst_SShortDayNameFri,	"Fri"
 	Sysconst_SShortDayNameSat,	"Sat"
-	Sysconst_SUnkOSError,	"A call to an OS function failed"
+	Sysconst_SLongDayNameSun,	"Sunday"
 	Sysconst_SShortMonthNameJan,	"Jan"
 	Sysconst_SShortMonthNameFeb,	"Feb"
 	Sysconst_SShortMonthNameMar,	"Mar"
@@ -517,7 +514,7 @@ BEGIN
 	Sysconst_SLongMonthNameJan,	"January"
 	Sysconst_SLongMonthNameFeb,	"February"
 	Sysconst_SLongMonthNameMar,	"March"
-	Sysconst_SInvalidVarNullOp,	"Invalid NULL variant operation"
+	Sysconst_SLongMonthNameApr,	"April"
 	Sysconst_SVarTypeCouldNotConvert,	"Could not convert variant of type (%s) into type (%s)"
 	Sysconst_SVarTypeConvertOverflow,	"Overflow while converting variant of type (%s) into type (%s)"
 	Sysconst_SVarOverflow,	"Variant overflow"
@@ -533,7 +530,7 @@ BEGIN
 	Sysconst_SAbstractError,	"Abstract Error"
 	Sysconst_SModuleAccessViolation,	"Access violation at address %p in module '%s'. %s of address %p"
 	Sysconst_SOSError,	"System Error.  Code: %d.\r\n%s"
-	Sysconst_SOperationAborted,	"Operation aborted"
+	Sysconst_SUnkOSError,	"A call to an OS function failed"
 	Sysconst_SException,	"Exception %s in module %s at %p.\r\n%s%s\r\n"
 	Sysconst_SExceptTitle,	"Application Error"
 	Sysconst_SInvalidFormat,	"Format '%s' invalid or incompatible with argument"
@@ -549,7 +546,7 @@ BEGIN
 	Sysconst_SInvalidVarOp,	"Invalid variant operation"
 	Sysconst_SInvalidVarOpWithHResult,	"Invalid variant operation ($%.8x)"
 	Sysconst_SVarNotArray,	"Variant is not an array"
-	Sysconst_SEndOfFile,	"Read beyond end of file"
+	Sysconst_SInvalidVarNullOp,	"Invalid NULL variant operation"
 	Sysconst_SDiskFull,	"Disk full"
 	Sysconst_SInvalidInput,	"Invalid numeric input"
 	Sysconst_SDivByZero,	"Division by zero"
@@ -565,7 +562,7 @@ BEGIN
 	Sysconst_SStackOverflow,	"Stack overflow"
 	Sysconst_SControlC,	"Control-C hit"
 	Sysconst_SPrivilege,	"Privileged instruction"
-	Comconst_SNoMethod,	"Method '%s' not supported by automation object"
+	Sysconst_SOperationAborted,	"Operation aborted"
 	Comconst_SVarNotObject,	"Variant does not reference an automation object"
 	Comconst_STooManyParams,	"Dispatch methods do not support more than 64 parameters"
 	Sysconst_SInvalidInteger,	"'%s' is not a valid integer value"
@@ -581,7 +578,7 @@ BEGIN
 	Sysconst_SInvalidFilename,	"Invalid filename"
 	Sysconst_STooManyOpenFiles,	"Too many open files"
 	Sysconst_SAccessDenied,	"File access denied"
-	Rtlconsts_SMemoryStreamError,	"Out of memory while expanding memory stream"
+	Sysconst_SEndOfFile,	"Read beyond end of file"
 	Rtlconsts_SPropertyException,	"Error reading %s%s%s: %s"
 	Rtlconsts_SReadError,	"Stream read error"
 	Rtlconsts_SReadOnlyProperty,	"Property is read-only"
@@ -597,7 +594,7 @@ BEGIN
 	Rtlconsts_SUnknownProperty,	"Property %s does not exist"
 	Rtlconsts_SWriteError,	"Stream write error"
 	Comconst_SOleError,	"OLE error %.8x"
-	Rtlconsts_SFixedColTooBig,	"Fixed column count must be less than column count"
+	Comconst_SNoMethod,	"Method '%s' not supported by automation object"
 	Rtlconsts_SFixedRowTooBig,	"Fixed row count must be less than row count"
 	Rtlconsts_SFOpenError,	"Cannot open file %s"
 	Rtlconsts_SGridTooLarge,	"Grid too large for operation"
@@ -613,7 +610,7 @@ BEGIN
 	Rtlconsts_SListCapacityError,	"List capacity out of bounds (%d)"
 	Rtlconsts_SListCountError,	"List count out of bounds (%d)"
 	Rtlconsts_SListIndexError,	"List index out of bounds (%d)"
-	Tcpip_SUnknownSockError,	"Unknown error"
+	Rtlconsts_SMemoryStreamError,	"Out of memory while expanding memory stream"
 	HelpIntfs_16398,	"Unable to find a Table of Contents"
 	HelpIntfs_16400,	"No help found for %s"
 	HelpIntfs_16402,	"No context-sensitive help installed"
@@ -629,6 +626,7 @@ BEGIN
 	Rtlconsts_SDuplicateName,	"A component named %s already exists"
 	Rtlconsts_SDuplicateString,	"String list does not allow duplicates"
 	Rtlconsts_SFCreateError,	"Cannot create file %s"
+	Rtlconsts_SFixedColTooBig,	"Fixed column count must be less than column count"
 	Customdirview_SDirNotExists,	"Directory '%s' doesn't exist."
 	Customunixdirview_SUnixDefaultRootName,	"/ <root>"
 	Unixdirviewcolproperties_SUnixDirViewRightsCol,	"Rights"
@@ -636,8 +634,6 @@ BEGIN
 	Unixdirviewcolproperties_SUnixDirViewGroupCol,	"Group"
 	Unixdirviewcolproperties_SUnixDirViewLinkTargetCol,	"Link target"
 	Unixdirviewcolproperties_SUnixDirViewTypeCol,	"Type"
-	Iepathcombobox_SSpecialFolderMyDocuments,	"My documents"
-	Iepathcombobox_SSpecialFolderDesktop,	"Desktop"
 	Customdriveview_SDragDropError,	"Drag&drop error: %d"
 	Morebutton_SDefaultExpandedCaption,	"<< &Less"
 	Morebutton_SDefaultCollapsedCaption,	"&More >>"
@@ -645,6 +641,8 @@ BEGIN
 	Comboedit_SDefaultFilter,	"All files (*.*)|*.*"
 	Comboedit_SInvalidFileName,	"Invalid file name - %s"
 	Tcpip_SSocketError,	"Error creating socket (%s)"
+	Tcpip_SUnknownSockError,	"Unknown error"
+	Tcpip_SHttpError,	"Received response %d %s from %s"
 	Dirviewcolproperties_SDirViewSizeCol,	"Size"
 	Dirviewcolproperties_SDirViewTypeCol,	"Type"
 	Dirviewcolproperties_SDirViewChangedCol,	"Changed"

+ 6 - 6
WinSCP.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 4,0,7,370
-PRODUCTVERSION 4,0,7,370
+FILEVERSION 4,1,0,375
+PRODUCTVERSION 4,1,0,375
 FILEOS 0x4
 FILETYPE 0x1
 {
@@ -9,14 +9,14 @@ FILETYPE 0x1
         BLOCK "040904E4"
         {
             VALUE "CompanyName", "Martin Prikryl\0"
-            VALUE "FileDescription", "Windows SFTP, FTP and SCP client\0"
-            VALUE "FileVersion", "4.0.7.370\0"
+            VALUE "FileDescription", "SFTP, FTP and SCP client\0"
+            VALUE "FileVersion", "4.1.0.375\0"
             VALUE "InternalName", "winscp\0"
             VALUE "LegalCopyright", "(c) 2000-2008 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
-            VALUE "OriginalFilename", "winscp407.exe\0"
+            VALUE "OriginalFilename", "winscp410.exe\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.0.7.0\0"
+            VALUE "ProductVersion", "4.1.0.0\0"
             VALUE "WWW", "http://winscp.net/\0"
         }
     }

+ 1 - 1
components/UnixDirView.h

@@ -104,7 +104,6 @@ __published:
     { read=FShowInaccesibleDirectories, write=SetShowInaccesibleDirectories,
       default=true  };
 
-  __property PathComboBox;
   __property OnUpdateStatusBar;
   __property PathLabel;
   __property LoadAnimation;
@@ -148,6 +147,7 @@ __published:
   __property OnBeginRename;
   __property OnEndRename;
   __property OnHistoryChange;
+  __property OnPathChange;
 
   __property ColumnClick;
   __property MultiSelect;

+ 0 - 129
components/UnixPathComboBox.cpp

@@ -1,129 +0,0 @@
-//---------------------------------------------------------------------------
-#include <vcl.h>
-#pragma hdrstop
-
-#include "UnixPathComboBox.h"
-
-#ifndef DESIGN_ONLY
-#include <RemoteFiles.h>
-#endif
-
-#include <Common.h>
-
-#include <CustomUnixDirView.hpp>
-#pragma package(smart_init)
-//---------------------------------------------------------------------------
-// ValidCtrCheck is used to assure that the components created do not have
-// any pure virtual functions.
-static inline void ValidCtrCheck(TUnixPathComboBox *)
-{
-  new TUnixPathComboBox(NULL);
-}
-//---------------------------------------------------------------------------
-namespace Unixpathcombobox
-{
-  void __fastcall PACKAGE Register()
-  {
-    TComponentClass classes[1] = {__classid(TUnixPathComboBox)};
-    RegisterComponents("Scp", classes, 0);
-  }
-}
-//---------------------------------------------------------------------------
-// TUnixPathComboBox
-//---------------------------------------------------------------------------
-__fastcall TUnixPathComboBox::TUnixPathComboBox(TComponent* Owner)
-        : TCustomPathComboBox(Owner)
-{
-  UseSystemImageList = True;
-  FRootName = Customunixdirview_SUnixDefaultRootName;
-  FPath = '/';
-  ResetItemHeight();
-}
-//---------------------------------------------------------------------------
-Integer __fastcall TUnixPathComboBox::GetItemImage(Integer Index)
-{
-  return (Index < Items->Count-1 ? StdDirIcon : StdDirSelIcon);
-}
-//---------------------------------------------------------------------------
-Integer __fastcall TUnixPathComboBox::GetItemIndent(Integer Index)
-{
-  return (10 * Index);
-}
-//---------------------------------------------------------------------------
-void __fastcall TUnixPathComboBox::SetRootName(AnsiString value)
-{
-  if (FRootName != value)
-  {
-    FRootName = value;
-    ResetItems();
-  }
-}
-//---------------------------------------------------------------------------
-Boolean __fastcall TUnixPathComboBox::IsRootNameStored()
-{
-  return (FRootName != Customunixdirview_SUnixDefaultRootName);
-}
-//---------------------------------------------------------------------------
-void __fastcall TUnixPathComboBox::ResetItems()
-{
-#ifndef DESIGN_ONLY
-  Items->BeginUpdate();
-  try {
-    Items->Clear();
-    AnsiString APath = UnixExcludeTrailingBackslash(Path);
-    while (!IsUnixRootPath(APath))
-    {
-      Integer P = APath.LastDelimiter('/');
-      assert(P >= 0);
-      Items->Insert(0, APath.SubString(P + 1, APath.Length() - P));
-      APath.SetLength(P - 1);
-    }
-    Items->Insert(0, RootName);
-  } __finally {
-    ItemIndex = Items->Count - 1;
-    Items->EndUpdate();
-  }
-#endif
-}
-//---------------------------------------------------------------------------
-void __fastcall TUnixPathComboBox::CreateWnd()
-{
-  TCustomPathComboBox::CreateWnd();
-  ResetItems();
-}
-//---------------------------------------------------------------------------
-void __fastcall TUnixPathComboBox::SetPath(AnsiString Value)
-{
-#ifndef DESIGN_ONLY
-  if (!Value.IsEmpty())
-  {
-    Value = UnixIncludeTrailingBackslash(Value);
-    if (Value != FPath)
-    {
-      FPath = Value;
-      ResetItems();
-    }
-  }
-#endif
-}
-//---------------------------------------------------------------------------
-void __fastcall TUnixPathComboBox::PathChanged()
-{
-#ifndef DESIGN_ONLY
-  AnsiString APath = UnixExcludeTrailingBackslash(Path);
-  for (int Index = ItemIndex; Index < Items->Count - 1; Index++)
-  {
-    APath = UnixExtractFileDir(APath);
-  }
-  // VanDyke style paths
-  if (APath.IsEmpty())
-  {
-    assert(ItemIndex == 0);
-    APath = ROOTDIRECTORY;
-  }
-  Path = APath;
-  TCustomPathComboBox::PathChanged();
-  // in case that path was not changed (e.g. inaccessible directory)
-  Path = ((TCustomDirView*)DirView)->Path;
-#endif
-}

+ 0 - 74
components/UnixPathComboBox.h

@@ -1,74 +0,0 @@
-//---------------------------------------------------------------------------
-#ifndef UnixPathComboBoxH
-#define UnixPathComboBoxH
-//---------------------------------------------------------------------------
-#include <SysUtils.hpp>
-#include <Controls.hpp>
-#include <Classes.hpp>
-#include <Forms.hpp>
-
-#include <CustomPathComboBox.hpp>
-//---------------------------------------------------------------------------
-class PACKAGE TUnixPathComboBox : public TCustomPathComboBox
-{
-private:
-  AnsiString FRootName;
-  Boolean __fastcall IsRootNameStored();
-  void __fastcall SetRootName(AnsiString value);
-protected:
-  virtual void __fastcall CreateWnd();
-  virtual Integer __fastcall GetItemImage(Integer Index);
-  virtual Integer __fastcall GetItemIndent(Integer Index);
-  virtual void __fastcall PathChanged();
-  void __fastcall ResetItems();
-  virtual void __fastcall SetPath(AnsiString Value);
-public:
-  __fastcall TUnixPathComboBox(TComponent* Owner);
-__published:
-  __property AnsiString RootName = { read = FRootName, write = SetRootName, stored = IsRootNameStored };
-
-  __property OnCloseUp;
-
-  __property Align;
-  __property Anchors;
-  __property BiDiMode;
-  __property Color;
-  __property Constraints;
-  __property Ctl3D;
-  __property DragCursor;
-  __property DragKind;
-  __property DragMode;
-  __property DropDownCount;
-  __property Enabled;
-  __property Font;
-  __property ImeMode;
-  __property ImeName;
-  __property ParentBiDiMode;
-  __property ParentColor;
-  __property ParentCtl3D;
-  __property ParentFont;
-  __property ParentShowHint;
-  __property PopupMenu;
-  __property ShowHint;
-  __property TabOrder;
-  __property TabStop;
-  __property Visible;
-  __property OnChange;
-  __property OnClick;
-  __property OnDblClick;
-  __property OnDragDrop;
-  __property OnDragOver;
-  __property OnDrawItem;
-  __property OnDropDown;
-  __property OnEndDock;
-  __property OnEndDrag;
-  __property OnEnter;
-  __property OnExit;
-  __property OnKeyDown;
-  __property OnKeyPress;
-  __property OnKeyUp;
-  __property OnStartDock;
-  __property OnStartDrag;
-};
-//---------------------------------------------------------------------------
-#endif

+ 10 - 7
console/Console.h

@@ -11,12 +11,14 @@ struct TConsoleCommStruct
 {
   enum TVersion
   {
-    Version0 = 0,
-    Version1 = 1,
-    Version2 = 2,
-    CurrentVersion = Version2,
-    MinVersion = Version0,
-    MaxVersion = CurrentVersion
+    CurrentVersion =          0x0003,
+    CurrentVersionConfirmed = 0x0103
+  };
+
+  struct TInitEvent
+  {
+    unsigned int InputType;
+    unsigned int OutputType;
   };
 
   struct TPrintEvent
@@ -50,13 +52,14 @@ struct TConsoleCommStruct
 
   size_t Size;
   int Version;
-  enum { NONE, PRINT, INPUT, CHOICE, TITLE } Event;
+  enum { NONE, PRINT, INPUT, CHOICE, TITLE, INIT } Event;
   union
   {
     TPrintEvent PrintEvent;
     TInputEvent InputEvent;
     TChoiceEvent ChoiceEvent;
     TTitleEvent TitleEvent;
+    TInitEvent InitEvent;
   };
 };
 //---------------------------------------------------------------------------

+ 23 - 16
console/Main.cpp

@@ -95,9 +95,7 @@ void InitializeConsole(int& InstanceNumber, HANDLE& RequestEvent, HANDLE& Respon
 
   TConsoleCommStruct* CommStruct = GetCommStruct(FileMapping);
   CommStruct->Size = sizeof(TConsoleCommStruct);
-  // if the application keeps version 1, it means that is actually supports
-  // version 0 only, otherwise it is obligated to upgrade version to at least 2
-  CommStruct->Version = TConsoleCommStruct::Version1;
+  CommStruct->Version = TConsoleCommStruct::CurrentVersion;
   CommStruct->Event = TConsoleCommStruct::NONE;
   FreeCommStruct(CommStruct);
 }
@@ -270,7 +268,7 @@ DWORD WINAPI InputTimerThreadProc(void * Parameter)
   return 0;
 }
 //---------------------------------------------------------------------------
-void ProcessInputEvent(TConsoleCommStruct::TInputEvent& Event, int Version)
+void ProcessInputEvent(TConsoleCommStruct::TInputEvent& Event)
 {
   if ((InputType == FILE_TYPE_DISK) || (InputType == FILE_TYPE_PIPE))
   {
@@ -311,11 +309,10 @@ void ProcessInputEvent(TConsoleCommStruct::TInputEvent& Event, int Version)
     SetConsoleMode(ConsoleInput, NewMode);
 
     HANDLE InputTimerThread = NULL;
-    bool SupportTimer = (Version >= TConsoleCommStruct::Version2);
 
     try
     {
-      if (SupportTimer && (Event.Timer > 0))
+      if (Event.Timer > 0)
       {
         unsigned long ThreadId;
         InputTimerEvent = CreateEvent(NULL, false, false, NULL);
@@ -353,7 +350,7 @@ void ProcessInputEvent(TConsoleCommStruct::TInputEvent& Event, int Version)
   }
 }
 //---------------------------------------------------------------------------
-void ProcessChoiceEvent(TConsoleCommStruct::TChoiceEvent& Event, int Version)
+void ProcessChoiceEvent(TConsoleCommStruct::TChoiceEvent& Event)
 {
   if ((InputType == FILE_TYPE_DISK) || (InputType == FILE_TYPE_PIPE))
   {
@@ -368,12 +365,7 @@ void ProcessChoiceEvent(TConsoleCommStruct::TChoiceEvent& Event, int Version)
     NewMode = (PrevMode | ENABLE_PROCESSED_INPUT) & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
     SetConsoleMode(ConsoleInput, NewMode);
 
-    bool SupportTimer = (Version >= TConsoleCommStruct::Version2);
-    unsigned int ATimer;
-    if (SupportTimer)
-    {
-      ATimer = Event.Timer;
-    }
+    unsigned int ATimer = Event.Timer;
 
     try
     {
@@ -420,7 +412,7 @@ void ProcessChoiceEvent(TConsoleCommStruct::TChoiceEvent& Event, int Version)
         {
           unsigned int TimerSlice = 50;
           Sleep(TimerSlice);
-          if (SupportTimer && (Event.Timer > 0))
+          if (Event.Timer > 0)
           {
             if (ATimer > TimerSlice)
             {
@@ -450,11 +442,22 @@ inline void ProcessTitleEvent(TConsoleCommStruct::TTitleEvent& Event)
   SetConsoleTitle(Event.Title);
 }
 //---------------------------------------------------------------------------
+inline void ProcessInitEvent(TConsoleCommStruct::TInitEvent& Event)
+{
+  Event.InputType = InputType;
+  Event.OutputType = OutputType;
+}
+//---------------------------------------------------------------------------
 void ProcessEvent(HANDLE ResponseEvent, HANDLE FileMapping)
 {
   TConsoleCommStruct* CommStruct = GetCommStruct(FileMapping);
   try
   {
+    if (CommStruct->Version != TConsoleCommStruct::CurrentVersionConfirmed)
+    {
+      throw logic_error("Incompatible console protocol version");
+    }
+
     switch (CommStruct->Event)
     {
       case TConsoleCommStruct::PRINT:
@@ -462,17 +465,21 @@ void ProcessEvent(HANDLE ResponseEvent, HANDLE FileMapping)
         break;
 
       case TConsoleCommStruct::INPUT:
-        ProcessInputEvent(CommStruct->InputEvent, CommStruct->Version);
+        ProcessInputEvent(CommStruct->InputEvent);
         break;
 
       case TConsoleCommStruct::CHOICE:
-        ProcessChoiceEvent(CommStruct->ChoiceEvent, CommStruct->Version);
+        ProcessChoiceEvent(CommStruct->ChoiceEvent);
         break;
 
       case TConsoleCommStruct::TITLE:
         ProcessTitleEvent(CommStruct->TitleEvent);
         break;
 
+      case TConsoleCommStruct::INIT:
+        ProcessInitEvent(CommStruct->InitEvent);
+        break;
+
       default:
         throw logic_error("Unknown event");
     }

+ 95 - 4
core/Common.cpp

@@ -1,4 +1,5 @@
 //---------------------------------------------------------------------------
+#define NO_WIN32_LEAN_AND_MEAN
 #include <vcl.h>
 #pragma hdrstop
 
@@ -8,7 +9,7 @@
 #include "Interface.h"
 #include <StrUtils.hpp>
 #include <math.h>
-#include <shellapi.h>
+#include <shfolder.h>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
@@ -268,6 +269,26 @@ AnsiString __fastcall SystemTemporaryDirectory()
   return TempDir;
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall GetShellFolderPath(int CSIdl)
+{
+  AnsiString Result;
+  HMODULE Shell32Lib = LoadLibrary("SHELL32.DLL");
+  if (Shell32Lib != NULL)
+  {
+    PFNSHGETFOLDERPATH SHGetFolderPath = (PFNSHGETFOLDERPATH)
+      GetProcAddress(Shell32Lib, "SHGetFolderPathA");
+    if (SHGetFolderPath != NULL)
+    {
+      char Path[2 * MAX_PATH + 10] = "\0";
+      if (SUCCEEDED(SHGetFolderPath(NULL, CSIdl, NULL, SHGFP_TYPE_CURRENT, Path)))
+      {
+        Result = Path;
+      }
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 AnsiString __fastcall StripPathQuotes(const AnsiString Path)
 {
   if ((Path.Length() >= 2) &&
@@ -456,8 +477,8 @@ AnsiString __fastcall HexToStr(const AnsiString Hex)
   {
     for (int i = 1; i <= Hex.Length(); i += 2)
     {
-      P1 = Digits.Pos(Hex[i]);
-      P2 = Digits.Pos(Hex[i + 1]);
+      P1 = Digits.Pos((char)toupper(Hex[i]));
+      P2 = Digits.Pos((char)toupper(Hex[i + 1]));
       if (P1 <= 0 || P2 <= 0)
       {
         Result = "";
@@ -479,7 +500,7 @@ unsigned int __fastcall HexToInt(const AnsiString Hex, int MinChars)
   int I = 1;
   while (I <= Hex.Length())
   {
-    int A = Digits.Pos(Hex[I]);
+    int A = Digits.Pos((char)toupper(Hex[I]));
     if (A <= 0)
     {
       if ((MinChars < 0) || (I <= MinChars))
@@ -496,6 +517,11 @@ unsigned int __fastcall HexToInt(const AnsiString Hex, int MinChars)
   return Result;
 }
 //---------------------------------------------------------------------------
+char __fastcall HexToChar(const AnsiString Hex)
+{
+  return (char)HexToInt(Hex);
+}
+//---------------------------------------------------------------------------
 bool __fastcall FileSearchRec(const AnsiString FileName, TSearchRec & Rec)
 {
   int FindAttrs = faReadOnly | faHidden | faSysFile | faDirectory | faArchive;
@@ -1156,3 +1182,68 @@ void __fastcall AnsiToOem(AnsiString & Str)
     CharToOem(Str.c_str(), Str.c_str());
   }
 }
+//---------------------------------------------------------------------------
+AnsiString __fastcall EscapeHotkey(const AnsiString & Caption)
+{
+  return StringReplace(Caption, "&", "&&", TReplaceFlags() << rfReplaceAll);
+}
+//---------------------------------------------------------------------------
+bool __fastcall CutToken(AnsiString & Str, AnsiString & Token)
+{
+  bool Result;
+
+  Token = "";
+
+  // inspired by Putty's sftp_getcmd() from PSFTP.C
+  int Index = 1;
+  while ((Index <= Str.Length()) &&
+    ((Str[Index] == ' ') || (Str[Index] == '\t')))
+  {
+    Index++;
+  }
+
+  if (Index <= Str.Length())
+  {
+    bool Quoting = false;
+
+    while (Index <= Str.Length())
+    {
+      if (!Quoting && ((Str[Index] == ' ') || (Str[Index] == '\t')))
+      {
+        break;
+      }
+      else if ((Str[Index] == '"') && (Index + 1 <= Str.Length()) &&
+        (Str[Index + 1] == '"'))
+      {
+        Index += 2;
+        Token += '"';
+      }
+      else if (Str[Index] == '"')
+      {
+        Index++;
+        Quoting = !Quoting;
+      }
+      else
+      {
+        Token += Str[Index];
+        Index++;
+      }
+    }
+
+    if (Index <= Str.Length())
+    {
+      Index++;
+    }
+
+    Str = Str.SubString(Index, Str.Length());
+
+    Result = true;
+  }
+  else
+  {
+    Result = false;
+    Str = "";
+  }
+
+  return Result;
+}

+ 4 - 0
core/Common.h

@@ -39,6 +39,7 @@ void __fastcall AnsiToOem(AnsiString & Str);
 AnsiString ExceptionLogString(Exception *E);
 bool IsDots(const AnsiString Str);
 AnsiString __fastcall SystemTemporaryDirectory();
+AnsiString __fastcall GetShellFolderPath(int CSIdl);
 AnsiString __fastcall StripPathQuotes(const AnsiString Path);
 AnsiString __fastcall AddPathQuotes(AnsiString Path);
 void __fastcall SplitCommand(AnsiString Command, AnsiString &Program,
@@ -56,6 +57,7 @@ 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);
+char __fastcall HexToChar(const AnsiString Hex);
 AnsiString __fastcall DecodeUrlChars(AnsiString S);
 AnsiString __fastcall EncodeUrlChars(AnsiString S, AnsiString Ignore = "");
 bool __fastcall RecursiveDeleteFile(const AnsiString FileName, bool ToRecycleBin);
@@ -64,6 +66,8 @@ int __fastcall AbortAnswer(int Answers);
 int __fastcall ContinueAnswer(int Answers);
 AnsiString __fastcall LoadStr(int Ident, unsigned int MaxLength);
 AnsiString __fastcall LoadStrPart(int Ident, int Part);
+AnsiString __fastcall EscapeHotkey(const AnsiString & Caption);
+bool __fastcall CutToken(AnsiString & Str, AnsiString & Token);
 struct TPasLibModule;
 TPasLibModule * __fastcall FindModule(void * Instance);
 //---------------------------------------------------------------------------

+ 61 - 33
core/Configuration.cpp

@@ -11,6 +11,7 @@
 #include "TextsCore.h"
 #include "Interface.h"
 #include "CoreMain.h"
+#include <shfolder.h>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
@@ -21,16 +22,23 @@ __fastcall TConfiguration::TConfiguration()
   FStorage = stDetect;
   FDontSave = false;
   FApplicationInfo = NULL;
-  FInitialized = false;
-}
-//---------------------------------------------------------------------------
-void __fastcall TConfiguration::Initialize()
-{
-  AnsiString ARandomSeedFile = seedpath_ptr();
-  FDefaultRandomSeedFile = StringReplace(ExtractFilePath(ARandomSeedFile) +
-    "winscp" + ExtractFileExt(ARandomSeedFile), "\\\\", "\\",
-    TReplaceFlags() << rfReplaceAll);
-  FInitialized = true;
+
+  char Buf[10];
+  AnsiString RandomSeedPath;
+  if (GetEnvironmentVariable("APPDATA", Buf, sizeof(Buf)) > 0)
+  {
+    RandomSeedPath = "%APPDATA%";
+  }
+  else
+  {
+    RandomSeedPath = GetShellFolderPath(CSIDL_LOCAL_APPDATA);
+    if (RandomSeedPath.IsEmpty())
+    {
+      RandomSeedPath = GetShellFolderPath(CSIDL_APPDATA);
+    }
+  }
+
+  FDefaultRandomSeedFile = IncludeTrailingBackslash(RandomSeedPath) + "winscp.rnd";
 }
 //---------------------------------------------------------------------------
 void __fastcall TConfiguration::Default()
@@ -44,8 +52,9 @@ void __fastcall TConfiguration::Default()
   FAutoReadDirectoryAfterOp = true;
   FSessionReopenAuto = 5000;
   FSessionReopenBackground = 2000;
-  FTunnelLocalPortNumberLow = 6000;
-  FTunnelLocalPortNumberHigh = 6100;
+  FTunnelLocalPortNumberLow = 50000;
+  FTunnelLocalPortNumberHigh = 50099;
+  FCacheDirectoryChangesMaxSize = 100;
   FShowFtpWelcomeMessage = false;
 
   FLogging = false;
@@ -98,6 +107,7 @@ THierarchicalStorage * TConfiguration::CreateScpStorage(bool /*SessionList*/)
     KEY(Integer,  SessionReopenBackground); \
     KEY(Integer,  TunnelLocalPortNumberLow); \
     KEY(Integer,  TunnelLocalPortNumberHigh); \
+    KEY(Integer,  CacheDirectoryChangesMaxSize); \
     KEY(Bool,     ShowFtpWelcomeMessage); \
   ); \
   BLOCK("Logging", CANCREATE, \
@@ -476,10 +486,12 @@ void __fastcall TConfiguration::CleanupRandomSeedFile()
   try
   {
     DontSaveRandomSeed();
-    AnsiString ExpandedRandomSeedFile = ExpandEnvironmentVariables(RandomSeedFile);
-    if (FileExists(ExpandedRandomSeedFile))
+    if (FileExists(RandomSeedFileName))
     {
-      if (!DeleteFile(ExpandedRandomSeedFile)) Abort();
+      if (!DeleteFile(RandomSeedFileName))
+      {
+        RaiseLastOSError();
+      }
     }
   }
   catch (Exception &E)
@@ -494,7 +506,10 @@ void __fastcall TConfiguration::CleanupIniFile()
   {
     if (FileExists(IniFileStorageName))
     {
-      if (!DeleteFile(IniFileStorageName)) Abort();
+      if (!DeleteFile(IniFileStorageName))
+      {
+        RaiseLastOSError();
+      }
     }
     if (Storage == stIniFile)
     {
@@ -599,11 +614,12 @@ AnsiString __fastcall TConfiguration::GetVersionStr()
   TGuard Guard(FCriticalSection);
   try
   {
-    return FmtLoadStr(VERSION, ARRAYOFCONST((
-      HIWORD(FixedApplicationInfo->dwFileVersionMS),
-      LOWORD(FixedApplicationInfo->dwFileVersionMS),
-      HIWORD(FixedApplicationInfo->dwFileVersionLS),
-      LOWORD(FixedApplicationInfo->dwFileVersionLS))));
+    TVSFixedFileInfo * Info = FixedApplicationInfo;
+    return FMTLOAD(VERSION, (
+      HIWORD(Info->dwFileVersionMS),
+      LOWORD(Info->dwFileVersionMS),
+      HIWORD(Info->dwFileVersionLS),
+      LOWORD(Info->dwFileVersionLS)));
   }
   catch (Exception &E)
   {
@@ -616,11 +632,12 @@ AnsiString __fastcall TConfiguration::GetVersion()
   TGuard Guard(FCriticalSection);
   try
   {
+    TVSFixedFileInfo * Info = FixedApplicationInfo;
     AnsiString Result;
     Result = TrimVersion(FORMAT("%d.%d.%d", (
-      HIWORD(FixedApplicationInfo->dwFileVersionMS),
-      LOWORD(FixedApplicationInfo->dwFileVersionMS),
-      HIWORD(FixedApplicationInfo->dwFileVersionLS))));
+      HIWORD(Info->dwFileVersionMS),
+      LOWORD(Info->dwFileVersionMS),
+      HIWORD(Info->dwFileVersionLS))));
     return Result;
   }
   catch (Exception &E)
@@ -768,25 +785,31 @@ void __fastcall TConfiguration::SetRandomSeedFile(AnsiString value)
 {
   if (RandomSeedFile != value)
   {
+    AnsiString PrevRandomSeedFileName = RandomSeedFileName;
+
+    FRandomSeedFile = value;
+
     // never allow empty seed file to avoid Putty trying to reinitialize the path
-    if (value.Trim().IsEmpty())
+    if (RandomSeedFileName.IsEmpty())
     {
       FRandomSeedFile = FDefaultRandomSeedFile;
     }
-    else
-    {
-      FRandomSeedFile = value;
-    }
 
-    char *seedpath = seedpath_ptr();
-    if (value.Length() >= seedpath_size())
+    if (!PrevRandomSeedFileName.IsEmpty() &&
+        (PrevRandomSeedFileName != RandomSeedFileName) &&
+        FileExists(PrevRandomSeedFileName))
     {
-      value.SetLength(seedpath_size() - 1);
+      // ignore any error
+      DeleteFile(PrevRandomSeedFileName);
     }
-    strcpy(seedpath, StripPathQuotes(ExpandEnvironmentVariables(FRandomSeedFile)).c_str());
   }
 }
 //---------------------------------------------------------------------
+AnsiString __fastcall TConfiguration::GetRandomSeedFileName()
+{
+  return StripPathQuotes(ExpandEnvironmentVariables(FRandomSeedFile)).Trim();
+}
+//---------------------------------------------------------------------
 void __fastcall TConfiguration::SetPuttyRegistryStorageKey(AnsiString value)
 {
   SET_CONFIG_PROPERTY(PuttyRegistryStorageKey);
@@ -952,6 +975,11 @@ void __fastcall TConfiguration::SetTunnelLocalPortNumberHigh(int value)
   SET_CONFIG_PROPERTY(TunnelLocalPortNumberHigh);
 }
 //---------------------------------------------------------------------------
+void __fastcall TConfiguration::SetCacheDirectoryChangesMaxSize(int value)
+{
+  SET_CONFIG_PROPERTY(CacheDirectoryChangesMaxSize);
+}
+//---------------------------------------------------------------------------
 void __fastcall TConfiguration::SetShowFtpWelcomeMessage(bool value)
 {
   SET_CONFIG_PROPERTY(ShowFtpWelcomeMessage);

+ 5 - 4
core/Configuration.h

@@ -16,12 +16,10 @@ class TCriticalSection;
 class TConfiguration : public TObject
 {
 private:
-  bool FInitialized;
   bool FDontSave;
   bool FChanged;
   int FUpdating;
   TNotifyEvent FOnChange;
-  bool FRandomSeedSave;
 
   void * FApplicationInfo;
   bool FLogging;
@@ -39,6 +37,7 @@ private:
   AnsiString FIniFileStorageName;
   int FTunnelLocalPortNumberLow;
   int FTunnelLocalPortNumberHigh;
+  int FCacheDirectoryChangesMaxSize;
   bool FShowFtpWelcomeMessage;
   AnsiString FDefaultRandomSeedFile;
   AnsiString FRandomSeedFile;
@@ -60,6 +59,7 @@ private:
   AnsiString __fastcall GetStoredSessionsSubKey();
   AnsiString __fastcall GetPuttySessionsKey();
   void __fastcall SetRandomSeedFile(AnsiString value);
+  AnsiString __fastcall GetRandomSeedFileName();
   void __fastcall SetPuttyRegistryStorageKey(AnsiString value);
   AnsiString __fastcall GetSshHostKeysSubKey();
   AnsiString __fastcall GetRootKeyStr();
@@ -88,6 +88,7 @@ private:
   void __fastcall SetSessionReopenBackground(int value);
   void __fastcall SetTunnelLocalPortNumberLow(int value);
   void __fastcall SetTunnelLocalPortNumberHigh(int value);
+  void __fastcall SetCacheDirectoryChangesMaxSize(int value);
   void __fastcall SetShowFtpWelcomeMessage(bool value);
 
 protected:
@@ -128,7 +129,6 @@ protected:
 public:
   __fastcall TConfiguration();
   virtual __fastcall ~TConfiguration();
-  void __fastcall Initialize();
   virtual void __fastcall Default();
   virtual void __fastcall Load();
   virtual void __fastcall Save(bool All, bool Explicit);
@@ -148,13 +148,13 @@ public:
   virtual THierarchicalStorage * CreateScpStorage(bool SessionList);
   void __fastcall TemporaryLogging(const AnsiString ALogFileName);
 
-  __property bool Initialized = { read = FInitialized };
   __property TVSFixedFileInfo *FixedApplicationInfo  = { read=GetFixedApplicationInfo };
   __property void * ApplicationInfo  = { read=GetApplicationInfo };
   __property AnsiString StoredSessionsSubKey = {read=GetStoredSessionsSubKey};
   __property AnsiString PuttyRegistryStorageKey  = { read=FPuttyRegistryStorageKey, write=SetPuttyRegistryStorageKey };
   __property AnsiString PuttySessionsKey  = { read=GetPuttySessionsKey };
   __property AnsiString RandomSeedFile  = { read=FRandomSeedFile, write=SetRandomSeedFile };
+  __property AnsiString RandomSeedFileName  = { read=GetRandomSeedFileName };
   __property AnsiString SshHostKeysSubKey  = { read=GetSshHostKeysSubKey };
   __property AnsiString RootKeyStr  = { read=GetRootKeyStr };
   __property AnsiString ConfigurationSubKey  = { read=GetConfigurationSubKey };
@@ -184,6 +184,7 @@ public:
   __property int SessionReopenBackground = { read = FSessionReopenBackground, write = SetSessionReopenBackground };
   __property int TunnelLocalPortNumberLow = { read = FTunnelLocalPortNumberLow, write = SetTunnelLocalPortNumberLow };
   __property int TunnelLocalPortNumberHigh = { read = FTunnelLocalPortNumberHigh, write = SetTunnelLocalPortNumberHigh };
+  __property int CacheDirectoryChangesMaxSize = { read = FCacheDirectoryChangesMaxSize, write = SetCacheDirectoryChangesMaxSize };
   __property bool ShowFtpWelcomeMessage = { read = FShowFtpWelcomeMessage, write = SetShowFtpWelcomeMessage };
 
   __property AnsiString TimeFormat = { read = GetTimeFormat };

+ 72 - 7
core/CopyParam.cpp

@@ -25,7 +25,7 @@ void __fastcall TCopyParamType::Default()
 {
   // when changing defaults, make sure GetInfoStr() can handle it
   FileNameCase = ncNoChange;
-  PreserveReadOnly = true;
+  PreserveReadOnly = false;
   PreserveTime = true;
   Rights.Number = TRights::rfDefault;
   PreserveRights = false; // Was True until #106
@@ -35,7 +35,7 @@ void __fastcall TCopyParamType::Default()
   TransferMode = tmAutomatic;
   AddXToDirectories = true;
   ResumeSupport = rsSmart;
-  ResumeThreshold = 100 * 1024; // (100 kB)
+  ResumeThreshold = 100 * 1024; // (100 KiB)
   InvalidCharsReplacement = TokenReplacement;
   LocalInvalidChars = "/\\:*?\"<>|";
   CalculateSize = true;
@@ -43,6 +43,7 @@ void __fastcall TCopyParamType::Default()
   ExcludeFileMask.Masks = "";
   NegativeExclude = false;
   ClearArchive = false;
+  CPSLimit = 0;
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TCopyParamType::GetInfoStr(AnsiString Separator, int Options) const
@@ -128,10 +129,10 @@ AnsiString __fastcall TCopyParamType::GetInfoStr(AnsiString Separator, int Optio
 
   if (PreserveReadOnly != Defaults.PreserveReadOnly)
   {
-    assert(!PreserveReadOnly);
-    if (!PreserveReadOnly)
+    assert(PreserveReadOnly);
+    if (PreserveReadOnly)
     {
-      ADD(LoadStr(COPY_INFO_DONT_PRESERVE_READONLY),
+      ADD(LoadStr(COPY_INFO_PRESERVE_READONLY),
         cpaExcludeMaskOnly | cpaNoPreserveReadOnly);
     }
   }
@@ -163,6 +164,11 @@ AnsiString __fastcall TCopyParamType::GetInfoStr(AnsiString Separator, int Optio
       cpaNoExcludeMask);
   }
 
+  if (CPSLimit > 0)
+  {
+    ADD(FMTLOAD(COPY_INFO_CPS_LIMIT, (int(CPSLimit))), cpaExcludeMaskOnly);
+  }
+
   if (SomeAttrExcluded)
   {
     Result += (Result.IsEmpty() ? AnsiString() : Separator) +
@@ -200,6 +206,7 @@ void __fastcall TCopyParamType::Assign(const TCopyParamType * Source)
   COPY(ExcludeFileMask);
   COPY(NegativeExclude);
   COPY(ClearArchive);
+  COPY(CPSLimit);
   #undef COPY
 }
 //---------------------------------------------------------------------------
@@ -252,7 +259,7 @@ char * __fastcall TCopyParamType::ReplaceChar(AnsiString & FileName, char * Inva
   {
     InvalidChar++;
   }
-  return InvalidChar; 
+  return InvalidChar;
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TCopyParamType::ValidLocalFileName(AnsiString FileName) const
@@ -277,6 +284,56 @@ AnsiString __fastcall TCopyParamType::ValidLocalFileName(AnsiString FileName) co
   return FileName;
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall TCopyParamType::RestoreChars(AnsiString FileName) const
+{
+  if (InvalidCharsReplacement == TokenReplacement)
+  {
+    char * InvalidChar = FileName.c_str();
+    while ((InvalidChar = strchr(InvalidChar, TokenPrefix)) != NULL)
+    {
+      int Index = InvalidChar - FileName.c_str() + 1;
+      if ((FileName.Length() >= Index + 2) &&
+          (FileName.ByteType(Index) == mbSingleByte) &&
+          (FileName.ByteType(Index + 1) == mbSingleByte) &&
+          (FileName.ByteType(Index + 2) == mbSingleByte))
+      {
+        char Char = HexToChar(FileName.SubString(Index + 1, 2));
+        if ((Char != '\0') &&
+            ((FTokenizibleChars.Pos(Char) > 0) ||
+             ((Char == ' ') && (Index == FileName.Length() - 2))))
+        {
+          FileName[Index] = Char;
+          FileName.Delete(Index + 1, 2);
+          InvalidChar = FileName.c_str() + Index;
+        }
+        else
+        {
+          InvalidChar++;
+        }
+      }
+      else
+      {
+        InvalidChar++;
+      }
+    }
+  }
+  return FileName;
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall TCopyParamType::ValidLocalPath(AnsiString Path) const
+{
+  AnsiString Result;
+  while (!Path.IsEmpty())
+  {
+    if (!Result.IsEmpty())
+    {
+      Result += "\\";
+    }
+    Result += ValidLocalFileName(CutToChar(Path, '\\', false));
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 // not used yet
 AnsiString __fastcall TCopyParamType::Untokenize(AnsiString FileName)
 {
@@ -336,6 +393,10 @@ AnsiString __fastcall TCopyParamType::ChangeFileName(AnsiString FileName,
   {
     FileName = ValidLocalFileName(FileName);
   }
+  else
+  {
+    FileName = RestoreChars(FileName);
+  }
   return FileName;
 }
 //---------------------------------------------------------------------------
@@ -367,7 +428,7 @@ AnsiString __fastcall TCopyParamType::GetLogStr() const
   return FORMAT(
     "  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"
+    "  TM: %s; ClAr: %s; CPS: %u; ExclM(%s): %s\n"
     "  AscM: %s\n",
     (BooleanToEngStr(PreserveTime),
      BooleanToEngStr(PreserveReadOnly),
@@ -382,6 +443,7 @@ AnsiString __fastcall TCopyParamType::GetLogStr() const
      FileMask,
      ModeC[TransferMode],
      BooleanToEngStr(ClearArchive),
+     int(CPSLimit),
      BooleanToEngStr(NegativeExclude),
      ExcludeFileMask.Masks,
      AsciiFileMask.Masks));
@@ -439,6 +501,7 @@ void __fastcall TCopyParamType::Load(THierarchicalStorage * Storage)
   ExcludeFileMask.Masks = Storage->ReadString("ExcludeFileMask", ExcludeFileMask.Masks);
   NegativeExclude = Storage->ReadBool("NegativeExclude", NegativeExclude);
   ClearArchive = Storage->ReadBool("ClearArchive", ClearArchive);
+  CPSLimit = Storage->ReadInteger("CPSLimit", CPSLimit);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamType::Save(THierarchicalStorage * Storage) const
@@ -460,6 +523,7 @@ void __fastcall TCopyParamType::Save(THierarchicalStorage * Storage) const
   Storage->WriteString("ExcludeFileMask", ExcludeFileMask.Masks);
   Storage->WriteBool("NegativeExclude", NegativeExclude);
   Storage->WriteBool("ClearArchive", ClearArchive);
+  Storage->WriteInteger("CPSLimit", CPSLimit);
 }
 //---------------------------------------------------------------------------
 #define C(Property) (Property == rhp.Property)
@@ -483,6 +547,7 @@ bool __fastcall TCopyParamType::operator==(const TCopyParamType & rhp) const
     C(ExcludeFileMask) &&
     C(NegativeExclude) &&
     C(ClearArchive) &&
+    C(CPSLimit) &&
     true;
 }
 #undef C

+ 4 - 0
core/CopyParam.h

@@ -50,6 +50,7 @@ private:
   TFileMasks FExcludeFileMask;
   bool FNegativeExclude;
   bool FClearArchive;
+  unsigned long FCPSLimit;
   static const char TokenPrefix = '%';
   static const char NoReplacement = char(false);
   static const char TokenReplacement = char(true);
@@ -59,6 +60,7 @@ private:
   bool __fastcall GetReplaceInvalidChars() const;
   void __fastcall SetReplaceInvalidChars(bool value);
   char * __fastcall ReplaceChar(AnsiString & FileName, char * InvalidChar) const;
+  AnsiString __fastcall RestoreChars(AnsiString FileName) const;
 
 public:
   __fastcall TCopyParamType();
@@ -75,6 +77,7 @@ public:
     const TFileMasks::TParams & Params) const;
   bool __fastcall AllowResume(__int64 Size) const;
   AnsiString __fastcall ValidLocalFileName(AnsiString FileName) const;
+  AnsiString __fastcall ValidLocalPath(AnsiString Path) const;
   bool __fastcall AllowTransfer(AnsiString FileName, TOperationSide Side,
     bool Directory, const TFileMasks::TParams & Params) const;
 
@@ -104,6 +107,7 @@ public:
   __property TFileMasks ExcludeFileMask = { read = FExcludeFileMask, write = FExcludeFileMask };
   __property bool NegativeExclude = { read = FNegativeExclude, write = FNegativeExclude };
   __property bool ClearArchive = { read = FClearArchive, write = FClearArchive };
+  __property unsigned long CPSLimit = { read = FCPSLimit, write = FCPSLimit };
 };
 //---------------------------------------------------------------------------
 #endif

+ 25 - 14
core/CoreMain.cpp

@@ -17,6 +17,11 @@
 TConfiguration * Configuration = NULL;
 TStoredSessionList * StoredSessions = NULL;
 //---------------------------------------------------------------------------
+TQueryButtonAlias::TQueryButtonAlias()
+{
+  OnClick = NULL;
+}
+//---------------------------------------------------------------------------
 TQueryParams::TQueryParams(unsigned int AParams, AnsiString AHelpKeyword)
 {
   Params = AParams;
@@ -31,19 +36,20 @@ TQueryParams::TQueryParams(unsigned int AParams, AnsiString AHelpKeyword)
   HelpKeyword = AHelpKeyword;
 }
 //---------------------------------------------------------------------------
+bool __fastcall IsAuthenticationPrompt(TPromptKind Kind)
+{
+  return
+    (Kind == pkUserName) && (Kind == pkPassphrase) && (Kind == pkTIS) &&
+    (Kind == pkCryptoCard) && (Kind == pkKeybInteractive) &&
+    (Kind == pkPassword) && (Kind == pkNewPassword);
+}
+//---------------------------------------------------------------------------
 void CoreInitialize()
 {
-  // configuration needs to be created before putty is initialized ...
+  // configuration needs to be created and loaded before putty is initialized,
+  // so that random seed path is known
   Configuration = CreateConfiguration();
 
-  PuttyInitialize();
-  #ifndef NO_FILEZILLA
-  TFileZillaIntf::Initialize();
-  #endif
-
-  // ... but some pieces of configuration can be initialized only afterwards
-  Configuration->Initialize();
-
   Randomize();
 
   try
@@ -55,6 +61,11 @@ void CoreInitialize()
     ShowExtendedException(&E);
   }
 
+  PuttyInitialize();
+  #ifndef NO_FILEZILLA
+  TFileZillaIntf::Initialize();
+  #endif
+
   StoredSessions = new TStoredSessionList();
 
   try
@@ -79,15 +90,15 @@ void CoreFinalize()
     ShowExtendedException(&E);
   }
 
-  delete StoredSessions;
-  StoredSessions = NULL;
-  delete Configuration;
-  Configuration = NULL;
-
   #ifndef NO_FILEZILLA
   TFileZillaIntf::Finalize();
   #endif
   PuttyFinalize();
+
+  delete StoredSessions;
+  StoredSessions = NULL;
+  delete Configuration;
+  Configuration = NULL;
 }
 //---------------------------------------------------------------------------
 void CoreSetResourceModule(void * ResourceHandle)

+ 18 - 15
core/FileBuffer.cpp

@@ -96,7 +96,17 @@ void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params)
 {
   assert(strlen(Source) <= 2);
   assert(strlen(Dest) <= 2);
-  bool RemoveCtrlZ = ((Params & cpRemoveCtrlZ) != 0);
+
+  if (FLAGSET(Params, cpRemoveBOM) && (Size >= 3) &&
+      (memcmp(Data, "\xEF\xBB\xBF", 3) == 0))
+  {
+    Delete(0, 3);
+  }
+
+  if (FLAGSET(Params, cpRemoveCtrlZ) && (Size > 0) && ((*(Data + Size - 1)) == '\x1A'))
+  {
+    Delete(Size-1, 1);
+  }
 
   if (strcmp(Source, Dest) == 0)
   {
@@ -110,7 +120,13 @@ void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params)
   {
     for (int Index = 0; Index < Size; Index++)
     {
-      if (*Ptr == Source[0])
+      // EOL already in wanted format, make sure to pass unmodified
+      if ((Index < Size - 1) && (*Ptr == Dest[0]) && (*(Ptr+1) == Dest[1]))
+      {
+        Index++;
+        Ptr++;
+      }
+      else if (*Ptr == Source[0])
       {
         *Ptr = Dest[0];
         if (Dest[1])
@@ -120,14 +136,6 @@ void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params)
           Ptr = Data + Index;
         }
       }
-      // this should fix LF -> CR/LF conversion "bug" on CR/FL files,
-      // which led to CR/CR/FL
-      else if (*Ptr == Dest[0] || *Ptr == Dest[1])
-      {
-        Delete(Index, 1);
-        Index--;
-        Ptr = Data + Index;
-      }
       Ptr++;
     }
   }
@@ -158,11 +166,6 @@ void __fastcall TFileBuffer::Convert(char * Source, char * Dest, int Params)
       Delete(Index, 1);
     }
   }
-
-  if (RemoveCtrlZ && (Size > 0) && ((*(Data + Size - 1)) == '\x1A'))
-  {
-    Delete(Size-1, 1);
-  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TFileBuffer::Convert(TEOLType Source, TEOLType Dest, int Params)

+ 1 - 0
core/FileBuffer.h

@@ -6,6 +6,7 @@
 //---------------------------------------------------------------------------
 enum TEOLType { eolLF /* \n */, eolCRLF /* \r\n */, eolCR /* \r */ };
 const int cpRemoveCtrlZ = 0x01;
+const int cpRemoveBOM =   0x02;
 //---------------------------------------------------------------------------
 class TFileBuffer
 {

+ 52 - 6
core/FileMasks.cpp

@@ -14,6 +14,7 @@ using namespace Masks;
 #include "TextsCore.h"
 #include "RemoteFiles.h"
 #include "PuttyTools.h"
+#include "Terminal.h"
 //---------------------------------------------------------------------------
 AnsiString __fastcall MaskFilePart(const AnsiString Part, const AnsiString Mask, bool& Masked)
 {
@@ -235,7 +236,8 @@ bool __fastcall TFileMasks::MatchesMask(AnsiString FileName, bool Directory,
         }
         if (D > 0)
         {
-          AnsiString MP = ToUnixPath(M.SubString(1, D - 1));
+          // make sure sole "/" (root dir) is preservedas is
+          AnsiString MP = UnixExcludeTrailingBackslash(ToUnixPath(M.SubString(1, D)));
           // 'Path' must already have unix slashes
           PathMatch = ::MatchesMask(Path, MP);
           M = M.SubString(D + 1, M.Length() - D);
@@ -602,14 +604,36 @@ bool __fastcall TInteractiveCustomCommand::PatternReplacement(int Index, const A
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-TFileCustomCommand::TFileCustomCommand() :
-  TCustomCommand()
+__fastcall TCustomCommandData::TCustomCommandData()
+{
+}
+//---------------------------------------------------------------------------
+__fastcall TCustomCommandData::TCustomCommandData(TTerminal * Terminal)
+{
+  HostName = Terminal->SessionData->HostName;
+  UserName = Terminal->SessionData->UserName;
+  Password = Terminal->Password;
+}
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+TFileCustomCommand::TFileCustomCommand()
+{
+}
+//---------------------------------------------------------------------------
+TFileCustomCommand::TFileCustomCommand(const TCustomCommandData & Data,
+  const AnsiString & Path)
 {
+  FData = Data;
+  FPath = Path;
 }
 //---------------------------------------------------------------------------
-TFileCustomCommand::TFileCustomCommand(const AnsiString & FileName, const AnsiString & FileList) :
+TFileCustomCommand::TFileCustomCommand(const TCustomCommandData & Data,
+    const AnsiString & Path, const AnsiString & FileName,
+    const AnsiString & FileList) :
   TCustomCommand()
 {
+  FData = Data;
+  FPath = Path;
   FFileName = FileName;
   FFileList = FileList;
 }
@@ -617,8 +641,12 @@ TFileCustomCommand::TFileCustomCommand(const AnsiString & FileName, const AnsiSt
 int __fastcall TFileCustomCommand::PatternLen(int /*Index*/, char PatternCmd)
 {
   int Len;
-  switch (PatternCmd)
+  switch (toupper(PatternCmd))
   {
+    case '@':
+    case 'U':
+    case 'P':
+    case '/':
     case '&':
       Len = 2;
       break;
@@ -633,7 +661,25 @@ int __fastcall TFileCustomCommand::PatternLen(int /*Index*/, char PatternCmd)
 bool __fastcall TFileCustomCommand::PatternReplacement(int /*Index*/,
   const AnsiString & Pattern, AnsiString & Replacement, bool & Delimit)
 {
-  if (Pattern == "!&")
+  // keep consistent with TSessionLog::OpenLogFile
+
+  if (Pattern == "!@")
+  {
+    Replacement = FData.HostName;
+  }
+  else if (AnsiSameText(Pattern, "!u"))
+  {
+    Replacement = FData.UserName;
+  }
+  else if (AnsiSameText(Pattern, "!p"))
+  {
+    Replacement = FData.Password;
+  }
+  else if (Pattern == "!/")
+  {
+    Replacement = UnixIncludeTrailingBackslash(FPath);
+  }
+  else if (Pattern == "!&")
   {
     Replacement = FFileList;
     // already delimited

+ 16 - 1
core/FileMasks.h

@@ -90,11 +90,24 @@ private:
   TCustomCommand * FChildCustomCommand;
 };
 //---------------------------------------------------------------------------
+class TTerminal;
+struct TCustomCommandData
+{
+  __fastcall TCustomCommandData();
+  __fastcall TCustomCommandData(TTerminal * Terminal);
+
+  AnsiString HostName;
+  AnsiString UserName;
+  AnsiString Password;
+};
+//---------------------------------------------------------------------------
 class TFileCustomCommand : public TCustomCommand
 {
 public:
   TFileCustomCommand();
-  TFileCustomCommand(const AnsiString & FileName, const AnsiString & FileList);
+  TFileCustomCommand(const TCustomCommandData & Data, const AnsiString & Path);
+  TFileCustomCommand(const TCustomCommandData & Data, const AnsiString & Path,
+    const AnsiString & FileName, const AnsiString & FileList);
 
   virtual void __fastcall Validate(const AnsiString & Command);
   virtual void __fastcall ValidatePattern(const AnsiString & Command,
@@ -109,6 +122,8 @@ protected:
     AnsiString & Replacement, bool & Delimit);
 
 private:
+  TCustomCommandData FData;
+  AnsiString FPath;
   AnsiString FFileName;
   AnsiString FFileList;
 };

+ 106 - 14
core/FileOperationProgress.cpp

@@ -36,7 +36,6 @@ void __fastcall TFileOperationProgressType::Clear()
   Count = 0;
   FFilesFinished = 0;
   StartTime = Now();
-  FStopped = 0;
   Suspended = false;
   FSuspendTime = 0;
   InProgress = false;
@@ -54,6 +53,9 @@ void __fastcall TFileOperationProgressType::Clear()
   AlternateResumeAlways = false;
   // to bypass check in ClearTransfer()
   TransferSize = 0;
+  CPSLimit = 0;
+  FTicks.clear();
+  FTotalTransferredThen.clear();
   ClearTransfer();
 }
 //---------------------------------------------------------------------------
@@ -70,12 +72,18 @@ void __fastcall TFileOperationProgressType::ClearTransfer()
   SkippedSize = 0;
   TransferedSize = 0;
   TransferingFile = false;
-  FFileStopped = 0;
+  FLastSecond = 0;
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation,
+  TOperationSide ASide, int ACount)
+{
+  Start(AOperation, ASide, ACount, false, "", 0);
 }
 //---------------------------------------------------------------------------
 void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation,
   TOperationSide ASide, int ACount, bool ATemp,
-  const AnsiString ADirectory)
+  const AnsiString ADirectory, unsigned long ACPSLimit)
 {
   Clear();
   Operation = AOperation;
@@ -85,6 +93,7 @@ void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation,
   Cancel = csContinue;
   Directory = ADirectory;
   Temp = ATemp;
+  CPSLimit = ACPSLimit;
   DoProgress();
 }
 //---------------------------------------------------------------------------
@@ -106,7 +115,7 @@ void __fastcall TFileOperationProgressType::Suspend()
 {
   assert(!Suspended);
   Suspended = true;
-  FSuspendTime = Now();
+  FSuspendTime = GetTickCount();
   DoProgress();
 }
 //---------------------------------------------------------------------------
@@ -114,10 +123,17 @@ void __fastcall TFileOperationProgressType::Resume()
 {
   assert(Suspended);
   Suspended = false;
-  TDateTime TimeSuspended = (Now() - FSuspendTime);
-  // see CPS()
-  FStopped += TimeSuspended;
-  FFileStopped += TimeSuspended;
+
+  // shift timestamps for CPS calculation in advance
+  // by the time the progress was suspended
+  unsigned long Stopped = (GetTickCount() - FSuspendTime);
+  size_t i = 0;
+  while (i < FTicks.size())
+  {
+    FTicks[i] += Stopped;
+    ++i;
+  }
+
   DoProgress();
 }
 //---------------------------------------------------------------------------
@@ -203,10 +219,50 @@ bool __fastcall TFileOperationProgressType::IsLocalyDone()
   return (LocalyUsed == LocalSize);
 }
 //---------------------------------------------------------------------------
+unsigned long __fastcall TFileOperationProgressType::AdjustToCPSLimit(
+  unsigned long Size)
+{
+  if (CPSLimit > 0)
+  {
+    // we must not return 0, hence, if we reach zero,
+    // we wait until the next second
+    do
+    {
+      unsigned int Second = (GetTickCount() / 1000);
+
+      if (Second != FLastSecond)
+      {
+        FRemainingCPS = CPSLimit;
+        FLastSecond = Second;
+      }
+
+      if (FRemainingCPS == 0)
+      {
+        SleepEx(100, true);
+        DoProgress();
+      }
+    }
+    while ((CPSLimit > 0) && (FRemainingCPS == 0));
+
+    // CPSLimit may have been dropped in DoProgress
+    if (CPSLimit > 0)
+    {
+      if (FRemainingCPS < Size)
+      {
+        Size = FRemainingCPS;
+      }
+
+      FRemainingCPS -= Size;
+    }
+  }
+  return Size;
+}
+//---------------------------------------------------------------------------
 unsigned long __fastcall TFileOperationProgressType::LocalBlockSize()
 {
   unsigned long Result = TRANSFER_BUF_SIZE;
   if (LocalyUsed + Result > LocalSize) Result = (unsigned long)(LocalSize - LocalyUsed);
+  Result = AdjustToCPSLimit(Result);
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -241,6 +297,8 @@ void __fastcall TFileOperationProgressType::RollbackTransfer()
   assert(TransferedSize <= TotalTransfered);
   TotalTransfered -= TransferedSize;
   assert(SkippedSize <= TotalSkipped);
+  FTicks.clear();
+  FTotalTransferredThen.clear();
   TotalSkipped -= SkippedSize;
   SkippedSize = 0;
   TransferedSize = 0;
@@ -265,6 +323,20 @@ void __fastcall TFileOperationProgressType::AddTransfered(__int64 ASize,
   if (AddToTotals)
   {
     TotalTransfered += ASize;
+    unsigned long Ticks = GetTickCount();
+    if (FTicks.empty() ||
+        (FTicks.back() > Ticks) || // ticks wrap after 49.7 days
+        ((Ticks - FTicks.back()) >= 1000))
+    {
+      FTicks.push_back(Ticks);
+      FTotalTransferredThen.push_back(TotalTransfered);
+    }
+
+    if (FTicks.size() > 10)
+    {
+      FTicks.erase(FTicks.begin());
+      FTotalTransferredThen.erase(FTotalTransferredThen.begin());
+    }
   }
   DoProgress();
 }
@@ -281,6 +353,7 @@ unsigned long __fastcall TFileOperationProgressType::TransferBlockSize()
 {
   unsigned long Result = TRANSFER_BUF_SIZE;
   if (TransferedSize + Result > TransferSize) Result = (unsigned long)(TransferSize - TransferedSize);
+  Result = AdjustToCPSLimit(Result);
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -314,17 +387,36 @@ TDateTime __fastcall TFileOperationProgressType::TimeElapsed()
 //---------------------------------------------------------------------------
 unsigned int __fastcall TFileOperationProgressType::CPS()
 {
-  TDateTime CurTime = Suspended ? FSuspendTime : Now();
-  TDateTime RealTime = (CurTime - StartTime) - FStopped;
-
-  if ((double)RealTime > 0)
+  unsigned int Result;
+  if (FTicks.empty())
   {
-    return TotalTransfered / ((double)RealTime * (24 * 60 * 60));
+    Result = 0;
   }
   else
   {
-    return 0;
+    unsigned long Ticks = (Suspended ? FSuspendTime : GetTickCount());
+    unsigned long TimeSpan;
+    if (Ticks < FTicks.front())
+    {
+      // clocks has wrapped, guess 10 seconds difference
+      TimeSpan = 10000;
+    }
+    else
+    {
+      TimeSpan = (Ticks - FTicks.front());
+    }
+
+    if (TimeSpan == 0)
+    {
+      Result = 0;
+    }
+    else
+    {
+      __int64 Transferred = (TotalTransfered - FTotalTransferredThen.front());
+      Result = (unsigned int)(Transferred * 1000 / TimeSpan);
+    }
   }
+  return Result;
 }
 //---------------------------------------------------------------------------
 TDateTime __fastcall TFileOperationProgressType::TimeExpected()

+ 11 - 7
core/FileOperationProgress.h

@@ -4,6 +4,7 @@
 //---------------------------------------------------------------------------
 #include "Configuration.h"
 #include "CopyParam.h"
+#include <vector>
 //---------------------------------------------------------------------------
 class TFileOperationProgressType;
 enum TFileOperation { foNone, foCopy, foMove, foDelete, foSetProperties,
@@ -20,18 +21,18 @@ typedef void __fastcall (__closure *TFileOperationFinished)
 class TFileOperationProgressType
 {
 private:
-  // how long it was stopped (e.g. while displaying error message)
-  TDateTime FStopped;
   // when it was last time suspended (to calculate suspend time in Resume())
-  TDateTime FSuspendTime;
+  unsigned int FSuspendTime;
   // when current file was started being transfered
   TDateTime FFileStartTime;
-  // how long current file transfer was stopped (e.g. while displaying error message)
-  TDateTime FFileStopped;
   int FFilesFinished;
   TFileOperationProgressEvent FOnProgress;
   TFileOperationFinished FOnFinished;
   bool FReset;
+  unsigned int FLastSecond;
+  unsigned long FRemainingCPS;
+  std::vector<unsigned long> FTicks;
+  std::vector<__int64> FTotalTransferredThen;
 
 protected:
   void __fastcall ClearTransfer();
@@ -69,6 +70,7 @@ public:
   bool NoToAll;
   bool SkipToAll;
   bool AlternateResumeAlways;
+  unsigned long CPSLimit;
 
   bool TotalSizeSet;
 
@@ -91,6 +93,7 @@ public:
   void __fastcall SetFile(AnsiString AFileName);
   int __fastcall OperationProgress();
   unsigned long __fastcall TransferBlockSize();
+  unsigned long __fastcall AdjustToCPSLimit(unsigned long Size);
   static unsigned long __fastcall StaticBlockSize();
   void __fastcall Reset();
   void __fastcall Resume();
@@ -101,9 +104,10 @@ public:
   void __fastcall ChangeTransferSize(__int64 ASize);
   void __fastcall RollbackTransfer();
   void __fastcall SetTotalSize(__int64 ASize);
+  void __fastcall Start(TFileOperation AOperation, TOperationSide ASide, int ACount);
   void __fastcall Start(TFileOperation AOperation,
-    TOperationSide ASide, int ACount, bool ATemp = false,
-    const AnsiString ADirectory = "");
+    TOperationSide ASide, int ACount, bool ATemp, const AnsiString ADirectory,
+    unsigned long ACPSLimit);
   void __fastcall Stop();
   void __fastcall Suspend();
   // whole operation

+ 5 - 2
core/FileSystems.h

@@ -17,9 +17,12 @@ enum TFSCommand { fsNull = 0, fsVarValue, fsLastLine, fsFirstLine,
   fsCurrentDirectory, fsChangeDirectory, fsListDirectory, fsListCurrentDirectory,
   fsListFile, fsLookupUsersGroups, fsCopyToRemote, fsCopyToLocal, fsDeleteFile,
   fsRenameFile, fsCreateDirectory, fsChangeMode, fsChangeGroup, fsChangeOwner,
-  fsHomeDirectory, fsUnset, fsUnalias, fsAliasGroupList, fsCreateLink, fsCopyFile,
+  fsHomeDirectory, fsUnset, fsUnalias, fsCreateLink, fsCopyFile,
   fsAnyCommand, fsReadSymlink, fsChangeProperties, fsMoveFile };
 //---------------------------------------------------------------------------
+const dfNoRecursive = 0x01;
+const dfAlternative = 0x02;
+//---------------------------------------------------------------------------
 class TCustomFileSystem
 {
 public:
@@ -53,7 +56,7 @@ public:
     const TRemoteProperties * Properties) = 0;
   virtual void __fastcall CreateLink(const AnsiString FileName, const AnsiString PointTo, bool Symbolic) = 0;
   virtual void __fastcall DeleteFile(const AnsiString FileName,
-    const TRemoteFile * File, bool Recursive) = 0;
+    const TRemoteFile * File, int Params) = 0;
   virtual void __fastcall CustomCommandOnFile(const AnsiString FileName,
     const TRemoteFile * File, AnsiString Command, int Params, TCaptureOutputEvent OutputEvent) = 0;
   virtual void __fastcall DoStartup() = 0;

+ 103 - 27
core/FtpFileSystem.cpp

@@ -213,6 +213,8 @@ void __fastcall TFTPFileSystem::Open()
   FSessionInfo.ProtocolBaseName = "FTP";
   FSessionInfo.ProtocolName = FSessionInfo.ProtocolBaseName;
 
+  FLastDataSent = Now();
+
   FMultineResponse = false;
 
   // initialize FZAPI on the first connect only
@@ -260,7 +262,7 @@ void __fastcall TFTPFileSystem::Open()
   int Pasv = (Data->FtpPasvMode ? 1 : 2);
   int TimeZoneOffset = int(double(Data->TimeDifference) * 24 * 60);
   int UTF8 = 0;
-  switch (Data->SFTPBug[sbUtf])
+  switch (Data->Utf)
   {
     case asOn:
       UTF8 = 1;
@@ -298,9 +300,8 @@ void __fastcall TFTPFileSystem::Open()
         PromptedForCredentials = true;
       }
 
-      if (!FTerminal->PromptUser(Data,
-            FMTLOAD(USERNAME_PROMPT, (Data->SessionName)),
-            pkPrompt, UserName))
+      if (!FTerminal->PromptUser(Data, pkUserName, LoadStr(USERNAME_TITLE), "",
+            LoadStr(USERNAME_PROMPT2), true, 0, UserName))
       {
         FTerminal->FatalError(NULL, LoadStr(AUTHENTICATION_FAILED));
       }
@@ -324,9 +325,8 @@ void __fastcall TFTPFileSystem::Open()
 
       // on retry ask for new password
       Password = "";
-      if (!FTerminal->PromptUser(Data,
-            FMTLOAD(PROMPT_SESSION_PASSWORD, (Data->SessionName)),
-            pkPassword, Password))
+      if (!FTerminal->PromptUser(Data, pkPassword, LoadStr(PASSWORD_TITLE), "",
+            LoadStr(PASSWORD_PROMPT), false, 0, Password))
       {
         FTerminal->FatalError(NULL, LoadStr(AUTHENTICATION_FAILED));
       }
@@ -387,13 +387,45 @@ bool __fastcall TFTPFileSystem::GetActive()
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::Idle()
 {
-  if (FActive && !FWaitingForReply)
+  if (FActive)
   {
-    unsigned int Reply = PoolForReply();
-    if (Reply != 0)
+    if (!FWaitingForReply)
     {
-      assert(FLAGSET(Reply, TFileZillaIntf::REPLY_DISCONNECTED));
-      GotReply(Reply);
+      unsigned int Reply = PoolForReply();
+      if (Reply != 0)
+      {
+        assert(FLAGSET(Reply, TFileZillaIntf::REPLY_DISCONNECTED));
+        GotReply(Reply);
+      }
+    }
+
+    // Keep session alive
+    if ((FTerminal->SessionData->FtpPingType != ptOff) &&
+        (Now() - FLastDataSent > FTerminal->SessionData->FtpPingIntervalDT))
+    {
+      FLastDataSent = Now();
+
+      char* Commands[] = { "PWD", "REST 0", "TYPE A", "TYPE I" };
+      int Choice = random(LENOF(Commands) + 1);
+      if (Choice == 0)
+      {
+        TRemoteDirectory * Files = new TRemoteDirectory(FTerminal);
+        try
+        {
+          Files->Directory = CurrentDirectory;
+          DoReadDirectory(Files);
+        }
+        __finally
+        {
+          delete Files;
+        }
+      }
+      else
+      {
+        FFileZillaIntf->CustomCommand(Commands[Choice - 1]);
+
+        GotReply(WaitForReply(), 0);
+      }
     }
   }
 }
@@ -619,6 +651,10 @@ bool __fastcall TFTPFileSystem::ConfirmOverwrite(AnsiString & FileName,
     {
       Answer = (CanResume && AutoResume ? qaRetry : qaYes);
     }
+    else if (!FTerminal->Configuration->ConfirmOverwriting)
+    {
+      Answer = qaYes;
+    }
     else
     {
       // retry = "resume"
@@ -660,8 +696,8 @@ bool __fastcall TFTPFileSystem::ConfirmOverwrite(AnsiString & FileName,
 
       // rename
       case qaIgnore:
-        if (FTerminal->PromptUser(FTerminal->SessionData, LoadStr(RENAME_PROMPT),
-              pkPrompt, FileName))
+        if (FTerminal->PromptUser(FTerminal->SessionData, pkPrompt,
+              LoadStr(RENAME_TITLE), "", LoadStr(RENAME_PROMPT2), true, 0, FileName))
         {
           OverwriteMode = omOverwrite;
         }
@@ -764,6 +800,11 @@ void __fastcall TFTPFileSystem::FileTransferProgress(__int64 TransferSize,
     FFileTransferAbort = ftaCancel;
     FFileZillaIntf->Cancel();
   }
+
+  if (FFileTransferCPSLimit != OperationProgress->CPSLimit)
+  {
+    FFileTransferCPSLimit = OperationProgress->CPSLimit;
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::FileTransfer(const AnsiString & FileName,
@@ -800,6 +841,7 @@ void __fastcall TFTPFileSystem::CopyToLocal(TStrings * FilesToCopy,
         SinkRobust(AbsolutePath(FileName), File, FullTargetDir, CopyParam, Params,
           OperationProgress, tfFirstLevel);
         Success = true;
+        FLastDataSent = Now();
       }
       catch(EScpSkipFile & E)
       {
@@ -960,6 +1002,7 @@ void __fastcall TFTPFileSystem::Sink(const AnsiString FileName,
     FIgnoreFileList = true;
     try
     {
+      FFileTransferCPSLimit = OperationProgress->CPSLimit;
       FFileTransferPreserveTime = CopyParam->PreserveTime;
       UserData.FileName = DestFileName;
       UserData.Params = Params;
@@ -999,8 +1042,8 @@ void __fastcall TFTPFileSystem::Sink(const AnsiString FileName,
     // If file is directory, do not delete it recursively, because it should be
     // empty already. If not, it should not be deleted (some files were
     // skipped or some new files were copied to it, while we were downloading)
-    bool Recursive = false;
-    FTerminal->DeleteFile(FileName, File, &Recursive);
+    int Params = dfNoRecursive;
+    FTerminal->DeleteFile(FileName, File, &Params);
   }
 }
 //---------------------------------------------------------------------------
@@ -1067,6 +1110,7 @@ void __fastcall TFTPFileSystem::CopyToRemote(TStrings * FilesToCopy,
         SourceRobust(FileName, FullTargetDir, CopyParam, Params, OperationProgress,
           tfFirstLevel);
         Success = true;
+        FLastDataSent = Now();
       }
       catch(EScpSkipFile & E)
       {
@@ -1181,6 +1225,7 @@ void __fastcall TFTPFileSystem::Source(const AnsiString FileName,
     FIgnoreFileList = true;
     try
     {
+      FFileTransferCPSLimit = OperationProgress->CPSLimit;
       // not supports for uploads anyway
       FFileTransferPreserveTime = CopyParam->PreserveTime;
       // not used for uploads
@@ -1324,7 +1369,7 @@ void __fastcall TFTPFileSystem::CreateLink(const AnsiString /*FileName*/,
 }
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::DeleteFile(const AnsiString AFileName,
-  const TRemoteFile * File, bool Recursive)
+  const TRemoteFile * File, int Params)
 {
   AnsiString FileName = AbsolutePath(AFileName);
   AnsiString FileNameOnly = UnixExtractFileName(FileName);
@@ -1332,9 +1377,9 @@ void __fastcall TFTPFileSystem::DeleteFile(const AnsiString AFileName,
 
   bool Dir = (File != NULL) && File->IsDirectory && !File->IsSymLink;
 
-  if (Dir && Recursive)
+  if (Dir && FLAGCLEAR(Params, dfNoRecursive))
   {
-    FTerminal->ProcessDirectory(FileName, FTerminal->DeleteFile, &Recursive);
+    FTerminal->ProcessDirectory(FileName, FTerminal->DeleteFile, &Params);
   }
 
   assert(!FIgnoreFileList);
@@ -1372,13 +1417,33 @@ void __fastcall TFTPFileSystem::CustomCommandOnFile(const AnsiString /*FileName*
   const TRemoteFile * /*File*/, AnsiString /*Command*/, int /*Params*/,
   TCaptureOutputEvent /*OutputEvent*/)
 {
-  // if ever implemeneted, do not forget to add EnsureLocation,
+  // if ever implemented, do not forget to add EnsureLocation,
   // see AnyCommand for a reason why
   assert(false);
 }
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::DoStartup()
 {
+  TStrings * PostLoginCommands = new TStringList();
+  try
+  {
+    PostLoginCommands->Text = FTerminal->SessionData->PostLoginCommands;
+    for (int Index = 0; Index < PostLoginCommands->Count; Index++)
+    {
+      AnsiString Command = PostLoginCommands->Strings[Index];
+      if (!Command.IsEmpty())
+      {
+        FFileZillaIntf->CustomCommand(Command.c_str());
+
+        GotReply(WaitForReply(), REPLY_2XX_CODE);
+      }
+    }
+  }
+  __finally
+  {
+    delete PostLoginCommands;
+  }
+
   // retrieve initialize working directory to save it as home directory
   ReadCurrentDirectory();
   FHomeDirectory = FCurrentDirectory;
@@ -1493,7 +1558,7 @@ void __fastcall TFTPFileSystem::DoReadDirectory(TRemoteFileList * FileList)
 {
   FileList->Clear();
   // FZAPI does not list parent directory, add it
-  FileList->Add(new TRemoteParentDirectory());
+  FileList->AddFile(new TRemoteParentDirectory(FTerminal));
 
   FLastReadDirectoryProgress = 0;
 
@@ -1508,6 +1573,8 @@ void __fastcall TFTPFileSystem::DoReadDirectory(TRemoteFileList * FileList)
     FFileZillaIntf->List(Directory.c_str());
 
     GotReply(WaitForReply(), REPLY_2XX_CODE | REPLY_ALLOW_CANCEL);
+
+    FLastDataSent = Now();
   }
   __finally
   {
@@ -1766,6 +1833,7 @@ int __fastcall TFTPFileSystem::GetOptionVal(int OptionID) const
           break;
 
         case pmTelnet:
+        case pmCmd:
         default:
           assert(false);
           Result = 0; // PROXYTYPE_NOPROXY;
@@ -1826,18 +1894,30 @@ int __fastcall TFTPFileSystem::GetOptionVal(int OptionID) const
       break;
 
     case OPTION_KEEPALIVE:
-      Result = ((Data->FtpPingType != ptOff) ? TRUE : FALSE);
+      Result = FALSE;
       break;
 
     case OPTION_INTERVALLOW:
     case OPTION_INTERVALHIGH:
-      Result = Data->FtpPingInterval;
+      // should never get here OPTION_KEEPALIVE being FALSE
+      assert(false);
+      Result = 60;
       break;
 
     case OPTION_VMSALLREVISIONS:
       Result = FALSE;
       break;
 
+    case OPTION_SPEEDLIMIT_DOWNLOAD_TYPE:
+    case OPTION_SPEEDLIMIT_UPLOAD_TYPE:
+      Result = (FFileTransferCPSLimit == 0 ? 0 : 1);
+      break;
+
+    case OPTION_SPEEDLIMIT_DOWNLOAD_VALUE:
+    case OPTION_SPEEDLIMIT_UPLOAD_VALUE:
+      Result = (FFileTransferCPSLimit / 1024); // FZAPI expects KiB/s
+      break;
+
     case OPTION_MPEXT_SHOWHIDDEN:
       Result = ((FListAll != 0) ? TRUE : FALSE);
       break;
@@ -2341,10 +2421,6 @@ bool __fastcall TFTPFileSystem::HandleAsynchRequestOverwrite(
       // on retry, use the same answer as on the first attempt
       RequestResult = UserData.OverwriteResult;
     }
-    else if (!FTerminal->Configuration->ConfirmOverwriting)
-    {
-      RequestResult = TFileZillaIntf::FILEEXISTS_OVERWRITE;
-    }
     else
     {
       TFileOperationProgressType * OperationProgress = FTerminal->OperationProgress;

+ 3 - 1
core/FtpFileSystem.h

@@ -51,7 +51,7 @@ public:
     const TRemoteProperties * Properties);
   virtual void __fastcall CreateLink(const AnsiString FileName, const AnsiString PointTo, bool Symbolic);
   virtual void __fastcall DeleteFile(const AnsiString FileName,
-    const TRemoteFile * File = NULL, bool Recursive = false);
+    const TRemoteFile * File = NULL, int Params = dfNoRecursive);
   virtual void __fastcall CustomCommandOnFile(const AnsiString FileName,
     const TRemoteFile * File, AnsiString Command, int Params, TCaptureOutputEvent OutputEvent);
   virtual void __fastcall DoStartup();
@@ -198,10 +198,12 @@ private:
   bool FFileTransferCancelled;
   __int64 FFileTransferResumed;
   bool FFileTransferPreserveTime;
+  unsigned long FFileTransferCPSLimit;
   bool FAwaitingProgress;
   TCaptureOutputEvent FOnCaptureOutput;
   AnsiString FUserName;
   int FListAll;
+  TDateTime FLastDataSent;
   mutable AnsiString FOptionScratch;
 };
 //---------------------------------------------------------------------------

+ 21 - 1
core/Interface.h

@@ -13,6 +13,10 @@ void __fastcall ShowExtendedException(Exception * E);
 AnsiString __fastcall GetRegistryKey();
 void __fastcall Busy(bool Start);
 AnsiString __fastcall SshVersionString();
+void __fastcall CopyToClipboard(AnsiString Text);
+int __fastcall StartThread(void * SecurityAttributes, unsigned StackSize,
+  TThreadFunc ThreadFunc, void * Parameter, unsigned CreationFlags,
+  unsigned & ThreadId);
 
 const unsigned int qaYes =      0x00000001;
 const unsigned int qaNo =       0x00000002;
@@ -35,8 +39,11 @@ const int qpAllowContinueOnError = 0x04;
 
 struct TQueryButtonAlias
 {
+  TQueryButtonAlias();
+
   unsigned int Button;
   AnsiString Alias;
+  TNotifyEvent OnClick;
 };
 
 typedef void __fastcall (__closure *TQueryParamsTimerEvent)(unsigned int & Result);
@@ -58,6 +65,19 @@ struct TQueryParams
 };
 
 enum TQueryType { qtConfirmation, qtWarning, qtError, qtInformation };
-enum TPromptKind { pkPassword, pkPassphrase, pkServerPrompt, pkPrompt };
+
+enum TPromptKind
+{
+  pkPrompt,
+  pkUserName,
+  pkPassphrase,
+  pkTIS,
+  pkCryptoCard,
+  pkKeybInteractive,
+  pkPassword,
+  pkNewPassword
+};
+
+bool __fastcall IsAuthenticationPrompt(TPromptKind Kind);
 //---------------------------------------------------------------------------
 #endif

+ 2 - 0
core/NamedObjs.h

@@ -39,4 +39,6 @@ public:
   __property int HiddenCount = { read = FHiddenCount, write = FHiddenCount };
 };
 //---------------------------------------------------------------------------
+int __fastcall NamedObjectSortProc(void * Item1, void * Item2);
+//---------------------------------------------------------------------------
 #endif

+ 229 - 0
core/Option.cpp

@@ -0,0 +1,229 @@
+//---------------------------------------------------------------------------
+#include <vcl.h>
+#pragma hdrstop
+
+#include <Common.h>
+#include "Option.h"
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+//---------------------------------------------------------------------------
+__fastcall TOptions::TOptions()
+{
+  FSwitchMarks = "-/";
+  FSwitchValueDelimiters = ":=";
+  FNoMoreSwitches = false;
+  FParamCount = 0;
+}
+//---------------------------------------------------------------------------
+void __fastcall TOptions::Add(AnsiString Value)
+{
+  if (!FNoMoreSwitches &&
+      (Value.Length() == 2) &&
+      (Value[1] == Value[2]) &&
+      (FSwitchMarks.Pos(Value[1]) > 0))
+  {
+    FNoMoreSwitches = true;
+  }
+  else if (!FNoMoreSwitches &&
+    (Value.Length() >= 2) &&
+    (FSwitchMarks.Pos(Value[1]) > 0))
+  {
+    int Index = 2;
+    while (Index <= Value.Length())
+    {
+      if (Value.IsDelimiter(FSwitchValueDelimiters, Index))
+      {
+        break;
+      }
+      ++Index;
+    }
+
+    TOption Option;
+    Option.Type = otSwitch;
+    Option.Name = Value.SubString(2, Index - 2);
+    Option.Value = Value.SubString(Index + 1, Value.Length());
+    Option.Used = false;
+    FOptions.push_back(Option);
+  }
+  else
+  {
+    TOption Option;
+    Option.Type = otParam;
+    Option.Value = Value;
+    Option.Used = false;
+    FOptions.push_back(Option);
+    ++FParamCount;
+  }
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall TOptions::GetParam(int Index)
+{
+  assert((Index >= 1) && (Index <= FParamCount));
+
+  AnsiString Result;
+  size_t I = 0;
+  while ((I < FOptions.size()) && (Index > 0))
+  {
+    if (FOptions[I].Type == otParam)
+    {
+      --Index;
+      if (Index == 0)
+      {
+        Result = FOptions[I].Value;
+        FOptions[I].Used = true;
+      }
+    }
+    ++I;
+  }
+
+  return Result;
+}
+//---------------------------------------------------------------------------
+bool __fastcall TOptions::GetEmpty()
+{
+  return FOptions.empty();
+}
+//---------------------------------------------------------------------------
+bool __fastcall TOptions::FindSwitch(const AnsiString Switch,
+  AnsiString & Value, int & ParamsStart, int & ParamsCount)
+{
+  ParamsStart = 0;
+  int Index = 0;
+  bool Found = false;
+  while ((Index < int(FOptions.size())) && !Found)
+  {
+    AnsiString S;
+    if (FOptions[Index].Type == otParam)
+    {
+      ParamsStart++;
+    }
+    else if (FOptions[Index].Type == otSwitch)
+    {
+      if (AnsiSameText(FOptions[Index].Name, Switch))
+      {
+        Found = true;
+        Value = FOptions[Index].Value;
+        FOptions[Index].Used = true;
+      }
+    }
+    Index++;
+  }
+
+  ParamsCount = 0;
+  if (Found)
+  {
+    ParamsStart++;
+    while ((Index + ParamsCount < int(FOptions.size())) &&
+           (FOptions[Index + ParamsCount].Type == otParam))
+    {
+      ParamsCount++;
+    }
+  }
+  else
+  {
+    ParamsStart = 0;
+  }
+
+  return Found;
+}
+//---------------------------------------------------------------------------
+bool __fastcall TOptions::FindSwitch(const AnsiString Switch, AnsiString & Value)
+{
+  int ParamsStart;
+  int ParamsCount;
+  return FindSwitch(Switch, Value, ParamsStart, ParamsCount);
+}
+//---------------------------------------------------------------------------
+bool __fastcall TOptions::FindSwitch(const AnsiString Switch)
+{
+  AnsiString Value;
+  int ParamsStart;
+  int ParamsCount;
+  return FindSwitch(Switch, Value, ParamsStart, ParamsCount);
+}
+//---------------------------------------------------------------------------
+bool __fastcall TOptions::FindSwitch(const AnsiString Switch,
+  TStrings * Params, int ParamsMax)
+{
+  AnsiString Value;
+  int ParamsStart;
+  int ParamsCount;
+  bool Result = FindSwitch(Switch, Value, ParamsStart, ParamsCount);
+  if (Result)
+  {
+    if ((ParamsMax >= 0) && (ParamsCount > ParamsMax))
+    {
+      ParamsCount = ParamsMax;
+    }
+
+    int Index = 0;
+    while (Index < ParamsCount)
+    {
+      Params->Add(Param[ParamsStart + Index]);
+      Index++;
+    }
+    ParamsProcessed(ParamsStart, ParamsCount);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall TOptions::SwitchValue(const AnsiString Switch,
+  const AnsiString Default)
+{
+  AnsiString Value;
+  FindSwitch(Switch, Value);
+  if (Value.IsEmpty())
+  {
+    Value = Default;
+  }
+  return Value;
+}
+//---------------------------------------------------------------------------
+bool __fastcall TOptions::UnusedSwitch(AnsiString & Switch)
+{
+  bool Result = false;
+  size_t Index = 0;
+  while (!Result && (Index < FOptions.size()))
+  {
+    if ((FOptions[Index].Type == otSwitch) &&
+        !FOptions[Index].Used)
+    {
+      Switch = FOptions[Index].Name;
+      Result = true;
+    }
+    ++Index;
+  }
+
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TOptions::ParamsProcessed(int ParamsStart, int ParamsCount)
+{
+  if (ParamsCount > 0)
+  {
+    assert((ParamsStart >= 0) && ((ParamsStart - ParamsCount + 1) <= FParamCount));
+
+    size_t Index = 0;
+    while ((Index < FOptions.size()) && (ParamsStart > 0))
+    {
+      AnsiString S;
+      if (FOptions[Index].Type == otParam)
+      {
+        --ParamsStart;
+
+        if (ParamsStart == 0)
+        {
+          while (ParamsCount > 0)
+          {
+            assert(Index < FOptions.size());
+            assert(FOptions[Index].Type == otParam);
+            FOptions.erase(FOptions.begin() + Index);
+            --FParamCount;
+            --ParamsCount;
+          }
+        }
+      }
+      Index++;
+    }
+  }
+}

+ 54 - 0
core/Option.h

@@ -0,0 +1,54 @@
+//---------------------------------------------------------------------------
+#ifndef OptionH
+#define OptionH
+
+#include <vector>
+//---------------------------------------------------------------------------
+enum TOptionType { otParam, otSwitch };
+//---------------------------------------------------------------------------
+class TOptions
+{
+public:
+  __fastcall TOptions();
+
+  bool __fastcall FindSwitch(const AnsiString Switch);
+  bool __fastcall FindSwitch(const AnsiString Switch, AnsiString & Value);
+  bool __fastcall FindSwitch(const AnsiString Switch, int & ParamsStart,
+    int & ParamsCount);
+  bool __fastcall FindSwitch(const AnsiString Switch, TStrings * Params,
+    int ParamsMax = -1);
+  void __fastcall ParamsProcessed(int Position, int Count);
+  AnsiString __fastcall SwitchValue(const AnsiString Switch, const AnsiString Default = "");
+  bool __fastcall UnusedSwitch(AnsiString & Switch);
+
+  __property int ParamCount = { read = FParamCount };
+  __property AnsiString Param[int Index] = { read = GetParam };
+  __property bool Empty = { read = GetEmpty };
+
+protected:
+  AnsiString FSwitchMarks;
+  AnsiString FSwitchValueDelimiters;
+
+  void __fastcall Add(AnsiString Option);
+
+  bool __fastcall FindSwitch(const AnsiString Switch,
+    AnsiString & Value, int & ParamsStart, int & ParamsCount);
+
+private:
+  struct TOption
+  {
+    TOptionType Type;
+    AnsiString Name;
+    AnsiString Value;
+    bool Used;
+  };
+
+  std::vector<TOption> FOptions;
+  bool FNoMoreSwitches;
+  int FParamCount;
+
+  AnsiString __fastcall GetParam(int Index);
+  bool __fastcall GetEmpty();
+};
+//---------------------------------------------------------------------------
+#endif

+ 118 - 78
core/PuttyIntf.cpp

@@ -14,8 +14,6 @@ char sshver[50];
 CRITICAL_SECTION noise_section;
 bool SaveRandomSeed;
 //---------------------------------------------------------------------------
-int get_line(void * frontend, const char * prompt, char * str, int maxlen, int is_pw);
-//---------------------------------------------------------------------------
 void __fastcall PuttyInitialize()
 {
   SaveRandomSeed = true;
@@ -26,14 +24,12 @@ void __fastcall PuttyInitialize()
   // in destructor can proceed
   random_ref();
 
-  // initialize default seed path value same way as putty does (only change filename)
-  putty_get_seedpath();
   flags = FLAG_VERBOSE | FLAG_SYNCAGENT; // verbose log
 
-  ssh_get_line = get_line;
-  ssh_getline_pw_only = FALSE;
   sk_init();
 
+  sspi_init();
+
   AnsiString VersionString = SshVersionString();
   assert(!VersionString.IsEmpty() && (VersionString.Length() < sizeof(sshver)));
   strcpy(sshver, VersionString.c_str());
@@ -47,6 +43,7 @@ void __fastcall PuttyFinalize()
   }
   random_unref();
 
+  sspi_cleanup();
   sk_cleanup();
   DeleteCriticalSection(&noise_section);
 }
@@ -131,41 +128,82 @@ extern "C" char * do_select(Plug plug, SOCKET skt, int startup)
   return NULL;
 }
 //---------------------------------------------------------------------------
-int from_backend(void * frontend, int is_stderr, const char * data, int datalen, int type)
+int from_backend(void * frontend, int is_stderr, const char * data, int datalen)
 {
   assert(frontend);
-  if (type > 0)
+  if (is_stderr >= 0)
   {
+    assert((is_stderr == 0) || (is_stderr == 1));
     ((TSecureShell *)frontend)->FromBackend((is_stderr == 1), data, datalen);
   }
   else
   {
-    assert(is_stderr == 1);
-    ((TSecureShell *)frontend)->CWrite(data, datalen, type < 0);
+    assert(is_stderr == -1);
+    ((TSecureShell *)frontend)->CWrite(data, datalen);
   }
   return 0;
 }
 //---------------------------------------------------------------------------
-static int get_line(void * frontend, const char * prompt, char * str,
-  int maxlen, int is_pw)
+int from_backend_untrusted(void * /*frontend*/, const char * /*data*/, int /*len*/)
 {
-  assert(frontend != NULL);
+  // currently used with authentication banner only,
+  // for which we have own interface display_banner
+  return 0;
+}
+//---------------------------------------------------------------------------
+int get_userpass_input(prompts_t * p, unsigned char * /*in*/, int /*inlen*/)
+{
+  assert(p != NULL);
+  TSecureShell * SecureShell = reinterpret_cast<TSecureShell *>(p->frontend);
+  assert(SecureShell != NULL);
+
+  int Result;
+  TStrings * Prompts = new TStringList();
+  TStrings * Results = new TStringList();
+  try
+  {
+    for (int Index = 0; Index < int(p->n_prompts); Index++)
+    {
+      prompt_t * Prompt = p->prompts[Index];
+      Prompts->AddObject(Prompt->prompt, (TObject *)Prompt->echo);
+      Results->AddObject("", (TObject *)Prompt->result_len);
+    }
 
-  TSecureShell * SecureShell = reinterpret_cast<TSecureShell*>(frontend);
-  AnsiString Response;
-  bool Result = SecureShell->PromptUser(prompt, Response, is_pw);
-  if (Result)
+    if (SecureShell->PromptUser(p->to_server, p->name, p->name_reqd,
+          p->instruction, p->instr_reqd, Prompts, Results))
+    {
+      for (int Index = 0; Index < int(p->n_prompts); Index++)
+      {
+        prompt_t * Prompt = p->prompts[Index];
+        strncpy(Prompt->result, Results->Strings[Index].c_str(), Prompt->result_len);
+        Prompt->result[Prompt->result_len - 1] = '\0';
+      }
+      Result = 1;
+    }
+    else
+    {
+      Result = 0;
+    }
+  }
+  __finally
   {
-    strcpy(str, Response.SubString(1, maxlen - 1).c_str());
+    delete Prompts;
+    delete Results;
   }
 
-  return Result ? 1 : 0;
+  return Result;
+}
+//---------------------------------------------------------------------------
+char * get_ttymode(void * /*frontend*/, const char * /*mode*/)
+{
+  // should never happen when Config.nopty == TRUE
+  assert(false);
+  return NULL;
 }
 //---------------------------------------------------------------------------
 void logevent(void * frontend, const char * string)
 {
   // Frontend maybe NULL here
-  // (one of the examples is indirect call from ssh_gssapi_init from HasGSSAPI)
   if (frontend != NULL)
   {
     ((TSecureShell *)frontend)->PuttyLogEvent(string);
@@ -318,24 +356,29 @@ void set_busy_status(void * /*frontend*/, int /*status*/)
 //---------------------------------------------------------------------------
 static long OpenWinSCPKey(HKEY Key, const char * SubKey, HKEY * Result, bool CanCreate)
 {
-  // This is called once during initialization
-  // from get_seedpath() (winstore.c).
-  // In that case we want it to really look into Putty regkey.
   long R;
   assert(Configuration != NULL);
-  if (Configuration->Initialized)
+
+  assert(Key == HKEY_CURRENT_USER);
+  USEDPARAM(Key);
+
+  AnsiString RegKey = SubKey;
+  int PuttyKeyLen = Configuration->PuttyRegistryStorageKey.Length();
+  assert(RegKey.SubString(1, PuttyKeyLen) == Configuration->PuttyRegistryStorageKey);
+  RegKey = RegKey.SubString(PuttyKeyLen + 1, RegKey.Length() - PuttyKeyLen);
+  if (!RegKey.IsEmpty())
   {
-    assert(Key == HKEY_CURRENT_USER);
+    assert(RegKey[1] == '\\');
+    RegKey.Delete(1, 1);
+  }
 
-    AnsiString RegKey = SubKey;
-    int PuttyKeyLen = Configuration->PuttyRegistryStorageKey.Length();
-    assert(RegKey.SubString(1, PuttyKeyLen) == Configuration->PuttyRegistryStorageKey);
-    RegKey = RegKey.SubString(PuttyKeyLen + 1, RegKey.Length() - PuttyKeyLen);
-    if (!RegKey.IsEmpty())
-    {
-      assert(RegKey[1] == '\\');
-      RegKey.Delete(1, 1);
-    }
+  if (RegKey.IsEmpty())
+  {
+    *Result = static_cast<HKEY>(NULL);
+    R = ERROR_SUCCESS;
+  }
+  else
+  {
     // we expect this to be called only from verify_host_key() or store_host_key()
     assert(RegKey == "SshHostKeys");
 
@@ -352,19 +395,7 @@ static long OpenWinSCPKey(HKEY Key, const char * SubKey, HKEY * Result, bool Can
       R = ERROR_CANTOPEN;
     }
   }
-  else
-  {
-    assert(Configuration->PuttyRegistryStorageKey == SubKey);
 
-    if (CanCreate)
-    {
-      R = RegCreateKey(Key, SubKey, Result);
-    }
-    else
-    {
-      R = RegOpenKey(Key, SubKey, Result);
-    }
-  }
   return R;
 }
 //---------------------------------------------------------------------------
@@ -378,24 +409,32 @@ long reg_create_winscp_key(HKEY Key, const char * SubKey, HKEY * Result)
   return OpenWinSCPKey(Key, SubKey, Result, true);
 }
 //---------------------------------------------------------------------------
-long reg_query_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long * Reserved,
+long reg_query_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long * /*Reserved*/,
   unsigned long * Type, unsigned char * Data, unsigned long * DataSize)
 {
   long R;
   assert(Configuration != NULL);
-  if (Configuration->Initialized)
+
+  THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
+  AnsiString Value;
+  if (Storage == NULL)
+  {
+    if (AnsiString(ValueName) == "RandSeedFile")
+    {
+      Value = Configuration->RandomSeedFileName;
+      R = ERROR_SUCCESS;
+    }
+    else
+    {
+      assert(false);
+      R = ERROR_READ_FAULT;
+    }
+  }
+  else
   {
-    THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
     if (Storage->ValueExists(ValueName))
     {
-      AnsiString Value;
       Value = Storage->ReadStringRaw(ValueName, "");
-      assert(Type != NULL);
-      *Type = REG_SZ;
-      char * DataStr = reinterpret_cast<char *>(Data);
-      strncpy(DataStr, Value.c_str(), *DataSize);
-      DataStr[*DataSize - 1] = '\0';
-      *DataSize = strlen(DataStr);
       R = ERROR_SUCCESS;
     }
     else
@@ -403,48 +442,49 @@ long reg_query_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long *
       R = ERROR_READ_FAULT;
     }
   }
-  else
+
+  if (R == ERROR_SUCCESS)
   {
-    R = RegQueryValueEx(Key, ValueName, Reserved, Type, Data, DataSize);
+    assert(Type != NULL);
+    *Type = REG_SZ;
+    char * DataStr = reinterpret_cast<char *>(Data);
+    strncpy(DataStr, Value.c_str(), *DataSize);
+    DataStr[*DataSize - 1] = '\0';
+    *DataSize = strlen(DataStr);
   }
+
   return R;
 }
 //---------------------------------------------------------------------------
-long reg_set_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long Reserved,
+long reg_set_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long /*Reserved*/,
   unsigned long Type, const unsigned char * Data, unsigned long DataSize)
 {
-  long R;
   assert(Configuration != NULL);
-  if (Configuration->Initialized)
+
+  assert(Type == REG_SZ);
+  USEDPARAM(Type);
+  THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
+  assert(Storage != NULL);
+  if (Storage != NULL)
   {
-    assert(Type == REG_SZ);
-    THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
     AnsiString Value(reinterpret_cast<const char*>(Data), DataSize - 1);
     Storage->WriteStringRaw(ValueName, Value);
-    R = ERROR_SUCCESS;
   }
-  else
-  {
-    R = RegSetValueEx(Key, ValueName, Reserved, Type, Data, DataSize);
-  }
-  return R;
+
+  return ERROR_SUCCESS;
 }
 //---------------------------------------------------------------------------
 long reg_close_winscp_key(HKEY Key)
 {
-  long R;
   assert(Configuration != NULL);
-  if (Configuration->Initialized)
+
+  THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
+  if (Storage != NULL)
   {
-    THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
     delete Storage;
-    R = ERROR_SUCCESS;
-  }
-  else
-  {
-    R = RegCloseKey(Key);
   }
-  return R;
+
+  return ERROR_SUCCESS;
 }
 //---------------------------------------------------------------------------
 TKeyType KeyType(AnsiString FileName)

+ 169 - 101
core/Queue.cpp

@@ -10,6 +10,69 @@
 //---------------------------------------------------------------------------
 class TBackgroundTerminal;
 //---------------------------------------------------------------------------
+class TUserAction
+{
+public:
+  virtual __fastcall ~TUserAction() {}
+  virtual void __fastcall Execute(TTerminalQueue * Queue, void * Arg) = 0;
+};
+//---------------------------------------------------------------------------
+class TQueryUserAction : public TUserAction
+{
+public:
+  virtual void __fastcall Execute(TTerminalQueue * Queue, void * Arg)
+  {
+    Queue->DoQueryUser(Sender, Query, MoreMessages, Answers, Params, Answer, Type, Arg);
+  }
+
+  TObject * Sender;
+  AnsiString Query;
+  TStrings * MoreMessages;
+  int Answers;
+  const TQueryParams * Params;
+  int Answer;
+  TQueryType Type;
+};
+//---------------------------------------------------------------------------
+class TPromptUserAction : public TUserAction
+{
+public:
+  __fastcall TPromptUserAction() :
+    Results(new TStringList())
+  {
+  }
+
+  virtual __fastcall ~TPromptUserAction()
+  {
+    delete Results;
+  }
+
+  virtual void __fastcall Execute(TTerminalQueue * Queue, void * Arg)
+  {
+    Queue->DoPromptUser(Terminal, Kind, Name, Instructions, Prompts, Results, Result, Arg);
+  }
+
+  TTerminal * Terminal;
+  TPromptKind Kind;
+  AnsiString Name;
+  AnsiString Instructions;
+  TStrings * Prompts;
+  TStrings * Results;
+  bool Result;
+};
+//---------------------------------------------------------------------------
+class TShowExtendedExceptionAction : public TUserAction
+{
+public:
+  virtual void __fastcall Execute(TTerminalQueue * Queue, void * Arg)
+  {
+    Queue->DoShowExtendedException(Terminal, E, Arg);
+  }
+
+  TTerminal * Terminal;
+  Exception * E;
+};
+//---------------------------------------------------------------------------
 class TTerminalItem : public TSignalThread
 {
 friend class TQueueItem;
@@ -27,50 +90,25 @@ public:
   bool __fastcall Resume();
 
 protected:
-  struct TQueryUserRec
-  {
-    TObject * Sender;
-    AnsiString Query;
-    TStrings * MoreMessages;
-    int Answers;
-    const TQueryParams * Params;
-    int Answer;
-    TQueryType Type;
-  };
-
-  struct TPromptUserRec
-  {
-    TTerminal * Terminal;
-    AnsiString Prompt;
-    TPromptKind Kind;
-    AnsiString Response;
-    bool Result;
-  };
-
-  struct TShowExtendedExceptionRec
-  {
-    TTerminal * Terminal;
-    Exception * E;
-  };
-
   TTerminalQueue * FQueue;
   TBackgroundTerminal * FTerminal;
   TQueueItem * FItem;
   TCriticalSection * FCriticalSection;
-  void * FUserActionParams;
+  TUserAction * FUserAction;
   bool FCancel;
   bool FPause;
 
   virtual void __fastcall ProcessEvent();
   virtual void __fastcall Finished();
-  bool __fastcall WaitForUserAction(TQueueItem::TStatus ItemStatus, void * Params);
+  bool __fastcall WaitForUserAction(TQueueItem::TStatus ItemStatus, TUserAction * UserAction);
   bool __fastcall OverrideItemStatus(TQueueItem::TStatus & ItemStatus);
 
   void __fastcall TerminalQueryUser(TObject * Sender,
     const AnsiString Query, TStrings * MoreMessages, int Answers,
     const TQueryParams * Params, int & Answer, TQueryType Type, void * Arg);
-  void __fastcall TerminalPromptUser(TTerminal * Terminal,
-    AnsiString Prompt, TPromptKind Kind, AnsiString & Response, bool & Result, void * Arg);
+  void __fastcall TerminalPromptUser(TTerminal * Terminal, TPromptKind Kind,
+    AnsiString Name, AnsiString Instructions,
+    TStrings * Prompts, TStrings * Results, bool & Result, void * Arg);
   void __fastcall TerminalShowExtendedException(TTerminal * Terminal,
     Exception * E, void * Arg);
   void __fastcall OperationFinished(TFileOperation Operation, TOperationSide Side,
@@ -82,7 +120,7 @@ protected:
 //---------------------------------------------------------------------------
 // TSignalThread
 //---------------------------------------------------------------------------
-int __fastcall ThreadProc(void * Thread)
+int __fastcall TSimpleThread::ThreadProc(void * Thread)
 {
   TSimpleThread * SimpleThread = reinterpret_cast<TSimpleThread*>(Thread);
   assert(SimpleThread != NULL);
@@ -94,7 +132,6 @@ int __fastcall ThreadProc(void * Thread)
   {
     SimpleThread->FFinished = true;
     SimpleThread->Finished();
-    EndThread(0);
   }
   return 0;
 }
@@ -104,7 +141,7 @@ __fastcall TSimpleThread::TSimpleThread() :
 {
   unsigned ThreadID;
   FThread = reinterpret_cast<HANDLE>(
-    BeginThread(NULL, 0, ThreadProc, this, CREATE_SUSPENDED, ThreadID));
+    StartThread(NULL, 0, ThreadProc, this, CREATE_SUSPENDED, ThreadID));
 }
 //---------------------------------------------------------------------------
 __fastcall TSimpleThread::~TSimpleThread()
@@ -362,19 +399,31 @@ void __fastcall TTerminalQueue::DeleteItem(TQueueItem * Item)
   if (!FTerminated)
   {
     bool Empty;
+    bool Monitored;
     {
       TGuard Guard(FItemsSection);
 
+      // does this need to be within guard?
+      Monitored = (Item->CompleteEvent != INVALID_HANDLE_VALUE);
       int Index = FItems->Remove(Item);
       assert(Index < FItemsInProcess);
       USEDPARAM(Index);
       FItemsInProcess--;
       delete Item;
-      Empty = (FItems->Count == 0);
+
+      Empty = true;
+      Index = 0;
+      while (Empty && (Index < FItems->Count))
+      {
+        Empty = (GetItem(Index) != INVALID_HANDLE_VALUE);
+        Index++;
+      }
     }
 
     DoListUpdate();
-    if (Empty)
+    // report empty, if queue is empty or only monitored items are pending.
+    // do not report if current item was the last, but was monitored.
+    if (!Monitored && Empty)
     {
       DoEvent(qeEmpty);
     }
@@ -625,6 +674,24 @@ bool __fastcall TTerminalQueue::ItemPause(TQueueItem * Item, bool Pause)
   return Result;
 }
 //---------------------------------------------------------------------------
+bool __fastcall TTerminalQueue::ItemSetCPSLimit(TQueueItem * Item, unsigned long CPSLimit)
+{
+  // to prevent deadlocks when closing queue from other thread
+  bool Result = !FFinished;
+  if (Result)
+  {
+    TGuard Guard(FItemsSection);
+
+    Result = (FItems->IndexOf(Item) >= 0);
+    if (Result)
+    {
+      Item->SetCPSLimit(CPSLimit);
+    }
+  }
+
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminalQueue::Idle()
 {
   if (Now() - FLastIdle > FIdleInterval)
@@ -732,11 +799,12 @@ void __fastcall TTerminalQueue::DoQueryUser(TObject * Sender,
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminalQueue::DoPromptUser(TTerminal * Terminal,
-  AnsiString Prompt, TPromptKind Kind, AnsiString & Response, bool & Result, void * Arg)
+  TPromptKind Kind, AnsiString Name, AnsiString Instructions,
+  TStrings * Prompts, TStrings * Results, bool & Result, void * Arg)
 {
   if (OnPromptUser != NULL)
   {
-    OnPromptUser(Terminal, Prompt, Kind, Response, Result, Arg);
+    OnPromptUser(Terminal, Kind, Name, Instructions, Prompts, Results, Result, Arg);
   }
 }
 //---------------------------------------------------------------------------
@@ -821,7 +889,7 @@ bool __fastcall TBackgroundTerminal::DoQueryReopen(Exception * /*E*/)
 //---------------------------------------------------------------------------
 __fastcall TTerminalItem::TTerminalItem(TTerminalQueue * Queue, int Index) :
   TSignalThread(), FQueue(Queue), FTerminal(NULL), FItem(NULL),
-  FCriticalSection(NULL), FUserActionParams(NULL)
+  FCriticalSection(NULL), FUserAction(NULL)
 {
   FCriticalSection = new TCriticalSection();
 
@@ -902,9 +970,10 @@ void __fastcall TTerminalItem::ProcessEvent()
   {
     // do not show error messages, if task was canceled anyway
     // (for example if transfer is cancelled during reconnection attempts)
-    if (!FCancel)
+    if (!FCancel &&
+        (FTerminal->QueryUserException("", &E, qaOK | qaCancel, NULL, qtError) == qaCancel))
     {
-      FTerminal->ShowExtendedException(&E);
+      FCancel = true;
     }
   }
 
@@ -955,7 +1024,8 @@ void __fastcall TTerminalItem::Idle()
 void __fastcall TTerminalItem::Cancel()
 {
   FCancel = true;
-  if (FItem->GetStatus() == TQueueItem::qsPaused)
+  if ((FItem->GetStatus() == TQueueItem::qsPaused) ||
+      TQueueItem::IsUserActionStatus(FItem->GetStatus()))
   {
     TriggerEvent();
   }
@@ -990,40 +1060,13 @@ bool __fastcall TTerminalItem::ProcessUserAction(void * Arg)
   // the second (user-action) change occurs. Thus it responds it.
   // Then as reaction to the second (user-action) change there will not be
   // any outstanding user-action.
-  bool Result = (FUserActionParams != NULL);
+  bool Result = (FUserAction != NULL);
   if (Result)
   {
     assert(FItem != NULL);
 
-    if (FItem->GetStatus() == TQueueItem::qsQuery)
-    {
-      TQueryUserRec * Params;
-      Params = reinterpret_cast<TQueryUserRec *>(FUserActionParams);
-
-      FQueue->DoQueryUser(Params->Sender, Params->Query, Params->MoreMessages,
-        Params->Answers, Params->Params, Params->Answer, Params->Type, Arg);
-    }
-    else if (FItem->GetStatus() == TQueueItem::qsPrompt)
-    {
-      TPromptUserRec * Params;
-      Params = reinterpret_cast<TPromptUserRec *>(FUserActionParams);
-
-      FQueue->DoPromptUser(Params->Terminal, Params->Prompt,
-        Params->Kind, Params->Response, Params->Result, Arg);
-    }
-    else if (FItem->GetStatus() == TQueueItem::qsError)
-    {
-      TShowExtendedExceptionRec * Params;
-      Params = reinterpret_cast<TShowExtendedExceptionRec *>(FUserActionParams);
-
-      FQueue->DoShowExtendedException(Params->Terminal, Params->E, Arg);
-    }
-    else
-    {
-      assert(false);
-    }
-
-    FUserActionParams = NULL;
+    FUserAction->Execute(FQueue, Arg);
+    FUserAction = NULL;
 
     TriggerEvent();
   }
@@ -1031,7 +1074,7 @@ bool __fastcall TTerminalItem::ProcessUserAction(void * Arg)
 }
 //---------------------------------------------------------------------------
 bool __fastcall TTerminalItem::WaitForUserAction(
-  TQueueItem::TStatus ItemStatus, void * Params)
+  TQueueItem::TStatus ItemStatus, TUserAction * UserAction)
 {
   assert(FItem != NULL);
   assert((FItem->GetStatus() == TQueueItem::qsProcessing) ||
@@ -1043,7 +1086,7 @@ bool __fastcall TTerminalItem::WaitForUserAction(
 
   try
   {
-    FUserActionParams = Params;
+    FUserAction = UserAction;
 
     FItem->SetStatus(ItemStatus);
     FQueue->DoEvent(qePendingUserAction);
@@ -1052,7 +1095,7 @@ bool __fastcall TTerminalItem::WaitForUserAction(
   }
   __finally
   {
-    FUserActionParams = NULL;
+    FUserAction = NULL;
     FItem->SetStatus(PrevStatus);
   }
 
@@ -1077,25 +1120,31 @@ void __fastcall TTerminalItem::TerminalQueryUser(TObject * Sender,
     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;
+    TQueryUserAction Action;
+    Action.Sender = Sender;
+    Action.Query = Query;
+    Action.MoreMessages = MoreMessages;
+    Action.Answers = Answers;
+    Action.Params = Params;
+    Action.Answer = Answer;
+    Action.Type = Type;
+
+    // if the query is "error", present it as an "error" state in UI,
+    // however it is still handled as query by the action.
 
-    if (WaitForUserAction(TQueueItem::qsQuery, &QueryUserRec))
+    TQueueItem::TStatus ItemStatus =
+      (Action.Type == qtError ? TQueueItem::qsError : TQueueItem::qsQuery);
+
+    if (WaitForUserAction(ItemStatus, &Action))
     {
-      Answer = QueryUserRec.Answer;
+      Answer = Action.Answer;
     }
   }
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminalItem::TerminalPromptUser(TTerminal * Terminal,
-  AnsiString Prompt, TPromptKind Kind, AnsiString & Response, bool & Result,
-  void * Arg)
+  TPromptKind Kind, AnsiString Name, AnsiString Instructions, TStrings * Prompts,
+  TStrings * Results, bool & Result, void * Arg)
 {
   if (FItem == NULL)
   {
@@ -1108,17 +1157,19 @@ void __fastcall TTerminalItem::TerminalPromptUser(TTerminal * Terminal,
     USEDPARAM(Arg);
     assert(Arg == NULL);
 
-    TPromptUserRec PromptUserRec;
-    PromptUserRec.Terminal = Terminal;
-    PromptUserRec.Prompt = Prompt;
-    PromptUserRec.Kind = Kind;
-    PromptUserRec.Response = Response.c_str();
-    PromptUserRec.Result = Result;
+    TPromptUserAction Action;
+    Action.Terminal = Terminal;
+    Action.Kind = Kind;
+    Action.Name = Name;
+    Action.Instructions = Instructions;
+    Action.Prompts = Prompts;
+    Action.Results->AddStrings(Results);
 
-    if (WaitForUserAction(TQueueItem::qsPrompt, &PromptUserRec))
+    if (WaitForUserAction(TQueueItem::qsPrompt, &Action))
     {
-      Response = PromptUserRec.Response.c_str();
-      Result = PromptUserRec.Result;
+      Results->Clear();
+      Results->AddStrings(Action.Results);
+      Result = Action.Result;
     }
   }
 }
@@ -1133,11 +1184,11 @@ void __fastcall TTerminalItem::TerminalShowExtendedException(
       !E->Message.IsEmpty() &&
       (dynamic_cast<EAbort*>(E) == NULL))
   {
-    TShowExtendedExceptionRec ShowExtendedExceptionRec;
-    ShowExtendedExceptionRec.Terminal = Terminal;
-    ShowExtendedExceptionRec.E = E;
+    TShowExtendedExceptionAction Action;
+    Action.Terminal = Terminal;
+    Action.E = E;
 
-    WaitForUserAction(TQueueItem::qsError, &ShowExtendedExceptionRec);
+    WaitForUserAction(TQueueItem::qsError, &Action);
   }
 }
 //---------------------------------------------------------------------------
@@ -1204,7 +1255,8 @@ bool __fastcall TTerminalItem::OverrideItemStatus(TQueueItem::TStatus & ItemStat
 //---------------------------------------------------------------------------
 __fastcall TQueueItem::TQueueItem() :
   FStatus(qsPending), FTerminalItem(NULL), FSection(NULL), FProgressData(NULL),
-  FQueue(NULL), FInfo(NULL), FCompleteEvent(INVALID_HANDLE_VALUE)
+  FQueue(NULL), FInfo(NULL), FCompleteEvent(INVALID_HANDLE_VALUE),
+  FCPSLimit(-1)
 {
   FSection = new TCriticalSection();
   FInfo = new TInfo();
@@ -1249,7 +1301,7 @@ void __fastcall TQueueItem::SetStatus(TStatus Status)
 }
 //---------------------------------------------------------------------------
 void __fastcall TQueueItem::SetProgress(
-  const TFileOperationProgressType & ProgressData)
+  TFileOperationProgressType & ProgressData)
 {
   {
     TGuard Guard(FSection);
@@ -1257,6 +1309,12 @@ void __fastcall TQueueItem::SetProgress(
     assert(FProgressData != NULL);
     *FProgressData = ProgressData;
     FProgressData->Reset();
+
+    if (FCPSLimit >= 0)
+    {
+      ProgressData.CPSLimit = static_cast<unsigned long>(FCPSLimit);
+      FCPSLimit = -1;
+    }
   }
   FQueue->DoQueueItemUpdate(this);
 }
@@ -1303,6 +1361,11 @@ void __fastcall TQueueItem::Execute(TTerminalItem * TerminalItem)
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TQueueItem::SetCPSLimit(unsigned long CPSLimit)
+{
+  FCPSLimit = static_cast<long>(CPSLimit);
+}
+//---------------------------------------------------------------------------
 // TQueueItemProxy
 //---------------------------------------------------------------------------
 __fastcall TQueueItemProxy::TQueueItemProxy(TTerminalQueue * Queue,
@@ -1407,6 +1470,11 @@ bool __fastcall TQueueItemProxy::ProcessUserAction(void * Arg)
   return Result;
 }
 //---------------------------------------------------------------------------
+bool __fastcall TQueueItemProxy::SetCPSLimit(unsigned long CPSLimit)
+{
+  return FQueue->ItemSetCPSLimit(FQueueItem, CPSLimit);
+}
+//---------------------------------------------------------------------------
 int __fastcall TQueueItemProxy::GetIndex()
 {
   assert(FQueueStatus != NULL);

+ 15 - 6
core/Queue.h

@@ -7,8 +7,6 @@
 //---------------------------------------------------------------------------
 class TSimpleThread
 {
-friend int __fastcall ThreadProc(void * Thread);
-
 public:
   __fastcall TSimpleThread();
   virtual __fastcall ~TSimpleThread();
@@ -24,6 +22,8 @@ protected:
 
   virtual void __fastcall Execute() = 0;
   virtual void __fastcall Finished();
+
+  static int __fastcall ThreadProc(void * Thread);
 };
 //---------------------------------------------------------------------------
 class TSignalThread : public TSimpleThread
@@ -62,7 +62,6 @@ typedef void __fastcall (__closure * TQueueEventEvent)
 //---------------------------------------------------------------------------
 class TTerminalQueue : public TSignalThread
 {
-friend class TTerminalItem;
 friend class TQueueItem;
 friend class TQueueItemProxy;
 
@@ -84,6 +83,11 @@ public:
   __property TQueueEventEvent OnEvent = { read = FOnEvent, write = FOnEvent };
 
 protected:
+  friend class TTerminalItem;
+  friend class TQueryUserAction;
+  friend class TPromptUserAction;
+  friend class TShowExtendedExceptionAction;
+
   TQueryUserEvent FOnQueryUser;
   TPromptUserEvent FOnPromptUser;
   TExtendedExceptionEvent FOnShowExtendedException;
@@ -111,6 +115,7 @@ protected:
   bool __fastcall ItemExecuteNow(TQueueItem * Item);
   bool __fastcall ItemDelete(TQueueItem * Item);
   bool __fastcall ItemPause(TQueueItem * Item, bool Pause);
+  bool __fastcall ItemSetCPSLimit(TQueueItem * Item, unsigned long CPSLimit);
 
   void __fastcall RetryItem(TQueueItem * Item);
   void __fastcall DeleteItem(TQueueItem * Item);
@@ -122,8 +127,9 @@ protected:
   void __fastcall DoQueryUser(TObject * Sender, const AnsiString Query,
     TStrings * MoreMessages, int Answers, const TQueryParams * Params, int & Answer,
     TQueryType Type, void * Arg);
-  void __fastcall DoPromptUser(TTerminal * Terminal, AnsiString Prompt,
-    TPromptKind Kind, AnsiString & Response, bool & Result, void * Arg);
+  void __fastcall DoPromptUser(TTerminal * Terminal, TPromptKind Kind,
+    AnsiString Name, AnsiString Instructions, TStrings * Prompts,
+    TStrings * Results, bool & Result, void * Arg);
   void __fastcall DoShowExtendedException(TTerminal * Terminal,
     Exception * E, void * Arg);
   void __fastcall DoQueueItemUpdate(TQueueItem * Item);
@@ -166,6 +172,7 @@ protected:
   TQueueItem::TInfo * FInfo;
   TTerminalQueue * FQueue;
   HANDLE FCompleteEvent;
+  long FCPSLimit;
 
   __fastcall TQueueItem();
   virtual __fastcall ~TQueueItem();
@@ -174,8 +181,9 @@ protected:
   TStatus __fastcall GetStatus();
   void __fastcall Execute(TTerminalItem * TerminalItem);
   virtual void __fastcall DoExecute(TTerminal * Terminal) = 0;
-  void __fastcall SetProgress(const TFileOperationProgressType & ProgressData);
+  void __fastcall SetProgress(TFileOperationProgressType & ProgressData);
   void __fastcall GetData(TQueueItemProxy * Proxy);
+  void __fastcall SetCPSLimit(unsigned long CPSLimit);
   virtual AnsiString __fastcall StartupDirectory() = 0;
 };
 //---------------------------------------------------------------------------
@@ -194,6 +202,7 @@ public:
   bool __fastcall Delete();
   bool __fastcall Pause();
   bool __fastcall Resume();
+  bool __fastcall SetCPSLimit(unsigned long CPSLimit);
 
   __property TFileOperationProgressType * ProgressData = { read = GetProgressData };
   __property TQueueItem::TInfo * Info = { read = FInfo };

+ 62 - 9
core/RemoteFiles.cpp

@@ -71,7 +71,16 @@ AnsiString __fastcall UnixExtractFilePath(const AnsiString Path)
 AnsiString __fastcall UnixExtractFileName(const AnsiString Path)
 {
   int Pos = Path.LastDelimiter('/');
-  return (Pos > 0) ? Path.SubString(Pos + 1, Path.Length() - Pos) : Path;
+  AnsiString Result;
+  if (Pos > 0)
+  {
+    Result = Path.SubString(Pos + 1, Path.Length() - Pos);
+  }
+  else
+  {
+    Result = Path;
+  }
+  return Result;
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall UnixExtractFileExt(const AnsiString Path)
@@ -1048,9 +1057,11 @@ __fastcall TRemoteDirectoryFile::TRemoteDirectoryFile() : TRemoteFile()
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-__fastcall TRemoteParentDirectory::TRemoteParentDirectory() : TRemoteDirectoryFile()
+__fastcall TRemoteParentDirectory::TRemoteParentDirectory(TTerminal * ATerminal)
+  : TRemoteDirectoryFile()
 {
   FileName = PARENTDIRECTORY;
+  Terminal = ATerminal;
 }
 //=== TRemoteFileList ------------------------------------------------------
 __fastcall TRemoteFileList::TRemoteFileList():
@@ -1372,8 +1383,9 @@ void __fastcall TRemoteDirectoryCache::Delete(int Index)
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-__fastcall TRemoteDirectoryChangesCache::TRemoteDirectoryChangesCache() :
-  TStringList()
+__fastcall TRemoteDirectoryChangesCache::TRemoteDirectoryChangesCache(int MaxSize) :
+  TStringList(),
+  FMaxSize(MaxSize)
 {
 }
 //---------------------------------------------------------------------------
@@ -1387,18 +1399,36 @@ bool __fastcall TRemoteDirectoryChangesCache::GetIsEmpty() const
   return (const_cast<TRemoteDirectoryChangesCache*>(this)->Count == 0);
 }
 //---------------------------------------------------------------------------
+void __fastcall TRemoteDirectoryChangesCache::SetValue(const AnsiString & Name,
+  const AnsiString & Value)
+{
+  int Index = IndexOfName(Name);
+  if (Index > 0)
+  {
+    Delete(Index);
+  }
+  Values[Name] = Value;
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall TRemoteDirectoryChangesCache::GetValue(const AnsiString & Name)
+{
+  AnsiString Value = Values[Name];
+  SetValue(Name, Value);
+  return Value;
+}
+//---------------------------------------------------------------------------
 void __fastcall TRemoteDirectoryChangesCache::AddDirectoryChange(
   const AnsiString SourceDir, const AnsiString Change,
   const AnsiString TargetDir)
 {
   assert(!TargetDir.IsEmpty());
-  Values[TargetDir] = "//";
+  SetValue(TargetDir, "//");
   if (TTerminal::ExpandFileName(Change, SourceDir) != TargetDir)
   {
     AnsiString Key;
     if (DirectoryChangeKey(SourceDir, Change, Key))
     {
-      Values[Key] = TargetDir;
+      SetValue(Key, TargetDir);
     }
   }
 }
@@ -1446,7 +1476,7 @@ bool __fastcall TRemoteDirectoryChangesCache::GetDirectoryChange(
   Result = (IndexOfName(Key) >= 0);
   if (Result)
   {
-    TargetDir = Values[Key];
+    TargetDir = GetValue(Key);
     // TargetDir is not "//" here only when Change is full path to symbolic link
     if (TargetDir == "//")
     {
@@ -1458,7 +1488,7 @@ bool __fastcall TRemoteDirectoryChangesCache::GetDirectoryChange(
     Result = DirectoryChangeKey(SourceDir, Change, Key);
     if (Result)
     {
-      AnsiString Directory = Values[Key];
+      AnsiString Directory = GetValue(Key);
       Result = !Directory.IsEmpty();
       if (Result)
       {
@@ -1471,7 +1501,30 @@ bool __fastcall TRemoteDirectoryChangesCache::GetDirectoryChange(
 //---------------------------------------------------------------------------
 void __fastcall TRemoteDirectoryChangesCache::Serialize(AnsiString & Data)
 {
-  Data = "A" + Text;
+  Data = "A";
+  int ACount = Count;
+  if (ACount > FMaxSize)
+  {
+    TStrings * Limited = new TStringList();
+    try
+    {
+      int Index = ACount - FMaxSize;
+      while (Index < ACount)
+      {
+        Limited->Add(Strings[Index]);
+        Index++;
+      }
+      Data += Limited->Text;
+    }
+    __finally
+    {
+      delete Limited;
+    }
+  }
+  else
+  {
+    Data += Text;
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TRemoteDirectoryChangesCache::Deserialize(const AnsiString Data)

+ 6 - 2
core/RemoteFiles.h

@@ -123,7 +123,7 @@ public:
 class TRemoteParentDirectory : public TRemoteDirectoryFile
 {
 public:
-  __fastcall TRemoteParentDirectory();
+  __fastcall TRemoteParentDirectory(TTerminal * Terminal);
 };
 //---------------------------------------------------------------------------
 class TRemoteFileList : public TObjectList
@@ -213,7 +213,7 @@ private:
 class TRemoteDirectoryChangesCache : private TStringList
 {
 public:
-  __fastcall TRemoteDirectoryChangesCache();
+  __fastcall TRemoteDirectoryChangesCache(int MaxSize);
 
   void __fastcall AddDirectoryChange(const AnsiString SourceDir,
     const AnsiString Change, const AnsiString TargetDir);
@@ -232,6 +232,10 @@ private:
   static bool __fastcall DirectoryChangeKey(const AnsiString SourceDir,
     const AnsiString Change, AnsiString & Key);
   bool __fastcall GetIsEmpty() const;
+  void __fastcall SetValue(const AnsiString & Name, const AnsiString & Value);
+  AnsiString __fastcall GetValue(const AnsiString & Name);
+
+  int FMaxSize;
 };
 //---------------------------------------------------------------------------
 class TRights

+ 102 - 109
core/ScpFileSystem.cpp

@@ -116,9 +116,9 @@ const TCommandType DefaultCommandSet[ShellCommandCount] = {
 /*CurrentDirectory*/    {  1,  1, F, F, F, "pwd" },
 /*ChangeDirectory*/     {  0,  0, F, T, F, "cd %s" /* directory */ },
 // list directory can be empty on permission denied, this is handled in ReadDirectory
-/*ListDirectory*/       { -1, -1, F, F, F, "ls -la %s \"%s\"" /* directory */ },
-/*ListCurrentDirectory*/{ -1, -1, F, F, F, "ls -la %s" },
-/*ListFile*/            {  1,  1, F, F, F, "ls -lad %s \"%s\"" /* file/directory */ },
+/*ListDirectory*/       { -1, -1, F, F, F, "%s %s \"%s\"" /* listing command, options, directory */ },
+/*ListCurrentDirectory*/{ -1, -1, F, F, F, "%s %s" /* listing command, options */ },
+/*ListFile*/            {  1,  1, F, F, F, "%s -d %s \"%s\"" /* listing command, options, file/directory */ },
 /*LookupUserGroups*/    {  0,  1, F, F, F, "groups" },
 /*CopyToRemote*/        { -1, -1, T, F, T, "scp -r %s -d -t \"%s\"" /* options, directory */ },
 /*CopyToLocal*/         { -1, -1, F, F, T, "scp -r %s -d -f \"%s\"" /* options, file */ },
@@ -131,7 +131,6 @@ const TCommandType DefaultCommandSet[ShellCommandCount] = {
 /*HomeDirectory*/       {  0,  0, F, T, F, "cd" },
 /*Unset*/               {  0,  0, F, F, F, "unset \"%s\"" /* variable */ },
 /*Unalias*/             {  0,  0, F, F, F, "unalias \"%s\"" /* alias */ },
-/*AliasGroupList*/      {  0,  0, F, F, F, "alias ls=\"ls -g\"" },
 /*CreateLink*/          {  0,  0, T, F, F, "ln %s \"%s\" \"%s\"" /*symbolic (-s), filename, point to*/},
 /*CopyFile*/            {  0,  0, T, F, F, "cp -p -r -f \"%s\" \"%s\"" /* file/directory, target name*/},
 /*AnyCommand*/          {  0, -1, T, T, F, "%s" }
@@ -678,7 +677,6 @@ void __fastcall TSCPFileSystem::DoStartup()
   #define COND_OPER(OPER) if (FTerminal->SessionData->OPER) OPER()
   COND_OPER(ClearAliases);
   COND_OPER(UnsetNationalVars);
-  COND_OPER(AliasGroupList);
   #undef COND_OPER
 }
 //---------------------------------------------------------------------------
@@ -801,19 +799,6 @@ void __fastcall TSCPFileSystem::ClearAliases()
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TSCPFileSystem::AliasGroupList()
-{
-  try
-  {
-    FTerminal->LogEvent("Aliasing LS to display file group.");
-    ExecCommand(fsAliasGroupList);
-  }
-  catch (Exception &E)
-  {
-    FTerminal->CommandError(&E, LoadStr(ALIAS_GROUPLIST_ERROR));
-  }
-}
-//---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::UnsetNationalVars()
 {
   try
@@ -877,47 +862,49 @@ void __fastcall TSCPFileSystem::CachedChangeDirectory(const AnsiString Directory
 void __fastcall TSCPFileSystem::ReadDirectory(TRemoteFileList * FileList)
 {
   assert(FileList);
-  TStringList * OutputCopy = NULL;
-  try
-  {
-    // emtying file list moved before command execution
-    FileList->Clear();
+  // emtying file list moved before command execution
+  FileList->Clear();
 
-    bool Again;
+  bool Again;
 
-    do
+  do
+  {
+    Again = false;
+    try
     {
-      Again = false;
-      try
+      int Params = ecDefault | ecReadProgress |
+        FLAGMASK(FTerminal->SessionData->IgnoreLsWarnings, ecIgnoreWarnings);
+      const char * Options =
+        ((FLsFullTime == asAuto) || (FLsFullTime == asOn)) ? FullTimeOption : "";
+      bool ListCurrentDirectory = (FileList->Directory == FTerminal->CurrentDirectory);
+      if (ListCurrentDirectory)
       {
-        int Params = ecDefault | ecReadProgress |
-          FLAGMASK(FTerminal->SessionData->IgnoreLsWarnings, ecIgnoreWarnings);
-        const char * Options =
-          ((FLsFullTime == asAuto) || (FLsFullTime == asOn)) ? FullTimeOption : "";
-        bool ListCurrentDirectory = (FileList->Directory == FTerminal->CurrentDirectory);
-        if (ListCurrentDirectory)
-        {
-          FTerminal->LogEvent("Listing current directory.");
-          ExecCommand(fsListCurrentDirectory, ARRAYOFCONST((Options)), Params);
-        }
-          else
-        {
-          FTerminal->LogEvent(FORMAT("Listing directory \"%s\".",
-            (FileList->Directory)));
-          ExecCommand(fsListDirectory, ARRAYOFCONST((Options, DelimitStr(FileList->Directory))),
-            Params);
-        }
+        FTerminal->LogEvent("Listing current directory.");
+        ExecCommand(fsListCurrentDirectory,
+          ARRAYOFCONST((FTerminal->SessionData->ListingCommand, Options)), Params);
+      }
+        else
+      {
+        FTerminal->LogEvent(FORMAT("Listing directory \"%s\".",
+          (FileList->Directory)));
+        ExecCommand(fsListDirectory,
+          ARRAYOFCONST((FTerminal->SessionData->ListingCommand, Options,
+            DelimitStr(FileList->Directory))),
+          Params);
+      }
 
-        TRemoteFile * File;
+      TRemoteFile * File;
 
-        // If output is not empty, we have succesfully got file listing,
-        // otherwise there was an error, in case it was "permission denied"
-        // we try to get at least parent directory (see "else" statement below)
-        if (FOutput->Count > 0)
+      // If output is not empty, we have succesfully got file listing,
+      // otherwise there was an error, in case it was "permission denied"
+      // we try to get at least parent directory (see "else" statement below)
+      if (FOutput->Count > 0)
+      {
+        // Copy LS command output, because eventual symlink analysis would
+        // modify FTerminal->Output
+        TStringList * OutputCopy = new TStringList();
+        try
         {
-          // Copy LS command output, because eventual symlink analysis would
-          // modify FTerminal->Output
-          OutputCopy = new TStringList();
           OutputCopy->Assign(FOutput);
 
           // delete leading "total xxx" line
@@ -934,73 +921,73 @@ void __fastcall TSCPFileSystem::ReadDirectory(TRemoteFileList * FileList)
             FileList->AddFile(File);
           }
         }
-          else
+        __finally
         {
-          bool Empty;
-          if (ListCurrentDirectory)
-          {
-            // Empty file list -> probably "permision denied", we
-            // at least get link to parent directory ("..")
-            FTerminal->ReadFile(
-              UnixIncludeTrailingBackslash(FTerminal->FFiles->Directory) +
-                PARENTDIRECTORY, File);
-            Empty = (File == NULL);
-            if (!Empty)
-            {
-              assert(File->IsParentDirectory);
-              FileList->AddFile(File);
-            }
-          }
-          else
-          {
-            Empty = true;
-          }
-
-          if (Empty)
+          delete OutputCopy;
+        }
+      }
+      else
+      {
+        bool Empty;
+        if (ListCurrentDirectory)
+        {
+          // Empty file list -> probably "permision denied", we
+          // at least get link to parent directory ("..")
+          FTerminal->ReadFile(
+            UnixIncludeTrailingBackslash(FTerminal->FFiles->Directory) +
+              PARENTDIRECTORY, File);
+          Empty = (File == NULL);
+          if (!Empty)
           {
-            throw Exception(FMTLOAD(EMPTY_DIRECTORY, (FileList->Directory)));
+            assert(File->IsParentDirectory);
+            FileList->AddFile(File);
           }
         }
+        else
+        {
+          Empty = true;
+        }
 
-        if (FLsFullTime == asAuto)
+        if (Empty)
         {
-            FTerminal->LogEvent(
-              FORMAT("Directory listing with %s succeed, next time all errors during "
-                "directory listing will be displayed immediatelly.",
-                (FullTimeOption)));
-            FLsFullTime = asOn;
+          throw Exception(FMTLOAD(EMPTY_DIRECTORY, (FileList->Directory)));
         }
       }
-      catch(Exception & E)
+
+      if (FLsFullTime == asAuto)
       {
-        if (FTerminal->Active)
-        {
-          if (FLsFullTime == asAuto)
-          {
-            FTerminal->FLog->AddException(&E);
-            FLsFullTime = asOff;
-            Again = true;
-            FTerminal->LogEvent(
-              FORMAT("Directory listing with %s failed, try again regular listing.",
+          FTerminal->LogEvent(
+            FORMAT("Directory listing with %s succeed, next time all errors during "
+              "directory listing will be displayed immediatelly.",
               (FullTimeOption)));
-          }
-          else
-          {
-            throw;
-          }
+          FLsFullTime = asOn;
+      }
+    }
+    catch(Exception & E)
+    {
+      if (FTerminal->Active)
+      {
+        if (FLsFullTime == asAuto)
+        {
+          FTerminal->FLog->AddException(&E);
+          FLsFullTime = asOff;
+          Again = true;
+          FTerminal->LogEvent(
+            FORMAT("Directory listing with %s failed, try again regular listing.",
+            (FullTimeOption)));
         }
         else
         {
           throw;
         }
       }
+      else
+      {
+        throw;
+      }
     }
-    while (Again);
-  }
-  __finally
-  {
-    delete OutputCopy;
   }
+  while (Again);
 }
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::ReadSymlink(TRemoteFile * SymlinkFile,
@@ -1044,7 +1031,9 @@ void __fastcall TSCPFileSystem::CustomReadFile(const AnsiString FileName,
   // the auto-detection of --full-time support is not implemented for fsListFile,
   // so we use it only if we already know that it is supported (asOn).
   const char * Options = (FLsFullTime == asOn) ? FullTimeOption : "";
-  ExecCommand(fsListFile, ARRAYOFCONST((Options, DelimitStr(FileName))), Params);
+  ExecCommand(fsListFile,
+    ARRAYOFCONST((FTerminal->SessionData->ListingCommand, Options, DelimitStr(FileName))),
+    Params);
   if (FOutput->Count)
   {
     int LineIndex = 0;
@@ -1058,11 +1047,11 @@ void __fastcall TSCPFileSystem::CustomReadFile(const AnsiString FileName,
 }
 //---------------------------------------------------------------------------
 void __fastcall TSCPFileSystem::DeleteFile(const AnsiString FileName,
-  const TRemoteFile * File, bool Recursive)
+  const TRemoteFile * File, int Params)
 {
-  USEDPARAM(Recursive);
   USEDPARAM(File);
-  assert(Recursive || (File && File->IsSymLink));
+  USEDPARAM(Params);
+  assert(FLAGCLEAR(Params, dfNoRecursive) || (File && File->IsSymLink));
   ExecCommand(fsDeleteFile, ARRAYOFCONST((DelimitStr(FileName))));
 }
 //---------------------------------------------------------------------------
@@ -1172,7 +1161,10 @@ void __fastcall TSCPFileSystem::CustomCommandOnFile(const AnsiString FileName,
 
   if (!Dir || (Params & ccApplyToDirectories))
   {
-    AnsiString Cmd = TRemoteCustomCommand(FileName, "").Complete(Command, true);
+    TCustomCommandData Data(FTerminal);
+    AnsiString Cmd = TRemoteCustomCommand(
+      Data, FTerminal->CurrentDirectory, FileName, "").
+      Complete(Command, true);
 
     AnyCommand(Cmd, OutputEvent);
   }
@@ -1601,7 +1593,7 @@ void __fastcall TSCPFileSystem::SCPSource(const AnsiString FileName,
           if (OperationProgress->AsciiTransfer)
           {
             BlockBuf.Convert(FTerminal->Configuration->LocalEOLType,
-              FTerminal->SessionData->EOLType, cpRemoveCtrlZ);
+              FTerminal->SessionData->EOLType, cpRemoveCtrlZ | cpRemoveBOM);
             BlockBuf.Memory->Seek(0, soFromBeginning);
             AsciiBuf.ReadStream(BlockBuf.Memory, BlockBuf.Size, true);
             // We don't need it any more
@@ -1667,10 +1659,11 @@ void __fastcall TSCPFileSystem::SCPSource(const AnsiString FileName,
               OperationProgress->ChangeTransferSize(AsciiBuf.Size);
               while (!OperationProgress->IsTransferDone())
               {
+                unsigned long BlockSize = OperationProgress->TransferBlockSize();
                 FSecureShell->Send(
                   AsciiBuf.Data + (unsigned int)OperationProgress->TransferedSize,
-                  OperationProgress->TransferBlockSize());
-                OperationProgress->AddTransfered(OperationProgress->TransferBlockSize());
+                  BlockSize);
+                OperationProgress->AddTransfered(BlockSize);
                 if (OperationProgress->Cancel == csCancelTransfer)
                 {
                   throw Exception(USER_TERMINATED);

+ 1 - 2
core/ScpFileSystem.h

@@ -41,7 +41,7 @@ public:
     const TRemoteProperties * Properties);
   virtual void __fastcall CreateLink(const AnsiString FileName, const AnsiString PointTo, bool Symbolic);
   virtual void __fastcall DeleteFile(const AnsiString FileName,
-    const TRemoteFile * File, bool Recursive);
+    const TRemoteFile * File, int Params);
   virtual void __fastcall CustomCommandOnFile(const AnsiString FileName,
     const TRemoteFile * File, AnsiString Command, int Params, TCaptureOutputEvent OutputEvent);
   virtual void __fastcall DoStartup();
@@ -86,7 +86,6 @@ private:
   int FLsFullTime;
   TCaptureOutputEvent FOnCaptureOutput;
 
-  void __fastcall AliasGroupList();
   void __fastcall ClearAliases();
   void __fastcall CustomReadFile(const AnsiString FileName,
     TRemoteFile *& File, TRemoteFile * ALinkedByFile);

File diff suppressed because it is too large
+ 317 - 263
core/Script.cpp


+ 18 - 26
core/Script.h

@@ -3,6 +3,7 @@
 #define ScriptH
 //---------------------------------------------------------------------------
 #include <time.h>
+#include "Option.h"
 #include "Terminal.h"
 #include "FileOperationProgress.h"
 //---------------------------------------------------------------------------
@@ -14,27 +15,18 @@ class TTerminalList;
 //---------------------------------------------------------------------------
 typedef void __fastcall (__closure *TScriptPrintEvent)(TScript * Script, const AnsiString Str);
 typedef void __fastcall (__closure *TScriptSynchronizeStartStop)(TScript * Script,
-  const AnsiString LocalDirectory, const AnsiString RemoteDirectory);
+  const AnsiString LocalDirectory, const AnsiString RemoteDirectory,
+  const TCopyParamType & CopyParam, int SynchronizeParams);
 //---------------------------------------------------------------------------
-class TScriptProcParams
+class TScriptProcParams : public TOptions
 {
 public:
-  __fastcall TScriptProcParams(TStrings * Params, const AnsiString & ParamsStr);
-  void __fastcall SkipParam();
+  __fastcall TScriptProcParams(AnsiString ParamsStr);
 
-  __property AnsiString Param[int Index] = { read = GetParam };
-  __property int ParamCount = { read = GetParamCount };
-  __property void * Arg = { read = FArg, write = FArg };
   __property AnsiString ParamsStr = { read = FParamsStr };
 
 private:
-  TStrings * FParams;
-  int FSkipParams;
-  void * FArg;
   AnsiString FParamsStr;
-
-  AnsiString __fastcall GetParam(int Index);
-  int __fastcall GetParamCount();
 };
 //---------------------------------------------------------------------------
 class TScript
@@ -42,15 +34,14 @@ class TScript
 public:
   enum TBatchMode { BatchOff, BatchOn, BatchAbort, BatchContinue };
 
-  __fastcall TScript();
-  __fastcall TScript(TTerminal * Terminal);
+  __fastcall TScript(bool LimitedOutput);
   virtual __fastcall ~TScript();
 
-  void __fastcall Command(const AnsiString Cmd);
+  void __fastcall Command(AnsiString Cmd);
 
   void __fastcall Synchronize(const AnsiString LocalDirectory,
     const AnsiString RemoteDirectory, const TCopyParamType & CopyParam,
-    TSynchronizeChecklist ** Checklist);
+    int SynchronizeParams, TSynchronizeChecklist ** Checklist);
 
   __property TScriptPrintEvent OnPrint = { read = FOnPrint, write = FOnPrint };
   __property TExtendedExceptionEvent OnShowExtendedException = { read = FOnShowExtendedException, write = FOnShowExtendedException };
@@ -76,15 +67,16 @@ protected:
   int FSynchronizeMode;
   bool FKeepingUpToDate;
   AnsiString FSynchronizeIntro;
+  bool FLimitedOutput;
 
   virtual void __fastcall ResetTransfer();
   virtual void __fastcall ConnectTerminal(TTerminal * Terminal);
   bool __fastcall EnsureCommandSessionFallback(TFSCapability Capability);
   void __fastcall Print(const AnsiString Str);
   void __fastcall PrintLine(const AnsiString Str);
-  void __fastcall Tokenize(const AnsiString Str, TStrings * Tokens,
-    AnsiString & AllButFirst);
   void __fastcall CheckSession();
+  void __fastcall CheckParams(TScriptProcParams * Parameters);
+  void __fastcall CopyParamParams(TCopyParamType & CopyParam, TScriptProcParams * Parameters);
   enum TFileListType
   {
     fltDefault =     0x00,
@@ -98,7 +90,6 @@ protected:
     int Start, int End, TFileListType ListType);
   void __fastcall FreeFileList(TStrings * FileList);
 
-  void __fastcall SecondaryProc(TScriptProcParams * Parameters);
   void __fastcall DummyProc(TScriptProcParams * Parameters);
   void __fastcall HelpProc(TScriptProcParams * Parameters);
   void __fastcall CallProc(TScriptProcParams * Parameters);
@@ -139,10 +130,10 @@ typedef void __fastcall (__closure *TScriptPrintProgressEvent)(TScript * Script,
 class TManagementScript : public TScript
 {
 public:
-  __fastcall TManagementScript(TStoredSessionList * StoredSessions);
+  __fastcall TManagementScript(TStoredSessionList * StoredSessions, bool LimitedOutput);
   virtual __fastcall ~TManagementScript();
 
-  void __fastcall Connect(const AnsiString Session);
+  void __fastcall Connect(const AnsiString Session, TOptions * Options, bool CheckParams);
 
   __property TScriptInputEvent OnInput = { read = FOnInput, write = FOnInput };
   __property TScriptQueryCancelEvent OnQueryCancel = { read = FOnQueryCancel, write = FOnQueryCancel };
@@ -181,13 +172,14 @@ protected:
   bool __fastcall QueryCancel();
   void __fastcall TerminalSynchronizeDirectory(const AnsiString LocalDirectory,
     const AnsiString RemoteDirectory, bool & Continue, bool Collect);
-  void __fastcall DoConnect(const AnsiString Session);
+  void __fastcall DoConnect(const AnsiString & Session, TOptions * Options,
+    bool CheckParams);
   void __fastcall DoClose(TTerminal * Terminal);
   virtual bool __fastcall HandleExtendedException(Exception * E,
     TTerminal * Terminal = NULL);
-  void __fastcall TerminalPromptUser(TTerminal * Terminal,
-    AnsiString Prompt, TPromptKind Kind, AnsiString & Response, bool & Result,
-    void * Arg);
+  void __fastcall TerminalPromptUser(TTerminal * Terminal, TPromptKind Kind,
+    AnsiString Name, AnsiString Instructions, TStrings * Prompts,
+    TStrings * Results, bool & Result, void * Arg);
   inline bool __fastcall Synchronizing();
   inline void __fastcall ShowPendingProgress();
 

+ 313 - 150
core/SecureShell.cpp

@@ -44,6 +44,7 @@ __fastcall TSecureShell::TSecureShell(TSessionUI* UI,
   FOnCaptureOutput = NULL;
   FOnReceive = NULL;
   FConfig = new Config();
+  memset(FConfig, 0, sizeof(*FConfig));
   FSocket = INVALID_SOCKET;
   FSocketEvent = CreateEvent(NULL, false, false, NULL);
   FFrozen = false;
@@ -54,6 +55,7 @@ __fastcall TSecureShell::~TSecureShell()
   Active = false;
   ResetConnection();
   CloseHandle(FSocketEvent);
+  ClearConfig(FConfig);
   delete FConfig;
   FConfig = NULL;
 }
@@ -119,10 +121,17 @@ const TSessionInfo & __fastcall TSecureShell::GetSessionInfo()
   return FSessionInfo;
 }
 //---------------------------------------------------------------------
-void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg)
+void __fastcall TSecureShell::ClearConfig(Config * cfg)
 {
-  // clear all (parameters not set below)
+  StrDispose(cfg->remote_cmd_ptr);
+  StrDispose(cfg->remote_cmd_ptr2);
+  // clear all
   memset(cfg, 0, sizeof(*cfg));
+}
+//---------------------------------------------------------------------
+void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg)
+{
+  ClearConfig(cfg);
 
   // user-configurable settings
   ASCOPY(cfg->host, Data->HostName);
@@ -133,6 +142,7 @@ void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg)
   // multi-threaded issues in putty timer list
   cfg->ping_interval = 0;
   cfg->compression = Data->Compression;
+  cfg->tryagent = Data->TryAgent;
   cfg->agentfwd = Data->AgentFwd;
   cfg->addressfamily = Data->AddressFamily;
   ASCOPY(cfg->ssh_rekey_data, Data->RekeyData);
@@ -147,6 +157,7 @@ void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg)
       case cipBlowfish: pcipher = CIPHER_BLOWFISH; break;
       case cipAES: pcipher = CIPHER_AES; break;
       case cipDES: pcipher = CIPHER_DES; break;
+      case cipArcfour: pcipher = CIPHER_ARCFOUR; break;
       default: assert(false);
     }
     cfg->ssh_cipherlist[c] = pcipher;
@@ -160,6 +171,9 @@ void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg)
       case kexDHGroup1: pkex = KEX_DHGROUP1; break;
       case kexDHGroup14: pkex = KEX_DHGROUP14; break;
       case kexDHGEx: pkex = KEX_DHGEX; break;
+      case kexGSSGroup1: pkex = KEX_GSSGROUP1; break;
+      case kexGSSGroup14: pkex = KEX_GSSGROUP14; break;
+      case kexGSSGEx: pkex = KEX_GSSGEX; break;
       default: assert(false);
     }
     cfg->ssh_kexlist[k] = pkex;
@@ -171,11 +185,16 @@ void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg)
   ASCOPY(cfg->keyfile.path, SPublicKeyFile);
   cfg->sshprot = Data->SshProt;
   cfg->ssh2_des_cbc = Data->Ssh2DES;
+  cfg->ssh_no_userauth = Data->SshNoUserAuth;
   cfg->try_tis_auth = Data->AuthTIS;
   cfg->try_ki_auth = Data->AuthKI;
-  cfg->try_gssapi_auth = Data->AuthGSSAPI;
-  cfg->gssapi_fwd_tgt = Data->GSSAPIFwdTGT;
-  ASCOPY(cfg->gssapi_server_realm, Data->GSSAPIServerRealm);
+  cfg->try_sspi_auth = Data->AuthGSSAPI;
+  cfg->sspi_fwd_ticket = Data->GSSAPIFwdTGT;
+  ASCOPY(cfg->service_principal_name, Data->GSSAPIServerRealm);
+  cfg->try_gsskex = Data->TryGSSKEX;
+  cfg->username_from_env = Data->UserNameFromEnvironment;
+  cfg->sspi_no_username = Data->GSSAPIServerChoosesUserName;
+  cfg->sspi_trust_dns = Data->GSSAPITrustDNS;
   cfg->change_username = Data->ChangeUsername;
 
   cfg->proxy_type = Data->ProxyMethod;
@@ -183,7 +202,14 @@ void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg)
   cfg->proxy_port = Data->ProxyPort;
   ASCOPY(cfg->proxy_username, Data->ProxyUsername);
   ASCOPY(cfg->proxy_password, Data->ProxyPassword);
-  ASCOPY(cfg->proxy_telnet_command, Data->ProxyTelnetCommand);
+  if (Data->ProxyMethod == pmCmd)
+  {
+    ASCOPY(cfg->proxy_telnet_command, Data->ProxyLocalCommand);
+  }
+  else
+  {
+    ASCOPY(cfg->proxy_telnet_command, Data->ProxyTelnetCommand);
+  }
   cfg->proxy_dns = Data->ProxyDNS;
   cfg->even_proxy_localhost = Data->ProxyLocalhost;
 
@@ -220,13 +246,21 @@ void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg)
       }
       else
       {
-        ASCOPY(cfg->remote_cmd, Data->Shell);
+        cfg->remote_cmd_ptr = StrNew(Data->Shell.c_str());
       }
     }
     else
     {
-      cfg->ssh_subsys = TRUE;
-      strcpy(cfg->remote_cmd, "sftp");
+      if (Data->SftpServer.IsEmpty())
+      {
+        cfg->ssh_subsys = TRUE;
+        strcpy(cfg->remote_cmd, "sftp");
+      }
+      else
+      {
+        cfg->ssh_subsys = FALSE;
+        cfg->remote_cmd_ptr = StrNew(Data->SftpServer.c_str());
+      }
 
       if (Data->FSProtocol != fsSFTPonly)
       {
@@ -235,23 +269,22 @@ void __fastcall TSecureShell::StoreToConfig(TSessionData * Data, Config * cfg)
         {
           // Following forces Putty to open default shell
           // see ssh.c: do_ssh2_authconn() and ssh1_protocol()
-          cfg->remote_cmd2[0] = '\0';
+          cfg->remote_cmd_ptr2 = StrNew("\0");
         }
         else
         {
-          ASCOPY(cfg->remote_cmd2, Data->Shell);
+          cfg->remote_cmd_ptr2 = StrNew(Data->Shell.c_str());
         }
-        // Putty reads only "ptr" member for fallback
-        cfg->remote_cmd_ptr2 = cfg->remote_cmd2;
       }
-      else
+
+      if ((Data->FSProtocol == fsSFTPonly) && Data->SftpServer.IsEmpty())
       {
         // see psftp_connect() from psftp.c
         cfg->ssh_subsys2 = FALSE;
-        cfg->remote_cmd_ptr2 =
+        cfg->remote_cmd_ptr2 = StrNew(
           "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n"
           "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n"
-          "exec sftp-server";
+          "exec sftp-server");
       }
     }
   }
@@ -286,8 +319,6 @@ void __fastcall TSecureShell::Open()
     PuttyFatalError(InitError);
   }
   FUI->Information(LoadStr(STATUS_CONNECT), true);
-  /*FLoggingContext = log_init(this, (void *)FConfig);
-  FBackend->provide_logctx(FBackendHandle, FLoggingContext);*/
   Init();
 
   CheckConnection(CONNECTION_FAILED);
@@ -378,107 +409,185 @@ void __fastcall TSecureShell::PuttyLogEvent(const AnsiString & Str)
   LogEvent(Str);
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSecureShell::PromptUser(const AnsiString Prompt,
-  AnsiString & Response, bool IsPassword)
-{
-  bool Result;
-  if (!IsPassword)
+bool __fastcall TSecureShell::PromptUser(bool /*ToServer*/,
+  AnsiString AName, bool /*NameRequired*/,
+  AnsiString Instructions, bool /*InstructionsRequired*/,
+  TStrings * Prompts, TStrings * Results)
+{
+  assert(Prompts->Count > 0);
+  assert(Results->Count == Prompts->Count);
+
+  TPromptKind PromptKind;
+  // beware of changing order
+  static const TPuttyTranslation NameTranslation[] = {
+    { "SSH login name", USERNAME_TITLE },
+    { "SSH key passphrase", PASSPHRASE_TITLE },
+    { "SSH TIS authentication", SERVER_PROMPT_TITLE },
+    { "SSH CryptoCard authentication", SERVER_PROMPT_TITLE },
+    { "SSH server: %", SERVER_PROMPT_TITLE2 },
+    { "SSH server authentication", SERVER_PROMPT_TITLE },
+    { "SSH password", PASSWORD_TITLE },
+    { "New SSH password", NEW_PASSWORD_TITLE },
+  };
+
+  AnsiString Name = AName;
+  int Index = TranslatePuttyMessage(NameTranslation, LENOF(NameTranslation), Name);
+
+  const TPuttyTranslation * InstructionTranslation = NULL;
+  const TPuttyTranslation * PromptTranslation = NULL;
+  size_t PromptTranslationCount = 1;
+
+  if (Index == 0) // username
+  {
+    static const TPuttyTranslation UsernamePromptTranslation[] = {
+      { "login as: ", USERNAME_PROMPT2 },
+    };
+
+    PromptTranslation = UsernamePromptTranslation;
+    PromptKind = pkUserName;
+  }
+  else if (Index == 1) // passhrase
+  {
+    static const TPuttyTranslation PassphrasePromptTranslation[] = {
+      { "Passphrase for key \"%s\": ", PROMPT_KEY_PASSPHRASE },
+    };
+
+    PromptTranslation = PassphrasePromptTranslation;
+    PromptKind = pkPassphrase;
+  }
+  else if (Index == 2) // TIS
+  {
+    static const TPuttyTranslation TISInstructionTranslation[] = {
+      { "Using TIS authentication.%", TIS_INSTRUCTION },
+    };
+    static const TPuttyTranslation TISPromptTranslation[] = {
+      { "Response: ", PROMPT_PROMPT },
+    };
+
+    InstructionTranslation = TISInstructionTranslation;
+    PromptTranslation = TISPromptTranslation;
+    PromptKind = pkTIS;
+  }
+  else if (Index == 3) // CryptoCard
+  {
+    static const TPuttyTranslation CryptoCardInstructionTranslation[] = {
+      { "Using CryptoCard authentication.%", CRYPTOCARD_INSTRUCTION },
+    };
+    static const TPuttyTranslation CryptoCardPromptTranslation[] = {
+      { "Response: ", PROMPT_PROMPT },
+    };
+
+    InstructionTranslation = CryptoCardInstructionTranslation;
+    PromptTranslation = CryptoCardPromptTranslation;
+    PromptKind = pkCryptoCard;
+  }
+  else if ((Index == 4) || (Index == 5))
+  {
+    static const TPuttyTranslation KeybInteractiveInstructionTranslation[] = {
+      { "Using keyboard-interactive authentication.%", KEYBINTER_INSTRUCTION },
+    };
+
+    InstructionTranslation = KeybInteractiveInstructionTranslation;
+    PromptKind = pkKeybInteractive;
+  }
+  else if (Index == 6)
+  {
+    assert(Prompts->Count == 1);
+    Prompts->Strings[0] = LoadStr(PASSWORD_PROMPT);
+    PromptKind = pkPassword;
+  }
+  else if (Index == 7)
+  {
+    static const TPuttyTranslation NewPasswordPromptTranslation[] = {
+      { "Current password (blank for previously entered password): ", NEW_PASSWORD_CURRENT_PROMPT },
+      { "Enter new password: ", NEW_PASSWORD_NEW_PROMPT },
+      { "Confirm new password: ", NEW_PASSWORD_CONFIRM_PROMPT },
+    };
+    PromptTranslation = NewPasswordPromptTranslation;
+    PromptTranslationCount = LENOF(NewPasswordPromptTranslation);
+    PromptKind = pkNewPassword;
+  }
+  else
+  {
+    PromptKind = pkPrompt;
+    assert(false);
+  }
+
+  LogEvent(FORMAT("Prompt (%d, %s, %s, %s)", (PromptKind, AName, Instructions, Prompts->Strings[0])));
+
+  Name = Name.Trim();
+
+  if (InstructionTranslation != NULL)
   {
-    assert(Prompt == "login as: ");
-    LogEvent(FORMAT("Username prompt (%s)", (Prompt)));
+    TranslatePuttyMessage(InstructionTranslation, 1, Instructions);
+  }
+
+  // some servers add leading blank line to make the prompt look prettier
+  // on terminal console
+  Instructions = Instructions.Trim();
 
+  for (int Index = 0; Index < Prompts->Count; Index++)
+  {
+    AnsiString Prompt = Prompts->Strings[Index];
+    if (PromptTranslation != NULL)
+    {
+      TranslatePuttyMessage(PromptTranslation, PromptTranslationCount, Prompt);
+    }
+    // some servers add leading blank line to make the prompt look prettier
+    // on terminal console
+    Prompts->Strings[Index] = Prompt.Trim();
+  }
+
+  bool Result = false;
+  if (PromptKind == pkUserName)
+  {
     if (FSessionData->AuthGSSAPI)
     {
       // use empty username if no username was filled on login dialog
       // and GSSAPI auth is enabled, hence there's chance that the server can
-      //  deduce the username otherwise
-      Response = "";
+      // deduce the username otherwise
+      Results->Strings[0] = "";
       Result = true;
     }
-    else
+  }
+  else if ((PromptKind == pkTIS) || (PromptKind == pkCryptoCard) ||
+      (PromptKind == pkKeybInteractive))
+  {
+    if (FSessionData->AuthKIPassword && !FSessionData->Password.IsEmpty() &&
+        !FStoredPasswordTriedForKI && (Prompts->Count == 1) &&
+        !bool(Prompts->Objects[0]))
     {
-      Result = FUI->PromptUser(FSessionData,
-        FMTLOAD(USERNAME_PROMPT, (FSessionData->SessionName)),
-        pkPrompt, Response);
-      if (Result)
-      {
-        FUserName = Response;
-      }
+      LogEvent("Using stored password.");
+      FUI->Information(LoadStr(AUTH_PASSWORD), false);
+      Result = true;
+      Results->Strings[0] = FSessionData->Password;
+      FStoredPasswordTriedForKI = true;
     }
   }
-  else
+  else if (PromptKind == pkPassword)
   {
-    if (Prompt.Pos("Passphrase for key ") == 1)
+    if (!FSessionData->Password.IsEmpty() && !FStoredPasswordTried)
     {
-      AnsiString Key(Prompt);
-      int P = Prompt.Pos("\"");
-      if (P > 0)
-      {
-        Key.Delete(1, P);
-        P = Key.LastDelimiter("\"");
-        if (P > 0)
-        {
-          Key.SetLength(P - 1);
-        }
-      }
+      LogEvent("Using stored password.");
+      FUI->Information(LoadStr(AUTH_PASSWORD), false);
+      Result = true;
+      Results->Strings[0] = FSessionData->Password;
+      FStoredPasswordTried = true;
+    }
+  }
 
-      LogEvent(FORMAT("Passphrase prompt (%s)", (Prompt)));
+  if (!Result)
+  {
+    Result = FUI->PromptUser(FSessionData,
+      PromptKind, Name, Instructions, Prompts, Results);
 
-      Result = FUI->PromptUser(FSessionData, FMTLOAD(PROMPT_KEY_PASSPHRASE, (Key)),
-        pkPassphrase, Response);
-    }
-    else if (Prompt.Pos("'s password: "))
+    if (Result)
     {
-      LogEvent(FORMAT("Session password prompt (%s)", (Prompt)));
-
-      if (!FSessionData->Password.IsEmpty() && !FStoredPasswordTried)
-      {
-        LogEvent("Using stored password.");
-        FUI->Information(LoadStr(AUTH_PASSWORD), false);
-        Result = true;
-        Response = FSessionData->Password;
-        FStoredPasswordTried = true;
-      }
-      else
+      if ((PromptKind == pkUserName) && (Prompts->Count == 1))
       {
-        Result = FUI->PromptUser(FSessionData,
-          FMTLOAD(PROMPT_SESSION_PASSWORD, (FSessionData->SessionName)),
-          pkPassword, Response);
+        FUserName = Results->Strings[0];
       }
     }
-    else
-    {
-      // in other cases we assume TIS/Cryptocard/keyboard-interactive authentification prompt
-      LogEvent(FORMAT("%s prompt from server", (Prompt)));
-
-      if (FSessionData->AuthKIPassword && !FSessionData->Password.IsEmpty() &&
-          !FStoredPasswordTriedForKI)
-      {
-        LogEvent("Using stored password.");
-        FUI->Information(LoadStr(AUTH_PASSWORD), false);
-        Result = true;
-        Response = FSessionData->Password;
-        FStoredPasswordTriedForKI = true;
-      }
-      else
-      {
-        static const AnsiString ResponseSuffix("\r\nResponse: ");
-
-        // Strip Cryptocard/TIS "Response" suffix
-        AnsiString UserPrompt = Prompt;
-        if (UserPrompt.SubString(UserPrompt.Length() - ResponseSuffix.Length() + 1,
-              ResponseSuffix.Length()) == ResponseSuffix)
-        {
-          UserPrompt.SetLength(UserPrompt.Length() - ResponseSuffix.Length());
-        }
-
-        // some servers add leading blank line to make the prompt look prettier
-        // on terminal console
-        UserPrompt = UserPrompt.Trim();
-
-        Result = FUI->PromptUser(FSessionData, UserPrompt, pkServerPrompt, Response);
-      }
-    };
   }
 
   return Result;
@@ -494,8 +603,15 @@ void __fastcall TSecureShell::GotHostKey()
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TSecureShell::DumpCWrite()
+void __fastcall TSecureShell::CWrite(const char * Data, int Length)
 {
+  // some messages to stderr may indicate that something has changed with the
+  // session, so reset the session info
+  ResetSessionInfo();
+
+  // We send only whole line at once, so we have to cache incoming data
+  FCWriteTemp += DeleteChar(AnsiString(Data, Length), '\r');
+
   AnsiString Line;
   // Do we have at least one complete line in std error cache?
   while (FCWriteTemp.Pos("\n") > 0)
@@ -506,42 +622,12 @@ void __fastcall TSecureShell::DumpCWrite()
 
     if (FAuthenticating)
     {
-      // No point trying to translate message coming from server
-      if (!FCWriteTempUntrusted)
-      {
-        TranslateAuthenticationMessage(Line);
-      }
+      TranslateAuthenticationMessage(Line);
       FAuthenticationLog += (FAuthenticationLog.IsEmpty() ? "" : "\n") + Line;
     }
 
-    // Untrusted means generally that it comes from the server,
-    // do not use such a output as "information" for end user
-    if (!FCWriteTempUntrusted)
-    {
-      FUI->Information(Line, false);
-    }
-  }
-}
-//---------------------------------------------------------------------------
-void __fastcall TSecureShell::CWrite(const char * Data, int Length, bool Untrusted)
-{
-  // some messages to stderr may indicate that something has changed with the
-  // session, so reset the session info
-  ResetSessionInfo();
-
-  // if data coming from server were not ended with new line,
-  // dump rest of the line, once trusted output arrive
-  if (!FCWriteTemp.IsEmpty() &&
-      (FCWriteTempUntrusted != Untrusted))
-  {
-    FCWriteTemp += '\n';
-    DumpCWrite();
+    FUI->Information(Line, false);
   }
-
-  // We send only whole line at once, so we have to cache incoming data
-  FCWriteTemp += DeleteChar(AnsiString(Data, Length), '\r');
-  FCWriteTempUntrusted = Untrusted;
-  DumpCWrite();
 }
 //---------------------------------------------------------------------------
 void __fastcall TSecureShell::RegisterReceiveHandler(TNotifyEvent Handler)
@@ -808,10 +894,10 @@ void __fastcall TSecureShell::SendLine(AnsiString Line)
   FLog->Add(llInput, Line);
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSecureShell::TranslatePuttyMessage(
+int __fastcall TSecureShell::TranslatePuttyMessage(
   const TPuttyTranslation * Translation, size_t Count, AnsiString & Message)
 {
-  bool Result = false;
+  int Result = -1;
   for (unsigned int Index = 0; Index < Count; Index++)
   {
     const char * Original = Translation[Index].Original;
@@ -821,7 +907,7 @@ bool __fastcall TSecureShell::TranslatePuttyMessage(
       if (strcmp(Message.c_str(), Original) == 0)
       {
         Message = LoadStr(Translation[Index].Translation);
-        Result = true;
+        Result = int(Index);
         break;
       }
     }
@@ -836,7 +922,7 @@ bool __fastcall TSecureShell::TranslatePuttyMessage(
       {
         Message = FMTLOAD(Translation[Index].Translation,
           (Message.SubString(PrefixLen + 1, Message.Length() - PrefixLen - SuffixLen).TrimRight()));
-        Result = true;
+        Result = int(Index);
         break;
       }
     }
@@ -844,11 +930,11 @@ bool __fastcall TSecureShell::TranslatePuttyMessage(
   return Result;
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSecureShell::TranslateAuthenticationMessage(AnsiString & Message)
+int __fastcall TSecureShell::TranslateAuthenticationMessage(AnsiString & Message)
 {
   static const TPuttyTranslation Translation[] = {
     { "Using username \"%\".", AUTH_TRANSL_USERNAME },
-    { "Using keyboard-interactive authentication.", AUTH_TRANSL_KEYB_INTER },
+    { "Using keyboard-interactive authentication.", AUTH_TRANSL_KEYB_INTER }, // not used anymore
     { "Authenticating with public key \"%\" from agent", AUTH_TRANSL_PUBLIC_KEY_AGENT },
     { "Authenticating with public key \"%\"", AUTH_TRANSL_PUBLIC_KEY },
     { "Authenticated using RSA key \"%\" from agent", AUTH_TRANSL_PUBLIC_KEY_AGENT },
@@ -937,7 +1023,7 @@ void __fastcall TSecureShell::FatalError(Exception * E, AnsiString Msg)
   SSH_FATAL_ERROR_EXT(E, Msg);
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSecureShell::TranslateErrorMessage(AnsiString & Message)
+int __fastcall TSecureShell::TranslateErrorMessage(AnsiString & Message)
 {
   static const TPuttyTranslation Translation[] = {
     { "Server unexpectedly closed network connection", UNEXPECTED_CLOSE_ERROR },
@@ -1465,8 +1551,8 @@ TCipher __fastcall TSecureShell::FuncToSsh1Cipher(const void * Cipher)
 TCipher __fastcall TSecureShell::FuncToSsh2Cipher(const void * Cipher)
 {
   const ssh2_ciphers *CipherFuncs[] =
-    {&ssh2_3des, &ssh2_des, &ssh2_aes, &ssh2_blowfish};
-  const TCipher TCiphers[] = {cip3DES, cipDES, cipAES, cipBlowfish};
+    {&ssh2_3des, &ssh2_des, &ssh2_aes, &ssh2_blowfish, &ssh2_arcfour};
+  const TCipher TCiphers[] = {cip3DES, cipDES, cipAES, cipBlowfish, cipArcfour};
   assert(LENOF(CipherFuncs) == LENOF(TCiphers));
   TCipher Result = cipWarn;
 
@@ -1485,25 +1571,69 @@ TCipher __fastcall TSecureShell::FuncToSsh2Cipher(const void * Cipher)
   return Result;
 }
 //---------------------------------------------------------------------------
+struct TClipboardHandler
+{
+  AnsiString Text;
+
+  void __fastcall Copy(TObject * /*Sender*/)
+  {
+    CopyToClipboard(Text);
+  }
+};
+//---------------------------------------------------------------------------
 void __fastcall TSecureShell::VerifyHostKey(AnsiString Host, int Port,
   const AnsiString KeyType, AnsiString KeyStr, const AnsiString Fingerprint)
 {
   GotHostKey();
 
+  char Delimiter = ';';
+  assert(KeyStr.Pos(Delimiter) == 0);
+
   if (FSessionData->Tunnel)
   {
     Host = FSessionData->OrigHostName;
     Port = FSessionData->OrigPortNumber;
   }
 
-  int Result;
-
   FSessionInfo.HostKeyFingerprint = Fingerprint;
 
-  // Verify the key against the registry.
-  Result = verify_host_key(Host.c_str(), Port, KeyType.c_str(), KeyStr.c_str());
+  bool Result = false;
+
+  AnsiString Buf = FSessionData->HostKey;
+  while (!Result && !Buf.IsEmpty())
+  {
+    AnsiString ExpectedKey = CutToChar(Buf, Delimiter, false);
+    if (ExpectedKey == Fingerprint)
+    {
+      Result = true;
+    }
+  }
 
-  if (Result != 0)
+  AnsiString StoredKeys;
+  if (!Result)
+  {
+    StoredKeys.SetLength(10240);
+    if (retrieve_host_key(Host.c_str(), Port, KeyType.c_str(),
+          StoredKeys.c_str(), StoredKeys.Length()) == 0)
+    {
+      PackStr(StoredKeys);
+      AnsiString Buf = StoredKeys;
+      while (!Result && !Buf.IsEmpty())
+      {
+        AnsiString StoredKey = CutToChar(Buf, Delimiter, false);
+        if (StoredKey == KeyStr)
+        {
+          Result = true;
+        }
+      }
+    }
+    else
+    {
+      StoredKeys = "";
+    }
+  }
+
+  if (!Result)
   {
     if (Configuration->DisableAcceptingHostKeys)
     {
@@ -1511,13 +1641,46 @@ void __fastcall TSecureShell::VerifyHostKey(AnsiString Host, int Port,
     }
     else
     {
+      TClipboardHandler ClipboardHandler;
+      ClipboardHandler.Text = Fingerprint;
+
+      bool Unknown = StoredKeys.IsEmpty();
+
+      int Answers;
+      int AliasesCount;
+      TQueryButtonAlias Aliases[3];
+      Aliases[0].Button = qaRetry;
+      Aliases[0].Alias = LoadStr(COPY_KEY_BUTTON);
+      Aliases[0].OnClick = &ClipboardHandler.Copy;
+      Answers = qaYes | qaCancel | qaRetry;
+      AliasesCount = 1;
+      if (!Unknown)
+      {
+        Aliases[1].Button = qaYes;
+        Aliases[1].Alias = LoadStr(UPDATE_KEY_BUTTON);
+        Aliases[2].Button = qaOK;
+        Aliases[2].Alias = LoadStr(ADD_KEY_BUTTON);
+        AliasesCount += 2;
+        Answers |= qaSkip | qaOK;
+      }
+      else
+      {
+        Answers |= qaNo;
+      }
+
       TQueryParams Params;
-      Params.HelpKeyword = (Result == 1 ? HELP_UNKNOWN_KEY : HELP_DIFFERENT_KEY);
+      Params.HelpKeyword = (Unknown ? HELP_UNKNOWN_KEY : HELP_DIFFERENT_KEY);
+      Params.Aliases = Aliases;
+      Params.AliasesCount = AliasesCount;
       int R = FUI->QueryUser(
-        FMTLOAD((Result == 1 ? UNKNOWN_KEY2 : DIFFERENT_KEY2), (KeyType, Fingerprint)),
-        NULL, qaYes | qaNo | qaCancel, &Params, qtWarning);
+        FMTLOAD((Unknown ? UNKNOWN_KEY2 : DIFFERENT_KEY3), (KeyType, Fingerprint)),
+        NULL, Answers, &Params, qtWarning);
 
       switch (R) {
+        case qaOK:
+          assert(!Unknown);
+          KeyStr = (StoredKeys + Delimiter + KeyStr);
+          // fall thru
         case qaYes:
           store_host_key(Host.c_str(), Port, KeyType.c_str(), KeyStr.c_str());
           break;

+ 10 - 9
core/SecureShell.h

@@ -55,7 +55,6 @@ private:
   AnsiString FStdErrorTemp;
   AnsiString FStdError;
   AnsiString FCWriteTemp;
-  bool FCWriteTempUntrusted;
   AnsiString FAuthenticationLog;
   AnsiString FLastTunnelError;
   AnsiString FUserName;
@@ -81,22 +80,22 @@ private:
   bool __fastcall EventSelectLoop(unsigned int MSec, bool ReadEventRequired,
     WSANETWORKEVENTS * Events);
   void __fastcall UpdateSessionInfo();
-  void __fastcall DumpCWrite();
 
 protected:
   TCaptureOutputEvent FOnCaptureOutput;
 
   void __fastcall GotHostKey();
-  bool __fastcall TranslatePuttyMessage(const TPuttyTranslation * Translation,
+  int __fastcall TranslatePuttyMessage(const TPuttyTranslation * Translation,
     size_t Count, AnsiString & Message);
-  bool __fastcall TranslateAuthenticationMessage(AnsiString & Message);
-  bool __fastcall TranslateErrorMessage(AnsiString & Message);
+  int __fastcall TranslateAuthenticationMessage(AnsiString & Message);
+  int __fastcall TranslateErrorMessage(AnsiString & Message);
   void __fastcall AddStdError(AnsiString Str);
   void __fastcall AddStdErrorLine(const AnsiString & Str);
   void __fastcall FatalError(Exception * E, AnsiString Msg);
   void __fastcall inline LogEvent(const AnsiString & Str);
   void __fastcall FatalError(AnsiString Error);
-  void __fastcall StoreToConfig(TSessionData * Data, Config * cfg);
+  static void __fastcall ClearConfig(Config * cfg);
+  static void __fastcall StoreToConfig(TSessionData * Data, Config * cfg);
 
 public:
   __fastcall TSecureShell(TSessionUI * UI, TSessionData * SessionData,
@@ -129,10 +128,12 @@ public:
   void __fastcall UpdateSocket(SOCKET value, bool Startup);
   void __fastcall UpdatePortFwdSocket(SOCKET value, bool Startup);
   void __fastcall PuttyFatalError(AnsiString Error);
-  bool __fastcall PromptUser(const AnsiString Prompt, AnsiString & Response,
-    bool IsPassword);
+  bool __fastcall PromptUser(bool ToServer,
+    AnsiString AName, bool NameRequired,
+    AnsiString Instructions, bool InstructionsRequired,
+    TStrings * Prompts, TStrings * Results);
   void __fastcall FromBackend(bool IsStdErr, const char * Data, int Length);
-  void __fastcall CWrite(const char * Data, int Length, bool Untrusted);
+  void __fastcall CWrite(const char * Data, int Length);
   const AnsiString & __fastcall GetStdError();
   void __fastcall VerifyHostKey(AnsiString Host, int Port,
     const AnsiString KeyType, AnsiString KeyStr, const AnsiString Fingerprint);

+ 274 - 28
core/SessionData.cpp

@@ -16,20 +16,21 @@
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
+enum TProxyType { pxNone, pxHTTP, pxSocks, pxTelnet }; // 0.53b and older
 const char * DefaultSessionName = "Default Settings";
-const char CipherNames[CIPHER_COUNT][10] = {"WARN", "3des", "blowfish", "aes", "des"};
-const char KexNames[KEX_COUNT][20] = {"WARN", "dh-group1-sha1", "dh-group14-sha1", "dh-gex-sha1" };
+const char CipherNames[CIPHER_COUNT][10] = {"WARN", "3des", "blowfish", "aes", "des", "arcfour"};
+const char KexNames[KEX_COUNT][20] = {"WARN", "dh-group1-sha1", "dh-group14-sha1", "dh-gex-sha1", "gssapi-group1", "gssapi-group14", "gssapi-gex" };
 const char SshProtList[][10] = {"1 only", "1", "2", "2 only"};
 const char ProxyMethodList[][10] = {"none", "SOCKS4", "SOCKS5", "HTTP", "Telnet", "Cmd" };
 const TCipher DefaultCipherList[CIPHER_COUNT] =
-  { cipAES, cipBlowfish, cip3DES, cipWarn, cipDES };
+  { cipAES, cipBlowfish, cip3DES, cipWarn, cipArcfour, cipDES };
 const TKex DefaultKexList[KEX_COUNT] =
-  { kexDHGEx, kexDHGroup14, kexDHGroup1, kexWarn };
+  { kexGSSGEx, kexGSSGroup14, kexGSSGroup1, kexDHGEx, kexDHGroup14, kexDHGroup1, kexWarn };
 const char FSProtocolNames[FSPROTOCOL_COUNT][11] = { "SCP", "SFTP (SCP)", "SFTP", "SSH", "SFTP", "FTP" };
 const int SshPortNumber = 22;
 const int FtpPortNumber = 21;
 //--- TSessionData ----------------------------------------------------
-AnsiString TSessionData::FInvalidChars("/\\[]");
+AnsiString TSessionData::FInvalidChars("\\[]");
 //---------------------------------------------------------------------
 __fastcall TSessionData::TSessionData(AnsiString aName):
   TNamedObject(aName)
@@ -45,8 +46,10 @@ void __fastcall TSessionData::Default()
   UserName = "";
   Password = "";
   PingInterval = 30;
+  // when changing default, update load/save logic
   PingType = ptOff;
   Timeout = 15;
+  TryAgent = true;
   AgentFwd = false;
   AuthTIS = false;
   AuthKI = true;
@@ -54,10 +57,15 @@ void __fastcall TSessionData::Default()
   AuthGSSAPI = false;
   GSSAPIFwdTGT = false;
   GSSAPIServerRealm = "";
+  TryGSSKEX = true;
+  UserNameFromEnvironment = false;
+  GSSAPIServerChoosesUserName = false;
+  GSSAPITrustDNS = false;
   ChangeUsername = false;
   Compression = false;
   SshProt = ssh2;
   Ssh2DES = false;
+  SshNoUserAuth = false;
   for (int Index = 0; Index < CIPHER_COUNT; Index++)
   {
     Cipher[Index] = DefaultCipherList[Index];
@@ -69,6 +77,7 @@ void __fastcall TSessionData::Default()
   PublicKeyFile = "";
   FProtocol = ptSSH;
   TcpNoDelay = true;
+  HostKey = "";
 
   ProxyMethod = pmNone;
   ProxyHost = "proxy";
@@ -76,6 +85,7 @@ void __fastcall TSessionData::Default()
   ProxyUsername = "";
   ProxyPassword = "";
   ProxyTelnetCommand = "connect %host %port\\n";
+  ProxyLocalCommand = "";
   ProxyDNS = asAuto;
   ProxyLocalhost = false;
 
@@ -104,6 +114,7 @@ void __fastcall TSessionData::Default()
   OverwrittenToRecycleBin = false;
   RecycleBinPath = "/tmp";
   Color = 0;
+  PostLoginCommands = "";
 
   // SCP
   ReturnVar = "";
@@ -113,13 +124,15 @@ void __fastcall TSessionData::Default()
   ReturnVar = "";
   ClearAliases = true;
   UnsetNationalVars = true;
-  AliasGroupList = false;
+  ListingCommand = "ls -la";
   IgnoreLsWarnings = true;
   Scp1Compatibility = false;
   TimeDifference = 0;
   SCPLsFullTime = asAuto;
+  Utf = asAuto;
 
   // SFTP
+  SftpServer = "";
   SFTPDownloadQueue = 4;
   SFTPUploadQueue = 4;
   SFTPListingQueue = 2;
@@ -174,18 +187,21 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
     DUPL(PingInterval);
     DUPL(PingType);
     DUPL(Timeout);
+    DUPL(TryAgent);
     DUPL(AgentFwd);
     DUPL(AuthTIS);
     DUPL(ChangeUsername);
     DUPL(Compression);
     DUPL(SshProt);
     DUPL(Ssh2DES);
+    DUPL(SshNoUserAuth);
     DUPL(CipherList);
     DUPL(KexList);
     DUPL(PublicKeyFile);
     DUPL(AddressFamily);
     DUPL(RekeyData);
     DUPL(RekeyTime);
+    DUPL(HostKey);
 
     DUPL(FSProtocol);
     DUPL(LocalDirectory);
@@ -207,7 +223,7 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
     DUPL(ClearAliases);
     DUPL(Scp1Compatibility);
     DUPL(UnsetNationalVars);
-    DUPL(AliasGroupList);
+    DUPL(ListingCommand);
     DUPL(IgnoreLsWarnings);
     DUPL(SCPLsFullTime);
 
@@ -219,9 +235,15 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
     DUPL(AuthGSSAPI);
     DUPL(GSSAPIFwdTGT);
     DUPL(GSSAPIServerRealm);
+    DUPL(TryGSSKEX);
+    DUPL(UserNameFromEnvironment);
+    DUPL(GSSAPIServerChoosesUserName);
+    DUPL(GSSAPITrustDNS);
     DUPL(DeleteToRecycleBin);
     DUPL(OverwrittenToRecycleBin);
     DUPL(RecycleBinPath);
+    DUPL(Utf);
+    DUPL(PostLoginCommands);
 
     DUPL(ProxyMethod);
     DUPL(ProxyHost);
@@ -229,6 +251,7 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
     DUPL(ProxyUsername);
     DUPL(ProxyPassword);
     DUPL(ProxyTelnetCommand);
+    DUPL(ProxyLocalCommand);
     DUPL(ProxyDNS);
     DUPL(ProxyLocalhost);
 
@@ -238,6 +261,7 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
     }
 
     // SFTP
+    DUPL(SftpServer);
     DUPL(SFTPDownloadQueue);
     DUPL(SFTPUploadQueue);
     DUPL(SFTPListingQueue);
@@ -308,24 +332,46 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
     PingInterval =
       Storage->ReadInteger("PingInterval", PingInterval/60)*60 +
       PingIntervalSecs;
-    PingType = static_cast<TPingType>
-      (Storage->ReadInteger("PingType", PingInterval > 0 ? ptNullPacket : ptOff));
     if (PingInterval == 0)
     {
       PingInterval = 30;
     }
+    // PingType has not existed before 3.5, where PingInterval > 0 meant today's ptNullPacket
+    // Since 3.5, until 4.1 PingType was stored unconditionally.
+    // Since 4.1 PingType is stored when it is not ptOff (default) or
+    // when PingInterval is stored.
+    if (!Storage->ValueExists("PingType"))
+    {
+      if (Storage->ReadInteger("PingInterval", 0) > 0)
+      {
+        PingType = ptNullPacket;
+      }
+    }
+    else
+    {
+      PingType = static_cast<TPingType>(Storage->ReadInteger("PingType", ptOff));
+    }
     Timeout = Storage->ReadInteger("Timeout", Timeout);
+    TryAgent = Storage->ReadBool("TryAgent", TryAgent);
     AgentFwd = Storage->ReadBool("AgentFwd", AgentFwd);
     AuthTIS = Storage->ReadBool("AuthTIS", AuthTIS);
     AuthKI = Storage->ReadBool("AuthKI", AuthKI);
     AuthKIPassword = Storage->ReadBool("AuthKIPassword", AuthKIPassword);
-    AuthGSSAPI = Storage->ReadBool("AuthGSSAPI", AuthGSSAPI);
-    GSSAPIFwdTGT = Storage->ReadBool("GSSAPIFwdTGT", GSSAPIFwdTGT);
-    GSSAPIServerRealm = Storage->ReadString("GSSAPIServerRealm", GSSAPIServerRealm);
+    // continue to use setting keys of previous kerberos implementation (vaclav tomec),
+    // but fallback to keys of new implementation (vintela quest putty),
+    // to allow imports from both putty versions
+    AuthGSSAPI = Storage->ReadBool("AuthGSSAPI", Storage->ReadBool("AuthSSPI", AuthGSSAPI));
+    GSSAPIFwdTGT = Storage->ReadBool("GSSAPIFwdTGT", Storage->ReadBool("SSPIFwdTGT", GSSAPIFwdTGT));
+    GSSAPIServerRealm = Storage->ReadString("GSSAPIServerRealm", Storage->ReadString("KerbPrincipal", GSSAPIServerRealm));
+    TryGSSKEX = Storage->ReadBool("TryGSSKEX", TryGSSKEX);
+    UserNameFromEnvironment = Storage->ReadBool("UserNameFromEnvironment", UserNameFromEnvironment);
+    GSSAPIServerChoosesUserName = Storage->ReadBool("GSSAPIServerChoosesUserName", GSSAPIServerChoosesUserName);
+    GSSAPITrustDNS = Storage->ReadBool("GSSAPITrustDNS", GSSAPITrustDNS);
     ChangeUsername = Storage->ReadBool("ChangeUsername", ChangeUsername);
     Compression = Storage->ReadBool("Compression", Compression);
     SshProt = (TSshProt)Storage->ReadInteger("SshProt", SshProt);
     Ssh2DES = Storage->ReadBool("Ssh2DES", Ssh2DES);
+    SshNoUserAuth = Storage->ReadBool("SshNoUserAuth", SshNoUserAuth);
     CipherList = Storage->ReadString("Cipher", CipherList);
     KexList = Storage->ReadString("KEX", KexList);
     PublicKeyFile = Storage->ReadString("PublicKeyFile", PublicKeyFile);
@@ -349,7 +395,8 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
     Shell = Storage->ReadString("Shell", Shell);
     ClearAliases = Storage->ReadBool("ClearAliases", ClearAliases);
     UnsetNationalVars = Storage->ReadBool("UnsetNationalVars", UnsetNationalVars);
-    AliasGroupList = Storage->ReadBool("AliasGroupList", AliasGroupList);
+    ListingCommand = Storage->ReadString("ListingCommand",
+      Storage->ReadBool("AliasGroupList", false) ? AnsiString("ls -gla") : ListingCommand);
     IgnoreLsWarnings = Storage->ReadBool("IgnoreLsWarnings", IgnoreLsWarnings);
     SCPLsFullTime = TAutoSwitch(Storage->ReadInteger("SCPLsFullTime", SCPLsFullTime));
     Scp1Compatibility = Storage->ReadBool("Scp1Compatibility", Scp1Compatibility);
@@ -357,12 +404,13 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
     DeleteToRecycleBin = Storage->ReadBool("DeleteToRecycleBin", DeleteToRecycleBin);
     OverwrittenToRecycleBin = Storage->ReadBool("OverwrittenToRecycleBin", OverwrittenToRecycleBin);
     RecycleBinPath = Storage->ReadString("RecycleBinPath", RecycleBinPath);
+    PostLoginCommands = Storage->ReadString("PostLoginCommands", PostLoginCommands);
 
     ReturnVar = Storage->ReadString("ReturnVar", ReturnVar);
     LookupUserGroups = Storage->ReadBool("LookupUserGroups", LookupUserGroups);
     EOLType = (TEOLType)Storage->ReadInteger("EOLType", EOLType);
+    Utf = TAutoSwitch(Storage->ReadInteger("Utf", Storage->ReadInteger("SFTPUtfBug", Utf)));
 
-    // new in 53b
     TcpNoDelay = Storage->ReadBool("TcpNoDelay", TcpNoDelay);
 
     ProxyMethod = (TProxyMethod)Storage->ReadInteger("ProxyMethod", -1);
@@ -400,7 +448,14 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
       // load encrypted password
       FProxyPassword = Storage->ReadString("ProxyPasswordEnc", FProxyPassword);
     }
-    ProxyTelnetCommand = Storage->ReadStringRaw("ProxyTelnetCommand", ProxyTelnetCommand);
+    if (ProxyMethod == pmCmd)
+    {
+      ProxyLocalCommand = Storage->ReadStringRaw("ProxyTelnetCommand", ProxyLocalCommand);
+    }
+    else
+    {
+      ProxyTelnetCommand = Storage->ReadStringRaw("ProxyTelnetCommand", ProxyTelnetCommand);
+    }
     ProxyDNS = TAutoSwitch((Storage->ReadInteger("ProxyDNS", (ProxyDNS + 2) % 3) + 1) % 3);
     ProxyLocalhost = Storage->ReadBool("ProxyLocalhost", ProxyLocalhost);
 
@@ -423,10 +478,10 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
         Bug[sbHMAC2] = asOn;
     }
 
+    SftpServer = Storage->ReadString("SftpServer", SftpServer);
     #define READ_SFTP_BUG(BUG) \
       SFTPBug[sb##BUG] = TAutoSwitch(Storage->ReadInteger("SFTP" #BUG "Bug", SFTPBug[sb##BUG]));
     READ_SFTP_BUG(Symlink);
-    READ_SFTP_BUG(Utf);
     READ_SFTP_BUG(SignedTS);
     #undef READ_SFTP_BUG
 
@@ -435,7 +490,6 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
 
     Color = Storage->ReadInteger("Color", Color);
 
-    // read only (used only on Import from Putty dialog)
     ProtocolStr = Storage->ReadString("Protocol", ProtocolStr);
 
     Tunnel = Storage->ReadBool("Tunnel", Tunnel);
@@ -522,20 +576,44 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
     WRITE_DATA_EX(Integer, "PingInterval", PingInterval / 60, );
     WRITE_DATA_EX(Integer, "PingIntervalSecs", PingInterval % 60, );
     Storage->DeleteValue("PingIntervalSec"); // obsolete
-    // store PingType always as it does not have fixed default
-    Storage->WriteInteger("PingType", PingType);
+    // when PingInterval is stored always store PingType not to attempt to
+    // deduce PingType from PingInterval (backward compatibility with pre 3.5)
+    if (((Default != NULL) && (PingType != Default->PingType)) ||
+        Storage->ValueExists("PingInterval"))
+    {
+      Storage->WriteInteger("PingType", PingType);
+    }
+    else
+    {
+      Storage->DeleteValue("PingType");
+    }
     WRITE_DATA(Integer, Timeout);
+    WRITE_DATA(Bool, TryAgent);
     WRITE_DATA(Bool, AgentFwd);
     WRITE_DATA(Bool, AuthTIS);
     WRITE_DATA(Bool, AuthKI);
     WRITE_DATA(Bool, AuthKIPassword);
+
     WRITE_DATA(Bool, AuthGSSAPI);
     WRITE_DATA(Bool, GSSAPIFwdTGT);
     WRITE_DATA(String, GSSAPIServerRealm);
+    WRITE_DATA(Bool, TryGSSKEX);
+    WRITE_DATA(Bool, UserNameFromEnvironment);
+    WRITE_DATA(Bool, GSSAPIServerChoosesUserName);
+    WRITE_DATA(Bool, GSSAPITrustDNS);
+    if (PuttyExport)
+    {
+      // duplicate kerberos setting with keys of the vintela quest putty
+      WRITE_DATA_EX(Bool, "AuthSSPI", AuthGSSAPI, );
+      WRITE_DATA_EX(Bool, "SSPIFwdTGT", GSSAPIFwdTGT, );
+      WRITE_DATA_EX(String, "KerbPrincipal", GSSAPIServerRealm, );
+    }
+
     WRITE_DATA(Bool, ChangeUsername);
     WRITE_DATA(Bool, Compression);
     WRITE_DATA(Integer, SshProt);
     WRITE_DATA(Bool, Ssh2DES);
+    WRITE_DATA(Bool, SshNoUserAuth);
     WRITE_DATA_EX(String, "Cipher", CipherList, );
     WRITE_DATA_EX(String, "KEX", KexList, );
     WRITE_DATA(Integer, AddressFamily);
@@ -571,7 +649,7 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
       WRITE_DATA(String, Shell);
       WRITE_DATA(Bool, ClearAliases);
       WRITE_DATA(Bool, UnsetNationalVars);
-      WRITE_DATA(Bool, AliasGroupList);
+      WRITE_DATA(String, ListingCommand);
       WRITE_DATA(Bool, IgnoreLsWarnings);
       WRITE_DATA(Integer, SCPLsFullTime);
       WRITE_DATA(Bool, Scp1Compatibility);
@@ -579,10 +657,13 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
       WRITE_DATA(Bool, DeleteToRecycleBin);
       WRITE_DATA(Bool, OverwrittenToRecycleBin);
       WRITE_DATA(String, RecycleBinPath);
+      WRITE_DATA(String, PostLoginCommands);
 
       WRITE_DATA(String, ReturnVar);
       WRITE_DATA(Bool, LookupUserGroups);
       WRITE_DATA(Integer, EOLType);
+      Storage->DeleteValue("SFTPUtfBug");
+      WRITE_DATA(Integer, Utf);
     }
 
     WRITE_DATA(Integer, ProxyMethod);
@@ -640,7 +721,14 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
       }
       Storage->DeleteValue("ProxyPassword");
     }
-    WRITE_DATA(StringRaw, ProxyTelnetCommand);
+    if (ProxyMethod == pmCmd)
+    {
+      WRITE_DATA_EX(StringRaw, "ProxyTelnetCommand", ProxyLocalCommand, );
+    }
+    else
+    {
+      WRITE_DATA(StringRaw, ProxyTelnetCommand);
+    }
     #define WRITE_DATA_CONV_FUNC(X) (((X) + 2) % 3)
     WRITE_DATA_CONV(Integer, "ProxyDNS", ProxyDNS);
     #undef WRITE_DATA_CONV_FUNC
@@ -660,6 +748,7 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
     #undef WRITE_DATA_CONV_FUNC
 
     Storage->DeleteValue("BuggyMAC");
+    Storage->DeleteValue("AliasGroupList");
 
     if (PuttyExport)
     {
@@ -668,9 +757,10 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
 
     if (!PuttyExport)
     {
+      WRITE_DATA(String, SftpServer);
+
       #define WRITE_SFTP_BUG(BUG) WRITE_DATA_EX(Integer, "SFTP" #BUG "Bug", SFTPBug[sb##BUG], );
       WRITE_SFTP_BUG(Symlink);
-      WRITE_SFTP_BUG(Utf);
       WRITE_SFTP_BUG(SignedTS);
       #undef WRITE_SFTP_BUG
 
@@ -865,6 +955,28 @@ bool __fastcall TSessionData::ParseUrl(AnsiString Url, int Params,
   return Result;
 }
 //---------------------------------------------------------------------
+bool __fastcall TSessionData::ParseOptions(TOptions * Options)
+{
+  AnsiString Value;
+  if (Options->FindSwitch("privatekey", Value))
+  {
+    PublicKeyFile = Value;
+  }
+  if (Options->FindSwitch("timeout", Value))
+  {
+    Timeout = StrToInt(Value);
+  }
+  if (Options->FindSwitch("hostkey", Value))
+  {
+    HostKey = Value;
+  }
+  if (Options->FindSwitch("passive", Value))
+  {
+    FtpPasvMode = (StrToIntDef(Value, 1) != 0);
+  }
+  return true;
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::ConfigureTunnel(int APortNumber)
 {
   FOrigHostName = HostName;
@@ -884,11 +996,19 @@ void __fastcall TSessionData::RollbackTunnel()
   ProxyMethod = FOrigProxyMethod;
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::ValidatePath(const AnsiString Path)
+{
+  if (Path.LastDelimiter(FInvalidChars) > 0)
+  {
+    throw Exception(FMTLOAD(ITEM_NAME_INVALID, (Path, FInvalidChars)));
+  }
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::ValidateName(const AnsiString Name)
 {
-  if (Name.LastDelimiter(FInvalidChars) > 0)
+  if (Name.LastDelimiter(FInvalidChars + "/") > 0)
   {
-    throw Exception(FMTLOAD(ITEM_NAME_INVALID, (Name, FInvalidChars)));
+    throw Exception(FMTLOAD(ITEM_NAME_INVALID, (Name, FInvalidChars + "/")));
   }
 }
 //---------------------------------------------------------------------
@@ -943,14 +1063,19 @@ void __fastcall TSessionData::SetShell(AnsiString value)
   SET_SESSION_PROPERTY(Shell);
 }
 //---------------------------------------------------------------------------
+void __fastcall TSessionData::SetSftpServer(AnsiString value)
+{
+  SET_SESSION_PROPERTY(SftpServer);
+}
+//---------------------------------------------------------------------------
 void __fastcall TSessionData::SetClearAliases(bool value)
 {
   SET_SESSION_PROPERTY(ClearAliases);
 }
 //---------------------------------------------------------------------------
-void __fastcall TSessionData::SetAliasGroupList(bool value)
+void __fastcall TSessionData::SetListingCommand(AnsiString value)
 {
-  SET_SESSION_PROPERTY(AliasGroupList);
+  SET_SESSION_PROPERTY(ListingCommand);
 }
 //---------------------------------------------------------------------------
 void __fastcall TSessionData::SetIgnoreLsWarnings(bool value)
@@ -992,6 +1117,11 @@ void __fastcall TSessionData::SetPingInterval(int value)
   SET_SESSION_PROPERTY(PingInterval);
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::SetTryAgent(bool value)
+{
+  SET_SESSION_PROPERTY(TryAgent);
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::SetAgentFwd(bool value)
 {
   SET_SESSION_PROPERTY(AgentFwd);
@@ -1027,6 +1157,26 @@ void __fastcall TSessionData::SetGSSAPIServerRealm(AnsiString value)
   SET_SESSION_PROPERTY(GSSAPIServerRealm);
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::SetTryGSSKEX(bool value)
+{
+  SET_SESSION_PROPERTY(TryGSSKEX);
+}
+//---------------------------------------------------------------------
+void __fastcall TSessionData::SetUserNameFromEnvironment(bool value)
+{
+  SET_SESSION_PROPERTY(UserNameFromEnvironment);
+}
+//---------------------------------------------------------------------
+void __fastcall TSessionData::SetGSSAPIServerChoosesUserName(bool value)
+{
+  SET_SESSION_PROPERTY(GSSAPIServerChoosesUserName);
+}
+//---------------------------------------------------------------------
+void __fastcall TSessionData::SetGSSAPITrustDNS(bool value)
+{
+  SET_SESSION_PROPERTY(GSSAPITrustDNS);
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::SetChangeUsername(bool value)
 {
   SET_SESSION_PROPERTY(ChangeUsername);
@@ -1047,6 +1197,11 @@ void __fastcall TSessionData::SetSsh2DES(bool value)
   SET_SESSION_PROPERTY(Ssh2DES);
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::SetSshNoUserAuth(bool value)
+{
+  SET_SESSION_PROPERTY(SshNoUserAuth);
+}
+//---------------------------------------------------------------------
 AnsiString __fastcall TSessionData::GetSshProtStr()
 {
   return SshProtList[FSshProt];
@@ -1193,6 +1348,11 @@ void __fastcall TSessionData::SetTimeout(int value)
   SET_SESSION_PROPERTY(Timeout);
 }
 //---------------------------------------------------------------------------
+void __fastcall TSessionData::SetProtocol(TProtocol value)
+{
+  SET_SESSION_PROPERTY(Protocol);
+}
+//---------------------------------------------------------------------------
 void __fastcall TSessionData::SetFSProtocol(TFSProtocol value)
 {
   SET_SESSION_PROPERTY(FSProtocol);
@@ -1295,6 +1455,56 @@ AnsiString __fastcall TSessionData::GetSessionName()
   }
 }
 //---------------------------------------------------------------------
+AnsiString __fastcall TSessionData::GetSessionUrl()
+{
+  AnsiString Url;
+  if (!Name.IsEmpty() && !TNamedObjectList::IsHidden(this) &&
+      (Name != DefaultSessionName))
+  {
+    Url = Name;
+  }
+  else
+  {
+    switch (FSProtocol)
+    {
+      case fsSCPonly:
+        Url = "scp://";
+        break;
+
+      default:
+        assert(false);
+        // fallback
+      case fsSFTP:
+      case fsSFTPonly:
+      case fsExternalSFTP:
+        Url = "sftp://";
+        break;
+
+      case fsExternalSSH:
+        Url = "ssh://";
+        break;
+
+      case fsFTP:
+        Url = "ftp://";
+        break;
+    }
+
+    if (!HostName.IsEmpty() && !UserName.IsEmpty())
+    {
+      Url += FORMAT("%s@%s", (UserName, HostName));
+    }
+    else if (!HostName.IsEmpty())
+    {
+      Url += HostName;
+    }
+    else
+    {
+      Url = "";
+    }
+  }
+  return Url;
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::SetTimeDifference(TDateTime value)
 {
   SET_SESSION_PROPERTY(TimeDifference);
@@ -1354,6 +1564,11 @@ void __fastcall TSessionData::SetRecycleBinPath(AnsiString value)
 {
   SET_SESSION_PROPERTY(RecycleBinPath);
 }
+//---------------------------------------------------------------------------
+void __fastcall TSessionData::SetPostLoginCommands(AnsiString value)
+{
+  SET_SESSION_PROPERTY(PostLoginCommands);
+}
 //---------------------------------------------------------------------
 void __fastcall TSessionData::SetLockInHome(bool value)
 {
@@ -1411,6 +1626,11 @@ void __fastcall TSessionData::SetProxyTelnetCommand(AnsiString value)
   SET_SESSION_PROPERTY(ProxyTelnetCommand);
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::SetProxyLocalCommand(AnsiString value)
+{
+  SET_SESSION_PROPERTY(ProxyLocalCommand);
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::SetProxyDNS(TAutoSwitch value)
 {
   SET_SESSION_PROPERTY(ProxyDNS);
@@ -1588,11 +1808,27 @@ void __fastcall TSessionData::SetFtpPingInterval(int value)
   SET_SESSION_PROPERTY(FtpPingInterval);
 }
 //---------------------------------------------------------------------------
+TDateTime __fastcall TSessionData::GetFtpPingIntervalDT()
+{
+  return TDateTime((unsigned short)(FtpPingInterval/60/60),
+    (unsigned short)(FtpPingInterval/60%60), (unsigned short)(FtpPingInterval%60), 0);
+}
+//---------------------------------------------------------------------------
 void __fastcall TSessionData::SetFtpPingType(TPingType value)
 {
   SET_SESSION_PROPERTY(FtpPingType);
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::SetUtf(TAutoSwitch value)
+{
+  SET_SESSION_PROPERTY(Utf);
+}
+//---------------------------------------------------------------------
+void __fastcall TSessionData::SetHostKey(AnsiString value)
+{
+  SET_SESSION_PROPERTY(HostKey);
+}
+//---------------------------------------------------------------------
 AnsiString __fastcall TSessionData::GetInfoTip()
 {
   if (UsesSsh)
@@ -1637,7 +1873,7 @@ void __fastcall TStoredSessionList::Load(THierarchicalStorage * Storage,
       bool ValidName = true;
       try
       {
-        TSessionData::ValidateName(SessionName);
+        TSessionData::ValidatePath(SessionName);
       }
       catch(...)
       {
@@ -1925,7 +2161,7 @@ void __fastcall TStoredSessionList::ImportHostKeys(const AnsiString TargetKey,
 }
 //---------------------------------------------------------------------------
 TSessionData * __fastcall TStoredSessionList::ParseUrl(AnsiString Url,
-  bool & DefaultsOnly, int Params, AnsiString * FileName,
+  TOptions * Options, bool & DefaultsOnly, int Params, AnsiString * FileName,
   bool * AProtocolDefined)
 {
   bool ProtocolDefined = false;
@@ -2024,6 +2260,16 @@ TSessionData * __fastcall TStoredSessionList::ParseUrl(AnsiString Url,
     {
       Data->FSProtocol = Protocol;
     }
+
+    if (Options != NULL)
+    {
+      // we deliberatelly do set defaultonly to false, in presence of any option,
+      // as the option should not make session "connectable"
+      if (!Data->ParseOptions(Options))
+      {
+        Abort();
+      }
+    }
   }
   catch(...)
   {

+ 52 - 12
core/SessionData.h

@@ -3,6 +3,7 @@
 #define SessionDataH
 
 #include "Common.h"
+#include "Option.h"
 #include "FileBuffer.h"
 #include "NamedObjs.h"
 #include "HierarchicalStorage.h"
@@ -10,20 +11,19 @@
 #define SET_SESSION_PROPERTY(Property) \
   if (F##Property != value) { F##Property = value; FModified = true; }
 //---------------------------------------------------------------------------
-enum TCipher { cipWarn, cip3DES, cipBlowfish, cipAES, cipDES };
-#define CIPHER_COUNT (cipDES+1)
+enum TCipher { cipWarn, cip3DES, cipBlowfish, cipAES, cipDES, cipArcfour };
+#define CIPHER_COUNT (cipArcfour+1)
 enum TProtocol { ptRaw, ptTelnet, ptRLogin, ptSSH };
 enum TFSProtocol { fsSCPonly, fsSFTP, fsSFTPonly, fsExternalSSH, fsExternalSFTP, fsFTP };
 #define FSPROTOCOL_COUNT (fsFTP+1)
-enum TProxyType { pxNone, pxHTTP, pxSocks, pxTelnet }; // 0.53b and older
-enum TProxyMethod { pmNone, pmSocks4, pmSocks5, pmHTTP, pmTelnet, pmCmd }; // after 0.53b
+enum TProxyMethod { pmNone, pmSocks4, pmSocks5, pmHTTP, pmTelnet, pmCmd };
 enum TSshProt { ssh1only, ssh1, ssh2, ssh2only };
-enum TKex { kexWarn, kexDHGroup1, kexDHGroup14, kexDHGEx };
-#define KEX_COUNT (kexDHGEx+1)
+enum TKex { kexWarn, kexDHGroup1, kexDHGroup14, kexDHGEx, kexGSSGroup1, kexGSSGroup14, kexGSSGEx };
+#define KEX_COUNT (kexGSSGEx+1)
 enum TSshBug { sbIgnore1, sbPlainPW1, sbRSA1, sbHMAC2, sbDeriveKey2, sbRSAPad2,
   sbRekey2, sbPKSessID2 };
 #define BUG_COUNT (sbPKSessID2+1)
-enum TSftpBug { sbSymlink, sbUtf, sbSignedTS };
+enum TSftpBug { sbSymlink, sbSignedTS };
 #define SFTP_BUG_COUNT (sbSignedTS+1)
 enum TAutoSwitch { asOn, asOff, asAuto };
 enum TPingType { ptOff, ptNullPacket, ptDummyCommand };
@@ -51,18 +51,24 @@ private:
   AnsiString FPassword;
   int FPingInterval;
   TPingType FPingType;
+  bool FTryAgent;
   bool FAgentFwd;
-  bool FAliasGroupList;
+  AnsiString FListingCommand;
   bool FAuthTIS;
   bool FAuthKI;
   bool FAuthKIPassword;
   bool FAuthGSSAPI;
   bool FGSSAPIFwdTGT;
   AnsiString FGSSAPIServerRealm;
+  bool FTryGSSKEX;
+  bool FUserNameFromEnvironment;
+  bool FGSSAPIServerChoosesUserName;
+  bool FGSSAPITrustDNS;
   bool FChangeUsername;
   bool FCompression;
   TSshProt FSshProt;
   bool FSsh2DES;
+  bool FSshNoUserAuth;
   TCipher FCiphers[CIPHER_COUNT];
   TKex FKex[KEX_COUNT];
   bool FClearAliases;
@@ -84,6 +90,7 @@ private:
   AnsiString FReturnVar;
   bool FScp1Compatibility;
   AnsiString FShell;
+  AnsiString FSftpServer;
   int FTimeout;
   bool FUnsetNationalVars;
   bool FIgnoreLsWarnings;
@@ -94,6 +101,7 @@ private:
   AnsiString FProxyUsername;
   AnsiString FProxyPassword;
   AnsiString FProxyTelnetCommand;
+  AnsiString FProxyLocalCommand;
   TAutoSwitch FProxyDNS;
   bool FProxyLocalhost;
   TAutoSwitch FBugs[BUG_COUNT];
@@ -111,6 +119,7 @@ private:
   bool FDeleteToRecycleBin;
   bool FOverwrittenToRecycleBin;
   AnsiString FRecycleBinPath;
+  AnsiString FPostLoginCommands;
   TAutoSwitch FSCPLsFullTime;
   TAddressFamily FAddressFamily;
   AnsiString FRekeyData;
@@ -128,6 +137,8 @@ private:
   AnsiString FFtpAccount;
   int FFtpPingInterval;
   TPingType FFtpPingType;
+  TAutoSwitch FUtf;
+  AnsiString FHostKey;
 
   AnsiString FOrigHostName;
   int FOrigPortNumber;
@@ -139,6 +150,7 @@ private:
   void __fastcall SetPassword(AnsiString value);
   AnsiString __fastcall GetPassword();
   void __fastcall SetPingInterval(int value);
+  void __fastcall SetTryAgent(bool value);
   void __fastcall SetAgentFwd(bool value);
   void __fastcall SetAuthTIS(bool value);
   void __fastcall SetAuthKI(bool value);
@@ -146,10 +158,15 @@ private:
   void __fastcall SetAuthGSSAPI(bool value);
   void __fastcall SetGSSAPIFwdTGT(bool value);
   void __fastcall SetGSSAPIServerRealm(AnsiString value);
+  void __fastcall SetTryGSSKEX(bool value);
+  void __fastcall SetUserNameFromEnvironment(bool value);
+  void __fastcall SetGSSAPIServerChoosesUserName(bool value);
+  void __fastcall SetGSSAPITrustDNS(bool value);
   void __fastcall SetChangeUsername(bool value);
   void __fastcall SetCompression(bool value);
   void __fastcall SetSshProt(TSshProt value);
   void __fastcall SetSsh2DES(bool value);
+  void __fastcall SetSshNoUserAuth(bool value);
   void __fastcall SetCipher(int Index, TCipher value);
   TCipher __fastcall GetCipher(int Index) const;
   void __fastcall SetKex(int Index, TKex value);
@@ -161,9 +178,12 @@ private:
   bool __fastcall GetCanLogin();
   void __fastcall SetPingIntervalDT(TDateTime value);
   TDateTime __fastcall GetPingIntervalDT();
+  TDateTime __fastcall GetFtpPingIntervalDT();
   void __fastcall SetTimeDifference(TDateTime value);
   void __fastcall SetPingType(TPingType value);
   AnsiString __fastcall GetSessionName();
+  AnsiString __fastcall GetSessionUrl();
+  void __fastcall SetProtocol(TProtocol value);
   void __fastcall SetFSProtocol(TFSProtocol value);
   AnsiString __fastcall GetFSProtocolStr();
   void __fastcall SetLocalDirectory(AnsiString value);
@@ -179,7 +199,7 @@ private:
   bool __fastcall GetDefaultShell();
   void __fastcall SetDetectReturnVar(bool value);
   bool __fastcall GetDetectReturnVar();
-  void __fastcall SetAliasGroupList(bool value);
+  void __fastcall SetListingCommand(AnsiString value);
   void __fastcall SetClearAliases(bool value);
   void __fastcall SetDefaultShell(bool value);
   void __fastcall SetEOLType(TEOLType value);
@@ -187,6 +207,7 @@ private:
   void __fastcall SetReturnVar(AnsiString value);
   void __fastcall SetScp1Compatibility(bool value);
   void __fastcall SetShell(AnsiString value);
+  void __fastcall SetSftpServer(AnsiString value);
   void __fastcall SetTimeout(int value);
   void __fastcall SetUnsetNationalVars(bool value);
   void __fastcall SetIgnoreLsWarnings(bool value);
@@ -203,6 +224,7 @@ private:
   void __fastcall SetProxyUsername(AnsiString value);
   void __fastcall SetProxyPassword(AnsiString value);
   void __fastcall SetProxyTelnetCommand(AnsiString value);
+  void __fastcall SetProxyLocalCommand(AnsiString value);
   void __fastcall SetProxyDNS(TAutoSwitch value);
   void __fastcall SetProxyLocalhost(bool value);
   AnsiString __fastcall GetProxyPassword() const;
@@ -225,6 +247,7 @@ private:
   void __fastcall SetDeleteToRecycleBin(bool value);
   void __fastcall SetOverwrittenToRecycleBin(bool value);
   void __fastcall SetRecycleBinPath(AnsiString value);
+  void __fastcall SetPostLoginCommands(AnsiString value);
   void __fastcall SetAddressFamily(TAddressFamily value);
   void __fastcall SetRekeyData(AnsiString value);
   void __fastcall SetRekeyTime(unsigned int value);
@@ -243,6 +266,8 @@ private:
   void __fastcall SetFtpAccount(AnsiString value);
   void __fastcall SetFtpPingInterval(int value);
   void __fastcall SetFtpPingType(TPingType value);
+  void __fastcall SetUtf(TAutoSwitch value);
+  void __fastcall SetHostKey(AnsiString value);
   static AnsiString __fastcall DecodeUrlChars(const AnsiString & S, bool Decode);
 
 public:
@@ -255,12 +280,14 @@ public:
   void __fastcall Remove();
   virtual void __fastcall Assign(TPersistent * Source);
   bool __fastcall ParseUrl(AnsiString Url, int Params, AnsiString * FileName);
+  bool __fastcall ParseOptions(TOptions * Options);
   void __fastcall ConfigureTunnel(int PortNumber);
   void __fastcall RollbackTunnel();
   static bool __fastcall ParseUrl(AnsiString Url, int Params,
     AnsiString * ConnectInfo, AnsiString * HostName, int * PortNumber,
     AnsiString * UserName, AnsiString * Password, AnsiString * Path,
     AnsiString * FileName);
+  static void __fastcall ValidatePath(const AnsiString Path);
   static void __fastcall ValidateName(const AnsiString Name);
 
   __property AnsiString HostName  = { read=FHostName, write=SetHostName };
@@ -268,23 +295,29 @@ public:
   __property AnsiString UserName  = { read=FUserName, write=SetUserName };
   __property AnsiString Password  = { read=GetPassword, write=SetPassword };
   __property int PingInterval  = { read=FPingInterval, write=SetPingInterval };
+  __property bool TryAgent  = { read=FTryAgent, write=SetTryAgent };
   __property bool AgentFwd  = { read=FAgentFwd, write=SetAgentFwd };
-  __property bool AliasGroupList = { read = FAliasGroupList, write = SetAliasGroupList };
+  __property AnsiString ListingCommand = { read = FListingCommand, write = SetListingCommand };
   __property bool AuthTIS  = { read=FAuthTIS, write=SetAuthTIS };
   __property bool AuthKI  = { read=FAuthKI, write=SetAuthKI };
   __property bool AuthKIPassword  = { read=FAuthKIPassword, write=SetAuthKIPassword };
   __property bool AuthGSSAPI  = { read=FAuthGSSAPI, write=SetAuthGSSAPI };
   __property bool GSSAPIFwdTGT = { read=FGSSAPIFwdTGT, write=SetGSSAPIFwdTGT };
   __property AnsiString GSSAPIServerRealm = { read=FGSSAPIServerRealm, write=SetGSSAPIServerRealm };
+  __property bool TryGSSKEX = { read=FTryGSSKEX, write=SetTryGSSKEX };
+  __property bool UserNameFromEnvironment = { read=FUserNameFromEnvironment, write=SetUserNameFromEnvironment };
+  __property bool GSSAPIServerChoosesUserName = { read=FGSSAPIServerChoosesUserName, write=SetGSSAPIServerChoosesUserName };
+  __property bool GSSAPITrustDNS = { read=FGSSAPITrustDNS, write=SetGSSAPITrustDNS };
   __property bool ChangeUsername  = { read=FChangeUsername, write=SetChangeUsername };
   __property bool Compression  = { read=FCompression, write=SetCompression };
   __property TSshProt SshProt  = { read=FSshProt, write=SetSshProt };
   __property bool UsesSsh = { read = GetUsesSsh };
   __property bool Ssh2DES  = { read=FSsh2DES, write=SetSsh2DES };
+  __property bool SshNoUserAuth  = { read=FSshNoUserAuth, write=SetSshNoUserAuth };
   __property TCipher Cipher[int Index] = { read=GetCipher, write=SetCipher };
   __property TKex Kex[int Index] = { read=GetKex, write=SetKex };
   __property AnsiString PublicKeyFile  = { read=FPublicKeyFile, write=SetPublicKeyFile };
-  __property TProtocol Protocol  = { read=FProtocol };
+  __property TProtocol Protocol  = { read=FProtocol, write=SetProtocol };
   __property AnsiString ProtocolStr  = { read=GetProtocolStr, write=SetProtocolStr };
   __property TFSProtocol FSProtocol  = { read=FFSProtocol, write=SetFSProtocol  };
   __property AnsiString FSProtocolStr  = { read=GetFSProtocolStr };
@@ -295,6 +328,7 @@ public:
   __property TDateTime TimeDifference = { read = FTimeDifference, write = SetTimeDifference };
   __property TPingType PingType = { read = FPingType, write = SetPingType };
   __property AnsiString SessionName  = { read=GetSessionName };
+  __property AnsiString SessionUrl  = { read=GetSessionUrl };
   __property AnsiString LocalDirectory  = { read=FLocalDirectory, write=SetLocalDirectory };
   __property AnsiString RemoteDirectory  = { read=FRemoteDirectory, write=SetRemoteDirectory };
   __property bool UpdateDirectories = { read=FUpdateDirectories, write=SetUpdateDirectories };
@@ -313,6 +347,7 @@ public:
   __property AnsiString ReturnVar = { read = FReturnVar, write = SetReturnVar };
   __property bool Scp1Compatibility = { read = FScp1Compatibility, write = SetScp1Compatibility };
   __property AnsiString Shell = { read = FShell, write = SetShell };
+  __property AnsiString SftpServer = { read = FSftpServer, write = SetSftpServer };
   __property int Timeout = { read = FTimeout, write = SetTimeout };
   __property bool UnsetNationalVars = { read = FUnsetNationalVars, write = SetUnsetNationalVars };
   __property bool IgnoreLsWarnings  = { read=FIgnoreLsWarnings, write=SetIgnoreLsWarnings };
@@ -326,6 +361,7 @@ public:
   __property AnsiString ProxyUsername  = { read=FProxyUsername, write=SetProxyUsername };
   __property AnsiString ProxyPassword  = { read=GetProxyPassword, write=SetProxyPassword };
   __property AnsiString ProxyTelnetCommand  = { read=FProxyTelnetCommand, write=SetProxyTelnetCommand };
+  __property AnsiString ProxyLocalCommand  = { read=FProxyLocalCommand, write=SetProxyLocalCommand };
   __property TAutoSwitch ProxyDNS  = { read=FProxyDNS, write=SetProxyDNS };
   __property bool ProxyLocalhost  = { read=FProxyLocalhost, write=SetProxyLocalhost };
   __property TAutoSwitch Bug[TSshBug Bug]  = { read=GetBug, write=SetBug };
@@ -344,6 +380,7 @@ public:
   __property bool DeleteToRecycleBin = { read = FDeleteToRecycleBin, write = SetDeleteToRecycleBin };
   __property bool OverwrittenToRecycleBin = { read = FOverwrittenToRecycleBin, write = SetOverwrittenToRecycleBin };
   __property AnsiString RecycleBinPath = { read = FRecycleBinPath, write = SetRecycleBinPath };
+  __property AnsiString PostLoginCommands = { read = FPostLoginCommands, write = SetPostLoginCommands };
   __property TAddressFamily AddressFamily = { read = FAddressFamily, write = SetAddressFamily };
   __property AnsiString RekeyData = { read = FRekeyData, write = SetRekeyData };
   __property unsigned int RekeyTime = { read = FRekeyTime, write = SetRekeyTime };
@@ -360,7 +397,10 @@ public:
   __property bool FtpPasvMode = { read = FFtpPasvMode, write = SetFtpPasvMode };
   __property AnsiString FtpAccount = { read = FFtpAccount, write = SetFtpAccount };
   __property int FtpPingInterval  = { read=FFtpPingInterval, write=SetFtpPingInterval };
+  __property TDateTime FtpPingIntervalDT  = { read=GetFtpPingIntervalDT };
   __property TPingType FtpPingType = { read = FFtpPingType, write = SetFtpPingType };
+  __property TAutoSwitch Utf = { read = FUtf, write = SetUtf };
+  __property AnsiString HostKey = { read = FHostKey, write = SetHostKey };
   __property AnsiString StorageKey = { read = GetStorageKey };
   __property AnsiString OrigHostName = { read = FOrigHostName };
   __property int OrigPortNumber = { read = FOrigPortNumber };
@@ -386,7 +426,7 @@ public:
   void __fastcall Cleanup();
   int __fastcall IndexOf(TSessionData * Data);
   TSessionData * __fastcall NewSession(AnsiString SessionName, TSessionData * Session);
-  TSessionData * __fastcall ParseUrl(AnsiString Url, bool & DefaultsOnly,
+  TSessionData * __fastcall ParseUrl(AnsiString Url, TOptions * Options, bool & DefaultsOnly,
     int Params, AnsiString * FileName = NULL, bool * ProtocolDefined = NULL);
   virtual __fastcall ~TStoredSessionList();
   __property TSessionData * Sessions[int Index]  = { read=AtSession };

+ 17 - 10
core/SessionInfo.cpp

@@ -155,7 +155,7 @@ void __fastcall TSessionLog::Add(TLogLineType Type, const AnsiString & Line)
     }
     catch (Exception &E)
     {
-      // We failed logging, turn it of and notify user.
+      // We failed logging, turn it off and notify user.
       FConfiguration->Logging = false;
       try
       {
@@ -230,9 +230,10 @@ void TSessionLog::OpenLogFile()
     TDateTime N = Now();
     for (int Index = 1; Index < NewFileName.Length(); Index++)
     {
-      if (NewFileName[Index] == '&')
+      if (NewFileName[Index] == '!')
       {
         AnsiString Replacement;
+        // keep consistent with TFileCustomCommand::PatternReplacement
         switch (tolower(NewFileName[Index + 1]))
         {
           case 'y':
@@ -251,7 +252,7 @@ void TSessionLog::OpenLogFile()
             Replacement = FormatDateTime("hhnnss", N);
             break;
 
-          case 'h':
+          case '@':
             Replacement = MakeValidFileName(FSessionData->HostName);
             break;
 
@@ -259,12 +260,12 @@ void TSessionLog::OpenLogFile()
             Replacement = MakeValidFileName(FSessionData->SessionName);
             break;
 
-          case '&':
-            Replacement = "&";
+          case '!':
+            Replacement = "!";
             break;
 
           default:
-            Replacement = AnsiString("&") + NewFileName[Index + 1];
+            Replacement = AnsiString("!") + NewFileName[Index + 1];
             break;
         }
         NewFileName.Delete(Index, 2);
@@ -395,13 +396,19 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
       {
         ADF("Telnet command: %s", (Data->ProxyTelnetCommand));
       }
+      if (Data->ProxyMethod == pmCmd)
+      {
+        ADF("Local command: %s", (Data->ProxyLocalCommand));
+      }
     }
     if (Data->UsesSsh)
     {
       ADF("SSH protocol version: %s; Compression: %s",
         (Data->SshProtStr, BooleanToEngStr(Data->Compression)));
-      ADF("Agent forwarding: %s; TIS/CryptoCard: %s; KI: %s; GSSAPI: %s",
-        (BooleanToEngStr(Data->AgentFwd), BooleanToEngStr(Data->AuthTIS),
+      ADF("Bypass authentication: %s",
+       (BooleanToEngStr(Data->SshNoUserAuth)));
+      ADF("Try agent: %s; Agent forwarding: %s; TIS/CryptoCard: %s; KI: %s; GSSAPI: %s",
+        (BooleanToEngStr(Data->TryAgent), BooleanToEngStr(Data->AgentFwd), BooleanToEngStr(Data->AuthTIS),
          BooleanToEngStr(Data->AuthKI), BooleanToEngStr(Data->AuthGSSAPI)));
       if (Data->AuthGSSAPI)
       {
@@ -430,8 +437,8 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
       ADF("Clear aliases: %s, Unset nat.vars: %s, Resolve symlinks: %s",
         (BooleanToEngStr(Data->ClearAliases), BooleanToEngStr(Data->UnsetNationalVars),
          BooleanToEngStr(Data->ResolveSymlinks)));
-      ADF("Alias LS: %s, Ign LS warn: %s, Scp1 Comp: %s",
-        (BooleanToEngStr(Data->AliasGroupList),
+      ADF("LS: %s, Ign LS warn: %s, Scp1 Comp: %s",
+        (Data->ListingCommand,
          BooleanToEngStr(Data->IgnoreLsWarnings),
          BooleanToEngStr(Data->Scp1Compatibility)));
     }

+ 3 - 2
core/SessionInfo.h

@@ -55,8 +55,9 @@ public:
   virtual int __fastcall QueryUserException(const AnsiString Query,
     Exception * E, int Answers, const TQueryParams * Params,
     TQueryType QueryType = qtConfirmation) = 0;
-  virtual bool __fastcall PromptUser(TSessionData * Data, AnsiString Prompt,
-    TPromptKind Kind, AnsiString & Response) = 0;
+  virtual bool __fastcall PromptUser(TSessionData * Data, TPromptKind Kind,
+    AnsiString Name, AnsiString Instructions, TStrings * Prompts,
+    TStrings * Results) = 0;
   virtual void __fastcall DisplayBanner(const AnsiString & Banner) = 0;
   virtual void __fastcall ShowExtendedException(Exception * E) = 0;
   virtual void __fastcall Closed() = 0;

+ 33 - 27
core/SftpFileSystem.cpp

@@ -1342,7 +1342,7 @@ protected:
         {
           __int64 PrevBufSize = BlockBuf.Size;
           BlockBuf.Convert(FTerminal->Configuration->LocalEOLType,
-            FFileSystem->GetEOL(), cpRemoveCtrlZ);
+            FFileSystem->GetEOL(), cpRemoveCtrlZ | cpRemoveBOM);
           // update transfer size with difference arised from EOL conversion
           OperationProgress->ChangeTransferSize(OperationProgress->TransferSize -
             PrevBufSize + BlockBuf.Size);
@@ -1899,6 +1899,9 @@ unsigned long __fastcall TSFTPFileSystem::TransferBlockSize(unsigned long Overhe
       }
     }
   }
+
+  Result = OperationProgress->AdjustToCPSLimit(Result);
+
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -2711,10 +2714,10 @@ void __fastcall TSFTPFileSystem::DoStartup()
   // use UTF when forced or ...
   // when "auto" and version is at least 4 and the server is not know not to use UTF
   FUtfNever = (GetSessionInfo().SshImplementation.Pos("Foxit-WAC-Server") == 1) ||
-    (FTerminal->SessionData->SFTPBug[sbUtf] == asOn);
+    (FTerminal->SessionData->Utf == asOn);
   FUtfStrings =
-    (FTerminal->SessionData->SFTPBug[sbUtf] == asOff) ||
-    ((FTerminal->SessionData->SFTPBug[sbUtf] == asAuto) &&
+    (FTerminal->SessionData->Utf == asOff) ||
+    ((FTerminal->SessionData->Utf == asAuto) &&
       (FVersion >= 4) && !FUtfNever);
 
   if (FUtfStrings)
@@ -2906,7 +2909,7 @@ void __fastcall TSFTPFileSystem::ReadDirectory(TRemoteFileList * FileList)
   {
     if (FTerminal->Active)
     {
-      FileList->AddFile(new TRemoteParentDirectory());
+      FileList->AddFile(new TRemoteParentDirectory(FTerminal));
     }
     throw;
   }
@@ -2926,7 +2929,6 @@ void __fastcall TSFTPFileSystem::ReadDirectory(TRemoteFileList * FileList)
     do
     {
       ReceiveResponse(&Packet, &Response);
-
       if (Response.Type == SSH_FXP_NAME)
       {
         TSFTPPacket ListingPacket = Response;
@@ -2952,6 +2954,10 @@ void __fastcall TSFTPFileSystem::ReadDirectory(TRemoteFileList * FileList)
           }
           else
           {
+            if (FTerminal->Configuration->LogProtocol >= 1)
+            {
+              FTerminal->LogEvent(FORMAT("Read file '%s' from listing", (File->FileName)));
+            }
             FileList->AddFile(File);
 
             Total++;
@@ -3012,7 +3018,7 @@ void __fastcall TSFTPFileSystem::ReadDirectory(TRemoteFileList * FileList)
       bool Failure = (File == NULL);
       if (Failure)
       {
-        File = new TRemoteParentDirectory();
+        File = new TRemoteParentDirectory(FTerminal);
       }
 
       assert(File && File->IsParentDirectory);
@@ -3160,15 +3166,15 @@ void __fastcall TSFTPFileSystem::CustomReadFile(const AnsiString FileName,
 }
 //---------------------------------------------------------------------------
 void __fastcall TSFTPFileSystem::DeleteFile(const AnsiString FileName,
-  const TRemoteFile * File, bool Recursive)
+  const TRemoteFile * File, int Params)
 {
   char Type;
   AnsiString RealFileName = LocalCanonify(FileName);
   if (File && File->IsDirectory && !File->IsSymLink)
   {
-    if (Recursive)
+    if (FLAGCLEAR(Params, dfNoRecursive))
     {
-      FTerminal->ProcessDirectory(FileName, FTerminal->DeleteFile, &Recursive);
+      FTerminal->ProcessDirectory(FileName, FTerminal->DeleteFile, &Params);
     }
     Type = SSH_FXP_RMDIR;
   }
@@ -3667,8 +3673,8 @@ void __fastcall TSFTPFileSystem::SFTPConfirmOverwrite(AnsiString & FileName,
     }
     else if (Answer == qaIgnore)
     {
-      if (FTerminal->PromptUser(FTerminal->SessionData, LoadStr(RENAME_PROMPT),
-            pkPrompt, FileName))
+      if (FTerminal->PromptUser(FTerminal->SessionData, pkPrompt, LoadStr(RENAME_TITLE), "",
+            LoadStr(RENAME_PROMPT2), true, 0, FileName))
       {
         OverwriteMode = omOverwrite;
       }
@@ -3976,15 +3982,6 @@ void __fastcall TSFTPFileSystem::SFTPSource(const AnsiString FileName,
       // will the transfer be resumable?
       bool DoResume = (ResumeAllowed && (OpenParams.OverwriteMode == omOverwrite));
 
-      if (DoResume && DestFileExists)
-      {
-        FILE_OPERATION_LOOP(FMTLOAD(DELETE_BEFORE_RESUME_ERROR,
-            (UnixExtractFileName(DestFullName), DestFullName)),
-
-          DeleteFile(DestFullName);
-        );
-      }
-
       OpenParams.RemoteFileName = DoResume ? DestPartinalFullName : DestFullName;
       OpenParams.Resume = DoResume;
       OpenParams.OperationProgress = OperationProgress;
@@ -4099,10 +4096,19 @@ void __fastcall TSFTPFileSystem::SFTPSource(const AnsiString FileName,
         }
       }
 
-      // originally this was before CLOSE (last __finally statement),
-      // on VShell it failed
       if (DoResume)
       {
+        if (DestFileExists)
+        {
+          FILE_OPERATION_LOOP(FMTLOAD(DELETE_ON_RESUME_ERROR,
+              (UnixExtractFileName(DestFullName), DestFullName)),
+
+            DeleteFile(DestFullName);
+          );
+        }
+
+        // originally this was before CLOSE (last __finally statement),
+        // on VShell it failed
         FILE_OPERATION_LOOP(FMTLOAD(RENAME_AFTER_RESUME_ERROR,
             (UnixExtractFileName(OpenParams.RemoteFileName), DestFileName)),
           RenameFile(OpenParams.RemoteFileName, DestFileName);
@@ -4340,8 +4346,8 @@ int __fastcall TSFTPFileSystem::SFTPOpenRemote(void * AOpenParams, void * /*Para
               FMTLOAD(SFTP_OVERWRITE_FILE_ERROR, (OpenParams->RemoteFileName)),
               true, LoadStr(SFTP_OVERWRITE_DELETE_BUTTON)))
         {
-          bool Recursive = false;
-          FTerminal->DeleteFile(OpenParams->RemoteFileName, NULL, &Recursive);
+          int Params = dfNoRecursive;
+          FTerminal->DeleteFile(OpenParams->RemoteFileName, NULL, &Params);
         }
       }
       else
@@ -5044,8 +5050,8 @@ void __fastcall TSFTPFileSystem::SFTPSink(const AnsiString FileName,
     // If file is directory, do not delete it recursively, because it should be
     // empty already. If not, it should not be deleted (some files were
     // skipped or some new files were copied to it, while we were downloading)
-    bool Recursive = false;
-    FTerminal->DeleteFile(FileName, File, &Recursive);
+    int Params = dfNoRecursive;
+    FTerminal->DeleteFile(FileName, File, &Params);
   }
 }
 //---------------------------------------------------------------------------

+ 1 - 1
core/SftpFileSystem.h

@@ -53,7 +53,7 @@ public:
     const TRemoteProperties * Properties);
   virtual void __fastcall CreateLink(const AnsiString FileName, const AnsiString PointTo, bool Symbolic);
   virtual void __fastcall DeleteFile(const AnsiString FileName,
-    const TRemoteFile * File = NULL, bool Recursive = false);
+    const TRemoteFile * File = NULL, int Params = dfNoRecursive);
   virtual void __fastcall CustomCommandOnFile(const AnsiString FileName,
     const TRemoteFile * File, AnsiString Command, int Params, TCaptureOutputEvent OutputEvent);
   virtual void __fastcall DoStartup();

+ 107 - 57
core/Terminal.cpp

@@ -219,8 +219,9 @@ public:
   virtual int __fastcall QueryUserException(const AnsiString Query,
     Exception * E, int Answers, const TQueryParams * Params,
     TQueryType QueryType);
-  virtual bool __fastcall PromptUser(TSessionData * Data, AnsiString Prompt,
-    TPromptKind Kind, AnsiString & Response);
+  virtual bool __fastcall PromptUser(TSessionData * Data, TPromptKind Kind,
+    AnsiString Name, AnsiString Instructions, TStrings * Prompts,
+    TStrings * Results);
   virtual void __fastcall DisplayBanner(const AnsiString & Banner);
   virtual void __fastcall ShowExtendedException(Exception * E);
   virtual void __fastcall Closed();
@@ -276,13 +277,20 @@ int __fastcall TTunnelUI::QueryUserException(const AnsiString Query,
   return Result;
 }
 //---------------------------------------------------------------------------
-bool __fastcall TTunnelUI::PromptUser(TSessionData * Data, AnsiString Prompt,
-  TPromptKind Kind, AnsiString & Response)
+bool __fastcall TTunnelUI::PromptUser(TSessionData * Data, TPromptKind Kind,
+  AnsiString Name, AnsiString Instructions, TStrings * Prompts, TStrings * Results)
 {
   bool Result;
   if (GetCurrentThreadId() == FTerminalThread)
   {
-    Result = FTerminal->PromptUser(Data, Prompt, Kind, Response);
+    if (IsAuthenticationPrompt(Kind))
+    {
+      Instructions = LoadStr(TUNNEL_INSTRUCTION) +
+        (Instructions.IsEmpty() ? "" : "\n") +
+        Instructions;
+    }
+
+    Result = FTerminal->PromptUser(Data, Kind, Name, Instructions, Prompts, Results);
   }
   else
   {
@@ -359,6 +367,7 @@ __fastcall TTerminal::TTerminal(TSessionData * SessionData,
   FTunnelData = NULL;
   FTunnelLog = NULL;
   FTunnelUI = NULL;
+  FTunnelOpening = false;
 }
 //---------------------------------------------------------------------------
 __fastcall TTerminal::~TTerminal()
@@ -590,7 +599,8 @@ void __fastcall TTerminal::Open()
         if (SessionData->CacheDirectoryChanges)
         {
           assert(FDirectoryChangesCache == NULL);
-          FDirectoryChangesCache = new TRemoteDirectoryChangesCache();
+          FDirectoryChangesCache = new TRemoteDirectoryChangesCache(
+            Configuration->CacheDirectoryChangesMaxSize);
           if (SessionData->PreserveDirectoryChanges)
           {
             Configuration->LoadDirectoryChangesCache(SessionData->SessionKey,
@@ -682,6 +692,7 @@ void __fastcall TTerminal::OpenTunnel()
     FTunnelData->ProxyUsername = FSessionData->ProxyUsername;
     FTunnelData->ProxyPassword = FSessionData->ProxyPassword;
     FTunnelData->ProxyTelnetCommand = FSessionData->ProxyTelnetCommand;
+    FTunnelData->ProxyLocalCommand = FSessionData->ProxyLocalCommand;
     FTunnelData->ProxyDNS = FSessionData->ProxyDNS;
     FTunnelData->ProxyLocalhost = FSessionData->ProxyLocalhost;
 
@@ -691,7 +702,15 @@ void __fastcall TTerminal::OpenTunnel()
     FTunnelUI = new TTunnelUI(this);
     FTunnel = new TSecureShell(FTunnelUI, FTunnelData, FTunnelLog, Configuration);
 
-    FTunnel->Open();
+    FTunnelOpening = true;
+    try
+    {
+      FTunnel->Open();
+    }
+    __finally
+    {
+      FTunnelOpening = false;
+    }
 
     FTunnelThread = new TTunnelThread(FTunnel);
   }
@@ -777,32 +796,58 @@ void __fastcall TTerminal::Reopen(int Params)
   }
 }
 //---------------------------------------------------------------------------
-bool __fastcall TTerminal::PromptUser(TSessionData * Data, AnsiString Prompt,
-  TPromptKind Kind, AnsiString & Response)
+bool __fastcall TTerminal::PromptUser(TSessionData * Data, TPromptKind Kind,
+  AnsiString Name, AnsiString Instructions, AnsiString Prompt, bool Echo, int MaxLen, AnsiString & Result)
+{
+  bool AResult;
+  TStrings * Prompts = new TStringList;
+  TStrings * Results = new TStringList;
+  try
+  {
+    Prompts->AddObject(Prompt, (TObject *)Echo);
+    Results->AddObject(Result, (TObject *)MaxLen);
+
+    AResult = PromptUser(Data, Kind, Name, Instructions, Prompts, Results);
+
+    Result = Results->Strings[0];
+  }
+  __finally
+  {
+    delete Prompts;
+    delete Results;
+  }
+
+  return AResult;
+}
+//---------------------------------------------------------------------------
+bool __fastcall TTerminal::PromptUser(TSessionData * Data, TPromptKind Kind,
+  AnsiString Name, AnsiString Instructions, TStrings * Prompts, TStrings * Results)
 {
   // If PromptUser is overriden in descendant class, the overriden version
   // is not called when accessed via TSessionIU interface.
   // So this is workaround.
-  return DoPromptUser(Data, Prompt, Kind, Response);
+  return DoPromptUser(Data, Kind, Name, Instructions, Prompts, Results);
 }
 //---------------------------------------------------------------------------
-bool __fastcall TTerminal::DoPromptUser(TSessionData * /*Data*/, AnsiString Prompt,
-  TPromptKind Kind, AnsiString & Response)
+bool __fastcall TTerminal::DoPromptUser(TSessionData * /*Data*/, TPromptKind Kind,
+  AnsiString Name, AnsiString Instructions, TStrings * Prompts, TStrings * Results)
 {
-  bool Result = false;
+  bool AResult = false;
 
   if (OnPromptUser != NULL)
   {
-    OnPromptUser(this, Prompt, Kind, Response, Result, NULL);
+    OnPromptUser(this, Kind, Name, Instructions, Prompts, Results, AResult, NULL);
   }
 
-  if ((Configuration->RememberPassword) &&
-      ((Kind == pkPassword) || (Kind == pkPassphrase) || (Kind == pkServerPrompt)))
+  if (AResult && (Configuration->RememberPassword) &&
+      (Prompts->Count == 1) && !bool(Prompts->Objects[0]) &&
+      ((Kind == pkPassword) || (Kind == pkPassphrase) || (Kind == pkKeybInteractive) ||
+       (Kind == pkTIS) || (Kind == pkCryptoCard)))
   {
-    FPassword = EncryptPassword(Response, SessionData->SessionName);
+    FPassword = EncryptPassword(Results->Strings[0], SessionData->SessionName);
   }
 
-  return Result;
+  return AResult;
 }
 //---------------------------------------------------------------------------
 int __fastcall TTerminal::QueryUser(const AnsiString Query,
@@ -1599,14 +1644,6 @@ void __fastcall TTerminal::FileModified(const TRemoteFile * File,
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::DoDirectoryModified(const AnsiString Path, bool SubDirs)
-{
-  if (OnDirectoryModified != NULL)
-  {
-    OnDirectoryModified(this, Path, SubDirs);
-  }
-}
-//---------------------------------------------------------------------------
 void __fastcall TTerminal::DirectoryModified(const AnsiString Path, bool SubDirs)
 {
   if (Path.IsEmpty())
@@ -1617,7 +1654,6 @@ void __fastcall TTerminal::DirectoryModified(const AnsiString Path, bool SubDirs
   {
     ClearCachedFileList(Path, SubDirs);
   }
-  DoDirectoryModified(Path, SubDirs);
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::DirectoryLoaded(TRemoteFileList * FileList)
@@ -2121,7 +2157,7 @@ void __fastcall TTerminal::RecycleFile(AnsiString FileName,
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::DeleteFile(AnsiString FileName,
-  const TRemoteFile * File, void * Recursive)
+  const TRemoteFile * File, void * AParams)
 {
   if (FileName.IsEmpty() && File)
   {
@@ -2132,7 +2168,9 @@ void __fastcall TTerminal::DeleteFile(AnsiString FileName,
     if (OperationProgress->Cancel != csContinue) Abort();
     OperationProgress->SetFile(FileName);
   }
-  if (SessionData->DeleteToRecycleBin && !IsRecycledFile(FileName))
+  int Params = *((int*)AParams);
+  bool Recycle = (SessionData->DeleteToRecycleBin != FLAGSET(Params, dfAlternative));
+  if (Recycle && !IsRecycledFile(FileName))
   {
     RecycleFile(FileName, File);
   }
@@ -2140,41 +2178,40 @@ void __fastcall TTerminal::DeleteFile(AnsiString FileName,
   {
     LogEvent(FORMAT("Deleting file \"%s\".", (FileName)));
     if (File) FileModified(File, FileName, true);
-    DoDeleteFile(FileName, File, Recursive);
+    DoDeleteFile(FileName, File, Params);
     ReactOnCommand(fsDeleteFile);
   }
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::DoDeleteFile(const AnsiString FileName,
-  const TRemoteFile * File, void * Recursive)
+  const TRemoteFile * File, int Params)
 {
   try
   {
     assert(FFileSystem);
     // 'File' parameter: SFTPFileSystem needs to know if file is file or directory
-    FFileSystem->DeleteFile(FileName, File,
-      Recursive ? *((bool*)Recursive) : true);
+    FFileSystem->DeleteFile(FileName, File, Params);
   }
   catch(Exception & E)
   {
     COMMAND_ERROR_ARI
     (
       FMTLOAD(DELETE_FILE_ERROR, (FileName)),
-      DoDeleteFile(FileName, File, Recursive)
+      DoDeleteFile(FileName, File, Params)
     );
   }
 }
 //---------------------------------------------------------------------------
-bool __fastcall TTerminal::DeleteFiles(TStrings * FilesToDelete, bool * Recursive)
+bool __fastcall TTerminal::DeleteFiles(TStrings * FilesToDelete, int Params)
 {
   // TODO: avoid resolving symlinks while reading subdirectories.
   // Resolving does not work anyway for relative symlinks in subdirectories
   // (at least for SFTP).
-  return ProcessFiles(FilesToDelete, foDelete, DeleteFile, Recursive);
+  return ProcessFiles(FilesToDelete, foDelete, DeleteFile, &Params);
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::DeleteLocalFile(AnsiString FileName,
-  const TRemoteFile * /*File*/, void * /*Param*/)
+  const TRemoteFile * /*File*/, void * Params)
 {
   if (OnDeleteLocalFile == NULL)
   {
@@ -2185,13 +2222,13 @@ void __fastcall TTerminal::DeleteLocalFile(AnsiString FileName,
   }
   else
   {
-    OnDeleteLocalFile(FileName);
+    OnDeleteLocalFile(FileName, FLAGSET(*((int*)Params), dfAlternative));
   }
 }
 //---------------------------------------------------------------------------
-bool __fastcall TTerminal::DeleteLocalFiles(TStrings * FileList)
+bool __fastcall TTerminal::DeleteLocalFiles(TStrings * FileList, int Params)
 {
-  return ProcessFiles(FileList, foDelete, DeleteLocalFile, NULL, osLocal);
+  return ProcessFiles(FileList, foDelete, DeleteLocalFile, &Params, osLocal);
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::CustomCommandOnFile(AnsiString FileName,
@@ -2278,7 +2315,10 @@ void __fastcall TTerminal::CustomCommandOnFiles(AnsiString Command,
       }
     }
 
-    AnsiString Cmd = TRemoteCustomCommand("", FileList).Complete(Command, true);
+    TCustomCommandData Data(this);
+    AnsiString Cmd =
+      TRemoteCustomCommand(Data, CurrentDirectory, "", FileList).
+        Complete(Command, true);
     AnyCommand(Cmd, OutputEvent);
   }
 }
@@ -2821,8 +2861,12 @@ TTerminal * __fastcall TTerminal::GetCommandSession()
 
       FCommandSession->AutoReadDirectory = false;
 
-      FCommandSession->FSessionData->RemoteDirectory = CurrentDirectory;
-      FCommandSession->FSessionData->FSProtocol = fsSCPonly;
+      TSessionData * CommandSessionData = FCommandSession->FSessionData;
+      CommandSessionData->RemoteDirectory = CurrentDirectory;
+      CommandSessionData->FSProtocol = fsSCPonly;
+      CommandSessionData->ClearAliases = false;
+      CommandSessionData->UnsetNationalVars = false;
+      CommandSessionData->LookupUserGroups = false;
 
       FCommandSession->FExceptionOnFail = FExceptionOnFail;
 
@@ -3832,11 +3876,15 @@ bool __fastcall TTerminal::GetStoredCredentialsTried()
   {
     Result = FFileSystem->GetStoredCredentialsTried();
   }
-  else
+  else if (FSecureShell != NULL)
   {
-    assert(FSecureShell != NULL);
     Result = FSecureShell->GetStoredCredentialsTried();
   }
+  else
+  {
+    assert(FTunnelOpening);
+    Result = false;
+  }
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -3864,7 +3912,7 @@ bool __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
 
     TFileOperationProgressType OperationProgress(FOnProgress, FOnFinished);
     OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osLocal,
-      FilesToCopy->Count, Params & cpTemporary, TargetDir);
+      FilesToCopy->Count, Params & cpTemporary, TargetDir, CopyParam->CPSLimit);
 
     OperationProgress.YesToNewer = FLAGSET(Params, cpNewerOnly);
 
@@ -3964,7 +4012,7 @@ bool __fastcall TTerminal::CopyToLocal(TStrings * FilesToCopy,
       }
 
       OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osRemote,
-        FilesToCopy->Count, Params & cpTemporary, TargetDir);
+        FilesToCopy->Count, Params & cpTemporary, TargetDir, CopyParam->CPSLimit);
 
       OperationProgress.YesToNewer = FLAGSET(Params, cpNewerOnly);
 
@@ -4057,30 +4105,32 @@ void __fastcall TSecondaryTerminal::DirectoryModified(const AnsiString Path,
 }
 //---------------------------------------------------------------------------
 bool __fastcall TSecondaryTerminal::DoPromptUser(TSessionData * Data,
-  AnsiString Prompt, TPromptKind Kind, AnsiString & Response)
+  TPromptKind Kind, AnsiString Name, AnsiString Instructions, TStrings * Prompts,
+  TStrings * Results)
 {
-  bool Result = false;
+  bool AResult = false;
 
-  if (!FMasterPasswordTried &&
-      ((Kind == pkPassword) || (Kind == pkPassphrase) || (Kind == pkServerPrompt)))
+  if (!FMasterPasswordTried && (Prompts->Count == 1) && !bool(Prompts->Objects[0]) &&
+      ((Kind == pkPassword) || (Kind == pkPassphrase) || (Kind == pkKeybInteractive) ||
+       (Kind == pkTIS) || (Kind == pkCryptoCard)))
   {
     // let's expect that the main session is already authenticated and its password
     // is not written after, so no locking is necessary
     // (no longer true, once the main session can be reconnected)
-    Response = FMainTerminal->Password;
-    if (!Response.IsEmpty())
+    Results->Strings[0] = FMainTerminal->Password;
+    if (!Results->Strings[0].IsEmpty())
     {
-      Result = true;
+      AResult = true;
     }
     FMasterPasswordTried = true;
   }
 
-  if (!Result)
+  if (!AResult)
   {
-    Result = TTerminal::DoPromptUser(Data, Prompt, Kind, Response);
+    AResult = TTerminal::DoPromptUser(Data, Kind, Name, Instructions, Prompts, Results);
   }
 
-  return Result;
+  return AResult;
 }
 //---------------------------------------------------------------------------
 __fastcall TTerminalList::TTerminalList(TConfiguration * AConfiguration) :

+ 21 - 18
core/Terminal.h

@@ -32,8 +32,8 @@ typedef void __fastcall (__closure *TQueryUserEvent)
   (TObject * Sender, const AnsiString Query, TStrings * MoreMessages, int Answers,
    const TQueryParams * Params, int & Answer, TQueryType QueryType, void * Arg);
 typedef void __fastcall (__closure *TPromptUserEvent)
-  (TTerminal * Terminal, AnsiString Prompt, TPromptKind Kind,
-   AnsiString & Response, bool & Result, void * Arg);
+  (TTerminal * Terminal, TPromptKind Kind, AnsiString Name, AnsiString Instructions,
+   TStrings * Prompts, TStrings * Results, bool & Result, void * Arg);
 typedef void __fastcall (__closure *TDisplayBannerEvent)
   (TTerminal * Terminal, AnsiString SessionName, const AnsiString & Banner,
    bool & NeverShowAgain, int Options);
@@ -51,7 +51,8 @@ typedef int __fastcall (__closure *TFileOperationEvent)
 typedef void __fastcall (__closure *TSynchronizeDirectory)
   (const AnsiString LocalDirectory, const AnsiString RemoteDirectory,
    bool & Continue, bool Collect);
-typedef void __fastcall (__closure *TDeleteLocalFileEvent)(const AnsiString FileName);
+typedef void __fastcall (__closure *TDeleteLocalFileEvent)(
+  const AnsiString FileName, bool Alternative);
 typedef int __fastcall (__closure *TDirectoryModifiedEvent)
   (TTerminal * Terminal, const AnsiString Directory, bool SubDirs);
 typedef void __fastcall (__closure *TInformationEvent)
@@ -119,7 +120,7 @@ class TTerminal : public TObject, public TSessionUI
 public:
   // TScript::SynchronizeProc relies on the order
   enum TSynchronizeMode { smRemote, smLocal, smBoth };
-  static const spDelete = 0x01; // cannot be combined with spTimestamp and spBySize
+  static const spDelete = 0x01; // cannot be combined with spTimestamp
   static const spNoConfirmation = 0x02; // has no effect for spTimestamp
   static const spExistingOnly = 0x04; // is implicit for spTimestamp
   static const spNoRecurse = 0x08;
@@ -155,7 +156,6 @@ private:
   int FInTransaction;
   TNotifyEvent FOnChangeDirectory;
   TReadDirectoryEvent FOnReadDirectory;
-  TDirectoryModifiedEvent FOnDirectoryModified;
   TNotifyEvent FOnStartReadDirectory;
   TReadDirectoryProgressEvent FOnReadDirectoryProgress;
   TDeleteLocalFileEvent FOnDeleteLocalFile;
@@ -185,6 +185,7 @@ private:
   TTunnelUI * FTunnelUI;
   int FTunnelLocalPortNumber;
   AnsiString FTunnelError;
+  bool FTunnelOpening;
   TQueryUserEvent FOnQueryUser;
   TPromptUserEvent FOnPromptUser;
   TDisplayBannerEvent FOnDisplayBanner;
@@ -220,11 +221,10 @@ protected:
   void __fastcall DoStartReadDirectory();
   void __fastcall DoReadDirectoryProgress(int Progress, bool & Cancel);
   void __fastcall DoReadDirectory(bool ReloadOnly);
-  void __fastcall DoDirectoryModified(const AnsiString Path, bool SubDirs);
   void __fastcall DoCreateDirectory(const AnsiString DirName,
     const TRemoteProperties * Properties);
-  void __fastcall DoDeleteFile(const AnsiString FileName,
-    const TRemoteFile * File, void * Param);
+  void __fastcall DoDeleteFile(const AnsiString FileName, const TRemoteFile * File,
+    int Params);
   void __fastcall DoCustomCommandOnFile(AnsiString FileName,
     const TRemoteFile * File, AnsiString Command, int Params, TCaptureOutputEvent OutputEvent);
   void __fastcall DoRenameFile(const AnsiString FileName,
@@ -291,12 +291,16 @@ protected:
   virtual bool __fastcall DoQueryReopen(Exception * E);
   void __fastcall FatalError(Exception * E, AnsiString Msg);
   void __fastcall ResetConnection();
-  virtual bool __fastcall DoPromptUser(TSessionData * Data, AnsiString Prompt,
-    TPromptKind Kind, AnsiString & Response);
+  virtual bool __fastcall DoPromptUser(TSessionData * Data, TPromptKind Kind,
+    AnsiString Name, AnsiString Instructions, TStrings * Prompts,
+    TStrings * Response);
   void __fastcall OpenTunnel();
   void __fastcall CloseTunnel();
   void __fastcall DoInformation(const AnsiString & Str, bool Status, bool Active = true);
   AnsiString __fastcall FileUrl(const AnsiString Protocol, const AnsiString FileName);
+  bool __fastcall PromptUser(TSessionData * Data, TPromptKind Kind,
+    AnsiString Name, AnsiString Instructions, AnsiString Prompt, bool Echo,
+    int MaxLen, AnsiString & Result);
 
   virtual void __fastcall Information(const AnsiString & Str, bool Status);
   virtual int __fastcall QueryUser(const AnsiString Query,
@@ -305,8 +309,8 @@ protected:
   virtual int __fastcall QueryUserException(const AnsiString Query,
     Exception * E, int Answers, const TQueryParams * Params,
     TQueryType QueryType = qtConfirmation);
-  virtual bool __fastcall PromptUser(TSessionData * Data, AnsiString Prompt,
-    TPromptKind Kind, AnsiString & Response);
+  virtual bool __fastcall PromptUser(TSessionData * Data, TPromptKind Kind,
+    AnsiString Name, AnsiString Instructions, TStrings * Prompts, TStrings * Results);
   virtual void __fastcall DisplayBanner(const AnsiString & Banner);
   virtual void __fastcall Closed();
 
@@ -340,9 +344,9 @@ public:
     const TRemoteProperties * Properties = NULL);
   void __fastcall CreateLink(const AnsiString FileName, const AnsiString PointTo, bool Symbolic);
   void __fastcall DeleteFile(AnsiString FileName,
-    const TRemoteFile * File = NULL, void * Recursive = NULL);
-  bool __fastcall DeleteFiles(TStrings * FilesToDelete, bool * Recursive = NULL);
-  bool __fastcall DeleteLocalFiles(TStrings * FileList);
+    const TRemoteFile * File = NULL, void * Params = NULL);
+  bool __fastcall DeleteFiles(TStrings * FilesToDelete, int Params = 0);
+  bool __fastcall DeleteLocalFiles(TStrings * FileList, int Params = 0);
   bool __fastcall IsRecycledFile(AnsiString FileName);
   void __fastcall CustomCommandOnFile(AnsiString FileName,
     const TRemoteFile * File, void * AParams);
@@ -414,7 +418,6 @@ public:
   __property TRemoteDirectory * Files = { read = FFiles };
   __property TNotifyEvent OnChangeDirectory = { read = FOnChangeDirectory, write = FOnChangeDirectory };
   __property TReadDirectoryEvent OnReadDirectory = { read = FOnReadDirectory, write = FOnReadDirectory };
-  __property TDirectoryModifiedEvent OnDirectoryModified = { read = FOnDirectoryModified, write = FOnDirectoryModified };
   __property TNotifyEvent OnStartReadDirectory = { read = FOnStartReadDirectory, write = FOnStartReadDirectory };
   __property TReadDirectoryProgressEvent OnReadDirectoryProgress = { read = FOnReadDirectoryProgress, write = FOnReadDirectoryProgress };
   __property TDeleteLocalFileEvent OnDeleteLocalFile = { read = FOnDeleteLocalFile, write = FOnDeleteLocalFile };
@@ -454,8 +457,8 @@ protected:
   virtual void __fastcall DirectoryLoaded(TRemoteFileList * FileList);
   virtual void __fastcall DirectoryModified(const AnsiString Path,
     bool SubDirs);
-  virtual bool __fastcall DoPromptUser(TSessionData * Data, AnsiString Prompt,
-    TPromptKind Kind, AnsiString & Response);
+  virtual bool __fastcall DoPromptUser(TSessionData * Data, TPromptKind Kind,
+    AnsiString Name, AnsiString Instructions, TStrings * Prompts, TStrings * Results);
 
 private:
   bool FMasterPasswordTried;

+ 7 - 7
dragext/DragExt64.def

@@ -1,7 +1,7 @@
-LIBRARY      "dragext64"
-
-EXPORTS
-    DllCanUnloadNow         PRIVATE
-    DllGetClassObject       PRIVATE
-    DllRegisterServer       PRIVATE
-    DllUnregisterServer     PRIVATE
+LIBRARY      "dragext64"
+
+EXPORTS
+    DllCanUnloadNow         PRIVATE
+    DllGetClassObject       PRIVATE
+    DllRegisterServer       PRIVATE
+    DllUnregisterServer     PRIVATE

+ 14 - 5
filezilla/ControlSocket.cpp

@@ -30,7 +30,7 @@
 #ifndef MPEXT_NO_GSS
 #include "AsyncGssSocketLayer.h"
 #endif
-#ifndef MPEXT_NO_SPEED_LIM
+#ifndef MPEXT_NO_SPEED_LIM_RULES
 #include "SpeedLimit.h"
 #endif
 #ifndef MPEXT
@@ -277,14 +277,18 @@ int CControlSocket::OnLayerCallback(std::list<t_callbackMsg>& callbacks)
 	return 1;
 }
 
-#ifndef MPEXT_NO_SPEED_LIM
+#ifndef MPEXT_NO_SPEED_LIM_RULES
 _int64 CControlSocket::GetSpeedLimit(CTime &time, int valType, int valValue, SPEEDLIMITSLIST &list)
+#else
+_int64 CControlSocket::GetSpeedLimit(CTime &time, int valType, int valValue)
+#endif
 {
 	int type = COptions::GetOptionVal(valType);
 
 	if ( type == 1)
 		return ( _int64)COptions::GetOptionVal(valValue) * 1024;
 
+#ifndef MPEXT_NO_SPEED_LIM_RULES
 	if ( type == 2)
 	{
 		CSingleLock lock(&COptions::m_Sync, TRUE);
@@ -294,21 +298,26 @@ _int64 CControlSocket::GetSpeedLimit(CTime &time, int valType, int valValue, SPE
 				return list[ i]->m_Speed * 1024;
 		}
 	}
+#endif
 
 	return ( _int64)1000000000000;	//I hope that when there will be something with 1000GB/s then I'll change it :)
 }
-#endif
 
 _int64 CControlSocket::GetSpeedLimit(enum transferDirection direction, CTime &time)
 {
-#ifndef MPEXT_NO_SPEED_LIM
 	if (direction == download)
+#ifndef MPEXT_NO_SPEED_LIM_RULES
 		return GetSpeedLimit(time, OPTION_SPEEDLIMIT_DOWNLOAD_TYPE, OPTION_SPEEDLIMIT_DOWNLOAD_VALUE, COptions::m_DownloadSpeedLimits);
+#else
+		return GetSpeedLimit(time, OPTION_SPEEDLIMIT_DOWNLOAD_TYPE, OPTION_SPEEDLIMIT_DOWNLOAD_VALUE);
+#endif
 	else
+#ifndef MPEXT_NO_SPEED_LIM_RULES
 		return GetSpeedLimit( time, OPTION_SPEEDLIMIT_UPLOAD_TYPE, OPTION_SPEEDLIMIT_UPLOAD_VALUE, COptions::m_UploadSpeedLimits);
 #else
-	return ( _int64)1000000000000;
+		return GetSpeedLimit( time, OPTION_SPEEDLIMIT_UPLOAD_TYPE, OPTION_SPEEDLIMIT_UPLOAD_VALUE);
 #endif
+	return ( _int64)1000000000000;
 }
 
 _int64 CControlSocket::GetAbleToUDSize( bool &beenWaiting, CTime &curTime, _int64 &curLimit, std::list<CControlSocket::t_ActiveList>::iterator &iter, enum transferDirection direction, int nBufSize)

+ 3 - 1
filezilla/ControlSocket.h

@@ -142,8 +142,10 @@ protected:
 	static _int64 m_CurrentTransferLimit[2];
 	static CCriticalSection m_SpeedLimitSync;
 	_int64 GetAbleToUDSize( bool &beenWaiting, CTime &curTime, _int64 &curLimit, std::list<t_ActiveList>::iterator &iter, enum transferDirection direction, int nBufSize);
-#ifndef MPEXT_NO_SPEED_LIM
+#ifndef MPEXT_NO_SPEED_LIM_RULES
 	_int64 GetSpeedLimit(CTime &time, int valType, int valValue, SPEEDLIMITSLIST &list);
+#else
+	_int64 GetSpeedLimit(CTime &time, int valType, int valValue);
 #endif
 	//End Speed limit
 	

+ 1 - 0
filezilla/Crypt.cpp

@@ -79,3 +79,4 @@ CString CCrypt::decrypt(CString str)
 	}
 	return ret;
 }
+

+ 1 - 1
filezilla/FileZillaOpt.h

@@ -109,11 +109,11 @@
 #ifndef MPEXT
 #define OPTION_FILEEXISTSACTION 85
 #endif
-#ifndef MPEXT_NO_SPEED_LIM
 #define OPTION_SPEEDLIMIT_DOWNLOAD_TYPE 86
 #define OPTION_SPEEDLIMIT_UPLOAD_TYPE 87
 #define OPTION_SPEEDLIMIT_DOWNLOAD_VALUE 88
 #define OPTION_SPEEDLIMIT_UPLOAD_VALUE 89
+#ifndef MPEXT_NO_SPEED_LIM_RULES
 #define OPTION_SPEEDLIMIT_DOWNLOAD_RULES 90
 #define OPTION_SPEEDLIMIT_UPLOAD_RULES 91
 #endif

+ 334 - 334
filezilla/MainThread.cpp

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

+ 2 - 2
filezilla/Options.h

@@ -2,14 +2,14 @@
 #ifndef OptionsH
 #define OptionsH
 //---------------------------------------------------------------------------
-#ifndef MPEXT_NO_SPEED_LIM
+#ifndef MPEXT_NO_SPEED_LIM_RULES
 #include <SpeedLimit.h>
 #endif
 //---------------------------------------------------------------------------
 class COptions
 {
 public:
-#ifndef MPEXT_NO_SPEED_LIM
+#ifndef MPEXT_NO_SPEED_LIM_RULES
   static CCriticalSection m_Sync; //  Moved to public section - needed for locking list
   static SPEEDLIMITSLIST m_DownloadSpeedLimits;
   static SPEEDLIMITSLIST m_UploadSpeedLimits;

+ 29 - 5
filezilla/stdafx.h

@@ -12,7 +12,7 @@
 #define MPEXT_NO_SFTP
 #define MPEXT_NO_IDENT
 #define MPEXT_NO_CACHE
-#define MPEXT_NO_SPEED_LIM
+#define MPEXT_NO_SPEED_LIM_RULES
 #define _AFX_NOFORCE_LIBS
 //---------------------------------------------------------------------------
 #define GetOption(OPTION) GetInstanceOption(this->m_pApiLogParent, OPTION)
@@ -80,12 +80,36 @@ typedef struct
 //---------------------------------------------------------------------------
 #undef CFile
 //---------------------------------------------------------------------------
-// MFC allocates CObject (ancestor of CFile) with new, but deallocates with free,
-// what codeguard dislikes, this is fix, not sure if it is necessary for
-// release version, but probably causes no harm
-class CFileFix: public CFile
+class CFileFix : public CFile
 {
 public:
+  // MFC CFile::Read does not include file name into error message
+  UINT Read(void * lpBuf, UINT nCount)
+  {
+    ASSERT_VALID(this);
+    ASSERT(m_hFile != (UINT)hFileNull);
+
+    if (nCount == 0)
+    {
+      return 0;   // avoid Win32 "null-read"
+    }
+
+    ASSERT(lpBuf != NULL);
+    ASSERT(AfxIsValidAddress(lpBuf, nCount));
+
+    DWORD dwRead;
+    if (!::ReadFile((HANDLE)m_hFile, lpBuf, nCount, &dwRead, NULL))
+    {
+      // The only change from MFC CFile::Read is m_strFileName
+      CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
+    }
+
+    return (UINT)dwRead;
+  }
+
+  // MFC allocates CObject (ancestor of CFile) with new, but deallocates with free,
+  // what codeguard dislikes, this is fix, not sure if it is necessary for
+  // release version, but probably causes no harm
   void PASCAL operator delete(void* p)
   {
     delete p;

+ 27 - 16
forms/About.cpp

@@ -15,12 +15,12 @@
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------------
 void __fastcall DoAboutDialog(TConfiguration * Configuration,
-  bool AllowLicence, TRegistration * Registration)
+  bool AllowLicense, TRegistration * Registration)
 {
   TAboutDialog * AboutDialog = NULL;
   try
   {
-    AboutDialog = new TAboutDialog(Application, Configuration, AllowLicence,
+    AboutDialog = new TAboutDialog(Application, Configuration, AllowLicense,
       Registration);
     AboutDialog->ShowModal();
   }
@@ -31,7 +31,7 @@ void __fastcall DoAboutDialog(TConfiguration * Configuration,
 }
 //---------------------------------------------------------------------------
 __fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
-  TConfiguration * Configuration, bool AllowLicence, TRegistration * Registration)
+  TConfiguration * Configuration, bool AllowLicense, TRegistration * Registration)
   : TForm(AOwner)
 {
   FConfiguration = Configuration;
@@ -39,7 +39,7 @@ __fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
   UseSystemSettings(this);
   LinkLabel(HomepageLabel, LoadStr(HOMEPAGE_URL));
   LinkLabel(ForumUrlLabel, LoadStr(FORUM_URL));
-  LinkLabel(PuttyLicenceLabel, "", FirstScrollingControlEnter);
+  LinkLabel(PuttyLicenseLabel, "", FirstScrollingControlEnter);
   LinkLabel(PuttyHomepageLabel, LoadStr(PUTTY_URL));
   LinkLabel(FileZillaHomepageLabel, LoadStr(FILEZILLA_URL));
   LinkLabel(Toolbar2000HomepageLabel);
@@ -67,19 +67,19 @@ __fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
     if (Registration->Registered)
     {
       AnsiString Text;
-      Text = FORMAT(LoadStrPart(ABOUT_REGISTRATION_LICENCES, 1),
-        (Registration->Licences >= 0 ? IntToStr(Registration->Licences) :
-          LoadStrPart(ABOUT_REGISTRATION_LICENCES, 2)));
+      Text = FORMAT(LoadStrPart(ABOUT_REGISTRATION_LICENSES, 1),
+        (Registration->Licenses >= 0 ? IntToStr(Registration->Licenses) :
+          LoadStrPart(ABOUT_REGISTRATION_LICENSES, 2)));
       if (!Registration->NeverExpires)
       {
         Text = FMTLOAD(ABOUT_REGISTRATION_EXPIRES,
           (Text, FormatDateTime("ddddd", Registration->Expiration)));
       }
-      RegistrationLicencesLabel->Caption = Text;
+      RegistrationLicensesLabel->Caption = Text;
       Text = FMTLOAD(ABOUT_REGISTRATION_PRODUCTID, (Registration->ProductId));
       if (Registration->EduLicense)
       {
-        Text = FMTLOAD(ABOUT_REGISTRATION_EDULICENCE, (Text));
+        Text = FMTLOAD(ABOUT_REGISTRATION_EDULICENSE, (Text));
       }
       RegistrationProductIdLabel->Caption = Text;
       RegistrationProductIdLabel->Font->Style =
@@ -87,8 +87,10 @@ __fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
     }
     else
     {
-      RegistrationLicencesLabel->Visible = false;
-      RegistrationProductIdLabel->Visible = false;
+      RegistrationLicensesLabel->Visible = false;
+      FRegistrationLink = Registration->RegistrationLink;
+      RegistrationProductIdLabel->Caption = LoadStr(ABOUT_REGISTRATION_LINK);
+      LinkLabel(RegistrationProductIdLabel, "");
     }
   }
 
@@ -131,7 +133,7 @@ __fastcall TAboutDialog::TAboutDialog(TComponent * AOwner,
   ThirdPartyBox->VertScrollBar->Range = ThirdPartyBox->VertScrollBar->Range - FileZillaHeight;
   #endif
 
-  LicenceButton->Visible = AllowLicence;
+  LicenseButton->Visible = AllowLicense;
   LoadData();
 }
 //---------------------------------------------------------------------------
@@ -147,14 +149,14 @@ void __fastcall TAboutDialog::LoadData()
   VersionLabel->Caption = Version;
 }
 //---------------------------------------------------------------------------
-void __fastcall TAboutDialog::DisplayLicence(TObject * Sender)
+void __fastcall TAboutDialog::DisplayLicense(TObject * Sender)
 {
-  DoLicenceDialog((TLicence)((TComponent*)Sender)->Tag);
+  DoLicenseDialog((TLicense)((TComponent*)Sender)->Tag);
 }
 //---------------------------------------------------------------------------
-void __fastcall TAboutDialog::LicenceButtonClick(TObject * /*Sender*/)
+void __fastcall TAboutDialog::LicenseButtonClick(TObject * /*Sender*/)
 {
-  DoProductLicence();
+  DoProductLicense();
 }
 //---------------------------------------------------------------------------
 void __fastcall TAboutDialog::HelpButtonClick(TObject * /*Sender*/)
@@ -173,3 +175,12 @@ void __fastcall TAboutDialog::LastScrollingControlEnter(TObject * /*Sender*/)
     ThirdPartyBox->VertScrollBar->Range - ThirdPartyBox->ClientHeight;
 }
 //---------------------------------------------------------------------------
+void __fastcall TAboutDialog::RegistrationProductIdLabelClick(
+  TObject * /*Sender*/)
+{
+  if (!FRegistrationLink.IsEmpty())
+  {
+    OpenBrowser(FRegistrationLink);
+  }
+}
+//---------------------------------------------------------------------------

+ 33 - 31
forms/About.dfm

@@ -6,7 +6,7 @@ object AboutDialog: TAboutDialog
   BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
   BorderStyle = bsDialog
   Caption = 'About application'
-  ClientHeight = 476
+  ClientHeight = 484
   ClientWidth = 388
   Color = clBtnFace
   Font.Charset = DEFAULT_CHARSET
@@ -15,10 +15,10 @@ object AboutDialog: TAboutDialog
   Font.Name = 'MS Sans Serif'
   Font.Style = []
   OldCreateOrder = True
-  Position = poOwnerFormCenter
+  Position = poMainFormCenter
   DesignSize = (
     388
-    476)
+    484)
   PixelsPerInch = 96
   TextHeight = 13
   object ApplicationLabel: TLabel
@@ -161,7 +161,7 @@ object AboutDialog: TAboutDialog
   end
   object Label3: TLabel
     Left = 72
-    Top = 295
+    Top = 303
     Width = 87
     Height = 13
     Anchors = [akLeft, akBottom]
@@ -170,10 +170,10 @@ object AboutDialog: TAboutDialog
   object RegistrationLabel: TLabel
     Left = 72
     Top = 188
-    Width = 127
+    Width = 126
     Height = 13
     Anchors = [akLeft, akBottom]
-    Caption = 'This product is licenced to:'
+    Caption = 'This product is licensed to:'
   end
   object HomepageLabel: TStaticText
     Left = 72
@@ -204,7 +204,7 @@ object AboutDialog: TAboutDialog
   end
   object ThirdPartyBox: TScrollBox
     Left = 72
-    Top = 313
+    Top = 321
     Width = 306
     Height = 121
     HorzScrollBar.Range = 289
@@ -214,7 +214,7 @@ object AboutDialog: TAboutDialog
     VertScrollBar.Tracking = True
     Anchors = [akLeft, akRight, akBottom]
     AutoScroll = False
-    TabOrder = 5
+    TabOrder = 6
     DesignSize = (
       285
       117)
@@ -227,7 +227,7 @@ object AboutDialog: TAboutDialog
       AutoSize = False
       Caption = 
         'License agreements of all following programs (libraries) are par' +
-        't of application licence agreement.'
+        't of application license agreement.'
       WordWrap = True
     end
     object Label4: TLabel
@@ -308,16 +308,16 @@ object AboutDialog: TAboutDialog
       Height = 13
       Caption = 'Copyright '#169' xxx Tim Kosse'
     end
-    object PuttyLicenceLabel: TStaticText
+    object PuttyLicenseLabel: TStaticText
       Tag = 1
       Left = 8
       Top = 80
-      Width = 75
+      Width = 74
       Height = 17
-      Caption = 'Display licence'
+      Caption = 'Display license'
       TabOrder = 0
       TabStop = True
-      OnClick = DisplayLicence
+      OnClick = DisplayLicense
     end
     object PuttyHomepageLabel: TStaticText
       Left = 8
@@ -358,7 +358,7 @@ object AboutDialog: TAboutDialog
   end
   object OKButton: TButton
     Left = 221
-    Top = 443
+    Top = 451
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
@@ -368,19 +368,19 @@ object AboutDialog: TAboutDialog
     ModalResult = 1
     TabOrder = 0
   end
-  object LicenceButton: TButton
+  object LicenseButton: TButton
     Left = 72
-    Top = 443
+    Top = 451
     Width = 75
     Height = 25
     Anchors = [akLeft, akBottom]
-    Caption = '&Licence...'
-    TabOrder = 6
-    OnClick = LicenceButtonClick
+    Caption = '&License...'
+    TabOrder = 7
+    OnClick = LicenseButtonClick
   end
   object HelpButton: TButton
     Left = 303
-    Top = 443
+    Top = 451
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
@@ -392,15 +392,15 @@ object AboutDialog: TAboutDialog
     Left = 72
     Top = 206
     Width = 306
-    Height = 81
+    Height = 89
     HorzScrollBar.Visible = False
     VertScrollBar.Smooth = True
     VertScrollBar.Tracking = True
     Anchors = [akLeft, akRight, akBottom]
-    TabOrder = 7
+    TabOrder = 5
     DesignSize = (
       302
-      77)
+      85)
     object RegistrationSubjectLabel: TLabel
       Left = 8
       Top = 8
@@ -411,19 +411,21 @@ object AboutDialog: TAboutDialog
       Caption = 'Someone'#13#10'Somewhere, some city'
       WordWrap = True
     end
-    object RegistrationLicencesLabel: TLabel
+    object RegistrationLicensesLabel: TLabel
       Left = 8
-      Top = 39
-      Width = 108
+      Top = 43
+      Width = 107
       Height = 13
-      Caption = 'Number of Licences: X'
+      Caption = 'Number of Licenses: X'
     end
-    object RegistrationProductIdLabel: TLabel
+    object RegistrationProductIdLabel: TStaticText
       Left = 8
-      Top = 57
-      Width = 128
-      Height = 13
+      Top = 65
+      Width = 132
+      Height = 17
       Caption = 'Product ID: xxxx-xxxx-xxxxx'
+      TabOrder = 0
+      OnClick = RegistrationProductIdLabelClick
     end
   end
 end

+ 9 - 7
forms/About.h

@@ -32,8 +32,8 @@ __published:
   TLabel *Label8;
   TLabel *Label10;
   TButton *OKButton;
-  TButton *LicenceButton;
-  TStaticText *PuttyLicenceLabel;
+  TButton *LicenseButton;
+  TStaticText *PuttyLicenseLabel;
   TLabel *TranslatorLabel;
   TLabel *Label1;
   TLabel *Label2;
@@ -47,23 +47,25 @@ __published:
   TLabel *Label3;
   TLabel *RegistrationLabel;
   TScrollBox *RegistrationBox;
-  TLabel *RegistrationLicencesLabel;
-  TLabel *RegistrationProductIdLabel;
+  TLabel *RegistrationLicensesLabel;
+  TStaticText *RegistrationProductIdLabel;
   TLabel *RegistrationSubjectLabel;
   TLabel *Label4;
   TLabel *FileZillaVersionLabel;
   TLabel *FileZillaCopyrightLabel;
   TStaticText *FileZillaHomepageLabel;
-  void __fastcall DisplayLicence(TObject *Sender);
-  void __fastcall LicenceButtonClick(TObject *Sender);
+  void __fastcall DisplayLicense(TObject *Sender);
+  void __fastcall LicenseButtonClick(TObject *Sender);
   void __fastcall HelpButtonClick(TObject *Sender);
+  void __fastcall RegistrationProductIdLabelClick(TObject *Sender);
 private:
   TConfiguration * FConfiguration;
+  AnsiString FRegistrationLink;
   void __fastcall FirstScrollingControlEnter(TObject * Sender);
   void __fastcall LastScrollingControlEnter(TObject * Sender);
 public:
   virtual __fastcall TAboutDialog(TComponent * AOwner,
-    TConfiguration * Configuration, bool AllowLicence, TRegistration * Registration);
+    TConfiguration * Configuration, bool AllowLicense, TRegistration * Registration);
   void __fastcall LoadData();
 };
 //----------------------------------------------------------------------------

+ 162 - 94
forms/Authenticate.cpp

@@ -9,18 +9,34 @@
 #include <VCLCommon.h>
 #include <TextsWin.h>
 #include <Terminal.h>
+#include <CoreMain.h>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma link "PasswordEdit"
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------------
-__fastcall TAuthenticateForm::TAuthenticateForm(TComponent * Owner,
-  AnsiString SessionName)
-  : TForm(Owner), FSessionName(SessionName), FHideTypingOnServerPrompt(true)
+__fastcall TAuthenticateForm::TAuthenticateForm(TComponent * Owner)
+  : TForm(Owner), FSessionData(NULL)
 {
+}
+//---------------------------------------------------------------------------
+void __fastcall TAuthenticateForm::Init(TSessionData * SessionData)
+{
+  FSessionData = SessionData;
+
   UseSystemSettings(this);
   FShowAsModalStorage = NULL;
   FFocusControl = NULL;
+
+  FPromptParent = InstructionsLabel->Parent;
+  FPromptLeft = InstructionsLabel->Left;
+  FPromptTop = InstructionsLabel->Top;
+  FPromptRight = FPromptParent->ClientWidth - InstructionsLabel->Width - FPromptLeft;
+  FPromptEditGap = PromptEdit1->Top - PromptLabel1->Top - PromptLabel1->Height;
+  FPromptsGap = PromptLabel2->Top - PromptEdit1->Top - PromptEdit1->Height;
+
+  ClientHeight = 270;
+
   ClearLog();
 }
 //---------------------------------------------------------------------------
@@ -41,8 +57,8 @@ void __fastcall TAuthenticateForm::HideAsModal()
 //---------------------------------------------------------------------------
 void __fastcall TAuthenticateForm::WMNCCreate(TWMNCCreate & Message)
 {
-  // bypass TForm::WMNCCreate no prevent disabling "resize"
-  // (wish is done for bsDialog, see comments in CreateParams)
+  // bypass TForm::WMNCCreate to prevent disabling "resize"
+  // (which is done for bsDialog, see comments in CreateParams)
   DefaultHandler(&Message);
 }
 //---------------------------------------------------------------------------
@@ -76,7 +92,7 @@ void __fastcall TAuthenticateForm::FormShow(TObject * /*Sender*/)
 
   if (FFocusControl != NULL)
   {
-    FFocusControl->SetFocus();
+    ActiveControl = FFocusControl;
   }
 }
 //---------------------------------------------------------------------------
@@ -95,98 +111,153 @@ void __fastcall TAuthenticateForm::Log(const AnsiString Message)
   LogView->Repaint();
 }
 //---------------------------------------------------------------------------
-void __fastcall TAuthenticateForm::UpdateControls()
-{
-  PasswordEdit->Password = HideTypingCheck->Checked;
-}
-//---------------------------------------------------------------------------
 void __fastcall TAuthenticateForm::AdjustControls()
 {
-  if (PasswordLabel->Caption != FPasswordCaption)
-  {
-    int LabelWidth = PasswordLabel->Width;
-    int LabelHeight = PasswordLabel->Height;
-    PasswordLabel->AutoSize = false;
-    PasswordLabel->Caption = FPasswordCaption;
-    PasswordLabel->AutoSize = true;
-    PasswordLabel->Width = LabelWidth;
-
-    int HeightDiff = (PasswordLabel->Height - LabelHeight);
-    PasswordEditPanel->Height = PasswordEditPanel->Height + HeightDiff;
-    PasswordPanel->Height = PasswordPanel->Height + HeightDiff;
-  }
-
   if (FStatus.IsEmpty())
   {
-    Caption = FSessionName;
+    Caption = FSessionData->SessionName;
   }
   else
   {
-    Caption = FORMAT("%s - %s", (FStatus, FSessionName));
+    Caption = FORMAT("%s - %s", (FStatus, FSessionData->SessionName));
   }
+}
+//---------------------------------------------------------------------------
+TLabel * __fastcall TAuthenticateForm::GenerateLabel(int Current, AnsiString Caption)
+{
+  TLabel * Result = new TLabel(this);
+  Result->Parent = FPromptParent;
+
+  Result->Anchors = TAnchors() << akLeft << akTop << akRight;
+  Result->WordWrap = true;
+  Result->AutoSize = false;
+
+  Result->Top = Current;
+  Result->Left = FPromptLeft;
+  Result->Caption = Caption;
+  int Width = FPromptParent->ClientWidth - FPromptLeft - FPromptRight;
+  Result->Width = Width;
+  Result->AutoSize = true;
 
-  UpdateControls();
+  return Result;
 }
 //---------------------------------------------------------------------------
-bool __fastcall TAuthenticateForm::PromptUser(AnsiString Caption,
-  TPromptKind Kind, AnsiString & Response, bool ForceLog)
+TCustomEdit * __fastcall TAuthenticateForm::GenerateEdit(int Current, bool Echo, int MaxLen)
 {
-  bool ShowServerPanel;
-  AnsiString Title;
+  TCustomEdit * Result = (Echo ? static_cast<TCustomEdit *>(new TEdit(this)) :
+    static_cast<TCustomEdit *>(new TPasswordEdit(this)));
+  Result->Parent = FPromptParent;
 
-  switch (Kind)
-  {
-    case pkPassword:
-      Title = LoadStr(PASSWORD_TITLE);
-      HideTypingCheck->Checked = true;
-      ShowServerPanel = false;
-      break;
-
-    case pkPassphrase:
-      Title = LoadStr(PASSPHRASE_TITLE);
-      HideTypingCheck->Checked = true;
-      ShowServerPanel = false;
-      break;
-
-    case pkServerPrompt:
-      Title = LoadStr(SERVER_PASSWORD_TITLE);
-      ShowServerPanel = true;
-      HideTypingCheck->Checked = FHideTypingOnServerPrompt;
-      break;
-
-    case pkPrompt:
-      Title = CutToChar(Caption, '|', true);
-      if (Caption.IsEmpty())
-      {
-        Caption = Title;
-      }
-      HideTypingCheck->Checked = false;
-      ShowServerPanel = false;
-      break;
+  Result->Anchors = TAnchors() << akLeft << akTop << akRight;
+  Result->Top = Current;
+  Result->Left = FPromptLeft;
+  Result->Width = FPromptParent->ClientWidth - FPromptLeft - FPromptRight;
+  ((TEdit *)Result)->MaxLength = MaxLen;
 
-    default:
-      assert(false);
+  return Result;
+}
+//---------------------------------------------------------------------------
+TList * __fastcall TAuthenticateForm::GeneratePrompt(AnsiString Instructions,
+  TStrings * Prompts, TStrings * Results)
+{
+  while (FPromptParent->ControlCount > 0)
+  {
+    delete FPromptParent->Controls[0];
   }
+  TList * Result = new TList;
 
-  FPasswordCaption = Caption;
+  int Current = FPromptTop;
 
-  if (ShowServerPanel != ServerPromptPanel->Visible)
+  if (!Instructions.IsEmpty())
   {
-    ServerPromptPanel->Visible = ShowServerPanel;
-    PasswordPanel->Height += (ShowServerPanel ? 1 : -1) * ServerPromptPanel->Height;
+    TLabel * Label = GenerateLabel(Current, Instructions);
+    Current += Label->Height + FPromptsGap;
   }
 
-  PasswordEdit->Text = Response;
-  bool Result = Execute(Title, PasswordPanel, PasswordEdit,
-    PasswordOKButton, PasswordCancelButton, true, false, ForceLog);
-  if (Result)
+  assert(Prompts->Count == Results->Count);
+  for (int Index = 0; Index < Prompts->Count; Index++)
   {
-    Response = PasswordEdit->Text;
+    if (Index > 0)
+    {
+      Current += FPromptEditGap;
+    }
+
+    TLabel * Label = GenerateLabel(Current, Prompts->Strings[0]);
+    Current += Label->Height + FPromptEditGap;
+
+    TCustomEdit * Edit = GenerateEdit(Current, bool(Prompts->Objects[Index]),
+      int(Results->Objects[Index]));
+    Result->Add(Edit);
+    Label->FocusControl = Edit;
+    Current += Edit->Height;
   }
 
-  if (Kind == pkServerPrompt)
+  FPromptParent->ClientHeight = Current;
+
+  return Result;
+}
+//---------------------------------------------------------------------------
+bool __fastcall TAuthenticateForm::PromptUser(TPromptKind Kind, AnsiString Name,
+  AnsiString Instructions, TStrings * Prompts, TStrings * Results, bool ForceLog,
+  bool StoredCredentialsTried)
+{
+
+  bool Result;
+  TList * Edits = GeneratePrompt(Instructions, Prompts, Results);
+
+  try
+  {
+    bool ShowSavePasswordPanel = false;
+    TSessionData * Data = NULL;
+    if (((Kind == pkPassword) || (Kind == pkTIS) || (Kind == pkCryptoCard) ||
+         (Kind == pkKeybInteractive)) &&
+        (Prompts->Count == 1) && !bool(Prompts->Objects[0]) &&
+        !FSessionData->Name.IsEmpty() &&
+        StoredCredentialsTried)
+    {
+      Data = dynamic_cast<TSessionData *>(StoredSessions->FindByName(FSessionData->Name));
+      ShowSavePasswordPanel = (Data != NULL) && !Data->Password.IsEmpty();
+    }
+
+    SavePasswordCheck->Checked = false;
+    SavePasswordPanel->Visible = ShowSavePasswordPanel;
+
+    if (PasswordPanel->AutoSize)
+    {
+      PasswordPanel->AutoSize = false;
+      PasswordPanel->AutoSize = true;
+    }
+    PasswordPanel->Realign();
+
+    assert(Results->Count == Edits->Count);
+    for (int Index = 0; Index < Edits->Count; Index++)
+    {
+      TCustomEdit * Edit = reinterpret_cast<TCustomEdit *>(Edits->Items[Index]);
+      Edit->Text = Results->Strings[Index];
+    }
+
+    Result = Execute(Name, PasswordPanel, reinterpret_cast<TWinControl *>(Edits->Items[0]),
+      PasswordOKButton, PasswordCancelButton, true, false, ForceLog);
+    if (Result)
+    {
+      for (int Index = 0; Index < Edits->Count; Index++)
+      {
+        TCustomEdit * Edit = reinterpret_cast<TCustomEdit *>(Edits->Items[Index]);
+        Results->Strings[Index] = Edit->Text;
+      }
+
+      if (SavePasswordCheck->Checked)
+      {
+        assert(Data != NULL);
+        Data->Password = Results->Strings[0];
+        // modified only, explicit
+        StoredSessions->Save(false, true);
+      }
+    }
+  }
+  __finally
   {
-    FHideTypingOnServerPrompt = HideTypingCheck->Checked;
+    delete Edits;
   }
 
   return Result;
@@ -206,11 +277,11 @@ void __fastcall TAuthenticateForm::Banner(const AnsiString & Banner,
   }
 }
 //---------------------------------------------------------------------------
-bool __fastcall TAuthenticateForm::Execute(AnsiString Status, TControl * Control,
+bool __fastcall TAuthenticateForm::Execute(AnsiString Status, TPanel * Panel,
   TWinControl * FocusControl, TButton * DefaultButton, TButton * CancelButton,
   bool FixHeight, bool Zoom, bool ForceLog)
 {
-  TAlign Align = Control->Align;
+  TAlign Align = Panel->Align;
   try
   {
     assert(FStatus.IsEmpty());
@@ -220,12 +291,19 @@ bool __fastcall TAuthenticateForm::Execute(AnsiString Status, TControl * Control
 
     if (Zoom)
     {
-      Control->Align = alClient;
+      Panel->Align = alClient;
     }
 
     if (ForceLog || Visible)
     {
-      Control->Show();
+      if (ClientHeight < Panel->Height)
+      {
+        ClientHeight = Panel->Height;
+      }
+      // Panel being hidden gets not realigned automatically, even if it
+      // has Align property set
+      Panel->Top = ClientHeight - Panel->Height;
+      Panel->Show();
       TCursor PrevCursor = Screen->Cursor;
       try
       {
@@ -253,7 +331,7 @@ bool __fastcall TAuthenticateForm::Execute(AnsiString Status, TControl * Control
           ShowAsModal();
         }
 
-        FocusControl->SetFocus();
+        ActiveControl = FocusControl;
         ModalResult = mrNone;
         AdjustControls();
         do
@@ -264,7 +342,7 @@ bool __fastcall TAuthenticateForm::Execute(AnsiString Status, TControl * Control
       }
       __finally
       {
-        Control->Hide();
+        Panel->Hide();
         Screen->Cursor = PrevCursor;
         if (Zoom)
         {
@@ -281,14 +359,14 @@ bool __fastcall TAuthenticateForm::Execute(AnsiString Status, TControl * Control
       try
       {
         Constraints->MinHeight = 0;
-        ClientHeight = Control->Height;
+        ClientHeight = Panel->Height;
         if (FixHeight)
         {
           Constraints->MinHeight = Height;
           Constraints->MaxHeight = Height;
         }
         LogView->Hide();
-        Control->Show();
+        Panel->Show();
         FFocusControl = FocusControl;
 
         ShowModal();
@@ -299,14 +377,14 @@ bool __fastcall TAuthenticateForm::Execute(AnsiString Status, TControl * Control
         ClientHeight = PrevHeight;
         Constraints->MinHeight = PrevMinHeight;
         Constraints->MaxHeight = PrevMaxHeight;
-        Control->Hide();
+        Panel->Hide();
         LogView->Show();
       }
     }
   }
   __finally
   {
-    Control->Align = Align;
+    Panel->Align = Align;
     DefaultButton->Default = false;
     CancelButton->Cancel = false;
     FStatus = "";
@@ -316,18 +394,8 @@ bool __fastcall TAuthenticateForm::Execute(AnsiString Status, TControl * Control
   return (ModalResult != mrCancel);
 }
 //---------------------------------------------------------------------------
-void __fastcall TAuthenticateForm::FormResize(TObject * /*Sender*/)
-{
-  AdjustControls();
-}
-//---------------------------------------------------------------------------
 void __fastcall TAuthenticateForm::HelpButtonClick(TObject * /*Sender*/)
 {
   FormHelp(this);
 }
 //---------------------------------------------------------------------------
-void __fastcall TAuthenticateForm::HideTypingCheckClick(TObject * /*Sender*/)
-{
-  UpdateControls();
-}
-//---------------------------------------------------------------------------

+ 94 - 67
forms/Authenticate.dfm

@@ -6,7 +6,7 @@ object AuthenticateForm: TAuthenticateForm
   BorderIcons = [biSystemMenu]
   BorderStyle = bsDialog
   Caption = 'AuthenticateForm'
-  ClientHeight = 270
+  ClientHeight = 316
   ClientWidth = 375
   Color = clBtnFace
   Constraints.MinHeight = 200
@@ -18,7 +18,6 @@ object AuthenticateForm: TAuthenticateForm
   Font.Style = []
   OldCreateOrder = False
   Position = poMainFormCenter
-  OnResize = FormResize
   OnShow = FormShow
   PixelsPerInch = 96
   TextHeight = 13
@@ -26,7 +25,7 @@ object AuthenticateForm: TAuthenticateForm
     Left = 0
     Top = 0
     Width = 375
-    Height = 35
+    Height = 26
     Align = alClient
     Columns = <
       item
@@ -45,117 +44,145 @@ object AuthenticateForm: TAuthenticateForm
   end
   object PasswordPanel: TPanel
     Left = 0
-    Top = 35
+    Top = 26
     Width = 375
-    Height = 153
+    Height = 208
     Align = alBottom
+    AutoSize = True
     BevelOuter = bvNone
     TabOrder = 1
     Visible = False
-    DesignSize = (
-      375
-      153)
-    object PasswordEditPanel: TPanel
+    object PromptEditPanel: TPanel
       Left = 0
       Top = 0
       Width = 375
-      Height = 50
+      Height = 139
       Align = alTop
       BevelOuter = bvNone
       TabOrder = 0
       DesignSize = (
         375
-        50)
-      object PasswordLabel: TLabel
+        139)
+      object InstructionsLabel: TLabel
         Left = 8
         Top = 8
         Width = 360
+        Height = 39
+        Anchors = [akLeft, akTop, akRight]
+        AutoSize = False
+        Caption = 
+          'Instructions for authentication. Please fill in your credentials' +
+          ' carefully. Enter all required information, including your sessi' +
+          'on username and session password.X'
+        FocusControl = PromptEdit1
+        WordWrap = True
+      end
+      object PromptLabel1: TLabel
+        Left = 8
+        Top = 56
+        Width = 360
+        Height = 13
+        Anchors = [akLeft, akTop, akRight]
+        AutoSize = False
+        Caption = '&UsernameX:'
+        FocusControl = PromptEdit1
+        WordWrap = True
+      end
+      object PromptLabel2: TLabel
+        Left = 8
+        Top = 101
+        Width = 360
         Height = 13
         Anchors = [akLeft, akTop, akRight]
         AutoSize = False
         Caption = '&PasswordX:'
-        FocusControl = PasswordEdit
+        FocusControl = PromptEdit2
         WordWrap = True
       end
-      object PasswordEdit: TPasswordEdit
+      object PromptEdit1: TPasswordEdit
         Left = 8
-        Top = 24
+        Top = 73
         Width = 361
         Height = 21
-        Anchors = [akLeft, akRight, akBottom]
+        Anchors = [akLeft, akTop, akRight]
         MaxLength = 250
         TabOrder = 0
       end
+      object PromptEdit2: TPasswordEdit
+        Left = 8
+        Top = 118
+        Width = 361
+        Height = 21
+        Anchors = [akLeft, akTop, akRight]
+        MaxLength = 250
+        TabOrder = 1
+      end
     end
-    object ServerPromptPanel: TPanel
+    object SavePasswordPanel: TPanel
       Left = 0
-      Top = 50
+      Top = 139
       Width = 375
-      Height = 69
+      Height = 25
       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
+      object SavePasswordCheck: TCheckBox
         Left = 14
-        Top = 2
+        Top = 6
         Width = 275
         Height = 17
-        Caption = 'Hide &typing'
+        Caption = '&Change stored password to this one'
         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
+    object ButtonsPanel: TPanel
+      Left = 0
+      Top = 164
+      Width = 375
+      Height = 44
+      Align = alTop
+      BevelOuter = bvNone
       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
+      DesignSize = (
+        375
+        44)
+      object PasswordOKButton: TButton
+        Left = 118
+        Top = 8
+        Width = 75
+        Height = 25
+        Anchors = [akTop, akRight]
+        Caption = 'OK'
+        ModalResult = 1
+        TabOrder = 0
+      end
+      object PasswordCancelButton: TButton
+        Left = 206
+        Top = 8
+        Width = 75
+        Height = 25
+        Anchors = [akTop, akRight]
+        Caption = 'Cancel'
+        ModalResult = 2
+        TabOrder = 1
+      end
+      object PasswordHelpButton: TButton
+        Left = 294
+        Top = 8
+        Width = 75
+        Height = 25
+        Anchors = [akTop, akRight]
+        Caption = '&Help'
+        TabOrder = 2
+        OnClick = HelpButtonClick
+      end
     end
   end
   object BannerPanel: TPanel
     Left = 0
-    Top = 188
+    Top = 234
     Width = 375
     Height = 82
     Align = alBottom

+ 28 - 19
forms/Authenticate.h

@@ -16,55 +16,64 @@ class TAuthenticateForm : public TForm
 __published:
   TListView *LogView;
   TPanel *PasswordPanel;
-  TPanel *PasswordEditPanel;
-  TLabel *PasswordLabel;
-  TPasswordEdit *PasswordEdit;
-  TPanel *ServerPromptPanel;
-  TLabel *ServerPromptLabel;
-  TCheckBox *HideTypingCheck;
-  TButton *PasswordOKButton;
-  TButton *PasswordCancelButton;
-  TButton *PasswordHelpButton;
+  TPanel *PromptEditPanel;
+  TLabel *PromptLabel1;
+  TPasswordEdit *PromptEdit1;
   TPanel *BannerPanel;
   TMemo *BannerMemo;
   TCheckBox *NeverShowAgainCheck;
   TButton *BannerCloseButton;
   TButton *BannerHelpButton;
+  TPanel *SavePasswordPanel;
+  TCheckBox *SavePasswordCheck;
+  TPanel *ButtonsPanel;
+  TButton *PasswordOKButton;
+  TButton *PasswordCancelButton;
+  TButton *PasswordHelpButton;
+  TLabel *InstructionsLabel;
+  TLabel *PromptLabel2;
+  TPasswordEdit *PromptEdit2;
   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);
+  __fastcall TAuthenticateForm(TComponent * Owner);
   virtual __fastcall ~TAuthenticateForm();
 
+  void __fastcall Init(TSessionData * SessionData);
   void __fastcall ShowAsModal();
   void __fastcall HideAsModal();
   void __fastcall Log(const AnsiString Message);
-  bool __fastcall PromptUser(AnsiString Caption,
-    TPromptKind Kind, AnsiString &Response, bool ForceLog);
+  bool __fastcall PromptUser(TPromptKind Kind, AnsiString Name, AnsiString Instructions,
+    TStrings * Prompts, TStrings * Results, bool ForceLog, bool StoredCredentialsTried);
   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,
+  bool __fastcall Execute(AnsiString Status, TPanel * Panel,
     TWinControl * FocusControl, TButton * DefaultButton, TButton * CancelButton,
     bool FixHeight, bool Zoom, bool ForceLog);
   virtual void __fastcall CreateParams(TCreateParams & Params);
   virtual void __fastcall Dispatch(void * AMessage);
   void __fastcall WMNCCreate(TWMNCCreate & Message);
+  TLabel * __fastcall GenerateLabel(int Current, AnsiString Caption);
+  TCustomEdit * __fastcall GenerateEdit(int Current, bool Echo, int MaxLen);
+  TList * __fastcall GeneratePrompt(AnsiString Instructions, TStrings * Prompts,
+    TStrings * Results);
 
 private:
   void * FShowAsModalStorage;
   TWinControl * FFocusControl;
-  AnsiString FSessionName;
+  TSessionData * FSessionData;
   AnsiString FStatus;
-  AnsiString FPasswordCaption;
-  bool FHideTypingOnServerPrompt;
+  TWinControl * FPromptParent;
+  int FPromptLeft;
+  int FPromptTop;
+  int FPromptRight;
+  int FPromptEditGap;
+  int FPromptsGap;
 };
 //---------------------------------------------------------------------------
 #endif

+ 1 - 1
forms/Cleanup.dfm

@@ -11,7 +11,7 @@ object CleanupDialog: TCleanupDialog
   Color = clBtnFace
   ParentFont = True
   OldCreateOrder = True
-  Position = poOwnerFormCenter
+  Position = poMainFormCenter
   OnShow = FormShow
   DesignSize = (
     489

+ 1 - 82
forms/ComboInput.cpp

@@ -5,11 +5,8 @@
 #include <Dialogs.hpp>
 //---------------------------------------------------------------------
 #include <Common.h>
-#include <TextsWin.h>
-#include <HelpWin.h>
 #include <WinInterface.h>
 #include <VCLCommon.h>
-#include <CoreMain.h>
 
 #include "ComboInput.h"
 //---------------------------------------------------------------------
@@ -17,7 +14,7 @@
 //---------------------------------------------------------------------
 bool __fastcall DoComboInputDialog(
   const AnsiString Caption, const AnsiString Prompt,
-  AnsiString & Text, TStrings * Items, TInputValidateEvent OnInputValidate,
+  AnsiString & Text, TStrings * Items,
   bool AllowEmpty, const AnsiString HelpKeyword)
 {
   bool Result;
@@ -29,7 +26,6 @@ bool __fastcall DoComboInputDialog(
     ComboInputDialog->Text = Text;
     ComboInputDialog->Items = Items;
     ComboInputDialog->AllowEmpty = AllowEmpty;
-    ComboInputDialog->OnInputValidate = OnInputValidate;
     ComboInputDialog->HelpKeyword = HelpKeyword;
     Result = (ComboInputDialog->ShowModal() == mrOk);
     if (Result)
@@ -44,78 +40,10 @@ bool __fastcall DoComboInputDialog(
   return Result;
 }
 //---------------------------------------------------------------------
-void __fastcall SaveSessionInputValidate(TObject * Sender, const AnsiString & Text)
-{
-  TSessionData * Data =
-    reinterpret_cast<TSessionData *>(dynamic_cast<TForm *>(Sender)->Tag);
-  SessionNameValidate(Text, Data);
-}
-//---------------------------------------------------------------------
-AnsiString __fastcall DoSaveSessionDialog(const AnsiString DefaultName,
-  TSessionData * OriginalSession)
-{
-  AnsiString Result;
-  TComboInputDialog * SaveSessionDialog = NULL;
-  TStrings * Items = NULL;
-  try
-  {
-    Items = new TStringList();
-    for (int Index = 0; Index < StoredSessions->Count; Index++)
-    {
-      TSessionData * Data = StoredSessions->Sessions[Index];
-      if (!Data->Special)
-      {
-        Items->Add(Data->Name);
-      }
-    }
-
-    SaveSessionDialog = new TComboInputDialog(Application);
-    SaveSessionDialog->Items = Items;
-    SaveSessionDialog->Text = DefaultName;
-    SaveSessionDialog->Caption = LoadStr(SAVE_SESSION_CAPTION);
-    SaveSessionDialog->Prompt = LoadStr(SAVE_SESSION_PROMPT);
-    SaveSessionDialog->OnInputValidate = SaveSessionInputValidate;
-    SaveSessionDialog->Tag = reinterpret_cast<int>(OriginalSession);
-    SaveSessionDialog->HelpKeyword = HELP_SESSION_SAVE;
-    if (SaveSessionDialog->ShowModal() == mrOk)
-    {
-      Result = SaveSessionDialog->Text;
-    }
-  }
-  __finally
-  {
-    delete SaveSessionDialog;
-    delete Items;
-  }
-  return Result;
-}
-//---------------------------------------------------------------------------
-void __fastcall SessionNameValidate(const AnsiString & Text,
-  TSessionData * RenamingSession)
-{
-  TSessionData::ValidateName(Text);
-
-  assert(StoredSessions);
-  TSessionData * Data = (TSessionData *)StoredSessions->FindByName(Text);
-  if (Data && Data->Special)
-  {
-    MessageDialog(FMTLOAD(CANNOT_OVERWRITE_SPECIAL_SESSION, (Text)),
-      qtError, qaOK, HELP_NONE);
-    Abort();
-  }
-  else if (Data && (Data != RenamingSession) &&
-    MessageDialog(FMTLOAD(CONFIRM_OVERWRITE_SESSION, (Text)),
-      qtConfirmation, qaYes | qaNo, HELP_SESSION_SAVE_OVERWRITE) != qaYes)
-  {
-    Abort();
-  }
-}
-//---------------------------------------------------------------------
 __fastcall TComboInputDialog::TComboInputDialog(TComponent* AOwner)
   : TForm(AOwner)
 {
   FAllowEmpty = false;
-  FOnInputValidate = NULL;
   UseSystemSettings(this);
 }
 //---------------------------------------------------------------------
@@ -184,12 +112,3 @@ void __fastcall TComboInputDialog::HelpButtonClick(TObject * /*Sender*/)
   FormHelp(this);
 }
 //---------------------------------------------------------------------------
-void __fastcall TComboInputDialog::FormCloseQuery(TObject * /*Sender*/,
-  bool & /*CanClose*/)
-{
-  if ((ModalResult == mrOk) && (OnInputValidate != NULL))
-  {
-    OnInputValidate(this, Text);
-  }
-}
-//---------------------------------------------------------------------------

+ 4 - 5
forms/ComboInput.dfm

@@ -3,14 +3,13 @@ object ComboInputDialog: TComboInputDialog
   Top = 281
   BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
   BorderStyle = bsDialog
-  Caption = 'Save session as'
+  Caption = 'Save session asX'
   ClientHeight = 86
   ClientWidth = 326
   Color = clBtnFace
   ParentFont = True
   OldCreateOrder = True
-  Position = poOwnerFormCenter
-  OnCloseQuery = FormCloseQuery
+  Position = poMainFormCenter
   OnShow = FormShow
   DesignSize = (
     326
@@ -20,9 +19,9 @@ object ComboInputDialog: TComboInputDialog
   object InputLabel: TLabel
     Left = 8
     Top = 8
-    Width = 80
+    Width = 87
     Height = 13
-    Caption = '&Save session as:'
+    Caption = '&Save session as:X'
     FocusControl = InputCombo
   end
   object OKButton: TButton

+ 0 - 6
forms/ComboInput.h

@@ -26,25 +26,19 @@ __published:
   void __fastcall InputComboChange(TObject * Sender);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall HelpButtonClick(TObject *Sender);
-  void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
 
 public:
   virtual __fastcall TComboInputDialog(TComponent * AOwner);
 
-  void __fastcall StoredSessionsCloseQuery(TObject * Sender, bool &CanClose);
-
   __property TStrings * Items  = { read=GetItems, write=SetItems };
   __property AnsiString Prompt  = { read=GetPrompt, write=SetPrompt };
   __property AnsiString Text  = { read=GetText, write=SetText };
   __property bool AllowEmpty  = { read=FAllowEmpty, write=FAllowEmpty };
-  __property TInputValidateEvent OnInputValidate = { read=FOnInputValidate, write=FOnInputValidate };
 
 private:
   bool FAllowEmpty;
-  TInputValidateEvent FOnInputValidate;
 
   void __fastcall UpdateControls();
-  void __fastcall SetSessionList(TStoredSessionList * value);
   void __fastcall SetText(AnsiString value);
   AnsiString __fastcall GetText();
   void __fastcall SetPrompt(AnsiString value);

+ 2 - 2
forms/Console.dfm

@@ -29,9 +29,9 @@ object ConsoleDialog: TConsoleDialog
   object Label1: TLabel
     Left = 13
     Top = 13
-    Width = 74
+    Width = 77
     Height = 13
-    Caption = 'Enter &command'
+    Caption = 'Enter &command:'
     FocusControl = CommandEdit
   end
   object Label2: TLabel

+ 58 - 38
forms/Copy.cpp

@@ -73,6 +73,7 @@ __fastcall TCopyDialog::TCopyDialog(TComponent* Owner)
   Move = false;
   FOptions = 0;
   FOutputOptions = 0;
+  FCopyParamAttrs = 0;
   FPresetsMenu = new TPopupMenu(this);
 
   UseSystemSettings(this);
@@ -102,14 +103,6 @@ void __fastcall TCopyDialog::AdjustTransferControls()
         Label = FMTLOAD(REMOTE_COPY_FILES, (FFileList->Count));
       }
 
-      // hack to remove trailing colon used for "duplicate" prompt
-      if (!Label.IsEmpty() &&
-          (Label.ByteType(Label.Length()) == mbSingleByte) &&
-          (Label[Label.Length()] == ':'))
-      {
-        Label.SetLength(Label.Length() - 1);
-      }
-
       DirectoryLabel->Caption = Label;
     }
     else
@@ -158,9 +151,8 @@ void __fastcall TCopyDialog::AdjustTransferControls()
   bool RemoteTransfer = FLAGSET(FOutputOptions, cooRemoteTransfer);
   assert(FLAGSET(Options, coAllowRemoteTransfer) || !RemoteTransfer);
 
-  EnableControl(CopyParamsFrame, !RemoteTransfer);
   EnableControl(NewerOnlyCheck, FLAGCLEAR(Options, coDisableNewerOnly) && !RemoteTransfer);
-  EnableControl(PresetsButton, !RemoteTransfer);
+  EnableControl(TransferSettingsButton, !RemoteTransfer);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::AdjustControls()
@@ -173,8 +165,6 @@ void __fastcall TCopyDialog::AdjustControls()
   EnableControl(DirectoryLabel, DirectoryEdit->Enabled);
   EnableControl(LocalDirectoryBrowseButton, DirectoryEdit->Enabled);
   DirectoryLabel->FocusControl = DirectoryEdit;
-  CopyParamsFrame->Direction = !ToRemote ? pdToLocal : pdToRemote;
-  PresetsButton->Visible = FLAGCLEAR(Options, coDoNotUsePresets);
 
   AdjustTransferControls();
 
@@ -210,7 +200,7 @@ void __fastcall TCopyDialog::SetOutputOptions(int value)
 {
   if (OutputOptions != value)
   {
-    SaveSettingsCheck->Checked = FLAGSET(FOutputOptions, cooSaveSettings);
+    FSaveSettings = FLAGSET(FOutputOptions, cooSaveSettings);
     NeverShowAgainCheck->Checked = FLAGSET(FOutputOptions, cooDoNotShowAgain);
     FOutputOptions = (value & ~(cooDoNotShowAgain | cooSaveSettings));
   }
@@ -219,18 +209,18 @@ void __fastcall TCopyDialog::SetOutputOptions(int value)
 int __fastcall TCopyDialog::GetOutputOptions()
 {
   return FOutputOptions |
-    FLAGMASK(SaveSettingsCheck->Checked, cooSaveSettings) |
+    FLAGMASK(FSaveSettings, cooSaveSettings) |
     FLAGMASK(NeverShowAgainCheck->Checked, cooDoNotShowAgain);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::SetCopyParamAttrs(int value)
 {
-  CopyParamsFrame->CopyParamAttrs = value;
+  FCopyParamAttrs = value;
 }
 //---------------------------------------------------------------------------
 int __fastcall TCopyDialog::GetCopyParamAttrs()
 {
-  return CopyParamsFrame->CopyParamAttrs;
+  return FCopyParamAttrs;
 }
 //---------------------------------------------------------------------------
 THistoryComboBox * __fastcall TCopyDialog::GetDirectoryEdit()
@@ -251,17 +241,18 @@ AnsiString __fastcall TCopyDialog::GetFileMask()
 void __fastcall TCopyDialog::SetParams(const TGUICopyParamType & value)
 {
   FParams = value;
-  CopyParamsFrame->Params = value;
+  FCopyParams = value;
   DirectoryEdit->Text = Directory + FParams.FileMask;
   QueueCheck->Checked = FParams.Queue;
   QueueNoConfirmationCheck->Checked = FParams.QueueNoConfirmation;
   NewerOnlyCheck->Checked = FLAGCLEAR(Options, coDisableNewerOnly) && FParams.NewerOnly;
+  UpdateControls();
 }
 //---------------------------------------------------------------------------
 TGUICopyParamType __fastcall TCopyDialog::GetParams()
 {
-  // overwrites TCopyParamType files only
-  FParams = CopyParamsFrame->Params;
+  // overwrites TCopyParamType fields only
+  FParams = FCopyParams;
   FParams.FileMask = GetFileMask();
   FParams.Queue = QueueCheck->Checked;
   FParams.QueueNoConfirmation = QueueNoConfirmationCheck->Checked;
@@ -327,14 +318,17 @@ void __fastcall TCopyDialog::UpdateControls()
     }
   }
 
+  AnsiString InfoStr = FCopyParams.GetInfoStr("; ", CopyParamAttrs);
+  CopyParamLabel->Caption = InfoStr;
+  CopyParamLabel->Hint = InfoStr;
+  CopyParamLabel->ShowHint =
+    (CopyParamLabel->Canvas->TextWidth(InfoStr) > (CopyParamLabel->Width * 3 / 2));
+
   bool RemoteTransfer = FLAGSET(FOutputOptions, cooRemoteTransfer);
   EnableControl(QueueCheck,
     ((Options & (coDisableQueue | coTemp)) == 0) && !RemoteTransfer);
   EnableControl(QueueNoConfirmationCheck,
     (((Options & coTemp) == 0) && QueueCheck->Checked) && !RemoteTransfer);
-  QueueNoConfirmationCheck->Visible = MoreButton->Expanded;
-  EnableControl(SaveSettingsCheck, FLAGCLEAR(Options, coDisableSaveSettings) &&
-    !RemoteTransfer);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::SetMove(bool value)
@@ -351,16 +345,11 @@ void __fastcall TCopyDialog::FormShow(TObject * /*Sender*/)
   assert(FileList && (FileList->Count > 0));
   if (DirectoryEdit->Enabled && DirectoryEdit->Visible)
   {
-    DirectoryEdit->SetFocus();
-  }
-  else
-  if (MoreButton->Expanded)
-  {
-    MorePanel->SetFocus();
+    ActiveControl = DirectoryEdit;
   }
   else
   {
-    CopyButton->SetFocus();
+    ActiveControl = CopyButton;
   }
   UpdateControls();
 
@@ -374,16 +363,12 @@ bool __fastcall TCopyDialog::Execute()
   FPreset = GUIConfiguration->CopyParamCurrent;
   DirectoryEdit->Items = CustomWinConfiguration->History[
     ToRemote ? "RemoteTarget" : "LocalTarget"];
-  MoreButton->Expanded = GUIConfiguration->CopyParamDialogExpanded;
-  CopyParamsFrame->BeforeExecute();
   bool Result = (ShowModal() == mrOk);
   if (Result)
   {
-    CopyParamsFrame->AfterExecute();
     Configuration->BeginUpdate();
     try
     {
-      GUIConfiguration->CopyParamDialogExpanded = MoreButton->Expanded;
       if (FLAGSET(OutputOptions, cooSaveSettings) &&
           FLAGCLEAR(Options, coDisableSaveSettings))
       {
@@ -465,12 +450,18 @@ void __fastcall TCopyDialog::ControlChange(TObject * /*Sender*/)
   ResetSystemSettings(this);
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyDialog::PresetsButtonClick(TObject * /*Sender*/)
+void __fastcall TCopyDialog::TransferSettingsButtonClick(TObject * /*Sender*/)
 {
-  TCopyParamType Param = Params;
-  CopyParamListPopup(
-    PresetsButton->ClientToScreen(TPoint(0, PresetsButton->Height)),
-    FPresetsMenu, Params, FPreset, CopyParamClick, cplNone);
+  if (FLAGCLEAR(FOptions, FLAGCLEAR(Options, coDoNotUsePresets)))
+  {
+    CopyParamListPopup(
+      TransferSettingsButton->ClientToScreen(TPoint(0, TransferSettingsButton->Height)),
+      0);
+  }
+  else
+  {
+    CopyParamGroupDblClick(NULL);
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::CopyParamClick(TObject * Sender)
@@ -487,3 +478,32 @@ void __fastcall TCopyDialog::HelpButtonClick(TObject * /*Sender*/)
   FormHelp(this);
 }
 //---------------------------------------------------------------------------
+void __fastcall TCopyDialog::CopyParamGroupDblClick(TObject * /*Sender*/)
+{
+  if (DoCopyParamCustomDialog(FCopyParams, CopyParamAttrs))
+  {
+    UpdateControls();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyDialog::CopyParamGroupContextPopup(TObject * /*Sender*/,
+  TPoint & MousePos, bool & Handled)
+{
+  if (FLAGCLEAR(FOptions, FLAGCLEAR(Options, coDoNotUsePresets)))
+  {
+    CopyParamListPopup(CopyParamGroup->ClientToScreen(MousePos), cplCustomizeDefault);
+    Handled = true;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyDialog::CopyParamListPopup(TPoint P, int AdditionalOptions)
+{
+  ::CopyParamListPopup(P, FPresetsMenu,
+    FCopyParams, FPreset, CopyParamClick,
+    cplCustomize | AdditionalOptions |
+      FLAGMASK(
+          FLAGCLEAR(Options, coDisableSaveSettings) &&
+          FLAGCLEAR(FOutputOptions, cooRemoteTransfer),
+        cplSaveSettings),
+    &FSaveSettings);
+}

+ 64 - 82
forms/Copy.dfm

@@ -6,7 +6,7 @@ object CopyDialog: TCopyDialog
   BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
   BorderStyle = bsDialog
   Caption = 'CopyDialog'
-  ClientHeight = 359
+  ClientHeight = 189
   ClientWidth = 511
   Color = clBtnFace
   Font.Charset = DEFAULT_CHARSET
@@ -20,7 +20,7 @@ object CopyDialog: TCopyDialog
   OnShow = FormShow
   DesignSize = (
     511
-    359)
+    189)
   PixelsPerInch = 96
   TextHeight = 13
   object DirectoryLabel: TLabel
@@ -54,84 +54,27 @@ object CopyDialog: TCopyDialog
     Text = 'RemoteDirectoryEdit'
     OnChange = ControlChange
   end
-  object MoreButton: TMoreButton
-    Left = 176
-    Top = 329
-    Width = 75
-    Height = 25
-    Anchors = [akRight, akBottom]
-    Caption = '<< &Less'
-    TabOrder = 7
-    OnChange = ControlChange
-    Panel = MorePanel
-    RepositionForm = True
-  end
   object CopyButton: TButton
     Left = 260
-    Top = 329
+    Top = 159
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
     Caption = 'Copy'
     Default = True
     ModalResult = 1
-    TabOrder = 8
+    TabOrder = 9
   end
   object CancelButton: TButton
     Left = 343
-    Top = 329
+    Top = 159
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
     Cancel = True
     Caption = 'Cancel'
     ModalResult = 2
-    TabOrder = 9
-  end
-  object MorePanel: TPanel
-    Left = 0
-    Top = 52
-    Width = 511
-    Height = 253
-    Anchors = [akLeft, akTop, akRight, akBottom]
-    BevelOuter = bvNone
-    TabOrder = 3
-    DesignSize = (
-      511
-      253)
-    object SaveSettingsCheck: TCheckBox
-      Left = 8
-      Top = 235
-      Width = 301
-      Height = 17
-      Caption = 'Use &same settings next time'
-      TabOrder = 2
-    end
-    inline CopyParamsFrame: TCopyParamsFrame
-      Left = 2
-      Top = 0
-      Width = 508
-      Height = 213
-      TabOrder = 0
-    end
-    object NewerOnlyCheck: TCheckBox
-      Left = 8
-      Top = 215
-      Width = 377
-      Height = 17
-      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
+    TabOrder = 10
   end
   object LocalDirectoryBrowseButton: TButton
     Left = 427
@@ -144,42 +87,81 @@ object CopyDialog: TCopyDialog
   end
   object QueueCheck: TCheckBox
     Left = 8
-    Top = 307
+    Top = 135
     Width = 301
     Height = 17
-    Anchors = [akLeft, akBottom]
     Caption = 'Transfer on background (add to transfer &queue)'
-    TabOrder = 4
+    TabOrder = 6
     OnClick = ControlChange
   end
   object QueueNoConfirmationCheck: TCheckBox
     Left = 312
-    Top = 307
+    Top = 135
     Width = 193
     Height = 17
-    Anchors = [akLeft, akBottom]
     Caption = 'No &confirmations'
-    TabOrder = 5
+    TabOrder = 7
     OnClick = ControlChange
   end
-  object PresetsButton: TButton
-    Left = 8
-    Top = 329
-    Width = 97
-    Height = 25
-    Anchors = [akRight, akBottom]
-    Caption = '&Presets...'
-    TabOrder = 6
-    OnClick = PresetsButtonClick
-  end
   object HelpButton: TButton
     Left = 427
-    Top = 329
+    Top = 159
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
-    Caption = 'Help'
-    TabOrder = 10
+    Caption = '&Help'
+    TabOrder = 11
     OnClick = HelpButtonClick
   end
+  object NewerOnlyCheck: TCheckBox
+    Left = 8
+    Top = 112
+    Width = 301
+    Height = 17
+    Caption = '&New and updated file(s) only'
+    TabOrder = 4
+  end
+  object NeverShowAgainCheck: TCheckBox
+    Left = 312
+    Top = 112
+    Width = 193
+    Height = 17
+    Caption = '&Do not show this dialog box again'
+    TabOrder = 5
+    OnClick = ControlChange
+  end
+  object TransferSettingsButton: TButton
+    Left = 8
+    Top = 159
+    Width = 129
+    Height = 25
+    Anchors = [akLeft, akBottom]
+    Caption = 'Transfer settin&gs...'
+    TabOrder = 8
+    OnClick = TransferSettingsButtonClick
+  end
+  object CopyParamGroup: TGroupBox
+    Left = 8
+    Top = 53
+    Width = 496
+    Height = 50
+    Caption = 'Transfer settings'
+    TabOrder = 3
+    OnContextPopup = CopyParamGroupContextPopup
+    OnDblClick = CopyParamGroupDblClick
+    DesignSize = (
+      496
+      50)
+    object CopyParamLabel: TLabel
+      Left = 7
+      Top = 15
+      Width = 482
+      Height = 26
+      Anchors = [akLeft, akTop, akRight, akBottom]
+      AutoSize = False
+      Caption = 'CopyParamLabel'
+      WordWrap = True
+      OnDblClick = CopyParamGroupDblClick
+    end
+  end
 end

+ 12 - 7
forms/Copy.h

@@ -21,25 +21,26 @@ __published:
   TLabel *DirectoryLabel;
   THistoryComboBox *LocalDirectoryEdit;
   THistoryComboBox *RemoteDirectoryEdit;
-  TMoreButton *MoreButton;
   TButton *CopyButton;
   TButton *CancelButton;
-  TPanel *MorePanel;
-  TCheckBox *SaveSettingsCheck;
-  TCopyParamsFrame *CopyParamsFrame;
   TButton *LocalDirectoryBrowseButton;
   TCheckBox *QueueCheck;
   TCheckBox *QueueNoConfirmationCheck;
-  TCheckBox *NewerOnlyCheck;
-  TButton *PresetsButton;
   TButton *HelpButton;
+  TCheckBox *NewerOnlyCheck;
   TCheckBox *NeverShowAgainCheck;
+  TButton *TransferSettingsButton;
+  TGroupBox *CopyParamGroup;
+  TLabel *CopyParamLabel;
   void __fastcall FormShow(TObject *Sender);
   void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
   void __fastcall LocalDirectoryBrowseButtonClick(TObject *Sender);
   void __fastcall ControlChange(TObject *Sender);
-  void __fastcall PresetsButtonClick(TObject *Sender);
+  void __fastcall TransferSettingsButtonClick(TObject *Sender);
   void __fastcall HelpButtonClick(TObject *Sender);
+  void __fastcall CopyParamGroupDblClick(TObject *Sender);
+  void __fastcall CopyParamGroupContextPopup(TObject *Sender,
+          TPoint &MousePos, bool &Handled);
 private:
   bool FDefaultToRemote;
   bool FToRemote;
@@ -50,6 +51,9 @@ private:
   TGUICopyParamType FParams;
   TPopupMenu * FPresetsMenu;
   AnsiString FPreset;
+  TCopyParamType FCopyParams;
+  int FCopyParamAttrs;
+  bool FSaveSettings;
   AnsiString __fastcall GetDirectory();
   void __fastcall SetToRemote(bool value);
   THistoryComboBox * __fastcall GetDirectoryEdit();
@@ -70,6 +74,7 @@ protected:
   void __fastcall AdjustControls();
   void __fastcall AdjustTransferControls();
   bool __fastcall RemotePaths();
+  void __fastcall CopyParamListPopup(TPoint P, int AdditionalOptions);
 public:
   __fastcall TCopyDialog(TComponent* Owner);
   virtual __fastcall ~TCopyDialog();

+ 10 - 10
forms/CopyParamPreset.dfm

@@ -26,9 +26,9 @@ object CopyParamPresetDialog: TCopyParamPresetDialog
   object Label1: TLabel
     Left = 11
     Top = 13
-    Width = 84
+    Width = 87
     Height = 13
-    Caption = 'Preset &description'
+    Caption = 'Preset &description:'
     FocusControl = DescriptionEdit
   end
   object OkButton: TButton
@@ -174,33 +174,33 @@ object CopyParamPresetDialog: TCopyParamPresetDialog
     object Label2: TLabel
       Left = 10
       Top = 20
-      Width = 76
+      Width = 79
       Height = 13
-      Caption = 'Hostna&me mask'
+      Caption = 'Hostna&me mask:'
       FocusControl = HostNameEdit
     end
     object Label3: TLabel
       Left = 10
       Top = 68
-      Width = 76
+      Width = 79
       Height = 13
-      Caption = 'Us&ername mask'
+      Caption = 'Us&ername mask:'
       FocusControl = UserNameEdit
     end
     object Label4: TLabel
       Left = 10
       Top = 116
-      Width = 108
+      Width = 111
       Height = 13
-      Caption = 'Remote director&y mask'
+      Caption = 'Remote director&y mask:'
       FocusControl = RemoteDirectoryEdit
     end
     object Label5: TLabel
       Left = 10
       Top = 164
-      Width = 97
+      Width = 100
       Height = 13
-      Caption = '&Local directory mask'
+      Caption = '&Local directory mask:'
       FocusControl = LocalDirectoryEdit
     end
     object HostNameEdit: TEdit

+ 0 - 2
forms/CopyParamPreset.h

@@ -8,8 +8,6 @@
 #include <Forms.hpp>
 #include "CopyParams.h"
 //---------------------------------------------------------------------------
-class TCustomCommands;
-//---------------------------------------------------------------------------
 class TCopyParamPresetDialog : public TForm
 {
 __published:

+ 7 - 5
forms/CopyParams.dfm

@@ -84,7 +84,7 @@ object CopyParamsFrame: TCopyParamsFrame
       Top = 16
       Width = 156
       Height = 17
-      Caption = 'Set pe&rmissions'
+      Caption = 'Set pe&rmissions:'
       ParentShowHint = False
       ShowHint = True
       TabOrder = 0
@@ -206,10 +206,10 @@ object CopyParamsFrame: TCopyParamsFrame
     object AsciiFileMaskLabel: TLabel
       Left = 10
       Top = 99
-      Width = 164
+      Width = 167
       Height = 13
       Anchors = [akLeft, akTop, akRight]
-      Caption = 'Transfer following &files in text mode'
+      Caption = 'Transfer following &files in text mode:'
       FocusControl = AsciiFileMaskCombo
     end
     object TMTextButton: TRadioButton
@@ -247,6 +247,7 @@ object CopyParamsFrame: TCopyParamsFrame
       Top = 115
       Width = 180
       Height = 21
+      AutoComplete = False
       Anchors = [akLeft, akTop, akRight]
       ItemHeight = 13
       MaxLength = 1000
@@ -268,9 +269,9 @@ object CopyParamsFrame: TCopyParamsFrame
     object ExclusionFileMaskLabel: TLabel
       Left = 90
       Top = 18
-      Width = 25
+      Width = 28
       Height = 13
-      Caption = 'mas&k'
+      Caption = 'mas&k:'
       FocusControl = ExcludeFileMaskCombo
     end
     object ExcludeFileMaskCombo: THistoryComboBox
@@ -278,6 +279,7 @@ object CopyParamsFrame: TCopyParamsFrame
       Top = 14
       Width = 358
       Height = 21
+      AutoComplete = False
       Anchors = [akLeft, akTop, akRight]
       ItemHeight = 13
       MaxLength = 3000

+ 1 - 1
forms/CustomCommand.cpp

@@ -54,7 +54,7 @@ __fastcall TCustomCommandDialog::TCustomCommandDialog(TComponent* Owner, unsigne
   FOnValidate = NULL;
   FOptions = Options;
   InstallPathWordBreakProc(CommandEdit);
-  HintLabel(HintText, LoadStr(CUSTOM_COMMAND_PATTERNS_HINT));
+  HintLabel(HintText, LoadStr(CUSTOM_COMMAND_PATTERNS_HINT2));
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomCommandDialog::UpdateControls()

File diff suppressed because it is too large
+ 364 - 275
forms/CustomScpExplorer.cpp


+ 11 - 10
forms/CustomScpExplorer.dfm

@@ -1,5 +1,5 @@
 object CustomScpExplorerForm: TCustomScpExplorerForm
-  Left = 304
+  Left = 251
   Top = 166
   Width = 636
   Height = 470
@@ -74,6 +74,7 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
       TabOrder = 1
       ViewStyle = vsReport
       OnColumnRightClick = DirViewColumnRightClick
+      OnEditing = DirViewEditing
       OnEnter = RemoteDirViewEnter
       NortonLike = nlOff
       UnixColProperties.ExtWidth = 20
@@ -132,7 +133,7 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
     Align = alBottom
     BevelOuter = bvNone
     TabOrder = 1
-    object QueueView: TListView
+    object QueueView2: TListView
       Left = 0
       Top = 26
       Width = 628
@@ -158,7 +159,7 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
         end
         item
           Alignment = taRightJustify
-          Caption = 'Elap./Speed'
+          Caption = 'Time/Speed'
           Width = 80
         end
         item
@@ -175,13 +176,13 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
       StateImages = GlyphsModule.QueueImages
       TabOrder = 0
       ViewStyle = vsReport
-      OnContextPopup = QueueViewContextPopup
-      OnDeletion = QueueViewDeletion
-      OnEnter = QueueViewEnter
-      OnDragDrop = QueueViewDragDrop
-      OnDragOver = QueueViewDragOver
-      OnSelectItem = QueueViewSelectItem
-      OnStartDrag = QueueViewStartDrag
+      OnContextPopup = QueueView2ContextPopup
+      OnDeletion = QueueView2Deletion
+      OnEnter = QueueView2Enter
+      OnDragDrop = QueueView2DragDrop
+      OnDragOver = QueueView2DragOver
+      OnSelectItem = QueueView2SelectItem
+      OnStartDrag = QueueView2StartDrag
     end
     object QueueDock: TTBXDock
       Tag = 1

+ 45 - 19
forms/CustomScpExplorer.h

@@ -63,7 +63,7 @@ __published:
   TTBXStatusBar *RemoteStatusBar;
   TUnixDirView *RemoteDirView;
   TTBXDock *TopDock;
-  TListView *QueueView;
+  TListView *QueueView2;
   TPanel *QueuePanel;
   TSplitter *QueueSplitter;
   TTBXToolbar *QueueToolbar;
@@ -107,17 +107,17 @@ __published:
     int dwEffect, HRESULT &Result);
   void __fastcall QueueSplitterCanResize(TObject *Sender, int &NewSize,
     bool &Accept);
-  void __fastcall QueueViewContextPopup(TObject *Sender, TPoint &MousePos,
+  void __fastcall QueueView2ContextPopup(TObject *Sender, TPoint &MousePos,
     bool &Handled);
-  void __fastcall QueueViewDeletion(TObject *Sender, TListItem *Item);
-  void __fastcall QueueViewStartDrag(TObject *Sender,
+  void __fastcall QueueView2Deletion(TObject *Sender, TListItem *Item);
+  void __fastcall QueueView2StartDrag(TObject *Sender,
     TDragObject *&DragObject);
-  void __fastcall QueueViewDragOver(TObject *Sender, TObject *Source,
+  void __fastcall QueueView2DragOver(TObject *Sender, TObject *Source,
     int X, int Y, TDragState State, bool &Accept);
-  void __fastcall QueueViewDragDrop(TObject *Sender, TObject *Source,
+  void __fastcall QueueView2DragDrop(TObject *Sender, TObject *Source,
     int X, int Y);
-  void __fastcall QueueViewEnter(TObject *Sender);
-  void __fastcall QueueViewSelectItem(TObject *Sender, TListItem *Item,
+  void __fastcall QueueView2Enter(TObject *Sender);
+  void __fastcall QueueView2SelectItem(TObject *Sender, TListItem *Item,
     bool Selected);
   void __fastcall RemoteFileControlDDFileOperation(TObject * Sender,
     int Effect, AnsiString SourcePath, AnsiString TargetPath,
@@ -140,12 +140,24 @@ __published:
   void __fastcall DirViewHistoryChange(TCustomDirView *Sender);
   void __fastcall RemoteStatusBarClick(TObject *Sender);
   void __fastcall DirViewLoaded(TObject *Sender);
-  void __fastcall AddressToolbarGetBaseSize(TTBCustomToolbar * Toolbar, TPoint & ASize);
+  void __fastcall ToolbarGetBaseSize(TTBCustomToolbar * Toolbar, TPoint & ASize);
   void __fastcall FormConstrainedResize(TObject * Sender, int & MinWidth,
     int  &MinHeight, int  &MaxWidth, int  &MaxHeight);
   void __fastcall SessionColorPaletteChange(TObject * Sender);
   void __fastcall StatusBarPanelDblClick(TTBXCustomStatusBar * Sender,
     TTBXStatusPanel * Panel);
+  void __fastcall RemotePathComboBoxAdjustImageIndex(
+    TTBXComboBoxItem * Sender, const AnsiString AText, int AIndex,
+    int & ImageIndex);
+  void __fastcall RemotePathComboBoxDrawItem(TTBXCustomList * Sender,
+    TCanvas * ACanvas, TRect & ARect, int AIndex, int AHoverIndex,
+    bool & DrawDefault);
+  void __fastcall RemotePathComboBoxMeasureWidth(TTBXCustomList * Sender,
+    TCanvas * ACanvas, int AIndex, int & AWidth);
+  void __fastcall RemotePathComboBoxItemClick(TObject * Sender);
+  void __fastcall RemotePathComboBoxCancel(TObject * Sender);
+  void __fastcall DirViewEditing(TObject *Sender, TListItem *Item,
+          bool &AllowEdit);
 
 private:
   TTerminal * FTerminal;
@@ -234,15 +246,18 @@ protected:
   AnsiString FNoteHints;
   TNotifyEvent FOnNoteClick;
   unsigned int FLockLevel;
+  TImageList * FSystemImageList;
+  bool FAlternativeDelete;
 
   virtual bool __fastcall CopyParamDialog(TTransferDirection Direction,
     TTransferType Type, bool Temp, TStrings * FileList,
     AnsiString & TargetDirectory, TGUICopyParamType & CopyParam, bool Confirm,
     bool DragDrop);
-  virtual bool __fastcall RemoteTransferDialog(TStrings * FileList,
-    AnsiString & Target, AnsiString & FileMask, bool NoConfirmation, bool Move);
+  virtual bool __fastcall RemoteTransferDialog(TTerminal *& Session,
+    AnsiString & Target, AnsiString & FileMask, bool & DirectCopy,
+    bool NoConfirmation, bool Move);
   virtual void __fastcall CreateParams(TCreateParams & Params);
-  void __fastcall DeleteFiles(TOperationSide Side, TStrings * FileList);
+  void __fastcall DeleteFiles(TOperationSide Side, TStrings * FileList, bool Alternative);
   void __fastcall RemoteTransferFiles(TStrings * FileList, bool NoConfirmation, bool Move);
   virtual void __fastcall DoDirViewExecFile(TObject * Sender, TListItem * Item, bool & AllowExec);
   virtual TControl * __fastcall GetComponent(Byte Component);
@@ -275,7 +290,7 @@ protected:
   void __fastcall ExecutedFileReload(const AnsiString FileName,
     const TEditedFileData & Data);
   void __fastcall ExecutedFileEarlyClosed(const TEditedFileData & Data,
-    bool * CloseFlag, bool & KeepOpen);
+    bool & KeepOpen);
   void __fastcall CMAppSysCommand(TMessage & Message);
   void __fastcall WMAppCommand(TMessage & Message);
   void __fastcall WMSysCommand(TMessage & Message);
@@ -336,20 +351,24 @@ protected:
   void __fastcall DDDownload(TStrings * FilesToCopy,
     const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params);
   bool __fastcall EnsureCommandSessionFallback(TFSCapability Capability);
+  bool __fastcall CommandSessionFallback();
   void __fastcall FileTerminalClosed(const AnsiString FileName,
     TEditedFileData & Data, TObject * Token, void * Arg);
   void __fastcall FileConfigurationChanged(const AnsiString FileName,
     TEditedFileData & Data, TObject * Token, void * Arg);
   void __fastcall CustomExecuteFile(TOperationSide Side,
     TExecuteFileBy ExecuteFileBy, AnsiString FileName, AnsiString OriginalFileName,
-    const TEditorPreferences * ExternalEditor);
+    const TEditorPreferences * ExternalEditor, AnsiString LocalRootDirectory);
   bool __fastcall RemoteExecuteForceText(TExecuteFileBy ExecuteFileBy,
     const TEditorPreferences * ExternalEditor);
   void __fastcall ExecuteFileNormalize(TExecuteFileBy & ExecuteFileBy,
     const TEditorPreferences *& ExternalEditor, const AnsiString & FileName,
     bool Local, const TFileMasks::TParams & MaskParams);
+  AnsiString __fastcall TemporaryDirectoryForRemoteFiles(TCopyParamType CopyParam,
+    AnsiString & RootDirectory);
   void __fastcall TemporarilyDownloadFiles(TStrings * FileList, bool ForceText,
-    AnsiString & TempDir, bool AllFiles, bool GetTargetNames);
+    AnsiString & RootTempDir, AnsiString & TempDir, bool AllFiles, bool GetTargetNames,
+    bool AutoOperation);
   TTBXPopupMenu * __fastcall HistoryMenu(TOperationSide Side, bool Back);
   AnsiString __fastcall FileStatusBarText(const TStatusFileInfo & FileInfo);
   void __fastcall UpdateFileStatusBar(TTBXStatusBar * StatusBar,
@@ -388,18 +407,22 @@ protected:
     bool AllowNeverAskAgain);
   void __fastcall UpdateTrayIcon();
   void __fastcall TrayIconClick(TObject * Sender);
-  void __fastcall PopupTrayBalloon(TTerminal * Terminal, const AnsiString & Str,
-    TQueryType Type, Exception * E = NULL, unsigned int Seconds = 0);
   void __fastcall Notify(TTerminal * Terminal, AnsiString Message,
     TQueryType Type, bool Important = false, TNotifyEvent OnClick = NULL,
     Exception * E = NULL);
   bool __fastcall OpenInNewWindow();
   virtual void __fastcall UpdateSessionData(TSessionData * Data);
+  virtual void __fastcall UpdateRemotePathComboBox(
+    TTBXComboBoxItem * RemotePathComboBox, bool TextOnly);
+  virtual void __fastcall ToolbarItemResize(TTBXCustomDropDownItem * Item, int Width);
+  void __fastcall ClickToolbarItem(TTBCustomItem * Item, bool PositionCursor);
 
 public:
   virtual __fastcall ~TCustomScpExplorerForm();
   void __fastcall AddBookmark(TOperationSide Side);
   virtual void __fastcall AddEditLink(bool Add);
+  bool __fastcall CanAddEditLink();
+  bool __fastcall LinkFocused();
   virtual Boolean __fastcall AllowedAction(TAction * Action, TActionAllowed Allowed) = 0;
   virtual void __fastcall ConfigurationChanged();
   void __fastcall CreateDirectory(TOperationSide Side);
@@ -420,6 +443,7 @@ public:
   void __fastcall DuplicateSession();
   void __fastcall CloseSession();
   void __fastcall OpenDirectory(TOperationSide Side);
+  virtual void __fastcall HomeDirectory(TOperationSide Side);
   void __fastcall OpenStoredSession(TSessionData * Data);
   void __fastcall Idle(bool AppIdle);
   __fastcall TCustomScpExplorerForm(TComponent* Owner);
@@ -439,8 +463,8 @@ public:
     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);
+  bool __fastcall AllowQueueOperation(TQueueOperation Operation, void ** Param = NULL);
+  void __fastcall ExecuteQueueOperation(TQueueOperation Operation, void * Param = NULL);
   TQueueOperation __fastcall DefaultQueueOperation();
   void __fastcall LastTerminalClosed(TObject * Sender);
   void __fastcall TerminalClosed(TObject * Sender);
@@ -475,6 +499,8 @@ public:
   void __fastcall SynchronizeBrowsingChanged();
   void __fastcall ToggleShowHiddenFiles();
   void __fastcall ToggleAutoReadDirectoryAfterOp();
+  void __fastcall PopupTrayBalloon(TTerminal * Terminal, const AnsiString & Str,
+    TQueryType Type, Exception * E = NULL, unsigned int Seconds = 0);
 
   __property bool ComponentVisible[Word Component] = { read = GetComponentVisible, write = SetComponentVisible };
   __property bool EnableFocusedOperation[TOperationSide Side] = { read = GetEnableFocusedOperation, index = 0 };

+ 249 - 50
forms/Editor.cpp

@@ -23,12 +23,11 @@
 //---------------------------------------------------------------------------
 TForm * __fastcall ShowEditorForm(const AnsiString FileName, TCustomForm * ParentForm,
   TNotifyEvent OnFileChanged, TNotifyEvent OnFileReload, TNotifyEvent OnClose,
-  const AnsiString Caption, bool ShowWindowButton)
+  const AnsiString Caption)
 {
   TEditorForm * Dialog = new TEditorForm(Application);
   try
   {
-    Dialog->ShowWindowButton = ShowWindowButton;
     Dialog->FileName = FileName;
     Dialog->ParentForm = ParentForm;
     Dialog->Caption = Caption.IsEmpty() ? FileName : Caption;
@@ -53,6 +52,210 @@ void __fastcall ReconfigureEditorForm(TForm * Form)
   Editor->ApplyConfiguration();
 }
 //---------------------------------------------------------------------------
+class TRichEdit20 : public TRichEdit
+{
+public:
+  virtual __fastcall TRichEdit20(TComponent * AOwner);
+
+  void __fastcall SetFormat(AnsiString FontName, int FontHeight,
+    TFontCharset FontCharset, TFontStyles FontStyles, unsigned int TabSize,
+    bool AWordWrap);
+  int __fastcall FindText(const AnsiString SearchStr, int StartPos, int Length,
+    TSearchTypes Options, bool Down);
+  void __fastcall Redo();
+
+  __property bool SupportsUpSearch = { read = FVersion20 };
+  __property bool CanRedo = { read = GetCanRedo };
+
+protected:
+  virtual void __fastcall CreateWnd(void);
+  virtual void __fastcall CreateParams(TCreateParams & Params);
+  virtual void __fastcall DestroyWnd();
+  bool __fastcall GetCanRedo();
+  void __fastcall ApplyTabSize();
+
+private:
+  HINSTANCE FLibrary;
+  bool FVersion20;
+  bool FWordWrap;
+  unsigned int FTabSize;
+};
+//---------------------------------------------------------------------------
+__fastcall TRichEdit20::TRichEdit20(TComponent * AOwner) :
+  TRichEdit(AOwner),
+  FLibrary(0),
+  FVersion20(false),
+  FTabSize(0),
+  FWordWrap(true)
+{
+}
+//---------------------------------------------------------------------------
+void __fastcall TRichEdit20::SetFormat(AnsiString FontName, int FontHeight,
+  TFontCharset FontCharset, TFontStyles FontStyles, unsigned int TabSize,
+  bool AWordWrap)
+{
+  bool RecalculateTabs = (Font->Name != FontName) || (Font->Height != FontHeight) ||
+    (TabSize != FTabSize);
+
+  LockWindowUpdate(Handle);
+
+  Font->Name = FontName;
+  Font->Height = FontHeight;
+  Font->Charset = FontCharset;
+  Font->Style = FontStyles;
+  DefAttributes->Assign(Font);
+  FTabSize = TabSize;
+
+  if (RecalculateTabs && HandleAllocated())
+  {
+    ApplyTabSize();
+  }
+
+  if (FWordWrap != AWordWrap)
+  {
+    if (Visible)
+    {
+      // Undocumented usage of EM_SETTARGETDEVICE.
+      // But note that it is used by MFC in CRichEditView::WrapChanged()
+      SendMessage(Handle, EM_SETTARGETDEVICE, 0, (AWordWrap ? 0 : 1));
+    }
+    else
+    {
+      WordWrap = AWordWrap;
+    }
+    FWordWrap = AWordWrap;
+  }
+
+  LockWindowUpdate(NULL);
+}
+//---------------------------------------------------------------------------
+int __fastcall TRichEdit20::FindText(const AnsiString SearchStr, int StartPos,
+  int /*Length*/, TSearchTypes Options, bool Down)
+{
+  int Result;
+  if (FVersion20)
+  {
+    ::FINDTEXTEX Find;
+    memset(&Find, 0, sizeof(Find));
+    Find.chrg.cpMin = StartPos;
+    Find.chrg.cpMax = -1;
+    Find.lpstrText = SearchStr.c_str();
+
+    unsigned int Flags =
+      FLAGMASK(Options.Contains(stWholeWord), FT_WHOLEWORD) |
+      FLAGMASK(Options.Contains(stMatchCase), FT_MATCHCASE) |
+      FLAGMASK(Down, FR_DOWN);
+    Result = SendMessage(Handle, EM_FINDTEXTEX, Flags, (LPARAM)&Find);
+  }
+  else
+  {
+    assert(Down);
+    Result = TRichEdit::FindText(SearchStr, StartPos, Text.Length(), Options);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TRichEdit20::Redo()
+{
+  assert(FVersion20);
+  SendMessage(Handle, EM_REDO, 0, 0);
+}
+//---------------------------------------------------------------------------
+void __fastcall TRichEdit20::CreateWnd(void)
+{
+  TRichEdit::CreateWnd();
+
+  ApplyTabSize();
+}
+//---------------------------------------------------------------------------
+void __fastcall TRichEdit20::CreateParams(TCreateParams & Params)
+{
+  const char RichEditModuleName[] = "RICHED20.DLL";
+  long int OldError;
+
+  OldError = SetErrorMode(SEM_NOOPENFILEERRORBOX);
+  FLibrary = LoadLibrary(RichEditModuleName);
+  SetErrorMode(OldError);
+
+  FVersion20 = (FLibrary != 0);
+  if (!FVersion20)
+  {
+    // fallback to richedit 1.0
+    TRichEdit::CreateParams(Params);
+  }
+  else
+  {
+    TCustomMemo::CreateParams(Params);
+    CreateSubClass(Params, RICHEDIT_CLASS);
+    Params.Style = Params.Style |
+      (HideScrollBars ? 0 : ES_DISABLENOSCROLL) |
+      (HideSelection ? 0 : ES_NOHIDESEL);
+    Params.WindowClass.style = Params.WindowClass.style &
+      ~(CS_HREDRAW | CS_VREDRAW);
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TRichEdit20::DestroyWnd()
+{
+  TRichEdit::DestroyWnd();
+
+  if (FLibrary != 0)
+  {
+    FreeLibrary(FLibrary);
+  }
+}
+//---------------------------------------------------------------------------
+bool __fastcall TRichEdit20::GetCanRedo()
+{
+  return FVersion20 && (SendMessage(Handle, EM_CANREDO, 0, 0) != 0);
+}
+//---------------------------------------------------------------------------
+void __fastcall TRichEdit20::ApplyTabSize()
+{
+  if (FTabSize > 0)
+  {
+    HDC DC = GetDC(Handle);
+    SaveDC(DC);
+    SetMapMode(DC, MM_TEXT);
+    SelectObject(DC, Font->Handle);
+
+    int LogPixelsX = GetDeviceCaps(DC, LOGPIXELSX);
+
+    SIZE Size;
+    GetTextExtentPoint(DC, AnsiString::StringOfChar('X', FTabSize).c_str(),
+      FTabSize, &Size);
+
+    RestoreDC(DC, -1);
+    ReleaseDC(Handle, DC);
+
+    unsigned int TabTwips = MulDiv(Size.cx, 1440, LogPixelsX);
+
+    // save selection
+    CHARRANGE CharRange;
+    SendMessage(Handle, EM_EXGETSEL, 0, (LPARAM)&CharRange);
+
+    CHARRANGE CharRangeAll;
+    CharRangeAll.cpMin = 0;
+    CharRangeAll.cpMax = -1;
+    SendMessage(Handle, EM_EXSETSEL, 0, (LPARAM)&CharRangeAll);
+
+    PARAFORMAT2 ParaFormat;
+    ParaFormat.cbSize = sizeof(ParaFormat);
+    ParaFormat.dwMask = PFM_TABSTOPS;
+    ParaFormat.cTabCount = MAX_TAB_STOPS;
+
+    for (int i = 0; i < ParaFormat.cTabCount; i++)
+    {
+      ParaFormat.rgxTabs[i] = (i + 1) * TabTwips;
+    }
+
+    SendMessage(Handle, EM_SETPARAFORMAT, 0, (LPARAM)&ParaFormat);
+
+    // restore selection
+    SendMessage(Handle, EM_EXSETSEL, 0, (LPARAM)&CharRange);
+  }
+}
+//---------------------------------------------------------------------------
 class TFindDialogEx : public TFindDialog
 {
 public:
@@ -64,7 +267,7 @@ public:
 protected:
   unsigned int FHelpMsg;
 
-    virtual bool __fastcall MessageHook(TMessage & Msg)
+  virtual bool __fastcall MessageHook(TMessage & Msg)
   {
     bool Result = false;
     if (Msg.Msg == FHelpMsg)
@@ -93,7 +296,7 @@ public:
 protected:
   unsigned int FHelpMsg;
 
-    virtual bool __fastcall MessageHook(TMessage & Msg)
+  virtual bool __fastcall MessageHook(TMessage & Msg)
   {
     bool Result = false;
     if (Msg.Msg == FHelpMsg)
@@ -114,11 +317,22 @@ protected:
 __fastcall TEditorForm::TEditorForm(TComponent* Owner)
   : TForm(Owner)
 {
+  EditorMemo = new TRichEdit20(this);
+  EditorMemo->Parent = this;
+  EditorMemo->Align = alClient;
+  EditorMemo->HideSelection = false;
+  EditorMemo->PlainText = true;
+  EditorMemo->PopupMenu = EditorPopup;
+  EditorMemo->ScrollBars = ssBoth;
+  EditorMemo->WantTabs = true;
+  EditorMemo->OnChange = EditorMemoChange;
+  EditorMemo->OnKeyUp = EditorMemoKeyUp;
+  EditorMemo->OnMouseUp = EditorMemoMouseUp;
+
   FParentForm = NULL;
   FCaretPos.x = -1;
   FCaretPos.y = -1;
   FLastFindDialog = NULL;
-  FShowWindowButton = false;
   FCloseAnnounced = false;
   ApplyConfiguration();
   FFindDialog = new TFindDialogEx(this);
@@ -157,7 +371,8 @@ void __fastcall TEditorForm::SetParentForm(TCustomForm * value)
     FParentForm = value;
     if (value)
     {
-      BoundsRect = value->BoundsRect;
+      Width = value->BoundsRect.Width();
+      Height = value->BoundsRect.Height();
     }
   }
 }
@@ -175,6 +390,10 @@ void __fastcall TEditorForm::EditorActionsUpdate(TBasicAction *Action,
     FindNextAction->Enabled =
       FLastFindDialog != NULL || !FFindDialog->FindText.IsEmpty();
   }
+  else if (Action == EditRedo)
+  {
+    EditRedo->Enabled = EditorMemo->CanRedo;
+  }
   else if (Action == PreferencesAction || Action == CloseAction ||
     Action == FindAction || Action == ReplaceAction || Action == GoToLineAction ||
     Action == HelpAction || Action == ReloadAction)
@@ -230,6 +449,10 @@ void __fastcall TEditorForm::EditorActionsExecute(TBasicAction *Action,
   {
     GoToLine();
   }
+  else if (Action == EditRedo)
+  {
+    EditorMemo->Redo();
+  }
   else if (Action == EditPaste)
   {
     // original source: http://home.att.net/~robertdunn/FAQs/Faqs.html
@@ -268,34 +491,10 @@ void __fastcall TEditorForm::ApplyConfiguration()
 {
   bool PrevModified = EditorMemo->Modified;
   assert(Configuration);
-  EditorMemo->Font->Name = WinConfiguration->Editor.FontName;
-  EditorMemo->Font->Height = WinConfiguration->Editor.FontHeight;
-  EditorMemo->Font->Charset = (TFontCharset)WinConfiguration->Editor.FontCharset;
-  EditorMemo->Font->Style = IntToFontStyles(WinConfiguration->Editor.FontStyle);
-  EditorMemo->DefAttributes->Assign(EditorMemo->Font);
-  if (EditorMemo->WordWrap != WinConfiguration->Editor.WordWrap)
-  {
-    if (Visible)
-    {
-      TStrings * Content = new TStringList();
-      try
-      {
-        EditorMemo->WordWrap = False;
-        Content->Assign(EditorMemo->Lines);
-        EditorMemo->WordWrap = WinConfiguration->Editor.WordWrap;
-        EditorMemo->Lines = Content;
-        EditorMemo->CaretPos = TPoint(0, 0);
-      }
-      __finally
-      {
-        delete Content;
-      }
-    }
-    else
-    {
-      EditorMemo->WordWrap = WinConfiguration->Editor.WordWrap;
-    }
-  }
+  EditorMemo->SetFormat(WinConfiguration->Editor.FontName,
+    WinConfiguration->Editor.FontHeight, (TFontCharset)WinConfiguration->Editor.FontCharset,
+    IntToFontStyles(WinConfiguration->Editor.FontStyle), WinConfiguration->Editor.TabSize,
+    WinConfiguration->Editor.WordWrap);
   EditorMemo->Modified = PrevModified;
   EditorMemo->ClearUndo();
   UpdateControls();
@@ -319,7 +518,7 @@ void __fastcall TEditorForm::UpdateControls()
       AnsiString Line = EditorMemo->Lines->Strings[FCaretPos.y];
       if (FCaretPos.x+1 <= Line.Length())
       {
-        Character = FMTLOAD(EDITOR_CHARACTER_STATUS,
+        Character = FMTLOAD(EDITOR_CHARACTER_STATUS2,
           (int((unsigned char)Line[FCaretPos.x+1]), int((unsigned char)Line[FCaretPos.x+1])));
       }
     }
@@ -380,6 +579,7 @@ void __fastcall TEditorForm::Find()
     EditorConfiguration.ReplaceText = FReplaceDialog->ReplaceText;
     EditorConfiguration.FindMatchCase = FLastFindDialog->Options.Contains(frMatchCase);
     EditorConfiguration.FindWholeWord = FLastFindDialog->Options.Contains(frWholeWord);
+    EditorConfiguration.FindDown = FLastFindDialog->Options.Contains(frDown);
     WinConfiguration->Editor = EditorConfiguration;
 
     if (EditorConfiguration.FindMatchCase)
@@ -393,7 +593,7 @@ void __fastcall TEditorForm::Find()
 
     NewPos = EditorMemo->FindText(EditorConfiguration.FindText,
       EditorMemo->SelLength ? EditorMemo->SelStart+1 : EditorMemo->SelStart,
-      EditorMemo->Text.Length(), SearchTypes);
+      EditorMemo->Text.Length(), SearchTypes, EditorConfiguration.FindDown);
 
     if (NewPos >= 0)
     {
@@ -493,7 +693,6 @@ void __fastcall TEditorForm::StartFind(bool Find)
 {
   AnsiString Text = EditorMemo->SelText;
   TFindOptions Options;
-  Options << frHideUpDown; // not implemented
   Options << frShowHelp;
   if (Text.IsEmpty())
   {
@@ -518,6 +717,18 @@ void __fastcall TEditorForm::StartFind(bool Find)
   {
     Options << frWholeWord;
   }
+  if (EditorMemo->SupportsUpSearch)
+  {
+    if (WinConfiguration->Editor.FindDown)
+    {
+      Options << frDown;
+    }
+  }
+  else
+  {
+    Options << frHideUpDown; // not implemented
+    Options << frDown;
+  }
   FLastFindDialog->Options = Options;
   if (!FLastFindDialog->Handle)
   {
@@ -572,22 +783,10 @@ void __fastcall TEditorForm::DoWindowClose()
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TEditorForm::SetShowWindowButton(bool value)
-{
-  if (value != ShowWindowButton)
-  {
-    FShowWindowButton = value;
-    RecreateWnd();
-  }
-}
-//---------------------------------------------------------------------------
 void __fastcall TEditorForm::CreateParams(TCreateParams & Params)
 {
   TForm::CreateParams(Params);
-  if (ShowWindowButton)
-  {
-    Params.WndParent = GetDesktopWindow();
-  }
+  Params.WndParent = GetDesktopWindow();
 }
 //---------------------------------------------------------------------------
 void __fastcall TEditorForm::Reload()

+ 35 - 39
forms/Editor.dfm

@@ -77,6 +77,9 @@ object EditorForm: TEditorForm
       object TBXItem8: TTBXItem
         Action = EditUndo
       end
+      object TBXItem17: TTBXItem
+        Action = EditRedo
+      end
       object TBXSeparatorItem3: TTBXSeparatorItem
       end
       object TBXItem9: TTBXItem
@@ -103,22 +106,6 @@ object EditorForm: TEditorForm
       end
     end
   end
-  object EditorMemo: TRichEdit
-    Left = 0
-    Top = 26
-    Width = 617
-    Height = 337
-    Align = alClient
-    HideSelection = False
-    PlainText = True
-    PopupMenu = EditorPopup
-    ScrollBars = ssBoth
-    TabOrder = 0
-    WantTabs = True
-    OnChange = EditorMemoChange
-    OnKeyUp = EditorMemoKeyUp
-    OnMouseUp = EditorMemoMouseUp
-  end
   object StatusBar: TTBXStatusBar
     Left = 0
     Top = 363
@@ -195,6 +182,12 @@ object EditorForm: TEditorForm
       ImageIndex = 4
       ShortCut = 16474
     end
+    object EditRedo: TAction
+      Caption = 'Re&do'
+      Hint = 'Redo|Reverts the effects of most recent Undo'
+      ImageIndex = 16
+      ShortCut = 16473
+    end
     object EditDelete: TEditDelete
       Caption = '&Delete'
       Hint = 'Delete|Erases the selection'
@@ -260,7 +253,7 @@ object EditorForm: TEditorForm
     Left = 536
     Top = 56
     Bitmap = {
-      494C010110001300040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010111001300040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000005000000001002000000000000050
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -302,6 +295,7 @@ object EditorForm: TEditorForm
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000008400
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -309,49 +303,48 @@ object EditorForm: TEditorForm
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000008400
+      0000000000000000000000000000000000000000000084000000840000008400
+      0000840000008400000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000840000000000
+      0000000000000000000000000000000000000000000000000000840000008400
+      0000840000008400000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000840000000000
+      0000000000000000000000000000000000000000000000000000000000008400
+      0000840000008400000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000840000000000
+      0000000000000000000000000000000000000000000000000000840000000000
+      0000840000008400000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000008400
+      0000000000000000000000000000000000008400000084000000000000000000
+      0000000000008400000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      0000840000008400000084000000840000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -904,11 +897,11 @@ object EditorForm: TEditorForm
       0000000000000000000000000000000000000000000000000000000000000000
       000000000000000000000000000000000000424D3E000000000000003E000000
       2800000040000000500000000100010000000000800200000000000000000000
-      000000000000000000000000FFFFFF0000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000FFFFFE7FFFFF8003F000F83FF9FF8003
+      000000000000000000000000FFFFFF00FFFF000000000000FFFF000000000000
+      FFFF000000000000FFFF000000000000FFFF000000000000EFFF000000000000
+      EF83000000000000DFC3000000000000DFE3000000000000DFD3000000000000
+      EF3B000000000000F0FF000000000000FFFF000000000000FFFF000000000000
+      FFFF000000000000FFFF000000000000FFFFFE7FFFFF8003F000F83FF9FF8003
       F000E01FF9FF8003F000800FF3C780037000000773C780033000000327FF8003
       1000000107C780031000000000C780033000000001E380037000800003F18003
       F000C00006388003F000E0000E388003F000F0011E388003F001F8073F018007
@@ -934,6 +927,9 @@ object EditorForm: TEditorForm
     object Undo1: TTBXItem
       Action = EditUndo
     end
+    object TBXItem18: TTBXItem
+      Action = EditRedo
+    end
     object N1: TTBXSeparatorItem
     end
     object Cut1: TTBXItem

+ 6 - 4
forms/Editor.h

@@ -20,6 +20,8 @@
 #include "TB2Toolbar.hpp"
 #include "TBXStatusBars.hpp"
 //---------------------------------------------------------------------------
+class TRichEdit20;
+//---------------------------------------------------------------------------
 class TEditorForm : public TForm
 {
 __published:
@@ -28,7 +30,6 @@ __published:
   TAction *SaveAction;
   TTBXDock *TopDock;
   TTBXToolbar *ToolBar;
-  TRichEdit *EditorMemo;
   TTBXStatusBar *StatusBar;
   TEditCut *EditCut;
   TEditCopy *EditCopy;
@@ -80,6 +81,9 @@ __published:
   TTBXItem *TBXItem15;
   TAction *ReloadAction;
   TTBXItem *TBXItem16;
+  TAction *EditRedo;
+  TTBXItem *TBXItem17;
+  TTBXItem *TBXItem18;
   void __fastcall EditorActionsUpdate(TBasicAction *Action, bool &Handled);
   void __fastcall EditorActionsExecute(TBasicAction *Action,
           bool &Handled);
@@ -100,13 +104,12 @@ private:
   TCustomForm * FParentForm;
   TFindDialog * FLastFindDialog;
   TPoint FCaretPos;
-  bool FShowWindowButton;
   TFindDialog * FFindDialog;
   TReplaceDialog * FReplaceDialog;
   bool FCloseAnnounced;
+  TRichEdit20 * EditorMemo;
   void __fastcall SetFileName(const AnsiString value);
   void __fastcall SetParentForm(TCustomForm * value);
-  void __fastcall SetShowWindowButton(bool value);
 public:
   __fastcall TEditorForm(TComponent* Owner);
   virtual __fastcall ~TEditorForm();
@@ -116,7 +119,6 @@ public:
   __property TNotifyEvent OnFileReload = { read = FOnFileReload, write = FOnFileReload };
   __property TNotifyEvent OnWindowClose = { read = FOnWindowClose, write = FOnWindowClose };
   __property TCustomForm * ParentForm = { read = FParentForm, write = SetParentForm };
-  __property bool ShowWindowButton = { read = FShowWindowButton, write = SetShowWindowButton };
 protected:
   bool __fastcall CursorInUpperPart();
   void __fastcall Find();

+ 2 - 2
forms/EditorPreferences.cpp

@@ -20,7 +20,7 @@ bool __fastcall DoEditorPreferencesDialog(TEditorPreferences * Editor,
 {
   bool Result;
 
-  TEditorPreferencesDialog * Dialog = SafeFormCreate<TEditorPreferencesDialog>(Application);
+  TEditorPreferencesDialog * Dialog = SafeFormCreate<TEditorPreferencesDialog>();
   try
   {
     Dialog->Init(Mode);
@@ -111,7 +111,7 @@ void __fastcall TEditorPreferencesDialog::ExternalEditorBrowseButtonClick(
 {
   BrowseForExecutable(ExternalEditorEdit,
     LoadStr(PREFERENCES_SELECT_EXTERNAL_EDITOR),
-    LoadStr(PREFERENCES_EXTERNAL_EDITOR_FILTER), true);
+    LoadStr(EXECUTABLE_FILTER), true, false);
 }
 //---------------------------------------------------------------------------
 void __fastcall TEditorPreferencesDialog::HelpButtonClick(TObject * /*Sender*/)

+ 2 - 1
forms/EditorPreferences.dfm

@@ -72,7 +72,7 @@ object EditorPreferencesDialog: TEditorPreferencesDialog
       Top = 45
       Width = 145
       Height = 17
-      Caption = '&External editor'
+      Caption = '&External editor:'
       TabOrder = 1
       OnClick = ControlChange
     end
@@ -123,6 +123,7 @@ object EditorPreferencesDialog: TEditorPreferencesDialog
       Top = 39
       Width = 367
       Height = 21
+      AutoComplete = False
       Anchors = [akLeft, akTop, akRight]
       ItemHeight = 13
       MaxLength = 1000

+ 2 - 2
forms/FileSystemInfo.dfm

@@ -185,9 +185,9 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
       object Label1: TLabel
         Left = 13
         Top = 13
-        Width = 22
+        Width = 25
         Height = 13
-        Caption = '&Path'
+        Caption = '&Path:'
         FocusControl = SpaceAvailablePathEdit
       end
       object SpaceAvailableView: TListView

+ 22 - 3
forms/FullSynchronize.cpp

@@ -143,7 +143,7 @@ int __fastcall TFullSynchronizeDialog::ActualCopyParamAttrs()
         break;
     }
   }
-  return Result;
+  return Result | cpaNoPreserveTime;
 }
 //---------------------------------------------------------------------------
 void __fastcall TFullSynchronizeDialog::ControlChange(TObject * /*Sender*/)
@@ -318,8 +318,13 @@ void __fastcall TFullSynchronizeDialog::TransferSettingsButtonClick(
 void __fastcall TFullSynchronizeDialog::CopyParamClick(TObject * Sender)
 {
   assert(FLAGCLEAR(FOptions, fsoDoNotUsePresets));
-  if (CopyParamListPopupClick(Sender, FCopyParams, FPreset, ActualCopyParamAttrs()))
+  // PreserveTime is forced for some settings, but avoid hard-setting it until
+  // user really confirms it on custom dialog
+  TCopyParamType ACopyParams = CopyParams;
+  if (CopyParamListPopupClick(Sender, ACopyParams, FPreset,
+        ActualCopyParamAttrs()))
   {
+    FCopyParams = ACopyParams;
     UpdateControls();
   }
 }
@@ -360,6 +365,13 @@ void __fastcall TFullSynchronizeDialog::SynchronizeByTimeSizeCheckClick(
   UpdateControls();
 }
 //---------------------------------------------------------------------------
+TCopyParamType __fastcall TFullSynchronizeDialog::GetCopyParams()
+{
+  TCopyParamType Result = FCopyParams;
+  Result.PreserveTime = true;
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall TFullSynchronizeDialog::SetCopyParams(const TCopyParamType & value)
 {
   FCopyParams = value;
@@ -371,6 +383,9 @@ void __fastcall TFullSynchronizeDialog::CopyParamGroupContextPopup(
 {
   if (FLAGCLEAR(FOptions, fsoDoNotUsePresets))
   {
+    // We pass in FCopyParams, although it may not be the exact copy param
+    // that will be used (because of Preservetime). The reason is to
+    // display checkbox next to user-selected preset
     CopyParamListPopup(CopyParamGroup->ClientToScreen(MousePos), FPresetsMenu,
       FCopyParams, FPreset, CopyParamClick, cplCustomize | cplCustomizeDefault);
     Handled = true;
@@ -380,8 +395,12 @@ void __fastcall TFullSynchronizeDialog::CopyParamGroupContextPopup(
 void __fastcall TFullSynchronizeDialog::CopyParamGroupDblClick(
   TObject * /*Sender*/)
 {
-  if (DoCopyParamCustomDialog(FCopyParams, ActualCopyParamAttrs()))
+  // PreserveTime is forced for some settings, but avoid hard-setting it until
+  // user really confirms it on cutom dialog
+  TCopyParamType ACopyParams = CopyParams;
+  if (DoCopyParamCustomDialog(ACopyParams, ActualCopyParamAttrs()))
   {
+    FCopyParams = ACopyParams;
     UpdateControls();
   }
 }

+ 1 - 1
forms/FullSynchronize.h

@@ -94,7 +94,7 @@ public:
   __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 };
+  __property TCopyParamType CopyParams = { read = GetCopyParams, write = SetCopyParams };
 
 protected:
   void __fastcall UpdateControls();

+ 95 - 95
forms/Glyphs.dfm

@@ -8,7 +8,7 @@ object GlyphsModule: TGlyphsModule
     Left = 32
     Top = 16
     Bitmap = {
-      494C01015C005E00040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C01015C005E00040010001000FFFFFFFFFF00FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000008001000001002000000000000080
       0100000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -906,129 +906,129 @@ object GlyphsModule: TGlyphsModule
       0000006633000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000002020200040404000404040004040
-      4000404040004040400040404000404040005050500000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000DDE0DE00CFBFB200CFBFB200DDE1DE00000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000080808000808080000000
-      0000000000000000000000000000000000007F7F7F00C0C0C000C0C0C000C0C0
-      C000C0C0C000808080006060600080808000A0A0A00060606000000000000000
+      00000000000000000000000000000000000030303000C0C0C000808080008080
+      8000808080008080800080808000808080008080800000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000084000000840000008400000084848400000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000DDE0DE00B77C5A00AF4A0100BC570100AF4A010099340100AB623C00D8D5
       CF00000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000808080000000
-      0000000000000000000000000000000000003F3F3F00AFAFAF007F7F7F007F7F
-      7F007F7F7F007F7F7F007F7F7F007F7F7F00CFCFCF0080808000000000000000
+      00000000000000000000000000000000000030303000FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0080808000808080008080800080808000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000008484840084000000840000000000000084000000000000000000
       000000000000000000000000000000000000000000000000000000000000DDE0
       DF00B0602D00C6610100B9540100B77D5A00CFBFB200E0ECEC00D8D5CF00CFBF
       B200000000000000000000000000000000000000000000000000000000000000
       000000000000000000000000000000000000FFFFFF0000000000808080000000
-      0000000000000000000000000000000000000000000000000000BFBFBF00BFBF
-      BF00BFBFBF00BFBFBF00BFBFBF0090909000404040005F5F5F00000000000000
+      0000000000000000000000000000000000000000000030303000808080008080
+      8000808080008080800080808000808080008080800080808000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000008400000084000000840000000000000000000000000000000000
       000000000000000000000000000000000000000000000000000000000000B66C
       3D00D16C0100C6610100C0917800000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000C0C0C0000000000000000000C0C0C000FFFFFF0000000000808080008080
-      8000C0C0C00000000000000000000000000000000000000000007F7F7F00FF00
-      00007F000000FF000000FF000000A0A0A0004040400000000000000000000000
+      8000C0C0C0000000000000000000000000000000000030303000C0C0C0008080
+      800080808000C0C0C000C0C0C000C0C0C0008080800000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000008400000084000000840000008484840000000000000000000000
       0000000000000000000000000000000000000000000000000000D7CBC200CA66
       0100DC770100B6510100DBD6D10000000000000000000000000000000000E1E3
       E000C09278000000000000000000000000000000000000000000000000000000
       000000000000C0C0C000FFFFFF00FFFFFF00FFFFFF00C0C0C000000000000000
-      00008080800080808000000000000000000000000000000000007F7F7F00FF00
-      00003F3F3F003F3F3F00BF000000A0A0A0004040400000000000000000000000
+      0000808080008080800000000000000000000000000030303000FFFFFF008000
+      000000FFFF0080000000FF000000C0C0C0008080800000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000008484840084000000840000008484840000000000000000000000
       0000000000000000000000000000000000000000000000000000C0917800E983
       0100E07B0100B75201000000000000000000000000000000000000000000AF66
       3D00A33E0100BA856A000000000000000000000000000000000000000000C0C0
       C000FFFFFF00FFFFFF00FFFFFF00FF000000FF000000FFFFFF00FFFFFF00C0C0
-      C0000000000080808000808080000000000000000000000000007F7F7F00FF00
-      0000FF0000003F3F3F0000BFBF00707070004040400000000000000000000000
+      C000000000008080800080808000000000000000000030303000FFFFFF00FF00
+      00008000000000FFFF0080000000808080008080800000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000008484840084000000840000008400000000000000000000000000
       000000000000000000000000000000000000A33E0100B6643100B6643100F690
       0100E47F0100B7520100A33E0100A33E01000000000000000000BA866A00A33E
       0100CC670100A33E0100C8A89500000000000000000080808000FFFFFF00FFFF
       FF00FFFFFF00FFFFFF00FFFFFF0080808000FF000000FFFFFF00FFFFFF00FFFF
-      FF00C0C0C0000000000080808000C0C0C0000000000000000000BFBFBF007F7F
-      7F007F7F7F007F7F7F003F7F7F0000BFBF00003F3F0040404000404040004040
-      4000404040004040400030303000000000000000000000000000000000000000
+      FF00C0C0C0000000000080808000C0C0C0000000000030303000FFFFFF00FF00
+      0000800000008000000000FFFF0000FFFF000000000000000000808080008080
+      8000808080008080800000000000000000000000000000000000000000000000
       0000000000000000000084848400840000008400000084848400000000000000
       000000000000000000000000000000000000E4EEEE00A33E0100F29B2C00F993
       0100E9840100D9740100A33E0100C49C860000000000C8A89500A33E0100CC67
       0100CC670100CC670100A33E0100D7CBC20080808000C0C0C000FFFFFF00FFFF
       FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00C0C0C00000000000808080000000000000000000303030006060
-      600060606000007F7F00007F7F0000BFBF0000FFFF00306F6F00808080006060
-      600060606000B0B0B00080808000202020000000000000000000000000000000
+      FF00FFFFFF00C0C0C00000000000808080000000000030303000FFFFFF008080
+      800000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000000000808080008080
+      8000808080008080800080808000000000000000000000000000000000000000
       0000000000000000000000000000840000008400000084000000000000000000
       00000000000000000000000000000000000000000000E4E4E100A33E0100F791
       0100ED880100D26D0100BA7E5B0000000000DACDC300A33E0100BF5A0100CC67
       0100CC670100C9640100BF5A0100A33E010080808000FFFFFF00FFFFFF00FFFF
       FF00FFFFFF00FFFFFF00FFFFFF00FF000000FF000000FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF0000000000808080000000000000000000000000000000
-      0000000000000000000000BFBF0000FFFF00007F7F00007F7F00003F3F007F7F
-      7F007F7F7F009F9F9F00AFAFAF00404040000000000000000000000000000000
+      FF00FFFFFF00FFFFFF0000000000808080000000000000000000303030003030
+      3000303030003030300000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000
+      0000808080008080800080808000000000000000000000000000000000000000
       0000000000008400000000000000840000008400000084000000000000000000
       0000000000000000000000000000000000000000000000000000DACDC300A33E
       0100EC870100B1612E00E3E4E100000000000000000000000000C59D8700BF5A
       0100CC670100B7520100000000000000000080808000FFFFFF00FFFFFF00FFFF
       FF00FFFFFF00FFFFFF00FFFFFF0080808000FF000000FF000000FFFFFF00FFFF
       FF00FFFFFF00FFFFFF0000000000808080000000000000000000000000000000
-      0000000000000000000000000000007F7F0000BFBF007F7F7F00BFBFBF00BFBF
-      BF00AFAFAF00606060005F5F5F00202020000000000000000000000000000000
+      000000000000000000003030300000FFFF0000FFFF008080800080808000C0C0
+      C000C0C0C0008080800000000000000000000000000000000000000000000000
       0000000000008484840084000000840000008400000084848400000000000000
       000000000000000000000000000000000000000000000000000000000000D4C1
       B400A3451000E3E4E10000000000000000000000000000000000D3C1B400BF5A
       0100CC670100B7520100000000000000000080808000FFFFFF00FFFFFF00FFFF
       FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0080808000FF00000080808000FFFF
       FF00FFFFFF00FFFFFF0000000000808080000000000000000000000000000000
-      00000000000000000000000000007F7F7F00003F3F0000BFBF00BF000000FF00
-      0000DF6060008080800000000000000000000000000000000000000000000000
+      0000000000000000000030303000808080008000000000FFFF0080000000FF00
+      0000C0C0C0008080800000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000BB866A00C964
       0100C9640100B46A3D00000000000000000080808000FFFFFF00FFFFFF00FFFF
       FF00FFFFFF00FF000000FF000000FFFFFF00FFFFFF00FF000000FF000000FFFF
       FF00FFFFFF00C0C0C00000000000000000000000000000000000000000000000
-      00000000000000000000000000007F7F7F007F0000007F000000007F7F00BF00
-      0000DF6060008080800000000000000000000000000000000000000000000000
+      0000000000000000000030303000FFFFFF00FF0000008000000000FFFF008000
+      0000C0C0C0008080800000000000000000000000000000000000000000000000
       0000000000000000000084848400840000008400000084848400000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000000000000000000000C69D8700B14C0100CC67
       0100B1521000DACDC30000000000000000000000000080808000FFFFFF00FFFF
       FF00FFFFFF0080808000FF000000FFFFFF00FFFFFF00FF000000FF000000FFFF
       FF00FFFFFF000000000080808000000000000000000000000000000000000000
-      00000000000000000000000000007F7F7F007F000000FF000000BF000000BF00
-      0000DF6060008080800000000000000000000000000000000000000000000000
+      0000000000000000000030303000FFFFFF00FF000000FF000000800000008000
+      0000C0C0C0008080800000000000000000000000000000000000000000000000
       0000000000000000000084000000840000008400000084000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       000000000000BB866A00AD633D00C1784100BC5D1000D5710100CA650100AD55
       1F00D9CDC3000000000000000000000000000000000080808000FFFFFF00FFFF
       FF00FFFFFF00FFFFFF00FF000000FF000000FF000000FF000000FFFFFF00FFFF
       FF00C0C0C0000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000007F7F7F007F7F7F007F7F7F007F7F7F007F7F
-      7F00AFAFAF008080800000000000000000000000000000000000000000000000
+      0000000000000000000030303000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00C0C0C0008080800000000000000000000000000000000000000000000000
       0000000000000000000084848400840000008400000084848400000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000DACEC400C2937900C5814C00BC866A00CBAA97000000
       0000000000000000000000000000000000000000000000000000808080008080
       8000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000006060600060606000606060006060
-      6000606060005050500000000000000000000000000000000000000000000000
+      0000000000000000000000000000303030003030300030303000303030003030
+      3000303030003030300000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -2186,129 +2186,129 @@ object GlyphsModule: TGlyphsModule
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000084
-      8400008484000084840000848400008484000084840000848400008484000084
-      8400008484000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000001821
       2100182121001821210018212100182121001821210018212100182121001821
-      210018212100182121001821210018212100000000000000000000000000C6C6
-      C600FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00C6C6C60000000000000000000000000000000000000000000000
+      210018212100182121001821210018212100000000000000000000000000FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000006363000063
       6300006363000063630000636300006363000063630000636300006363000063
-      6300006363000063630018212100182121000000000000000000000000008484
-      8400FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF00FFFFFF00FFFF
-      FF00FFFFFF00C6C6C60000000000000000000000000000000000000000008484
+      630000636300006363001821210018212100000000000000000000000000FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0080008000FFFF
+      FF00FFFFFF00FFFFFF0000000000000000000000000000000000000000008484
       8400CECECE00CECECE00CECECE00CECECE00CECECE00CECECE00CECECE00CECE
       CE00CECECE00CECECE00CECECE00000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000006363009CFF
       FF00009CCE0000CEFF00009CCE0000CEFF00009CCE00009CCE00009CCE00639C
-      9C00009CCE00006363001821210018212100000000000000000000000000FFFF
-      FF00C6C6C600FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF00C6C6C600FFFF
-      FF00FFFFFF00C6C6C60000000000000000000000000000000000000000008484
+      9C00009CCE000063630018212100182121000000000000000000C0C0C0000000
+      0000FFFFFF00C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0
+      C000C0C0C000FFFFFF0000000000000000000000000000000000000000008484
       8400CECECE004A4A4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A
       4A004A4A4A004A4A4A00CECECE00000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000000000000000000000006363009CFFFF0000CE
       FF0000CEFF00009CCE0000CEFF00009CCE0000CEFF00009CCE00009CCE00009C
       CE00639C9C00182121000063630018212100000000000000000000000000FFFF
-      FF00C6C6C600FFFFFF00FFFFFF00FFFFFF00FFFFFF0084848400C6C6C600FFFF
-      FF00FFFFFF00C6C6C60000000000000000000000000000000000000000008484
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00800080008686
+      8600FFFFFF00FFFFFF0000000000000000000000000000000000000000008484
       8400CECECE00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
       FF00FFFFFF00FFFFFF00CECECE00000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000000000000000000000006363009CFFFF00FFFF
       FF0000CEFF0000CEFF0000CEFF0000CEFF00009CCE0000CEFF00009CCE00009C
-      CE00009CCE00182121000063630018212100000000000000000000000000C6C6
-      C600FFFFFF00FFFFFF00FFFFFF00C6C6C600FFFFFF000000000084848400FFFF
-      FF00FFFFFF00C6C6C60000000000000000000000000000000000000000000000
+      CE00009CCE001821210000636300182121000000000000000000C0C0C0000000
+      0000FFFFFF00C0C0C000C0C0C00086868600C0C0C000C0C0C000C0C0C0008000
+      800086868600FFFFFF0000000000000000000000000000000000000000000000
       CE00FFFFFF004A4A4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A
       4A004A4A4A004A4A4A00CECECE00000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       000000000000000000000000000000000000006363009CFFFF00FFFFFF0000CE
       FF00FFFFFF0000CEFF00009CCE0000CEFF0000CEFF00009CCE0000CEFF00009C
-      CE001821210000CEFF0000CEFF00182121000000000000000000000000008484
-      8400FFFFFF00C6C6C600FFFFFF00FFFFFF0084848400848484000000FF00C6C6
-      C600FFFFFF00C6C6C60000000000000000000000CE0000000000000000008484
+      CE001821210000CEFF0000CEFF0018212100000000000000000000000000FFFF
+      FF00FFFFFF00FFFFFF000000FF00FFFFFF00FFFFFF0080008000868686008000
+      8000FFFFFF00FFFFFF0000000000000000000000CE0000000000000000008484
       8400FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
       FF00FFFFFF00FFFFFF00CECECE00000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       000000000000000000000000000000000000006363009CFFFF0000CEFF00FFFF
       FF0000CEFF00FFFFFF0000CEFF0000CEFF00009CCE0000CEFF00009CCE0000CE
-      FF00000000000000000000CEFF0018212100000000000000000000000000FFFF
-      FF00C6C6C600FFFFFF00C6C6C600C6C6C600000084000000000000008400FFFF
-      FF00FFFFFF00C6C6C6000000000000000000000000000000CE00000000000000
+      FF00000000000000000000CEFF00182121000000000000000000C0C0C0000000
+      0000FFFFFF00C0C0C000FFFFFF0086868600C0C0C000C0C0C00080008000C0C0
+      C000C0C0C000FFFFFF000000000000000000000000000000CE00000000000000
       CE00FFFFFF000000CE00DEDEDE00DEDEDE00DEDEDE00CECECE00CECECE000084
       00000084000000840000CECECE00000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000063630000636300006363000063
       6300006363000063630000636300006363000063630000636300006363000063
-      6300CECECE000000000000CEFF0018212100000000000000000000000000C6C6
-      C600FFFFFF00FFFFFF0000FFFF00C6C6C600FFFFFF00FFFFFF00FFFFFF00C6C6
-      C600FFFFFF00C6C6C600000000000000000000000000000000000000CE000000
+      6300CECECE000000000000CEFF0018212100000000000000000000000000FFFF
+      FF00FFFFFF00FFFFFF000000FF0086868600FFFFFF00FFFFFF00FFFFFF008686
+      8600FFFFFF00FFFFFF00000000000000000000000000000000000000CE000000
       9C000000CE00FFFFFF00FFFFFF00FFFFFF00FFFFFF00DEDEDE00CECECE0000FF
       000000FF000000FF0000CECECE00000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000084848400CECECE004A4A
       4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A
-      4A00CECECE000000000000CEFF00182121000000000000000000000000008484
-      8400FFFFFF00C6C6C600C6C6C600C6C6C600C6C6C600C6C6C60084848400C6C6
-      C600FFFFFF00C6C6C60000000000000000000000CE000000CE0000009C00FFFF
+      4A00CECECE000000000000CEFF00182121000000000000000000C0C0C0000000
+      0000FFFFFF00C0C0C0000000FF0086868600C0C0C000C0C0C000FF0000008686
+      8600C0C0C000FFFFFF0000000000000000000000CE000000CE0000009C00FFFF
       FF0000009C000000000000000000000000008484840084848400848484008484
       8400848484008484840084848400000000000000FF0000009C00000000000000
       00000000FF0000009C0000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000084848400CECECE00FFFF
       FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
       FF00CECECE00000000009CFFFF0018212100000000000000000000000000FFFF
-      FF00C6C6C600FFFFFF0000FFFF00C6C6C600FFFFFF00FFFFFF00FF000000C6C6
-      C600FFFFFF00C6C6C600000000000000000000000000000000000000CE000000
+      FF00FFFFFF00FFFFFF000000FF0086868600FFFFFF00FFFFFF00FF0000008686
+      8600FFFFFF00FFFFFF00000000000000000000000000000000000000CE000000
       9C000000CE000000000000000000000000000000000000000000000000000000
       000000000000000000000000000000000000000000000000FF0000009C000000
       FF0000009C000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000084848400CECECE004A4A
       4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A4A004A4A
-      4A00CECECE00000000000063630000000000000000000000000000000000C6C6
-      C600FFFFFF00FFFFFF0000FFFF00C6C6C600C6C6C600FFFFFF00FF000000C6C6
-      C600FFFFFF00C6C6C6000000000000000000000000000000CE00000000000000
+      4A00CECECE000000000000636300000000000000000000000000C0C0C0000000
+      0000FFFFFF00C0C0C0000000FF00C0C0C000C0C0C000C0C0C000FF000000C0C0
+      C000C0C0C000FFFFFF000000000000000000000000000000CE00000000000000
       CE00000000000000CE0000000000000000000000000000000000000000000000
       00000000000000000000000000000000000000000000000000000000FF000000
       9C00000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000084848400CECECE00FFFF
       FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00CECECE000000000000000000000000000000000000000000000000008484
-      8400FFFFFF00C6C6C60000FFFF00C6C6C600FFFFFF00C6C6C60084848400C6C6
-      C600FFFFFF00C6C6C60000000000000000000000CE0000000000000000000000
+      FF00CECECE00000000000000000000000000000000000000000000000000FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008686
+      8600FFFFFF00FFFFFF0000000000000000000000CE0000000000000000000000
       000000000000000000000000CE00000000000000000000000000000000000000
       000000000000000000000000000000000000000000000000FF0000009C000000
       FF0000009C000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000084848400CECECE00DEDE
       DE00DEDEDE00DEDEDE00DEDEDE00CECECE00CECECE0000840000008400000084
-      0000CECECE00000000000000000000000000000000000000000000000000FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF000000FFFF
-      FF00FFFFFF00C6C6C60000000000000000000000000000000000000000000000
+      0000CECECE000000000000000000000000000000000000000000C0C0C0000000
+      0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF000000FFFF
+      FF00FFFFFF00FFFFFF0000000000000000000000000000000000000000000000
       CE00000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000FF0000009C00000000000000
       00000000FF0000009C0000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000084848400CECECE00CECE
       CE00CECECE00CECECE00CECECE00CECECE00CECECE0000FF000000FF000000FF
-      0000CECECE00000000000000000000000000000000000000000000000000C6C6
-      C600FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00C6C6C60000000000000000000000000000000000000000000000
+      0000CECECE00000000000000000000000000000000000000000000000000FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000084848400848484008484
       8400848484008484840084848400848484008484840084848400848484008484
-      8400848484000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      8400848484000000000000000000000000000000000000000000868686008686
+      8600868686008686860086868600868686008686860086868600868686008686
+      8600868686008686860000000000000000000000000000000000000000000000
       CE00000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -3112,11 +3112,11 @@ object GlyphsModule: TGlyphsModule
       E0030000F3FF8FFFC0010000F1FF87F780010000F0FFC7EF80000000F07FE3CF
       00000000F03FF19F00000000F01FF83F00000000F00FFC7F00000000F01FF83F
       00010000F03FF19F80010000F07FC3CF80030000F0FF87E7C0070000F1FF8FFB
-      E00F0000F3FFFFFFF83FFFFFF7FFFFFF003FFFFFFC3FFF9F001FFC3FF00FFF1F
-      001FF8BFE00FFE1F801FF8FFE1FFF007807FF87FC1E7E003807FF87FC3E3C001
-      807FF87F00C180008001FC3F00800000C000FE3F81000000F800FA3FC1C30000
-      FC00F83FE3C30000FE01FFFFFFC30001FE01FC3FFF838001FE01FC3FF8078003
-      FE01FC3FFC1FC007FE01FFFFFFFFF01F0003FFFFFFFFFE7F00030015FFFFF00F
+      E00F0000F3FFFFFFF83FFFFFF7FFFFFF807FFFFFFC3FFF9F003FFC3FF00FFF1F
+      001FF8BFE00FFE1F801FF8FFE1FFF007803FF87FC1E7E003803FF87FC3E3C001
+      8003F87F00C180008001FC3F008000008000FE3F81000000C000FA3FC1C30000
+      FC01F83FE3C30000FC01FFFFFFC30001FC01FC3FFF838001FC01FC3FF8078003
+      FC01FC3FFC1FC007FE03FFFFFFFFF01F0003FFFFFFFFFE7F00030015FFFFF00F
       00030000FFFFE00700030000FFFFC0030003E007E000C0030003E007E0008001
       0003E007600080018003E007200080018003E007200080018003E00760008001
       8003E007E00080018003E007E000C0038003FFFFE000C0038007F81FFFFFE001
@@ -3152,10 +3152,10 @@ object GlyphsModule: TGlyphsModule
       F42FE000FFFFCCF1E007C0008003CFE0C003C0000001C0FBC00780000000CCFB
       000180000000E1FB000100000000FFFB000100000000FFFB000100000000E0FB
       C00780008000CCFBC0038000C001CCFBC0078001FFFFE0FBE00FC07FFFFFFCFB
-      FC3FE0FFFFFFE1FBFC3FFFFFFFFFFFFFC001FFFFFFFFE0008001E000FFFFC000
-      8001E000EAAAC0008001E000FFFF80008001E000ED5680008001E000FFFF0000
-      80016000ED5600008001A000FFFF00008001C000EFD680008001000033FF8000
-      8001C7FF86AA80018001ABFFCFFF800380017DFF87FF80038001EFFF33FF8003
+      FC3FE0FFFFFFE1FBFC3FFFFFFFFFFFFFC001FFFFFFFFE000C001E000FFFFC000
+      C001E000EAAAC0008001E000FFFF8000C001E000ED5680008001E000FFFF0000
+      C0016000ED5600008001A000FFFF0000C001C000EFD680008001000033FF8000
+      C001C7FF86AA80018001ABFFCFFF8003C0017DFF87FF80038001EFFF33FF8003
       C001FFFFFFFF8003C003EFFFFFFFFFFFFFFFFFFFFFFFFFFF5555555555555555
       FFFFFFFFFFFFFFFF7FFD7EFD7EFD7FFDFFFFFEFFFCFFEC7F7FFD7D7D783D73BD
       FFFFFD7FFCDFF3DF7FFD7BBD7EDD6DEDE00FFBBFF7DFEEEF7FFD77DD76FD6F6D
@@ -3180,14 +3180,13 @@ object GlyphsModule: TGlyphsModule
       FC01FC018FFFEBFFFC01FC0187F7FFFF00015401C7EFEA7F0001A801E3CFFE3F
       00015401F19FEA1F0001A801F83FFE0F00035403FC7FFE070007A807F83FFF03
       000F500FF19FFF0300F7AAF7C3CFFF8701E355E387E7FF8F03C1ABC18FFBFFFF
-      FEF7FEF7FFFFFFFFFF0FFF0FFFFFFFFF00000000000000000000000000000000
-      000000000000}
+      FEF7FEF7FFFFFFFFFF0FFF0FFFFFFFFF}
   end
   object SessionImages: TImageList
     Left = 32
     Top = 80
     Bitmap = {
-      494C010102000400040010001000FFFFFFFFFF00FFFFFFFFFFFFFFFF424D3600
+      494C010102000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000001000000001002000000000000010
       0000000000000000000000000000000000000000000000000000000000000000
       00000000000000000000000000009C630000000000009C63000000000000CE9C
@@ -3323,7 +3322,8 @@ object GlyphsModule: TGlyphsModule
       FFCFC00300000000FC07C00300000000F803C003000000000001C00300000000
       0011C003000000000011C003000000000011C003000000000011E00300000000
       0011F007000000000011F3CF000000000011F3CF000000000001F58F00000000
-      8803FA1F00000000FC07FC3F00000000}
+      8803FA1F00000000FC07FC3F0000000000000000000000000000000000000000
+      000000000000}
   end
   object QueueImages: TImageList
     Left = 136

+ 1 - 1
forms/ImportSessions.dfm

@@ -11,7 +11,7 @@ object ImportSessionsDialog: TImportSessionsDialog
   Color = clBtnFace
   ParentFont = True
   OldCreateOrder = True
-  Position = poOwnerFormCenter
+  Position = poMainFormCenter
   OnClose = FormClose
   OnShow = FormShow
   DesignSize = (

+ 23 - 1
forms/InputDlg.cpp

@@ -10,15 +10,27 @@
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
+struct TInputDialogToken
+{
+  TInputDialogInitialize OnInitialize;
+  TInputDialogData Data;
+};
+//---------------------------------------------------------------------------
 void __fastcall InputDialogHelp(void * /*Data*/, TObject * Sender)
 {
   TControl * Control = dynamic_cast<TControl *>(Sender);
   Application->HelpKeyword(Control->Parent->HelpKeyword);
 }
 //---------------------------------------------------------------------------
+void __fastcall InputDialogShow(void * Data, TObject * Sender)
+{
+  TInputDialogToken & Token = *static_cast<TInputDialogToken *>(Data);
+  Token.OnInitialize(Sender, &Token.Data);
+}
+//---------------------------------------------------------------------------
 bool __fastcall InputDialog(const AnsiString ACaption,
   const AnsiString APrompt, AnsiString & Value, AnsiString HelpKeyword,
-  TStrings * History, bool PathInput)
+  TStrings * History, bool PathInput, TInputDialogInitialize OnInitialize)
 {
   TForm * Form;
   TLabel * Prompt;
@@ -27,11 +39,20 @@ bool __fastcall InputDialog(const AnsiString ACaption,
   TPoint DialogUnits;
   int ButtonTop, ButtonWidth, ButtonHeight;
   bool Result = False;
+  TInputDialogToken Token;
   Form = new TForm(Application, 0); // bypass the VCL streaming (for Salamander)
   try
   {
     SetCorrectFormParent(Form);
     UseSystemSettingsPre(Form);
+    if (OnInitialize != NULL)
+    {
+      Token.OnInitialize = OnInitialize;
+      TNotifyEvent OnShow;
+      ((TMethod *)&OnShow)->Data = &Token;
+      ((TMethod *)&OnShow)->Code = InputDialogShow;
+      Form->OnShow = OnShow;
+    }
     Form->Canvas->Font = Form->Font;
     DialogUnits = GetAveCharSize(Form->Canvas);
     Form->BorderStyle = bsDialog;
@@ -61,6 +82,7 @@ bool __fastcall InputDialog(const AnsiString ACaption,
       Edit->Text = Value;
       Edit->SelectAll();
       Edit->MaxLength = 255;
+      Token.Data.Edit = Edit;
       EditControl = Edit;
     }
     else

+ 0 - 84
forms/Licence.cpp

@@ -1,84 +0,0 @@
-//---------------------------------------------------------------------------
-#include <vcl.h>
-#pragma hdrstop
-
-#include <Common.h>
-#include <TextsWin.h>
-
-#include <VCLCommon.h>
-#include "WinInterface.h"
-#include "Licence.h"
-#include "Tools.h"
-//---------------------------------------------------------------------------
-#pragma package(smart_init)
-#pragma resource "*.dfm"
-//---------------------------------------------------------------------------
-AnsiString LicenceStr[2] = { "LICENCE", "LICENCE_PUTTY" };
-//---------------------------------------------------------------------------
-void __fastcall DoLicenceDialog(TLicence Licence)
-{
-  TLicenceDialog *LicenceDialog = NULL;
-  try
-  {
-    LicenceDialog = new TLicenceDialog(Application);
-    LicenceDialog->Licence = Licence;
-    LicenceDialog->ShowModal();
-  }
-  __finally
-  {
-    delete LicenceDialog;
-  }
-}
-//---------------------------------------------------------------------------
-void __fastcall DoLicenceDialog(const AnsiString LicenceText)
-{
-  TLicenceDialog *LicenceDialog = NULL;
-  try
-  {
-    LicenceDialog = new TLicenceDialog(Application);
-    LicenceDialog->LicenceText = LicenceText;
-    LicenceDialog->ShowModal();
-  }
-  __finally
-  {
-    delete LicenceDialog;
-  }
-}
-//---------------------------------------------------------------------------
-__fastcall TLicenceDialog::TLicenceDialog(TComponent* Owner)
-        : TForm(Owner)
-{
-  FLicence = lcNoLicence;
-  UseSystemSettings(this);
-}
-//---------------------------------------------------------------------------
-void __fastcall TLicenceDialog::SetLicence(TLicence value)
-{
-  if (FLicence != value)
-  {
-    FLicence = value;
-    TStrings * LicenceList = new TStringList();
-    try
-    {
-      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;
-    }
-  }
-}
-//---------------------------------------------------------------------------
-void __fastcall TLicenceDialog::SetLicenceText(AnsiString value)
-{
-  LicenceMemo->Lines->Text = value;
-}
-//---------------------------------------------------------------------------
-AnsiString __fastcall TLicenceDialog::GetLicenceText()
-{
-  return LicenceMemo->Lines->Text;
-}

+ 0 - 29
forms/Licence.h

@@ -1,29 +0,0 @@
-//---------------------------------------------------------------------------
-#ifndef LicenceH
-#define LicenceH
-//---------------------------------------------------------------------------
-#include <Classes.hpp>
-#include <Controls.hpp>
-#include <StdCtrls.hpp>
-#include <Forms.hpp>
-#include <Mask.hpp>
-
-#include "WinInterface.h"
-//---------------------------------------------------------------------------
-class TLicenceDialog : public TForm
-{
-__published:
-  TButton *CloseButton;
-  TMemo *LicenceMemo;
-public:
-  __fastcall TLicenceDialog(TComponent* Owner);
-  __property TLicence Licence  = { read=FLicence, write=SetLicence };
-  __property AnsiString LicenceText = { read = GetLicenceText, write = SetLicenceText };
-private:
-  TLicence FLicence;
-  AnsiString __fastcall GetLicenceText();
-  void __fastcall SetLicence(TLicence value);
-  void __fastcall SetLicenceText(AnsiString value);
-};
-//---------------------------------------------------------------------------
-#endif

+ 50 - 0
forms/License.cpp

@@ -0,0 +1,50 @@
+//---------------------------------------------------------------------------
+#include <vcl.h>
+#pragma hdrstop
+
+#include <Common.h>
+#include <TextsWin.h>
+
+#include <VCLCommon.h>
+#include "WinInterface.h"
+#include "License.h"
+#include "Tools.h"
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma resource "*.dfm"
+//---------------------------------------------------------------------------
+AnsiString LicenseStr[2] = { "LICENSE", "LICENSE_PUTTY" };
+//---------------------------------------------------------------------------
+void __fastcall DoLicenseDialog(TLicense License)
+{
+  TLicenseDialog * LicenseDialog = NULL;
+  try
+  {
+    LicenseDialog = new TLicenseDialog(Application, License);
+    LicenseDialog->ShowModal();
+  }
+  __finally
+  {
+    delete LicenseDialog;
+  }
+}
+//---------------------------------------------------------------------------
+__fastcall TLicenseDialog::TLicenseDialog(TComponent * Owner, TLicense License)
+  : TForm(Owner)
+{
+  UseSystemSettings(this);
+
+  TStrings * LicenseList = new TStringList();
+  try
+  {
+    LicenseList->Text = ReadResource(LicenseStr[License]);
+    assert(LicenseList->Count > 0);
+    Caption = FMTLOAD(LICENSE_CAPTION, (LicenseList->Strings[0]));
+    LicenseList->Delete(0);
+    LicenseMemo->Lines->Text = LicenseList->Text;
+  }
+  __finally
+  {
+    delete LicenseList;
+  }
+}

+ 4 - 4
forms/Licence.dfm → forms/License.dfm

@@ -1,16 +1,16 @@
-object LicenceDialog: TLicenceDialog
+object LicenseDialog: TLicenseDialog
   Left = 413
   Top = 230
   ActiveControl = CloseButton
   BorderIcons = [biSystemMenu]
   BorderStyle = bsDialog
-  Caption = 'Licence'
+  Caption = 'License'
   ClientHeight = 320
   ClientWidth = 504
   Color = clBtnFace
   ParentFont = True
   OldCreateOrder = True
-  Position = poOwnerFormCenter
+  Position = poMainFormCenter
   DesignSize = (
     504
     320)
@@ -28,7 +28,7 @@ object LicenceDialog: TLicenceDialog
     ModalResult = 1
     TabOrder = 0
   end
-  object LicenceMemo: TMemo
+  object LicenseMemo: TMemo
     Left = 8
     Top = 8
     Width = 489

+ 23 - 0
forms/License.h

@@ -0,0 +1,23 @@
+//---------------------------------------------------------------------------
+#ifndef LicenseH
+#define LicenseH
+//---------------------------------------------------------------------------
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <Mask.hpp>
+
+#include "WinInterface.h"
+//---------------------------------------------------------------------------
+class TLicenseDialog : public TForm
+{
+__published:
+  TButton * CloseButton;
+  TMemo * LicenseMemo;
+
+public:
+  __fastcall TLicenseDialog(TComponent * Owner, TLicense License);
+};
+//---------------------------------------------------------------------------
+#endif

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