瀏覽代碼

Raw site settings editor

Source commit: caf055e335fef5e08a1685b4fb7a52986f3043cf
Martin Prikryl 6 年之前
父節點
當前提交
177f67ba48

+ 32 - 17
source/core/SessionData.cpp

@@ -116,7 +116,7 @@ TSessionData * __fastcall TSessionData::Clone()
   return Data.release();
 }
 //---------------------------------------------------------------------
-void __fastcall TSessionData::Default()
+void __fastcall TSessionData::DefaultSettings()
 {
   HostName = L"";
   PortNumber = SshPortNumber;
@@ -275,6 +275,11 @@ void __fastcall TSessionData::Default()
 
   CustomParam1 = L"";
   CustomParam2 = L"";
+}
+//---------------------------------------------------------------------
+void __fastcall TSessionData::Default()
+{
+  DefaultSettings();
 
   IsWorkspace = false;
   Link = L"";
@@ -1176,7 +1181,12 @@ void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
     WRITE_DATA(String, CustomParam2);
   }
 
-  SavePasswords(Storage, PuttyExport, DoNotEncryptPasswords);
+  // This is for collecting all keys for TSiteRawDialog::AddButtonClick.
+  // It should be enough to test for (Default == NULL),
+  // the DoNotEncryptPasswords and PuttyExport were added to limit a possible unintended impact.
+  bool SaveAll = (Default == NULL) && DoNotEncryptPasswords && !PuttyExport;
+
+  SavePasswords(Storage, PuttyExport, DoNotEncryptPasswords, SaveAll);
 }
 //---------------------------------------------------------------------
 TStrings * __fastcall TSessionData::SaveToOptions(const TSessionData * Default, bool SaveName)
@@ -1486,21 +1496,26 @@ void __fastcall TSessionData::ImportFromFilezilla(
 
 }
 //---------------------------------------------------------------------
