1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00

Session URL can contain any raw session settings using connection parameter. New custom command pattern !E can generate such URL for use in WinSCP extensions.

Source commit: 7c9de42181088d8aaa9a96abaa420534f9e71a27
This commit is contained in:
Martin Prikryl
2018-05-16 13:10:51 +00:00
parent a0cc394164
commit 3267334917
11 changed files with 115 additions and 39 deletions

View File

@@ -210,10 +210,15 @@ namespace WinSCP
string parameter = CutToChar(ref parameters, ';');
string parameterName = CutToChar(ref parameter, '=');
parameter = UriUnescape(parameter);
const string RawSettingsPrefix = "x-";
if (parameterName.Equals("fingerprint", StringComparison.OrdinalIgnoreCase))
{
SshHostKeyFingerprint = parameter;
}
else if (parameterName.StartsWith(RawSettingsPrefix, StringComparison.OrdinalIgnoreCase))
{
AddRawSettings(UriUnescape(parameterName.Substring(RawSettingsPrefix.Length)), parameter);
}
else
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Unsupported connection parameter {0}", parameterName), "url");

View File

@@ -1,5 +1,6 @@
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@@ -25,6 +26,8 @@ using System.Runtime.InteropServices;
[assembly: CLSCompliant(true)]
[assembly: InternalsVisibleTo("Tests")]
namespace WinSCP
{
internal static class AssemblyConstants

View File

@@ -1185,6 +1185,7 @@ int __fastcall TFileCustomCommand::PatternLen(const UnicodeString & Command, int
switch (PatternCmd)
{
case L's':
case L'e':
case L'@':
case L'u':
case L'p':
@@ -1208,6 +1209,13 @@ bool __fastcall TFileCustomCommand::PatternReplacement(
// keep consistent with TSessionLog::OpenLogFile
if (SameText(Pattern, L"!s"))
{
if (FData.SessionData != NULL)
{
Replacement = FData.SessionData->GenerateSessionUrl(sufSession);
}
}
else if (SameText(Pattern, L"!e"))
{
if (FData.SessionData != NULL)
{

View File

@@ -64,6 +64,7 @@ const wchar_t UrlParamSeparator = L';';
const wchar_t UrlParamValueSeparator = L'=';
const UnicodeString UrlHostKeyParamName(L"fingerprint");
const UnicodeString UrlSaveParamName(L"save");
const UnicodeString UrlRawSettingsParamNamePrefix(L"x-");
const UnicodeString PassphraseOption(L"passphrase");
const UnicodeString RawSettingsOption(L"rawsettings");
const UnicodeString S3HostName(S3LibDefaultHostName());
@@ -1918,6 +1919,8 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
UnicodeString ConnectionParams = UserInfo;
UserInfo = UserInfoWithoutConnectionParams;
std::unique_ptr<TStrings> RawSettings(new TStringList());
while (!ConnectionParams.IsEmpty())
{
UnicodeString ConnectionParam = CutToChar(ConnectionParams, UrlParamSeparator, false);
@@ -1927,6 +1930,17 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
HostKey = DecodeUrlChars(ConnectionParam);
FOverrideCachedHostKey = false;
}
else if (StartsText(UrlRawSettingsParamNamePrefix, ConnectionParamName))
{
UnicodeString Name = RightStr(ConnectionParamName, ConnectionParamName.Length() - UrlRawSettingsParamNamePrefix.Length());
Name = DecodeUrlChars(Name);
RawSettings->Values[Name] = DecodeUrlChars(ConnectionParam);
}
}
if (RawSettings->Count > 0) // optimization
{
ApplyRawSettings(RawSettings.get());
}
bool HasPassword = (UserInfo.Pos(L':') > 0);
@@ -2072,22 +2086,10 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
}
if (Options->FindSwitch(RawSettingsOption))
{
TStrings * RawSettings = NULL;
TOptionsStorage * OptionsStorage = NULL;
try
std::unique_ptr<TStrings> RawSettings(new TStringList());
if (Options->FindSwitch(RawSettingsOption, RawSettings.get()))
{
RawSettings = new TStringList();
if (Options->FindSwitch(RawSettingsOption, RawSettings))
{
OptionsStorage = new TOptionsStorage(RawSettings, false);
ApplyRawSettings(OptionsStorage);
}
}
__finally
{
delete RawSettings;
delete OptionsStorage;
ApplyRawSettings(RawSettings.get());
}
}
}
@@ -2095,6 +2097,12 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
return true;
}
//---------------------------------------------------------------------
void __fastcall TSessionData::ApplyRawSettings(TStrings * RawSettings)
{
std::unique_ptr<TOptionsStorage> OptionsStorage(new TOptionsStorage(RawSettings, false));
ApplyRawSettings(OptionsStorage.get());
}
//---------------------------------------------------------------------
void __fastcall TSessionData::ApplyRawSettings(THierarchicalStorage * Storage)
{
bool Dummy;
@@ -2900,6 +2908,27 @@ UnicodeString __fastcall EscapeIPv6Literal(const UnicodeString & IP)
return L"[" + IP + L"]";
}
//---------------------------------------------------------------------
TStrings * __fastcall TSessionData::GetRawSettingsForUrl()
{
std::unique_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
std::unique_ptr<TSessionData> SessionData(Clone());
SessionData->FSProtocol = FactoryDefaults->FSProtocol;
SessionData->HostName = FactoryDefaults->HostName;
SessionData->PortNumber = FactoryDefaults->PortNumber;
SessionData->UserName = FactoryDefaults->UserName;
SessionData->Password = FactoryDefaults->Password;
SessionData->Ftps = FactoryDefaults->Ftps;
SessionData->HostKey = FactoryDefaults->HostKey;
SessionData->CopyNonCoreData(FactoryDefaults.get());
return SessionData->SaveToOptions(FactoryDefaults.get());
}
//---------------------------------------------------------------------
bool __fastcall TSessionData::HasRawSettingsForUrl()
{
std::unique_ptr<TStrings> RawSettings(GetRawSettingsForUrl());
return (RawSettings->Count > 0);
}
//---------------------------------------------------------------------
UnicodeString __fastcall TSessionData::GenerateSessionUrl(unsigned int Flags)
{
UnicodeString Url;
@@ -2931,6 +2960,18 @@ UnicodeString __fastcall TSessionData::GenerateSessionUrl(unsigned int Flags)
UnicodeString(UrlParamValueSeparator) + S;
}
if (FLAGSET(Flags, sufRawSettings))
{
std::unique_ptr<TStrings> RawSettings(GetRawSettingsForUrl());
for (int Index = 0; Index < RawSettings->Count; Index++)
{
Url +=
UnicodeString(UrlParamSeparator) +
UrlRawSettingsParamNamePrefix + EncodeUrlString(LowerCase(RawSettings->Names[Index])) +
UnicodeString(UrlParamValueSeparator) + EncodeUrlString(RawSettings->ValueFromIndex[Index]);
}
}
Url += L"@";
}

View File

@@ -46,7 +46,9 @@ enum TSessionUrlFlags
sufUserName = 0x02,
sufPassword = 0x04,
sufHostKey = 0x08,
sufComplete = sufUserName | sufPassword | sufHostKey,
sufRawSettings = 0x10,
sufSession = sufUserName | sufPassword | sufHostKey,
sufComplete = sufSession | sufRawSettings,
sufOpen = sufUserName | sufPassword
};
//---------------------------------------------------------------------------
@@ -431,6 +433,8 @@ private:
UnicodeString & Result, TAssemblyLanguage Language,
const UnicodeString & Name, bool Value);
TStrings * __fastcall SaveToOptions(const TSessionData * Default);
void __fastcall ApplyRawSettings(TStrings * RawSettings);
TStrings * __fastcall GetRawSettingsForUrl();
template<class AlgoT>
void __fastcall SetAlgoList(AlgoT * List, const AlgoT * DefaultList, const UnicodeString * Names,
int Count, AlgoT WarnAlgo, UnicodeString value);
@@ -473,6 +477,8 @@ public:
bool __fastcall IsSameSite(const TSessionData * Default);
bool __fastcall IsInFolderOrWorkspace(UnicodeString Name);
UnicodeString __fastcall GenerateSessionUrl(unsigned int Flags);
bool __fastcall TSessionData::HasRawSettingsForUrl();
UnicodeString __fastcall GenerateOpenCommandArgs(bool Rtf);
void __fastcall GenerateAssemblyCode(TAssemblyLanguage Language, UnicodeString & Head, UnicodeString & Tail, int & Indent);
void __fastcall LookupLastFingerprint();

