Martin Prikryl 21 years ago
parent
commit
73d181ad04
76 changed files with 2491 additions and 812 deletions
  1. 4 4
      DragExt.bpr
  2. BIN
      DragExt.res
  3. 4 3
      Putty.bpr
  4. 1 1
      ScpCore.bpr
  5. 10 8
      WinSCP3.bpr
  6. BIN
      WinSCP3.res
  7. 3 3
      components/UnixDirView.cpp
  8. 1 0
      components/UnixDirView.h
  9. 15 22
      core/Configuration.cpp
  10. 6 4
      core/Configuration.h
  11. 9 4
      core/CopyParam.cpp
  12. 3 2
      core/CopyParam.h
  13. 1 0
      core/FileOperationProgress.h
  14. 12 3
      core/Net.cpp
  15. 2 0
      core/PuttyIntf.h
  16. 36 9
      core/Queue.cpp
  17. 5 0
      core/Queue.h
  18. 8 2
      core/RemoteFiles.cpp
  19. 4 5
      core/ScpFileSystem.cpp
  20. 36 2
      core/SecureShell.cpp
  21. 8 0
      core/SecureShell.h
  22. 26 0
      core/SessionData.cpp
  23. 6 0
      core/SessionData.h
  24. 27 9
      core/SftpFileSystem.cpp
  25. 22 15
      core/Terminal.cpp
  26. 8 5
      core/Terminal.h
  27. 81 109
      forms/Copy.cpp
  28. 9 19
      forms/Copy.h
  29. 87 430
      forms/CustomScpExplorer.cpp
  30. 0 3
      forms/CustomScpExplorer.dfm
  31. 6 13
      forms/CustomScpExplorer.h
  32. 1 0
      forms/FileSystemInfo.cpp
  33. 36 16
      forms/FileSystemInfo.dfm
  34. 2 0
      forms/FileSystemInfo.h
  35. 1 1
      forms/ImportSessions.cpp
  36. 2 2
      forms/ImportSessions.h
  37. 15 2
      forms/Login.cpp
  38. 22 13
      forms/Login.dfm
  39. 2 0
      forms/Login.h
  40. 18 7
      forms/Preferences.cpp
  41. 46 30
      forms/Preferences.dfm
  42. 2 0
      forms/Preferences.h
  43. 41 6
      forms/ScpCommander.cpp
  44. 1 1
      forms/ScpCommander.dfm
  45. 5 3
      forms/ScpCommander.h
  46. 4 2
      forms/ScpExplorer.cpp
  47. 1 1
      forms/ScpExplorer.dfm
  48. 2 2
      forms/ScpExplorer.h
  49. 1 0
      forms/Symlink.h
  50. 2 2
      forms/Synchronize.cpp
  51. 1 0
      general/filemanager toolset/DirView.pas
  52. 14 0
      general/moje komponenty/filemanager toolset/CustomDirView.pas
  53. 2 1
      packages/filemng/DirView.hpp
  54. 3 0
      packages/my/filemng/CustomDirView.hpp
  55. 183 0
      putty/BUFFER.C
  56. 12 0
      putty/CONFIG.C
  57. 27 14
      putty/MAKEFILE.VC
  58. 8 0
      putty/SETTINGS.C
  59. 555 4
      putty/SSH.C
  60. 6 0
      putty/SSH_.C
  61. 4 0
      putty/WINHELP.H
  62. 44 0
      putty/buffer.h
  63. 379 0
      putty/gssapiw.h
  64. 4 0
      putty/putty.org.h
  65. 3 6
      release/winscpsetup.iss
  66. 2 0
      resource/TextsWin.h
  67. 2 0
      resource/TextsWin1.rc
  68. 89 1
      windows/GUIConfiguration.cpp
  69. 28 0
      windows/GUIConfiguration.h
  70. 423 0
      windows/QueueController.cpp
  71. 45 0
      windows/QueueController.h
  72. 1 2
      windows/TerminalManager.cpp
  73. 0 7
      windows/WinConfiguration.cpp
  74. 0 3
      windows/WinConfiguration.h
  75. 7 6
      windows/WinInterface.h
  76. 5 5
      windows/WinMain.cpp

+ 4 - 4
DragExt.bpr

@@ -61,8 +61,8 @@ IncludeVerInfo=1
 AutoIncBuild=1
 MajorVer=1
 MinorVer=1
-Release=0
-Build=34
+Release=1
+Build=36
 Debug=0
 PreRelease=0
 Special=0
@@ -74,13 +74,13 @@ CodePage=1252
 [Version Info Keys]
 CompanyName=Martin Prikryl
 FileDescription=Drag&Drop shell extension for WinSCP
-FileVersion=1.1.0.34
+FileVersion=1.1.1.36
 InternalName=dragext
 LegalCopyright=(c) 2004 Martin Prikryl
 LegalTrademarks=
 OriginalFilename=dragext.dll
 ProductName=WinSCP
-ProductVersion=3.6.0.0
+ProductVersion=3.6.1.0
 Comments=
 WWW=http://winscp.sourceforge.net/
 

BIN
DragExt.res


+ 4 - 3
Putty.bpr

@@ -4,8 +4,8 @@
   <MACROS>
     <VERSION value="BCB.06.00"/>
     <PROJECT value="lib\Putty.lib"/>
-    <OBJFILES value="putty\BE_NONE.obj putty\CMDLINE.obj putty\INT64.obj 
-      putty\LOGGING.obj putty\MISC.obj putty\NOISE.obj 
+    <OBJFILES value="putty\BE_NONE.obj putty\BUFFER.obj putty\CMDLINE.obj 
+      putty\INT64.obj putty\LOGGING.obj putty\MISC.obj putty\NOISE.obj 
       putty\PAGEANTC.obj putty\PORTFWD.obj putty\PPROXY.obj 
       putty\PROXY.obj putty\SETTINGS.obj putty\SSH_.obj putty\SSHAES.obj 
       putty\SSHBLOWF.obj putty\SSHBN.obj putty\SSHCRC.obj 
@@ -27,7 +27,7 @@
     <PATHRC value=".;"/>
     <PATHASM value=".;"/>
     <LINKER value="TLib"/>
-    <USERDEFINES value="PUTTY_LIB;_WINDOWS;_MSC_VER=1000"/>
+    <USERDEFINES value="PUTTY_LIB;GSSAPI;_WINDOWS;_MSC_VER=1000"/>
     <SYSDEFINES value="_RTLDLL;NO_STRICT"/>
     <MAINSOURCE value="Putty.bpf"/>
     <INCLUDEPATH value="putty;putty\CHARSET;$(BCB)\include;$(BCB)\include\vcl"/>
@@ -51,6 +51,7 @@
   <FILELIST>
       <FILE FILENAME="Putty.bpf" FORMNAME="" UNITNAME="Putty" CONTAINERID="BPF" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\BE_NONE.C" FORMNAME="" UNITNAME="BE_NONE.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="putty\BUFFER.C" FORMNAME="" UNITNAME="BUFFER" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\CMDLINE.C" FORMNAME="" UNITNAME="CMDLINE.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\INT64.C" FORMNAME="" UNITNAME="INT64.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="putty\LOGGING.C" FORMNAME="" UNITNAME="LOGGING.C" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>

+ 1 - 1
ScpCore.bpr

@@ -24,7 +24,7 @@
     <PATHRC value=".;"/>
     <PATHASM value=".;"/>
     <LINKER value="TLib"/>
-    <USERDEFINES value="USE_COMPATIBLE_THREAD;_WINDOWS"/>
+    <USERDEFINES value="USE_COMPATIBLE_THREAD;GSSAPI;_WINDOWS"/>
     <SYSDEFINES value="NO_STRICT"/>
     <MAINSOURCE value="ScpCore.bpf"/>
     <INCLUDEPATH value="windows;core;putty;resource;packages\my\filemng;$(BCB)\include;$(BCB)\include\vcl"/>

+ 10 - 8
WinSCP3.bpr

@@ -7,9 +7,10 @@
     <OBJFILES value="WinSCP3.obj forms\CustomScpExplorer.obj 
       windows\CustomWinConfiguration.obj windows\GUIConfiguration.obj 
       windows\GUITools.obj forms\NonVisual.obj windows\ProgParams.obj 
-      forms\ScpCommander.obj forms\ScpExplorer.obj 
-      windows\TerminalManager.obj windows\Tools.obj windows\UserInterface.obj 
-      windows\WinConfiguration.obj windows\WinInterface.obj windows\WinMain.obj"/>
+      windows\QueueController.obj forms\ScpCommander.obj 
+      forms\ScpExplorer.obj windows\TerminalManager.obj windows\Tools.obj 
+      windows\UserInterface.obj windows\WinConfiguration.obj 
+      windows\WinInterface.obj windows\WinMain.obj"/>
     <RESFILES value="windows\Windows.res WinSCP3.res"/>
     <DEFFILE value=""/>
     <RESDEPEN value="$(RESFILES) forms\CustomScpExplorer.dfm forms\NonVisual.dfm 
@@ -73,6 +74,7 @@
       <FILE FILENAME="windows\GUITools.cpp" FORMNAME="" UNITNAME="GUITools" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\NonVisual.cpp" FORMNAME="NonVisualDataModule" UNITNAME="NonVisual" CONTAINERID="CCompiler" DESIGNCLASS="TDataModule" LOCALCOMMAND=""/>
       <FILE FILENAME="windows\ProgParams.cpp" FORMNAME="" UNITNAME="ProgParams" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="windows\QueueController.cpp" FORMNAME="" UNITNAME="QueueController" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\ScpCommander.cpp" FORMNAME="ScpCommanderForm" UNITNAME="ScpCommander" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="forms\ScpExplorer.cpp" FORMNAME="ScpExplorerForm" UNITNAME="ScpExplorer" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
       <FILE FILENAME="windows\TerminalManager.cpp" FORMNAME="" UNITNAME="TerminalManager" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
@@ -97,8 +99,8 @@ IncludeVerInfo=1
 AutoIncBuild=1
 MajorVer=3
 MinorVer=6
-Release=0
-Build=218
+Release=1
+Build=220
 Debug=0
 PreRelease=0
 Special=0
@@ -110,13 +112,13 @@ CodePage=1252
 [Version Info Keys]
 CompanyName=Martin Prikryl
 FileDescription=Windows SCP/SFTP client
-FileVersion=3.6.0.218
+FileVersion=3.6.1.220
 InternalName=winscp3
 LegalCopyright=(c) 2000-2004 Martin Prikryl
 LegalTrademarks=
-OriginalFilename=winscp360.exe
+OriginalFilename=winscp361.exe
 ProductName=WinSCP
-ProductVersion=3.6.0.0
+ProductVersion=3.6.1.0
 WWW=http://winscp.sourceforge.net/
 
 [Compiler]

BIN
WinSCP3.res


+ 3 - 3
components/UnixDirView.cpp

@@ -366,7 +366,7 @@ AnsiString __fastcall TUnixDirView::ItemDragFileName(TListItem * Item)
 {
 #ifndef DESIGN_ONLY
   assert(Item && Item->Data && Terminal && (Terminal->Files->IndexOf(ITEMFILE) >= 0) && !FUniqTempDir.IsEmpty());
-  return FUniqTempDir + Configuration->CopyParam.ValidLocalFileName(ITEMFILE->FileName);
+  return FUniqTempDir + GUIConfiguration->CopyParam.ValidLocalFileName(ITEMFILE->FileName);
 #else
   return 0;
 #endif
@@ -524,7 +524,7 @@ void __fastcall TUnixDirView::PerformItemDragDropOperation(TListItem * Item, int
   assert(DragDropFilesEx);
 
   TTransferType Type;
-  TCopyParamType CopyParams = Configuration->CopyParam;
+  TCopyParamType CopyParams = GUIConfiguration->CopyParam;
   TStrings *FileList = NULL;
   AnsiString Directory;
 
@@ -901,7 +901,7 @@ void __fastcall TUnixDirView::DDTargetDrop()
           FileList->AddObject(File->FileName, File);
         }
 
-        TCopyParamType CopyParams = Configuration->CopyParam;
+        TCopyParamType CopyParams = GUIConfiguration->CopyParam;
         AnsiString TargetDir = "";
 
         if (OnGetCopyParam)

+ 1 - 0
components/UnixDirView.h

@@ -172,6 +172,7 @@ __published:
   __property OnDDFileOperation;
   __property OnDDFileOperationExecuted;
   __property OnDDCreateDataObject;
+  __property OnDDMenuPopup;
 
   __property OnContextPopup;
   __property OnBeginRename;

+ 15 - 22
core/Configuration.cpp

@@ -10,6 +10,7 @@
 #include "PuttyIntf.h"
 #include "TextsCore.h"
 #include "Interface.h"
+#define GSSAPIDLL "gssapi32"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
@@ -21,6 +22,7 @@ __fastcall TConfiguration::TConfiguration()
   DontSave = false;
   RandomSeedSave = true;
   FApplicationInfo = NULL;
+  FGSSAPIInstalled = -1;
 }
 //---------------------------------------------------------------------------
 void __fastcall TConfiguration::Default()
@@ -34,7 +36,7 @@ void __fastcall TConfiguration::Default()
     "winscp" + ExtractFileExt(ARandomSeedFile), "\\\\", "\\",
     TReplaceFlags() << rfReplaceAll);
   FConfirmOverwriting = true;
-  FCopyParam.Default();
+  FRememberPassword = false;
 
   FLogging = false;
   FLogFileName = "";
@@ -78,21 +80,7 @@ THierarchicalStorage * TConfiguration::CreateScpStorage(bool /*SessionList*/)
       BLOCK("Interface", CANCREATE, \
         KEY(String,   RandomSeedFile); \
         KEY(Bool,     ConfirmOverwriting); \
-      ); \
-      BLOCK("Interface\\CopyParam", CANCREATE, \
-        KEY(Bool,    CopyParam.AddXToDirectories); \
-        KEY(String,  CopyParam.AsciiFileMask.Masks); \
-        KEY(Integer, CopyParam.FileNameCase); \
-        KEY(Bool,    CopyParam.PreserveReadOnly); \
-        KEY(Bool,    CopyParam.PreserveTime); \
-        KEY(Bool,    CopyParam.PreserveRights); \
-        KEY(String,  CopyParam.Rights.Text); \
-        KEY(Integer, CopyParam.TransferMode); \
-        KEY(Integer, CopyParam.ResumeSupport); \
-        KEY(Int64,   CopyParam.ResumeThreshold); \
-        KEY(Bool,    CopyParam.ReplaceInvalidChars); \
-        KEY(String,  CopyParam.LocalInvalidChars); \
-        KEY(Bool,    CopyParam.CalculateSize); \
+        KEY(Bool,     RememberPassword); \
       ); \
       BLOCK("Logging", CANCREATE, \
         KEY(Bool,    Logging); \
@@ -524,6 +512,17 @@ AnsiString __fastcall TConfiguration::GetRootKeyStr()
   return RootKeyToStr(HKEY_CURRENT_USER);
 }
 //---------------------------------------------------------------------------
+bool __fastcall TConfiguration::GetGSSAPIInstalled()
+{
+  if (FGSSAPIInstalled < 0)
+  {
+    HINSTANCE Library = LoadLibrary(GSSAPIDLL);
+    FGSSAPIInstalled = (Library != NULL ? 1 : 0);
+    FreeLibrary(Library);
+  }
+  return (FGSSAPIInstalled > 0);
+}
+//---------------------------------------------------------------------------
 void __fastcall TConfiguration::SetStorage(TStorage value)
 {
   if (FStorage != value)
@@ -558,12 +557,6 @@ void __fastcall TConfiguration::SetRandomSeedFile(AnsiString value)
   strcpy(seedpath, StripPathQuotes(value).c_str());
 }
 //---------------------------------------------------------------------------
-void __fastcall TConfiguration::SetCopyParam(TCopyParamType value)
-{
-  FCopyParam.Assign(value);
-  Changed();
-}
-//---------------------------------------------------------------------------
 AnsiString __fastcall TConfiguration::GetRandomSeedFile()
 {
   return AnsiString(seedpath_ptr());

+ 6 - 4
core/Configuration.h

@@ -2,7 +2,7 @@
 #ifndef ConfigurationH
 #define ConfigurationH
 
-#include "CopyParam.h"
+#include "RemoteFiles.h"
 #include "FileBuffer.h"
 #include "HierarchicalStorage.h"
 //---------------------------------------------------------------------------
@@ -20,7 +20,6 @@ private:
   TNotifyEvent FOnChange;
   bool FRandomSeedSave;
   
-  TCopyParamType FCopyParam;
   void * FApplicationInfo;
   bool FLogging;
   AnsiString FLogFileName;
@@ -28,8 +27,10 @@ private:
   bool FLogFileAppend;
   bool FConfirmOverwriting;
   AnsiString FIniFileStorageName;
+  bool FRememberPassword;
 
   bool FDisablePasswordStoring;
+  int FGSSAPIInstalled; 
 
   AnsiString __fastcall GetOSVersionStr();
   TVSFixedFileInfo *__fastcall GetFixedApplicationInfo();
@@ -49,7 +50,6 @@ private:
   AnsiString __fastcall GetRootKeyStr();
   AnsiString __fastcall GetConfigurationSubKey();
   TEOLType __fastcall GetLocalEOLType();
-  void __fastcall SetCopyParam(TCopyParamType value);
   void __fastcall SetLogging(bool value);
   void __fastcall SetLogFileName(AnsiString value);
   void __fastcall SetLogToFile(bool value);
@@ -67,6 +67,7 @@ private:
   AnsiString __fastcall GetPartialExt() const;
   AnsiString __fastcall GetFileInfoString(const AnsiString Key);
   AnsiString __fastcall GetLocalInvalidChars();
+  bool __fastcall GetGSSAPIInstalled();
 
 protected:
   TStorage FStorage;
@@ -113,7 +114,6 @@ public:
 
   __property TVSFixedFileInfo *FixedApplicationInfo  = { read=GetFixedApplicationInfo };
   __property void * ApplicationInfo  = { read=GetApplicationInfo };
-  __property TCopyParamType CopyParam = { read = FCopyParam, write = SetCopyParam };
   __property AnsiString StoredSessionsSubKey = {read=GetStoredSessionsSubKey};
   __property AnsiString PuttyRegistryStorageKey  = { read=GetPuttyRegistryStorageKey };
   __property AnsiString PuttySessionsKey  = { read=GetPuttySessionsKey };
@@ -140,6 +140,7 @@ public:
   __property AnsiString DefaultLogFileName  = { read=GetDefaultLogFileName };
   __property TNotifyEvent OnChange = { read = FOnChange, write = FOnChange };
   __property bool ConfirmOverwriting = { read = GetConfirmOverwriting, write = SetConfirmOverwriting};
+  __property bool RememberPassword = { read = FRememberPassword, write = FRememberPassword };
   __property AnsiString PartialExt = {read=GetPartialExt};
 
   __property AnsiString TimeFormat = { read = GetTimeFormat };
@@ -150,6 +151,7 @@ public:
   __property AnsiString LocalInvalidChars = { read = GetLocalInvalidChars };
 
   __property bool DisablePasswordStoring = { read = FDisablePasswordStoring };
+  __property bool GSSAPIInstalled = { read = GetGSSAPIInstalled };
 };
 //---------------------------------------------------------------------------
 #endif

+ 9 - 4
core/CopyParam.cpp

@@ -12,7 +12,11 @@ __fastcall TCopyParamType::TCopyParamType()
 //---------------------------------------------------------------------------
 __fastcall TCopyParamType::TCopyParamType(const TCopyParamType & Source)
 {
-  Assign(Source);
+  Assign(&Source);
+}
+//---------------------------------------------------------------------------
+__fastcall TCopyParamType::~TCopyParamType()
+{
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamType::Default()
@@ -34,9 +38,10 @@ void __fastcall TCopyParamType::Default()
   FileMask = "*.*";
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyParamType::Assign(const TCopyParamType & Source)
+void __fastcall TCopyParamType::Assign(const TCopyParamType * Source)
 {
-  #define COPY(Prop) Prop = Source.Prop
+  assert(Source != NULL);
+  #define COPY(Prop) Prop = Source->Prop
   COPY(FileNameCase);
   COPY(PreserveReadOnly);
   COPY(PreserveTime);
@@ -56,7 +61,7 @@ void __fastcall TCopyParamType::Assign(const TCopyParamType & Source)
 //---------------------------------------------------------------------------
 TCopyParamType & __fastcall TCopyParamType::operator =(const TCopyParamType & rhp)
 {
-  Assign(rhp);
+  Assign(&rhp);
   return *this;
 }
 //---------------------------------------------------------------------------

+ 3 - 2
core/CopyParam.h

@@ -32,9 +32,10 @@ private:
 public:
   __fastcall TCopyParamType();
   __fastcall TCopyParamType(const TCopyParamType & Source);
+  virtual __fastcall ~TCopyParamType();
   TCopyParamType & __fastcall operator =(const TCopyParamType & rhp);
-  void __fastcall Assign(const TCopyParamType & Source);
-  void __fastcall Default();
+  virtual void __fastcall Assign(const TCopyParamType * Source);
+  virtual void __fastcall Default();
   AnsiString __fastcall ChangeFileName(AnsiString FileName,
     TOperationSide Side, bool FirstLevel) const;
   int __fastcall LocalFileAttrs(const TRights & Rights) const;

+ 1 - 0
core/FileOperationProgress.h

@@ -3,6 +3,7 @@
 #define FileOperationProgressH
 //---------------------------------------------------------------------------
 #include "Configuration.h"
+#include "CopyParam.h"
 //---------------------------------------------------------------------------
 class TFileOperationProgressType;
 enum TFileOperation { foNone, foCopy, foMove, foDelete, foSetProperties,

+ 12 - 3
core/Net.cpp

@@ -60,7 +60,16 @@ void __fastcall InitWinsock(void)
 extern "C" char * do_select(Plug plug, SOCKET skt, int startup)
 {
   assert(plug != NULL);
-  void * frontend = get_ssh_frontend(plug);
+  void * frontend;
+  if (!is_ssh(plug))
+  {
+    // If it is not SSH plug, them it must be Proxy plug.
+    // Get SSH plug which it wraps.
+    Proxy_Socket ProxySocket = ((Proxy_Plug)plug)->proxy_socket;
+    plug = ProxySocket->plug;
+  }
+
+  frontend = get_ssh_frontend(plug);
   assert(frontend);
 
   if (startup == 0)
@@ -68,7 +77,7 @@ extern "C" char * do_select(Plug plug, SOCKET skt, int startup)
     skt = INVALID_SOCKET;
   }
   reinterpret_cast<TSecureShell*>(frontend)->SetSocket(&skt);
-  
+
   return NULL;
 }
 //---------------------------------------------------------------------------
@@ -100,7 +109,7 @@ void SSHLogEvent(void * frontend, char * string)
   // Frontend maybe NULL here
   if (frontend != NULL)
   {
-    ((TSecureShell *)frontend)->LogEvent(string);
+    ((TSecureShell *)frontend)->PuttyLogEvent(string);
   }
 }
 //---------------------------------------------------------------------------

+ 2 - 0
core/PuttyIntf.h

@@ -34,6 +34,7 @@ extern "C"
 
   void ssh_close(void * handle);
   int get_ssh_version(void * handle);
+  int is_ssh(void * handle);
   void * get_ssh_frontend(void * handle);
   int get_ssh1_compressing(void * handle);
   const struct ssh_cipher * get_cipher(void * handle);
@@ -89,5 +90,6 @@ extern const struct ssh2_ciphers ssh2_blowfish;
 //---------------------------------------------------------------------------
 #include "Putty.h"
 #include <SSH.h>
+#include <Proxy.h>
 //---------------------------------------------------------------------------
 #endif

+ 36 - 9
core/Queue.cpp

@@ -47,6 +47,7 @@ protected:
     Exception * E;
   };
 
+  bool FMasterPasswordTried;
   TTerminalQueue * FQueue;
   TTerminal * FTerminal;
   TQueueItem * FItem;
@@ -336,6 +337,7 @@ void __fastcall TTerminalQueue::RetryItem(TQueueItem * Item)
 
       int Index = FItems->Remove(Item);
       assert(Index < FItemsInProcess);
+      USEDPARAM(Index);
       FItemsInProcess--;
       FItems->Add(Item);
     }
@@ -355,6 +357,7 @@ void __fastcall TTerminalQueue::DeleteItem(TQueueItem * Item)
 
       int Index = FItems->Remove(Item);
       assert(Index < FItemsInProcess);
+      USEDPARAM(Index);
       FItemsInProcess--;
       delete Item;
     }
@@ -756,6 +759,8 @@ void __fastcall TTerminalItem::ProcessEvent()
     {
       FItem->SetStatus(TQueueItem::qsConnecting);
 
+      FMasterPasswordTried = false;
+      FTerminal->SessionData->RemoteDirectory = FItem->StartupDirectory();
       FTerminal->Open();
       FTerminal->DoStartup();
     }
