Selaa lähdekoodia

Transfer settings that do not have a dedicated scripting switch or a .NET TransferSettings property can be set using -rawtransfesettings switch or TransferSettings.AddRawSettings method + Generated script/code can generate these + Tests that previously used AddRawConfiguration(@"Interface\CopyParam\...), use AddRawSettings now. + It's possible to limit number of command line parameters used for open-ended switches like -rawconfig, -rawsettings and -rawtransfesettings using syntax -switch[count] + Fixing GetFilesExcludeEmptyDirectories test (it didn't upload hidden files previously)

Source commit: 4a84ba5ed0f2f09f4815c11cb4714e0c2ef7fc12
Martin Prikryl 7 vuotta sitten
vanhempi
sitoutus
78506ae1b7

+ 2 - 2
dotnet/Session.cs

@@ -1489,8 +1489,8 @@ namespace WinSCP
                 SessionOptionsToSwitches(sessionOptions, scanFingerprint, out string arguments, out string logArguments);
 
                 const string switchName = "-rawsettings";
-                Tools.AddRawParameters(ref arguments, sessionOptions.RawSettings, switchName);
-                Tools.AddRawParameters(ref logArguments, sessionOptions.RawSettings, switchName);
+                Tools.AddRawParameters(ref arguments, sessionOptions.RawSettings, switchName, false);
+                Tools.AddRawParameters(ref logArguments, sessionOptions.RawSettings, switchName, false);
 
                 if (!string.IsNullOrEmpty(arguments))
                 {

+ 12 - 1
dotnet/TransferOptions.cs

@@ -36,12 +36,20 @@ namespace WinSCP
         public int SpeedLimit { get; set; }
         public OverwriteMode OverwriteMode { get; set; }
 
+        internal Dictionary<string, string> RawSettings { get; private set; }
+
         public TransferOptions()
         {
             PreserveTimestamp = true;
             TransferMode = TransferMode.Binary;
             ResumeSupport = new TransferResumeSupport();
             OverwriteMode = OverwriteMode.Overwrite;
+            RawSettings = new Dictionary<string,string>();
+        }
+
+        public void AddRawSettings(string setting, string value)
+        {
+            RawSettings.Add(setting, value);
         }
 
         internal string ToSwitches()
@@ -106,7 +114,10 @@ namespace WinSCP
                     throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "{0} is not supported", OverwriteMode));
             }
 
-            return string.Join(" ", switches.ToArray());
+            string arguments = string.Join(" ", switches.ToArray());
+            Tools.AddRawParameters(ref arguments, RawSettings, "-rawtransfersettings", true);
+
+            return arguments;
         }
     }
 }

+ 1 - 1
dotnet/internal/ExeSessionProcess.cs

@@ -101,7 +101,7 @@ namespace WinSCP
                     xmlLogSwitch + "/nointeractiveinput " + assemblyVersionSwitch +
                     configSwitch + logSwitch + logLevelSwitch + _session.AdditionalExecutableArguments;
 
-                Tools.AddRawParameters(ref arguments, _session.RawConfiguration, "/rawconfig");
+                Tools.AddRawParameters(ref arguments, _session.RawConfiguration, "/rawconfig", false);
 
                 if (!string.IsNullOrEmpty(additionalArguments))
                 {

+ 7 - 1
dotnet/internal/Tools.cs

@@ -35,7 +35,8 @@ namespace WinSCP
             return value;
         }
 