View File

@@ -47,7 +47,7 @@ __fastcall TCustomCommandDialog::TCustomCommandDialog(TComponent* Owner,
FCustomCommandList = CustomCommandList;
FMode = Mode;
FOnValidate = OnValidate;
HintLabel(HintText, LoadStr(CUSTOM_COMMAND_PATTERNS_HINT5));
HintLabel(HintText, LoadStr(CUSTOM_COMMAND_PATTERNS_HINT6));
int CaptionRes;
switch (FMode)

View File

@@ -181,7 +181,8 @@ UnicodeString __fastcall TGenerateUrlDialog::GenerateUrl(UnicodeString Path)
FLAGMASK(WinSCPSpecificCheck->Checked, sufSpecific) |
FLAGMASK(UserNameCheck->Enabled && UserNameCheck->Checked, sufUserName) |
FLAGMASK(PasswordCheck->Enabled && PasswordCheck->Checked, sufPassword) |
FLAGMASK(HostKeyCheck->Enabled && HostKeyCheck->Checked, sufHostKey));
FLAGMASK(HostKeyCheck->Enabled && HostKeyCheck->Checked, sufHostKey) |
FLAGMASK(RawSettingsCheck->Enabled && RawSettingsCheck->Checked, sufRawSettings));
if ((RemoteDirectoryCheck->Enabled && RemoteDirectoryCheck->Checked) ||
IsFileUrl())
@@ -663,6 +664,7 @@ void __fastcall TGenerateUrlDialog::UpdateControls()
EnableControl(HostKeyCheck, UserNameIncluded && !FData->HostKey.IsEmpty());
EnableControl(RemoteDirectoryCheck, !FData->RemoteDirectory.IsEmpty() && !IsFileUrl());
EnableControl(SaveExtensionCheck, !IsFileUrl());
EnableControl(RawSettingsCheck, UserNameIncluded && FData->HasRawSettingsForUrl());
UnicodeString Result;

