Pārlūkot izejas kodu

Generating transfer script + Not highlighting script strings + Script command-line

Source commit: ccddd850406040fc9feda4e5a71ae20f5514bf09
Martin Prikryl 9 gadi atpakaļ
vecāks
revīzija
fb68ee6f0c

+ 1 - 0
dotnet/Session.cs

@@ -958,6 +958,7 @@ namespace WinSCP
             int lastSlash = fileMask.LastIndexOf('/');
             string path = lastSlash > 0 ? fileMask.Substring(0, lastSlash + 1) : string.Empty;
             string mask = lastSlash > 0 ? fileMask.Substring(lastSlash + 1) : fileMask;
+            // Keep in sync with EscapeFileMask in GenerateUrl.cpp
             mask = mask.Replace("[", "[[]").Replace("*", "[*]").Replace("?", "[?]");
             return path + mask;
         }

+ 83 - 1
source/core/Common.cpp

@@ -2930,6 +2930,7 @@ bool __fastcall IsHttpUrl(const UnicodeString & S)
 const UnicodeString RtfPara = L"\\par\n";
 const UnicodeString RtfHyperlinkField = L"HYPERLINK";
 const UnicodeString RtfHyperlinkFieldPrefix = RtfHyperlinkField + L" \"";
+const UnicodeString RtfHyperlinkFieldSuffix = L"\" ";
 //---------------------------------------------------------------------
 UnicodeString __fastcall RtfColor(int Index)
 {
@@ -3000,6 +3001,87 @@ UnicodeString __fastcall RtfString(const UnicodeString & Text)
 UnicodeString __fastcall RtfLink(const UnicodeString & Link, const UnicodeString & RtfText)
 {
   return
-    L"{\\field{\\*\\fldinst{HYPERLINK \"" + Link + L"\" }}{\\fldrslt{" +
+    L"{\\field{\\*\\fldinst{" + RtfHyperlinkFieldPrefix + Link + RtfHyperlinkFieldSuffix + L"}}{\\fldrslt{" +
     RtfText + L"}}}";
 }
+//---------------------------------------------------------------------
+UnicodeString __fastcall ScriptCommandLink(const UnicodeString & Command)
+{
+  return L"scriptcommand_" + Command;
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfSwitch(const UnicodeString & Switch, const UnicodeString & Link)
+{
+  return RtfText(L" ") + RtfLink(Link + L"#" + Switch.LowerCase(), RtfParameter(FORMAT(L"-%s", (Switch))));
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfSwitchValue(const UnicodeString & Name, const UnicodeString & Link, const UnicodeString & Value)
+{
+  return RtfSwitch(Name, Link) + L"=" + Value;
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfSwitch(const UnicodeString & Name, const UnicodeString & Link, const UnicodeString & Value)
+{
+  return RtfSwitchValue(Name, Link, RtfText(FORMAT("\"%s\"", (EscapeParam(Value)))));
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfSwitch(const UnicodeString & Name, const UnicodeString & Link, int Value)
+{
+  return RtfSwitchValue(Name, Link, RtfText(IntToStr(Value)));
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfRemoveHyperlinks(UnicodeString Text)
+{
+  // Remove all tags HYPERLINK "http://www.example.com".
+  // See also RtfEscapeParam
+  int Index = 1;
+  int P;
+  while ((P = PosFrom(RtfHyperlinkFieldPrefix, Text, Index)) > 0)
+  {
+    int Index2 = P + RtfHyperlinkFieldPrefix.Length();
+    int P2 = PosFrom(RtfHyperlinkFieldSuffix, Text, Index2);
+    if (P2 > 0)
+    {
+      Text.Delete(P, P2 - P + RtfHyperlinkFieldSuffix.Length());
+    }
+    else
+    {
+      Index = Index2;
+    }
+  }
+  return Text;
+}
+//---------------------------------------------------------------------
+UnicodeString __fastcall RtfEscapeParam(UnicodeString Param)
+{
+  const UnicodeString Quote(L"\"");
+  // Equivalent of EscapeParam, except that it does not double quotes in HYPERLINK.
+  // See also RtfRemoveHyperlinks.
+  int Index = 1;
+  while (true)
+  {
+    int P1 = PosFrom(Quote, Param, Index);
+    if (P1 == 0)
+    {
+      // no more quotes
+      break;
+    }
+    else
+    {
+      int P2 = PosFrom(RtfHyperlinkFieldPrefix, Param, Index);
+      int P3;
+      if ((P2 > 0) && (P2 < P1) && ((P3 = PosFrom(RtfHyperlinkFieldSuffix, Param, P2)) > 0))
+      {
+        // skip HYPERLINK
+        Index = P3 + RtfHyperlinkFieldSuffix.Length();
+      }
+      else
+      {
+        Param.Insert(Quote, P1);
+        Index = P1 + (Quote.Length() * 2);
+      }
+    }
+  }
+
+  return Param;
+}

+ 7 - 2
source/core/Common.h

@@ -203,8 +203,6 @@ MethodT __fastcall MakeMethod(void * Data, void * Code)
 }
 //---------------------------------------------------------------------------
 extern const UnicodeString RtfPara;
-extern const UnicodeString RtfHyperlinkField;
-extern const UnicodeString RtfHyperlinkFieldPrefix;
 //---------------------------------------------------------------------
 UnicodeString __fastcall RtfText(const UnicodeString & Text);
 UnicodeString __fastcall RtfColor(int Index);
@@ -215,6 +213,13 @@ UnicodeString __fastcall RtfKeyword(const UnicodeString & Text);
 UnicodeString __fastcall RtfParameter(const UnicodeString & Text);
 UnicodeString __fastcall RtfString(const UnicodeString & Text);
 UnicodeString __fastcall RtfLink(const UnicodeString & Link, const UnicodeString & RtfText);
+UnicodeString __fastcall RtfSwitch(const UnicodeString & Name, const UnicodeString & Link);
+UnicodeString __fastcall RtfSwitchValue(const UnicodeString & Name, const UnicodeString & Link, const UnicodeString & Value);
+UnicodeString __fastcall RtfSwitch(const UnicodeString & Name, const UnicodeString & Link, const UnicodeString & Value);
+UnicodeString __fastcall RtfSwitch(const UnicodeString & Name, const UnicodeString & Link, int Value);
+UnicodeString __fastcall RtfEscapeParam(UnicodeString Param);
+UnicodeString __fastcall RtfRemoveHyperlinks(UnicodeString Text);
+UnicodeString __fastcall ScriptCommandLink(const UnicodeString & Command);
 //---------------------------------------------------------------------------
 #include "Global.h"
 //---------------------------------------------------------------------------

+ 126 - 34
source/core/CopyParam.cpp

@@ -7,6 +7,10 @@
 #include "CopyParam.h"
 #include "HierarchicalStorage.h"
 #include "TextsCore.h"
+#include "Interface.h"
+//---------------------------------------------------------------------------
+const wchar_t * TransferModeNames[] = { L"binary", L"ascii", L"automatic" };
+const int TransferModeNamesCount = LENOF(TransferModeNames);
 //---------------------------------------------------------------------------
 __fastcall TCopyParamType::TCopyParamType()
 {
@@ -57,7 +61,9 @@ UnicodeString __fastcall TCopyParamType::GetInfoStr(
 {
   UnicodeString Result;
   bool SomeAttrIncluded;
-  DoGetInfoStr(Separator, Attrs, Result, SomeAttrIncluded);
+  UnicodeString ScriptArgs;
+  bool NoScriptArgs;
+  DoGetInfoStr(Separator, Attrs, Result, SomeAttrIncluded, UnicodeString(), ScriptArgs, NoScriptArgs);
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -65,17 +71,30 @@ bool __fastcall TCopyParamType::AnyUsableCopyParam(int Attrs) const
 {
   UnicodeString Result;
   bool SomeAttrIncluded;
-  DoGetInfoStr(L";", Attrs, Result, SomeAttrIncluded);
+  UnicodeString ScriptArgs;
+  bool NoScriptArgs;
+  DoGetInfoStr(L";", Attrs, Result, SomeAttrIncluded, UnicodeString(), ScriptArgs, NoScriptArgs);
   return SomeAttrIncluded;
 }
 //---------------------------------------------------------------------------
+UnicodeString __fastcall TCopyParamType::GenerateTransferCommandArgs(int Attrs, const UnicodeString & Link, bool & NoScriptArgs) const
+{
+  UnicodeString Result;
+  bool SomeAttrIncluded;
+  UnicodeString ScriptArgs;
+  DoGetInfoStr(L";", Attrs, Result, SomeAttrIncluded, Link, ScriptArgs, NoScriptArgs);
+  return ScriptArgs;
+}
+//---------------------------------------------------------------------------
 void __fastcall TCopyParamType::DoGetInfoStr(
   UnicodeString Separator, int Options,
-  UnicodeString & Result, bool & SomeAttrIncluded) const
+  UnicodeString & Result, bool & SomeAttrIncluded,
+  const UnicodeString & Link, UnicodeString & ScriptArgs, bool & NoScriptArgs) const
 {
   TCopyParamType Defaults;
 
   bool SomeAttrExcluded = false;
+  NoScriptArgs = false;
   SomeAttrIncluded = false;
   #define ADD(STR, EXCEPT) \
     if (FLAGCLEAR(Options, EXCEPT)) \
@@ -88,9 +107,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
       SomeAttrExcluded = true; \
     }
 
-  bool TransferModeDiffers =
-    ((TransferMode != Defaults.TransferMode) ||
-     ((TransferMode == tmAutomatic) && !(AsciiFileMask == Defaults.AsciiFileMask)));
+  bool AsciiFileMaskDiffers = (TransferMode == tmAutomatic) && !(AsciiFileMask == Defaults.AsciiFileMask);
+  bool TransferModeDiffers = ((TransferMode != Defaults.TransferMode) || AsciiFileMaskDiffers);
 
   if (FLAGCLEAR(Options, cpaIncludeMaskOnly | cpaNoTransferMode))
   {
@@ -124,6 +142,12 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     if (TransferModeDiffers)
     {
       ADD("", cpaIncludeMaskOnly | cpaNoTransferMode);
+
+      ScriptArgs += RtfSwitchValue(TRANSFER_SWITCH, Link, TransferModeNames[TransferMode]);
+      if (AsciiFileMaskDiffers)
+      {
+        NoScriptArgs = true;
+      }
     }
   }
   else
@@ -131,6 +155,7 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     if (TransferModeDiffers)
     {
       SomeAttrExcluded = true;
+      NoScriptArgs = true;
     }
   }
 
@@ -139,6 +164,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     ADD(FORMAT(LoadStrPart(COPY_INFO_FILENAME, 1),
       (LoadStrPart(COPY_INFO_FILENAME, FileNameCase + 2))),
       cpaIncludeMaskOnly);
+
+    NoScriptArgs = true;
   }
 
   if ((InvalidCharsReplacement == NoReplacement) !=
@@ -149,15 +176,16 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     {
       ADD(LoadStr(COPY_INFO_DONT_REPLACE_INV_CHARS), cpaIncludeMaskOnly);
     }
+
+    NoScriptArgs = true;
   }
 
   if ((PreserveRights != Defaults.PreserveRights) ||
       (PreserveRights &&
        ((Rights != Defaults.Rights) || (AddXToDirectories != Defaults.AddXToDirectories))))
   {
-    DebugAssert(PreserveRights);
-
-    if (PreserveRights)
+    const int Except = cpaIncludeMaskOnly | cpaNoRights;
+    if (DebugAlwaysTrue(PreserveRights))
     {
       UnicodeString RightsStr = Rights.Text;
       if (AddXToDirectories)
@@ -165,7 +193,17 @@ void __fastcall TCopyParamType::DoGetInfoStr(
         RightsStr += L", " + LoadStr(COPY_INFO_ADD_X_TO_DIRS);
       }
       ADD(FORMAT(LoadStr(COPY_INFO_PERMISSIONS), (RightsStr)),
-        cpaIncludeMaskOnly | cpaNoRights);
+        Except);
+
+      if (FLAGCLEAR(Options, Except))
+      {
+        ScriptArgs += RtfSwitchValue(PERMISSIONS_SWITCH, Link, Rights.Octal);
+      }
+    }
+
+    if (AddXToDirectories != Defaults.AddXToDirectories)
+    {
+      NoScriptArgs = NoScriptArgs || FLAGCLEAR(Options, Except);
     }
   }
 
@@ -175,63 +213,83 @@ void __fastcall TCopyParamType::DoGetInfoStr(
   {
     UnicodeString Str = LoadStr(PreserveTime ? COPY_INFO_TIMESTAMP : COPY_INFO_DONT_PRESERVE_TIME);
 
+    const int Except = cpaIncludeMaskOnly | cpaNoPreserveTime;
+    const int ExceptDirs = cpaNoPreserveTimeDirs;
     if (APreserveTimeDirs != Defaults.PreserveTimeDirs)
     {
       if (DebugAlwaysTrue(PreserveTimeDirs))
       {
-        if (FLAGCLEAR(Options, cpaNoPreserveTimeDirs))
+        if (FLAGCLEAR(Options, ExceptDirs))
         {
           Str = FMTLOAD(COPY_INFO_PRESERVE_TIME_DIRS, (Str));
           AddPreserveTime = true;
         }
       }
-      ADD("", cpaIncludeMaskOnly | cpaNoPreserveTime | cpaNoPreserveTimeDirs);
+      ADD("", Except | ExceptDirs);
     }
 
     if (AddPreserveTime)
     {
-      ADD(Str, cpaIncludeMaskOnly | cpaNoPreserveTime);
+      ADD(Str, Except);
+    }
+
+    if (FLAGCLEAR(Options, Except))
+    {
+      if (PreserveTime)
+      {
+        if (PreserveTimeDirs && FLAGCLEAR(Options, ExceptDirs))
+        {
+          ScriptArgs += RtfSwitchValue(PRESERVETIME_SWITCH, Link, PRESERVETIMEDIRS_SWITCH_VALUE);
+        }
+        else
+        {
+          ScriptArgs += RtfSwitch(PRESERVETIME_SWITCH, Link);
+        }
+      }
+      else
+      {
+        ScriptArgs += RtfSwitch(NOPRESERVETIME_SWITCH, Link);
+      }
     }
   }
 
   if ((PreserveRights || PreserveTime) &&
       (IgnorePermErrors != Defaults.IgnorePermErrors))
   {
-    DebugAssert(IgnorePermErrors);
-
-    if (IgnorePermErrors)
+    if (DebugAlwaysTrue(IgnorePermErrors))
     {
-      ADD(LoadStr(COPY_INFO_IGNORE_PERM_ERRORS),
-        cpaIncludeMaskOnly | cpaNoIgnorePermErrors);
+      const int Except = cpaIncludeMaskOnly | cpaNoIgnorePermErrors;
+      ADD(LoadStr(COPY_INFO_IGNORE_PERM_ERRORS), Except);
+      NoScriptArgs = NoScriptArgs || (FLAGCLEAR(Options, Except));
     }
   }
 
   if (PreserveReadOnly != Defaults.PreserveReadOnly)
   {
-    DebugAssert(PreserveReadOnly);
-    if (PreserveReadOnly)
+    if (DebugAlwaysTrue(PreserveReadOnly))
     {
-      ADD(LoadStr(COPY_INFO_PRESERVE_READONLY),
-        cpaIncludeMaskOnly | cpaNoPreserveReadOnly);
+      const int Except = cpaIncludeMaskOnly | cpaNoPreserveReadOnly;
+      ADD(LoadStr(COPY_INFO_PRESERVE_READONLY), Except);
+      NoScriptArgs = NoScriptArgs || (FLAGCLEAR(Options, Except));
     }
   }
 
   if (CalculateSize != Defaults.CalculateSize)
   {
-    DebugAssert(!CalculateSize);
-    if (!CalculateSize)
+    if (DebugAlwaysTrue(!CalculateSize))
     {
       ADD(LoadStr(COPY_INFO_DONT_CALCULATE_SIZE), cpaIncludeMaskOnly);
+      // Always false in scripting, in assembly controlled by use of FileTransferProgress
     }
   }
 
   if (ClearArchive != Defaults.ClearArchive)
   {
-    DebugAssert(ClearArchive);
-    if (ClearArchive)
+    if (DebugAlwaysTrue(ClearArchive))
     {
-      ADD(LoadStr(COPY_INFO_CLEAR_ARCHIVE),
-        cpaIncludeMaskOnly | cpaNoClearArchive);
+      const int Except = cpaIncludeMaskOnly | cpaNoClearArchive;
+      ADD(LoadStr(COPY_INFO_CLEAR_ARCHIVE), Except);
+      NoScriptArgs = NoScriptArgs || (FLAGCLEAR(Options, Except));
     }
   }
 
@@ -241,8 +299,9 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     {
       if (DebugAlwaysTrue(RemoveBOM))
       {
-        ADD(LoadStr(COPY_INFO_REMOVE_BOM),
-          cpaIncludeMaskOnly | cpaNoRemoveBOM | cpaNoTransferMode);
+        const int Except = cpaIncludeMaskOnly | cpaNoRemoveBOM | cpaNoTransferMode;
+        ADD(LoadStr(COPY_INFO_REMOVE_BOM), Except);
+        NoScriptArgs = NoScriptArgs || (FLAGCLEAR(Options, Except));
       }
     }
 
@@ -250,8 +309,9 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     {
       if (DebugAlwaysTrue(RemoveCtrlZ))
       {
-        ADD(LoadStr(COPY_INFO_REMOVE_CTRLZ),
-          cpaIncludeMaskOnly | cpaNoRemoveCtrlZ | cpaNoTransferMode);
+        const int Except = cpaIncludeMaskOnly | cpaNoRemoveCtrlZ | cpaNoTransferMode;
+        ADD(LoadStr(COPY_INFO_REMOVE_CTRLZ),Except);
+        NoScriptArgs = NoScriptArgs || (FLAGCLEAR(Options, Except));
       }
     }
   }
@@ -260,6 +320,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
   {
     ADD(FORMAT(LoadStr(COPY_INFO_FILE_MASK), (IncludeFileMask.Masks)),
       cpaNoIncludeMask);
+
+    ScriptArgs += RtfSwitch(FILEMASK_SWITCH, Link, IncludeFileMask.Masks);
   }
 
   DebugAssert(FTransferSkipList.get() == NULL);
@@ -267,15 +329,45 @@ void __fastcall TCopyParamType::DoGetInfoStr(
 
   if (CPSLimit > 0)
   {
-    ADD(FMTLOAD(COPY_INFO_CPS_LIMIT2, (int(CPSLimit / 1024))), cpaIncludeMaskOnly);
+    int LimitKB = int(CPSLimit / 1024);
+    ADD(FMTLOAD(COPY_INFO_CPS_LIMIT2, (LimitKB)), cpaIncludeMaskOnly);
+
+    ScriptArgs += RtfSwitch(SPEED_SWITCH, Link, LimitKB);
   }
 
   if (NewerOnly != Defaults.NewerOnly)
   {
     if (DebugAlwaysTrue(NewerOnly))
     {
-      ADD(StripHotkey(LoadStr(COPY_PARAM_NEWER_ONLY)), cpaIncludeMaskOnly | cpaNoNewerOnly);
+      const int Except = cpaIncludeMaskOnly | cpaNoNewerOnly;
+      ADD(StripHotkey(LoadStr(COPY_PARAM_NEWER_ONLY)), Except);
+      if (FLAGCLEAR(Options, Except))
+      {
+        ScriptArgs += RtfSwitch(NEWERONLY_SWICH, Link);
+      }
+    }
+  }
+
+  if (((ResumeSupport != Defaults.ResumeSupport) ||
+       ((ResumeSupport == rsSmart) && (ResumeThreshold != Defaults.ResumeThreshold))) &&
+      (TransferMode != tmAscii) && FLAGCLEAR(Options, cpaNoResumeSupport))
+  {
+    UnicodeString Value;
+    switch (ResumeSupport)
+    {
+      case rsOff:
+        Value = ToggleNames[ToggleOff];
+        break;
+
+      case rsOn:
+        Value = ToggleNames[ToggleOn];
+        break;
+
+      case rsSmart:
+        Value = IntToStr(ResumeThreshold / 1024);
+        break;
     }
+    ScriptArgs += RtfSwitchValue(RESUMESUPPORT_SWITCH, Link, Value);
   }
 
   if (SomeAttrExcluded)

+ 5 - 1
source/core/CopyParam.h

@@ -24,6 +24,7 @@ const int cpaNoNewerOnly        = 0x100;
 const int cpaNoRemoveCtrlZ      = 0x200;
 const int cpaNoRemoveBOM        = 0x400;
 const int cpaNoPreserveTimeDirs = 0x800;
+const int cpaNoResumeSupport    = 0x1000;
 //---------------------------------------------------------------------------
 struct TUsableCopyParamAttrs
 {
@@ -70,7 +71,8 @@ private:
   void __fastcall SetReplaceInvalidChars(bool value);
   UnicodeString __fastcall RestoreChars(UnicodeString FileName) const;
   void __fastcall DoGetInfoStr(UnicodeString Separator, int Attrs,
-    UnicodeString & Result, bool & SomeAttrIncluded) const;
+    UnicodeString & Result, bool & SomeAttrIncluded,
+    const UnicodeString & Link, UnicodeString & ScriptArgs, bool & NoScriptArgs) const;
   TStrings * __fastcall GetTransferSkipList() const;
   void __fastcall SetTransferSkipList(TStrings * value);
 
@@ -100,6 +102,8 @@ public:
   void __fastcall Save(THierarchicalStorage * Storage) const;
   UnicodeString __fastcall GetInfoStr(UnicodeString Separator, int Attrs) const;
   bool __fastcall AnyUsableCopyParam(int Attrs) const;
+  UnicodeString __fastcall GenerateTransferCommandArgs(
+    int Attrs, const UnicodeString & Link, bool & NoScriptArgs) const;
 
   bool __fastcall operator==(const TCopyParamType & rhp) const;
 

+ 1 - 0
source/core/FtpFileSystem.cpp

@@ -2320,6 +2320,7 @@ bool __fastcall TFTPFileSystem::IsCapable(int Capability) const
     case fcRemoveCtrlZUpload:
     case fcLocking:
     case fcPreservingTimestampDirs:
+    case fcResumeSupport:
       return false;
 
     default:

+ 17 - 0
source/core/Interface.h

@@ -5,9 +5,26 @@
 #include "Configuration.h"
 #include "SessionData.h"
 #define HELP_NONE ""
+#define SCRIPT_SWITCH "script"
 #define COMMAND_SWITCH L"Command"
 #define SESSIONNAME_SWICH L"SessionName"
 #define INI_NUL L"nul"
+#define PRESERVETIME_SWITCH L"preservetime"
+#define PRESERVETIMEDIRS_SWITCH_VALUE L"all"
+#define NOPRESERVETIME_SWITCH L"nopreservetime"
+#define PERMISSIONS_SWITCH L"permissions"
+#define NOPERMISSIONS_SWITCH L"nopermissions"
+#define SPEED_SWITCH L"speed"
+#define TRANSFER_SWITCH L"transfer"
+#define FILEMASK_SWITCH L"filemask"
+#define RESUMESUPPORT_SWITCH L"resumesupport"
+#define NEWERONLY_SWICH L"neweronly"
+#define NONEWERONLY_SWICH L"noneweronly"
+#define DELETE_SWITCH L"delete"
+extern const wchar_t * TransferModeNames[];
+extern const int TransferModeNamesCount;
+extern const wchar_t * ToggleNames[];
+enum TToggle { ToggleOff, ToggleOn };
 //---------------------------------------------------------------------------
 TConfiguration * __fastcall CreateConfiguration();
 class TOptions;

+ 1 - 0
source/core/ScpFileSystem.cpp

@@ -461,6 +461,7 @@ bool __fastcall TSCPFileSystem::IsCapable(int Capability) const
     case fcMoveToQueue:
     case fcLocking:
     case fcPreservingTimestampDirs:
+    case fcResumeSupport:
       return false;
 
     default:

+ 28 - 30
source/core/Script.cpp

@@ -14,9 +14,7 @@
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
-static const wchar_t * TransferModeNames[] = { L"binary", L"ascii", L"automatic" };
-enum { Off, On };
-static const wchar_t * ToggleNames[] = { L"off", L"on" };
+const wchar_t * ToggleNames[] = { L"off", L"on" };
 //---------------------------------------------------------------------------
 __fastcall TScriptProcParams::TScriptProcParams(UnicodeString ParamsStr)
 {
@@ -936,7 +934,7 @@ void __fastcall TScript::TransferParamParams(int & Params, TScriptProcParams * P
 {
   Params |= FLAGMASK(!FConfirm, cpNoConfirmation);
 
-  if (Parameters->FindSwitch(L"delete"))
+  if (Parameters->FindSwitch(DELETE_SWITCH))
   {
     Params |= cpDelete;
   }
@@ -961,34 +959,34 @@ void __fastcall TScript::CopyParamParams(TCopyParamType & CopyParam, TScriptProc
     CopyParam.CalculateSize = false;
   }
 
-  if (Parameters->FindSwitch(L"nopreservetime"))
+  if (Parameters->FindSwitch(NOPRESERVETIME_SWITCH))
   {
     CopyParam.PreserveTime = false;
     CopyParam.PreserveTimeDirs = false;
   }
 
-  if (Parameters->FindSwitch(L"preservetime", Value))
+  if (Parameters->FindSwitch(PRESERVETIME_SWITCH, Value))
   {
     CopyParam.PreserveTime = true;
 
-    if (SameText(Value, L"all"))
+    if (SameText(Value, PRESERVETIMEDIRS_SWITCH_VALUE))
     {
       CopyParam.PreserveTimeDirs = true;
     }
   }
 
-  if (Parameters->FindSwitch(L"nopermissions"))
+  if (Parameters->FindSwitch(NOPERMISSIONS_SWITCH))
   {
     CopyParam.PreserveRights = false;
   }
 
-  if (Parameters->FindSwitch(L"permissions", Value))
+  if (Parameters->FindSwitch(PERMISSIONS_SWITCH, Value))
   {
     CopyParam.PreserveRights = true;
     CopyParam.Rights.Octal = Value;
   }
 
-  if (Parameters->FindSwitch(L"speed", Value))
+  if (Parameters->FindSwitch(SPEED_SWITCH, Value))
   {
     int CPSLimit;
     if (Value.IsEmpty())
@@ -1006,12 +1004,12 @@ void __fastcall TScript::CopyParamParams(TCopyParamType & CopyParam, TScriptProc
     CopyParam.CPSLimit = CPSLimit;
   }
 
-  if (Parameters->FindSwitch(L"transfer", Value))
+  if (Parameters->FindSwitch(TRANSFER_SWITCH, Value))
   {
     CopyParam.TransferMode = ParseTransferModeName(Value);
   }
 
-  if (Parameters->FindSwitch(L"filemask", Value))
+  if (Parameters->FindSwitch(FILEMASK_SWITCH, Value))
   {
     CopyParam.IncludeFileMask = Value;
     if (FIncludeFileMaskOptionUsed)
@@ -1020,7 +1018,7 @@ void __fastcall TScript::CopyParamParams(TCopyParamType & CopyParam, TScriptProc
     }
   }
 
-  if (Parameters->FindSwitch(L"resumesupport", Value))
+  if (Parameters->FindSwitch(RESUMESUPPORT_SWITCH, Value))
   {
     int ToggleValue = TScriptCommands::FindCommand(ToggleNames,
       LENOF(ToggleNames), Value);
@@ -1028,11 +1026,11 @@ void __fastcall TScript::CopyParamParams(TCopyParamType & CopyParam, TScriptProc
     {
       switch (ToggleValue)
       {
-        case Off:
+        case ToggleOff:
           CopyParam.ResumeSupport = rsOff;
           break;
 
-        case On:
+        case ToggleOn:
           CopyParam.ResumeSupport = rsOn;
           break;
 
@@ -1046,19 +1044,19 @@ void __fastcall TScript::CopyParamParams(TCopyParamType & CopyParam, TScriptProc
       int ThresholdValue;
       if (!TryStrToInt(Value, ThresholdValue))
       {
-        throw Exception(FMTLOAD(SCRIPT_VALUE_UNKNOWN, (L"resumesupport", Value)));
+        throw Exception(FMTLOAD(SCRIPT_VALUE_UNKNOWN, (RESUMESUPPORT_SWITCH, Value)));
       }
       CopyParam.ResumeSupport = rsSmart;
       CopyParam.ResumeThreshold = ThresholdValue * 1024;
     }
   }
 
-  if (Parameters->FindSwitch(L"noneweronly"))
+  if (Parameters->FindSwitch(NONEWERONLY_SWICH))
   {
     CopyParam.NewerOnly = false;
   }
 
-  if (Parameters->FindSwitch(L"neweronly"))
+  if (Parameters->FindSwitch(NEWERONLY_SWICH))
   {
     CopyParam.NewerOnly = true;
   }
@@ -1484,7 +1482,7 @@ TTransferMode __fastcall TScript::ParseTransferModeName(UnicodeString Name)
   DebugAssert((tmBinary == 0) && (tmAscii == 1) && (tmAutomatic == 2));
 
   int Value = TScriptCommands::FindCommand(TransferModeNames,
-    LENOF(TransferModeNames), Name);
+    TransferModeNamesCount, Name);
   if (Value < 0)
   {
     throw Exception(FMTLOAD(SCRIPT_VALUE_UNKNOWN, (L"transfer", Name)));
@@ -1530,10 +1528,10 @@ void __fastcall TScript::OptionImpl(UnicodeString OptionName, UnicodeString Valu
       {
         throw Exception(FMTLOAD(SCRIPT_VALUE_UNKNOWN, (ValueName, OptionName)));
       }
-      FEcho = (Value == On);
+      FEcho = (Value == ToggleOn);
     }
 
-    PrintLine(FORMAT(ListFormat, (Names[Echo], ToggleNames[FEcho ? On : Off])));
+    PrintLine(FORMAT(ListFormat, (Names[Echo], ToggleNames[FEcho ? ToggleOn : ToggleOff])));
   }
 
   if (OPT(Batch))
@@ -1568,11 +1566,11 @@ void __fastcall TScript::OptionImpl(UnicodeString OptionName, UnicodeString Valu
       {
         throw Exception(FMTLOAD(SCRIPT_VALUE_UNKNOWN, (ValueName, OptionName)));
       }
-      FConfirm = (Value == On);
+      FConfirm = (Value == ToggleOn);
       FInteractiveConfirm = FConfirm;
     }
 
-    PrintLine(FORMAT(ListFormat, (Names[Confirm], ToggleNames[FConfirm ? On : Off])));
+    PrintLine(FORMAT(ListFormat, (Names[Confirm], ToggleNames[FConfirm ? ToggleOn : ToggleOff])));
   }
 
   // omit the option in listing
@@ -1583,7 +1581,7 @@ void __fastcall TScript::OptionImpl(UnicodeString OptionName, UnicodeString Valu
       FCopyParam.TransferMode = ParseTransferModeName(ValueName);
     }
 
-    DebugAssert(FCopyParam.TransferMode < (TTransferMode)LENOF(TransferModeNames));
+    DebugAssert(FCopyParam.TransferMode < (TTransferMode)TransferModeNamesCount);
     const wchar_t * Value = TransferModeNames[FCopyParam.TransferMode];
     PrintLine(FORMAT(ListFormat, (Names[Transfer], Value)));
   }
@@ -1600,11 +1598,11 @@ void __fastcall TScript::OptionImpl(UnicodeString OptionName, UnicodeString Valu
       }
       FSynchronizeParams =
         (FSynchronizeParams & ~TTerminal::spDelete) |
-        FLAGMASK(Value == On, TTerminal::spDelete);
+        FLAGMASK(Value == ToggleOn, TTerminal::spDelete);
     }
 
     PrintLine(FORMAT(ListFormat, (Names[SynchDelete],
-      ToggleNames[FLAGSET(FSynchronizeParams, TTerminal::spDelete) ? On : Off])));
+      ToggleNames[FLAGSET(FSynchronizeParams, TTerminal::spDelete) ? ToggleOn : ToggleOff])));
   }
 
   static const wchar_t * Clear = L"clear";
@@ -1641,7 +1639,7 @@ void __fastcall TScript::OptionImpl(UnicodeString OptionName, UnicodeString Valu
     if (SetValue && !PrintReconnectTime)
     {
       int Value;
-      if (AnsiSameText(ValueName, ToggleNames[Off]))
+      if (AnsiSameText(ValueName, ToggleNames[ToggleOff]))
       {
         Value = 0;
       }
@@ -1661,7 +1659,7 @@ void __fastcall TScript::OptionImpl(UnicodeString OptionName, UnicodeString Valu
 
     if (FSessionReopenTimeout == 0)
     {
-      ValueName = ToggleNames[Off];
+      ValueName = ToggleNames[ToggleOff];
     }
     else
     {
@@ -1679,10 +1677,10 @@ void __fastcall TScript::OptionImpl(UnicodeString OptionName, UnicodeString Valu
       {
         throw Exception(FMTLOAD(SCRIPT_VALUE_UNKNOWN, (ValueName, OptionName)));
       }
-      FFailOnNoMatch = (Value == On);
+      FFailOnNoMatch = (Value == ToggleOn);
     }
 
-    PrintLine(FORMAT(ListFormat, (Names[FailOnNoMatch], ToggleNames[FFailOnNoMatch ? On : Off])));
+    PrintLine(FORMAT(ListFormat, (Names[FailOnNoMatch], ToggleNames[FFailOnNoMatch ? ToggleOn : ToggleOff])));
   }
 
   #undef OPT

+ 5 - 9
source/core/SessionData.cpp

@@ -2524,25 +2524,21 @@ UnicodeString __fastcall TSessionData::GenerateSessionUrl(unsigned int Flags)
   return Url;
 }
 //---------------------------------------------------------------------
-void __fastcall TSessionData::AddSwitch(UnicodeString & Result, const UnicodeString & Switch)
-{
-  Result += RtfText(L" ") + RtfLink(L"scriptcommand_open#" + Switch.LowerCase(), RtfParameter(FORMAT(L"-%s", (Switch))));
-}
+UnicodeString ScriptCommandOpenLink = ScriptCommandLink(L"open");
 //---------------------------------------------------------------------
-void __fastcall TSessionData::AddSwitchValue(UnicodeString & Result, const UnicodeString & Name, const UnicodeString & Value)
+void __fastcall TSessionData::AddSwitch(UnicodeString & Result, const UnicodeString & Name)
 {
-  AddSwitch(Result, Name);
-  Result += L"=" + Value;
+  Result += RtfSwitch(Name, ScriptCommandOpenLink);
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::AddSwitch(UnicodeString & Result, const UnicodeString & Name, const UnicodeString & Value)
 {
-  AddSwitchValue(Result, Name, RtfString(FORMAT("\"%s\"", (EscapeParam(Value)))));
+  Result += RtfSwitch(Name, ScriptCommandOpenLink, Value);
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::AddSwitch(UnicodeString & Result, const UnicodeString & Name, int Value)
 {
-  AddSwitchValue(Result, Name, RtfText(IntToStr(Value)));
+  Result += RtfSwitch(Name, ScriptCommandOpenLink, Value);
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::LookupLastFingerprint()

+ 1 - 2
source/core/SessionData.h

@@ -373,8 +373,7 @@ private:
   static RawByteString __fastcall StronglyRecryptPassword(const RawByteString & Password, UnicodeString Key);
   static bool __fastcall DoIsProtocolUrl(const UnicodeString & Url, const UnicodeString & Protocol, int & ProtocolLen);
   static bool __fastcall IsProtocolUrl(const UnicodeString & Url, const UnicodeString & Protocol, int & ProtocolLen);
-  static void __fastcall AddSwitch(UnicodeString & Result, const UnicodeString & Switch);
-  static void __fastcall AddSwitchValue(UnicodeString & Result, const UnicodeString & Name, const UnicodeString & Value);
+  static void __fastcall AddSwitch(UnicodeString & Result, const UnicodeString & Name);
   static void __fastcall AddSwitch(UnicodeString & Result, const UnicodeString & Name, const UnicodeString & Value);
   static void __fastcall AddSwitch(UnicodeString & Result, const UnicodeString & Name, int Value);
   static UnicodeString __fastcall AssemblyString(TAssemblyLanguage Language, UnicodeString S);

+ 1 - 1
source/core/SessionInfo.h

@@ -41,7 +41,7 @@ enum TFSCapability { fcUserGroupListing, fcModeChanging, fcGroupChanging,
   fcCheckingSpaceAvailable, fcIgnorePermErrors, fcCalculatingChecksum,
   fcModeChangingUpload, fcPreservingTimestampUpload, fcShellAnyCommand,
   fcSecondaryShell, fcRemoveCtrlZUpload, fcRemoveBOMUpload, fcMoveToQueue,
-  fcLocking, fcPreservingTimestampDirs,
+  fcLocking, fcPreservingTimestampDirs, fcResumeSupport,
   fcCount };
 //---------------------------------------------------------------------------
 struct TFileSystemInfo

+ 1 - 0
source/core/SftpFileSystem.cpp

@@ -2074,6 +2074,7 @@ bool __fastcall TSFTPFileSystem::IsCapable(int Capability) const
     case fcRemoveBOMUpload:
     case fcMoveToQueue:
     case fcPreservingTimestampDirs:
+    case fcResumeSupport:
       return true;
 
     case fcRename:

+ 2 - 1
source/core/Terminal.cpp

@@ -3224,7 +3224,8 @@ TUsableCopyParamAttrs __fastcall TTerminal::UsableCopyParamAttrs(int Params)
     FLAGMASK(!IsCapable[fcModeChangingUpload], cpaNoRights) |
     FLAGMASK(!IsCapable[fcRemoveCtrlZUpload], cpaNoRemoveCtrlZ) |
     FLAGMASK(!IsCapable[fcRemoveBOMUpload], cpaNoRemoveBOM) |
-    FLAGMASK(!IsCapable[fcPreservingTimestampDirs], cpaNoPreserveTimeDirs);
+    FLAGMASK(!IsCapable[fcPreservingTimestampDirs], cpaNoPreserveTimeDirs) |
+    FLAGMASK(!IsCapable[fcResumeSupport], cpaNoResumeSupport);
   Result.Download = Result.General | cpaNoClearArchive |
     cpaNoIgnorePermErrors |
     // May be already set in General flags, but it's unconditional here

+ 1 - 0
source/core/WebDAVFileSystem.cpp

@@ -650,6 +650,7 @@ bool __fastcall TWebDAVFileSystem::IsCapable(int Capability) const
     case fcRemoveBOMUpload:
     case fcRemoteCopy:
     case fcPreservingTimestampDirs:
+    case fcResumeSupport:
       return false;
 
     case fcLocking:

+ 32 - 12
source/forms/Copy.cpp

@@ -23,10 +23,11 @@
 //---------------------------------------------------------------------------
 bool __fastcall DoCopyDialog(bool ToRemote,
   bool Move, TStrings * FileList, UnicodeString & TargetDirectory,
-  TGUICopyParamType * Params, int Options, int CopyParamAttrs, int * OutputOptions)
+  TGUICopyParamType * Params, int Options, int CopyParamAttrs, TSessionData * SessionData,
+  int * OutputOptions)
 {
   bool Result;
-  TCopyDialog *CopyDialog = new TCopyDialog(Application, ToRemote, Move, FileList, Options, CopyParamAttrs);
+  TCopyDialog *CopyDialog = new TCopyDialog(Application, ToRemote, Move, FileList, Options, CopyParamAttrs, SessionData);
   try
   {
     if (FLAGSET(CopyParamAttrs, cpaNoTransferMode))
@@ -60,14 +61,15 @@ bool __fastcall DoCopyDialog(bool ToRemote,
 }
 //---------------------------------------------------------------------------
 __fastcall TCopyDialog::TCopyDialog(
-  TComponent* Owner, bool ToRemote, bool Move, TStrings * FileList, int Options, int CopyParamAttrs)
-        : TForm(Owner)
+  TComponent* Owner, bool ToRemote, bool Move, TStrings * FileList, int Options,
+  int CopyParamAttrs, TSessionData * SessionData) : TForm(Owner)
 {
   FToRemote = ToRemote;
   FMove = Move;
   FOptions = Options;
   FCopyParamAttrs = CopyParamAttrs;
   FFileList = FileList;
+  FSessionData = SessionData;
 
   FOutputOptions = 0;
 
@@ -485,24 +487,41 @@ void __fastcall TCopyDialog::TransferSettingsButtonClick(TObject * /*Sender*/)
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCopyDialog::GenerateCode()
+{
+  TFilesSelected FilesSelected = FLAGSET(FOptions, coAllFiles) ? fsAll : fsList;
+  DoGenerateTransferCodeDialog(FToRemote, FMove, FCopyParamAttrs, FSessionData, FilesSelected, FFileList, Directory, Params);
+}
+//---------------------------------------------------------------------------
 void __fastcall TCopyDialog::CopyParamClick(TObject * Sender)
 {
   // Save including the preset-unspecific queue properties,
   // so that they are preserved when assigning back later
   TGUICopyParamType Param = Params;
   bool PrevSaveSettings = FSaveSettings;
-  if (CopyParamListPopupClick(Sender, Param, FPreset, FCopyParamAttrs, &FSaveSettings))
+  int Result = CopyParamListPopupClick(Sender, Param, FPreset, FCopyParamAttrs, &FSaveSettings);
+  if (Result < 0)
   {
-    Params = Param;
+    if (DebugAlwaysTrue(Result == -cplGenerateCode))
+    {
+      GenerateCode();
+    }
   }
   else
   {
-    UpdateControls();
-  }
+    if (Result > 0)
+    {
+      Params = Param;
+    }
+    else
+    {
+      UpdateControls();
+    }
 
-  if (PrevSaveSettings && !FSaveSettings)
-  {
-    NeverShowAgainCheck->Checked = false;
+    if (PrevSaveSettings && !FSaveSettings)
+    {
+      NeverShowAgainCheck->Checked = false;
+    }
   }
 }
 //---------------------------------------------------------------------------
@@ -541,7 +560,8 @@ void __fastcall TCopyDialog::CopyParamListPopup(TRect R, int AdditionalOptions)
     cplCustomize | AdditionalOptions |
       FLAGMASK(
           FLAGCLEAR(FOptions, coDisableSaveSettings) && !RemoteTransfer,
-        cplSaveSettings),
+        cplSaveSettings) |
+      FLAGMASK(FLAGCLEAR(FOutputOptions, cooRemoteTransfer) && FLAGCLEAR(FOptions, coTemp), cplGenerateCode),
     FCopyParamAttrs,
     FSaveSettings);
 }

+ 5 - 1
source/forms/Copy.h

@@ -58,6 +58,7 @@ private:
   UnicodeString FPreset;
   TCopyParamType FCopyParams;
   int FCopyParamAttrs;
+  TSessionData * FSessionData;
   bool FSaveSettings;
   UnicodeString __fastcall GetDirectory();
   THistoryComboBox * __fastcall GetDirectoryEdit();
@@ -68,6 +69,7 @@ private:
   void __fastcall SetOutputOptions(int value);
   int __fastcall GetOutputOptions();
   void __fastcall CopyParamClick(TObject * Sender);
+  void __fastcall GenerateCode();
 protected:
   void __fastcall UpdateControls();
   void __fastcall AdjustControls();
@@ -75,7 +77,9 @@ protected:
   bool __fastcall RemotePaths();
   void __fastcall CopyParamListPopup(TRect R, int AdditionalOptions);
 public:
-  __fastcall TCopyDialog(TComponent* Owner, bool ToRemote, bool Move, TStrings * FileList, int Options, int CopyParamAttrs);
+  __fastcall TCopyDialog(
+    TComponent* Owner, bool ToRemote, bool Move, TStrings * FileList, int Options,
+    int CopyParamAttrs, TSessionData * SessionData);
   virtual __fastcall ~TCopyDialog();
   bool __fastcall Execute();
 

+ 19 - 3
source/forms/CustomScpExplorer.cpp

@@ -1047,8 +1047,9 @@ bool __fastcall TCustomScpExplorerForm::CopyParamDialog(
     int OutputOptions =
       FLAGMASK(DragDrop && (WinConfiguration->DDTransferConfirmation == asAuto),
         cooDoNotShowAgain);
+    std::unique_ptr<TSessionData> SessionData(SessionDataForCode());
     Result = DoCopyDialog(Direction == tdToRemote, Type == ttMove,
-      FileList, TargetDirectory, &CopyParam, Options, CopyParamAttrs, &OutputOptions);
+      FileList, TargetDirectory, &CopyParam, Options, CopyParamAttrs, SessionData.get(), &OutputOptions);
 
     if (Result)
     {
@@ -2486,8 +2487,10 @@ void __fastcall TCustomScpExplorerForm::ExecuteCopyOperationCommand(
   {
     Flags &= ~cocShortCutHint;
   }
+  TCustomDirView * DView = DirView(Side);
   Param.Options =
-    FLAGMASK(FLAGSET(Flags, cocShortCutHint), coShortCutHint);
+    FLAGMASK(FLAGSET(Flags, cocShortCutHint), coShortCutHint) |
+    FLAGMASK((DView->SelCount == DView->FilesCount), coAllFiles);
   if (FLAGSET(Flags, cocQueue))
   {
     Param.Queue = asOn;
@@ -7048,6 +7051,11 @@ TDragDropFilesEx * __fastcall TCustomScpExplorerForm::DragDropFiles(TObject * Se
   return Result;
 }
 //---------------------------------------------------------------------------
+bool __fastcall TCustomScpExplorerForm::DraggingAllFilesFromDirView(TOperationSide Side, TStrings * FileList)
+{
+  return HasDirView[Side] && (DropSourceControl == DirView(Side)) && (FileList->Count == DirView(Side)->FilesCount);
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::RemoteFileControlDragDropFileOperation(
   TObject * Sender, int Effect, UnicodeString TargetPath, bool ForceQueue)
 {
@@ -7084,6 +7092,8 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDragDropFileOperation(
       // upload, no temp dirs
       Param.Temp = false;
       Param.DragDrop = true;
+      Param.Options =
+        FLAGMASK(DraggingAllFilesFromDirView(osLocal, FileList), coAllFiles);
       if (ForceQueue)
       {
         Param.Queue = asOn;
@@ -8051,11 +8061,17 @@ void __fastcall TCustomScpExplorerForm::FileSystemInfo()
     OnGetSpaceAvailable);
 }
 //---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::GenerateUrl(TStrings * Paths)
+TSessionData * __fastcall TCustomScpExplorerForm::SessionDataForCode()
 {
   std::unique_ptr<TSessionData> Data(CloneCurrentSessionData());
   const TSessionInfo & SessionInfo = Terminal->GetSessionInfo();
   Data->HostKey = SessionInfo.HostKeyFingerprint;
+  return Data.release();
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::GenerateUrl(TStrings * Paths)
+{
+  std::unique_ptr<TSessionData> Data(SessionDataForCode());
   DoGenerateUrlDialog(Data.get(), Paths);
 }
 //---------------------------------------------------------------------------

+ 2 - 0
source/forms/CustomScpExplorer.h

@@ -561,6 +561,8 @@ protected:
   virtual void __fastcall StartingDisconnected();
   void __fastcall DoTerminalListChanged(bool Force);
   void __fastcall NeedSession(bool ReloadSessions);
+  bool __fastcall DraggingAllFilesFromDirView(TOperationSide Side, TStrings * FileList);
+  TSessionData * __fastcall SessionDataForCode();
 
 public:
   virtual __fastcall ~TCustomScpExplorerForm();

+ 1 - 1
source/forms/FullSynchronize.cpp

@@ -339,7 +339,7 @@ void __fastcall TFullSynchronizeDialog::CopyParamClick(TObject * Sender)
   // user really confirms it on custom dialog
   TCopyParamType ACopyParams = CopyParams;
   if (CopyParamListPopupClick(Sender, ACopyParams, FPreset,
-        ActualCopyParamAttrs()))
+        ActualCopyParamAttrs()) > 0)
   {
     FCopyParams = ACopyParams;
     UpdateControls();

+ 224 - 49
source/forms/GenerateUrl.cpp

@@ -19,7 +19,17 @@
 //---------------------------------------------------------------------------
 void __fastcall DoGenerateUrlDialog(TSessionData * Data, TStrings * Paths)
 {
-  std::unique_ptr<TGenerateUrlDialog> Dialog(new TGenerateUrlDialog(GetFormOwner(), Data, Paths));
+  std::unique_ptr<TGenerateUrlDialog> Dialog(
+    new TGenerateUrlDialog(GetFormOwner(), Data, fsList, Paths, false, false, false, 0, UnicodeString(), TCopyParamType()));
+  Dialog->Execute();
+}
+//---------------------------------------------------------------------------
+void __fastcall DoGenerateTransferCodeDialog(
+  bool ToRemote, bool Move, int CopyParamAttrs, TSessionData * Data, TFilesSelected FilesSelected, TStrings * FileList, const UnicodeString & Path,
+  const TCopyParamType & CopyParam)
+{
+  std::unique_ptr<TGenerateUrlDialog> Dialog(
+    new TGenerateUrlDialog(GetFormOwner(), Data, FilesSelected, FileList, true, ToRemote, Move, CopyParamAttrs, Path, CopyParam));
   Dialog->Execute();
 }
 //---------------------------------------------------------------------------
@@ -117,12 +127,51 @@ void __fastcall TRichEdit41::DestroyWnd()
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TGenerateUrlDialog::TGenerateUrlDialog(
-  TComponent * Owner, TSessionData * Data, TStrings * Paths)
+  TComponent * Owner, TSessionData * Data, TFilesSelected FilesSelected, TStrings * Paths,
+  bool Transfer, bool ToRemote, bool Move, int CopyParamAttrs, const UnicodeString & Path, const TCopyParamType & CopyParam)
   : TForm(Owner)
 {
   UseSystemSettings(this);
   FData = Data;
-  FPaths = Paths;
+
+  if (Paths != NULL)
+  {
+    FPaths.reset(new TStringList());
+    FPaths->AddStrings(Paths);
+  }
+
+  FTransfer = Transfer;
+  FToRemote = ToRemote;
+  FMove = Move;
+  FCopyParamAttrs = CopyParamAttrs;
+  FCopyParam = CopyParam;
+
+  if (FTransfer)
+  {
+    DebugAssert(FPaths.get() != NULL);
+
+    if (FToRemote)
+    {
+      UnicodeString FirstPath = Paths->Strings[0];
+      FSourcePath = FToRemote ? ExcludeTrailingBackslash(ExtractFilePath(FirstPath)) : UnixExtractFilePath(FirstPath);
+      for (int Index = 0; Index < FPaths->Count; Index++)
+      {
+        FPaths->Strings[Index] = ExtractFileName(FPaths->Strings[Index]);
+      }
+    }
+    else
+    {
+      FSourcePath = Data->RemoteDirectory;
+      // should be noop as we get only file names for remote files
+      for (int Index = 0; Index < FPaths->Count; Index++)
+      {
+        FPaths->Strings[Index] = UnixExtractFileName(FPaths->Strings[Index]);
+      }
+    }
+  }
+
+  FPath = Path;
+  FFilesSelected = FilesSelected;
   FChanging = false;
 
   FResultMemo41 = new TRichEdit41(this);
@@ -142,7 +191,7 @@ __fastcall TGenerateUrlDialog::TGenerateUrlDialog(
 //---------------------------------------------------------------------------
 bool __fastcall TGenerateUrlDialog::IsFileUrl()
 {
-  return (FPaths != NULL);
+  return (FPaths.get() != NULL) && !FTransfer;
 }
 //---------------------------------------------------------------------------
 UnicodeString __fastcall TGenerateUrlDialog::GenerateUrl(UnicodeString Path)
@@ -190,7 +239,7 @@ static UnicodeString __fastcall RtfScriptPlaceholder(const UnicodeString & Text)
 //---------------------------------------------------------------------
 static UnicodeString __fastcall RtfScriptCommand(const UnicodeString & Command)
 {
-  return RtfLink(L"scriptcommand_" + Command, RtfKeyword(Command));
+  return RtfLink(ScriptCommandLink(Command), RtfKeyword(Command));
 }
 //---------------------------------------------------------------------
 UnicodeString __fastcall RtfCommandlineSwitch(const UnicodeString & Switch, const UnicodeString & Anchor)
@@ -198,13 +247,34 @@ UnicodeString __fastcall RtfCommandlineSwitch(const UnicodeString & Switch, cons
   return RtfLink(L"commandline#" + Anchor, RtfParameter(TProgramParams::FormatSwitch(Switch.LowerCase())));
 }
 //---------------------------------------------------------------------------
+static UnicodeString __fastcall QuoteStringParam(UnicodeString S)
+{
+  return AddQuotes(RtfEscapeParam(S));
+}
+//---------------------------------------------------------------------------
+// Keep in sync with .NET Session.EscapeFileMask
+static UnicodeString __fastcall EscapeFileMask(UnicodeString S)
+{
+  return ReplaceStr(ReplaceStr(ReplaceStr(S, L"[", L"[[]"), L"*", L"[*]"), L"?", L"[?]");
+}
+//---------------------------------------------------------------------------
 void __fastcall TGenerateUrlDialog::UpdateControls()
 {
   if (!FChanging)
   {
     UnicodeString ExeName = Application->ExeName;
-    Caption = LoadStr(IsFileUrl() ? GENERATE_URL_FILE_TITLE : GENERATE_URL_SESSION_TITLE);
+    int CaptionId;
+    if (FTransfer)
+    {
+      CaptionId = GENERATE_URL_TRANSFER_TITLE;
+    }
+    else
+    {
+      CaptionId = IsFileUrl() ? GENERATE_URL_FILE_TITLE : GENERATE_URL_SESSION_TITLE;
+    }
+    Caption = LoadStr(CaptionId);
 
+    UrlSheet->TabVisible = !FTransfer;
     ScriptSheet->TabVisible = !IsFileUrl();
     AssemblySheet->TabVisible = !IsFileUrl();
 
@@ -217,21 +287,14 @@ void __fastcall TGenerateUrlDialog::UpdateControls()
     }
     else if (OptionsPageControl->ActivePage == ScriptSheet)
     {
-      UnicodeString ScriptDescription;
       if (ScriptFormatCombo->ItemIndex == sfCommandLine)
       {
         ResultGroupCaption = LoadStr(GENERATE_URL_COMMANDLINE_LABEL);
-        ScriptDescription = FMTLOAD(GENERATE_URL_COMMANDLINE_DESC, (FORMAT("\"%s\"", (ExeName)))) + L"\n";
       }
       else
       {
         ResultGroupCaption = ScriptFormatCombo->Items->Strings[ScriptFormatCombo->ItemIndex];
       }
-      if (HostKeyUnknown)
-      {
-        ScriptDescription += LoadStr(GENERATE_URL_HOSTKEY_UNKNOWN) + L"\n";
-      }
-      ScriptDescriptionLabel->Caption = ScriptDescription;
     }
     else if (DebugAlwaysTrue(OptionsPageControl->ActivePage == AssemblySheet))
     {
@@ -283,24 +346,101 @@ void __fastcall TGenerateUrlDialog::UpdateControls()
       UnicodeString OpenCommand = FData->GenerateOpenCommandArgs();
       UnicodeString CommandPlaceholder1 = FMTLOAD(GENERATE_URL_COMMAND, (1));
       UnicodeString CommandPlaceholder2 = FMTLOAD(GENERATE_URL_COMMAND, (2));
+      UnicodeString LogPath = LoadStr(GENERATE_URL_WRITABLE_PATH_TO_LOG) + RtfText(BaseExeName + L".log");
       UnicodeString LogParameter =
         RtfCommandlineSwitch(LOG_SWITCH, L"logging") + RtfText(L"=") +
-        RtfScriptPlaceholder(L"\"" + LoadStr(GENERATE_URL_WRITABLE_PATH_TO_LOG) + RtfText(BaseExeName + L".log") + L"\"");
+        RtfScriptPlaceholder(L"\"" + LogPath + L"\"");
       UnicodeString IniParameter =
         RtfCommandlineSwitch(INI_SWITCH, L"configuration") + RtfText(UnicodeString(L"=") + INI_NUL);
       UnicodeString CommandParameter = RtfCommandlineSwitch(COMMAND_SWITCH, L"scripting");
 
+      typedef std::vector<UnicodeString> TCommands;
+      TCommands Commands;
+
+      Commands.push_back(RtfScriptCommand(L"open") + L" " + OpenCommand);
+      Commands.push_back(UnicodeString());
+
+      bool NoArgs = false;
+
+      if (FTransfer)
+      {
+        UnicodeString TransferCommand;
+
+        if (FToRemote)
+        {
+          Commands.push_back(RtfScriptCommand(L"lcd") + L" " + RtfText(QuoteStringParam(FSourcePath)));
+          Commands.push_back(RtfScriptCommand(L"cd") + L" " + RtfText(QuoteStringParam(UnixExcludeTrailingBackslash(FPath))));
+          TransferCommand = L"put";
+        }
+        else
+        {
+          Commands.push_back(RtfScriptCommand(L"cd") + L" " + RtfText(QuoteStringParam(FSourcePath)));
+          Commands.push_back(RtfScriptCommand(L"lcd") + L" " + RtfText(QuoteStringParam(ExcludeTrailingBackslash(FPath))));
+          TransferCommand = L"get";
+        }
+
+        Commands.push_back(UnicodeString());
+
+        UnicodeString TransferCommandLink = ScriptCommandLink(TransferCommand);
+        UnicodeString TransferCommandArgs;
+        if (FMove)
+        {
+          TransferCommandArgs += RtfSwitch(DELETE_SWITCH, TransferCommandLink);
+        }
+        TransferCommandArgs += FCopyParam.GenerateTransferCommandArgs(FCopyParamAttrs, TransferCommandLink, NoArgs);
+
+        TransferCommand = RtfScriptCommand(TransferCommand) + TransferCommandArgs;
+
+        if (FFilesSelected == fsList)
+        {
+          for (int Index = 0; Index < FPaths->Count; Index++)
+          {
+            Commands.push_back(TransferCommand + L" " + RtfText(QuoteStringParam(EscapeFileMask(FPaths->Strings[Index]))));
+          }
+        }
+        else
+        {
+          Commands.push_back(TransferCommand + L" " + RtfText(QuoteStringParam(FSourcePath + L"*")));
+        }
+      }
+      else
+      {
+        Commands.push_back(L"# " + CommandPlaceholder1);
+        Commands.push_back(L"# " + CommandPlaceholder2);
+      }
+
+      Commands.push_back(UnicodeString());
+      Commands.push_back(RtfScriptCommand(L"exit"));
+
+      UnicodeString ScriptDescription;
+
       if (ScriptFormatCombo->ItemIndex == sfScriptFile)
       {
-        Result =
-          FORMAT(
-            RtfScriptCommand(L"open") + L" %s" + RtfPara +
-            RtfPara +
-            RtfScriptComment("# %s") + RtfPara +
-            RtfScriptComment("# %s") + RtfPara +
-            RtfPara +
-            RtfScriptCommand(L"exit") + RtfPara,
-            (OpenCommand, CommandPlaceholder1, CommandPlaceholder2));
+        for (TCommands::const_iterator I = Commands.begin(); I != Commands.end(); I++)
+        {
+          UnicodeString Command = *I;
+          if (!Command.IsEmpty())
+          {
+            if (Command[1] == L'#')
+            {
+              Result += RtfScriptComment(Command);
+            }
+            else
+            {
+              Result += Command;
+            }
+          }
+          Result += RtfPara;
+        }
+
+        UnicodeString ScriptCommandLine =
+          FORMAT("\"%s\" /%s=\"%s\" /%s=%s /%s=\"%s\"",
+            (ExeName, LowerCase(LOG_SWITCH), LogPath, LowerCase(INI_SWITCH), INI_NUL, LowerCase(SCRIPT_SWITCH), LoadStr(GENERATE_URL_PATH_TO_SCRIPT)));
+        Result +=
+          RtfPara +
+          RtfScriptComment(L"# " + LoadStr(GENERATE_URL_SCRIPT_DESC)) + RtfPara +
+          RtfScriptComment(L"# " + ScriptCommandLine) + RtfPara;
+
         WordWrap = false;
         FixedWidth = true;
       }
@@ -313,11 +453,32 @@ void __fastcall TGenerateUrlDialog::UpdateControls()
           RtfPara +
           RtfText(L"\"" + ComExeName + "\" ^") + RtfPara +
           RtfText(L"  ") + LogParameter + L" " + IniParameter + RtfText(L" ^") + RtfPara +
-          RtfText(L"  ") + CommandParameter + RtfText(L" ^") + RtfPara +
-          RtfText(L"    \"") + RtfScriptCommand(L"open") + RtfText(L" ") + EscapeParam(ReplaceStr(OpenCommand, L"%", L"%%")) + RtfText(L"\" ^") + RtfPara +
-          RtfText(L"    \"") + RtfScriptPlaceholder(CommandPlaceholder1) + RtfText(L"\" ^") + RtfPara +
-          RtfText(L"    \"") + RtfScriptPlaceholder(CommandPlaceholder2) + RtfText(L"\" ^") + RtfPara +
-          RtfText(L"    \"") + RtfScriptCommand(L"exit") + RtfText(L"\"") + RtfPara +
+          RtfText(L"  ") + CommandParameter;
+
+        for (TCommands::const_iterator I = Commands.begin(); I != Commands.end(); I++)
+        {
+          UnicodeString Command = *I;
+          if (!Command.IsEmpty())
+          {
+            Result +=
+              RtfText(L" ^") + RtfPara +
+              RtfText(L"    \"");
+
+            if (Command[1] == L'#')
+            {
+              Command.Delete(1, 1);
+              Result += RtfScriptPlaceholder(Command.TrimLeft());
+            }
+            else
+            {
+              Result += RtfEscapeParam(ReplaceStr(Command, L"%", L"%%"));
+            }
+            Result += L"\"";
+          }
+        }
+
+        Result +=
+          RtfPara +
           RtfPara +
           RtfKeyword(L"set") + RtfText(L" WINSCP_RESULT=%ERRORLEVEL%") + RtfPara +
           RtfKeyword(L"if") + RtfText(L" %WINSCP_RESULT% ") + RtfKeyword(L"equ") + RtfText(L" 0 (") + RtfPara +
@@ -335,14 +496,43 @@ void __fastcall TGenerateUrlDialog::UpdateControls()
         Result =
           LogParameter + L" " +
           IniParameter + L" " +
-          CommandParameter + L" " +
-            RtfText(L"\"") + RtfScriptCommand(L"open") + RtfText(L" ") + EscapeParam(OpenCommand) + RtfText(L"\" ") +
-            RtfText(L"\"") + RtfScriptPlaceholder(CommandPlaceholder1) + RtfText(L"\" ") +
-            RtfText(L"\"") + RtfScriptPlaceholder(CommandPlaceholder2) + RtfText(L"\" ") +
-            RtfText(L"\"") + RtfScriptCommand(L"exit") + RtfText(L"\"");
+          CommandParameter;
+
+        for (TCommands::const_iterator I = Commands.begin(); I != Commands.end(); I++)
+        {
+          UnicodeString Command = *I;
+          if (!Command.IsEmpty())
+          {
+            Result += RtfText(L" \"");
+            if (Command[1] == L'#')
+            {
+              Command.Delete(1, 1);
+              Result += RtfScriptPlaceholder(Command.TrimLeft());
+            }
+            else
+            {
+              Result += RtfEscapeParam(Command);
+            }
+            Result += L"\"";
+          }
+        }
+
         WordWrap = true;
         FixedWidth = false;
+
+        ScriptDescription = FMTLOAD(GENERATE_URL_COMMANDLINE_DESC, (FORMAT("\"%s\"", (ExeName)))) + L"\n";
       }
+
+      if (HostKeyUnknown)
+      {
+        ScriptDescription += LoadStr(GENERATE_URL_HOSTKEY_UNKNOWN) + L"\n";
+      }
+      if (NoArgs)
+      {
+        ScriptDescription += LoadStr(GENERATE_URL_COPY_PARAM_SCRIPT_REMAINING) + L"\n";
+      }
+
+      ScriptDescriptionLabel->Caption = ScriptDescription;
     }
     else if (DebugAlwaysTrue(OptionsPageControl->ActivePage == AssemblySheet))
     {
@@ -519,22 +709,7 @@ void __fastcall TGenerateUrlDialog::ClipboardButtonClick(TObject * /*Sender*/)
     Text += EOL;
   }
 
-  // Remove all tags HYPERLINK "http://www.example.com"
-  int Index = 1;
-  while ((P = PosFrom(RtfHyperlinkFieldPrefix, Text, Index)) > 0)
-  {
-    int Index2 = P + RtfHyperlinkFieldPrefix.Length();
-    UnicodeString RtfHyperlinkFieldSuffix = L"\" ";
-    int P2 = PosFrom(RtfHyperlinkFieldSuffix, Text, Index2);
-    if (P2 > 0)
-    {
-      Text.Delete(P, P2 - P + RtfHyperlinkFieldSuffix.Length());
-    }
-    else
-    {
-      Index = Index2;
-    }
-  }
+  Text = RtfRemoveHyperlinks(Text);
 
   CopyToClipboard(Text);
 }

+ 13 - 2
source/forms/GenerateUrl.h

@@ -13,6 +13,7 @@
 #include <System.Actions.hpp>
 #include <Vcl.ActnList.hpp>
 #include <Vcl.StdActns.hpp>
+#include <WinInterface.h>
 //---------------------------------------------------------------------------
 class TRichEdit41;
 //---------------------------------------------------------------------------
@@ -53,9 +54,17 @@ __published:
 
 private:
   TSessionData * FData;
-  TStrings * FPaths;
+  std::unique_ptr<TStrings> FPaths;
   bool FChanging;
   TRichEdit41 * FResultMemo41;
+  bool FTransfer;
+  bool FToRemote;
+  bool FMove;
+  int FCopyParamAttrs;
+  UnicodeString FPath;
+  TFilesSelected FFilesSelected;
+  UnicodeString FSourcePath;
+  TCopyParamType FCopyParam;
 
 protected:
   void __fastcall UpdateControls();
@@ -65,7 +74,9 @@ protected:
   virtual void __fastcall Dispatch(void * AMessage);
 
 public:
-  __fastcall TGenerateUrlDialog(TComponent * Owner, TSessionData * Data, TStrings * Paths);
+  __fastcall TGenerateUrlDialog(
+    TComponent * Owner, TSessionData * Data, TFilesSelected FilesSelected, TStrings * Paths,
+    bool Transfer, bool ToRemote, bool Move, int CopyParamAttrs, const UnicodeString & Path, const TCopyParamType & CopyParam);
   void __fastcall Execute();
 };
 //---------------------------------------------------------------------------

+ 2 - 1
source/forms/ScpCommander.cpp

@@ -1473,7 +1473,8 @@ void __fastcall TScpCommanderForm::LocalFileControlDDFileOperation(
         {
           TransferType = ttMove;
         }
-        int Options = 0;
+        int Options =
+          FLAGMASK(DraggingAllFilesFromDirView(osRemote, FInternalDDDownloadList), coAllFiles);
         if (CopyParamDialog(tdToLocal, TransferType,
               false, FInternalDDDownloadList, TargetDirectory, CopyParams,
               (WinConfiguration->DDTransferConfirmation != asOff), true, Options))

+ 1 - 1
source/forms/Synchronize.cpp

@@ -555,7 +555,7 @@ void __fastcall TSynchronizeDialog::CopyParamClick(TObject * Sender)
   // user really confirms it on custom dialog
   TCopyParamType ACopyParams = CopyParams;
   if (CopyParamListPopupClick(Sender, ACopyParams, FPreset,
-        ActualCopyParamAttrs()))
+        ActualCopyParamAttrs()) > 0)
   {
     FCopyParams = ACopyParams;
     UpdateControls();

+ 5 - 0
source/resource/TextsWin.h

@@ -561,6 +561,11 @@
 #define GENERATE_URL_COMMANDLINE_DESC 1959
 #define GENERATE_URL_HOSTKEY_UNKNOWN 1960
 #define GENERATE_URL_WRITABLE_PATH_TO_LOG 1961
+#define COPY_PARAM_GENERATE_CODE 1962
+#define GENERATE_URL_TRANSFER_TITLE 1963
+#define GENERATE_URL_COPY_PARAM_SCRIPT_REMAINING 1964
+#define GENERATE_URL_SCRIPT_DESC 1965
+#define GENERATE_URL_PATH_TO_SCRIPT 1966
 
 // 2xxx is reserved for TextsFileZilla.h
 

+ 6 - 1
source/resource/TextsWin1.rc

@@ -425,7 +425,7 @@ BEGIN
         SPECIAL_FOLDER_MY_DOCUMENTS, "My documents"
         SPECIAL_FOLDER_DESKTOP, "Desktop"
         COMMAND_LINE_LABEL, "Command"
-        COPY_PARAM_SAVE_SETTINGS, "&Set as default"
+        COPY_PARAM_SAVE_SETTINGS, "&Set as Default"
         CIPHER_NAME_WARN, "-- warn below here --"
         CIPHER_NAME_3DES, "3DES"
         CIPHER_NAME_BLOWFISH, "Blowfish"
@@ -564,6 +564,11 @@ BEGIN
         GENERATE_URL_COMMANDLINE_DESC, "Command-line arguments for %s"
         GENERATE_URL_HOSTKEY_UNKNOWN, "A server host key is not known. Please connect at least once, before generating the code."
         GENERATE_URL_WRITABLE_PATH_TO_LOG, "C:\\writable\\path\\to\\log\\"
+        COPY_PARAM_GENERATE_CODE, "Generate &Code..."
+        GENERATE_URL_TRANSFER_TITLE, "Generate transfer code"
+        GENERATE_URL_COPY_PARAM_SCRIPT_REMAINING, "Some configured transfer settings do not have a scripting equivalent. Use the /rawconfig command-line switch instead."
+        GENERATE_URL_SCRIPT_DESC, "Execute the script using a command like:"
+        GENERATE_URL_PATH_TO_SCRIPT, "C:\\path\\to\\script\\script.txt"
 
         WIN_VARIABLE_STRINGS, "WIN_VARIABLE"
         WINSCP_COPYRIGHT, "Copyright © 2000-2016 Martin Prikryl"

+ 1 - 1
source/windows/ConsoleRunner.cpp

@@ -2511,7 +2511,7 @@ int __fastcall Console(TConsoleMode Mode)
         if (CheckSafe(Params))
         {
           UnicodeString Value;
-          if (Params->FindSwitch(L"script", Value) && !Value.IsEmpty())
+          if (Params->FindSwitch(SCRIPT_SWITCH, Value) && !Value.IsEmpty())
           {
             Configuration->Usage->Inc(L"ScriptFile");
             LoadScriptFromFile(Value, ScriptCommands);

+ 27 - 8
source/windows/WinInterface.cpp

@@ -754,6 +754,7 @@ const int cpiDefault = -1;
 const int cpiConfigure = -2;
 const int cpiCustom = -3;
 const int cpiSaveSettings = -4;
+const int cpiGenerateCode = -5;
 //---------------------------------------------------------------------------
 void __fastcall CopyParamListPopup(TRect Rect, TPopupMenu * Menu,
   const TCopyParamType & Param, UnicodeString Preset, TNotifyEvent OnClick,
@@ -840,24 +841,38 @@ void __fastcall CopyParamListPopup(TRect Rect, TPopupMenu * Menu,
   Item->OnClick = OnClick;
   Menu->Items->Add(Item);
 
+  if (FLAGSET(Options, cplGenerateCode))
+  {
+    Item = new TMenuItem(Menu);
+    Item->Caption = L"-";
+    Menu->Items->Add(Item);
+
+    Item = new TMenuItem(Menu);
+    Item->Caption = LoadStr(COPY_PARAM_GENERATE_CODE);
+    Item->Tag = cpiGenerateCode;
+    Item->OnClick = OnClick;
+    Menu->Items->Add(Item);
+  }
+
+
   MenuPopup(Menu, Rect, NULL);
 }
 //---------------------------------------------------------------------------
-bool __fastcall CopyParamListPopupClick(TObject * Sender,
+int __fastcall CopyParamListPopupClick(TObject * Sender,
   TCopyParamType & Param, UnicodeString & Preset, int CopyParamAttrs,
   bool * SaveSettings)
 {
   TComponent * Item = dynamic_cast<TComponent *>(Sender);
   DebugAssert(Item != NULL);
-  DebugAssert((Item->Tag >= cpiSaveSettings) && (Item->Tag < GUIConfiguration->CopyParamList->Count));
+  DebugAssert((Item->Tag >= cpiGenerateCode) && (Item->Tag < GUIConfiguration->CopyParamList->Count));
 
-  bool Result;
+  int Result;
   if (Item->Tag == cpiConfigure)
   {
     bool MatchedPreset = (GUIConfiguration->CopyParamPreset[Preset] == Param);
     DoPreferencesDialog(pmPresets);
-    Result = (MatchedPreset && GUIConfiguration->HasCopyParamPreset[Preset]);
-    if (Result)
+    Result = (MatchedPreset && GUIConfiguration->HasCopyParamPreset[Preset]) ? 1 : 0;
+    if (Result > 0)
     {
       // For cast, see a comment below
       Param = TCopyParamType(GUIConfiguration->CopyParamPreset[Preset]);
@@ -865,7 +880,7 @@ bool __fastcall CopyParamListPopupClick(TObject * Sender,
   }
   else if (Item->Tag == cpiCustom)
   {
-    Result = DoCopyParamCustomDialog(Param, CopyParamAttrs);
+    Result = DoCopyParamCustomDialog(Param, CopyParamAttrs) ? 1 : 0;
   }
   else if (Item->Tag == cpiSaveSettings)
   {
@@ -873,7 +888,11 @@ bool __fastcall CopyParamListPopupClick(TObject * Sender,
     {
       *SaveSettings = !*SaveSettings;
     }
-    Result = false;
+    Result = 0;
+  }
+  else if (Item->Tag == cpiGenerateCode)
+  {
+    Result = -cplGenerateCode;
   }
   else
   {
@@ -882,7 +901,7 @@ bool __fastcall CopyParamListPopupClick(TObject * Sender,
     // The cast strips away the "queue" properties of the TGUICopyParamType
     // that are not configurable in presets
     Param = TCopyParamType(GUIConfiguration->CopyParamPreset[Preset]);
-    Result = true;
+    Result = 1;
   }
   return Result;
 }

+ 8 - 2
source/windows/WinInterface.h

@@ -186,13 +186,14 @@ const coAllowRemoteTransfer = 0x100;
 const coNoQueue             = 0x200;
 const coNoQueueIndividually = 0x400;
 const coShortCutHint        = 0x800;
+const coAllFiles            = 0x1000;
 const cooDoNotShowAgain     = 0x01;
 const cooRemoteTransfer     = 0x02;
 const cooSaveSettings       = 0x04;
 bool __fastcall DoCopyDialog(bool ToRemote,
   bool Move, TStrings * FileList, UnicodeString & TargetDirectory,
   TGUICopyParamType * Params, int Options, int CopyParamAttrs,
-  int * OutputOptions);
+  TSessionData * SessionData, int * OutputOptions);
 
 // forms\CreateDirectory.cpp
 bool __fastcall DoCreateDirectoryDialog(UnicodeString & Directory,
@@ -405,16 +406,21 @@ bool __fastcall DoFileFindDialog(UnicodeString Directory,
 
 // forms\GenerateUrl.cpp
 void __fastcall DoGenerateUrlDialog(TSessionData * Data, TStrings * Paths);
+enum TFilesSelected { fsList, fsAll };
+void __fastcall DoGenerateTransferCodeDialog(
+  bool ToRemote, bool Move, int CopyParamAttrs, TSessionData * Data, TFilesSelected FilesSelected,
+  TStrings * FileList, const UnicodeString & Path, const TCopyParamType & CopyParam);
 
 void __fastcall CopyParamListButton(TButton * Button);
 const int cplNone =             0x00;
 const int cplCustomize =        0x01;
 const int cplCustomizeDefault = 0x02;
 const int cplSaveSettings =     0x04;
+const int cplGenerateCode =     0x08;
 void __fastcall CopyParamListPopup(TRect R, TPopupMenu * Menu,
   const TCopyParamType & Param, UnicodeString Preset, TNotifyEvent OnClick,
   int Options, int CopyParamAttrs, bool SaveSettings = false);
-bool __fastcall CopyParamListPopupClick(TObject * Sender,
+int __fastcall CopyParamListPopupClick(TObject * Sender,
   TCopyParamType & Param, UnicodeString & Preset, int CopyParamAttrs,
   bool * SaveSettings = NULL);
 

+ 3 - 3
source/windows/WinMain.cpp

@@ -103,7 +103,7 @@ void __fastcall Upload(TTerminal * Terminal, TStrings * FileList, bool UseDefaul
   int CopyParamAttrs = Terminal->UsableCopyParamAttrs(0).Upload;
   if (UseDefaults ||
       DoCopyDialog(true, false, FileList, TargetDirectory, &CopyParam, Options,
-        CopyParamAttrs, NULL))
+        CopyParamAttrs, NULL, NULL))
   {
     Terminal->CopyToRemote(FileList, TargetDirectory, &CopyParam, 0);
   }
@@ -136,7 +136,7 @@ void __fastcall Download(TTerminal * Terminal, const UnicodeString FileName,
     int CopyParamAttrs = Terminal->UsableCopyParamAttrs(0).Download;
     if (UseDefaults ||
         DoCopyDialog(false, false, FileList, TargetDirectory, &CopyParam,
-          Options, CopyParamAttrs, NULL))
+          Options, CopyParamAttrs, NULL, NULL))
     {
       Terminal->CopyToLocal(FileList, TargetDirectory, &CopyParam, 0);
     }
@@ -668,7 +668,7 @@ int __fastcall Execute()
   // We have to check for /console only after the other options,
   // as the /console is always used when we are run by winscp.com
   // (ambiguous use to pass console version)
-  else if (Params->FindSwitch(L"Console") || Params->FindSwitch(L"script") ||
+  else if (Params->FindSwitch(L"Console") || Params->FindSwitch(SCRIPT_SWITCH) ||
       Params->FindSwitch(COMMAND_SWITCH))
   {
     Mode = cmScripting;