-        public static void AddRawParameters(ref string arguments, Dictionary<string, string> parameters, string switchName)
+        public static void AddRawParameters(
+            ref string arguments, Dictionary<string, string> parameters, string switchName, bool count)
         {
             if (parameters.Count > 0)
             {
@@ -44,6 +45,11 @@ namespace WinSCP
                     arguments += " ";
                 }
                 arguments += switchName;
+                if (count)
+                {
+                    arguments += string.Format(CultureInfo.InvariantCulture, "[{0}]", parameters.Count);
+                }
+
                 foreach (KeyValuePair<string, string> rawSetting in parameters)
                 {
                     arguments += string.Format(CultureInfo.InvariantCulture, " {0}=\"{1}\"", rawSetting.Key, ArgumentEscape(rawSetting.Value));

+ 39 - 10
source/core/Common.cpp

@@ -3773,19 +3773,34 @@ UnicodeString __fastcall AssemblyNewClassInstance(TAssemblyLanguage Language, co
   return Result;
 }
 //---------------------------------------------------------------------
+UnicodeString __fastcall AssemblyVariableDeclaration(TAssemblyLanguage Language)
+{
+  UnicodeString Result;
+  switch (Language)
+  {
+    case alVBNET:
+      Result = RtfKeyword(L"Dim") + RtfText(L" ");
+      break;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------
 UnicodeString __fastcall AssemblyNewClassInstanceStart(
   TAssemblyLanguage Language, const UnicodeString & ClassName, bool Inline)
 {
-  UnicodeString NewClassInstance = AssemblyNewClassInstance(Language, ClassName, Inline);
   UnicodeString SpaceOrPara = (Inline ? UnicodeString(L" ") : RtfPara);
 
   UnicodeString Result;
+  if (!Inline)
+  {
+    Result += AssemblyVariableDeclaration(Language);
+  }
+  Result += AssemblyNewClassInstance(Language, ClassName, Inline);
+
   switch (Language)
   {
     case alCSharp:
-      Result =
-        NewClassInstance + SpaceOrPara +
-        RtfText(L"{") + SpaceOrPara;
+      Result += SpaceOrPara + RtfText(L"{") + SpaceOrPara;
       break;
 
     case alVBNET:
@@ -3793,11 +3808,7 @@ UnicodeString __fastcall AssemblyNewClassInstanceStart(
       // But for inline use, we have to use object initialize.
       // We should consistently always use object initilizers.
       // Unfortunatelly VB.NET object initializer (contrary to C#) does not allow trailing comma.
-      if (!Inline)
-      {
-        Result += RtfKeyword(L"Dim") + RtfText(L" ");
-      }
-      Result += NewClassInstance + SpaceOrPara + RtfKeyword(L"With");
+      Result += SpaceOrPara + RtfKeyword(L"With");
       if (Inline)
       {
         Result += RtfText(L" { ");
@@ -3809,7 +3820,7 @@ UnicodeString __fastcall AssemblyNewClassInstanceStart(
       break;
 
     case alPowerShell:
-      Result = NewClassInstance + RtfText(" -Property @{") + SpaceOrPara;
+      Result += RtfText(" -Property @{") + SpaceOrPara;
       break;
   }
   return Result;
@@ -3858,6 +3869,24 @@ UnicodeString __fastcall AssemblyNewClassInstanceEnd(TAssemblyLanguage Language,
   return Result;
 }
 //---------------------------------------------------------------------------
+UnicodeString __fastcall AssemblyAddRawSettings(
+  TAssemblyLanguage Language, TStrings * RawSettings, const UnicodeString & ClassName,
+  const UnicodeString & MethodName)
+{
+  UnicodeString Result;
+  for (int Index = 0; Index < RawSettings->Count; Index++)
+  {
+    UnicodeString Name = RawSettings->Names[Index];
+    UnicodeString Value = RawSettings->ValueFromIndex[Index];
+    UnicodeString AddRawSettingsMethod =
+      RtfLibraryMethod(ClassName, MethodName, false) +
+      FORMAT(L"(%s, %s)", (AssemblyString(Language, Name), AssemblyString(Language, Value)));
+    UnicodeString VariableName = AssemblyVariableName(Language, ClassName);
+    Result += RtfText(VariableName + L".") + AddRawSettingsMethod + AssemblyStatementSeparator(Language) + RtfPara;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 void __fastcall LoadScriptFromFile(UnicodeString FileName, TStrings * Lines)
 {
   std::auto_ptr<TFileStream> Stream(new TFileStream(ApiPath(FileName), fmOpenRead | fmShareDenyWrite));

+ 4 - 0
source/core/Common.h

@@ -303,11 +303,15 @@ UnicodeString __fastcall RtfLibraryMethod(const UnicodeString & ClassName, const
 UnicodeString __fastcall RtfLibraryClass(const UnicodeString & ClassName);
 UnicodeString __fastcall AssemblyVariableName(TAssemblyLanguage Language, const UnicodeString & ClassName);
 UnicodeString __fastcall AssemblyStatementSeparator(TAssemblyLanguage Language);
+UnicodeString __fastcall AssemblyVariableDeclaration(TAssemblyLanguage Language);
 UnicodeString __fastcall AssemblyNewClassInstance(
   TAssemblyLanguage Language, const UnicodeString & ClassName, bool Inline);
 UnicodeString __fastcall AssemblyNewClassInstanceStart(
   TAssemblyLanguage Language, const UnicodeString & ClassName, bool Inline);
 UnicodeString __fastcall AssemblyNewClassInstanceEnd(TAssemblyLanguage Language, bool Inline);
+UnicodeString __fastcall AssemblyAddRawSettings(
+  TAssemblyLanguage Language, TStrings * RawSettings, const UnicodeString & ClassName,
+  const UnicodeString & MethodName);
 //---------------------------------------------------------------------------
 #include "Global.h"
 //---------------------------------------------------------------------------

+ 83 - 46
source/core/CopyParam.cpp

@@ -66,12 +66,10 @@ UnicodeString __fastcall TCopyParamType::GetInfoStr(
   UnicodeString Result;
   bool SomeAttrIncluded;
   UnicodeString ScriptArgs;
-  bool NoScriptArgs;
   UnicodeString AssemblyCode;
-  bool NoCodeProperties;
   DoGetInfoStr(
     Separator, Attrs, Result, SomeAttrIncluded,
-    UnicodeString(), ScriptArgs, NoScriptArgs, TAssemblyLanguage(0), AssemblyCode, NoCodeProperties);
+    UnicodeString(), ScriptArgs, TAssemblyLanguage(0), AssemblyCode);
   return Result;
 }
 //---------------------------------------------------------------------------
@@ -80,51 +78,45 @@ bool __fastcall TCopyParamType::AnyUsableCopyParam(int Attrs) const
   UnicodeString Result;
   bool SomeAttrIncluded;
   UnicodeString ScriptArgs;
-  bool NoScriptArgs;
   UnicodeString AssemblyCode;
-  bool NoCodeProperties;
   DoGetInfoStr(
     L";", Attrs, Result, SomeAttrIncluded,
-    UnicodeString(), ScriptArgs, NoScriptArgs, TAssemblyLanguage(0), AssemblyCode, NoCodeProperties);
+    UnicodeString(), ScriptArgs, TAssemblyLanguage(0), AssemblyCode);
   return SomeAttrIncluded;
 }
 //---------------------------------------------------------------------------
-UnicodeString __fastcall TCopyParamType::GenerateTransferCommandArgs(int Attrs, const UnicodeString & Link, bool & NoScriptArgs) const
+UnicodeString __fastcall TCopyParamType::GenerateTransferCommandArgs(int Attrs, const UnicodeString & Link) const
 {
   UnicodeString Result;
   bool SomeAttrIncluded;
   UnicodeString ScriptArgs;
   UnicodeString AssemblyCode;
-  bool NoCodeProperties;
   DoGetInfoStr(
     L";", Attrs, Result, SomeAttrIncluded,
-    Link, ScriptArgs, NoScriptArgs, TAssemblyLanguage(0), AssemblyCode, NoCodeProperties);
+    Link, ScriptArgs, TAssemblyLanguage(0), AssemblyCode);
   return ScriptArgs;
 }
 //---------------------------------------------------------------------------
-UnicodeString __fastcall TCopyParamType::GenerateAssemblyCode(
-  TAssemblyLanguage Language, int Attrs, bool & NoCodeProperties) const
+UnicodeString __fastcall TCopyParamType::GenerateAssemblyCode(TAssemblyLanguage Language, int Attrs) const
 {
   UnicodeString Result;
   bool SomeAttrIncluded;
   UnicodeString ScriptArgs;
-  bool NoScriptArgs;
   UnicodeString AssemblyCode;
-  DoGetInfoStr(L";", Attrs, Result, SomeAttrIncluded, UnicodeString(), ScriptArgs, NoScriptArgs, Language, AssemblyCode, NoCodeProperties);
+  DoGetInfoStr(L";", Attrs, Result, SomeAttrIncluded, UnicodeString(), ScriptArgs, Language, AssemblyCode);
   return AssemblyCode;
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamType::DoGetInfoStr(
   UnicodeString Separator, int Options,
   UnicodeString & Result, bool & SomeAttrIncluded,
-  const UnicodeString & Link, UnicodeString & ScriptArgs, bool & NoScriptArgs, TAssemblyLanguage Language, UnicodeString & AssemblyCode,
-  bool & NoCodeProperties) const
+  const UnicodeString & Link, UnicodeString & ScriptArgs, TAssemblyLanguage Language, UnicodeString & AssemblyCode) const
 {
   TCopyParamType Defaults;
+  TCopyParamType ScriptNonDefaults;
+  TCopyParamType CodeNonDefaults;
 
   bool SomeAttrExcluded = false;
-  NoScriptArgs = false;
-  NoCodeProperties = false;
   SomeAttrIncluded = false;
   #define ADD(STR, EXCEPT) \
     FLAGCLEAR(Options, EXCEPT) ? (AddToList(Result, (STR), Separator), SomeAttrIncluded = true, true) : (SomeAttrExcluded = true, false)
@@ -171,8 +163,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
         Language, TransferOptionsClassName, L"TransferMode", L"TransferMode", TransferModeMembers[TransferMode], false);
       if (AsciiFileMaskDiffers)
       {
-        NoScriptArgs = true;
-        NoCodeProperties = true;
+        ScriptNonDefaults.AsciiFileMask = AsciiFileMask;
+        CodeNonDefaults.AsciiFileMask = AsciiFileMask;
       }
     }
   }
@@ -190,15 +182,13 @@ void __fastcall TCopyParamType::DoGetInfoStr(
          (LoadStrPart(COPY_INFO_FILENAME, FileNameCase + 2))),
          cpaIncludeMaskOnly))
     {
-      NoScriptArgs = true;
-      NoCodeProperties = true;
+      ScriptNonDefaults.FileNameCase = FileNameCase;
+      CodeNonDefaults.FileNameCase = FileNameCase;
     }
   }
 
-  if ((InvalidCharsReplacement == NoReplacement) !=
-        (Defaults.InvalidCharsReplacement == NoReplacement))
+  if (InvalidCharsReplacement != Defaults.InvalidCharsReplacement)
   {
-    DebugAssert(InvalidCharsReplacement == NoReplacement);
     int Except = cpaIncludeMaskOnly;
     if (InvalidCharsReplacement == NoReplacement)
     {
@@ -207,8 +197,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
 
     if (FLAGCLEAR(Options, Except))
     {
-      NoScriptArgs = true;
-      NoCodeProperties = true;
+      ScriptNonDefaults.InvalidCharsReplacement = InvalidCharsReplacement;
+      CodeNonDefaults.InvalidCharsReplacement = InvalidCharsReplacement;
     }
   }
 
@@ -244,8 +234,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
 
     if ((AddXToDirectories != Defaults.AddXToDirectories) && FLAGCLEAR(Options, Except))
     {
-      NoScriptArgs = true;
-      NoCodeProperties = true;
+      ScriptNonDefaults.AddXToDirectories = AddXToDirectories;
+      CodeNonDefaults.AddXToDirectories = AddXToDirectories;
     }
   }
 
@@ -291,7 +281,7 @@ void __fastcall TCopyParamType::DoGetInfoStr(
         if (PreserveTimeDirs && FLAGCLEAR(Options, ExceptDirs))
         {
           ScriptArgs += RtfSwitchValue(PRESERVETIME_SWITCH, Link, PRESERVETIMEDIRS_SWITCH_VALUE);
-          NoCodeProperties = true;
+          CodeNonDefaults.PreserveTimeDirs = PreserveTimeDirs;
         }
         else
         {
@@ -314,8 +304,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     {
       if (ADD(LoadStr(COPY_INFO_IGNORE_PERM_ERRORS), cpaIncludeMaskOnly | cpaNoIgnorePermErrors))
       {
-        NoScriptArgs = true;
-        NoCodeProperties = true;
+        ScriptNonDefaults.IgnorePermErrors = IgnorePermErrors;
+        CodeNonDefaults.IgnorePermErrors = IgnorePermErrors;
       }
     }
   }
@@ -326,8 +316,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     {
       if (ADD(LoadStr(COPY_INFO_PRESERVE_READONLY), cpaIncludeMaskOnly | cpaNoPreserveReadOnly))
       {
-        NoScriptArgs = true;
-        NoCodeProperties = true;
+        ScriptNonDefaults.PreserveReadOnly = PreserveReadOnly;
+        CodeNonDefaults.PreserveReadOnly = PreserveReadOnly;
       }
     }
   }
@@ -347,8 +337,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     {
       if (ADD(LoadStr(COPY_INFO_CLEAR_ARCHIVE), cpaIncludeMaskOnly | cpaNoClearArchive))
       {
-        NoScriptArgs = true;
-        NoCodeProperties = true;
+        ScriptNonDefaults.ClearArchive = ClearArchive;
+        CodeNonDefaults.ClearArchive = ClearArchive;
       }
     }
   }
@@ -361,8 +351,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
       {
         if (ADD(LoadStr(COPY_INFO_REMOVE_BOM), cpaIncludeMaskOnly | cpaNoRemoveBOM | cpaNoTransferMode))
         {
-          NoScriptArgs = true;
-          NoCodeProperties = true;
+          ScriptNonDefaults.RemoveBOM = RemoveBOM;
+          CodeNonDefaults.RemoveBOM = RemoveBOM;
         }
       }
     }
@@ -373,8 +363,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
       {
         if (ADD(LoadStr(COPY_INFO_REMOVE_CTRLZ), cpaIncludeMaskOnly | cpaNoRemoveCtrlZ | cpaNoTransferMode))
         {
-          NoScriptArgs = true;
-          NoCodeProperties = true;
+          ScriptNonDefaults.RemoveCtrlZ = RemoveCtrlZ;
+          CodeNonDefaults.RemoveCtrlZ = RemoveCtrlZ;
         }
       }
     }