View File

@@ -35,7 +35,7 @@ object GenerateUrlDialog: TGenerateUrlDialog
Tag = 1
Left = 11
Top = 8
Width = 216
Width = 144
Height = 17
Caption = '&User name'
TabOrder = 0
@@ -43,29 +43,29 @@ object GenerateUrlDialog: TGenerateUrlDialog
end
object HostKeyCheck: TCheckBox
Tag = 4
Left = 11
Top = 31
Width = 216
Left = 161
Top = 8
Width = 144
Height = 17
Caption = 'SSH &host Key'
TabOrder = 1
TabOrder = 3
OnClick = ControlChange
end
object WinSCPSpecificCheck: TCheckBox
Tag = 16
Left = 11
Top = 54
Width = 216
Left = 161
Top = 31
Width = 144
Height = 17
Caption = '&WinSCP-specific'
TabOrder = 2
TabOrder = 4
OnClick = ControlChange
end
object SaveExtensionCheck: TCheckBox
Tag = 32
Left = 235
Left = 161
Top = 54
Width = 216
Width = 144
Height = 17
Caption = '&Save extension'
TabOrder = 5
@@ -73,23 +73,33 @@ object GenerateUrlDialog: TGenerateUrlDialog
end
object RemoteDirectoryCheck: TCheckBox
Tag = 8
Left = 235
Top = 31
Width = 216
Left = 11
Top = 54
Width = 144
Height = 17
Caption = 'Initial &directory'
TabOrder = 4
TabOrder = 2
OnClick = ControlChange
end
object PasswordCheck: TCheckBox
Tag = 2
Left = 235
Top = 8
Width = 216
Left = 11
Top = 31
Width = 144
Height = 17
HelpType = htKeyword
Caption = '&Password'
TabOrder = 3
TabOrder = 1
OnClick = ControlChange
end
object RawSettingsCheck: TCheckBox
Tag = 64
Left = 311
Top = 8
Width = 144
Height = 17
Caption = '&Advanced settings'
TabOrder = 6
OnClick = ControlChange
end
end