-void __fastcall TSessionData::SavePasswords(THierarchicalStorage * Storage, bool PuttyExport, bool DoNotEncryptPasswords)
+void __fastcall TSessionData::SavePasswords(THierarchicalStorage * Storage, bool PuttyExport, bool DoNotEncryptPasswords, bool SaveAll)
 {
-  if (!Configuration->DisablePasswordStoring && !PuttyExport && !FPassword.IsEmpty())
+  if (!Configuration->DisablePasswordStoring && !PuttyExport && (!FPassword.IsEmpty() || SaveAll))
   {
-    // DoNotEncryptPasswords is set when called from GenerateOpenCommandArgs only
-    // and it never saves session password
-    DebugAssert(!DoNotEncryptPasswords);
-
-    Storage->WriteBinaryDataAsString(L"Password", StronglyRecryptPassword(FPassword, UserName+HostName));
+    if (DoNotEncryptPasswords)
+    {
+      Storage->WriteString(L"PasswordPlain", Password);
+      Storage->DeleteValue(L"Password");
+    }
+    else
+    {
+      Storage->WriteBinaryDataAsString(L"Password", StronglyRecryptPassword(FPassword, UserName+HostName));
+      Storage->DeleteValue(L"PasswordPlain");
+    }
   }
   else
   {
     Storage->DeleteValue(L"Password");
+    Storage->DeleteValue(L"PasswordPlain");
   }
-  Storage->DeleteValue(L"PasswordPlain");
 
   if (PuttyExport)
   {
@@ -1511,7 +1526,7 @@ void __fastcall TSessionData::SavePasswords(THierarchicalStorage * Storage, bool
   {
     if (DoNotEncryptPasswords)
     {
-      if (!FProxyPassword.IsEmpty())
+      if (!FProxyPassword.IsEmpty() || SaveAll)
       {
         Storage->WriteString(L"ProxyPassword", ProxyPassword);
       }
@@ -1524,7 +1539,7 @@ void __fastcall TSessionData::SavePasswords(THierarchicalStorage * Storage, bool
     else
     {
       // save password encrypted
-      if (!FProxyPassword.IsEmpty())
+      if (!FProxyPassword.IsEmpty() || SaveAll)
       {
         Storage->WriteBinaryDataAsString(L"ProxyPasswordEnc", StronglyRecryptPassword(FProxyPassword, ProxyUsername+ProxyHost));
       }
@@ -1537,7 +1552,7 @@ void __fastcall TSessionData::SavePasswords(THierarchicalStorage * Storage, bool
 
     if (DoNotEncryptPasswords)
     {
-      if (!FTunnelPassword.IsEmpty())
+      if (!FTunnelPassword.IsEmpty() || SaveAll)
       {
         Storage->WriteString(L"TunnelPasswordPlain", TunnelPassword);
       }
@@ -1548,7 +1563,7 @@ void __fastcall TSessionData::SavePasswords(THierarchicalStorage * Storage, bool
     }
     else
     {
-      if (!Configuration->DisablePasswordStoring && !FTunnelPassword.IsEmpty())
+      if (!Configuration->DisablePasswordStoring && (!FTunnelPassword.IsEmpty() || SaveAll))
       {
         Storage->WriteBinaryDataAsString(L"TunnelPassword", StronglyRecryptPassword(FTunnelPassword, TunnelUserName+TunnelHostName));
       }
@@ -1560,7 +1575,7 @@ void __fastcall TSessionData::SavePasswords(THierarchicalStorage * Storage, bool
 
     if (DoNotEncryptPasswords)
     {
-      if (!FEncryptKey.IsEmpty())
+      if (!FEncryptKey.IsEmpty() || SaveAll)
       {
         Storage->WriteString(L"EncryptKeyPlain", EncryptKey);
       }
@@ -1572,7 +1587,7 @@ void __fastcall TSessionData::SavePasswords(THierarchicalStorage * Storage, bool
     }
     else
     {
-      if (!FEncryptKey.IsEmpty())
+      if (!FEncryptKey.IsEmpty() || SaveAll)
       {
         Storage->WriteBinaryDataAsString(L"EncryptKey", StronglyRecryptPassword(FEncryptKey, UserName+HostName));
       }
@@ -1664,7 +1679,7 @@ void __fastcall TSessionData::SaveRecryptedPasswords(THierarchicalStorage * Stor
     {
       RecryptPasswords();
 
-      SavePasswords(Storage, false, false);
+      SavePasswords(Storage, false, false, false);
     }
     __finally
     {

+ 4 - 3
source/core/SessionData.h

@@ -403,7 +403,7 @@ private:
   void __fastcall SetEncryptKey(UnicodeString value);
 
   TDateTime __fastcall GetTimeoutDT();
-  void __fastcall SavePasswords(THierarchicalStorage * Storage, bool PuttyExport, bool DoNotEncryptPasswords);
+  void __fastcall SavePasswords(THierarchicalStorage * Storage, bool PuttyExport, bool DoNotEncryptPasswords, bool SaveAll);
   UnicodeString __fastcall GetLocalName();
   UnicodeString __fastcall GetFolderName();
   void __fastcall Modify();
@@ -444,8 +444,6 @@ private:
   void __fastcall AddAssemblyProperty(
     UnicodeString & Result, TAssemblyLanguage Language,
     const UnicodeString & Name, bool Value);
-  TStrings * __fastcall SaveToOptions(const TSessionData * Default, bool SaveName);
-  void __fastcall ApplyRawSettings(TStrings * RawSettings);
   TStrings * __fastcall GetRawSettingsForUrl();
   void __fastcall DoCopyData(TSessionData * SourceData, bool NoRecrypt);
   template<class AlgoT>
@@ -460,8 +458,10 @@ public:
   virtual __fastcall ~TSessionData();
   TSessionData * __fastcall Clone();
   void __fastcall Default();
+  void __fastcall DefaultSettings();
   void __fastcall NonPersistant();
   void __fastcall Load(THierarchicalStorage * Storage, bool PuttyImport);
+  void __fastcall ApplyRawSettings(TStrings * RawSettings);
   void __fastcall ApplyRawSettings(THierarchicalStorage * Storage);
   void __fastcall ImportFromFilezilla(_di_IXMLNode Node, const UnicodeString & Path, _di_IXMLNode SettingsNode);
   void __fastcall Save(THierarchicalStorage * Storage, bool PuttyExport,
@@ -483,6 +483,7 @@ public:
   bool __fastcall ParseUrl(UnicodeString Url, TOptions * Options,
     TStoredSessionList * StoredSessions, bool & DefaultsOnly,
     UnicodeString * FileName, bool * AProtocolDefined, UnicodeString * MaskedUrl, int Flags);
+  TStrings * __fastcall SaveToOptions(const TSessionData * Default, bool SaveName);
   void __fastcall ConfigureTunnel(int PortNumber);
   void __fastcall RollbackTunnel();
   void __fastcall ExpandEnvironmentVariables();

+ 162 - 0
source/forms/Custom.cpp

@@ -1443,3 +1443,165 @@ void __fastcall DoUsageStatisticsDialog()
   std::unique_ptr<TUsageStatisticsDialog> Dialog(new TUsageStatisticsDialog());
   Dialog->Execute();
 }
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+class TSiteRawDialog : public TCustomDialog
+{
+public:
+  __fastcall TSiteRawDialog();
+
+  bool __fastcall Execute(TSessionData * Data);
+
+protected:
+//  virtual void __fastcall DoChange(bool & CanSubmit);
+
+private:
+  TMemo * SettingsMemo;
+  TButton * AdddButton;
+
+  void __fastcall AddButtonClick(TObject * Sender);
+  void __fastcall SettingsMemoKeyDown(TObject * Sender, WORD & Key, TShiftState Shift);
+
+  void DeleteNames(TStrings * Names, TStrings * Options);
+};
+//---------------------------------------------------------------------------
+__fastcall TSiteRawDialog::TSiteRawDialog() :
+  TCustomDialog(HELP_SITE_RAW)
+{
+  Caption = LoadStr(SITE_RAW_CAPTION);
+  Width = ScaleByTextHeight(this, 400);
+
+  SettingsMemo = new TMemo(this);
+  SettingsMemo->Height = ScaleByTextHeight(this, 300);
+  SettingsMemo->OnKeyDown = SettingsMemoKeyDown;
+  AddEdit(SettingsMemo, NULL);
+
+  AdddButton = new TButton(this);
+  AdddButton->Caption = LoadStr(SITE_RAW_ADD);
+  AdddButton->Width = OKButton->Width;
+  AdddButton->OnClick = AddButtonClick;
+  AddDialogButton(AdddButton);
+}
+//---------------------------------------------------------------------------
+bool __fastcall TSiteRawDialog::Execute(TSessionData * Data)
+{
+  std::unique_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
+  std::unique_ptr<TSessionData> RawData(new TSessionData(L""));
+  RawData->Assign(Data);
+  // SFTP-only is not reflected by the protocol prefix, we have to use rawsettings for that
+  if (RawData->FSProtocol != fsSFTPonly)
+  {
+    RawData->FSProtocol = FactoryDefaults->FSProtocol;
+  }
+  RawData->HostName = FactoryDefaults->HostName;
+  RawData->PortNumber = FactoryDefaults->PortNumber;
+  RawData->UserName = FactoryDefaults->UserName;
+  RawData->Password = FactoryDefaults->Password;
+  RawData->Ftps = FactoryDefaults->Ftps;
+
+  std::unique_ptr<TStrings> Options(RawData->SaveToOptions(FactoryDefaults.get(), false));
+
+  SettingsMemo->Lines = Options.get();
+
+  bool Result = TCustomDialog::Execute();
+  if (Result)
+  {
+    std::unique_ptr<TSessionData> BackupData(new TSessionData(L""));
+    BackupData->Assign(Data);
+    Data->DefaultSettings();
+
+    Data->FSProtocol = BackupData->FSProtocol;
+    Data->HostName = BackupData->HostName;
+    Data->PortNumber = BackupData->PortNumber;
+    Data->UserName = BackupData->UserName;
+    Data->Password = BackupData->Password;
+    Data->Ftps = BackupData->Ftps;
+
+    Data->ApplyRawSettings(SettingsMemo->Lines);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TSiteRawDialog::SettingsMemoKeyDown(TObject * Sender, WORD & Key, TShiftState Shift)
+{
+  MemoKeyDown(Sender, Key, Shift);
+}
+//---------------------------------------------------------------------------
+void __fastcall TSiteRawDialog::AddButtonClick(TObject *)
+{
+  std::unique_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
+  std::unique_ptr<TSessionData> BasicData(new TSessionData(L""));
+  BasicData->FSProtocol = TFSProtocol(FactoryDefaults->FSProtocol + 1);
+  UnicodeString RandomAppendix(L"_");
+  BasicData->HostName = FactoryDefaults->HostName + RandomAppendix;
+  BasicData->Ftps = TFtps(FactoryDefaults->Ftps + 1);
+  BasicData->PortNumber = DefaultPort(BasicData->FSProtocol, BasicData->Ftps) + 1;
+  BasicData->UserName = FactoryDefaults->UserName + RandomAppendix;
+  BasicData->Password = FactoryDefaults->Password + RandomAppendix;
+
+  std::unique_ptr<TStrings> BasicOptions(BasicData->SaveToOptions(FactoryDefaults.get(), false));
+
+  std::unique_ptr<TStrings> AllOptions(FactoryDefaults->SaveToOptions(NULL, false));
+
+  std::unique_ptr<TStrings> Names(CreateSortedStringList());
+  for (int Index = 0; Index < AllOptions->Count; Index++)
+  {
+    Names->Add(AllOptions->Names[Index]);
+  }
+  DeleteNames(Names.get(), BasicOptions.get());
+  DeleteNames(Names.get(), SettingsMemo->Lines);
+
+  std::unique_ptr<TCustomDialog> AddDialog(new TCustomDialog(HelpKeyword));
+  AddDialog->Caption = LoadStr(SITE_RAW_ADD_CAPTION);
+  TComboBox * AddComboBox = new TComboBox(AddDialog.get());
+  AddComboBox->Style = csDropDownList;
+  AddComboBox->DropDownCount = Max(AddComboBox->DropDownCount, 16);
+  AddDialog->AddComboBox(AddComboBox, CreateLabel(LoadStr(SITE_RAW_ADD_LABEL)), Names.get(), true);
+  AddComboBox->ItemIndex = 0;
+  if (AddDialog->Execute())
+  {
+    UnicodeString Name = AddComboBox->Items->Strings[AddComboBox->ItemIndex];
+    UnicodeString Value = AllOptions->Values[Name];
+    UnicodeString NameAndSeparator = Name + SettingsMemo->Lines->NameValueSeparator;
+    int Start = (SettingsMemo->Lines->Text + NameAndSeparator).Length();
+    SettingsMemo->Lines->Add(NameAndSeparator + Value);
+    SettingsMemo->SetFocus();
+    SettingsMemo->SelStart = Start;
+    SettingsMemo->SelLength = Value.Length();
+  }
+}
+//---------------------------------------------------------------------------
+void TSiteRawDialog::DeleteNames(TStrings * Names, TStrings * Options)
+{
+  for (int Index = 0; Index < Options->Count; Index++)
+  {
+    UnicodeString Name = Options->Names[Index];
+    if (!Name.IsEmpty())
+    {
+      int I = Names->IndexOf(Name);
+      if (I >= 0)
+      {
+        Names->Delete(I);
+      }
+    }
+  }
+}
+//---------------------------------------------------------------------------
+/*void __fastcall TUsageStatisticsDialog::DoChange(bool & CanSubmit)
+{
+  TCustomDialog::DoChange(CanSubmit);
+  UnicodeString Text = Configuration->Usage->Serialize(L"\n", FilterEdit->Text);
+  bool NoUsage = Text.IsEmpty();
+  ClipboardButton->Enabled = !NoUsage;
+  if (NoUsage)
+  {
+    Text = LoadStr(USAGE_DATA_NONE2);
+  }
+  UsageMemo->Lines->Text = Text;
+} */
+//---------------------------------------------------------------------------
+void __fastcall DoSiteRawDialog(TSessionData * Data)
+{
+  std::unique_ptr<TSiteRawDialog> Dialog(new TSiteRawDialog());
+  Dialog->Execute(Data);
+}

+ 13 - 2
source/forms/Login.cpp

@@ -1182,6 +1182,10 @@ void __fastcall TLoginDialog::ActionListUpdate(TBasicAction * BasicAction,
   {
     SessionAdvancedAction->Enabled = Editable;
   }
+  else if (Action == SessionRawAction)
+  {
+    SessionRawAction->Enabled = Editable;
+  }
   else if (Action == SaveAsSessionAction)
   {
     // Save as is needed for new site only when !SupportsSplitButton()
@@ -2773,7 +2777,7 @@ void __fastcall TLoginDialog::PersistNewSiteIfNeeded()
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TLoginDialog::SessionAdvancedActionExecute(TObject * /*Sender*/)
+void __fastcall TLoginDialog::SessionAdvancedActionExecute(TObject * Sender)
 {
   // If we ever allow showing advanced settings, while read-only,
   // we must make sure that FSessionData actually holds the advanced settings,
@@ -2789,7 +2793,14 @@ void __fastcall TLoginDialog::SessionAdvancedActionExecute(TObject * /*Sender*/)
     ParseHostName();
 
     SaveSession(FSessionData);
-    DoSiteAdvancedDialog(FSessionData);
+    if (Sender == SessionAdvancedAction)
+    {
+      DoSiteAdvancedDialog(FSessionData);
+    }
+    else
+    {
+      DoSiteRawDialog(FSessionData);
+    }
     // Needed only for Note.
     // The only other property visible on Login dialog that Advanced site dialog
     // can change is protocol (between fsSFTP and fsSFTPonly),

+ 8 - 0
source/forms/Login.dfm

@@ -682,6 +682,11 @@ object LoginDialog: TLoginDialog
       Caption = 'Close and Do Not Show Automatically Again'
       OnExecute = NeverShowAgainActionExecute
     end
+    object SessionRawAction: TAction
+      Category = 'Session'
+      Caption = 'Edit &Raw Settings...'
+      OnExecute = SessionAdvancedActionExecute
+    end
   end
   object ToolsPopupMenu: TPopupMenu
     Left = 144
@@ -1387,6 +1392,9 @@ object LoginDialog: TLoginDialog
       Action = SessionAdvancedAction
       Default = True
     end
+    object EditRawSettings1: TMenuItem
+      Action = SessionRawAction
+    end
     object TransferSettingsRule1: TMenuItem
       Action = CopyParamRuleAction
     end

+ 2 - 0
source/forms/Login.h

@@ -211,6 +211,8 @@ __published:
   TMenuItem *MenuItem20;
   TAction *CloseAction;
   TAction *NeverShowAgainAction;
+  TAction *SessionRawAction;
+  TMenuItem *EditRawSettings1;
   void __fastcall DataChange(TObject *Sender);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall SessionTreeDblClick(TObject *Sender);

+ 1 - 0
source/resource/HelpWin.h

@@ -65,5 +65,6 @@
 #define HELP_DD_TARGET_UNKNOWN       "ui_pref_dragdrop#fake_file"
 #define HELP_FILE_COLORS             "ui_file_color"
 #define HELP_AUTOMATIC_UPDATE        "updates#automatic_upgrade"
+#define HELP_SITE_RAW                "ui_login_raw"
 
 #endif // TextsWin

+ 4 - 0
source/resource/TextsWin.h

@@ -620,6 +620,10 @@
 #define UPDATES_DONATE_HTML     6020
 #define EDITOR_NEW              6021
 #define PREFERENCES_STATISTICS_CAPTION 6022
+#define SITE_RAW_CAPTION        6023
+#define SITE_RAW_ADD            6024
+#define SITE_RAW_ADD_CAPTION    6025
+#define SITE_RAW_ADD_LABEL      6026
 
 // 2xxx is reserved for TextsFileZilla.h
 

+ 4 - 0
source/resource/TextsWin1.rc

@@ -625,6 +625,10 @@ BEGIN
         UPDATES_DONATE_HTML, "To enable automatic updates, please <a href=\"%DONATE_URL%\">donate to WinSCP development</a> or %GET_IMG% WinSCP from <a href=\"%STORE_URL%\">Microsoft Store</a>."
         EDITOR_NEW, "New"
         PREFERENCES_STATISTICS_CAPTION, "Statistics"
+        SITE_RAW_CAPTION, "Raw Site Settings"
+        SITE_RAW_ADD, "&Add..."
+        SITE_RAW_ADD_CAPTION, "Add Raw Site Setting"
+        SITE_RAW_ADD_LABEL, "&Site Setting:"
 
         WIN_VARIABLE_STRINGS, "WIN_VARIABLE"
         WINSCP_COPYRIGHT, "Copyright © 2000-2019 Martin Prikryl"

+ 1 - 0
source/windows/WinInterface.h

@@ -150,6 +150,7 @@ bool __fastcall DoCustomCommandOptionsDialog(
   const TCustomCommandType * Command, TStrings * CustomCommandOptions, TShortCut * ShortCut, unsigned int Flags,
   TCustomCommand * CustomCommandForOptions, const UnicodeString & Site, const TShortCuts * ShortCuts);
 void __fastcall DoUsageStatisticsDialog();
+void __fastcall DoSiteRawDialog(TSessionData * Data);
 
 // windows\UserInterface.cpp
 bool __fastcall DoMasterPasswordDialog();