@@ -409,7 +399,7 @@ void __fastcall TCopyParamType::DoGetInfoStr(
       if (ADD(StripHotkey(LoadStr(COPY_PARAM_NEWER_ONLY)), cpaIncludeMaskOnly | cpaNoNewerOnly))
       {
         ScriptArgs += RtfSwitch(NEWERONLY_SWICH, Link);
-        NoCodeProperties = true;
+        CodeNonDefaults.NewerOnly = NewerOnly;
       }
     }
   }
@@ -420,8 +410,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     {
       if (ADD(StripHotkey(LoadStr(COPY_INFO_DONT_ENCRYPT_NEW_FILES)), cpaIncludeMaskOnly | cpaNoEncryptNewFiles))
       {
-        NoScriptArgs = true;
-        NoCodeProperties = true;
+        ScriptNonDefaults.EncryptNewFiles = EncryptNewFiles;
+        CodeNonDefaults.EncryptNewFiles = EncryptNewFiles;
       }
     }
   }
@@ -432,8 +422,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     {
       if (ADD(StripHotkey(LoadStr(COPY_INFO_EXCLUDE_HIDDEN_FILES)), cpaNoIncludeMask))
       {
-        NoScriptArgs = true;
-        NoCodeProperties = true;
+        ScriptNonDefaults.ExcludeHiddenFiles = ExcludeHiddenFiles;
+        CodeNonDefaults.ExcludeHiddenFiles = ExcludeHiddenFiles;
       }
     }
   }