View File

@@ -39,6 +39,7 @@ __published:
TComboBox *AssemblyLanguageCombo;
TLabel *ScriptDescriptionLabel;
TLabel *AssemblyDescriptionLabel;
TCheckBox *RawSettingsCheck;
void __fastcall ControlChange(TObject *Sender);
void __fastcall ClipboardButtonClick(TObject *Sender);
void __fastcall HelpButtonClick(TObject *Sender);

View File

@@ -200,7 +200,7 @@
#define EXTERNAL_EDITOR_HINT 1488
#define MASK_HINT2 1489
#define PATH_MASK_HINT2 1490
#define CUSTOM_COMMAND_PATTERNS_HINT5 1491
#define CUSTOM_COMMAND_PATTERNS_HINT6 1491
#define CLOSED_ON_QUEUE_EMPTY 1492
#define DIRECTORY_READING_CANCELLED 1493
#define SYNC_DIR_BROWSE_TOGGLE 1494

View File

@@ -203,7 +203,7 @@ BEGIN
EXTERNAL_EDITOR_HINT, "Edit (external)|Edit selected file(s) using external editor '%s'"
MASK_HINT2, "* matches any number of characters.\n? matches exactly one character.\n[abc] matches one character from the set.\n[a-z] matches one character from the range.\nExample: *.html; photo??.png"
PATH_MASK_HINT2, "Mask can be extended with path mask.\nExample: */public_html/*.html"
CUSTOM_COMMAND_PATTERNS_HINT5, "Patterns:\n!! expands to exclamation mark\n! expands to file name\n!& expands to list of selected files (quoted, space-delimited)\n!/ expands to current remote path\n!S expands to current session URL\n!@ expands to current session hostname\n!U expands to current session username\n!P expands to current session password\n!# expands to current session port number\n!N expands to current session name\n!?prompt[\\]?default! expands to user-entered value with given prompt and default (optional \\ avoids escaping)\n!`command` expands to output of local command\n \nLocal command patterns:\n!^! expands to file name from local panel\n \nExample:\ngrep \"!?Pattern:?!\" !&"
CUSTOM_COMMAND_PATTERNS_HINT6, "Patterns:\n!! expands to exclamation mark\n! expands to file name\n!& expands to list of selected files (quoted, space-delimited)\n!/ expands to current remote path\n!S expands to current session URL\n!E expands to serialized connection data of current session\n!@ expands to current session hostname\n!U expands to current session username\n!P expands to current session password\n!# expands to current session port number\n!N expands to current session name\n!?prompt[\\]?default! expands to user-entered value with given prompt and default (optional \\ avoids escaping)\n!`command` expands to output of local command\n \nLocal command patterns:\n!^! expands to file name from local panel\n \nExample:\ngrep \"!?Pattern:?!\" !&"
CLOSED_ON_QUEUE_EMPTY, "All background transfers were finished. Connection was closed."
DIRECTORY_READING_CANCELLED, "Reading of remote directory was cancelled."
SYNC_DIR_BROWSE_TOGGLE, "Synchronized browsing was turned %s.|on|off"