@@ -900,17 +905,34 @@ void __fastcall TTerminalItem::TerminalQueryUser(TObject * Sender,
 void __fastcall TTerminalItem::TerminalPromptUser(TSecureShell * SecureShell,
   AnsiString Prompt, TPromptKind Kind, AnsiString & Response, bool & Result)
 {
-  TPromptUserRec PromptUserRec;
-  PromptUserRec.SecureShell = SecureShell;
-  PromptUserRec.Prompt = Prompt;
-  PromptUserRec.Kind = Kind;
-  PromptUserRec.Response = Response;
-  PromptUserRec.Result = Result;
+  Result = false;
+  
+  if (!FMasterPasswordTried)
+  {
+    // let's expect that the main session is already authenticated and its password
+    // is not written after, so no locking is necessary
+    Response = FQueue->FTerminal->Password;
+    if (!Response.IsEmpty())
+    {
+      Result = true;
+    }
+    FMasterPasswordTried = true;
+  }
 
-  if (WaitForUserAction(TQueueItem::qsPrompt, &PromptUserRec))
+  if (!Result)
   {
-    Response = PromptUserRec.Response;
-    Result = PromptUserRec.Result;
+    TPromptUserRec PromptUserRec;
+    PromptUserRec.SecureShell = SecureShell;
+    PromptUserRec.Prompt = Prompt;
+    PromptUserRec.Kind = Kind;
+    PromptUserRec.Response = Response;
+    PromptUserRec.Result = Result;
+
+    if (WaitForUserAction(TQueueItem::qsPrompt, &PromptUserRec))
+    {
+      Response = PromptUserRec.Response;
+      Result = PromptUserRec.Result;
+    }
   }
 }
 //---------------------------------------------------------------------------
@@ -1238,6 +1260,11 @@ __fastcall TLocatedQueueItem::TLocatedQueueItem(TTerminal * Terminal) :
   FCurrentDir = Terminal->CurrentDirectory;
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall TLocatedQueueItem::StartupDirectory()
+{
+  return FCurrentDir;
+}
+//---------------------------------------------------------------------------
 void __fastcall TLocatedQueueItem::DoExecute(TTerminal * Terminal)
 {
   assert(Terminal != NULL);

+ 5 - 0
core/Queue.h

@@ -2,6 +2,9 @@
 #ifndef QueueH
 #define QueueH
 //---------------------------------------------------------------------------
+#include "SecureShell.h"
+#include "FileOperationProgress.h"
+//---------------------------------------------------------------------------
 class TSignalThread
 {
 friend int __fastcall ThreadProc(void * Thread);
@@ -145,6 +148,7 @@ protected:
   virtual void __fastcall DoExecute(TTerminal * Terminal) = 0;
   void __fastcall SetProgress(const TFileOperationProgressType & ProgressData);
   void __fastcall GetData(TQueueItemProxy * Proxy);
+  virtual AnsiString __fastcall StartupDirectory() = 0; 
 };
 //---------------------------------------------------------------------------
 class TQueueItemProxy
@@ -220,6 +224,7 @@ protected:
   __fastcall TLocatedQueueItem(TTerminal * Terminal);
 
   virtual void __fastcall DoExecute(TTerminal * Terminal);
+  virtual AnsiString __fastcall StartupDirectory(); 
 
 private:
   AnsiString FCurrentDir;

+ 8 - 2
core/RemoteFiles.cpp

@@ -220,6 +220,7 @@ TRemoteFile * __fastcall TRemoteFile::Duplicate()
     COPY_FP(FileName);
     COPY_FP(INodeBlocks);
     COPY_FP(Modification);
+    COPY_FP(LastAccess);
     COPY_FP(Group);
     COPY_FP(IconIndex);
     COPY_FP(IsSymLink);
@@ -669,7 +670,7 @@ void __fastcall TRemoteFile::SetTerminal(TTerminal * value)
 //---------------------------------------------------------------------------
 __fastcall TRemoteParentDirectory::TRemoteParentDirectory() : TRemoteFile()
 {
-  FileName = "..";
+  FileName = PARENTDIRECTORY;
   Modification = Now();
   LastAccess = Modification;
   Type = 'D';
@@ -1048,7 +1049,12 @@ bool __fastcall TRemoteDirectoryChangesCache::GetDirectoryChange(
   Result = (IndexOfName(Key) >= 0);
   if (Result)
   {
-    TargetDir = Key;
+    TargetDir = Values[Key];
+    // TargetDir is not "//" here only when Change is full path to symbolic link
+    if (TargetDir == "//")
+    {
+      TargetDir = Key;
+    }
   }
   else
   {

+ 4 - 5
core/ScpFileSystem.cpp

@@ -1240,11 +1240,10 @@ void __fastcall TSCPFileSystem::CopyToRemote(TStrings * FilesToCopy,
           }
         }
 
-        AnsiString OrigFileNameOnly = ExtractFileName(FileName);
         try
         {
           SCPSource(FileName, CopyParam, Params, OperationProgress, 0);
-          OperationProgress->Finish(OrigFileNameOnly, true, DisconnectWhenComplete);
+          OperationProgress->Finish(FileName, true, DisconnectWhenComplete);
         }
         catch (EScpFileSkipped &E)
         {
@@ -1254,13 +1253,13 @@ void __fastcall TSCPFileSystem::CopyToRemote(TStrings * FilesToCopy,
             {
               OperationProgress->Cancel = csCancel;
             }
-            OperationProgress->Finish(OrigFileNameOnly, false, DisconnectWhenComplete);
+            OperationProgress->Finish(FileName, false, DisconnectWhenComplete);
             if (!FTerminal->HandleException(&E)) throw;
           );
         }
         catch (EScpSkipFile &E)
         {
-          OperationProgress->Finish(OrigFileNameOnly, false, DisconnectWhenComplete);
+          OperationProgress->Finish(FileName, false, DisconnectWhenComplete);
           // If ESkipFile occurs, just log it and continue with next file
           SUSPEND_OPERATION (
             if (!FTerminal->HandleException(&E)) throw;
@@ -1268,7 +1267,7 @@ void __fastcall TSCPFileSystem::CopyToRemote(TStrings * FilesToCopy,
         }
         catch (...)
         {
-          OperationProgress->Finish(OrigFileNameOnly, false, DisconnectWhenComplete);
+          OperationProgress->Finish(FileName, false, DisconnectWhenComplete);
           throw;
         }
       }

+ 36 - 2
core/SecureShell.cpp

@@ -11,6 +11,7 @@
 #include "TextsCore.h"
 #include "Common.h"
 #include "ScpMain.h"
+#include "Security.h"
 
 #ifndef AUTO_WINSOCK
 #include <winsock2.h>
@@ -155,6 +156,33 @@ void __fastcall TSecureShell::Init()
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TSecureShell::PuttyLogEvent(const AnsiString & Str)
+{
+  #define SERVER_VERSION_MSG "Server version: "
+  // Gross hack
+  if (Str.Pos(SERVER_VERSION_MSG) == 1)
+  {
+    FSshVersionString = Str.SubString(strlen(SERVER_VERSION_MSG) + 1,
+      Str.Length() - strlen(SERVER_VERSION_MSG));
+  }
+  LogEvent(Str);
+}
+//---------------------------------------------------------------------------
+AnsiString __fastcall TSecureShell::GetSshImplementation()
+{
+  const char * Ptr = strchr(FSshVersionString.c_str(), '-');
+  if (Ptr != NULL)
+  {
+    Ptr = strchr(Ptr + 1, '-');
+  }
+  return (Ptr != NULL) ? AnsiString(Ptr + 1) : AnsiString(); 
+}
+//---------------------------------------------------------------------
+AnsiString __fastcall TSecureShell::GetPassword()
+{
+  return DecryptPassword(FPassword, SessionData->SessionName);
+}
+//---------------------------------------------------------------------------
 bool __fastcall TSecureShell::PromptUser(const AnsiString Prompt,
   AnsiString & Response, bool IsPassword)
 {
@@ -230,6 +258,12 @@ bool __fastcall TSecureShell::PromptUser(const AnsiString Prompt,
     }
     FPasswordTriedForKI = true;
   };
+
+  if (Configuration->RememberPassword)
+  {
+    FPassword = EncryptPassword(Response, SessionData->SessionName);
+  }
+  
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -1182,9 +1216,9 @@ void __fastcall TSessionLog::AddStartupInfo()
       ADF("Transfer Protocol: %s", (Data->FSProtocolStr));
       ADF("SSH protocol version: %s; Compression: %s",
         (Data->SshProtStr, BooleanToEngStr(Data->Compression)));
-      ADF("Agent forwarding: %s; TIS/CryptoCard: %s; KI: %s",
+      ADF("Agent forwarding: %s; TIS/CryptoCard: %s; KI: %s; GSSAPI: %s",
         (BooleanToEngStr(Data->AgentFwd), BooleanToEngStr(Data->AuthTIS),
-         BooleanToEngStr(Data->AuthKI)));
+         BooleanToEngStr(Data->AuthKI), BooleanToEngStr(Data->AuthGSSAPI)));
       ADF("Ciphers: %s; Ssh2DES: %s",
         (Data->CipherList, BooleanToEngStr(Data->Ssh2DES)));
       char * PingTypes = "-NC";

+ 8 - 0
core/SecureShell.h

@@ -124,6 +124,8 @@ private:
   void * FBackendHandle;
   unsigned long FMaxPacketSize;
   Config * FConfig;
+  AnsiString FSshVersionString;
+  AnsiString FPassword;
 
   unsigned PendLen;
   unsigned PendSize;
@@ -164,6 +166,8 @@ private:
   void __fastcall SetConfiguration(TConfiguration * value);
   void __fastcall SetUserObject(TObject * value);
   void __fastcall Discard();
+  AnsiString __fastcall GetSshImplementation();
+  AnsiString __fastcall GetPassword();
 
 protected:
   AnsiString StdError;
@@ -218,6 +222,7 @@ public:
   {
     return Log->IsLogging();
   }
+  void __fastcall PuttyLogEvent(const AnsiString & Str);
   void __fastcall inline LogEvent(const AnsiString & Str)
   {
     if (IsLogging()) Log->Add(llMessage, Str);
@@ -237,6 +242,8 @@ public:
   __property TCipher SCCipher = { read = GetSCCipher };
   __property TCompressionType SCCompression = { read = GetSCCompression };
   __property int SshVersion = { read = GetSshVersion };
+  __property AnsiString SshVersionString = { read = FSshVersionString };
+  __property AnsiString SshImplementation = { read = GetSshImplementation };
   __property TQueryUserEvent OnQueryUser = { read = FOnQueryUser, write = FOnQueryUser };
   __property TPromptUserEvent OnPromptUser = { read = FOnPromptUser, write = FOnPromptUser };
   __property TExtendedExceptionEvent OnShowExtendedException = { read = FOnShowExtendedException, write = FOnShowExtendedException };
@@ -244,6 +251,7 @@ public:
   __property TNotifyEvent OnClose = { read = FOnClose, write = FOnClose };
   __property int Status = { read = GetStatus };
   __property TObject * UserObject = { read = FUserObject, write = SetUserObject };
+  __property AnsiString Password = { read = GetPassword };
 };
 //---------------------------------------------------------------------------
 #endif

+ 26 - 0
core/SessionData.cpp

@@ -43,6 +43,7 @@ void __fastcall TSessionData::Default()
   AuthTIS = false;
   AuthKI = true;
   AuthKIPassword = true;
+  AuthGSSAPI = false;
   Compression = false;
   SshProt = ssh2;
   Ssh2DES = false;
@@ -100,6 +101,7 @@ void __fastcall TSessionData::Default()
   SFTPDownloadQueue = 4;
   SFTPUploadQueue = 4;
   SFTPListingQueue = 2;
+  SFTPSymlinkBug = asAuto;
 
   CustomParam1 = "";
   CustomParam2 = "";
@@ -164,6 +166,7 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
     DUPL(TcpNoDelay);
     DUPL(AuthKI);
     DUPL(AuthKIPassword);
+    DUPL(AuthGSSAPI);
 
     DUPL(ProxyMethod);
     DUPL(ProxyHost);
@@ -179,6 +182,12 @@ void __fastcall TSessionData::Assign(TPersistent * Source)
       DUPL(Bug[(TSshBug)Index]);
     }
 
+    // SFTP
+    DUPL(SFTPDownloadQueue);
+    DUPL(SFTPUploadQueue);
+    DUPL(SFTPListingQueue);
+    DUPL(SFTPSymlinkBug);
+
     DUPL(CustomParam1);
     DUPL(CustomParam2);
 
@@ -229,6 +238,7 @@ void __fastcall TSessionData::StoreToConfig(void * config)
   cfg->ssh2_des_cbc = Ssh2DES;
   cfg->try_tis_auth = AuthTIS;
   cfg->try_ki_auth = AuthKI;
+  cfg->try_gssapi_auth = AuthGSSAPI;
 
   cfg->proxy_type = ProxyMethod;
   ASCOPY(cfg->proxy_host, ProxyHost);
@@ -330,6 +340,7 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
     AuthTIS = Storage->ReadBool("AuthTIS", AuthTIS);
     AuthKI = Storage->ReadBool("AuthKI", AuthKI);
     AuthKIPassword = Storage->ReadBool("AuthKIPassword", AuthKIPassword);
+    AuthGSSAPI = Storage->ReadBool("AuthGSSAPI", AuthGSSAPI);
     Compression = Storage->ReadBool("Compression", Compression);
     SshProt = (TSshProt)Storage->ReadInteger("SshProt", SshProt);
     Ssh2DES = Storage->ReadBool("Ssh2DES", Ssh2DES);
@@ -412,6 +423,8 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage)
         Bug[sbHMAC2] = asOn;
     }
 
+    SFTPSymlinkBug = TAutoSwitch(Storage->ReadInteger("SFTPSymlinkBug", SFTPSymlinkBug));
+
     // read only (used only on Import from Putty dialog)
     ProtocolStr = Storage->ReadString("Protocol", ProtocolStr);
 
@@ -455,6 +468,7 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage, bool PuttyExp
     }
     else
     {
+      Storage->WriteBool("AuthGSSAPI", AuthGSSAPI);
       Storage->WriteString("PublicKeyFile", PublicKeyFile);
       Storage->WriteInteger("FSProtocol", FSProtocol);
       Storage->WriteString("LocalDirectory", LocalDirectory);
@@ -539,6 +553,8 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage, bool PuttyExp
 
     if (!PuttyExport)
     {
+      Storage->WriteInteger("SFTPSymlinkBug", SFTPSymlinkBug);
+      
       Storage->WriteString("CustomParam1", CustomParam1);
       Storage->WriteString("CustomParam2", CustomParam2);
     }
@@ -783,6 +799,11 @@ void __fastcall TSessionData::SetAuthKIPassword(bool value)
   SET_SESSION_PROPERTY(AuthKIPassword);
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::SetAuthGSSAPI(bool value)
+{
+  SET_SESSION_PROPERTY(AuthGSSAPI);
+}
+//---------------------------------------------------------------------
 void __fastcall TSessionData::SetCompression(bool value)
 {
   SET_SESSION_PROPERTY(Compression);
@@ -1136,6 +1157,11 @@ void __fastcall TSessionData::SetSFTPListingQueue(int value)
   SET_SESSION_PROPERTY(SFTPListingQueue);
 }
 //---------------------------------------------------------------------
+void __fastcall TSessionData::SetSFTPSymlinkBug(TAutoSwitch value)
+{
+  SET_SESSION_PROPERTY(SFTPSymlinkBug);
+}
+//---------------------------------------------------------------------
 AnsiString __fastcall TSessionData::GetInfoTip()
 {
   return FmtLoadStr(SESSION_INFO_TIP,

+ 6 - 0
core/SessionData.h

@@ -45,6 +45,7 @@ private:
   bool FAuthTIS;
   bool FAuthKI;
   bool FAuthKIPassword;
+  bool FAuthGSSAPI;
   bool FCompression;
   TSshProt FSshProt;
   bool FSsh2DES;
@@ -89,6 +90,7 @@ private:
   int FSFTPUploadQueue;
   int FSFTPListingQueue;
   bool FConsiderDST;
+  TAutoSwitch FSFTPSymlinkBug;
 
   void __fastcall SetHostName(AnsiString value);
   void __fastcall SetPortNumber(int value);
@@ -100,6 +102,7 @@ private:
   void __fastcall SetAuthTIS(bool value);
   void __fastcall SetAuthKI(bool value);
   void __fastcall SetAuthKIPassword(bool value);
+  void __fastcall SetAuthGSSAPI(bool value);
   void __fastcall SetCompression(bool value);
   void __fastcall SetSshProt(TSshProt value);
   void __fastcall SetSsh2DES(bool value);
@@ -163,6 +166,7 @@ private:
   void __fastcall SetSFTPDownloadQueue(int value);
   void __fastcall SetSFTPUploadQueue(int value);
   void __fastcall SetSFTPListingQueue(int value);
+  void __fastcall SetSFTPSymlinkBug(TAutoSwitch value);
   AnsiString __fastcall GetStorageKey();
   void __fastcall SetConsiderDST(bool value);
 
@@ -190,6 +194,7 @@ public:
   __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 Compression  = { read=FCompression, write=SetCompression };
   __property TSshProt SshProt  = { read=FSshProt, write=SetSshProt };
   __property bool Ssh2DES  = { read=FSsh2DES, write=SetSsh2DES };
@@ -246,6 +251,7 @@ public:
   __property int SFTPDownloadQueue = { read = FSFTPDownloadQueue, write = SetSFTPDownloadQueue };
   __property int SFTPUploadQueue = { read = FSFTPUploadQueue, write = SetSFTPUploadQueue };
   __property int SFTPListingQueue = { read = FSFTPListingQueue, write = SetSFTPListingQueue };
+  __property TAutoSwitch SFTPSymlinkBug = { read = FSFTPSymlinkBug, write = SetSFTPSymlinkBug };
   __property bool ConsiderDST = { read = FConsiderDST, write = SetConsiderDST };
   __property AnsiString StorageKey = { read = GetStorageKey };
 };

+ 27 - 9
core/SftpFileSystem.cpp

@@ -406,6 +406,10 @@ public:
           GetCardinal(); // skip access time subseconds
         }
       }
+      else
+      {
+        File->LastAccess = Now();
+      }
       if (Flags & SSH_FILEXFER_ATTR_CREATETIME)
       {
         GetInt64(); // skip create time
@@ -422,6 +426,10 @@ public:
           GetCardinal(); // skip modification time subseconds
         }
       }
+      else
+      {
+        File->Modification = Now();
+      }
     }
 
     if ((Version < 4) && (Type != SSH_FXP_ATTRS))
@@ -2038,10 +2046,7 @@ void __fastcall TSFTPFileSystem::ReadDirectory(TRemoteFileList * FileList)
       bool Failure = (File == NULL);
       if (Failure)
       {
-        File = new TRemoteFile();
-        File->FileName = PARENTDIRECTORY;
-        File->Modification = Now();
-        File->Type = FILETYPE_DIRECTORY;
+        File = new TRemoteParentDirectory();
       }
 
       assert(File && File->IsParentDirectory);
@@ -2227,8 +2232,22 @@ void __fastcall TSFTPFileSystem::CreateLink(const AnsiString FileName,
   assert(Symbolic); // only symlinks are supported by SFTP
   assert(FVersion >= 3); // symlinks are supported with SFTP version 3 and later
   TSFTPPacket Packet(SSH_FXP_SYMLINK);
-  Packet.AddString(PointTo);
-  Packet.AddString(Canonify(FileName));
+
+  bool Buggy = (FTerminal->SessionData->SFTPSymlinkBug == asOn) ||
+    ((FTerminal->SessionData->SFTPSymlinkBug == asAuto) &&
+      (FTerminal->SshImplementation.Pos("OpenSSH") == 1));
+
+  if (!Buggy)
+  {
+    Packet.AddString(Canonify(FileName));
+    Packet.AddString(PointTo);
+  }
+  else
+  {
+    FTerminal->LogEvent("We believe the server has SFTP symlink bug");
+    Packet.AddString(PointTo);
+    Packet.AddString(Canonify(FileName));
+  }
   SendPacketAndReceiveResponse(&Packet, &Packet, SSH_FXP_STATUS);
 }
 //---------------------------------------------------------------------------
@@ -2321,7 +2340,7 @@ void __fastcall TSFTPFileSystem::CopyToRemote(TStrings * FilesToCopy,
     __finally
     {
       FAvoidBusy = false;
-      OperationProgress->Finish(FileNameOnly, Success, DisconnectWhenComplete);
+      OperationProgress->Finish(FileName, Success, DisconnectWhenComplete);
     }
     Index++;
   }