@@ -444,8 +434,8 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     {
       if (ADD(StripHotkey(LoadStr(COPY_INFO_EXCLUDE_EMPTY_DIRS)), 0))
       {
-        NoScriptArgs = true;
-        NoCodeProperties = true;
+        ScriptNonDefaults.ExcludeEmptyDirectories = ExcludeEmptyDirectories;
+        CodeNonDefaults.ExcludeEmptyDirectories = ExcludeEmptyDirectories;
       }
     }
   }
@@ -492,6 +482,53 @@ void __fastcall TCopyParamType::DoGetInfoStr(
     AssemblyCode += AssemblyPropertyRaw(Language, TransferOptionsClassName, L"ResumeSupport", ResumeSupportCode, false);
   }
 
+  std::unique_ptr<TStringList> RawOptions;
+  std::unique_ptr<TOptionsStorage> OptionsStorage;
+
+  RawOptions.reset(new TStringList());
+  OptionsStorage.reset(new TOptionsStorage(RawOptions.get(), true));
+  ScriptNonDefaults.Save(OptionsStorage.get(), &Defaults);
+
+  if (RawOptions->Count > 0)
+  {
+    ScriptArgs +=
+      RtfSwitch(RAWTRANSFERSETTINGS_SWICH, Link) +
+      FORMAT(L"[%d]", (RawOptions->Count)) +
+      StringsToParams(RawOptions.get());
+  }
+
+  RawOptions.reset(new TStringList());
+  OptionsStorage.reset(new TOptionsStorage(RawOptions.get(), true));
+  CodeNonDefaults.Save(OptionsStorage.get(), &Defaults);
+
+  if (!AssemblyCode.IsEmpty())
+  {
+    AssemblyCode =
+      AssemblyNewClassInstanceStart(Language, TransferOptionsClassName, false) +
+      AssemblyCode +
+      AssemblyNewClassInstanceEnd(Language, false);
+  }
+
+  if (RawOptions->Count > 0)
+  {
+    if (AssemblyCode.IsEmpty())
+    {
+      AssemblyCode = AssemblyVariableDeclaration(Language) + AssemblyNewClassInstance(Language, TransferOptionsClassName, false);
+      if (Language == alCSharp)
+      {
+        AssemblyCode += RtfText(L"()");
+      }
+      AssemblyCode += AssemblyStatementSeparator(Language) + RtfPara;
+    }
+    else
+    {
+      AssemblyCode += RtfPara;
+    }
+
+    AssemblyCode +=
+      AssemblyAddRawSettings(Language, RawOptions.get(), TransferOptionsClassName, L"AddRawSettings");
+  }
+
   if (SomeAttrExcluded)
   {
     Result += (Result.IsEmpty() ? UnicodeString() : Separator) +

+ 4 - 6
source/core/CopyParam.h

@@ -76,9 +76,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 & Link, UnicodeString & ScriptArgs, bool & NoScriptArgs,
-    TAssemblyLanguage Language, UnicodeString & AssemblyCode, bool & NoCodeProperties) const;
+    UnicodeString & Result, bool & SomeAttrIncluded, const UnicodeString & Link, UnicodeString & ScriptArgs,
+    TAssemblyLanguage Language, UnicodeString & AssemblyCode) const;
   TStrings * __fastcall GetTransferSkipList() const;
   void __fastcall SetTransferSkipList(TStrings * value);
 
@@ -108,9 +107,8 @@ public:
   void __fastcall Save(THierarchicalStorage * Storage, const TCopyParamType * Defaults = NULL) 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;
-  UnicodeString __fastcall GenerateAssemblyCode(TAssemblyLanguage Language, int Attrs, bool & NoCodeProperties) const;
+  UnicodeString __fastcall GenerateTransferCommandArgs(int Attrs, const UnicodeString & Link) const;
+  UnicodeString __fastcall GenerateAssemblyCode(TAssemblyLanguage Language, int Attrs) const;
 
   bool __fastcall operator==(const TCopyParamType & rhp) const;
 

+ 1 - 0
source/core/Interface.h

@@ -24,6 +24,7 @@
 #define NONEWERONLY_SWICH L"noneweronly"
 #define DELETE_SWITCH L"delete"
 #define REFRESH_SWITCH L"refresh"
+#define RAWTRANSFERSETTINGS_SWICH L"rawtransfersettings"
 extern const wchar_t * TransferModeNames[];
 extern const int TransferModeNamesCount;
 extern const wchar_t * ToggleNames[];

+ 16 - 1
source/core/Option.cpp

@@ -5,13 +5,17 @@
 #include <Common.h>
 #include "Option.h"
 #include "TextsCore.h"
+#include "System.StrUtils.hpp"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
+const wchar_t ArrayValueDelimiter = L'[';
+const wchar_t ArrayValueEnd = L']';
+//---------------------------------------------------------------------------
 __fastcall TOptions::TOptions()
 {
   FSwitchMarks = L"/-";
-  FSwitchValueDelimiters = L"=:";
+  FSwitchValueDelimiters = UnicodeString(L"=:") + ArrayValueDelimiter;
   FNoMoreSwitches = false;
   FParamCount = 0;
 }
@@ -30,6 +34,7 @@ void __fastcall TOptions::Add(UnicodeString Value)
     bool Switch = false;
     int Index = 0; // shut up
     wchar_t SwitchMark = L'\0';
+    wchar_t ValueDelimiter = L'\0';
     if (!FNoMoreSwitches &&
         (Value.Length() >= 2) &&
         (FSwitchMarks.Pos(Value[1]) > 0))
@@ -41,6 +46,7 @@ void __fastcall TOptions::Add(UnicodeString Value)
       {
         if (Value.IsDelimiter(FSwitchValueDelimiters, Index))
         {
+          ValueDelimiter = Value[Index];
           break;
         }
         // this is to treat /home/martin as parameter, not as switch
@@ -60,6 +66,10 @@ void __fastcall TOptions::Add(UnicodeString Value)
       Option.Type = otSwitch;
       Option.Name = Value.SubString(2, Index - 2);
       Option.Value = Value.SubString(Index + 1, Value.Length());
+      if ((ValueDelimiter == ArrayValueDelimiter) && EndsStr(ArrayValueEnd, Option.Value))
+      {
+        Option.Value.SetLength(Option.Value.Length() - 1);
+      }
       Option.ValueSet = (Index <= Value.Length());
     }
     else