@@ -2945,7 +2964,6 @@ void __fastcall TSFTPFileSystem::CopyToLocal(TStrings * FilesToCopy,
   {
     Success = false;
     FileName = FilesToCopy->Strings[Index];
-    FileNameOnly = UnixExtractFileName(FileName);
     File = (TRemoteFile *)FilesToCopy->Objects[Index];
 
     assert(!FAvoidBusy);
@@ -2973,7 +2991,7 @@ void __fastcall TSFTPFileSystem::CopyToLocal(TStrings * FilesToCopy,
     __finally
     {
       FAvoidBusy = false;
-      OperationProgress->Finish(FileNameOnly, Success, DisconnectWhenComplete);
+      OperationProgress->Finish(FileName, Success, DisconnectWhenComplete);
     }
     Index++;
   }

+ 22 - 15
core/Terminal.cpp

@@ -592,7 +592,10 @@ void __fastcall TTerminal::RefreshDirectory()
   if (SessionData->CacheDirectories &&
       FDirectoryCache->HasNewerFileList(CurrentDirectory, FFiles->Timestamp))
   {
-    ReadDirectory(true);
+    // Second parameter was added to allow (rather force) using the cache.
+    // Before, the directory was reloaded always, it seems useless,
+    // has it any reason?
+    ReadDirectory(true, true);
     FReadDirectoryPending = false;
   }
 }
@@ -677,13 +680,13 @@ void __fastcall TTerminal::ReadCurrentDirectory()
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::ReadDirectory(bool ReloadOnly)
+void __fastcall TTerminal::ReadDirectory(bool ReloadOnly, bool ForceCache)
 {
   bool LoadedFromCache = false;
 
   if (SessionData->CacheDirectories && FDirectoryCache->HasFileList(CurrentDirectory))
   {
-    if (ReloadOnly)
+    if (ReloadOnly && !ForceCache)
     {
       LogEvent("Cached directory not reloaded.");
     }
@@ -900,9 +903,7 @@ bool __fastcall TTerminal::ProcessFiles(TStrings * FileList,
           }
           __finally
           {
-            AnsiString FileNameOnly = (Side == osRemote) ?
-              UnixExtractFileName(FileName) : ExtractFileName(FileName);
-            Progress.Finish(FileNameOnly, Success, DisconnectWhenComplete);
+            Progress.Finish(FileName, Success, DisconnectWhenComplete);
           }
           Index++;
         }
@@ -1661,17 +1662,23 @@ struct TSynchronizeData
   TStringList * LocalFileList;
   TStringList * ModifiedRemoteFileList;
   TStringList * NewRemoteFileList;
+  const TCopyParamType * CopyParam;
 };
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::Synchronize(const AnsiString LocalDirectory,
-  const AnsiString RemoteDirectory, TSynchronizeMode Mode, int Params,
+  const AnsiString RemoteDirectory, TSynchronizeMode Mode,
+  const TCopyParamType * CopyParam, int Params,
   TSynchronizeDirectory OnSynchronizeDirectory)
 {
+  assert(CopyParam != NULL);
+  TCopyParamType SyncCopyParam = *CopyParam;
+  SyncCopyParam.PreserveTime = true;
+
   BeginTransaction();
   try
   {
-    DoSynchronizeDirectory(LocalDirectory, RemoteDirectory, Mode, Params,
-      OnSynchronizeDirectory);
+    DoSynchronizeDirectory(LocalDirectory, RemoteDirectory, Mode,
+      &SyncCopyParam, Params, OnSynchronizeDirectory);
   }
   __finally
   {
@@ -1680,7 +1687,8 @@ void __fastcall TTerminal::Synchronize(const AnsiString LocalDirectory,
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::DoSynchronizeDirectory(const AnsiString LocalDirectory,
-  const AnsiString RemoteDirectory, TSynchronizeMode Mode, int Params,
+  const AnsiString RemoteDirectory, TSynchronizeMode Mode,
+  const TCopyParamType * CopyParam, int Params,
   TSynchronizeDirectory OnSynchronizeDirectory)
 {
   TSearchRec SearchRec;
@@ -1696,6 +1704,7 @@ void __fastcall TTerminal::DoSynchronizeDirectory(const AnsiString LocalDirector
   Data.LocalFileList = NULL;
   Data.NewRemoteFileList = NULL;
   Data.ModifiedRemoteFileList = NULL;
+  Data.CopyParam = CopyParam;
   TStrings * LocalFileList = NULL;
 
   LogEvent(FORMAT("Synchronizing local directory '%s' with remote directory '%s', "
@@ -1770,8 +1779,6 @@ void __fastcall TTerminal::DoSynchronizeDirectory(const AnsiString LocalDirector
         }
       }
 
-      TCopyParamType CopyParam = Configuration->CopyParam;
-      CopyParam.PreserveTime = true;
       int CopyParams = (Params & spNoConfirmation) != 0 ? cpNoConfirmation : 0;
 
       if (LocalFileList->Count > 0)
@@ -1779,7 +1786,7 @@ void __fastcall TTerminal::DoSynchronizeDirectory(const AnsiString LocalDirector
         bool Result;
         if ((Mode == smBoth) || (Mode == smRemote))
         {
-          Result = CopyToRemote(LocalFileList, RemoteDirectory, &CopyParam, CopyParams);
+          Result = CopyToRemote(LocalFileList, RemoteDirectory, CopyParam, CopyParams);
         }
         else if ((Mode == smLocal) && Delete)
         {
@@ -1797,7 +1804,7 @@ void __fastcall TTerminal::DoSynchronizeDirectory(const AnsiString LocalDirector
         if (Data.ModifiedRemoteFileList->Count > 0)
         {
           if (!CopyToLocal(Data.ModifiedRemoteFileList, LocalDirectory,
-            &CopyParam, CopyParams))
+                CopyParam, CopyParams))
           {
             Abort();
           }
@@ -1888,7 +1895,7 @@ void __fastcall TTerminal::SynchronizeFile(const AnsiString FileName,
       DoSynchronizeDirectory(
         Data->LocalDirectory + File->FileName,
         Data->RemoteDirectory + File->FileName,
-        Data->Mode, Data->Params, Data->OnSynchronizeDirectory);
+        Data->Mode, Data->CopyParam, Data->Params, Data->OnSynchronizeDirectory);
     }
   }
 

+ 8 - 5
core/Terminal.h

@@ -116,8 +116,6 @@ private:
   TDirectoryModifiedEvent FOnDirectoryModified;
   TNotifyEvent FOnStartReadDirectory;
   TDeleteLocalFileEvent FOnDeleteLocalFile;
-  bool FReadCurrentDirectoryPending;
-  bool FReadDirectoryPending;
   TUsersGroupsList * FGroups;
   TUsersGroupsList * FUsers;
   bool FUsersGroupsLookedup;
@@ -148,6 +146,9 @@ private:
   void __fastcall AddCachedFileList(TRemoteFileList * FileList);
 
 protected:
+  bool FReadCurrentDirectoryPending;
+  bool FReadDirectoryPending;
+
   virtual void __fastcall KeepAlive();
   void __fastcall DoStartReadDirectory();
   void __fastcall DoReadDirectory(bool ReloadOnly);
@@ -197,7 +198,8 @@ protected:
     const TOverwriteFileParams * FileParams, int Answers, int Params,
     TOperationSide Side);
   void __fastcall DoSynchronizeDirectory(const AnsiString LocalDirectory,
-    const AnsiString RemoteDirectory, TSynchronizeMode Mode, int Params,
+    const AnsiString RemoteDirectory, TSynchronizeMode Mode,
+    const TCopyParamType * CopyParam, int Params,
     TSynchronizeDirectory OnSynchronizeDirectory);
   void __fastcall SynchronizeFile(const AnsiString FileName,
     const TRemoteFile * File, /*TSynchronizeData*/ void * Param);
@@ -219,7 +221,7 @@ public:
   AnsiString __fastcall AbsolutePath(AnsiString Path);
   void __fastcall BeginTransaction();
   void __fastcall ReadCurrentDirectory();
-  void __fastcall ReadDirectory(bool ReloadOnly);
+  void __fastcall ReadDirectory(bool ReloadOnly, bool ForceCache = false);
   void __fastcall ReadFile(const AnsiString FileName, TRemoteFile *& File);
   void __fastcall ReadSymlink(TRemoteFile * SymlinkFile, TRemoteFile *& File);
   bool __fastcall CopyToLocal(TStrings * FilesToCopy,
@@ -257,7 +259,8 @@ public:
   void __fastcall CalculateFilesSize(TStrings * FileList, __int64 & Size, int Params);
   void __fastcall ClearCaches();
   void __fastcall Synchronize(const AnsiString LocalDirectory,
-    const AnsiString RemoteDirectory, TSynchronizeMode Mode, int Params,
+    const AnsiString RemoteDirectory, TSynchronizeMode Mode,
+    const TCopyParamType * CopyParam, int Params,
     TSynchronizeDirectory OnSynchronizeDirectory);
 
   static bool __fastcall IsAbsolutePath(const AnsiString Path);

+ 81 - 109
forms/Copy.cpp

@@ -19,35 +19,30 @@
 #pragma resource "*.dfm"
 //---------------------------------------------------------------------------
 bool __fastcall DoCopyDialog(bool ToRemote,
-  bool Move, bool DragDrop, TStrings * FileList,
-  bool AllowTransferMode, AnsiString & TargetDirectory,
-  TCopyParamType * Params, int & Options, bool AllowDirectory)
+  bool Move, TStrings * FileList, AnsiString & TargetDirectory,
+  TGUICopyParamType * Params, int Options)
 {
   bool Result;
   TCopyDialog *CopyDialog = new TCopyDialog(Application);
   try
   {
-    if (!AllowTransferMode)
+    if ((Options & coDisableTransferMode) != 0)
     {
       // If local and remote EOL types are the same, there is no need
       // for ASCII (or Automatic) mode
-      CopyDialog->AllowTransferMode = false; // Default is true
       Params->TransferMode = tmBinary;
     }
     CopyDialog->ToRemote = ToRemote;
-    CopyDialog->DragDrop = DragDrop && !ToRemote;
-    if (!CopyDialog->DragDrop) CopyDialog->Directory = TargetDirectory;
+    CopyDialog->Options = Options;
+    CopyDialog->Directory = TargetDirectory;
     CopyDialog->FileList = FileList;
     CopyDialog->Params = *Params;
     CopyDialog->Move = Move;
-    CopyDialog->AllowDirectory = AllowDirectory;
-    CopyDialog->Options = Options;
     Result = CopyDialog->Execute();
     if (Result)
     {
-      if (!CopyDialog->DragDrop) TargetDirectory = CopyDialog->Directory;
-      Params->Assign(CopyDialog->Params);
-      Options = CopyDialog->Options;
+      TargetDirectory = CopyDialog->Directory;
+      *Params = CopyDialog->Params;
     }
   }
   __finally
@@ -66,13 +61,24 @@ __fastcall TCopyDialog::TCopyDialog(TComponent* Owner)
 
   ToRemote = true;
   Move = false;
-  AllowTransferMode = true;
-  AllowDirectory = true;
   FOptions = 0;
 
   UseSystemSettings(this);
 }
 //---------------------------------------------------------------------------
+void __fastcall TCopyDialog::AdjustControls()
+{
+  RemoteDirectoryEdit->Visible = false;
+  LocalDirectoryEdit->Visible = false;
+  DirectoryEdit->Visible = ((Options & coDragDropTemp) == 0);
+  DirectoryEdit->Enabled = ((Options & coDisableDirectory) == 0);
+  DirectoryLabel->FocusControl = DirectoryEdit;
+  CopyParamsFrame->Direction = !ToRemote ? pdToLocal : pdToRemote;
+  CopyParamsFrame->AllowTransferMode = ((Options & coDisableTransferMode) == 0);
+
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
 void __fastcall TCopyDialog::SetToRemote(bool value)
 {
   if (FToRemote != value)
@@ -81,102 +87,80 @@ void __fastcall TCopyDialog::SetToRemote(bool value)
     FToRemote = value;
     DirectoryEdit->Text = ADirectory;
 
-    RemoteDirectoryEdit->Visible = false;
-    LocalDirectoryEdit->Visible = false;
-    DirectoryEdit->Visible = !DragDrop;
-    DirectoryEdit->Enabled = AllowDirectory;
-    DirectoryLabel->FocusControl = DirectoryEdit;
-    UpdateControls();
-    CopyParamsFrame->Direction = !ToRemote ? pdToLocal : pdToRemote;
+    AdjustControls();
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyDialog::SetAllowDirectory(bool value)
+void __fastcall TCopyDialog::SetOptions(int value)
 {
-  if (AllowDirectory != value)
+  if (Options != value)
   {
-    FAllowDirectory = value;
-    DirectoryEdit->Enabled = AllowDirectory;
+    FOptions = value;
+
+    AdjustControls();
   }
 }
 //---------------------------------------------------------------------------
-int __fastcall TCopyDialog::GetOptions()
-{
-  return
-    (FOptions & ~(coQueue | coQueueNoConfirmation)) |
-    (QueueCheck->Checked ? coQueue : 0) |
-    (QueueNoConfirmationCheck->Checked ? coQueueNoConfirmation : 0);
-}
-//---------------------------------------------------------------------------
-void __fastcall TCopyDialog::SetOptions(int value)
-{
-  FOptions = value;
-  QueueCheck->Checked = ((value & coQueue) != 0);
-  QueueNoConfirmationCheck->Checked = ((value & coQueueNoConfirmation) != 0);
-}
-//---------------------------------------------------------------------------
 THistoryComboBox * __fastcall TCopyDialog::GetDirectoryEdit()
 {
   return ToRemote ? RemoteDirectoryEdit : LocalDirectoryEdit;
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyDialog::SetFileMask(const AnsiString value)
-{
-  if (!DragDrop)
-  {
-    DirectoryEdit->Text = Directory + value;
-  }
-  else
-  {
-    FFileMask = value;
-  }
-}
-//---------------------------------------------------------------------------
 AnsiString __fastcall TCopyDialog::GetFileMask()
 {
-  if (!DragDrop)
-  {
-    return ToRemote ? UnixExtractFileName(DirectoryEdit->Text) :
-      ExtractFileName(DirectoryEdit->Text);
-  }
-  else
-  {
-    return FFileMask;
-  }
+  return ToRemote ? UnixExtractFileName(DirectoryEdit->Text) :
+    ExtractFileName(DirectoryEdit->Text);
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyDialog::SetParams(TCopyParamType value)
+void __fastcall TCopyDialog::SetParams(const TGUICopyParamType & value)
 {
+  FParams = value;
   CopyParamsFrame->Params = value;
-  SetFileMask(value.FileMask);
+  DirectoryEdit->Text = Directory + FParams.FileMask;
+  QueueCheck->Checked = FParams.Queue;
+  QueueNoConfirmationCheck->Checked = FParams.QueueNoConfirmation;
 }
 //---------------------------------------------------------------------------
-TCopyParamType __fastcall TCopyDialog::GetParams()
+TGUICopyParamType __fastcall TCopyDialog::GetParams()
 {
-  TCopyParamType Params = CopyParamsFrame->Params;
-  Params.FileMask = GetFileMask();
-  return Params;
+  // overwrites TCopyParamType files only
+  FParams = CopyParamsFrame->Params;
+  FParams.FileMask = GetFileMask();
+  FParams.Queue = QueueCheck->Checked;
+  FParams.QueueNoConfirmation = QueueNoConfirmationCheck->Checked;
+  return FParams;
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::SetDirectory(AnsiString value)
 {
-  value = ToRemote ? UnixIncludeTrailingBackslash(value) :
-    IncludeTrailingBackslash(value);
+  if (!value.IsEmpty())
+  {
+    value = ToRemote ? UnixIncludeTrailingBackslash(value) :
+      IncludeTrailingBackslash(value);
+  }
   DirectoryEdit->Text = value + GetFileMask();
 }
 //---------------------------------------------------------------------------
 AnsiString __fastcall TCopyDialog::GetDirectory()
 {
-  assert(DirectoryEdit && !DragDrop);
+  assert(DirectoryEdit);
 
   AnsiString Result = DirectoryEdit->Text;
   if (ToRemote)
   {
-    Result = UnixIncludeTrailingBackslash(UnixExtractFilePath(Result));
+    Result = UnixExtractFilePath(Result);
+    if (!Result.IsEmpty())
+    {
+      Result = UnixIncludeTrailingBackslash(Result);
+    }
   }
   else
   {
-    Result = IncludeTrailingBackslash(ExtractFilePath(Result));
+    Result = ExtractFilePath(Result);
+    if (!Result.IsEmpty())
+    {
+      Result = IncludeTrailingBackslash(Result);
+    }
   }
   return Result;
 }
@@ -196,7 +180,8 @@ void __fastcall TCopyDialog::UpdateControls()
   {
     AnsiString TransferStr = LoadStr(!Move ? COPY_COPY : COPY_MOVE);
     AnsiString DirectionStr =
-      LoadStr((DragDrop ? COPY_TODROP : (!ToRemote ? COPY_TOLOCAL : COPY_TOREMOTE)));
+      LoadStr(((Options & coDragDropTemp) != 0) ? COPY_TODROP :
+        (ToRemote ? COPY_TOREMOTE : COPY_TOLOCAL));
 
     if (FileList->Count == 1)
     {
@@ -224,28 +209,16 @@ void __fastcall TCopyDialog::UpdateControls()
     CopyButton->Caption = LoadStr(COPY_MOVE_BUTTON);
   }
 
-  LocalDirectoryBrowseButton->Visible = !ToRemote && !DragDrop && AllowDirectory;
+  LocalDirectoryBrowseButton->Visible = !ToRemote &&
+    ((Options & coDragDropTemp) == 0);
 
-  EnableControl(QueueCheck, !DragDrop && ((Options & coQueueDisable) == 0));
-  EnableControl(QueueNoConfirmationCheck, !DragDrop && QueueCheck->Checked);
+  EnableControl(QueueCheck,
+    (Options & (coDisableQueue | coDragDropTemp)) == 0);
+  EnableControl(QueueNoConfirmationCheck,
+    ((Options & coDragDropTemp) == 0) && QueueCheck->Checked);
   QueueNoConfirmationCheck->Visible = MoreButton->Expanded;
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyDialog::SetDragDrop(Boolean value)
-{
-  if (DragDrop != value)
-  {
-    FDragDrop = value;
-    if (value)
-    {
-      ToRemote = false;
-      DirectoryEdit->Text = "";
-    }
-    DirectoryEdit->Visible = !value || ToRemote;
-    UpdateControls();
-  }
-}
-//---------------------------------------------------------------------------
 void __fastcall TCopyDialog::SetMove(bool value)
 {
   if (Move != value)
@@ -257,11 +230,20 @@ void __fastcall TCopyDialog::SetMove(bool value)
 //---------------------------------------------------------------------------
 void __fastcall TCopyDialog::FormShow(TObject * /*Sender*/)
 {
-  assert(FileList && (FileList->Count > 0) && (!ToRemote || !DragDrop));
-  if (!DragDrop && AllowDirectory) DirectoryEdit->SetFocus();
-    else
-  if (MoreButton->Expanded) MorePanel->SetFocus();
-    else CopyButton->SetFocus();
+  assert(FileList && (FileList->Count > 0));
+  if (DirectoryEdit->Enabled && DirectoryEdit->Visible)
+  {
+    DirectoryEdit->SetFocus();
+  }
+  else
+  if (MoreButton->Expanded)
+  {
+    MorePanel->SetFocus();
+  }
+  else
+  {
+    CopyButton->SetFocus();
+  }
   UpdateControls();
 }
 //---------------------------------------------------------------------------
@@ -282,7 +264,7 @@ bool __fastcall TCopyDialog::Execute()
       GUIConfiguration->CopyParamDialogExpanded = MoreButton->Expanded;
       if (SaveSettingsCheck->Checked)
       {
-        Configuration->CopyParam = Params;
+        GUIConfiguration->CopyParam = Params;
       }
       DirectoryEdit->SaveToHistory();
       CustomWinConfiguration->History[ToRemote ?
@@ -301,7 +283,7 @@ void __fastcall TCopyDialog::FormCloseQuery(TObject * /*Sender*/,
 {
   if (ModalResult != mrCancel)
   {
-    if (!ToRemote && !DragDrop)
+    if (!ToRemote && ((Options & coDragDropTemp) == 0))
     {
       AnsiString Dir = Directory;
       AnsiString Drive = ExtractFileDrive(Dir);
@@ -350,18 +332,8 @@ void __fastcall TCopyDialog::FormCloseQuery(TObject * /*Sender*/,
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TCopyDialog::SetAllowTransferMode(Boolean value)
-{
-  CopyParamsFrame->AllowTransferMode = value;
-}
-//---------------------------------------------------------------------------
-bool __fastcall TCopyDialog::GetAllowTransferMode()
-{
-  return CopyParamsFrame->AllowTransferMode;
-}
-//---------------------------------------------------------------------------
 void __fastcall TCopyDialog::LocalDirectoryBrowseButtonClick(
-      TObject * /*Sender*/)
+  TObject * /*Sender*/)
 {
   assert(!ToRemote);
   AnsiString Directory = LocalDirectoryEdit->Text;

+ 9 - 19
forms/Copy.h

@@ -37,44 +37,34 @@ __published:
   void __fastcall ControlChange(TObject *Sender);
 private:
   bool FToRemote;
-  bool FDragDrop;
   TStrings * FFileList;
   bool FMove;
-  AnsiString FFileMask;
-  bool FAllowDirectory;
   int FOptions;
-  bool __fastcall GetAllowTransferMode();
+  TGUICopyParamType FParams;
   AnsiString __fastcall GetDirectory();
   void __fastcall SetToRemote(bool value);
   THistoryComboBox * __fastcall GetDirectoryEdit();
-  void __fastcall SetParams(TCopyParamType value);
-  TCopyParamType __fastcall GetParams();
-  void __fastcall SetAllowTransferMode(Boolean value);
+  void __fastcall SetParams(const TGUICopyParamType & value);
+  TGUICopyParamType __fastcall GetParams();
   void __fastcall SetDirectory(AnsiString value);
-  void __fastcall SetDragDrop(Boolean value);
   void __fastcall SetFileList(TStrings * value);
   void __fastcall SetMove(bool value);
-  void __fastcall SetFileMask(const AnsiString value);
   AnsiString __fastcall GetFileMask();
-  void __fastcall SetAllowDirectory(bool value);
-  int __fastcall GetOptions();
   void __fastcall SetOptions(int value);
+protected:
+  void __fastcall UpdateControls();
+  void __fastcall AdjustControls();
 public:
   __fastcall TCopyDialog(TComponent* Owner);
   bool __fastcall Execute();
-  
-  __property bool AllowTransferMode = { read = GetAllowTransferMode, write = SetAllowTransferMode };
+
   __property bool ToRemote = { read = FToRemote, write = SetToRemote };
   __property AnsiString Directory = { read = GetDirectory, write = SetDirectory };
   __property THistoryComboBox * DirectoryEdit = { read = GetDirectoryEdit };
-  __property bool DragDrop = { read = FDragDrop, write = SetDragDrop };
   __property TStrings * FileList = { read = FFileList, write = SetFileList };
-  __property TCopyParamType Params = { read = GetParams, write = SetParams };
+  __property TGUICopyParamType Params = { read = GetParams, write = SetParams };
   __property bool Move = { read = FMove, write = SetMove };
-  __property bool AllowDirectory = { read = FAllowDirectory, write = SetAllowDirectory };
-  __property int Options = { read = GetOptions, write = SetOptions };
-protected:
-  void __fastcall UpdateControls();
+  __property int Options = { read = FOptions, write = SetOptions };
 };
 //---------------------------------------------------------------------------
 #endif

+ 87 - 430
forms/CustomScpExplorer.cpp

@@ -4,7 +4,6 @@
 
 #include <Clipbrd.hpp>
 #include <Common.h>
-#include <AssociatedStatusBar.hpp>
 
 #include "CustomScpExplorer.h"
 
@@ -97,7 +96,6 @@ __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
     FLastDirView(NULL), FFormRestored(False), TForm(Owner)
 {
   RestoreParams();
-  FixControlsPlacement();
   RemoteDirView->Invalidate();
   assert(NonVisualDataModule && !NonVisualDataModule->ScpExplorer);
   NonVisualDataModule->ScpExplorer = this;
@@ -112,7 +110,6 @@ __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
   FRefreshLocalDirectory = false;
   FRefreshRemoteDirectory = false;
   FDDMoveSlipped = false;
-  FDDExtCopySlipped = false;
   FDDExtMapFile = NULL;
   FDDExtMutex = CreateMutex(NULL, false, DRAG_EXT_MUTEX);
   assert(FDDExtMutex != NULL);
@@ -122,6 +119,7 @@ __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
   FQueueStatusInvalidated = false;
   FQueueItemInvalidated = false;
   FQueueActedItem = NULL;
+  FQueueController = new TQueueController(QueueView);
 
   FUserActionTimer = new TTimer(this);
   FUserActionTimer->Enabled = false;
@@ -129,8 +127,6 @@ __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
   FUserActionTimer->OnTimer = UserActionTimer;
 
   FOle32Library = LoadLibrary("Ole32.dll");
-  FDragCopyCursor = FOle32Library != NULL ?
-    LoadCursor(FOle32Library, MAKEINTRESOURCE(3)) : NULL;
   FDragMoveCursor = FOle32Library != NULL ?
     LoadCursor(FOle32Library, MAKEINTRESOURCE(2)) : NULL;
 
@@ -161,7 +157,6 @@ __fastcall TCustomScpExplorerForm::~TCustomScpExplorerForm()
 
   FreeLibrary(FOle32Library);
   FOle32Library = NULL;
-  FDragCopyCursor = NULL;
   FDragMoveCursor = NULL;
 
   assert(!FErrorList);
@@ -171,6 +166,8 @@ __fastcall TCustomScpExplorerForm::~TCustomScpExplorerForm()
   assert(NonVisualDataModule && (NonVisualDataModule->ScpExplorer == this));
   NonVisualDataModule->ScpExplorer = NULL;
 
+  delete FQueueController;
+  FQueueController = NULL;
   delete FQueueStatusSection;
   FQueueStatusSection = NULL;
   delete FQueueStatus;
@@ -262,80 +259,8 @@ void __fastcall TCustomScpExplorerForm::UpdateQueueStatus()
     }
   }
 
-  if (FQueueStatus != NULL)
-  {
-    TQueueItemProxy * QueueItem;
-    TListItem * Item;
-    int Index = 0;
-    for (int ItemIndex = 0; ItemIndex < FQueueStatus->Count; ItemIndex++)
-    {
-      QueueItem = FQueueStatus->Items[ItemIndex];
-
-      int Index2 = Index;
-      while ((Index2 < QueueView->Items->Count) &&
-             (QueueView->Items->Item[Index2]->Data != QueueItem))
-      {
-        Index2++;
-      }
-
-      if (Index2 < QueueView->Items->Count)
-      {
-        while (Index < Index2)
-        {
-          QueueView->Items->Delete(Index);
-          Index2--;
-        }
-      }
-
-      if (Index == QueueView->Items->Count)
-      {
-        Item = QueueView->Items->Add();
-      }
-      else if (QueueView->Items->Item[Index]->Data != QueueItem)
-      {
-        Item = QueueView->Items->Insert(Index);
-      }
-      else
-      {
-        Item = QueueView->Items->Item[Index];
-        assert(Item->Data == QueueItem);
-      }
-      FillQueueViewItem(Item, QueueItem, false);
-      Index++;
-
-      assert((QueueItem->Status != TQueueItem::qsPending) ==
-        (ItemIndex < FQueueStatus->ActiveCount));
-
-      if (ItemIndex < FQueueStatus->ActiveCount)
-      {
-        if (Index == QueueView->Items->Count)
-        {
-          Item = QueueView->Items->Add();
-        }
-        else if (QueueView->Items->Item[Index]->Data != QueueItem)
-        {
-          Item = QueueView->Items->Insert(Index);
-        }
-        else
-        {
-          Item = QueueView->Items->Item[Index];
-          assert(Item->Data == QueueItem);
-        }
-        FillQueueViewItem(Item, QueueItem, true);
-        Index++;
-      }
-    }
-
-    while (Index < QueueView->Items->Count)
-    {
-      QueueView->Items->Delete(Index);
-    }
-  }
-  else
-  {
-    QueueView->Items->Clear();
-  }
-
+  FQueueController->UpdateQueueStatus(FQueueStatus);
+  
   UpdateQueueView();
 }
 //---------------------------------------------------------------------------
@@ -395,8 +320,6 @@ TQueueItemProxy * __fastcall TCustomScpExplorerForm::RefreshQueueItems()
   TQueueItemProxy * Result = NULL;
   if (FQueueStatus != NULL)
   {
-    TGuard Guard(FQueueStatusSection);
-
     bool Refresh = FQueueItemInvalidated;
     FQueueItemInvalidated = false;
 
@@ -405,14 +328,11 @@ TQueueItemProxy * __fastcall TCustomScpExplorerForm::RefreshQueueItems()
     bool Updated = false;
     bool Update;
     TQueueItemProxy * QueueItem;
-    bool Active;
-    int ItemIndex = 0;
     bool UserAction;
     for (int Index = 0; Index < Limit; Index++)
     {
       Update = false;
       QueueItem = FQueueStatus->Items[Index];
-      Active = (QueueItem->Status != TQueueItem::qsPending);
       UserAction = TQueueItem::IsUserActionStatus(QueueItem->Status);
       if (UserAction && (Result == NULL))
       {
@@ -424,13 +344,6 @@ TQueueItemProxy * __fastcall TCustomScpExplorerForm::RefreshQueueItems()
         QueueItem->Flag = false;
         QueueItem->Update();
         Updated = true;
-        bool IsActive = (QueueItem->Status != TQueueItem::qsPending);
-        assert(!Active || IsActive);
-        if (!Active && IsActive)
-        {
-          QueueView->Items->Insert(ItemIndex + 1);
-          Active = true;
-        }
         Update = true;
       }
       else if (UserAction)
@@ -440,16 +353,8 @@ TQueueItemProxy * __fastcall TCustomScpExplorerForm::RefreshQueueItems()
 
       if (Update)
       {
-        assert(QueueView->Items->Item[ItemIndex]->Data == QueueItem);
-        FillQueueViewItem(QueueView->Items->Item[ItemIndex], QueueItem, false);
-        if (Active)
-        {
-          FillQueueViewItem(QueueView->Items->Item[ItemIndex + 1],
-            QueueItem, true);
-        }
+        FQueueController->RefreshQueueItem(QueueItem);
       }
-
-      ItemIndex += (Active ? 2 : 1);
     }
 
     if (Updated)
@@ -464,8 +369,7 @@ TQueueItemProxy * __fastcall TCustomScpExplorerForm::RefreshQueueItems()
 void __fastcall TCustomScpExplorerForm::ConfigurationChanged()
 {
   assert(Configuration && RemoteDirView);
-  RemoteDirView->DDAllowMove = WinConfiguration->DDExtEnabled ||
-    WinConfiguration->DDAllowMoveInit;
+  RemoteDirView->DDAllowMove = WinConfiguration->DDAllowMoveInit;
   RemoteDirView->DimmHiddenFiles = WinConfiguration->DimmHiddenFiles;
   RemoteDirView->ShowHiddenFiles = WinConfiguration->ShowHiddenFiles;
   RemoteDirView->ShowInaccesibleDirectories = WinConfiguration->ShowInaccesibleDirectories;
@@ -478,16 +382,23 @@ void __fastcall TCustomScpExplorerForm::RemoteDirViewGetCopyParam(
       TTransferType Type, AnsiString &TargetDirectory, TStrings * FileList,
       TCopyParamType &CopyParam)
 {
+  TGUICopyParamType GUICopyParam = GUIConfiguration->CopyParam;
+  // overwrites TCopyParamType fields only
+  GUICopyParam = CopyParam;
   if (!CopyParamDialog(Direction, Type, true, FileList,
-        TargetDirectory, CopyParam, WinConfiguration->DDTransferConfirmation))
+        TargetDirectory, GUICopyParam, WinConfiguration->DDTransferConfirmation))
   {
     Abort();
   }
+  else
+  {
+    CopyParam = GUICopyParam;
+  }
 }
 //---------------------------------------------------------------------------
 bool __fastcall TCustomScpExplorerForm::CopyParamDialog(
   TTransferDirection Direction, TTransferType Type, bool DragDrop,
-  TStrings * FileList, AnsiString & TargetDirectory, TCopyParamType & CopyParam,
+  TStrings * FileList, AnsiString & TargetDirectory, TGUICopyParamType & CopyParam,
   bool Confirm)
 {
   bool Result = true;
@@ -507,41 +418,44 @@ bool __fastcall TCustomScpExplorerForm::CopyParamDialog(
     }
   }
 
+  bool DragDropTemp = (DragDrop && (Direction == tdToLocal));
   if (Result && Confirm)
   {
-    int Options = coQueueNoConfirmation;
+    int Options =
+      (!Terminal->IsCapable[fcTextMode] ? coDisableTransferMode : 0) |
+      (DragDropTemp ? coDragDropTemp : 0);
     Result = DoCopyDialog(Direction == tdToRemote, Type == ttMove,
-      DragDrop, FileList, Terminal->IsCapable[fcTextMode], TargetDirectory,
-      &CopyParam, Options, true);
+      FileList, TargetDirectory, &CopyParam, Options);
+  }
 
-    if ((Options & coQueue) != 0)
-    {
-      assert(Queue != NULL);
+  if (Result && CopyParam.Queue && !DragDropTemp)
+  {
+    assert(Queue != NULL);
 
-      int Params =
-        ((Type == ttMove) ? cpDelete : 0) |
-        (((Options & coQueueNoConfirmation) != 0) ? cpNoConfirmation : 0);
-      TQueueItem * QueueItem;
-      if (Direction == tdToRemote)
-      {
-        QueueItem = new TUploadQueueItem(Terminal, FileList, TargetDirectory,
-          &CopyParam, Params);
-      }
-      else
-      {
-        QueueItem = new TDownloadQueueItem(Terminal, FileList, TargetDirectory,
-          &CopyParam, Params);
-      }
-      Queue->AddItem(QueueItem);
-      Result = false;
+    int Params =
+      ((Type == ttMove) ? cpDelete : 0) |
+      (CopyParam.QueueNoConfirmation ? cpNoConfirmation : 0);
+    TQueueItem * QueueItem;
+    if (Direction == tdToRemote)
+    {
+      QueueItem = new TUploadQueueItem(Terminal, FileList, TargetDirectory,
+        &CopyParam, Params);
+    }
+    else
+    {
+      QueueItem = new TDownloadQueueItem(Terminal, FileList, TargetDirectory,
+        &CopyParam, Params);
+    }
+    Queue->AddItem(QueueItem);
+    Result = false;
 
-      TOperationSide Side = ((Direction == tdToRemote) ? osLocal : osRemote);
-      if (HasDirView[Side])
-      {
-        DirView(Side)->SelectAll(smNone);
-      }
+    TOperationSide Side = ((Direction == tdToRemote) ? osLocal : osRemote);
+    if (HasDirView[Side])
+    {
+      DirView(Side)->SelectAll(smNone);
     }
   }
+  
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -630,15 +544,17 @@ void __fastcall TCustomScpExplorerForm::DoOperationFinished(
     // (it is not displayed)
     if (!DragDrop && Visible && (Operation != foCalculateSize))
     {
-      TListItem *Item = DirView(Side)->FindFileItem(FileName);
+      AnsiString FileNameOnly = (Side == osRemote) ?
+        UnixExtractFileName(FileName) : ExtractFileName(FileName);
+      TListItem *Item = DirView(Side)->FindFileItem(FileNameOnly);
       assert(Item);
       if (Success) Item->Selected = false;
       Item->MakeVisible(false);
     }
-    if (FProgressForm)
-    {
-      DisconnectWhenComplete = FProgressForm->DisconnectWhenComplete;
-    }
+  }
+  if (FProgressForm)
+  {
+    DisconnectWhenComplete = FProgressForm->DisconnectWhenComplete;
   }
 }
 //---------------------------------------------------------------------------
@@ -740,7 +656,7 @@ void __fastcall TCustomScpExplorerForm::ExecuteFileOperation(TFileOperation Oper
       {
         TargetDirectory = *static_cast<AnsiString*>(Param);
       }
-      TCopyParamType CopyParam = Configuration->CopyParam;
+      TGUICopyParamType CopyParam = GUIConfiguration->CopyParam;
       if (CopyParamDialog(Direction, Type, false, FileList, TargetDirectory,
           CopyParam, !NoConfirmation))
       {
@@ -989,7 +905,7 @@ void __fastcall TCustomScpExplorerForm::ExecuteFile(TOperationSide Side,
     assert(FileList->Count == 1);
     if (Side == osRemote)
     {
-      TCopyParamType CopyParam = Configuration->CopyParam;
+      TCopyParamType CopyParam = GUIConfiguration->CopyParam;
       if (FExecutedFileForceText)
       {
         CopyParam.TransferMode = tmAscii;
@@ -1170,7 +1086,7 @@ void __fastcall TCustomScpExplorerForm::ExecutedFileChanged(TObject * Sender)
           {
             FileList->Add(FExecutedFile);
 
-            TCopyParamType CopyParam = Configuration->CopyParam;
+            TCopyParamType CopyParam = GUIConfiguration->CopyParam;
             if (FExecutedFileForceText)
             {
               CopyParam.TransferMode = tmAscii;
@@ -1362,6 +1278,11 @@ void __fastcall TCustomScpExplorerForm::SetProperties(TOperationSide Side, TStri
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::KeyDown(Word & Key, Classes::TShiftState Shift)
 {
+  if (QueueView->Focused() && (QueueView->OnKeyDown != NULL))
+  {
+    QueueView->OnKeyDown(QueueView, Key, Shift); 
+  }
+
   if (!DirView(osCurrent)->IsEditing())
   {
     TShortCut KeyShortCut = ShortCut(Key, Shift);
@@ -1643,9 +1564,19 @@ void __fastcall TCustomScpExplorerForm::NewSession()
   }
 }
 //---------------------------------------------------------------------------
+bool __fastcall TCustomScpExplorerForm::CanCloseQueue()
+{
+  assert(FQueue != NULL);
+  return (FQueue->IsEmpty ||
+    (MessageDialog(LoadStr(PENDING_QUEUE_ITEMS), qtWarning, qaOK | qaCancel) == qaOK));
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::CloseSession()
 {
-  TTerminalManager::Instance()->FreeActiveTerminal();
+  if (CanCloseQueue())
+  {
+    TTerminalManager::Instance()->FreeActiveTerminal();
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::OpenStoredSession(TSessionData * Data)
@@ -1680,6 +1611,11 @@ void __fastcall TCustomScpExplorerForm::FormCloseQuery(TObject * /*Sender*/,
     }
     CanClose = (Result == qaOK || Result == qaNeverAskAgain);
   }
+
+  if (CanClose)
+  {
+    CanClose = CanCloseQueue();
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::DropDownButtonMenu(TObject *Sender)
@@ -1753,6 +1689,9 @@ bool __fastcall TCustomScpExplorerForm::GetComponentVisible(Word Component)
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::FixControlsPlacement()
 {
+  TToolBar * MenuToolBar = dynamic_cast<TToolBar*>(GetComponent(fcMenuToolBar));
+  MenuToolBar->Height = MenuToolBar->Controls[0]->Height;
+
   if (RemoteDirView->ItemFocused != NULL)
   {
     RemoteDirView->ItemFocused->MakeVisible(false);
@@ -1871,12 +1810,13 @@ bool __fastcall TCustomScpExplorerForm::DoFullSynchronizeDirectories(
 
     try
     {
+      TCopyParamType CopyParam = GUIConfiguration->CopyParam;
       FSynchronizeProgressForm = new TSynchronizeProgressForm(Application);
       FSynchronizeProgressForm->Start();
 
       Terminal->Synchronize(LocalDirectory, RemoteDirectory,
         static_cast<TTerminal::TSynchronizeMode>(Mode),
-        Params, TerminalSynchronizeDirectory);
+        &CopyParam, Params, TerminalSynchronizeDirectory);
     }
     __finally
     {
@@ -2244,8 +2184,7 @@ void __fastcall TCustomScpExplorerForm::CMAppSysCommand(TMessage & Message)
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::DoShow()
 {
-  TToolBar * MenuToolBar = dynamic_cast<TToolBar*>(GetComponent(fcMenuToolBar));
-  MenuToolBar->Height = MenuToolBar->Controls[0]->Height;
+  FixControlsPlacement();
 
   TForm::DoShow();
 }
@@ -2331,7 +2270,6 @@ void __fastcall TCustomScpExplorerForm::DDExtInitDrag(TFileList * FileList,
     UnmapViewOfFile(CommStruct);
   }
 
-  FDDExtCopySlipped = false;
   FDDMoveSlipped = false;
 }
 //---------------------------------------------------------------------------
@@ -2349,18 +2287,6 @@ void __fastcall TCustomScpExplorerForm::RemoteDirViewDDEnd(TObject * /*Sender*/)
 
         Operation = (RemoteDirView->LastDDResult == drMove) ? foMove : foCopy;
 
-        // Heuristics: if we slipped copy operation, but interval between
-        // DDTargetDrop() and DDEnd() is greater than some interval,
-        // we suppose that target (explorer) has shown the drop menu.
-        // If such case we use actual operation returned by target application.
-        if (FDDExtCopySlipped)
-        {
-          int SlipInterval = MSecsPerDay * (Now() - FDDDropTime);
-          if (SlipInterval < WinConfiguration->DDExtCopySlipTimeout)
-          {
-            Operation = foCopy;
-          }
-        }
         if (FDDMoveSlipped)
         {
           Operation = foMove;
@@ -2385,31 +2311,16 @@ void __fastcall TCustomScpExplorerForm::RemoteDirViewDDEnd(TObject * /*Sender*/)
 void __fastcall TCustomScpExplorerForm::RemoteDirViewDDGiveFeedback(
   TObject * /*Sender*/, int dwEffect, HRESULT & /*Result*/)
 {
-  HCURSOR SlippedMoveCursor;
   HCURSOR SlippedCopyCursor;
 
-  // When dragging outside of winscp using shellext, move operation is usually
-  // selected as default (by explorer). We want copy instead. As the operation is
-  // finally hold by us, we can slip "copy" cursor in place of "move" cursor.
-  // Thus explorer thinks that file is moving, but we display copy cursor
-  // and we do actually copy, when shellext steals processing from explorer.
-  // See TCustomScpExplorerForm::DDGetTarget
-  FDDExtCopySlipped =
-    (FDDExtMapFile != NULL) && (FDDTargetDirView == NULL) &&
-    (dwEffect == DROPEFFECT_Move) && (FDragCopyCursor != NULL) &&
-    (GetKeyState(VK_SHIFT) >= 0) && (GetKeyState(VK_CONTROL) >= 0);
-
   FDDMoveSlipped =
-    (FDDExtMapFile == NULL) && (FDragMoveCursor != NULL) &&
+    (FDragMoveCursor != NULL) &&
     (!RemoteDirView->DDAllowMove) && (dwEffect == DROPEFFECT_Copy) &&
     ((FDDTargetDirView == RemoteDirView) ||
      ((FDDTargetDirView != NULL) && (GetKeyState(VK_SHIFT) < 0)));
 
-  SlippedMoveCursor = FDDExtCopySlipped ? FDragCopyCursor : Dragdrop::DefaultCursor;
   SlippedCopyCursor = FDDMoveSlipped ? FDragMoveCursor : Dragdrop::DefaultCursor;
 
-  RemoteDirView->DragDropFilesEx->CHMove = SlippedMoveCursor;
-  RemoteDirView->DragDropFilesEx->CHScrollMove = SlippedMoveCursor;
   RemoteDirView->DragDropFilesEx->CHCopy = SlippedCopyCursor;
   RemoteDirView->DragDropFilesEx->CHScrollCopy = SlippedCopyCursor;
 }
@@ -2582,68 +2493,14 @@ void __fastcall TCustomScpExplorerForm::PanelExportStore(TOperationSide /*Side*/
   }
 }
 //---------------------------------------------------------------------------
-TQueueItemProxy * __fastcall TCustomScpExplorerForm::QueueViewItemToQueueItem(
-  TListItem * Item, bool * Detail)
-{
-  assert(Item != NULL);
-  bool ADetail = false;
-
-  int Index = Item->Index;
-  if (Index < FQueueStatus->ActiveCount * 2)
-  {
-    ADetail = ((Index % 2) > 0);
-    Index /= 2;
-  }
-  else
-  {
-    Index -= FQueueStatus->ActiveCount;
-  }
-
-  if (Detail != NULL)
-  {
-    *Detail = ADetail;
-  }
-
-  return FQueueStatus->Items[Index];
-}
-//---------------------------------------------------------------------------
 TQueueOperation __fastcall TCustomScpExplorerForm::DefaultQueueOperation()
 {
-  TQueueItemProxy * QueueItem;
-
-  if (QueueView->ItemFocused != NULL)
-  {
-    QueueItem = QueueViewItemToQueueItem(QueueView->ItemFocused);
-
-    switch (QueueItem->Status)
-    {
-      case TQueueItem::qsPending:
-        return qoItemExecute;
-
-      case TQueueItem::qsQuery:
-        return qoItemQuery;
-
-      case TQueueItem::qsError:
-        return qoItemError;
-
-      case TQueueItem::qsPrompt:
-        return qoItemPrompt;
-    }
-  }
-
-  return qoNone;
+  return FQueueController->DefaultOperation();
 }
 //---------------------------------------------------------------------------
 bool __fastcall TCustomScpExplorerForm::AllowQueueOperation(
   TQueueOperation Operation)
 {
-  TQueueItemProxy * QueueItem = NULL;
-
-  if (QueueView->ItemFocused != NULL)
-  {
-    QueueItem = QueueViewItemToQueueItem(QueueView->ItemFocused);
-  }
-
   switch (Operation)
   {
     case qoPreferences:
@@ -2652,35 +2509,8 @@ bool __fastcall TCustomScpExplorerForm::AllowQueueOperation(
     case qoGoTo:
       return ComponentVisible[fcQueueView];
 
-    case qoItemQuery:
-      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsQuery);
-
-    case qoItemError:
-      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsError);
-
-    case qoItemPrompt:
-      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsPrompt);
-
-    case qoItemDelete:
-      return (QueueItem != NULL) && (QueueItem->Status != TQueueItem::qsDone) &&
-        !TQueueItem::IsUserActionStatus(QueueItem->Status);
-
-    case qoItemExecute:
-      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsPending);
-
-    case qoItemUp:
-      return (QueueItem != NULL) &&
-        (QueueItem->Status == TQueueItem::qsPending) &&
-        (QueueView->ItemFocused->Index > (FQueueStatus->ActiveCount * 2));
-
-    case qoItemDown:
-      return (QueueItem != NULL) &&
-        (QueueItem->Status == TQueueItem::qsPending) &&
-        (QueueView->ItemFocused->Index < (QueueView->Items->Count - 1));
-
     default:
-      assert(false);
-      return false;
+      return FQueueController->AllowOperation(Operation);
   }
 }
 //---------------------------------------------------------------------------
@@ -2698,171 +2528,7 @@ void __fastcall TCustomScpExplorerForm::ExecuteQueueOperation(
   }
   else
   {
-    TQueueItemProxy * QueueItem = NULL;
-
-    if (QueueView->ItemFocused != NULL)
-    {
-      QueueItem = QueueViewItemToQueueItem(QueueView->ItemFocused);
-    }
-
-    if (QueueItem != NULL)
-    {
-      switch (Operation)
-      {
-        case qoItemQuery:
-        case qoItemError:
-        case qoItemPrompt:
-          QueueItem->ProcessUserAction();
-          break;
-
-        case qoItemExecute:
-          QueueItem->ExecuteNow();
-          break;
-
-        case qoItemUp:
-        case qoItemDown:
-          QueueItem->Move(Operation == qoItemUp);
-          break;
-
-        case qoItemDelete:
-          QueueItem->Delete();
-          break;
-
-        default:
-          assert(false);
-          break;
-      }
-    }
-  }
-}
-//---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::FillQueueViewItem(TListItem * Item,
-  TQueueItemProxy * QueueItem, bool Detail)
-{
-  assert(!Detail || (QueueItem->Status != TQueueItem::qsPending));
-
-  assert((Item->Data == NULL) || (Item->Data == QueueItem));
-  Item->Data = QueueItem;
-
-  AnsiString ProgressStr;
-  int State = -1;
-
-  switch (QueueItem->Status)
-  {
-    case TQueueItem::qsPending:
-      ProgressStr = LoadStr(QUEUE_PENDING);
-      break;
-
-    case TQueueItem::qsConnecting:
-      ProgressStr = LoadStr(QUEUE_CONNECTING);
-      break;
-
-    case TQueueItem::qsQuery:
-      ProgressStr = LoadStr(QUEUE_QUERY);
-      State = 4;
-      break;
-
-    case TQueueItem::qsError:
-      ProgressStr = LoadStr(QUEUE_ERROR);
-      State = 5;
-      break;
-
-    case TQueueItem::qsPrompt:
-      ProgressStr = LoadStr(QUEUE_PROMPT);
-      State = 6;
-      break;
-  }
-
-  bool BlinkHide = TQueueItem::IsUserActionStatus(QueueItem->Status) &&
-    !QueueItem->ProcessingUserAction &&
-    ((GetTickCount() % 1000) >= 500);
-
-  int Image = -1;
-  AnsiString Values[4];
-  TFileOperationProgressType * ProgressData = QueueItem->ProgressData;
-  TQueueItem::TInfo * Info = QueueItem->Info;
-
-  if (!Detail)
-  {
-    switch (Info->Operation)
-    {
-      case foCopy:
-        Image = 2;
-        break;
-
-      case foMove:
-        Image = 3;
-        break;
-    }
-    State = ((Info->Side == osLocal) ? 1 : 0);
-
-    Values[0] = Info->Source;
-    Values[1] = Info->Destination;
-
-    if (ProgressData != NULL)
-    {
-      Values[2] = FormatBytes(ProgressData->TotalTransfered);
-      if (ProgressStr.IsEmpty())
-      {
-        ProgressStr = FORMAT("%d%%", (ProgressData->OverallProgress()));
-      }
-    }
-    Values[3] = ProgressStr;
-  }
-  else
-  {
-    if (ProgressData != NULL)
-    {
-      Values[0] = ProgressData->FileName;
-      Values[2] = FormatBytes(ProgressData->TransferedSize);
-      Values[3] = FORMAT("%d%%", (ProgressData->TransferProgress()));
-    }
-    else
-    {
-      Values[0] = ProgressStr;
-    }
-  }
-
-  Item->StateIndex = (!BlinkHide ? State : -1);
-  Item->ImageIndex = (!BlinkHide ? Image : -1);
-  for (int Index = 0; Index < LENOF(Values); Index++)
-  {
-    if (Index < Item->SubItems->Count)
-    {
-      Item->SubItems->Strings[Index] = Values[Index];
-    }
-    else
-    {
-      Item->SubItems->Add(Values[Index]);
-    }
-  }
-}
-//---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::QueueViewDblClick(TObject * /*Sender*/)
-{
-  TQueueOperation Operation = DefaultQueueOperation();
-
-  if (Operation != qoNone)
-  {
-    ExecuteQueueOperation(Operation);
-  }
-}
-//---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::QueueViewKeyDown(TObject * /*Sender*/,
-  WORD & Key, TShiftState /*Shift*/)
-{
-  if (Key == VK_RETURN)
-  {
-    TQueueOperation Operation = DefaultQueueOperation();
-
-    if (Operation != qoNone)
-    {
-      ExecuteQueueOperation(Operation);
-    }
-  }
-  else if (Key == VK_DELETE)
-  {
-    ExecuteQueueOperation(qoItemDelete);
+    FQueueController->ExecuteOperation(Operation);
   }
 }
 //---------------------------------------------------------------------------
@@ -2889,15 +2555,6 @@ void __fastcall TCustomScpExplorerForm::QueueSplitterCanResize(
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::FormResize(TObject * /*Sender*/)
-{
-  DoResize();
-}
-//---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::DoResize()
-{
-}
-//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::StatusBarResize(
   TObject * Sender)
 {

+ 0 - 3
forms/CustomScpExplorer.dfm

@@ -10,7 +10,6 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
   OldCreateOrder = False
   Position = poDefaultPosOnly
   OnCloseQuery = FormCloseQuery
-  OnResize = FormResize
   PixelsPerInch = 96
   TextHeight = 13
   object QueueSplitter: TSplitter
@@ -140,12 +139,10 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
       TabOrder = 0
       ViewStyle = vsReport
       OnContextPopup = QueueViewContextPopup
-      OnDblClick = QueueViewDblClick
       OnDeletion = QueueViewDeletion
       OnEnter = QueueViewEnter
       OnDragDrop = QueueViewDragDrop
       OnDragOver = QueueViewDragOver
-      OnKeyDown = QueueViewKeyDown
       OnSelectItem = QueueViewSelectItem
       OnStartDrag = QueueViewStartDrag
     end

+ 6 - 13
forms/CustomScpExplorer.h

@@ -17,21 +17,21 @@
 #include <ToolWin.hpp>
 
 #include <WinInterface.h>
+#include "QueueController.h"
 //---------------------------------------------------------------------------
 class TProgressForm;
 class TSynchronizeProgressForm;
 class TTerminalQueue;
 class TTerminalQueueStatus;
 class TQueueItem;
-class TQueueItemProxy; 
+class TQueueItemProxy;
+class TQueueController;
 //---------------------------------------------------------------------------
 enum TActionAllowed { aaShortCut, aaUpdate, aaExecute };
 enum TActionFlag { afLocal = 1, afRemote = 2, afExplorer = 4 , afCommander = 8 };
 enum TExecuteFileBy { efDefault, efEditor, efAlternativeEditor };
 enum TPanelExport { pePath, peFileList, peFullFileList };
 enum TPanelExportDestination { pedClipboard, pedCommandLine };
-enum TQueueOperation { qoNone, qoGoTo, qoPreferences, qoItemQuery, qoItemError,
-  qoItemPrompt, qoItemDelete, qoItemExecute, qoItemUp, qoItemDown };
 //---------------------------------------------------------------------------
 class TCustomScpExplorerForm : public TForm
 {
@@ -91,12 +91,8 @@ __published:
     TDataObject *&DataObject);
   void __fastcall RemoteDirViewDDGiveFeedback(TObject *Sender,
     int dwEffect, HRESULT &Result);
-  void __fastcall QueueViewDblClick(TObject *Sender);
-  void __fastcall QueueViewKeyDown(TObject *Sender, WORD &Key,
-    TShiftState Shift);
   void __fastcall QueueSplitterCanResize(TObject *Sender, int &NewSize,
     bool &Accept);
-  void __fastcall FormResize(TObject *Sender);
   void __fastcall StatusBarResize(TObject *Sender);
   void __fastcall QueueViewContextPopup(TObject *Sender, TPoint &MousePos,
     bool &Handled);
@@ -132,11 +128,11 @@ private:
   HANDLE FDDExtMutex;
   AnsiString FDragExtFakeDirectory;
   HINSTANCE FOle32Library;
-  HCURSOR FDragCopyCursor;
   HCURSOR FDragMoveCursor;
   bool FRefreshLocalDirectory;
   bool FRefreshRemoteDirectory;
   TListItem * FQueueActedItem;
+  TQueueController * FQueueController;
 
   bool __fastcall GetEnableFocusedOperation(TOperationSide Side);
   bool __fastcall GetEnableSelectedOperation(TOperationSide Side);
@@ -156,7 +152,6 @@ protected:
   AnsiString FCustomCommandName;
   TSynchronizeProgressForm * FSynchronizeProgressForm;
   HANDLE FDDExtMapFile;
-  bool FDDExtCopySlipped;
   bool FDDMoveSlipped;
   TDateTime FDDDropTime;
   TTimer * FUserActionTimer;
@@ -164,7 +159,7 @@ protected:
 
   virtual bool __fastcall CopyParamDialog(TTransferDirection Direction,
     TTransferType Type, bool DragDrop, TStrings * FileList,
-    AnsiString & TargetDirectory, TCopyParamType & CopyParam, bool Confirm);
+    AnsiString & TargetDirectory, TGUICopyParamType & CopyParam, bool Confirm);
   virtual bool __fastcall RemoteMoveDialog(TStrings * FileList,
     AnsiString & Target, AnsiString & FileMask, bool NoConfirmation);
   virtual void __fastcall CreateParams(TCreateParams & Params);
@@ -212,17 +207,15 @@ protected:
     TStringList * ExportData);
   void __fastcall QueueListUpdate(TTerminalQueue * Queue);
   void __fastcall QueueItemUpdate(TTerminalQueue * Queue, TQueueItem * Item);
-  TQueueItemProxy * __fastcall QueueViewItemToQueueItem(TListItem * Item,
-    bool * Detail = NULL);
   void __fastcall UpdateQueueStatus();
   TQueueItemProxy * __fastcall RefreshQueueItems();
   virtual int __fastcall GetStaticComponentsHeight();
-  virtual void __fastcall DoResize();
   void __fastcall FillQueueViewItem(TListItem * Item,
     TQueueItemProxy * QueueItem, bool Detail);
   void __fastcall QueueViewDeleteItem(int Index);
   void __fastcall UserActionTimer(TObject * Sender);
   void __fastcall UpdateQueueView();
+  bool __fastcall CanCloseQueue();
 
   #pragma warn -inl
   BEGIN_MESSAGE_MAP

+ 1 - 0
forms/FileSystemInfo.cpp

@@ -45,6 +45,7 @@ void __fastcall TFileSystemInfoDialog::UpdateControls()
   assert(Terminal);
 
   SshVersionEdit->Text = IntToStr(Terminal->SshVersion);
+  SshImplementationEdit->Text = Terminal->SshImplementation;
 
   AnsiString Str = CipherNames[Terminal->CSCipher];
   if (Terminal->CSCipher != Terminal->SCCipher)

+ 36 - 16
forms/FileSystemInfo.dfm

@@ -3,7 +3,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
   Top = 178
   BorderStyle = bsDialog
   Caption = 'Server and protocol information'
-  ClientHeight = 372
+  ClientHeight = 385
   ClientWidth = 367
   Color = clBtnFace
   ParentFont = True
@@ -11,12 +11,12 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
   Position = poMainFormCenter
   DesignSize = (
     367
-    372)
+    385)
   PixelsPerInch = 96
   TextHeight = 13
   object CloseButton: TButton
     Left = 283
-    Top = 338
+    Top = 351
     Width = 75
     Height = 25
     Anchors = [akRight, akBottom]
@@ -30,13 +30,13 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
     Left = 8
     Top = 8
     Width = 351
-    Height = 89
+    Height = 105
     Anchors = [akLeft, akTop, akRight]
     Caption = 'Server information'
     TabOrder = 1
     DesignSize = (
       351
-      89)
+      105)
     object Label1: TLabel
       Left = 10
       Top = 18
@@ -46,25 +46,32 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
     end
     object Label2: TLabel
       Left = 10
-      Top = 34
+      Top = 50
       Width = 98
       Height = 13
       Caption = 'Encryption algorithm:'
     end
     object Label3: TLabel
       Left = 10
-      Top = 50
+      Top = 66
       Width = 63
       Height = 13
       Caption = 'Compression:'
     end
     object Label7: TLabel
       Left = 10
-      Top = 66
+      Top = 82
       Width = 98
       Height = 13
       Caption = 'File transfer protocol:'
     end
+    object Label11: TLabel
+      Left = 10
+      Top = 34
+      Width = 98
+      Height = 13
+      Caption = 'SSH implementation:'
+    end
     object SshVersionEdit: TEdit
       Left = 214
       Top = 18
@@ -80,7 +87,7 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
     end
     object CipherEdit: TEdit
       Left = 214
-      Top = 34
+      Top = 50
       Width = 129
       Height = 17
       TabStop = False
@@ -88,12 +95,12 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
       BorderStyle = bsNone
       Color = clBtnFace
       ReadOnly = True
-      TabOrder = 1
+      TabOrder = 2
       Text = 'CipherEdit'
     end
     object CompressionEdit: TEdit
       Left = 214
-      Top = 50
+      Top = 66
       Width = 129
       Height = 17
       TabStop = False
@@ -101,12 +108,12 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
       BorderStyle = bsNone
       Color = clBtnFace
       ReadOnly = True
-      TabOrder = 2
+      TabOrder = 3
       Text = 'CompressionEdit'
     end
     object FSProtocolEdit: TEdit
       Left = 214
-      Top = 66
+      Top = 82
       Width = 129
       Height = 17
       TabStop = False
@@ -114,16 +121,29 @@ object FileSystemInfoDialog: TFileSystemInfoDialog
       BorderStyle = bsNone
       Color = clBtnFace
       ReadOnly = True
-      TabOrder = 3
+      TabOrder = 4
       Text = 'FSProtocolEdit'
     end
+    object SshImplementationEdit: TEdit
+      Left = 214
+      Top = 34
+      Width = 129
+      Height = 17
+      TabStop = False
+      Anchors = [akLeft, akTop, akRight]
+      BorderStyle = bsNone
+      Color = clBtnFace
+      ReadOnly = True
+      TabOrder = 1
+      Text = 'SshImplementationEdit'
+    end
   end
   object ProtocolGroup: TXPGroupBox
     Left = 8
-    Top = 104
+    Top = 120
     Width = 351
     Height = 223
-    Anchors = [akLeft, akTop, akRight, akBottom]
+    Anchors = [akLeft, akTop, akRight]
     Caption = 'Protocol capabilities/information'
     TabOrder = 2
     DesignSize = (

+ 2 - 0
forms/FileSystemInfo.h

@@ -43,6 +43,8 @@ __published:
   TLabel *Label10;
   TEdit *UserGroupListingEdit;
   TMemo *InfoMemo;
+  TEdit *SshImplementationEdit;
+  TLabel *Label11;
 public:
 	virtual __fastcall TFileSystemInfoDialog(TComponent* AOwner);
 

+ 1 - 1
forms/ImportSessions.cpp

@@ -69,7 +69,7 @@ void __fastcall TImportSessionsDialog::SetSessionList(TStoredSessionList *value)
   }
 }
 //---------------------------------------------------------------------
-void TImportSessionsDialog::LoadSessions()
+void __fastcall TImportSessionsDialog::LoadSessions()
 {
   SessionListView->Items->BeginUpdate();
   try {

+ 2 - 2
forms/ImportSessions.h

@@ -35,12 +35,12 @@ __published:
     TShiftState Shift);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall CheckAllButtonClick(TObject *Sender);
-  bool __fastcall GetImportKeys();
 private:
   TStoredSessionList *FSessionList;
   void __fastcall UpdateControls();
   void __fastcall SetSessionList(TStoredSessionList *value);
-  void LoadSessions();
+  void __fastcall LoadSessions();
+  bool __fastcall GetImportKeys();
 public:
   virtual __fastcall TImportSessionsDialog(TComponent* AOwner);
   __property TStoredSessionList *SessionList  = { read=FSessionList, write=SetSessionList };

+ 15 - 2
forms/Login.cpp

@@ -102,9 +102,7 @@ void __fastcall TLoginDialog::Init()
     LocalDirectoryLabel->Visible = false;
     LocalDirectoryEdit->Visible = false;
     LocalDirectoryDescLabel->Visible = false;
-    int PrevHeight = DirectoriesGroup->Height;
     DirectoriesGroup->Height = RemoteDirectoryEdit->Top + RemoteDirectoryEdit->Height + 12;
-    EOLTypeGroup->Top = EOLTypeGroup->Top - PrevHeight + DirectoriesGroup->Height;
   }
 
   ShowTabs(false);
@@ -215,6 +213,7 @@ void __fastcall TLoginDialog::LoadSession(TSessionData * aSessionData)
     AuthTISCheck->Checked = aSessionData->AuthTIS;
     AuthKICheck->Checked = aSessionData->AuthKI;
     AuthKIPasswordCheck->Checked = aSessionData->AuthKIPassword;
+    AuthGSSAPICheck->Checked = aSessionData->AuthGSSAPI;
     AgentFwdCheck->Checked = aSessionData->AgentFwd;
 
     // SSH tab
@@ -358,6 +357,7 @@ void __fastcall TLoginDialog::SaveSession(TSessionData * aSessionData)
   aSessionData->AuthTIS = AuthTISCheck->Checked;
   aSessionData->AuthKI = AuthKICheck->Checked;
   aSessionData->AuthKIPassword = AuthKIPasswordCheck->Checked;
+  aSessionData->AuthGSSAPI = AuthGSSAPICheck->Checked;
   aSessionData->AgentFwd = AgentFwdCheck->Checked;
 
   // Connection tab
@@ -476,6 +476,7 @@ void __fastcall TLoginDialog::UpdateControls()
       EnableControl(AuthKICheck, !SshProt1onlyButton->Checked);
       EnableControl(AuthKIPasswordCheck,
         AuthTISCheck->Checked || AuthKICheck->Checked);
+      EnableControl(AuthGSSAPICheck, !SshProt1onlyButton->Checked);
 
       EnableControl(CipherUpButton, CipherListBox->ItemIndex > 0);
       EnableControl(CipherDownButton, CipherListBox->ItemIndex >= 0 &&
@@ -1122,4 +1123,16 @@ void __fastcall TLoginDialog::PathEditsKeyDown(TObject * Sender,
     (Sender == RemoteDirectoryEdit));
 }
 //---------------------------------------------------------------------------
+void __fastcall TLoginDialog::AuthGSSAPICheckClick(TObject * /*Sender*/)
+{
+  if (!NoUpdate)
+  {
+    UpdateControls();
+    if (AuthGSSAPICheck->Checked && !Configuration->GSSAPIInstalled)
+    {
+      throw Exception(LoadStr(GSSAPI_NOT_INSTALLED));
+    }
+  }
+}
+//---------------------------------------------------------------------------
 

+ 22 - 13
forms/Login.dfm

@@ -1364,7 +1364,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 0
           end
           object BugPlainPW1Combo: TComboBox
@@ -1374,7 +1374,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 1
           end
           object BugRSA1Combo: TComboBox
@@ -1384,7 +1384,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 2
           end
           object BugHMAC2Combo: TComboBox
@@ -1394,7 +1394,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 3
           end
           object BugDeriveKey2Combo: TComboBox
@@ -1404,7 +1404,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 4
           end
           object BugRSAPad2Combo: TComboBox
@@ -1414,7 +1414,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 5
           end
           object BugDHGEx2Combo: TComboBox
@@ -1424,7 +1424,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 6
           end
           object BugPKSessID2Combo: TComboBox
@@ -1434,7 +1434,7 @@ object LoginDialog: TLoginDialog
             Height = 21
             Style = csDropDownList
             Anchors = [akLeft, akTop, akRight]
-            ItemHeight = 13
+            ItemHeight = 0
             TabOrder = 7
           end
         end
@@ -1451,13 +1451,13 @@ object LoginDialog: TLoginDialog
           Left = 0
           Top = 6
           Width = 345
-          Height = 123
+          Height = 145
           Anchors = [akLeft, akTop, akRight]
           Caption = 'Authentication options'
           TabOrder = 0
           DesignSize = (
             345
-            123)
+            145)
           object AuthTISCheck: TCheckBox
             Left = 12
             Top = 19
@@ -1470,12 +1470,12 @@ object LoginDialog: TLoginDialog
           end
           object AgentFwdCheck: TCheckBox
             Left = 12
-            Top = 91
+            Top = 115
             Width = 325
             Height = 17
             Anchors = [akLeft, akTop, akRight]
             Caption = 'Allow agent &forwarding'
-            TabOrder = 3
+            TabOrder = 4
             OnClick = DataChange
           end
           object AuthKICheck: TCheckBox
@@ -1498,6 +1498,15 @@ object LoginDialog: TLoginDialog
             TabOrder = 2
             OnClick = DataChange
           end
+          object AuthGSSAPICheck: TCheckBox
+            Left = 12
+            Top = 91
+            Width = 325
+            Height = 17
+            Caption = 'Attempt MIT Kerberos 5 &GSSAPI authentication (SSH2)'
+            TabOrder = 3
+            OnClick = AuthGSSAPICheckClick
+          end
         end
       end
     end
@@ -1553,7 +1562,7 @@ object LoginDialog: TLoginDialog
           00000000001053746F7265642073657373696F6E735821000000000000000600
           000000000000FFFFFFFF0000000000000000084C6F6767696E67582500000000
           0000000400000000000000FFFFFFFF00000000020000000C456E7669726F6E6D
-          656E745825000000000000000C000000FFFFFFFFFFFFFFFF0000000000000000
+          656E745825000000000000000C00000000000000FFFFFFFF0000000000000000
           0C4469726563746F72696573581D000000000000000500000000000000FFFFFF
           FF0000000000000000045343505824000000000000000800000000000000FFFF
           FFFF00000000010000000B436F6E6E656374696F6E581F000000000000000900

+ 2 - 0
forms/Login.h

@@ -203,6 +203,7 @@ __published:
   TXPGroupBox *ConsiderDSTGroup;
   TRadioButton *ConsiderDSTOnCheck;
   TRadioButton *ConsiderDSTOffCheck;
+  TCheckBox *AuthGSSAPICheck;
   void __fastcall DataChange(TObject *Sender);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall SessionListViewSelectItem(TObject *Sender,
@@ -242,6 +243,7 @@ __published:
   void __fastcall LanguagesButtonClick(TObject *Sender);
   void __fastcall PathEditsKeyDown(TObject *Sender, WORD &Key,
           TShiftState Shift);
+  void __fastcall AuthGSSAPICheckClick(TObject *Sender);
 
 private:
   int NoUpdate;

+ 18 - 7
forms/Preferences.cpp

@@ -183,11 +183,11 @@ void __fastcall TPreferencesDialog::LoadConfiguration()
   FEditorFont->Charset = (TFontCharset)WinConfiguration->Editor.FontCharset;
   FEditorFont->Style = IntToFontStyles(WinConfiguration->Editor.FontStyle);
 
-  CopyParamsFrame->Params = Configuration->CopyParam;
-  ResumeOnButton->Checked = Configuration->CopyParam.ResumeSupport == rsOn;
-  ResumeSmartButton->Checked = Configuration->CopyParam.ResumeSupport == rsSmart;
-  ResumeOffButton->Checked = Configuration->CopyParam.ResumeSupport == rsOff;
-  ResumeThresholdEdit->Value = Configuration->CopyParam.ResumeThreshold / 1024;
+  CopyParamsFrame->Params = GUIConfiguration->CopyParam;
+  ResumeOnButton->Checked = GUIConfiguration->CopyParam.ResumeSupport == rsOn;
+  ResumeSmartButton->Checked = GUIConfiguration->CopyParam.ResumeSupport == rsSmart;
+  ResumeOffButton->Checked = GUIConfiguration->CopyParam.ResumeSupport == rsOff;
+  ResumeThresholdEdit->Value = GUIConfiguration->CopyParam.ResumeThreshold / 1024;
 
   TransferSheet->Enabled = WinConfiguration->ExpertMode;
   GeneralSheet->Enabled = (PreferencesMode != pmLogin) && WinConfiguration->ExpertMode;
@@ -207,8 +207,11 @@ void __fastcall TPreferencesDialog::LoadConfiguration()
 
   PuttyPathEdit->FileName = WinConfiguration->PuttyPath;
 
+  // Queue
   QueueTransferLimitEdit->AsInteger = GUIConfiguration->QueueTransfersLimit;
   QueueAutoPopupCheck->Checked = GUIConfiguration->QueueAutoPopup;
+  QueueCheck->Checked = GUIConfiguration->CopyParam.Queue;
+  RememberPasswordCheck->Checked = Configuration->RememberPassword;
   if (WinConfiguration->QueueView.Show == qvShow)
   {
     QueueViewShowButton->Checked = true;
@@ -230,6 +233,8 @@ void __fastcall TPreferencesDialog::SaveConfiguration()
   Configuration->BeginUpdate();
   try
   {
+    TGUICopyParamType CopyParam = GUIConfiguration->CopyParam;
+
     if (FPreferencesMode != pmLogin)
     {
       LoggingFrame->SaveConfiguration();
@@ -292,19 +297,23 @@ void __fastcall TPreferencesDialog::SaveConfiguration()
     WinConfiguration->Editor.FontCharset = FEditorFont->Charset;
     WinConfiguration->Editor.FontStyle = FontStylesToInt(FEditorFont->Style);
 
-    TCopyParamType CopyParam = CopyParamsFrame->Params;
+    // overwrites only TCopyParamType fields
+    CopyParam = CopyParamsFrame->Params;
     if (ResumeOnButton->Checked) CopyParam.ResumeSupport = rsOn;
     if (ResumeSmartButton->Checked) CopyParam.ResumeSupport = rsSmart;
     if (ResumeOffButton->Checked) CopyParam.ResumeSupport = rsOff;
     CopyParam.ResumeThreshold = ResumeThresholdEdit->Value * 1024;
-    Configuration->CopyParam = CopyParam;
 
     WinConfiguration->CustomCommands = FCustomCommands;
 
     WinConfiguration->PuttyPath = PuttyPathEdit->FileName;
 
+    // Queue
     GUIConfiguration->QueueTransfersLimit = QueueTransferLimitEdit->AsInteger;
     GUIConfiguration->QueueAutoPopup = QueueAutoPopupCheck->Checked;
+    CopyParam.Queue = QueueCheck->Checked;
+    Configuration->RememberPassword = RememberPasswordCheck->Checked;
+
     if (QueueViewShowButton->Checked)
     {
       WinConfiguration->QueueView.Show = qvShow;
@@ -317,6 +326,8 @@ void __fastcall TPreferencesDialog::SaveConfiguration()
     {
       WinConfiguration->QueueView.Show = qvHide;
     }
+    
+    GUIConfiguration->CopyParam = CopyParam;
   }
   __finally
   {

+ 46 - 30
forms/Preferences.dfm

@@ -25,7 +25,7 @@ object PreferencesDialog: TPreferencesDialog
     Caption = 'OK'
     Default = True
     ModalResult = 1
-    TabOrder = 0
+    TabOrder = 1
   end
   object CloseButton: TButton
     Left = 440
@@ -36,7 +36,7 @@ object PreferencesDialog: TPreferencesDialog
     Cancel = True
     Caption = 'Cancel'
     ModalResult = 2
-    TabOrder = 1
+    TabOrder = 2
   end
   object MainPanel: TPanel
     Left = 0
@@ -46,7 +46,7 @@ object PreferencesDialog: TPreferencesDialog
     Align = alTop
     Anchors = [akLeft, akTop, akRight, akBottom]
     BevelOuter = bvNone
-    TabOrder = 2
+    TabOrder = 0
     object PageControl: TPageControl
       Left = 141
       Top = 0
@@ -57,7 +57,7 @@ object PreferencesDialog: TPreferencesDialog
       MultiLine = True
       Style = tsButtons
       TabIndex = 0
-      TabOrder = 0
+      TabOrder = 1
       OnChange = PageControlChange
       object PreferencesSheet: TTabSheet
         Tag = 1
@@ -1061,16 +1061,16 @@ object PreferencesDialog: TPreferencesDialog
           Left = 8
           Top = 8
           Width = 362
-          Height = 286
+          Height = 287
           Anchors = [akLeft, akTop, akRight]
-          Caption = 'Drag && Drop download mode'
+          Caption = 'Drag && Drop downloads'
           TabOrder = 0
           DesignSize = (
             362
-            286)
+            287)
           object DDExtEnabledLabel: TLabel
             Left = 35
-            Top = 44
+            Top = 68
             Width = 318
             Height = 41
             Anchors = [akLeft, akTop, akRight]
@@ -1084,7 +1084,7 @@ object PreferencesDialog: TPreferencesDialog
           end
           object DDExtDisabledLabel: TLabel
             Left = 35
-            Top = 116
+            Top = 140
             Width = 319
             Height = 41
             Anchors = [akLeft, akTop, akRight]
@@ -1098,7 +1098,7 @@ object PreferencesDialog: TPreferencesDialog
           end
           object DDExtEnabledButton: TRadioButton
             Left = 16
-            Top = 24
+            Top = 48
             Width = 337
             Height = 17
             Anchors = [akLeft, akTop, akRight]
@@ -1108,7 +1108,7 @@ object PreferencesDialog: TPreferencesDialog
           end
           object DDExtDisabledButton: TRadioButton
             Left = 16
-            Top = 96
+            Top = 120
             Width = 329
             Height = 17
             Anchors = [akLeft, akTop, akRight]
@@ -1118,14 +1118,14 @@ object PreferencesDialog: TPreferencesDialog
           end
           object DDExtDisabledPanel: TPanel
             Left = 34
-            Top = 160
+            Top = 184
             Width = 325
-            Height = 121
+            Height = 97
             BevelOuter = bvNone
             TabOrder = 2
             DesignSize = (
               325
-              121)
+              97)
             object DDSystemTemporaryDirectoryButton: TRadioButton
               Left = 0
               Top = 0
@@ -1168,26 +1168,26 @@ object PreferencesDialog: TPreferencesDialog
               OnClick = ControlChange
             end
             object DDWarnOnMoveCheck: TCheckBox
-              Left = 16
-              Top = 99
-              Width = 303
-              Height = 17
-              Anchors = [akLeft, akTop, akRight]
-              Caption = 'Warn when mo&ving to temporary directory'
-              TabOrder = 5
-              OnClick = ControlChange
-            end
-            object DDAllowMoveInitCheck: TCheckBox
               Left = 0
               Top = 76
-              Width = 319
+              Width = 303
               Height = 17
               Anchors = [akLeft, akTop, akRight]
-              Caption = 'Allow &moving via temporary directory'
+              Caption = 'Warn when mo&ving via temporary directory'
               TabOrder = 4
               OnClick = ControlChange
             end
           end
+          object DDAllowMoveInitCheck: TCheckBox
+            Left = 16
+            Top = 24
+            Width = 319
+            Height = 17
+            Anchors = [akLeft, akTop, akRight]
+            Caption = 'Allow &moving from remote directory to other applications'
+            TabOrder = 3
+            OnClick = ControlChange
+          end
         end
       end
       object QueueSheet: TTabSheet
@@ -1202,7 +1202,7 @@ object PreferencesDialog: TPreferencesDialog
           Left = 8
           Top = 8
           Width = 362
-          Height = 81
+          Height = 126
           Anchors = [akLeft, akTop, akRight]
           Caption = 'Background transfers'
           TabOrder = 0
@@ -1227,16 +1227,32 @@ object PreferencesDialog: TPreferencesDialog
           end
           object QueueAutoPopupCheck: TCheckBox
             Left = 16
-            Top = 50
+            Top = 74
             Width = 337
             Height = 17
             Caption = '&Automatically popup prompts of background transfers when idle'
+            TabOrder = 2
+          end
+          object QueueCheck: TCheckBox
+            Left = 16
+            Top = 50
+            Width = 337
+            Height = 17
+            Caption = '&Transfer on background by default'
             TabOrder = 1
           end
+          object RememberPasswordCheck: TCheckBox
+            Left = 16
+            Top = 98
+            Width = 337
+            Height = 17
+            Caption = 'Remember &password of main session for background transfers'
+            TabOrder = 3
+          end
         end
         object QueueViewGroup: TXPGroupBox
           Left = 8
-          Top = 96
+          Top = 140
           Width = 362
           Height = 105
           Anchors = [akLeft, akTop, akRight]
@@ -1276,7 +1292,7 @@ object PreferencesDialog: TPreferencesDialog
       Height = 390
       Align = alLeft
       BevelOuter = bvNone
-      TabOrder = 1
+      TabOrder = 0
       DesignSize = (
         141
         390)

+ 2 - 0
forms/Preferences.h

@@ -142,7 +142,9 @@ __published:
   TRadioButton *QueueViewHideWhenEmptyButton;
   TRadioButton *QueueViewHideButton;
   TCheckBox *QueueAutoPopupCheck;
+  TCheckBox *QueueCheck;
   TCheckBox *DDAllowMoveInitCheck;
+  TCheckBox *RememberPasswordCheck;
   void __fastcall FormShow(TObject *Sender);
   void __fastcall ControlChange(TObject *Sender);
   void __fastcall EditorFontButtonClick(TObject *Sender);

+ 41 - 6
forms/ScpCommander.cpp

@@ -202,7 +202,7 @@ bool __fastcall TScpCommanderForm::InternalDDDownload(AnsiString & TargetDirecto
 //---------------------------------------------------------------------------
 bool __fastcall TScpCommanderForm::CopyParamDialog(TTransferDirection Direction,
   TTransferType Type, bool DragDrop, TStrings * FileList, AnsiString & TargetDirectory,
-  TCopyParamType & CopyParam, bool Confirm)
+  TGUICopyParamType & CopyParam, bool Confirm)
 {
   bool Result = false;
   if (DragDrop && (Direction == tdToLocal) && (FDDTargetDirView == LocalDirView))
@@ -234,8 +234,10 @@ bool __fastcall TScpCommanderForm::CopyParamDialog(TTransferDirection Direction,
   return Result;
 }
 //---------------------------------------------------------------------------
-void __fastcall TScpCommanderForm::FormShow(TObject */*Sender*/)
+void __fastcall TScpCommanderForm::DoShow()
 {
+  TCustomScpExplorerForm::DoShow();
+
   assert(FDirViewToSelect);
   FDirViewToSelect->SetFocus();
 
@@ -500,7 +502,7 @@ void __fastcall TScpCommanderForm::CompareDirectories()
 void __fastcall TScpCommanderForm::SynchronizeDirectories()
 {
   TSynchronizeParamType Params;
-  Params.CopyParams.Assign(Configuration->CopyParam);
+  Params.CopyParams = GUIConfiguration->CopyParam;
   Params.AllowTransferMode = Terminal->IsCapable[fcTextMode];
   if (!Params.AllowTransferMode)
   {
@@ -920,7 +922,7 @@ void __fastcall TScpCommanderForm::LocalDirViewDDFileOperation(
       {
         assert(FInternalDDDownloadList->Count > 0);
         assert(dwEffect == DROPEFFECT_Copy || dwEffect == DROPEFFECT_Move);
-        TCopyParamType CopyParams = Configuration->CopyParam;
+        TGUICopyParamType CopyParams = GUIConfiguration->CopyParam;
         TTransferType TransferType = dwEffect == DROPEFFECT_Copy ? ttCopy : ttMove;
         if (FDDMoveSlipped)
         {
@@ -1119,9 +1121,9 @@ int __fastcall TScpCommanderForm::GetStaticComponentsHeight()
     (StatusBar->Visible ? StatusBar->Height : 0);
 }
 //---------------------------------------------------------------------------
-void __fastcall TScpCommanderForm::DoResize()
+void __fastcall TScpCommanderForm::Resize()
 {
-  TCustomScpExplorerForm::DoResize();
+  TCustomScpExplorerForm::Resize();
 
   LocalPanelWidth = FLastLocalPanelWidth;
   UpdateControls();
@@ -1132,4 +1134,37 @@ void __fastcall TScpCommanderForm::StatusBarDblClick(TObject * /*Sender*/)
   DoFileSystemInfoDialog(Terminal);
 }
 //---------------------------------------------------------------------------
+void __fastcall TScpCommanderForm::LocalDirViewDDMenuPopup(TObject * /*Sender*/,
+  HMENU AMenu, IDataObject * /*DataObj*/, int /*AMinCustCmd*/, int /*grfKeyState*/,
+  TPoint & /*pt*/)
+{
+  if ((DropSourceControl == RemoteDirView) &&
+      !RemoteDirView->DDAllowMove)
+  {
+    // index of copy item
+    int Index = GetMenuDefaultItem(AMenu, TRUE, 0);
+    assert(Index >= 0);
+
+    AnsiString Caption = Dragdrop_MIMoveStr;
+
+    MENUITEMINFO MI;
+    memset(&MI, 0, sizeof(MI));
+    MI.cbSize = sizeof(MI);
+    MI.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
+    MI.fType = MFT_STRING;
+    MI.wID = 1 /*DragDrop::CmdMove*/;
+    MI.dwTypeData = Caption.c_str();
+    MI.cch = Caption.Length();
+    MI.fState = MFS_ENABLED;
+    InsertMenuItem(AMenu, Index, TRUE, &MI);
+
+    if (FDDMoveSlipped)
+    {
+      SetMenuDefaultItem(AMenu, Index, TRUE);  
+    }
+
+    FDDMoveSlipped = false;
+  }
+}
+//---------------------------------------------------------------------------
 

+ 1 - 1
forms/ScpCommander.dfm

@@ -5,7 +5,6 @@ inherited ScpCommanderForm: TScpCommanderForm
   Height = 622
   Caption = 'ScpCommanderForm'
   OldCreateOrder = True
-  OnShow = FormShow
   PixelsPerInch = 96
   TextHeight = 13
   object Splitter: TSplitter [0]
@@ -834,6 +833,7 @@ inherited ScpCommanderForm: TScpCommanderForm
       OnDDDragOver = LocalDirViewDDDragOver
       OnDDTargetHasDropHandler = LocalDirViewDDTargetHasDropHandler
       OnDDFileOperation = LocalDirViewDDFileOperation
+      OnDDMenuPopup = LocalDirViewDDMenuPopup
       OnExecFile = LocalDirViewExecFile
       ConfirmDelete = False
       ConfirmOverwrite = False

+ 5 - 3
forms/ScpCommander.h

@@ -131,7 +131,6 @@ __published:
   TPathLabel *CommandLineLabel;
   TLabel *CommandLinePromptLabel;
   TToolButton *ToolButton50;
-  void __fastcall FormShow(TObject *Sender);
   void __fastcall SplitterMoved(TObject *Sender);
   void __fastcall SplitterCanResize(TObject *Sender, int &NewSize,
     bool &Accept);
@@ -161,6 +160,8 @@ __published:
   void __fastcall LocalDirViewDDTargetHasDropHandler(TObject *Sender,
     TListItem *Item, int &Effect, bool &DropHandler);
   void __fastcall StatusBarDblClick(TObject *Sender);
+  void __fastcall LocalDirViewDDMenuPopup(TObject *Sender, HMENU AMenu,
+    IDataObject *DataObj, int AMinCustCmd, int grfKeyState, TPoint &pt);
 
 private:
   TCustomDirView * FDirViewToSelect;
@@ -183,7 +184,7 @@ private:
 protected:
   virtual bool __fastcall CopyParamDialog(TTransferDirection Direction,
     TTransferType Type, bool DragDrop, TStrings * FileList,
-    AnsiString & TargetDirectory, TCopyParamType & CopyParam, bool Confirm);
+    AnsiString & TargetDirectory, TGUICopyParamType & CopyParam, bool Confirm);
   virtual TCustomDirView * __fastcall DirView(TOperationSide Side);
   TControl * __fastcall GetComponent(Byte Component);
   virtual void __fastcall RestoreFormParams();
@@ -215,7 +216,8 @@ protected:
     TStringList * ExportData);
   void __fastcall CommandLinePopulate();
   virtual int __fastcall GetStaticComponentsHeight();
-  virtual void __fastcall DoResize();
+  DYNAMIC void __fastcall Resize();
+  DYNAMIC void __fastcall DoShow();
 
 public:
   __fastcall TScpCommanderForm(TComponent* Owner);

+ 4 - 2
forms/ScpExplorer.cpp

@@ -96,7 +96,7 @@ void __fastcall TScpExplorerForm::StoreParams()
 //---------------------------------------------------------------------------
 bool __fastcall TScpExplorerForm::CopyParamDialog(TTransferDirection Direction,
   TTransferType Type, Boolean DragDrop, TStrings * FileList,
-  AnsiString & TargetDirectory, TCopyParamType & CopyParam, bool Confirm)
+  AnsiString & TargetDirectory, TGUICopyParamType & CopyParam, bool Confirm)
 {
   if ((Direction == tdToLocal) && !DragDrop && TargetDirectory.IsEmpty())
   {
@@ -111,13 +111,15 @@ bool __fastcall TScpExplorerForm::CopyParamDialog(TTransferDirection Direction,
   return Result;
 }
 //---------------------------------------------------------------------------
-void __fastcall TScpExplorerForm::FormShow(TObject * /*Sender*/)
+void __fastcall TScpExplorerForm::DoShow()
 {
   FLastDirView = RemoteDirView; // Only dir view
   RemoteDirView->SetFocus();
 
   // called for second time after menu font was updated (see also RestoreParams)
   SetCoolBandsMinWidth(TopCoolBar);
+
+  TCustomScpExplorerForm::DoShow();
 }
 //---------------------------------------------------------------------------
 bool __fastcall TScpExplorerForm::AllowedAction(TAction * Action, TActionAllowed Allowed)

+ 1 - 1
forms/ScpExplorer.dfm

@@ -5,7 +5,6 @@ inherited ScpExplorerForm: TScpExplorerForm
   ActiveControl = RemoteDirView
   Caption = 'ScpExplorerForm'
   OldCreateOrder = True
-  OnShow = FormShow
   PixelsPerInch = 96
   TextHeight = 13
   inherited QueueSplitter: TSplitter
@@ -537,6 +536,7 @@ inherited ScpExplorerForm: TScpExplorerForm
       end
     end
     object ToolBar5: TToolBar
+      Tag = 1
       Left = 51
       Top = 24
       Width = 581

+ 2 - 2
forms/ScpExplorer.h

@@ -88,18 +88,18 @@ __published:
   TToolButton *ToolButton48;
   TToolButton *ToolButton49;
   TToolButton *ToolButton50;
-  void __fastcall FormShow(TObject *Sender);
   void __fastcall RemoteStatusBarDblClick(TObject *Sender);
 private:
 protected:
   virtual bool __fastcall CopyParamDialog(TTransferDirection Direction,
     TTransferType Type, bool DragDrop, TStrings * FileList,
-    AnsiString & TargetDirectory, TCopyParamType & CopyParam, bool Confirm);
+    AnsiString & TargetDirectory, TGUICopyParamType & CopyParam, bool Confirm);
   virtual void __fastcall RestoreFormParams();
   virtual void __fastcall RestoreParams();
   virtual void __fastcall ConfigurationChanged();
   virtual TControl * __fastcall GetComponent(Byte Component);
   virtual void __fastcall FixControlsPlacement();
+  DYNAMIC void __fastcall DoShow();
 
 public:
   __fastcall TScpExplorerForm(TComponent* Owner);

+ 1 - 0
forms/Symlink.h

@@ -7,6 +7,7 @@
 #include <StdCtrls.hpp>
 #include <Forms.hpp>
 #include "XPGroupBox.hpp"
+#include "CopyParam.h"
 //---------------------------------------------------------------------------
 class TSymlinkDialog : public TForm
 {

+ 2 - 2
forms/Synchronize.cpp

@@ -39,7 +39,7 @@ TSynchronizeParamType __fastcall TSynchronizeParamType::operator =(TSynchronizeP
 //---------------------------------------------------------------------
 void __fastcall TSynchronizeParamType::Assign(TSynchronizeParamType Source)
 {
-  CopyParams.Assign(Source.CopyParams);
+  CopyParams = Source.CopyParams;
   AllowTransferMode = Source.AllowTransferMode;
   LocalDirectory = Source.LocalDirectory;
   RemoteDirectory = Source.RemoteDirectory;
@@ -72,7 +72,7 @@ bool __fastcall TSynchronizeDialog::Execute()
       WinConfiguration->CopyParamDialogExpanded = MoreButton->Expanded;
       if (SaveSettingsCheck->Checked)
       {
-        Configuration->CopyParam = Params.CopyParams;
+        GUIConfiguration->CopyParam = Params.CopyParams;
       }
     }
     __finally

+ 1 - 0
general/filemanager toolset/DirView.pas

@@ -452,6 +452,7 @@ type
     property OnDDExecuted;
     property OnDDFileOperation;
     property OnDDFileOperationExecuted;
+    property OnDDMenuPopup;
 
     property OnExecFile;
 

+ 14 - 0
general/moje komponenty/filemanager toolset/CustomDirView.pas

@@ -119,6 +119,7 @@ type
     FOnDDEnd: TNotifyEvent;
     FOnDDCreateDataObject: TDDOnCreateDataObject;
     FOnDDTargetHasDropHandler: TDDOnTargetHasDropHandler;
+    FOnDDMenuPopup: TOnMenuPopup;
     FOnExecFile: TDirViewExecFileEvent;
     FForceRename: Boolean;
     FLastDDResult: TDragResult;
@@ -214,6 +215,8 @@ type
     procedure DDDrop(DataObj: IDataObject; grfKeyState: LongInt; Point: TPoint; var dwEffect: Longint);
     procedure DDDropHandlerSucceeded(Sender: TObject; grfKeyState: Longint; Point: TPoint; dwEffect: Longint); virtual;
     procedure DDGiveFeedback(dwEffect: Longint; var Result: HResult); virtual;
+    procedure DDMenuPopup(Sender: TObject; AMenu: HMenu; DataObj: IDataObject;
+      AMinCustCmd:integer; grfKeyState: Longint; pt: TPoint); 
     procedure DDMenuDone(Sender: TObject; AMenu: HMenu); virtual;
     procedure DDProcessDropped(Sender: TObject; grfKeyState: Longint;
       Point: TPoint; dwEffect: Longint);
@@ -429,6 +432,7 @@ type
     property OnDDFileOperationExecuted: TDDFileOperationExecutedEvent
       read FOnDDFileOperationExecuted write FOnDDFileOperationExecuted;
     {Set AllowExec to false, if actual file should not be executed:}
+    property OnDDMenuPopup: TOnMenuPopup read FOnDDMenuPopup write FOnDDMenuPopup;
     property OnExecFile: TDirViewExecFileEvent
       read FOnExecFile write FOnExecFile;
     property OnHistoryChange: THistoryChangeEvent read FOnHistoryChange write FOnHistoryChange;
@@ -843,6 +847,7 @@ begin
     OnDrop := DDDrop;
     OnQueryContinueDrag := DDQueryContinueDrag;
     OnSpecifyDropTarget := DDSpecifyDropTarget;
+    OnMenuPopup := DDMenuPopup;
     OnMenuDestroy := DDMenuDone;
     OnDropHandlerSucceeded := DDDropHandlerSucceeded;
     OnGiveFeedback := DDGiveFeedback;
@@ -2070,6 +2075,15 @@ begin
     else FileName := '';
 end;
 
+procedure TCustomDirView.DDMenuPopup(Sender: TObject; AMenu: HMenu;
+  DataObj: IDataObject; AMinCustCmd: Integer; grfKeyState: Longint; pt: TPoint);
+begin
+  if Assigned(OnDDMenuPopup) then
+  begin
+    OnDDMenuPopup(Self, AMenu, DataObj, AMinCustCmd, grfKeyState, pt);
+  end;
+end;
+
 procedure TCustomDirView.DDMenuDone(Sender: TObject; AMenu: HMenu);
 begin
 end;

+ 2 - 1
packages/filemng/DirView.hpp

@@ -14,8 +14,8 @@
 #include <PathLabel.hpp>	// Pascal unit
 #include <CustomPathComboBox.hpp>	// Pascal unit
 #include <Controls.hpp>	// Pascal unit
-#include <IEListView.hpp>	// Pascal unit
 #include <NortonLikeListView.hpp>	// Pascal unit
+#include <IEListView.hpp>	// Pascal unit
 #include <BaseUtils.hpp>	// Pascal unit
 #include <SysUtils.hpp>	// Pascal unit
 #include <FileCtrl.hpp>	// Pascal unit
@@ -494,6 +494,7 @@ __published:
 	__property OnDDExecuted ;
 	__property OnDDFileOperation ;
 	__property OnDDFileOperationExecuted ;
+	__property OnDDMenuPopup ;
 	__property OnExecFile ;
 	__property Graphics::TColor CompressedColor = {read=FCompressedColor, write=SetCompressedColor, default=16711680};
 	__property bool ConfirmDelete = {read=FConfirmDelete, write=FConfirmDelete, default=1};

+ 3 - 0
packages/my/filemng/CustomDirView.hpp

@@ -173,6 +173,7 @@ private:
 	Classes::TNotifyEvent FOnDDEnd;
 	TDDOnCreateDataObject FOnDDCreateDataObject;
 	TDDOnTargetHasDropHandler FOnDDTargetHasDropHandler;
+	Dragdrop::TOnMenuPopup FOnDDMenuPopup;
 	TDirViewExecFileEvent FOnExecFile;
 	bool FForceRename;
 	Dragdrop::TDragResult FLastDDResult;
@@ -268,6 +269,7 @@ protected:
 	void __fastcall DDDrop(_di_IDataObject DataObj, int grfKeyState, const Types::TPoint &Point, int &dwEffect);
 	virtual void __fastcall DDDropHandlerSucceeded(System::TObject* Sender, int grfKeyState, const Types::TPoint &Point, int dwEffect);
 	virtual void __fastcall DDGiveFeedback(int dwEffect, HRESULT &Result);
+	void __fastcall DDMenuPopup(System::TObject* Sender, HMENU AMenu, _di_IDataObject DataObj, int AMinCustCmd, int grfKeyState, const Types::TPoint &pt);
 	virtual void __fastcall DDMenuDone(System::TObject* Sender, HMENU AMenu);
 	void __fastcall DDProcessDropped(System::TObject* Sender, int grfKeyState, const Types::TPoint &Point, int dwEffect);
 	virtual void __fastcall DDQueryContinueDrag(BOOL FEscapePressed, int grfKeyState, HRESULT &Result);
@@ -440,6 +442,7 @@ public:
 	__property TDDExecutedEvent OnDDExecuted = {read=FOnDDExecuted, write=FOnDDExecuted};
 	__property TDDFileOperationEvent OnDDFileOperation = {read=FOnDDFileOperation, write=FOnDDFileOperation};
 	__property TDDFileOperationExecutedEvent OnDDFileOperationExecuted = {read=FOnDDFileOperationExecuted, write=FOnDDFileOperationExecuted};
+	__property Dragdrop::TOnMenuPopup OnDDMenuPopup = {read=FOnDDMenuPopup, write=FOnDDMenuPopup};
 	__property TDirViewExecFileEvent OnExecFile = {read=FOnExecFile, write=FOnExecFile};
 	__property THistoryChangeEvent OnHistoryChange = {read=FOnHistoryChange, write=FOnHistoryChange};
 	__property Custompathcombobox::TCustomPathComboBox* PathComboBox = {read=FPathComboBox, write=SetPathComboBox};

+ 183 - 0
putty/BUFFER.C

@@ -0,0 +1,183 @@
+/*
+ * Author: Tatu Ylonen <[email protected]>
+ * Copyright (c) 1995 Tatu Ylonen <[email protected]>, Espoo, Finland
+ *                    All rights reserved
+ * Functions for manipulating fifo buffers (that can grow if needed).
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include "buffer.h"
+#include "puttymem.h"
+
+#define PUT_32BIT(cp, value) do { \
+  (cp)[0] = (value) >> 24; \
+  (cp)[1] = (value) >> 16; \
+  (cp)[2] = (value) >> 8; \
+  (cp)[3] = (value); } while (0)
+
+
+/* Initializes the buffer structure. */
+
+void
+buffer_init(Buffer *buffer)
+{
+	const u_int len = 4096;
+
+	buffer->alloc = 0;
+	buffer->buf = smalloc(len);
+	buffer->alloc = len;
+	buffer->offset = 0;
+	buffer->end = 0;
+}
+
+/* Frees any memory used for the buffer. */
+
+void
+buffer_free(Buffer *buffer)
+{
+	if (buffer->alloc > 0) {
+		memset(buffer->buf, 0, buffer->alloc);
+		buffer->alloc = 0;
+		sfree(buffer->buf);
+	}
+}
+
+/* Appends data to the buffer, expanding it if necessary. */
+
+void
+buffer_append(Buffer *buffer, const void *data, u_int len)
+{
+	void *p;
+	p = buffer_append_space(buffer, len);
+	memcpy(p, data, len);
+}
+
+/*
+ * Appends space to the buffer, expanding the buffer if necessary. This does
+ * not actually copy the data into the buffer, but instead returns a pointer
+ * to the allocated region.
+ */
+
+void *
+buffer_append_space(Buffer *buffer, u_int len)
+{
+	u_int newlen;
+	void *p;
+
+	if (len > 0x100000) {
+#if 0
+		fatal("buffer_append_space: len %u not supported", len);
+#endif
+		printf("buffer_append_space: len %u not supported\r\n", len);
+		return NULL;
+	}
+
+	/* If the buffer is empty, start using it from the beginning. */
+	if (buffer->offset == buffer->end) {
+		buffer->offset = 0;
+		buffer->end = 0;
+	}
+restart:
+	/* If there is enough space to store all data, store it now. */
+	if (buffer->end + len < buffer->alloc) {
+		p = buffer->buf + buffer->end;
+		buffer->end += len;
+		return p;
+	}
+	/*
+	 * If the buffer is quite empty, but all data is at the end, move the
+	 * data to the beginning and retry.
+	 */
+	if (buffer->offset > buffer->alloc / 2) {
+		memmove(buffer->buf, buffer->buf + buffer->offset,
+			buffer->end - buffer->offset);
+		buffer->end -= buffer->offset;
+		buffer->offset = 0;
+		goto restart;
+	}
+	/* Increase the size of the buffer and retry. */
+
+	newlen = buffer->alloc + len + 32768;
+	if (newlen > 0xa00000) {
+#if 0
+		fatal("buffer_append_space: alloc %u not supported",
+		    newlen);
+#endif
+		printf("buffer_append_space: alloc %u not supported\r\n",
+		    newlen);
+		return NULL;
+	}
+
+	buffer->buf = srealloc(buffer->buf, newlen);
+	buffer->alloc = newlen;
+	goto restart;
+	/* NOTREACHED */
+}
+
+/* Returns the number of bytes of data in the buffer. */
+
+u_int
+buffer_len(Buffer *buffer)
+{
+	return buffer->end - buffer->offset;
+}
+
+/* Returns a pointer to the first used byte in the buffer. */
+
+void *
+buffer_ptr(Buffer *buffer)
+{
+	return buffer->buf + buffer->offset;
+}
+
+void
+buffer_put_int(Buffer *buffer, u_int value)
+{
+	char buf[4];
+
+	PUT_32BIT(buf, value);
+	buffer_append(buffer, buf, 4);
+}
+
+/*
+ * Stores a character in the buffer.
+ */
+void
+buffer_put_char(Buffer *buffer, int value)
+{
+	char ch = value;
+
+	buffer_append(buffer, &ch, 1);
+}
+
+/*
+ * Stores and arbitrary binary string in the buffer.
+ */
+void
+buffer_put_string(Buffer *buffer, const void *buf, u_int len)
+{
+	buffer_put_int(buffer, len);
+	buffer_append(buffer, buf, len);
+}
+void
+buffer_put_cstring(Buffer *buffer, const char *s)
+{
+	if (s == NULL) {
+#if 0
+		fatal("buffer_put_cstring: s == NULL");
+#endif
+		printf("buffer_put_cstring: s == NULL\r\n");
+		return;
+	}
+
+	buffer_put_string(buffer, s, strlen(s));
+}

+ 12 - 0
putty/CONFIG.C

@@ -1512,6 +1512,12 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
 		      'i', HELPCTX(ssh_auth_ki),
 		      dlg_stdcheckbox_handler,
 		      I(offsetof(Config,try_ki_auth)));
+#ifdef GSSAPI
+	ctrl_checkbox(s, "Attempt MIT Kerberos 5 GSSAPI auth (SSH2)", NO_SHORTCUT,
+		      HELPCTX(ssh_auth_gssapi),
+		      dlg_stdcheckbox_handler,
+		      I(offsetof(Config, try_gssapi_auth)));
+#endif
 
 	s = ctrl_getset(b, "Connection/SSH/Auth", "params",
 			"Authentication parameters");
@@ -1522,6 +1528,12 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
 		      HELPCTX(ssh_auth_changeuser),
 		      dlg_stdcheckbox_handler,
 		      I(offsetof(Config,change_username)));
+#ifdef GSSAPI
+	ctrl_checkbox(s, "Allow Kerberos 5 ticket forwarding in GSSAPI (SSH2)", NO_SHORTCUT,
+		      HELPCTX(ssh_auth_gssapi_fwd_tgt),
+		      dlg_stdcheckbox_handler,
+		      I(offsetof(Config, gssapi_fwd_tgt)));
+#endif
 	ctrl_filesel(s, "Private key file for authentication:", 'k',
 		     FILTER_KEY_FILES, FALSE, "Select private key file",
 		     HELPCTX(ssh_auth_privkey),

+ 27 - 14
putty/MAKEFILE.VC

@@ -75,14 +75,26 @@
 #      show up as GPFs at the point of failure rather than appearing
 #      later on as second-level damage.
 #
+#  - XFLAGS=/DGSSAPI
+#      Enable support for GSSAPI authentication in SSH 2
+#
 
 # If you rename this file to `Makefile', you should change this line,
 # so that the .rsp files still depend on the correct makefile.
 MAKEFILE = Makefile.vc
 
+# location of MIT's Kerberos for Windows SDK
+# (available here: http://web.mit.edu/kerberos/www/index.html)
+KRB5_DIR = "D:\Devel\Kerberos\kfw-2.6.1\kfw-2.6.1-sdk"
+
+XFLAGS = /I$(KRB5_DIR)\inc\krb5 /DGSSAPI
+#GSSAPILIBS = $(KRB5_DIR)\lib\i386\gssapi32.lib
+
+VER=/DRELEASE="0.54 - Kerberos 5 GSSAPI"
+
 # C compilation flags
 CFLAGS = /nologo /W3 /O1 /D_WINDOWS /D_WIN32_WINDOWS=0x401 /DWINVER=0x401
-LFLAGS = /incremental:no /fixed
+LFLAGS = /incremental:no /fixed /opt:ref
 
 .c.obj:
 	cl $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) /c $*.c
@@ -98,7 +110,7 @@ pageant.exe: misc.obj pageant.obj pageant.res pageantc.obj sshaes.obj \
 		winmisc.obj winutils.obj pageant.rsp
 	link $(LFLAGS) -out:pageant.exe -map:pageant.map @pageant.rsp
 
-plink.exe: be_all.obj cmdline.obj console.obj ldisc.obj logging.obj misc.obj \
+plink.exe: be_all.obj buffer.obj cmdline.obj console.obj ldisc.obj logging.obj misc.obj \
 		noise.obj pageantc.obj plink.obj plink.res portfwd.obj \
 		pproxy.obj proxy.obj raw.obj rlogin.obj settings.obj ssh.obj \
 		sshaes.obj sshblowf.obj sshbn.obj sshcrc.obj sshcrcda.obj \
@@ -106,9 +118,9 @@ plink.exe: be_all.obj cmdline.obj console.obj ldisc.obj logging.obj misc.obj \
 		sshrand.obj sshrsa.obj sshsh512.obj sshsha.obj sshzlib.obj \
 		telnet.obj tree234.obj version.obj wildcard.obj windefs.obj \
 		winmisc.obj winnet.obj winstore.obj x11fwd.obj plink.rsp
-	link $(LFLAGS) -out:plink.exe -map:plink.map @plink.rsp
+	link $(LFLAGS) -out:plink.exe -map:plink.map $(GSSAPILIBS) @plink.rsp
 
-pscp.exe: be_none.obj cmdline.obj console.obj int64.obj logging.obj misc.obj \
+pscp.exe: be_none.obj buffer.obj cmdline.obj console.obj int64.obj logging.obj misc.obj \
 		noise.obj pageantc.obj portfwd.obj pproxy.obj proxy.obj \
 		scp.obj scp.res settings.obj sftp.obj ssh.obj sshaes.obj \
 		sshblowf.obj sshbn.obj sshcrc.obj sshcrcda.obj sshdes.obj \
@@ -116,9 +128,9 @@ pscp.exe: be_none.obj cmdline.obj console.obj int64.obj logging.obj misc.obj \
 		sshrsa.obj sshsh512.obj sshsha.obj sshzlib.obj tree234.obj \
 		version.obj wildcard.obj windefs.obj winmisc.obj winnet.obj \
 		winsftp.obj winstore.obj x11fwd.obj pscp.rsp
-	link $(LFLAGS) -out:pscp.exe -map:pscp.map @pscp.rsp
+	link $(LFLAGS) -out:pscp.exe -map:pscp.map $(GSSAPILIBS) @pscp.rsp
 
-psftp.exe: be_none.obj cmdline.obj console.obj int64.obj logging.obj \
+psftp.exe: be_none.obj buffer.obj cmdline.obj console.obj int64.obj logging.obj \
 		misc.obj noise.obj pageantc.obj portfwd.obj pproxy.obj \
 		proxy.obj psftp.obj scp.res settings.obj sftp.obj ssh.obj \
 		sshaes.obj sshblowf.obj sshbn.obj sshcrc.obj sshcrcda.obj \
@@ -126,9 +138,9 @@ psftp.exe: be_none.obj cmdline.obj console.obj int64.obj logging.obj \
 		sshrand.obj sshrsa.obj sshsh512.obj sshsha.obj sshzlib.obj \
 		tree234.obj version.obj wildcard.obj windefs.obj winmisc.obj \
 		winnet.obj winsftp.obj winstore.obj x11fwd.obj psftp.rsp
-	link $(LFLAGS) -out:psftp.exe -map:psftp.map @psftp.rsp
+	link $(LFLAGS) -out:psftp.exe -map:psftp.map $(GSSAPILIBS) @psftp.rsp
 
-putty.exe: be_all.obj cmdline.obj config.obj dialog.obj ldisc.obj \
+putty.exe: be_all.obj buffer.obj cmdline.obj config.obj dialog.obj ldisc.obj \
 		ldiscucs.obj logging.obj misc.obj noise.obj pageantc.obj \
 		portfwd.obj pproxy.obj printing.obj proxy.obj raw.obj \
 		rlogin.obj settings.obj sizetip.obj ssh.obj sshaes.obj \
@@ -139,7 +151,7 @@ putty.exe: be_all.obj cmdline.obj config.obj dialog.obj ldisc.obj \
 		wildcard.obj win_res.res wincfg.obj winctrls.obj windefs.obj \
 		windlg.obj window.obj winmisc.obj winnet.obj winstore.obj \
 		winutils.obj x11fwd.obj putty.rsp
-	link $(LFLAGS) -out:putty.exe -map:putty.map @putty.rsp
+	link $(LFLAGS) -out:putty.exe -map:putty.map $(GSSAPILIBS) @putty.rsp
 
 puttygen.exe: import.obj misc.obj noise.obj puttygen.obj puttygen.res \
 		sshaes.obj sshbn.obj sshdes.obj sshdss.obj sshdssg.obj \
@@ -170,7 +182,7 @@ pageant.rsp: $(MAKEFILE)
 
 plink.rsp: $(MAKEFILE)
 	echo /nologo /subsystem:console > plink.rsp
-	echo advapi32.lib be_all.obj cmdline.obj comctl32.lib >> plink.rsp
+	echo advapi32.lib be_all.obj buffer.obj cmdline.obj comctl32.lib >> plink.rsp
 	echo comdlg32.lib console.obj gdi32.lib imm32.lib >> plink.rsp
 	echo ldisc.obj logging.obj misc.obj noise.obj >> plink.rsp
 	echo pageantc.obj plink.obj plink.res portfwd.obj >> plink.rsp
@@ -186,7 +198,7 @@ plink.rsp: $(MAKEFILE)
 
 pscp.rsp: $(MAKEFILE)
 	echo /nologo /subsystem:console > pscp.rsp
-	echo advapi32.lib be_none.obj cmdline.obj comctl32.lib >> pscp.rsp
+	echo advapi32.lib be_none.obj buffer.obj cmdline.obj comctl32.lib >> pscp.rsp
 	echo comdlg32.lib console.obj gdi32.lib imm32.lib >> pscp.rsp
 	echo int64.obj logging.obj misc.obj noise.obj >> pscp.rsp
 	echo pageantc.obj portfwd.obj pproxy.obj proxy.obj >> pscp.rsp
@@ -201,7 +213,7 @@ pscp.rsp: $(MAKEFILE)
 
 psftp.rsp: $(MAKEFILE)
 	echo /nologo /subsystem:console > psftp.rsp
-	echo advapi32.lib be_none.obj cmdline.obj comctl32.lib >> psftp.rsp
+	echo advapi32.lib be_none.obj buffer.obj cmdline.obj comctl32.lib >> psftp.rsp
 	echo comdlg32.lib console.obj gdi32.lib imm32.lib >> psftp.rsp
 	echo int64.obj logging.obj misc.obj noise.obj >> psftp.rsp
 	echo pageantc.obj portfwd.obj pproxy.obj proxy.obj >> psftp.rsp
@@ -217,7 +229,7 @@ psftp.rsp: $(MAKEFILE)
 
 putty.rsp: $(MAKEFILE)
 	echo /nologo /subsystem:windows > putty.rsp
-	echo advapi32.lib be_all.obj cmdline.obj comctl32.lib >> putty.rsp
+	echo advapi32.lib be_all.obj buffer.obj cmdline.obj comctl32.lib >> putty.rsp
 	echo comdlg32.lib config.obj dialog.obj gdi32.lib >> putty.rsp
 	echo imm32.lib ldisc.obj ldiscucs.obj logging.obj >> putty.rsp
 	echo misc.obj noise.obj pageantc.obj portfwd.obj >> putty.rsp
@@ -269,6 +281,7 @@ be_none.obj: be_none.c putty.h puttyps.h network.h misc.h winstuff.h \
 be_nossh.obj: be_nossh.c putty.h puttyps.h network.h misc.h winstuff.h \
 		mac\macstuff.h unix\unix.h puttymem.h tree234.h winhelp.h \
 		charset\charset.h
+buffer.obj: buffer.c puttymem.h
 cmdgen.obj: cmdgen.c putty.h ssh.h puttyps.h network.h misc.h puttymem.h \
 		int64.h winstuff.h mac\macstuff.h unix\unix.h tree234.h \
 		winhelp.h charset\charset.h
@@ -424,7 +437,7 @@ slookup.obj: charset\slookup.c charset\charset.h charset\internal.h \
 		charset\enum.c charset\sbcsdat.c charset\utf8.c
 ssh.obj: ssh.c putty.h tree234.h ssh.h puttyps.h network.h misc.h puttymem.h \
 		int64.h winstuff.h mac\macstuff.h unix\unix.h winhelp.h \
-		charset\charset.h
+		charset\charset.h buffer.h buffer.c
 sshaes.obj: sshaes.c ssh.h puttymem.h network.h int64.h misc.h
 sshblowf.obj: sshblowf.c ssh.h puttymem.h network.h int64.h misc.h
 sshbn.obj: sshbn.c misc.h ssh.h puttymem.h network.h int64.h

+ 8 - 0
putty/SETTINGS.C

@@ -225,6 +225,10 @@ void save_open_settings(void *sesskey, int do_host, Config *cfg)
 	   cfg->ssh_cipherlist);
     write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth);
     write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
+#ifdef GSSAPI
+    write_setting_i(sesskey, "AuthGSSAPI", cfg->try_gssapi_auth);
+    write_setting_i(sesskey, "GSSAPIFwdTGT", cfg->gssapi_fwd_tgt);
+#endif
     write_setting_i(sesskey, "SshProt", cfg->sshprot);
     write_setting_i(sesskey, "SSH2DES", cfg->ssh2_des_cbc);
     write_setting_filename(sesskey, "PublicKeyFile", cfg->keyfile);
@@ -481,6 +485,10 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg)
     gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc);
     gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
     gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth);
+#ifdef GSSAPI
+    gppi(sesskey, "AuthGSSAPI", 0, &cfg->try_gssapi_auth);
+    gppi(sesskey, "GSSAPIFwdTGT", 0, &cfg->gssapi_fwd_tgt);
+#endif
     gppfile(sesskey, "PublicKeyFile", &cfg->keyfile);
     gpps(sesskey, "RemoteCommand", "", cfg->remote_cmd,
 	 sizeof(cfg->remote_cmd));

+ 555 - 4
putty/SSH.C

@@ -100,6 +100,16 @@
 #define SSH2_MSG_CHANNEL_SUCCESS                  99	/* 0x63 */
 #define SSH2_MSG_CHANNEL_FAILURE                  100	/* 0x64 */
 
+/* draft-ietf-secsh-gsskeyex-06 */
+#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE		60
+#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN			61
+#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE	63
+#define SSH2_MSG_USERAUTH_GSSAPI_ERROR			64
+#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK			65
+#define SSH2_MSG_USERAUTH_GSSAPI_MIC			66
+
+#define SSH_GSS_OIDTYPE 0x06
+
 /*
  * Packet type contexts, so that ssh2_pkt_type can correctly decode
  * the ambiguous type numbers back into the correct type strings.
@@ -109,6 +119,9 @@
 #define SSH2_PKTCTX_PUBLICKEY        0x0010
 #define SSH2_PKTCTX_PASSWORD         0x0020
 #define SSH2_PKTCTX_KBDINTER         0x0040
+#ifdef GSSAPI
+#	define SSH2_PKTCTX_GSSAPI    0x0080
+#endif
 #define SSH2_PKTCTX_AUTH_MASK        0x00F0
 
 #define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1	/* 0x1 */
@@ -127,6 +140,26 @@
 #define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14	/* 0xe */
 #define SSH2_DISCONNECT_ILLEGAL_USER_NAME         15	/* 0xf */
 
+#ifdef GSSAPI
+#include "gssapiw.h"
+#include "buffer.h"
+
+#define GSSAPIDLL "gssapi32"
+
+typedef struct {
+	OM_uint32	major;   /* both */
+	OM_uint32	minor;   /* both */
+	gss_ctx_id_t	context; /* both */
+	gss_name_t	name;    /* both */
+	gss_OID		oid;     /* client */
+} Gssctxt;
+
+#ifdef _WINDOWS
+#	define snprintf _snprintf
+#endif
+
+#endif
+
 static const char *const ssh2_disconnect_reasons[] = {
     NULL,
     "SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT",
@@ -250,6 +283,14 @@ static char *ssh2_pkt_type(int pkt_ctx, int type)
     translate(SSH2_MSG_CHANNEL_REQUEST);
     translate(SSH2_MSG_CHANNEL_SUCCESS);
     translate(SSH2_MSG_CHANNEL_FAILURE);
+#ifdef GSSAPI
+    translatec(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, SSH2_PKTCTX_GSSAPI);
+    translatec(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, SSH2_PKTCTX_GSSAPI);
+    translatec(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, SSH2_PKTCTX_GSSAPI);
+    translatec(SSH2_MSG_USERAUTH_GSSAPI_ERROR, SSH2_PKTCTX_GSSAPI);
+    translatec(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, SSH2_PKTCTX_GSSAPI);
+    translatec(SSH2_MSG_USERAUTH_GSSAPI_MIC, SSH2_PKTCTX_GSSAPI);
+#endif
     return "unknown";
 }
 #undef translate
@@ -4455,6 +4496,357 @@ static void ssh2_set_window(struct ssh_channel *c, unsigned newwin)
     }
 }
 
+#ifdef GSSAPI
+/* Check that the OID in a data stream matches that in the context */
+static int
+ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
+{
+	return (ctx != NULL && ctx->oid != GSS_C_NO_OID &&
+	    ctx->oid->length == len &&
+	    memcmp(ctx->oid->elements, data, len) == 0);
+}
+
+/* Set the contexts OID from a data stream */
+static void
+ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len)
+{
+	if (ctx->oid != GSS_C_NO_OID) {
+		sfree(ctx->oid->elements);
+		sfree(ctx->oid);
+	}
+	ctx->oid = smalloc(sizeof(gss_OID_desc));
+	ctx->oid->length = len;
+	ctx->oid->elements = smalloc(len);
+	memcpy(ctx->oid->elements, data, len);
+}
+
+/* Set the contexts OID */
+static void
+ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid)
+{
+	ssh_gssapi_set_oid_data(ctx, oid->elements, oid->length);
+}
+
+static void
+ssh_gssapi_last_error(Ssh ssh, Gssctxt *ctxt,
+		      OM_uint32 *major_status, OM_uint32 *minor_status)
+{
+	OM_uint32 lmin;
+	gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
+	OM_uint32 ctx;
+	char *msgbuf;
+
+
+	if (major_status != NULL)
+		*major_status = ctxt->major;
+	if (minor_status != NULL)
+		*minor_status = ctxt->minor;
+
+	ctx = 0;
+	/* The GSSAPI error */
+	do {
+		gss_display_status(&lmin, ctxt->major,
+		    GSS_C_GSS_CODE, GSS_C_NULL_OID, &ctx, &msg);
+		msgbuf = dupprintf("GSSAPI error: %s\r\n", msg.value);
+		logeventf(ssh, msgbuf);
+		c_write_str(ssh, msgbuf);
+		sfree(msgbuf);
+
+		gss_release_buffer(&lmin, &msg);
+	} while (ctx != 0);
+
+	/* The mechanism specific error */
+	do {
+		gss_display_status(&lmin, ctxt->minor,
+		    GSS_C_MECH_CODE, GSS_C_NULL_OID, &ctx, &msg);
+
+		msgbuf = dupprintf("GSSAPI mech specific error: %s\r\n", msg.value);
+		logeventf(ssh, msgbuf);
+		c_write_str(ssh, msgbuf);
+		sfree(msgbuf);
+
+		gss_release_buffer(&lmin, &msg);
+	} while (ctx != 0);
+
+}
+
+/* All this effort to report an error ... */
+static void
+ssh_gssapi_error(Ssh ssh, Gssctxt *ctxt)
+{
+	ssh_gssapi_last_error(ssh, ctxt, NULL, NULL);
+}
+
+/*
+ * Initialise our GSSAPI context. We use this opaque structure to contain all
+ * of the data which both the client and server need to persist across
+ * {accept,init}_sec_context calls, so that when we do it from the userauth
+ * stuff life is a little easier
+ */
+static void
+ssh_gssapi_build_ctx(Gssctxt **ctx)
+{
+	*ctx = smalloc(sizeof (Gssctxt));
+	(*ctx)->major = 0;
+	(*ctx)->minor = 0;
+	(*ctx)->context = GSS_C_NO_CONTEXT;
+	(*ctx)->name = GSS_C_NO_NAME;
+	(*ctx)->oid = GSS_C_NO_OID;
+}
+
+/* Delete our context, providing it has been built correctly */
+static void
+ssh_gssapi_delete_ctx(Gssctxt **ctx)
+{
+	OM_uint32 ms;
+
+	if ((*ctx) == NULL)
+		return;
+	if ((*ctx)->context != GSS_C_NO_CONTEXT)
+		gss_delete_sec_context(&ms, &(*ctx)->context, GSS_C_NO_BUFFER);
+	if ((*ctx)->name != GSS_C_NO_NAME)
+		gss_release_name(&ms, &(*ctx)->name);
+	if ((*ctx)->oid != GSS_C_NO_OID) {
+		sfree((*ctx)->oid->elements);
+		sfree((*ctx)->oid);
+		(*ctx)->oid = GSS_C_NO_OID;
+	}
+
+	sfree(*ctx);
+	*ctx = NULL;
+}
+
+/*
+ * Wrapper to init_sec_context
+ * Requires that the context contains:
+ *	oid
+ *	server name (from ssh_gssapi_import_name)
+ */
+static OM_uint32
+ssh_gssapi_init_ctx(Ssh ssh, Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
+    gss_buffer_desc* send_tok, OM_uint32 *flags)
+{
+	int deleg_flag = 0;
+
+	if (deleg_creds) {
+		deleg_flag = GSS_C_DELEG_FLAG;
+		logevent("GSSAPI: delegating credentials");
+	}
+
+	ctx->major = gss_init_sec_context(&ctx->minor,
+	    GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
+	    GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
+	    0, NULL, recv_tok, NULL, send_tok, flags, NULL);
+
+	if (GSS_ERROR(ctx->major))
+		ssh_gssapi_error(ssh, ctx);
+
+	return (ctx->major);
+}
+
+/* Create a service name for the given host */
+static OM_uint32
+ssh_gssapi_import_name(Ssh ssh, Gssctxt *ctx)
+{
+	gss_buffer_desc gssbuf;
+	const char *host = ssh->savedhost;
+
+	gssbuf.length = sizeof("host@") + strlen(host);
+	gssbuf.value = smalloc(gssbuf.length);
+	snprintf(gssbuf.value, gssbuf.length, "host@%s", host);
+
+	if ((ctx->major = gss_import_name(&ctx->minor,
+	    &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
+		ssh_gssapi_error(ssh, ctx);
+
+	sfree(gssbuf.value);
+	return (ctx->major);
+}
+
+static void
+ssh_gssapi_buildmic(Buffer *b, const char *session_id, const char *user,
+    const char *service, const char *context)
+{
+	buffer_init(b);
+	buffer_put_cstring(b, session_id);
+	buffer_put_char(b, SSH2_MSG_USERAUTH_REQUEST);
+	buffer_put_cstring(b, user);
+	buffer_put_cstring(b, service);
+	buffer_put_cstring(b, context);
+}
+
+static OM_uint32
+ssh_gssapi_sign(Ssh ssh, Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
+{
+	if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
+	    GSS_C_QOP_DEFAULT, buffer, hash)))
+		ssh_gssapi_error(ssh, ctx);
+
+	return (ctx->major);
+}
+
+static OM_uint32
+process_gssapi_token(Ssh ssh, Gssctxt *gssctxt, gss_buffer_t recv_tok, const char *username)
+{
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+	gss_buffer_desc gssbuf, mic;
+	OM_uint32 status, ms, gss_flags;
+	Buffer b;
+
+	logevent("GSSAPI: process_gssapi_token");
+
+	status = ssh_gssapi_init_ctx(ssh, gssctxt, ssh->cfg.gssapi_fwd_tgt,
+	    recv_tok, &send_tok, &gss_flags);
+
+	if (send_tok.length > 0) {
+		if (GSS_ERROR(status))
+			ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+		else
+			ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+
+		ssh2_pkt_addstring_start(ssh);
+		ssh2_pkt_addstring_data(ssh, send_tok.value, send_tok.length);
+		ssh2_pkt_send(ssh);
+		gss_release_buffer(&ms, &send_tok);
+	}
+
+	if (status == GSS_S_COMPLETE) {
+		/* send either complete or MIC, depending on mechanism */
+		if (!(gss_flags & GSS_C_INTEG_FLAG)) {
+			ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
+			ssh2_pkt_send(ssh);
+		} else {
+			ssh_gssapi_buildmic(&b, ssh->v2_session_id, username,
+				"ssh-connection", "gssapi-with-mic");
+
+			gssbuf.value = buffer_ptr(&b);
+			gssbuf.length = buffer_len(&b);
+
+			status = ssh_gssapi_sign(ssh, gssctxt, &gssbuf, &mic);
+
+			if (!GSS_ERROR(status)) {
+				ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC);
+				ssh2_pkt_addstring_start(ssh);
+				ssh2_pkt_addstring_data(ssh, mic.value, mic.length);
+				ssh2_pkt_send(ssh);
+			} else
+				ssh_gssapi_error(ssh, gssctxt);
+
+			buffer_free(&b);
+			gss_release_buffer(&ms, &mic);
+		}
+	}
+
+	return status;
+}
+
+static int
+input_gssapi_response(Ssh ssh, Gssctxt *gssctxt, char *username)
+{
+	int oidlen;
+	char *oidv;
+
+	logevent("GSSAPI: input_gssapi_response");
+	
+	/* Setup our OID */
+	ssh2_pkt_getstring(ssh, &oidv, &oidlen);
+
+	if (oidlen <= 2 ||
+	    oidv[0] != SSH_GSS_OIDTYPE ||
+	    oidv[1] != oidlen - 2) {
+		sfree(oidv);
+		logevent("GSSAPI: Badly encoded mechanism OID received");
+		return TRUE;
+	}
+
+	if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2))
+		bombout(("GSSAPI: Server returned different OID than expected"));
+
+	sfree(oidv);
+
+	if (GSS_ERROR(process_gssapi_token(ssh, gssctxt, GSS_C_NO_BUFFER, username))) {
+		/* Start again with next method on list */
+		logevent("GSSAPI: Trying to start again");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static int
+input_gssapi_token(Ssh ssh, Gssctxt *gssctxt, char *username)
+{
+	gss_buffer_desc recv_tok;
+	OM_uint32 status;
+	char *sval;
+	u_int slen;
+
+	logevent("GSSAPI: input_gssapi_token");
+
+	ssh2_pkt_getstring(ssh, &sval, &slen);
+	recv_tok.value = sval;
+	recv_tok.length = slen;
+
+	status = process_gssapi_token(ssh, gssctxt, &recv_tok, username);
+
+	sfree(recv_tok.value);
+
+	if (GSS_ERROR(status)) {
+		/* Start again with the next method in the list */
+		logevent("GSSAPI: Trying to start again");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+input_gssapi_errtok(Ssh ssh, Gssctxt *gssctxt)
+{
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+	gss_buffer_desc recv_tok;
+	OM_uint32 status, ms;
+	char *val;
+	u_int len;
+
+
+	logevent("GSSAPI: input_gssapi_errtok");
+
+	ssh2_pkt_getstring(ssh, &val, &len);
+	recv_tok.value = val;
+	recv_tok.length = len;
+
+	/* Stick it into GSSAPI and see what it says */
+	status = ssh_gssapi_init_ctx(ssh, gssctxt, ssh->cfg.gssapi_fwd_tgt,
+				     &recv_tok, &send_tok, NULL);
+
+	sfree(recv_tok.value);
+	gss_release_buffer(&ms, &send_tok);
+
+	/* Server will be returning a failed packet after this one */
+}
+
+static void
+input_gssapi_error(Ssh ssh)
+{
+	OM_uint32 maj, min;
+	char *msg;
+	char *lang;
+
+	logevent("GSSAPI: input_gssapi_error");
+
+	maj = ssh2_pkt_getuint32(ssh);
+	min = ssh2_pkt_getuint32(ssh);
+	ssh2_pkt_getstring(ssh, &msg, NULL);
+	ssh2_pkt_getstring(ssh, &lang, NULL);
+
+	logeventf(ssh, "GSSAPI Server Error: %s", msg);
+
+	sfree(msg);
+	sfree(lang);
+}
+#endif /* GSSAPI */
+
 /*
  * Handle the SSH2 userauth and connection layers.
  */
@@ -4464,7 +4856,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 	enum {
 	    AUTH_INVALID, AUTH_PUBLICKEY_AGENT, AUTH_PUBLICKEY_FILE,
 		AUTH_PASSWORD,
-		AUTH_KEYBOARD_INTERACTIVE
+		AUTH_KEYBOARD_INTERACTIVE,
+		AUTH_GSSAPI
 	} method;
 	enum {
 	    AUTH_TYPE_NONE,
@@ -4473,10 +4866,19 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 		AUTH_TYPE_PUBLICKEY_OFFER_QUIET,
 		AUTH_TYPE_PASSWORD,
 		AUTH_TYPE_KEYBOARD_INTERACTIVE,
-		AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET
+		AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET,
+		AUTH_TYPE_GSSAPI
 	} type;
-	int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;
-	int tried_pubkey_config, tried_agent, tried_keyb_inter;
+	int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter
+#ifdef GSSAPI
+		, can_gssapi
+#endif
+		;
+	int tried_pubkey_config, tried_agent, tried_keyb_inter
+#ifdef GSSAPI
+		, tried_gssapi
+#endif
+		;
 	int kbd_inter_running;
 	int we_are_in;
 	int num_prompts, curr_prompt, echo;
@@ -4495,6 +4897,13 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 	int siglen, retlen, len;
 	char *q, *agentreq, *ret;
 	int try_send;
+#ifdef GSSAPI
+	Gssctxt *gssctxt;
+	gss_OID_set gss_supported;
+	OM_uint32 minor_status;
+	size_t gss_mech;
+	int gss_repeat_auth;
+#endif
     };
     crState(do_ssh2_authconn_state);
 
@@ -4606,6 +5015,14 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 	s->tried_agent = FALSE;
 	s->tried_keyb_inter = FALSE;
 	s->kbd_inter_running = FALSE;
+#ifdef GSSAPI
+	s->gss_supported = NULL;
+	s->tried_gssapi = FALSE;
+	s->gss_mech = 0;
+	gssapiDLLH = NULL;
+	s->gss_repeat_auth = FALSE;
+#endif
+
 	/* Load the pub half of ssh->cfg.keyfile so we notice if it's in Pageant */
 	if (!filename_is_null(ssh->cfg.keyfile)) {
 	    int keytype;
@@ -4721,6 +5138,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 			logevent("Server refused public key");
 		    } else if (s->type==AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) {
 			/* server declined keyboard-interactive; ignore */
+#ifdef GSSAPI
+		    } else if (s->type == AUTH_TYPE_GSSAPI) {
+#endif
 		    } else {
 			c_write_str(ssh, "Access denied\r\n");
 			logevent("Access denied");
@@ -4734,6 +5154,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 		    logevent("Further authentication required");
 		}
 
+#ifdef GSSAPI
+		s->can_gssapi =	ssh->cfg.try_gssapi_auth &&
+		    in_commasep_string("gssapi-with-mic", methods, methlen);
+#endif
 		s->can_pubkey =
 		    in_commasep_string("publickey", methods, methlen);
 		s->can_passwd =
@@ -4742,6 +5166,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 		    in_commasep_string("keyboard-interactive", methods, methlen);
 	    }
 
+#ifdef GSSAPI
+auth_begin:
+#endif
 	    s->method = 0;
 	    ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
 	    s->need_pw = FALSE;
@@ -4754,6 +5181,45 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 	     */
 	    s->echo = 0;
 
+#ifdef GSSAPI
+	    if (!s->method && s->can_gssapi && !s->tried_gssapi) {
+			s->tried_gssapi = TRUE;
+
+
+			if (gssapiDLLH != NULL)
+				FreeLibrary(gssapiDLLH);
+
+			logeventf(ssh, "GSSAPI: loading %s.dll", GSSAPIDLL);
+			gssapiDLLH = LoadLibrary(GSSAPIDLL);
+
+			if (gssapiDLLH == NULL) {
+				LPVOID message;
+				char *msgbuf;
+
+				FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+				      FORMAT_MESSAGE_FROM_SYSTEM |
+				      FORMAT_MESSAGE_IGNORE_INSERTS,
+				      NULL, GetLastError(),
+				      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+				      (LPTSTR)&message, 0, NULL);
+
+				msgbuf = dupprintf("GSSAPI: can't load Kerberos 5 GSSAPI library (%s.dll): %s",
+						GSSAPIDLL, (LPCTSTR)message);
+
+				LocalFree(message);
+				logevent(msgbuf);
+				if (flags & FLAG_VERBOSE)
+					c_write_str(ssh, msgbuf);
+				sfree(message);
+			} else {
+				if (gssapiLoadFuncs())
+					s->method = AUTH_GSSAPI;
+				else
+					FreeLibrary(gssapiDLLH);
+			}
+	    }
+#endif /* GSSAPI */
+
 	    if (!s->method && s->can_pubkey &&
 		agent_exists() && !s->tried_agent) {
 		/*
@@ -5120,6 +5586,91 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 		}
 	    }
 
+#ifdef GSSAPI
+	    if (s->method == AUTH_GSSAPI) {
+			logevent("GSSAPI: trying GSSAPI auth");
+			do {
+				int ok = FALSE;
+
+				if (s->gss_supported == NULL) {
+					gss_indicate_mechs(&s->minor_status, &s->gss_supported);
+					logeventf(ssh, "GSSAPI: number of OIDs: %d", s->gss_supported->count);
+				}
+
+				/* Check to see if the mechanism is usable before we offer it */
+				while (s->gss_mech < s->gss_supported->count && !ok) {
+					if (s->gssctxt)
+						ssh_gssapi_delete_ctx(&s->gssctxt);
+					ssh_gssapi_build_ctx(&s->gssctxt);
+					ssh_gssapi_set_oid(s->gssctxt, &s->gss_supported->elements[s->gss_mech]);
+
+					/* My DER encoding requires length<128 */
+					if (s->gss_supported->elements[s->gss_mech].length < 128 &&
+					    !GSS_ERROR(ssh_gssapi_import_name(ssh, s->gssctxt))) {
+						ok = TRUE; /* Mechanism works */
+					} else {
+						s->gss_mech++;
+					}
+				}
+
+				if (!ok) {
+					logevent("GSSAPI: no mechanisms available");
+					goto auth_begin;
+				}
+
+				logeventf(ssh, "GSSAPI: current OID: %d", s->gss_mech);
+
+				ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
+				ssh->pkt_ctx |= SSH2_PKTCTX_GSSAPI;
+
+				ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST);
+				ssh2_pkt_addstring(ssh, s->username);
+				ssh2_pkt_addstring(ssh, "ssh-connection");	/* service requested */
+				ssh2_pkt_addstring(ssh, "gssapi-with-mic");	/* method */
+				ssh2_pkt_adduint32(ssh, 1);
+				ssh2_pkt_adduint32(ssh, (s->gss_supported->elements[s->gss_mech].length) + 2);
+				ssh2_pkt_addbool(ssh, (char) SSH_GSS_OIDTYPE);
+				ssh2_pkt_addbool(ssh, (char) s->gss_supported->elements[s->gss_mech].length);
+				ssh2_pkt_adddata(ssh, s->gss_supported->elements[s->gss_mech].elements,
+					s->gss_supported->elements[s->gss_mech].length);
+				ssh2_pkt_send(ssh);
+
+				s->type = AUTH_TYPE_GSSAPI;
+				s->gss_mech++; /* Move along to next candidate */
+
+
+				do {
+					crWaitUntilV(ispkt);
+
+					if (ssh->pktin.type == SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) {
+						if ((s->gss_repeat_auth = input_gssapi_response(ssh, s->gssctxt, s->username)))
+							break;
+					}
+					else if (ssh->pktin.type == SSH2_MSG_USERAUTH_GSSAPI_TOKEN) {
+						if ((s->gss_repeat_auth = input_gssapi_token(ssh, s->gssctxt, s->username)))
+							break;
+					}
+					else if (ssh->pktin.type == SSH2_MSG_USERAUTH_GSSAPI_ERROR) {
+						input_gssapi_error(ssh);
+						break;
+					}
+					else if (ssh->pktin.type == SSH2_MSG_USERAUTH_GSSAPI_ERRTOK) {
+						input_gssapi_errtok(ssh, s->gssctxt);
+						break;
+					}
+					else {
+						break;
+					}
+				} while (1);
+
+			} while (s->gss_repeat_auth);
+
+			FreeLibrary(gssapiDLLH);
+			s->gotit = TRUE;
+	    }
+	    else
+#endif /* GSSAPI */
+
 	    if (s->method == AUTH_PUBLICKEY_FILE) {
 		/*
 		 * We have our passphrase. Now try the actual authentication.

+ 6 - 0
putty/SSH_.C

@@ -5,6 +5,12 @@ void ssh_close(void * handle)
   ssh_do_close((Ssh)handle);
 }
 
+int is_ssh(void * handle)
+{
+  Plug fn = (Plug)handle;
+  return (*fn)->closing == ssh_closing;
+} 
+
 int get_ssh_version(void * handle)
 {
   return ((Ssh)handle)->version;

+ 4 - 0
putty/WINHELP.H

@@ -85,6 +85,10 @@
 #define WINHELP_CTX_ssh_auth_changeuser "ssh.auth.changeuser"
 #define WINHELP_CTX_ssh_auth_tis "ssh.auth.tis"
 #define WINHELP_CTX_ssh_auth_ki "ssh.auth.ki"
+#ifdef GSSAPI
+#	define WINHELP_CTX_ssh_auth_gssapi "ssh.auth.gssapi"
+#	define WINHELP_CTX_ssh_auth_gssapi_fwd_tgt "ssh.auth.gssapifwdtgt"
+#endif
 #define WINHELP_CTX_selection_buttons "selection.buttons"
 #define WINHELP_CTX_selection_shiftdrag "selection.shiftdrag"
 #define WINHELP_CTX_selection_rect "selection.rect"

+ 44 - 0
putty/buffer.h

@@ -0,0 +1,44 @@
+/*	$OpenBSD: buffer.h,v 1.11 2002/03/04 17:27:39 stevesk Exp $	*/
+
+/*
+ * Author: Tatu Ylonen <[email protected]>
+ * Copyright (c) 1995 Tatu Ylonen <[email protected]>, Espoo, Finland
+ *                    All rights reserved
+ * Code for manipulating FIFO buffers.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#ifndef BUFFER_H
+#define BUFFER_H
+
+typedef unsigned int  u_int;
+typedef unsigned char u_char;
+
+typedef struct {
+	u_char	*buf;		/* Buffer for data. */
+	u_int	 alloc;		/* Number of bytes allocated for data. */
+	u_int	 offset;	/* Offset of first byte containing data. */
+	u_int	 end;		/* Offset of last byte containing data. */
+}    Buffer;
+
+void	buffer_init(Buffer *);
+void	buffer_free(Buffer *);
+
+void	buffer_append(Buffer *, const void *, u_int);
+void	*buffer_append_space(Buffer *, u_int);
+
+u_int	buffer_len(Buffer *);
+void	*buffer_ptr(Buffer *);
+
+void	buffer_put_int(Buffer *, u_int);
+
+void	buffer_put_char(Buffer *, int);
+void	buffer_put_string(Buffer *, const void *, u_int);
+void	buffer_put_cstring(Buffer *, const char *);
+
+#endif				/* BUFFER_H */

+ 379 - 0
putty/gssapiw.h

@@ -0,0 +1,379 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Copyright 2004 Vaclav Tomec <[email protected]>
+ *
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *
+ *  wrapper for gssapi32.dll
+ *  you don't need link PuTTY with gssapi32.lib
+ *
+ */
+
+#ifndef GSSAPIW_H
+#define GSSAPIW_H
+
+
+HMODULE gssapiDLLH;
+
+
+typedef unsigned int gss_uint32;
+typedef gss_uint32	OM_uint32;
+
+typedef struct gss_OID_desc_struct {
+      OM_uint32 length;
+      void *elements;
+} gss_OID_desc, *gss_OID;
+
+typedef struct gss_OID_set_desc_struct  {
+      size_t  count;
+      gss_OID elements;
+} gss_OID_set_desc, *gss_OID_set;
+
+typedef struct gss_buffer_desc_struct {
+      size_t length;
+      void *value;
+} gss_buffer_desc, *gss_buffer_t;
+
+typedef void * gss_ctx_id_t;
+
+typedef void * gss_name_t;
+
+typedef void * gss_cred_id_t;
+
+typedef struct gss_channel_bindings_struct {
+      OM_uint32 initiator_addrtype;
+      gss_buffer_desc initiator_address;
+      OM_uint32 acceptor_addrtype;
+      gss_buffer_desc acceptor_address;
+      gss_buffer_desc application_data;
+} *gss_channel_bindings_t;
+
+typedef	OM_uint32	gss_qop_t;
+
+/*
+ * Various Null values.
+ */
+#define GSS_C_NO_NAME ((gss_name_t) 0)
+#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
+#define GSS_C_NO_OID ((gss_OID) 0)
+#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
+#define GSS_C_EMPTY_BUFFER {0, NULL}
+
+/*
+ * Status code types for gss_display_status
+ */
+#define GSS_C_GSS_CODE 1
+#define GSS_C_MECH_CODE 2
+
+/*
+ * Flag bits for context-level services.
+ */
+#define GSS_C_DELEG_FLAG 1
+#define GSS_C_MUTUAL_FLAG 2
+#define GSS_C_REPLAY_FLAG 4
+#define GSS_C_SEQUENCE_FLAG 8
+#define GSS_C_CONF_FLAG 16
+#define GSS_C_INTEG_FLAG 32
+#define	GSS_C_ANON_FLAG 64
+#define GSS_C_PROT_READY_FLAG 128
+#define GSS_C_TRANS_FLAG 256
+
+
+#define GSS_C_QOP_DEFAULT 0
+
+/*
+ * Some "helper" definitions to make the status code macros obvious.
+ */
+#define GSS_C_CALLING_ERROR_OFFSET 24
+#define GSS_C_ROUTINE_ERROR_OFFSET 16
+#define GSS_C_SUPPLEMENTARY_OFFSET 0
+#define GSS_C_CALLING_ERROR_MASK ((OM_uint32) 0377ul)
+#define GSS_C_ROUTINE_ERROR_MASK ((OM_uint32) 0377ul)
+#define GSS_C_SUPPLEMENTARY_MASK ((OM_uint32) 0177777ul)
+
+#define GSS_ERROR(x) \
+  ((x) & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
+	  (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
+
+/*
+ * Various Null values.
+ */
+#define GSS_C_NO_NAME ((gss_name_t) 0)
+#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
+#define GSS_C_NO_OID ((gss_OID) 0)
+#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
+#define GSS_C_EMPTY_BUFFER {0, NULL}
+
+/*
+ * Some alternate names for a couple of the above values.  These are defined
+ * for V1 compatibility.
+ */
+#define	GSS_C_NULL_OID		GSS_C_NO_OID
+#define	GSS_C_NULL_OID_SET	GSS_C_NO_OID_SET
+
+
+/* Reserved static storage for GSS_oids.  Comments are quotes from RFC 2744. */
+
+static gss_OID_desc oids[] = {
+    /*
+     * The implementation must reserve static storage for a
+	 * gss_OID_desc object containing the value */
+    {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01"},
+    /* corresponding to an object-identifier value of
+	 * {iso(1) member-body(2) United States(840) mit(113554)
+	 * infosys(1) gssapi(2) generic(1) user_name(1)}.  The constant
+	 * GSS_C_NT_USER_NAME should be initialized to point
+	 * to that gss_OID_desc.
+	 */                                
+    
+    /*
+	 * The implementation must reserve static storage for a
+	 * gss_OID_desc object containing the value */
+    {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"},
+    /* corresponding to an object-identifier value of
+	 * {iso(1) member-body(2) United States(840) mit(113554)
+	 * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+	 * The constant GSS_C_NT_MACHINE_UID_NAME should be
+	 * initialized to point to that gss_OID_desc.
+	 */
+     
+    /*
+    * The implementation must reserve static storage for a
+    * gss_OID_desc object containing the value */
+    {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03"},
+    /* corresponding to an object-identifier value of
+    * {iso(1) member-body(2) United States(840) mit(113554)
+    * infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+    * The constant GSS_C_NT_STRING_UID_NAME should be
+    * initialized to point to that gss_OID_desc.
+    */
+    
+    /*
+     * The implementation must reserve static storage for a
+     * gss_OID_desc object containing the value */
+    {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+    /* corresponding to an object-identifier value of
+     * {iso(1) org(3) dod(6) internet(1) security(5)
+     * nametypes(6) gss-host-based-services(2)).  The constant
+     * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+     * to that gss_OID_desc.  This is a deprecated OID value, and
+     * implementations wishing to support hostbased-service names
+     * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+     * defined below, to identify such names;
+     * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+     * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+     * parameter, but should not be emitted by GSS-API
+     * implementations
+     */
+    
+    /*
+     * The implementation must reserve static storage for a
+     * gss_OID_desc object containing the value */
+    {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"}, 
+    /* corresponding to an object-identifier value of 
+     * {iso(1) member-body(2) Unites States(840) mit(113554) 
+     * infosys(1) gssapi(2) generic(1) service_name(4)}.  
+     * The constant GSS_C_NT_HOSTBASED_SERVICE should be 
+     * initialized to point to that gss_OID_desc.
+     */
+
+    /*
+     * The implementation must reserve static storage for a
+     * gss_OID_desc object containing the value */
+    {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+    /* corresponding to an object identifier value of
+     * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+     * 6(nametypes), 3(gss-anonymous-name)}.  The constant
+     * and GSS_C_NT_ANONYMOUS should be initialized to point
+     * to that gss_OID_desc.
+     */
+    
+    /*
+     * The implementation must reserve static storage for a
+     * gss_OID_desc object containing the value */
+    {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+    /* corresponding to an object-identifier value of
+     * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+     * 6(nametypes), 4(gss-api-exported-name)}.  The constant
+     * GSS_C_NT_EXPORT_NAME should be initialized to point
+     * to that gss_OID_desc.
+     */
+};
+
+/* Here are the constants which point to the static structure above.
+ *
+ * Constants of the form GSS_C_NT_* are specified by rfc 2744.
+ *
+ * Constants of the form gss_nt_* are the original MIT krb5 names 
+ * found in gssapi_generic.h.  They are provided for compatibility. */ 
+
+gss_OID GSS_C_NT_USER_NAME           = oids+0;
+gss_OID gss_nt_user_name             = oids+0;
+
+gss_OID GSS_C_NT_MACHINE_UID_NAME    = oids+1;
+gss_OID gss_nt_machine_uid_name      = oids+1;
+
+gss_OID GSS_C_NT_STRING_UID_NAME     = oids+2;
+gss_OID gss_nt_string_uid_name       = oids+2;
+
+gss_OID GSS_C_NT_HOSTBASED_SERVICE_X = oids+3;
+gss_OID gss_nt_service_name_v2       = oids+3;
+
+gss_OID GSS_C_NT_HOSTBASED_SERVICE   = oids+4;
+gss_OID gss_nt_service_name          = oids+4;
+
+gss_OID GSS_C_NT_ANONYMOUS           = oids+5;
+
+gss_OID GSS_C_NT_EXPORT_NAME         = oids+6;
+gss_OID gss_nt_exported_name         = oids+6;
+
+
+#define GSS_S_COMPLETE 0
+
+
+
+#define DECLARE_DLL_FUNCTION(ret, cc, func, params) \
+	ret	(cc* func)params;
+
+#define LOAD_DLL_FUNCTION(ret, cc, func, params, origin) \
+	if (retval) \
+	{ \
+		func = (ret (cc* )params)GetProcAddress(gssapiDLLH, origin); \
+	} \
+	if (!func) \
+		retval = 0;
+
+
+DECLARE_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_indicate_mechs, (OM_uint32 *, gss_OID_set *))
+
+DECLARE_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_display_status, (OM_uint32 *, OM_uint32, int, gss_OID, OM_uint32 *, gss_buffer_t))
+
+DECLARE_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_release_buffer, (OM_uint32 *, gss_buffer_t))
+
+DECLARE_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_delete_sec_context, (OM_uint32 *, gss_ctx_id_t *, gss_buffer_t))
+
+DECLARE_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_release_name, (OM_uint32 *, gss_name_t *))
+
+DECLARE_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_init_sec_context,
+						(OM_uint32 *,
+						 gss_cred_id_t,
+						 gss_ctx_id_t *,
+						 gss_name_t,
+						 gss_OID,
+						 OM_uint32,
+						 OM_uint32,
+						 gss_channel_bindings_t,
+						 gss_buffer_t,
+						 gss_OID *,
+						 gss_buffer_t,
+						 OM_uint32 *,
+						 OM_uint32 *))
+
+DECLARE_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_import_name, (OM_uint32 *, gss_buffer_t, gss_OID, gss_name_t *))
+
+DECLARE_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_get_mic,
+						(OM_uint32 *,
+					    gss_ctx_id_t,
+					    gss_qop_t,
+					    gss_buffer_t,
+					    gss_buffer_t))
+
+
+
+int
+gssapiLoadFuncs(void) {
+	int retval = 1;
+
+	if (gssapiDLLH == NULL)
+		retval = 0;
+
+	LOAD_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_indicate_mechs, (OM_uint32 *, gss_OID_set *),
+						"gss_indicate_mechs")
+
+	LOAD_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_display_status, (OM_uint32 *, OM_uint32, int, gss_OID, OM_uint32 *, gss_buffer_t),
+						"gss_display_status")
+
+	LOAD_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_release_buffer, (OM_uint32 *, gss_buffer_t),
+						"gss_release_buffer")
+
+	LOAD_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_delete_sec_context, (OM_uint32 *, gss_ctx_id_t *, gss_buffer_t),
+						"gss_delete_sec_context")
+
+	LOAD_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_release_name, (OM_uint32 *, gss_name_t *),
+						"gss_release_name")
+
+	LOAD_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_init_sec_context,
+						(OM_uint32 *,
+						 gss_cred_id_t,
+						 gss_ctx_id_t *,
+						 gss_name_t,
+						 gss_OID,
+						 OM_uint32,
+						 OM_uint32,
+						 gss_channel_bindings_t,
+						 gss_buffer_t,
+						 gss_OID *,
+						 gss_buffer_t,
+						 OM_uint32 *,
+						 OM_uint32 *),
+						"gss_init_sec_context")
+
+	LOAD_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_import_name, (OM_uint32 *, gss_buffer_t, gss_OID, gss_name_t *),
+						"gss_import_name")
+
+	LOAD_DLL_FUNCTION(OM_uint32, CALLBACK,
+						gss_get_mic,
+						(OM_uint32 *,
+					    gss_ctx_id_t,
+					    gss_qop_t,
+					    gss_buffer_t,
+					    gss_buffer_t),
+						"gss_get_mic")
+
+
+	return retval;
+}
+
+#endif /* GSSAPIW_H */

+ 4 - 0
putty/putty.org.h

@@ -357,6 +357,10 @@ struct config_tag {
     int ssh2_des_cbc;		       /* "des-cbc" nonstandard SSH2 cipher */
     int try_tis_auth;
     int try_ki_auth;
+#ifdef GSSAPI
+    int try_gssapi_auth;
+    int gssapi_fwd_tgt;
+#endif
     int ssh_subsys;		       /* run a subsystem rather than a command */
     int ssh_subsys2;		       /* fallback to go with remote_cmd2 */
     /* Telnet options */

+ 3 - 6
release/winscpsetup.iss

@@ -59,9 +59,7 @@ ShowTasksTreeLines=yes
 #dim Languages[100]
 #define LanguageCount 0
 #define LangI
-#define MessageID
 #define MessagesPath
-#define MessageStr
 
 #sub ProcessTranslationFile
 
@@ -85,12 +83,11 @@ ShowTasksTreeLines=yes
     #expr LanguageCount++
   #endif
 
+[Languages]
 Name: {#Lang}; MessagesFile: {#MessagesPath}
 
 #endsub /* sub ProcessTranslationFile */
 
-[Languages]
-
 #define FindHandle 0
 #expr ProcessTranslationFile
 
@@ -253,7 +250,7 @@ Root: HKCU; Subkey: "Software\Classes\SCP"; Flags: dontcreatekey uninsdeletekey;
 Name: transl\eng; Description: "English"; Types: fulllangs full custom compact; \
   Flags: fixed
 
-#sub EmitLang
+  #sub EmitLang
 
 [Components]
 Name: transl\{#Languages[LangI*3]}; Description: {#Languages[LangI*3+1]}; \
@@ -271,7 +268,7 @@ Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; \
   ValueType: dword; ValueName: "LocaleSafe"; ValueData: {#Languages[LangI*3+2]}; \
   Components: transl\{#Languages[LangI*3]}; Languages: {#Languages[LangI*3]}
 
-#endsub /* sub EmitLang */
+  #endsub /* sub EmitLang */
 
   #for {LangI = 0; LangI < LanguageCount; LangI++} EmitLang
 

+ 2 - 0
resource/TextsWin.h

@@ -56,6 +56,7 @@
 #define UNKNOWN_TRANSLATION     1135
 #define INCOMPATIBLE_TRANSLATION 1136
 #define DRAGEXT_TARGET_NOT_INSTALLED 1137
+#define GSSAPI_NOT_INSTALLED    1138
 
 #define WIN_CONFIRMATION_STRINGS 1300
 #define CONFIRM_OVERWRITE_SESSION 1301
@@ -85,6 +86,7 @@
 #define UNINSTALL_CLEANUP       1325
 #define EXIT_ON_COMPLETION      1326
 #define DISCONNECT_ON_COMPLETION 1327
+#define PENDING_QUEUE_ITEMS     1328
 
 #define WIN_INFORMATION_STRINGS 1400
 #define APP_CAPTION             1401

+ 2 - 0
resource/TextsWin1.rc

@@ -39,6 +39,7 @@ BEGIN
         UNKNOWN_TRANSLATION, "File '%s' does not contain translation for this product version."
         INCOMPATIBLE_TRANSLATION, "File '%s' contains translation for %s version %s."
         DRAGEXT_TARGET_NOT_INSTALLED, "Shell drag extension support is enabled, but the extension was not loaded. Either it is not installed or you have not restarted the computer yet after installation. Install the extension or switch to compatible drag&&drop mode (from Preferences window), which uses temporary folder for downloads."
+        GSSAPI_NOT_INSTALLED, "MIT Kerberos 5 GSSAPI not found. You need to install it before using this feature."
 
         REGISTER_URL_ERROR, "Cannot register application to handle scp:// and sftp:// addresses."
 
@@ -67,6 +68,7 @@ BEGIN
         UNINSTALL_CLEANUP, "Do you want to cleanup data stored by the application on this computer?"
         EXIT_ON_COMPLETION, "%s\n\nDo you want to close application?"
         DISCONNECT_ON_COMPLETION, "%%s\n\nDo you want to terminate %d remaining session(s) and close the application?"
+        PENDING_QUEUE_ITEMS, "There are still some background transfers in queue. Do you want to disconnect anyway?\n \nWarning: Pressing 'OK' will terminate all transfers immediatelly."
 
         WIN_INFORMATION_STRINGS, "WIN_INFORMATION"
         APP_CAPTION, "%s - %s"

+ 89 - 1
windows/GUIConfiguration.cpp

@@ -22,6 +22,69 @@ struct TPasLibModule {
 static const unsigned int AdditionaLanguageMask = 0xFFFFFF00;
 static const AnsiString AdditionaLanguagePrefix("XX");
 //---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+__fastcall TGUICopyParamType::TGUICopyParamType()
+  : TCopyParamType()
+{
+  GUIDefault();
+}
+//---------------------------------------------------------------------------
+__fastcall TGUICopyParamType::TGUICopyParamType(const TCopyParamType & Source)
+  : TCopyParamType(Source)
+{
+  GUIDefault();
+}
+//---------------------------------------------------------------------------
+__fastcall TGUICopyParamType::TGUICopyParamType(const TGUICopyParamType & Source) 
+  : TCopyParamType(Source)
+{
+  GUIAssign(&Source);
+}
+//---------------------------------------------------------------------------
+void __fastcall TGUICopyParamType::Assign(const TCopyParamType * Source)
+{
+  TCopyParamType::Assign(Source);
+
+  const TGUICopyParamType * GUISource;
+  GUISource = dynamic_cast<const TGUICopyParamType *>(Source);
+  if (GUISource != NULL)
+  {
+    GUIAssign(GUISource);
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TGUICopyParamType::GUIAssign(const TGUICopyParamType * Source)
+{
+  Queue = Source->Queue;
+  QueueNoConfirmation = Source->QueueNoConfirmation;
+}
+//---------------------------------------------------------------------------
+void __fastcall TGUICopyParamType::Default()
+{
+  TCopyParamType::Default();
+
+  GUIDefault();
+}
+//---------------------------------------------------------------------------
+void __fastcall TGUICopyParamType::GUIDefault()
+{
+  Queue = false;
+  QueueNoConfirmation = true;
+}
+//---------------------------------------------------------------------------
+TGUICopyParamType & __fastcall TGUICopyParamType::operator =(const TCopyParamType & rhp)
+{
+  Assign(&rhp);
+  return *this;
+}
+//---------------------------------------------------------------------------
+TGUICopyParamType & __fastcall TGUICopyParamType::operator =(const TGUICopyParamType & rhp)
+{
+  Assign(&rhp);
+  return *this;
+}
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
 __fastcall TGUIConfiguration::TGUIConfiguration(): TConfiguration()
 {
   FLocale = 0;
@@ -40,6 +103,7 @@ void __fastcall TGUIConfiguration::Default()
 {
   TConfiguration::Default();
 
+  FCopyParam.Default();
   FIgnoreCancelBeforeFinish = TDateTime(0, 0, 3, 0);
   FCopyParamDialogExpanded = false;
   FErrorDialogExpanded = false;
@@ -69,7 +133,24 @@ void __fastcall TGUIConfiguration::Default()
     KEY(String,   PuttySession); \
     KEY(String,   PuttyPath); \
     KEY(DateTime, IgnoreCancelBeforeFinish); \
-  );
+  ); \
+  BLOCK("Interface\\CopyParam", CANCREATE, \
+    KEY(Bool,    CopyParam.AddXToDirectories); \
+    KEY(String,  CopyParam.AsciiFileMask.Masks); \
+    KEY(Integer, CopyParam.FileNameCase); \
+    KEY(Bool,    CopyParam.PreserveReadOnly); \
+    KEY(Bool,    CopyParam.PreserveTime); \
+    KEY(Bool,    CopyParam.PreserveRights); \
+    KEY(String,  CopyParam.Rights.Text); \
+    KEY(Integer, CopyParam.TransferMode); \
+    KEY(Integer, CopyParam.ResumeSupport); \
+    KEY(Int64,   CopyParam.ResumeThreshold); \
+    KEY(Bool,    CopyParam.ReplaceInvalidChars); \
+    KEY(String,  CopyParam.LocalInvalidChars); \
+    KEY(Bool,    CopyParam.CalculateSize); \
+    KEY(Bool,    CopyParam.Queue); \
+    KEY(Bool,    CopyParam.QueueNoConfirmation); \
+  ); \
 //---------------------------------------------------------------------------
 void __fastcall TGUIConfiguration::SaveSpecial(THierarchicalStorage * Storage)
 {
@@ -378,3 +459,10 @@ TStrings * __fastcall TGUIConfiguration::GetLocales()
 
   return FLocales;
 }
+//---------------------------------------------------------------------------
+void __fastcall TGUIConfiguration::SetCopyParam(TGUICopyParamType value)
+{
+  FCopyParam.Assign(&value);
+  Changed();
+}
+

+ 28 - 0
windows/GUIConfiguration.h

@@ -3,11 +3,36 @@
 #define GUIConfigurationH
 //---------------------------------------------------------------------------
 #include "Configuration.h"
+#include "CopyParam.h"
 //---------------------------------------------------------------------------
 struct TPasLibModule;
 enum TLogView { lvNone, lvWindow, pvPanel };
 enum TInterface { ifCommander, ifExplorer };
 //---------------------------------------------------------------------------
+class TGUICopyParamType : public TCopyParamType
+{
+public:
+  __fastcall TGUICopyParamType();
+  __fastcall TGUICopyParamType(const TCopyParamType & Source);
+  __fastcall TGUICopyParamType(const TGUICopyParamType & Source);
+
+  virtual void __fastcall Default();
+  virtual void __fastcall Assign(const TCopyParamType * Source);
+  TGUICopyParamType & __fastcall operator =(const TGUICopyParamType & rhp);
+  TGUICopyParamType & __fastcall operator =(const TCopyParamType & rhp);
+
+  __property bool Queue = { read = FQueue, write = FQueue };
+  __property bool QueueNoConfirmation = { read = FQueueNoConfirmation, write = FQueueNoConfirmation };
+
+protected:
+  void __fastcall GUIDefault();
+  void __fastcall GUIAssign(const TGUICopyParamType * Source);
+
+private:
+  bool FQueue;
+  bool FQueueNoConfirmation;
+};
+//---------------------------------------------------------------------------
 class TGUIConfiguration : public TConfiguration
 {
 private:
@@ -22,6 +47,7 @@ private:
   TDateTime FIgnoreCancelBeforeFinish;
   bool FQueueAutoPopup;
   int FQueueTransfersLimit;
+  TGUICopyParamType FCopyParam;
 
 protected:
   LCID FLocale;
@@ -38,6 +64,7 @@ protected:
   LCID __fastcall InternalLocale();
   TPasLibModule * __fastcall FindModule(void * Instance);
   void __fastcall FreeResourceModule(HANDLE Instance);
+  void __fastcall SetCopyParam(TGUICopyParamType value);
 
 public:
   __fastcall TGUIConfiguration();
@@ -56,6 +83,7 @@ public:
   __property AnsiString PuttyPath = { read = FPuttyPath, write = FPuttyPath };
   __property AnsiString PuttySession = { read = FPuttySession, write = FPuttySession };
   __property TDateTime IgnoreCancelBeforeFinish = { read = FIgnoreCancelBeforeFinish, write = FIgnoreCancelBeforeFinish };
+  __property TGUICopyParamType CopyParam = { read = FCopyParam, write = SetCopyParam };
 };
 //---------------------------------------------------------------------------
 #define GUIConfiguration (dynamic_cast<TGUIConfiguration *>(Configuration))

+ 423 - 0
windows/QueueController.cpp

@@ -0,0 +1,423 @@
+//---------------------------------------------------------------------------
+#include <vcl.h>
+#pragma hdrstop
+
+#include <Common.h>
+#include <Queue.h>
+#include <TextsWin.h>
+#include <AssociatedStatusBar.hpp>
+#include "QueueController.h"
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+//---------------------------------------------------------------------------
+__fastcall TQueueController::TQueueController(TListView * ListView)
+{
+  FListView = ListView;
+  assert(FListView != NULL);
+  assert(FListView->OnDblClick == NULL);
+  FListView->OnDblClick = QueueViewDblClick;
+  assert(FListView->OnKeyDown == NULL);
+  FListView->OnKeyDown = QueueViewKeyDown;
+
+  FQueueStatus = NULL;
+  FOnChange = NULL;
+}
+//---------------------------------------------------------------------------
+__fastcall TQueueController::~TQueueController()
+{
+  assert(FListView->OnDblClick == QueueViewDblClick);
+  FListView->OnDblClick = NULL;
+  assert(FListView->OnKeyDown == QueueViewKeyDown);
+  FListView->OnKeyDown = NULL;
+}
+//---------------------------------------------------------------------------
+TQueueItemProxy * __fastcall TQueueController::QueueViewItemToQueueItem(
+  TListItem * Item, bool * Detail)
+{
+  assert(Item != NULL);
+  bool ADetail = false;
+
+  int Index = Item->Index;
+  if (Index < FQueueStatus->ActiveCount * 2)
+  {
+    ADetail = ((Index % 2) > 0);
+    Index /= 2;
+  }
+  else
+  {
+    Index -= FQueueStatus->ActiveCount;
+  }
+
+  if (Detail != NULL)
+  {
+    *Detail = ADetail;
+  }
+
+  return FQueueStatus->Items[Index];
+}
+//---------------------------------------------------------------------------
+TQueueOperation __fastcall TQueueController::DefaultOperation()
+{
+  TQueueItemProxy * QueueItem;
+
+  if (FListView->ItemFocused != NULL)
+  {
+    QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);
+
+    switch (QueueItem->Status)
+    {
+      case TQueueItem::qsPending:
+        return qoItemExecute;
+
+      case TQueueItem::qsQuery:
+        return qoItemQuery;
+
+      case TQueueItem::qsError:
+        return qoItemError;
+
+      case TQueueItem::qsPrompt:
+        return qoItemPrompt;
+    }
+  }
+
+  return qoNone;
+}
+//---------------------------------------------------------------------------
+bool __fastcall TQueueController::AllowOperation(
+  TQueueOperation Operation)
+{
+  TQueueItemProxy * QueueItem = NULL;
+
+  if (FListView->ItemFocused != NULL)
+  {
+    QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);
+  }
+
+  switch (Operation)
+  {
+    case qoItemUserAction:
+      return (QueueItem != NULL) && TQueueItem::IsUserActionStatus(QueueItem->Status);
+
+    case qoItemQuery:
+      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsQuery);
+
+    case qoItemError:
+      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsError);
+
+    case qoItemPrompt:
+      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsPrompt);
+
+    case qoItemDelete:
+      return (QueueItem != NULL) && (QueueItem->Status != TQueueItem::qsDone) &&
+        !TQueueItem::IsUserActionStatus(QueueItem->Status);
+
+    case qoItemExecute:
+      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsPending);
+
+    case qoItemUp:
+      return (QueueItem != NULL) &&
+        (QueueItem->Status == TQueueItem::qsPending) &&
+        (FListView->ItemFocused->Index > (FQueueStatus->ActiveCount * 2));
+
+    case qoItemDown:
+      return (QueueItem != NULL) &&
+        (QueueItem->Status == TQueueItem::qsPending) &&
+        (FListView->ItemFocused->Index < (FListView->Items->Count - 1));
+
+    default:
+      assert(false);
+      return false;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TQueueController::ExecuteOperation(TQueueOperation Operation)
+{
+  TQueueItemProxy * QueueItem = NULL;
+
+  if (FListView->ItemFocused != NULL)
+  {
+    QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);
+  }
+
+  if (QueueItem != NULL)
+  {
+    switch (Operation)
+    {
+      case qoItemUserAction:
+      case qoItemQuery:
+      case qoItemError:
+      case qoItemPrompt:
+        QueueItem->ProcessUserAction();
+        break;
+
+      case qoItemExecute:
+        QueueItem->ExecuteNow();
+        break;
+
+      case qoItemUp:
+      case qoItemDown:
+        QueueItem->Move(Operation == qoItemUp);
+        break;
+
+      case qoItemDelete:
+        QueueItem->Delete();
+        break;
+
+      default:
+        assert(false);
+        break;
+    }
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TQueueController::FillQueueViewItem(TListItem * Item,
+  TQueueItemProxy * QueueItem, bool Detail)
+{
+  assert(!Detail || (QueueItem->Status != TQueueItem::qsPending));
+
+  assert((Item->Data == NULL) || (Item->Data == QueueItem));
+  Item->Data = QueueItem;
+
+  AnsiString ProgressStr;
+  int State = -1;
+
+  switch (QueueItem->Status)
+  {
+    case TQueueItem::qsPending:
+      ProgressStr = LoadStr(QUEUE_PENDING);
+      break;
+
+    case TQueueItem::qsConnecting:
+      ProgressStr = LoadStr(QUEUE_CONNECTING);
+      break;
+
+    case TQueueItem::qsQuery:
+      ProgressStr = LoadStr(QUEUE_QUERY);
+      State = 4;
+      break;
+
+    case TQueueItem::qsError:
+      ProgressStr = LoadStr(QUEUE_ERROR);
+      State = 5;
+      break;
+
+    case TQueueItem::qsPrompt:
+      ProgressStr = LoadStr(QUEUE_PROMPT);
+      State = 6;
+      break;
+  }
+
+  bool BlinkHide = TQueueItem::IsUserActionStatus(QueueItem->Status) &&
+    !QueueItem->ProcessingUserAction &&
+    ((GetTickCount() % 1000) >= 500);
+
+  int Image = -1;
+  AnsiString Values[4];
+  TFileOperationProgressType * ProgressData = QueueItem->ProgressData;
+  TQueueItem::TInfo * Info = QueueItem->Info;
+
+  if (!Detail)
+  {
+    switch (Info->Operation)
+    {
+      case foCopy:
+        Image = 2;
+        break;
+
+      case foMove:
+        Image = 3;
+        break;
+    }
+    State = ((Info->Side == osLocal) ? 1 : 0);
+
+    Values[0] = Info->Source;
+    Values[1] = Info->Destination;
+
+    if (ProgressData != NULL)
+    {
+      Values[2] = FormatBytes(ProgressData->TotalTransfered);
+      if (ProgressStr.IsEmpty())
+      {
+        ProgressStr = FORMAT("%d%%", (ProgressData->OverallProgress()));
+      }
+    }
+    Values[3] = ProgressStr;
+  }
+  else
+  {
+    if (ProgressData != NULL)
+    {
+      Values[0] = ProgressData->FileName;
+      Values[2] = FormatBytes(ProgressData->TransferedSize);
+      Values[3] = FORMAT("%d%%", (ProgressData->TransferProgress()));
+    }
+    else
+    {
+      Values[0] = ProgressStr;
+    }
+  }
+
+  Item->StateIndex = (!BlinkHide ? State : -1);
+  Item->ImageIndex = (!BlinkHide ? Image : -1);
+  for (int Index = 0; Index < LENOF(Values); Index++)
+  {
+    if (Index < Item->SubItems->Count)
+    {
+      Item->SubItems->Strings[Index] = Values[Index];
+    }
+    else
+    {
+      Item->SubItems->Add(Values[Index]);
+    }
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TQueueController::UpdateQueueStatus(
+  TTerminalQueueStatus * QueueStatus)
+{
+  FQueueStatus = QueueStatus;
+   
+  if (FQueueStatus != NULL)
+  {
+    TQueueItemProxy * QueueItem;
+    TListItem * Item;
+    int Index = 0;
+    for (int ItemIndex = 0; ItemIndex < FQueueStatus->Count; ItemIndex++)
+    {
+      QueueItem = FQueueStatus->Items[ItemIndex];
+
+      int Index2 = Index;
+      while ((Index2 < FListView->Items->Count) &&
+             (FListView->Items->Item[Index2]->Data != QueueItem))
+      {
+        Index2++;
+      }
+
+      if (Index2 < FListView->Items->Count)
+      {
+        while (Index < Index2)
+        {
+          FListView->Items->Delete(Index);
+          Index2--;
+        }
+      }
+
+      if (Index == FListView->Items->Count)
+      {
+        Item = FListView->Items->Add();
+      }
+      else if (FListView->Items->Item[Index]->Data != QueueItem)
+      {
+        Item = FListView->Items->Insert(Index);
+      }
+      else
+      {
+        Item = FListView->Items->Item[Index];
+        assert(Item->Data == QueueItem);
+      }
+      FillQueueViewItem(Item, QueueItem, false);
+      Index++;
+
+      assert((QueueItem->Status != TQueueItem::qsPending) ==
+        (ItemIndex < FQueueStatus->ActiveCount));
+
+      if (ItemIndex < FQueueStatus->ActiveCount)
+      {
+        if (Index == FListView->Items->Count)
+        {
+          Item = FListView->Items->Add();
+        }
+        else if (FListView->Items->Item[Index]->Data != QueueItem)
+        {
+          Item = FListView->Items->Insert(Index);
+        }
+        else
+        {
+          Item = FListView->Items->Item[Index];
+          assert(Item->Data == QueueItem);
+        }
+        FillQueueViewItem(Item, QueueItem, true);
+        Index++;
+      }
+    }
+
+    while (Index < FListView->Items->Count)
+    {
+      FListView->Items->Delete(Index);
+    }
+  }
+  else
+  {
+    FListView->Items->Clear();
+  }
+
+  DoChange();
+}
+//---------------------------------------------------------------------------
+void __fastcall TQueueController::RefreshQueueItem(TQueueItemProxy * QueueItem)
+{
+  TListItem * NextListItem = NULL;
+  TListItem * ListItem;
+
+  ListItem = FListView->FindData(0, QueueItem, true, false);
+  assert(ListItem != NULL);
+
+  int ItemIndex = ListItem->Index;
+  if (ItemIndex + 1 < FListView->Items->Count)
+  {
+    NextListItem = FListView->Items->Item[ItemIndex + 1];
+    if (NextListItem->Data != QueueItem)
+    {
+      NextListItem = NULL;
+    }
+  }
+
+  FillQueueViewItem(ListItem, QueueItem, false);
+
+  if (NextListItem == NULL)
+  {
+    NextListItem = FListView->Items->Insert(ItemIndex + 1);
+  }
+  FillQueueViewItem(NextListItem, QueueItem, true);
+
+  DoChange();
+}
+//---------------------------------------------------------------------------
+void __fastcall TQueueController::DoChange()
+{
+  if (FOnChange != NULL)
+  {
+    FOnChange(NULL);
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TQueueController::QueueViewDblClick(TObject * /*Sender*/)
+{
+  TQueueOperation Operation = DefaultOperation();
+
+  if (Operation != qoNone)
+  {
+    ExecuteOperation(Operation);
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TQueueController::QueueViewKeyDown(TObject * /*Sender*/,
+  WORD & Key, TShiftState /*Shift*/)
+{
+  if (Key == VK_RETURN)
+  {
+    TQueueOperation Operation = DefaultOperation();
+
+    if (Operation != qoNone)
+    {
+      ExecuteOperation(Operation);
+    }
+    Key = 0;
+  }
+  else if (Key == VK_DELETE)
+  {
+    ExecuteOperation(qoItemDelete);
+    Key = 0;
+  }
+}
+

+ 45 - 0
windows/QueueController.h

@@ -0,0 +1,45 @@
+//---------------------------------------------------------------------------
+#ifndef QueueControllerH
+#define QueueControllerH
+//---------------------------------------------------------------------------
+#include <ComCtrls.hpp>
+//---------------------------------------------------------------------------
+enum TQueueOperation { qoNone, qoGoTo, qoPreferences, qoItemUserAction,
+  qoItemQuery, qoItemError, qoItemPrompt, qoItemDelete, qoItemExecute,
+  qoItemUp, qoItemDown };
+class TCustomListView;
+class TCriticalSection;
+class TQueueItemProxy;
+class TTerminalQueueStatus;
+//---------------------------------------------------------------------------
+class TQueueController
+{
+public:
+  __fastcall TQueueController(TListView * ListView);
+  __fastcall ~TQueueController();
+
+  TQueueOperation __fastcall DefaultOperation();
+  bool __fastcall AllowOperation(TQueueOperation Operation);
+  void __fastcall ExecuteOperation(TQueueOperation Operation);
+
+  void __fastcall UpdateQueueStatus(TTerminalQueueStatus * QueueStatus);
+  void __fastcall RefreshQueueItem(TQueueItemProxy * QueueItem);
+
+  __property TNotifyEvent OnChange = { read = FOnChange, write = FOnChange };
+
+private:
+  TListView * FListView;
+  TTerminalQueueStatus * FQueueStatus;
+  TNotifyEvent FOnChange;
+
+  TQueueItemProxy * __fastcall QueueViewItemToQueueItem(
+    TListItem * Item, bool * Detail = NULL);
+  void __fastcall QueueViewDblClick(TObject * Sender);
+  void __fastcall QueueViewKeyDown(TObject * Sender, WORD & Key, TShiftState Shift);
+  virtual void __fastcall DoChange();
+
+  static void __fastcall FillQueueViewItem(TListItem * Item,
+    TQueueItemProxy * QueueItem, bool Detail);
+};
+//---------------------------------------------------------------------------
+#endif

+ 1 - 2
windows/TerminalManager.cpp

@@ -76,10 +76,9 @@ TTerminal * __fastcall TTerminalManager::NewTerminal(TSessionData * Data)
 {
   FTerminalList->Clear();
   TTerminal * Terminal = TTerminalList::NewTerminal(Data);
-  TTerminalQueue * Queue = NULL;
   try
   {
-    Queue = new TTerminalQueue(Terminal, Configuration);
+    TTerminalQueue * Queue = new TTerminalQueue(Terminal, Configuration);
     Queue->TransfersLimit = GUIConfiguration->QueueTransfersLimit;
     Queue->OnQueryUser = TerminalQueryUser;
     Queue->OnPromptUser = TerminalPromptUser;

+ 0 - 7
windows/WinConfiguration.cpp

@@ -55,7 +55,6 @@ void __fastcall TWinConfiguration::Default()
   FDDWarnLackOfTempSpaceRatio = 1.1;
   FDDExtEnabled = true;
   FDDExtTimeout = 1000;
-  FDDExtCopySlipTimeout = 100;
   FDeleteToRecycleBin = true;
   FSelectDirectories = false;
   FSelectMask = "*.*";
@@ -220,7 +219,6 @@ THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool SessionList)
     KEY(Integer,  LocaleSafe); \
     KEY(Bool,     DDExtEnabled); \
     KEY(Integer,  DDExtTimeout); \
-    KEY(Integer,  DDExtCopySlipTimeout); \
     KEY(Bool,     DefaultDirIsHome); \
   ); \
   BLOCK("Interface\\Editor", CANCREATE, \
@@ -513,11 +511,6 @@ void __fastcall TWinConfiguration::SetDDExtTimeout(int value)
   SET_CONFIG_PROPERTY(DDExtTimeout);
 }
 //---------------------------------------------------------------------------
-void __fastcall TWinConfiguration::SetDDExtCopySlipTimeout(int value)
-{
-  SET_CONFIG_PROPERTY(DDExtCopySlipTimeout);
-}
-//---------------------------------------------------------------------------
 void __fastcall TWinConfiguration::SetDDWarnLackOfTempSpace(bool value)
 {
   SET_CONFIG_PROPERTY(DDWarnLackOfTempSpace);

+ 0 - 3
windows/WinConfiguration.h

@@ -126,7 +126,6 @@ private:
   bool FDDExtEnabled;
   int FDDExtInstalled;
   int FDDExtTimeout;
-  int FDDExtCopySlipTimeout;
   bool FConfirmClosingSession;
   bool FConfirmExitOnCompletion;
   double FDDWarnLackOfTempSpaceRatio;
@@ -164,7 +163,6 @@ private:
   void __fastcall SetDDWarnLackOfTempSpace(bool value);
   void __fastcall SetDDExtEnabled(bool value);
   void __fastcall SetDDExtTimeout(int value);
-  void __fastcall SetDDExtCopySlipTimeout(int value);
   void __fastcall SetConfirmClosingSession(bool value);
   void __fastcall SetConfirmExitOnCompletion(bool value);
   void __fastcall SetForceDeleteTempFolder(bool value);
@@ -236,7 +234,6 @@ public:
   __property bool DDExtEnabled = { read=FDDExtEnabled, write=SetDDExtEnabled };
   __property bool DDExtInstalled = { read=GetDDExtInstalled };
   __property int DDExtTimeout = { read=FDDExtTimeout, write=SetDDExtTimeout };
-  __property int DDExtCopySlipTimeout = { read=FDDExtCopySlipTimeout, write=SetDDExtCopySlipTimeout };
   __property bool ConfirmClosingSession  = { read=FConfirmClosingSession, write=SetConfirmClosingSession };
   __property bool ConfirmExitOnCompletion  = { read=FConfirmExitOnCompletion, write=SetConfirmExitOnCompletion };
   __property bool ForceDeleteTempFolder  = { read=FForceDeleteTempFolder, write=SetForceDeleteTempFolder };

+ 7 - 6
windows/WinInterface.h

@@ -4,6 +4,7 @@
 //---------------------------------------------------------------------------
 #include <Classes.hpp>
 #include <Interface.h>
+#include <GUIConfiguration.h>
 
 class TStoredSessionList;
 class TConfiguration;
@@ -66,13 +67,13 @@ void __fastcall DoConsoleDialog(TTerminal * Terminal,
     const AnsiString Command = "");
 
 // forms\Copy.cpp
-const coQueue               = 0x01;
-const coQueueNoConfirmation = 0x02;
-const coQueueDisable        = 0x04;
+const coDragDropTemp        = 0x01;
+const coDisableQueue        = 0x02;
+const coDisableTransferMode = 0x04;
+const coDisableDirectory    = 0x08; // not used anymore
 bool __fastcall DoCopyDialog(bool ToRemote,
-  bool Move, bool DragDrop, TStrings * FileList,
-  bool AllowTransferMode, AnsiString & TargetDirectory,
-  TCopyParamType * Params, int & Options, bool AllowDirectory);
+  bool Move, TStrings * FileList, AnsiString & TargetDirectory,
+  TGUICopyParamType * Params, int Options);
 
 // forms\CopyParams.cpp
 enum TParamsForDirection { pdBoth, pdToRemote, pdToLocal, pdAll };

+ 5 - 5
windows/WinMain.cpp

@@ -46,7 +46,7 @@ TSessionData * GetLoginData(AnsiString SessionName)
   TSessionData *Data = new TSessionData("");
   if (!SessionName.IsEmpty())
   {
-    TSessionData * AData = NULL;
+    TSessionData * AData;
     // lookup stored session session even if protocol was defined
     // (this allows setting for example default username for host
     // by creating stored session named by host)
@@ -107,7 +107,7 @@ void __fastcall Upload(TTerminal * Terminal, TProgramParams * Params,
   int ListFrom, int ListTo)
 {
   AnsiString TargetDirectory;
-  TCopyParamType CopyParam = Configuration->CopyParam;
+  TGUICopyParamType CopyParam = GUIConfiguration->CopyParam;
   TStrings * FileList = NULL;
 
   try
@@ -119,9 +119,9 @@ void __fastcall Upload(TTerminal * Terminal, TProgramParams * Params,
     }
     TargetDirectory = UnixIncludeTrailingBackslash(Terminal->CurrentDirectory);
 
-    int Options = coQueueDisable;
-    if (DoCopyDialog(true, false, false, FileList, Terminal->IsCapable[fcTextMode],
-          TargetDirectory, &CopyParam, Options, true))
+    int Options = coDisableQueue |
+      (!Terminal->IsCapable[fcTextMode] ? coDisableTransferMode : 0);
+    if (DoCopyDialog(true, false, FileList, TargetDirectory, &CopyParam, Options))
     {
       int Params = 0;
       Terminal->CopyToRemote(FileList, TargetDirectory, &CopyParam, Params);