@@ -205,6 +215,11 @@ bool __fastcall TOptions::DoFindSwitch(const UnicodeString Switch,
   bool Result = FindSwitch(Switch, Value, ParamsStart, ParamsCount, CaseSensitive, ValueSet);
   if (Result)
   {
+    int AParamsCount;
+    if (TryStrToInt(Value, AParamsCount) && (AParamsCount < ParamsCount))
+    {
+      ParamsCount = AParamsCount;
+    }
     if ((ParamsMax >= 0) && (ParamsCount > ParamsMax))
     {
       ParamsCount = ParamsMax;

+ 74 - 60
source/core/Script.cpp

@@ -16,7 +16,7 @@
 //---------------------------------------------------------------------------
 const wchar_t * ToggleNames[] = { L"off", L"on" };
 //---------------------------------------------------------------------------
-__fastcall TScriptProcParams::TScriptProcParams(UnicodeString ParamsStr)
+__fastcall TScriptProcParams::TScriptProcParams(const UnicodeString & FullCommand, const UnicodeString & ParamsStr)
 {
   int P = FSwitchMarks.Pos(L"/");
   DebugAssert(P > 0);
@@ -25,9 +25,11 @@ __fastcall TScriptProcParams::TScriptProcParams(UnicodeString ParamsStr)
     FSwitchMarks.Delete(P, 1);
   }
 
+  FFullCommand = FullCommand;
   FParamsStr = ParamsStr;
   UnicodeString Param;
-  while (CutToken(ParamsStr, Param))
+  UnicodeString AParamsStr = ParamsStr;
+  while (CutToken(AParamsStr, Param))
   {
     Add(Param);
   }
@@ -266,42 +268,35 @@ UnicodeString __fastcall TScriptCommands::ResolveCommand(const UnicodeString & C
 // decreased on exit by exception, leading to memory leak
 void __fastcall TScriptCommands::Execute(const UnicodeString & Command, const UnicodeString & Params)
 {
-  TScriptProcParams * Parameters = new TScriptProcParams(Params);
-  try
-  {
-    UnicodeString Matches;
-    int Index = FindCommand(this, Command, &Matches);
+  UnicodeString Matches;
+  int Index = FindCommand(this, Command, &Matches);
 
-    if (Index == -2)
-    {
-      throw Exception(FMTLOAD(SCRIPT_COMMAND_AMBIGUOUS, (Command, Matches)));
-    }
-    else if (Index < 0)
-    {
-      throw Exception(FMTLOAD(SCRIPT_COMMAND_UNKNOWN, (Command)));
-    }
+  if (Index == -2)
+  {
+    throw Exception(FMTLOAD(SCRIPT_COMMAND_AMBIGUOUS, (Command, Matches)));
+  }
+  else if (Index < 0)
+  {
+    throw Exception(FMTLOAD(SCRIPT_COMMAND_UNKNOWN, (Command)));
+  }
 
-    TScriptCommand * ScriptCommand = reinterpret_cast<TScriptCommand *>(Objects[Index]);
-    UnicodeString FullCommand = Strings[Index];
+  TScriptCommand * ScriptCommand = reinterpret_cast<TScriptCommand *>(Objects[Index]);
+  UnicodeString FullCommand = Strings[Index];
 
-    if (Parameters->ParamCount < ScriptCommand->MinParams)
-    {
-      throw Exception(FMTLOAD(SCRIPT_MISSING_PARAMS, (FullCommand)));
-    }
-    else if ((ScriptCommand->MaxParams >= 0) && (Parameters->ParamCount > ScriptCommand->MaxParams))
-    {
-      throw Exception(FMTLOAD(SCRIPT_TOO_MANY_PARAMS, (FullCommand)));
-    }
-    else
-    {
-      CheckParams(Parameters, ScriptCommand->Switches);
-
-      ScriptCommand->Proc(Parameters);
-    }
+  std::unique_ptr<TScriptProcParams> Parameters(new TScriptProcParams(FullCommand, Params));
+  if (Parameters->ParamCount < ScriptCommand->MinParams)
+  {
+    throw Exception(FMTLOAD(SCRIPT_MISSING_PARAMS, (FullCommand)));
   }
-  __finally
+  else if ((ScriptCommand->MaxParams >= 0) && (Parameters->ParamCount > ScriptCommand->MaxParams))
   {
-    delete Parameters;
+    throw Exception(FMTLOAD(SCRIPT_TOO_MANY_PARAMS, (FullCommand)));
+  }
+  else
+  {
+    CheckParams(Parameters.get(), ScriptCommand->Switches);
+
+    ScriptCommand->Proc(Parameters.get());
   }
 }
 //---------------------------------------------------------------------------
@@ -370,16 +365,16 @@ void __fastcall TScript::Init()
   FCommands->Register(L"ln", SCRIPT_LN_DESC, SCRIPT_LN_HELP, &LnProc, 2, 2, false);
   FCommands->Register(L"symlink", 0, SCRIPT_LN_HELP, &LnProc, 2, 2, false);
   FCommands->Register(L"mkdir", SCRIPT_MKDIR_DESC, SCRIPT_MKDIR_HELP, &MkDirProc, 1, 1, false);
-  FCommands->Register(L"get", SCRIPT_GET_DESC, SCRIPT_GET_HELP8, &GetProc, 1, -1, true);
-  FCommands->Register(L"recv", 0, SCRIPT_GET_HELP8, &GetProc, 1, -1, true);
-  FCommands->Register(L"mget", 0, SCRIPT_GET_HELP8, &GetProc, 1, -1, true);
-  FCommands->Register(L"put", SCRIPT_PUT_DESC, SCRIPT_PUT_HELP8, &PutProc, 1, -1, true);
-  FCommands->Register(L"send", 0, SCRIPT_PUT_HELP8, &PutProc, 1, -1, true);
-  FCommands->Register(L"mput", 0, SCRIPT_PUT_HELP8, &PutProc, 1, -1, true);
+  FCommands->Register(L"get", SCRIPT_GET_DESC, SCRIPT_GET_HELP8, &GetProc, 0, -1, true);
+  FCommands->Register(L"recv", 0, SCRIPT_GET_HELP8, &GetProc, 0, -1, true);
+  FCommands->Register(L"mget", 0, SCRIPT_GET_HELP8, &GetProc, 0, -1, true);
+  FCommands->Register(L"put", SCRIPT_PUT_DESC, SCRIPT_PUT_HELP8, &PutProc, 0, -1, true);
+  FCommands->Register(L"send", 0, SCRIPT_PUT_HELP8, &PutProc, 0, -1, true);
+  FCommands->Register(L"mput", 0, SCRIPT_PUT_HELP8, &PutProc, 0, -1, true);
   FCommands->Register(L"option", SCRIPT_OPTION_DESC, SCRIPT_OPTION_HELP7, &OptionProc, -1, 2, false);
   FCommands->Register(L"ascii", 0, SCRIPT_OPTION_HELP7, &AsciiProc, 0, 0, false);
   FCommands->Register(L"binary", 0, SCRIPT_OPTION_HELP7, &BinaryProc, 0, 0, false);
-  FCommands->Register(L"synchronize", SCRIPT_SYNCHRONIZE_DESC, SCRIPT_SYNCHRONIZE_HELP7, &SynchronizeProc, 1, 3, true);
+  FCommands->Register(L"synchronize", SCRIPT_SYNCHRONIZE_DESC, SCRIPT_SYNCHRONIZE_HELP7, &SynchronizeProc, 0, 3, true);
   FCommands->Register(L"keepuptodate", SCRIPT_KEEPUPTODATE_DESC, SCRIPT_KEEPUPTODATE_HELP5, &KeepUpToDateProc, 0, 2, true);
   // the echo command does not have switches actually, but it must handle dashes in its arguments
   FCommands->Register(L"echo", SCRIPT_ECHO_DESC, SCRIPT_ECHO_HELP, &EchoProc, -1, -1, true);
@@ -387,6 +382,14 @@ void __fastcall TScript::Init()
   FCommands->Register(L"checksum", SCRIPT_CHECKSUM_DESC, SCRIPT_CHECKSUM_HELP, &ChecksumProc, 2, 2, false);
 }
 //---------------------------------------------------------------------------
+void __fastcall TScript::RequireParams(TScriptProcParams * Parameters, int MinParams)
+{
+  if (Parameters->ParamCount < MinParams)
+  {
+    throw Exception(FMTLOAD(SCRIPT_MISSING_PARAMS, (Parameters->FullCommand)));
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TScript::CheckDefaultCopyParam()
 {
   if (FWarnNonDefaultCopyParam)
@@ -506,7 +509,7 @@ void __fastcall TScript::Command(UnicodeString Cmd)
           UnicodeString DummyLogCmd;
           if (DebugAlwaysTrue(CutToken(LogCmd, DummyLogCmd)))
           {
-            std::unique_ptr<TScriptProcParams> Parameters(new TScriptProcParams(LogCmd));
+            std::unique_ptr<TScriptProcParams> Parameters(new TScriptProcParams(FCommands->ResolveCommand(Cmd), LogCmd));
             Parameters->LogOptions(LogOption);
           }
         }
@@ -1067,6 +1070,13 @@ void __fastcall TScript::CopyParamParams(TCopyParamType & CopyParam, TScriptProc
   {
     CopyParam.NewerOnly = true;
   }
+
+  std::unique_ptr<TStrings> RawSettings(new TStringList());
+  if (Parameters->FindSwitch(RAWTRANSFERSETTINGS_SWICH, RawSettings.get()))
+  {
+    std::unique_ptr<TOptionsStorage> OptionsStorage(new TOptionsStorage(RawSettings.get(), false));
+    CopyParam.Load(OptionsStorage.get());
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TScript::ResetTransfer()
@@ -1426,13 +1436,18 @@ void __fastcall TScript::GetProc(TScriptProcParams * Parameters)
   ResetTransfer();
 
   bool Latest = Parameters->FindSwitch(L"latest");
+  CheckDefaultCopyParam();
+  TCopyParamType CopyParam = FCopyParam;
+  CopyParamParams(CopyParam, Parameters);
+  int Params = 0;
+  TransferParamParams(Params, Parameters);
+
+  RequireParams(Parameters, 1);
   int LastFileParam = (Parameters->ParamCount == 1 ? 1 : Parameters->ParamCount - 1);
   TStrings * FileList = CreateFileList(Parameters, 1, LastFileParam,
     (TFileListType)(fltQueryServer | fltMask | FLAGMASK(Latest, fltLatest)));
   try
   {
-    CheckDefaultCopyParam();
-    TCopyParamType CopyParam = FCopyParam;
 
     UnicodeString TargetDirectory;
     if (Parameters->ParamCount == 1)
@@ -1453,9 +1468,6 @@ void __fastcall TScript::GetProc(TScriptProcParams * Parameters)
       CheckMultiFilesToOne(FileList, Target, false);
     }
 
-    int Params = 0;
-    TransferParamParams(Params, Parameters);
-    CopyParamParams(CopyParam, Parameters);
     CheckParams(Parameters);
 
     FTerminal->CopyToLocal(FileList, TargetDirectory, &CopyParam, Params, NULL);
@@ -1472,15 +1484,19 @@ void __fastcall TScript::PutProc(TScriptProcParams * Parameters)
   ResetTransfer();
 
   bool Latest = Parameters->FindSwitch(L"latest");
+  CheckDefaultCopyParam();
+  TCopyParamType CopyParam = FCopyParam;
+  CopyParamParams(CopyParam, Parameters);
+  int Params = 0;
+  TransferParamParams(Params, Parameters);
+
+  RequireParams(Parameters, 1);
   int LastFileParam = (Parameters->ParamCount == 1 ? 1 : Parameters->ParamCount - 1);
   TStrings * FileList =
     CreateLocalFileList(
       Parameters, 1, LastFileParam, (TFileListType)(fltMask | FLAGMASK(Latest, fltLatest)));
   try
   {
-    CheckDefaultCopyParam();
-    TCopyParamType CopyParam = FCopyParam;
-
     UnicodeString TargetDirectory;
     if (Parameters->ParamCount == 1)
     {
@@ -1500,9 +1516,6 @@ void __fastcall TScript::PutProc(TScriptProcParams * Parameters)
       CheckMultiFilesToOne(FileList, Target, true);
     }
 
-    int Params = 0;
-    TransferParamParams(Params, Parameters);
-    CopyParamParams(CopyParam, Parameters);
     CheckParams(Parameters);
 
     FTerminal->CopyToRemote(FileList, TargetDirectory, &CopyParam, Params, NULL);
@@ -1882,6 +1895,11 @@ void __fastcall TScript::SynchronizeProc(TScriptProcParams * Parameters)
 
   static const wchar_t * ModeNames[] = { L"remote", L"local", L"both" };
 
+  CheckDefaultCopyParam();
+  TCopyParamType CopyParam = FCopyParam;
+  CopyParamParams(CopyParam, Parameters);
+
+  RequireParams(Parameters, 1);
   UnicodeString ModeName = Parameters->Param[1];
   DebugAssert(FSynchronizeMode < 0);
   FSynchronizeMode = TScriptCommands::FindCommand(ModeNames, LENOF(ModeNames), ModeName);
@@ -1898,10 +1916,6 @@ void __fastcall TScript::SynchronizeProc(TScriptProcParams * Parameters)
 
     SynchronizeDirectories(Parameters, LocalDirectory, RemoteDirectory, 2);
 
-    CheckDefaultCopyParam();
-    TCopyParamType CopyParam = FCopyParam;
-    CopyParamParams(CopyParam, Parameters);
-
     CheckDefaultSynchronizeParams();
     int SynchronizeParams = FSynchronizeParams | TTerminal::spNoConfirmation;
 
@@ -2051,6 +2065,10 @@ void __fastcall TScript::KeepUpToDateProc(TScriptProcParams * Parameters)
   CheckSession();
   ResetTransfer();
 
+  CheckDefaultCopyParam();
+  TCopyParamType CopyParam = FCopyParam;
+  CopyParamParams(CopyParam, Parameters);
+
   UnicodeString LocalDirectory;
   UnicodeString RemoteDirectory;
 
@@ -2066,10 +2084,6 @@ void __fastcall TScript::KeepUpToDateProc(TScriptProcParams * Parameters)
     SynchronizeParams |= TTerminal::spDelete;
   }
 
-  CheckDefaultCopyParam();
-  TCopyParamType CopyParam = FCopyParam;
-  CopyParamParams(CopyParam, Parameters);
-
   CheckParams(Parameters);
 
   PrintLine(LoadStr(SCRIPT_KEEPING_UP_TO_DATE));

+ 5 - 1
source/core/Script.h

@@ -37,12 +37,14 @@ class TScriptProcParams : public TOptions
 public:
   friend class TManagementScript;
 
-  __fastcall TScriptProcParams(UnicodeString ParamsStr);
+  __fastcall TScriptProcParams(const UnicodeString & FullCommand, const UnicodeString & ParamsStr);
 
   __property UnicodeString ParamsStr = { read = FParamsStr };
+  __property UnicodeString FullCommand = { read = FFullCommand };
 
 private:
   UnicodeString FParamsStr;
+  UnicodeString FFullCommand;
 };
 //---------------------------------------------------------------------------
 class TScript
@@ -62,6 +64,8 @@ public:
     const UnicodeString RemoteDirectory, const TCopyParamType & CopyParam,
     int SynchronizeParams, TSynchronizeChecklist ** Checklist);
 
+  static void __fastcall RequireParams(TScriptProcParams * Parameters, int MinParams);
+
   __property TScriptPrintEvent OnPrint = { read = FOnPrint, write = FOnPrint };
   __property TExtendedExceptionEvent OnShowExtendedException = { read = FOnShowExtendedException, write = FOnShowExtendedException };
   __property TSynchronizeDirectory OnTerminalSynchronizeDirectory = { read = FOnTerminalSynchronizeDirectory, write = FOnTerminalSynchronizeDirectory };

+ 3 - 11
source/core/SessionData.cpp

@@ -3402,17 +3402,9 @@ void __fastcall TSessionData::GenerateAssemblyCode(
 
   if (RawSettings->Count > 0)
   {
-    Head += RtfPara;
-
-    for (int Index = 0; Index < RawSettings->Count; Index++)
-    {
-      UnicodeString Name = RawSettings->Names[Index];
-      UnicodeString Value = RawSettings->ValueFromIndex[Index];
-      UnicodeString AddRawSettingsMethod =
-        RtfLibraryMethod(SessionOptionsClassName, L"AddRawSettings", false) +
-        FORMAT(L"(%s, %s)", (AssemblyString(Language, Name), AssemblyString(Language, Value)));
-      Head += RtfText(SessionOptionsVariableName + L".") + AddRawSettingsMethod + AssemblyStatementSeparator(Language) + RtfPara;
-    }
+    Head +=
+      RtfPara +
+      AssemblyAddRawSettings(Language, RawSettings.get(), SessionOptionsClassName, L"AddRawSettings");
   }
 
   Head += RtfPara;

+ 2 - 17
source/forms/GenerateUrl.cpp

@@ -329,13 +329,7 @@ UnicodeString __fastcall TGenerateUrlDialog::GenerateScript(UnicodeString & Scri
     {
       TransferCommandArgs += RtfSwitch(DELETE_SWITCH, TransferCommandLink);
     }
-    bool NoArgs;
-    TransferCommandArgs += FCopyParam.GenerateTransferCommandArgs(FCopyParamAttrs, TransferCommandLink, NoArgs);
-
-    if (NoArgs)
-    {
-      ScriptDescription += LoadStr(GENERATE_URL_COPY_PARAM_SCRIPT_REMAINING) + L"\n";
-    }
+    TransferCommandArgs += FCopyParam.GenerateTransferCommandArgs(FCopyParamAttrs, TransferCommandLink);
 
     AddSampleDescription(ScriptDescription);
 
@@ -527,23 +521,14 @@ UnicodeString __fastcall TGenerateUrlDialog::GenerateAssemblyCode(UnicodeString
   UnicodeString Code;
   if (FTransfer)
   {
-    bool NoCodeProperties;
-    UnicodeString CopyParamProperties =
-      FCopyParam.GenerateAssemblyCode(Language, FCopyParamAttrs, NoCodeProperties);
-
-    if (NoCodeProperties)
-    {
-      AssemblyDescription += LoadStr(GENERATE_URL_COPY_PARAM_CODE_REMAINING) + L"\n";
-    }
+    UnicodeString CopyParamProperties = FCopyParam.GenerateAssemblyCode(Language, FCopyParamAttrs);
 
     bool HasTransferOptions = !CopyParamProperties.IsEmpty();
     if (HasTransferOptions)
     {
       Code +=
         AssemblyCommentLine(Language, LoadStr(GENERATE_URL_COPY_PARAM)) +
-        AssemblyNewClassInstanceStart(Language, TransferOptionsClassName, false) +
         CopyParamProperties +
-        AssemblyNewClassInstanceEnd(Language, false) +
         RtfPara;
     }
 

+ 0 - 2
source/resource/TextsWin.h

@@ -571,11 +571,9 @@
 #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
 #define GENERATE_URL_YOUR_CODE  1967
-#define GENERATE_URL_COPY_PARAM_CODE_REMAINING 1968
 #define GENERATE_URL_COPY_PARAM 1969
 #define GENERATE_URL_TRANSFER_FILES 1970
 #define GENERATE_URL_FILE_SAMPLE 1971

+ 0 - 2
source/resource/TextsWin1.rc

@@ -576,11 +576,9 @@ BEGIN
         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"
         GENERATE_URL_YOUR_CODE, "Your code"
-        GENERATE_URL_COPY_PARAM_CODE_REMAINING, "Some configured transfer settings do not have an equivalent in .NET assembly API. Use the Session.AddRawConfiguration instead."
         GENERATE_URL_COPY_PARAM, "Set up transfer options"
         GENERATE_URL_TRANSFER_FILES, "Transfer files"
         GENERATE_URL_FILE_SAMPLE, "A sample file list is used only, consider using a file mask to select files for the transfer."