Custom.cpp 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897
  1. //---------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <Dialogs.hpp>
  5. //---------------------------------------------------------------------
  6. #include <Common.h>
  7. #include <CustomWinConfiguration.h>
  8. #include <WinInterface.h>
  9. #include <VCLCommon.h>
  10. #include <TextsWin.h>
  11. #include <HelpWin.h>
  12. #include <CoreMain.h>
  13. #include <PasTools.hpp>
  14. #include <ProgParams.h>
  15. #include <Tools.h>
  16. #include <GUITools.h>
  17. #include <PuttyTools.h>
  18. #include <HistoryComboBox.hpp>
  19. #include <Math.hpp>
  20. #include <System.Character.hpp>
  21. #include "Custom.h"
  22. //---------------------------------------------------------------------
  23. #pragma link "PasswordEdit"
  24. #pragma resource "*.dfm"
  25. //---------------------------------------------------------------------
  26. const int GroupBoxBorderWidth = 1;
  27. //---------------------------------------------------------------------
  28. __fastcall TCustomDialog::TCustomDialog(UnicodeString AHelpKeyword)
  29. : TForm(GetFormOwner())
  30. {
  31. UseSystemSettings(this);
  32. FControlPadding = ScaleByTextHeight(this, 6);
  33. FPos = ScaleByTextHeight(this, 8);
  34. FPrePos = FPos;
  35. FHorizontalMargin = ScaleByTextHeight(this, 8);
  36. FIndent = FHorizontalMargin;
  37. FGroupBox = NULL;
  38. HelpKeyword = AHelpKeyword;
  39. TBorderIcons BI = BorderIcons;
  40. if (HelpKeyword.IsEmpty())
  41. {
  42. BI >> biHelp;
  43. OKButton->Left = CancelButton->Left;
  44. CancelButton->Left = HelpButton->Left;
  45. HelpButton->Visible = false;
  46. }
  47. else
  48. {
  49. BI << biHelp;
  50. }
  51. BorderIcons = BI;
  52. }
  53. //---------------------------------------------------------------------
  54. bool __fastcall TCustomDialog::Execute()
  55. {
  56. Changed();
  57. return (ShowModal() == DefaultResult(this));
  58. }
  59. //---------------------------------------------------------------------
  60. void __fastcall TCustomDialog::DoChange(bool & /*CanSubmit*/)
  61. {
  62. // noop
  63. }
  64. //---------------------------------------------------------------------
  65. void __fastcall TCustomDialog::Changed()
  66. {
  67. bool CanSubmit = true;
  68. DoChange(CanSubmit);
  69. EnableControl(OKButton, CanSubmit);
  70. }
  71. //---------------------------------------------------------------------
  72. void __fastcall TCustomDialog::Change(TObject * /*Sender*/)
  73. {
  74. Changed();
  75. }
  76. //---------------------------------------------------------------------------
  77. void __fastcall TCustomDialog::DoHelp()
  78. {
  79. FormHelp(this);
  80. }
  81. //---------------------------------------------------------------------------
  82. void __fastcall TCustomDialog::HelpButtonClick(TObject * /*Sender*/)
  83. {
  84. DoHelp();
  85. }
  86. //---------------------------------------------------------------------------
  87. void __fastcall TCustomDialog::DoShow()
  88. {
  89. OKButton->TabOrder = FCount;
  90. CancelButton->TabOrder = static_cast<short>(FCount + 1);
  91. HelpButton->TabOrder = static_cast<short>(FCount + 2);
  92. Changed();
  93. TForm::DoShow();
  94. }
  95. //---------------------------------------------------------------------------
  96. void __fastcall TCustomDialog::DoValidate()
  97. {
  98. // noop
  99. }
  100. //---------------------------------------------------------------------------
  101. bool __fastcall TCustomDialog::CloseQuery()
  102. {
  103. if (ModalResult == DefaultResult(this))
  104. {
  105. DoValidate();
  106. }
  107. return TForm::CloseQuery();
  108. }
  109. //---------------------------------------------------------------------------
  110. void __fastcall TCustomDialog::RemoveCancelButton()
  111. {
  112. CancelButton->Visible = false;
  113. OKButton->Left = CancelButton->Left;
  114. OKButton->Cancel = true;
  115. DebugAssert(OKButton->Width == CancelButton->Width);
  116. DebugAssert(OKButton->Top == CancelButton->Top);
  117. }
  118. //---------------------------------------------------------------------------
  119. void __fastcall TCustomDialog::AddDialogButton(TButton * Button)
  120. {
  121. Button->Parent = this;
  122. Button->Top = OKButton->Top;
  123. Button->Left = FHorizontalMargin;
  124. Button->Height = OKButton->Height;
  125. AddWinControl(Button);
  126. }
  127. //---------------------------------------------------------------------------
  128. void __fastcall TCustomDialog::AddImage(const UnicodeString & ImageName)
  129. {
  130. TImage * Image = new TImage(this);
  131. Image->Name = L"Image";
  132. Image->Parent = GetDefaultParent();
  133. LoadDialogImage(Image, ImageName);
  134. Image->SetBounds(FIndent, FPos + ScaleByTextHeight(this, 3), Image->Picture->Width, Image->Picture->Height);
  135. FIndent += Image->Width + ScaleByTextHeight(this, 12);
  136. }
  137. //---------------------------------------------------------------------------
  138. int __fastcall TCustomDialog::GetMaxControlWidth(TControl * Control)
  139. {
  140. return GetDefaultParent()->ClientWidth - Control->Left - FHorizontalMargin - (FGroupBox != NULL ? GroupBoxBorderWidth : 0);
  141. }
  142. //---------------------------------------------------------------------------
  143. TWinControl * __fastcall TCustomDialog::GetDefaultParent()
  144. {
  145. return (FGroupBox != NULL) ? FGroupBox : static_cast<TWinControl *>(this);
  146. }
  147. //---------------------------------------------------------------------------
  148. void __fastcall TCustomDialog::AdjustHeight(TControl * Control)
  149. {
  150. FPos = Control->Top + Control->Height + FControlPadding;
  151. int Delta = (FPos - FPrePos);
  152. ClientHeight = ClientHeight + Delta;
  153. if (FGroupBox != NULL)
  154. {
  155. FGroupBox->Height = FGroupBox->Height + Delta;
  156. }
  157. FPrePos = FPos;
  158. }
  159. //---------------------------------------------------------------------------
  160. void __fastcall TCustomDialog::AddWinControl(TWinControl * Control)
  161. {
  162. Control->TabOrder = FCount;
  163. FCount++;
  164. }
  165. //---------------------------------------------------------------------------
  166. TCheckBox * __fastcall TCustomDialog::CreateAndAddCheckBox(const UnicodeString & Caption)
  167. {
  168. TCheckBox * CheckBox = new TCheckBox(this);
  169. CheckBox->Caption = Caption;
  170. AddButtonControl(CheckBox);
  171. return CheckBox;
  172. }
  173. //---------------------------------------------------------------------------
  174. TLabel * __fastcall TCustomDialog::CreateLabel(UnicodeString Label)
  175. {
  176. TLabel * Result = ::CreateLabel(this);
  177. Result->Caption = Label;
  178. return Result;
  179. }
  180. //---------------------------------------------------------------------------
  181. void __fastcall TCustomDialog::AddEditLikeControl(TWinControl * Edit, TLabel * Label, bool OneLine)
  182. {
  183. Edit->Parent = GetDefaultParent();
  184. // this updates Height property to real value
  185. Edit->HandleNeeded();
  186. if (Label != NULL)
  187. {
  188. Label->Parent = GetDefaultParent();
  189. Label->Left = FIndent;
  190. if (OneLine)
  191. {
  192. DebugAssert(Edit->Height > Label->Height);
  193. Label->Top = FPos + ((Edit->Height - Label->Height) / 2);
  194. }
  195. else
  196. {
  197. Label->Top = FPos;
  198. FPos += Label->Height + ScaleByTextHeight(this, 3);
  199. }
  200. }
  201. Edit->Top = FPos;
  202. if (OneLine)
  203. {
  204. Edit->Left = GetDefaultParent()->ClientWidth - FHorizontalMargin - Edit->Width;
  205. }
  206. else
  207. {
  208. Edit->Left = FIndent;
  209. Edit->Width = GetMaxControlWidth(Edit);
  210. }
  211. AdjustHeight(Edit);
  212. if (Label != NULL)
  213. {
  214. if (Label->FocusControl == NULL)
  215. {
  216. Label->FocusControl = Edit;
  217. }
  218. else
  219. {
  220. DebugAssert(Label->FocusControl == Edit);
  221. }
  222. }
  223. AddWinControl(Edit);
  224. }
  225. //---------------------------------------------------------------------------
  226. void __fastcall TCustomDialog::AddEdit(TCustomEdit * Edit, TLabel * Label, bool OneLine)
  227. {
  228. AddEditLikeControl(Edit, Label, OneLine);
  229. TEdit * PublicEdit = reinterpret_cast<TEdit *>(Edit);
  230. if (PublicEdit->OnChange == NULL)
  231. {
  232. PublicEdit->OnChange = Change;
  233. }
  234. }
  235. //---------------------------------------------------------------------------
  236. void __fastcall TCustomDialog::SetUpComboBox(TCustomCombo * Combo, TStrings * Items, bool OneLine)
  237. {
  238. if (Items != NULL)
  239. {
  240. Combo->Items = Items;
  241. }
  242. if (OneLine)
  243. {
  244. int Width = 0;
  245. for (int Index = 0; Index < Combo->Items->Count; Index++)
  246. {
  247. Width = Max(Width, Combo->Canvas->TextWidth(Combo->Items->Strings[Index]));
  248. }
  249. Width += ScaleByTextHeight(Combo, 4 + 16 + 14);
  250. Width = Max(Width, HelpButton->Width);
  251. Combo->Width = Width;
  252. Combo->Left = GetDefaultParent()->ClientWidth - FHorizontalMargin - Width;
  253. }
  254. TComboBox * PublicCombo = reinterpret_cast<TComboBox *>(Combo);
  255. if (PublicCombo->OnChange == NULL)
  256. {
  257. PublicCombo->OnChange = Change;
  258. }
  259. }
  260. //---------------------------------------------------------------------------
  261. void __fastcall TCustomDialog::AddComboBox(TCustomCombo * Combo, TLabel * Label, TStrings * Items, bool OneLine)
  262. {
  263. AddEditLikeControl(Combo, Label, OneLine);
  264. SetUpComboBox(Combo, Items, OneLine);
  265. }
  266. //---------------------------------------------------------------------------
  267. void __fastcall TCustomDialog::AddShortCutComboBox(TComboBox * Combo, TLabel * Label, const TShortCuts & ShortCuts)
  268. {
  269. AddEditLikeControl(Combo, Label, true);
  270. InitializeShortCutCombo(Combo, ShortCuts);
  271. SetUpComboBox(Combo, NULL, true);
  272. }
  273. //---------------------------------------------------------------------------
  274. void __fastcall TCustomDialog::ScaleButtonControl(TButtonControl * Control)
  275. {
  276. // this updates Height property to real value
  277. Control->HandleNeeded();
  278. // buttons do not scale with text on their own
  279. Control->Height = ScaleByTextHeight(Control, Control->Height);
  280. }
  281. //---------------------------------------------------------------------------
  282. void __fastcall TCustomDialog::AddButtonControl(TButtonControl * Control)
  283. {
  284. Control->Parent = GetDefaultParent();
  285. Control->Left = FIndent + ScaleByTextHeight(this, 2);
  286. Control->Top = FPos;
  287. Control->Width = GetMaxControlWidth(Control);
  288. ScaleButtonControl(Control);
  289. AdjustHeight(Control);
  290. AddWinControl(Control);
  291. TCheckBox * PublicControl = reinterpret_cast<TCheckBox *>(Control);
  292. if (PublicControl->OnClick == NULL)
  293. {
  294. PublicControl->OnClick = Change;
  295. }
  296. }
  297. //---------------------------------------------------------------------------
  298. void TCustomDialog::AddButtonNextToEdit(TButton * Button, TWinControl * Edit)
  299. {
  300. Button->Parent = GetDefaultParent();
  301. Button->Width = HelpButton->Width;
  302. Button->Left = GetDefaultParent()->ClientWidth - Button->Width - HorizontalMargin;
  303. Edit->Width = Button->Left - Edit->Left - ScaleByTextHeight(this, 6);
  304. Button->Top = Edit->Top - ScaleByTextHeight(this, 1);
  305. ScaleButtonControl(Button);
  306. AddWinControl(Button);
  307. }
  308. //---------------------------------------------------------------------------
  309. void __fastcall TCustomDialog::AddText(TLabel * Label)
  310. {
  311. Label->Parent = GetDefaultParent();
  312. DebugAssert(Label->AutoSize);
  313. Label->WordWrap = true;
  314. Label->Left = FIndent;
  315. Label->Width = GetMaxControlWidth(Label);
  316. Label->Top = FPos;
  317. Label->ShowAccelChar = false;
  318. AutoSizeLabel(Label);
  319. AdjustHeight(Label);
  320. }
  321. //---------------------------------------------------------------------------
  322. void __fastcall TCustomDialog::AddText(TStaticText * Label)
  323. {
  324. Label->Parent = GetDefaultParent();
  325. DebugAssert(Label->AutoSize);
  326. Label->Left = FIndent;
  327. Label->Top = FPos;
  328. Label->ShowAccelChar = false;
  329. AdjustHeight(Label);
  330. AddWinControl(Label);
  331. }
  332. //---------------------------------------------------------------------------
  333. void __fastcall TCustomDialog::AddSeparator()
  334. {
  335. TBevel * Bevel = new TBevel(this);
  336. Bevel->Parent = GetDefaultParent();
  337. Bevel->Left = FIndent;
  338. Bevel->Top = FPos;
  339. Bevel->Height = 2;
  340. Bevel->Width = GetMaxControlWidth(Bevel);
  341. AdjustHeight(Bevel);
  342. }
  343. //---------------------------------------------------------------------------
  344. void __fastcall TCustomDialog::StartGroup(const UnicodeString & Caption)
  345. {
  346. if (FGroupBox != NULL)
  347. {
  348. FIndent = FGroupBox->Left;
  349. FPos = FGroupBox->Top + FGroupBox->Height + FControlPadding;
  350. FPrePos = FPos;
  351. FGroupBox = NULL;
  352. }
  353. TGroupBox * GroupBox = new TGroupBox(this);
  354. GroupBox->Parent = this;
  355. GroupBox->Caption = Caption;
  356. GroupBox->Left = FIndent;
  357. GroupBox->Top = FPos;
  358. GroupBox->Height = ScaleByTextHeight(GroupBox, 26);
  359. GroupBox->Width = GetMaxControlWidth(GroupBox);
  360. AdjustHeight(GroupBox);
  361. AddWinControl(GroupBox);
  362. // but if the first control is oneline box, then we should roll back a bit
  363. FPos = ScaleByTextHeight(this, 22);
  364. FPrePos = FPos;
  365. FIndent = FHorizontalMargin + GroupBoxBorderWidth;
  366. FGroupBox = GroupBox;
  367. }
  368. //---------------------------------------------------------------------------
  369. //---------------------------------------------------------------------------
  370. class TSaveSessionDialog : public TCustomDialog
  371. {
  372. public:
  373. __fastcall TSaveSessionDialog(TComponent* AOwner);
  374. void __fastcall Init(bool CanSavePassword, bool NotRecommendedSavingPassword,
  375. TStrings * AdditionalFolders);
  376. bool __fastcall Execute(UnicodeString & SessionName, bool & SavePassword,
  377. bool & CreateShortcut, const UnicodeString & OriginalSessionName);
  378. protected:
  379. virtual void __fastcall DoValidate();
  380. virtual void __fastcall DoChange(bool & CanSubmit);
  381. private:
  382. UnicodeString FOriginalSessionName;
  383. TEdit * SessionNameEdit;
  384. TComboBox * FolderCombo;
  385. TCheckBox * SavePasswordCheck;
  386. TCheckBox * CreateShortcutCheck;
  387. UnicodeString FRootFolder;
  388. UnicodeString __fastcall GetSessionName();
  389. };
  390. //---------------------------------------------------------------------------
  391. // Need to have an Owner argument for SafeFormCreate
  392. __fastcall TSaveSessionDialog::TSaveSessionDialog(TComponent* /*AOwner*/) :
  393. TCustomDialog(HELP_SESSION_SAVE)
  394. {
  395. }
  396. //---------------------------------------------------------------------------
  397. void __fastcall TSaveSessionDialog::Init(bool CanSavePassword,
  398. bool NotRecommendedSavingPassword, TStrings * AdditionalFolders)
  399. {
  400. Caption = LoadStr(SAVE_SESSION_CAPTION);
  401. SessionNameEdit = new TEdit(this);
  402. AddEdit(SessionNameEdit, CreateLabel(LoadStr(SAVE_SESSION_PROMPT)));
  403. FRootFolder = LoadStr(SAVE_SESSION_ROOT_FOLDER2);
  404. std::unique_ptr<TStringList> Folders(new TStringList());
  405. if (AdditionalFolders != NULL)
  406. {
  407. Folders->AddStrings(AdditionalFolders);
  408. }
  409. for (int Index = 0; Index < StoredSessions->Count; Index++)
  410. {
  411. TSessionData * Data = StoredSessions->Sessions[Index];
  412. if (!Data->Special && !Data->IsWorkspace)
  413. {
  414. UnicodeString Folder = Data->FolderName;
  415. if (!Folder.IsEmpty() && Folders->IndexOf(Folder) < 0)
  416. {
  417. Folders->Add(Folder);
  418. }
  419. }
  420. }
  421. DebugAssert(!Folders->CaseSensitive);
  422. Folders->Sort();
  423. FolderCombo = new TUIStateAwareComboBox(this);
  424. AddComboBox(FolderCombo, CreateLabel(LoadStr(SAVE_SESSION_FOLDER)));
  425. FolderCombo->DropDownCount = Max(FolderCombo->DropDownCount, 16);
  426. FolderCombo->Items->Add(FRootFolder);
  427. FolderCombo->Items->AddStrings(Folders.get());
  428. SavePasswordCheck = CreateAndAddCheckBox(
  429. LoadStr(NotRecommendedSavingPassword ? SAVE_SESSION_PASSWORD :
  430. (CustomWinConfiguration->UseMasterPassword ? SAVE_SESSION_PASSWORD_MASTER : SAVE_SESSION_PASSWORD_RECOMMENDED)));
  431. CreateShortcutCheck = CreateAndAddCheckBox(LoadStr(SAVE_SITE_WORKSPACE_SHORTCUT));
  432. EnableControl(SavePasswordCheck, CanSavePassword);
  433. }
  434. //---------------------------------------------------------------------------
  435. bool __fastcall TSaveSessionDialog::Execute(
  436. UnicodeString & SessionName, bool & SavePassword, bool & CreateShortcut,
  437. const UnicodeString & OriginalSessionName)
  438. {
  439. FOriginalSessionName = OriginalSessionName;
  440. SessionNameEdit->Text = TSessionData::ExtractLocalName(SessionName);
  441. UnicodeString Folder = TSessionData::ExtractFolderName(SessionName);
  442. if (Folder.IsEmpty())
  443. {
  444. FolderCombo->Text = FRootFolder;
  445. }
  446. else
  447. {
  448. FolderCombo->Text = Folder;
  449. }
  450. SavePasswordCheck->Checked = SavePassword;
  451. CreateShortcutCheck->Checked = CreateShortcut;
  452. bool Result = TCustomDialog::Execute();
  453. if (Result)
  454. {
  455. SessionName = GetSessionName();
  456. SavePassword = SavePasswordCheck->Checked;
  457. CreateShortcut = CreateShortcutCheck->Checked;
  458. }
  459. return Result;
  460. }
  461. //---------------------------------------------------------------------------
  462. UnicodeString __fastcall TSaveSessionDialog::GetSessionName()
  463. {
  464. UnicodeString Folder;
  465. if (FolderCombo->Text != FRootFolder)
  466. {
  467. Folder = FolderCombo->Text;
  468. }
  469. return TSessionData::ComposePath(Folder, SessionNameEdit->Text);
  470. }
  471. //---------------------------------------------------------------------------
  472. void __fastcall TSaveSessionDialog::DoValidate()
  473. {
  474. TSessionData::ValidateName(SessionNameEdit->Text);
  475. SessionNameValidate(GetSessionName(), FOriginalSessionName);
  476. UnicodeString Folder = TSessionData::ExtractFolderName(GetSessionName());
  477. if (!Folder.IsEmpty() && StoredSessions->IsWorkspace(Folder))
  478. {
  479. throw Exception(FMTLOAD(WORKSPACE_NOT_FOLDER, (Folder)));
  480. }
  481. if (SavePasswordCheck->Enabled && SavePasswordCheck->Checked &&
  482. CustomWinConfiguration->UseMasterPassword)
  483. {
  484. CustomWinConfiguration->AskForMasterPasswordIfNotSet();
  485. }
  486. TCustomDialog::DoValidate();
  487. }
  488. //---------------------------------------------------------------------------
  489. void __fastcall TSaveSessionDialog::DoChange(bool & CanSubmit)
  490. {
  491. CanSubmit = !SessionNameEdit->Text.IsEmpty();
  492. TCustomDialog::DoChange(CanSubmit);
  493. }
  494. //---------------------------------------------------------------------------
  495. TSessionData * __fastcall DoSaveSession(TSessionData * SessionData,
  496. TSessionData * OriginalSession, bool ForceDialog,
  497. TStrings * AdditionalFolders)
  498. {
  499. bool SavePassword = false;
  500. bool * PSavePassword;
  501. bool NotRecommendedSavingPassword =
  502. !CustomWinConfiguration->UseMasterPassword &&
  503. !SameText(SessionData->UserName, AnonymousUserName);
  504. if (Configuration->DisablePasswordStoring ||
  505. !SessionData->HasAnySessionPassword())
  506. {
  507. PSavePassword = NULL;
  508. }
  509. else
  510. {
  511. PSavePassword = &SavePassword;
  512. SavePassword =
  513. ((OriginalSession != NULL) && OriginalSession->HasAnySessionPassword()) ||
  514. !NotRecommendedSavingPassword;
  515. }
  516. UnicodeString SessionName = SessionData->SessionName;
  517. bool Result;
  518. bool CreateShortcut = false;
  519. if (!ForceDialog && ((PSavePassword == NULL) || SavePassword))
  520. {
  521. // This is probably here to ask before session is started saving.
  522. // Otherwise we would ask implicitly, when saving passwords, but at that moment,
  523. // part of the site is already saved and when the user cancel the prompt it's too late.
  524. CustomWinConfiguration->AskForMasterPasswordIfNotSetAndNeededToPersistSessionData(SessionData);
  525. Result = true;
  526. }
  527. else
  528. {
  529. // This can be a standalone dialog when used with save URL (from GetLoginData)
  530. TSaveSessionDialog * Dialog = SafeFormCreate<TSaveSessionDialog>();
  531. try
  532. {
  533. Dialog->Init((PSavePassword != NULL), NotRecommendedSavingPassword, AdditionalFolders);
  534. Result = Dialog->Execute(SessionName, SavePassword, CreateShortcut, SessionData->Name);
  535. }
  536. __finally
  537. {
  538. delete Dialog;
  539. }
  540. }
  541. TSessionData * NewSession = NULL;
  542. if (Result)
  543. {
  544. if ((PSavePassword != NULL) && !SavePassword)
  545. {
  546. SessionData->ClearSessionPasswords();
  547. }
  548. NewSession =
  549. StoredSessions->NewSession(SessionName, SessionData);
  550. // modified only, explicit
  551. StoredSessions->Save(false, true);
  552. if (!SessionData->HostKey.IsEmpty())
  553. {
  554. SessionData->CacheHostKeyIfNotCached();
  555. }
  556. if (CreateShortcut)
  557. {
  558. TOperationVisualizer Visualizer;
  559. UnicodeString AdditionalParams =
  560. TProgramParams::FormatSwitch(DESKTOP_SWITCH) + L" " +
  561. TProgramParams::FormatSwitch(UPLOAD_IF_ANY_SWITCH);
  562. CreateDesktopSessionShortCut(SessionName, L"", AdditionalParams, -1, SITE_ICON);
  563. }
  564. }
  565. return NewSession;
  566. }
  567. //---------------------------------------------------------------------------
  568. void __fastcall SessionNameValidate(const UnicodeString & Text,
  569. const UnicodeString & OriginalName)
  570. {
  571. TSessionData::ValidatePath(Text);
  572. DebugAssert(StoredSessions);
  573. TSessionData * Data = (TSessionData *)StoredSessions->FindByName(Text);
  574. if (Data && Data->Special)
  575. {
  576. MessageDialog(FMTLOAD(CANNOT_OVERWRITE_SPECIAL_SESSION, (Text)),
  577. qtError, qaOK, HELP_NONE);
  578. Abort();
  579. }
  580. else if ((Data != NULL) && !Data->IsSameName(OriginalName) &&
  581. MessageDialog(MainInstructions(FMTLOAD(CONFIRM_OVERWRITE_SESSION, (Text))),
  582. qtConfirmation, qaYes | qaNo, HELP_SESSION_SAVE_OVERWRITE) != qaYes)
  583. {
  584. Abort();
  585. }
  586. }
  587. //---------------------------------------------------------------------------
  588. //---------------------------------------------------------------------------
  589. class TSaveWorkspaceDialog : public TCustomDialog
  590. {
  591. public:
  592. __fastcall TSaveWorkspaceDialog(bool CanSavePasswords,
  593. bool NotRecommendedSavingPasswords);
  594. bool __fastcall Execute(
  595. UnicodeString & WorkspaceName, bool & SavePasswords, bool & CreateShortcut,
  596. bool & EnableAutoSave);
  597. protected:
  598. virtual void __fastcall DoValidate();
  599. virtual void __fastcall DoChange(bool & CanSubmit);
  600. private:
  601. TComboBox * WorkspaceNameCombo;
  602. TCheckBox * SavePasswordsCheck;
  603. TCheckBox * CreateShortcutCheck;
  604. TCheckBox * EnableAutoSaveCheck;
  605. };
  606. //---------------------------------------------------------------------------
  607. __fastcall TSaveWorkspaceDialog::TSaveWorkspaceDialog(
  608. bool CanSavePasswords, bool NotRecommendedSavingPasswords) :
  609. TCustomDialog(HELP_WORKSPACE_SAVE)
  610. {
  611. Caption = LoadStr(SAVE_WORKSPACE_CAPTION);
  612. WorkspaceNameCombo = new TUIStateAwareComboBox(this);
  613. WorkspaceNameCombo->AutoComplete = false;
  614. AddComboBox(WorkspaceNameCombo, CreateLabel(LoadStr(SAVE_WORKSPACE_PROMPT)));
  615. WorkspaceNameCombo->DropDownCount = Max(WorkspaceNameCombo->DropDownCount, 16);
  616. std::unique_ptr<TStrings> Workspaces(StoredSessions->GetWorkspaces());
  617. WorkspaceNameCombo->Items->AddStrings(Workspaces.get());
  618. SavePasswordsCheck = CreateAndAddCheckBox(
  619. LoadStr(NotRecommendedSavingPasswords ? SAVE_WORKSPACE_PASSWORDS :
  620. (CustomWinConfiguration->UseMasterPassword ?
  621. SAVE_WORKSPACE_PASSWORDS_MASTER : SAVE_WORKSPACE_PASSWORDS_RECOMMENDED)));
  622. EnableControl(SavePasswordsCheck, CanSavePasswords);
  623. CreateShortcutCheck = CreateAndAddCheckBox(LoadStr(SAVE_SITE_WORKSPACE_SHORTCUT));
  624. EnableAutoSaveCheck = CreateAndAddCheckBox(LoadStr(SAVE_WORKSPACE_AUTO));
  625. }
  626. //---------------------------------------------------------------------------
  627. bool __fastcall TSaveWorkspaceDialog::Execute(
  628. UnicodeString & WorkspaceName, bool & SavePasswords, bool & CreateShortcut,
  629. bool & EnableAutoSave)
  630. {
  631. WorkspaceNameCombo->Text = WorkspaceName;
  632. SavePasswordsCheck->Checked = SavePasswords;
  633. CreateShortcutCheck->Checked = CreateShortcut;
  634. EnableAutoSaveCheck->Checked = EnableAutoSave;
  635. bool Result = TCustomDialog::Execute();
  636. if (Result)
  637. {
  638. WorkspaceName = WorkspaceNameCombo->Text;
  639. SavePasswords = SavePasswordsCheck->Checked;
  640. CreateShortcut = CreateShortcutCheck->Checked;
  641. EnableAutoSave = EnableAutoSaveCheck->Checked;
  642. }
  643. return Result;
  644. }
  645. //---------------------------------------------------------------------------
  646. void __fastcall TSaveWorkspaceDialog::DoValidate()
  647. {
  648. TSessionData::ValidateName(WorkspaceNameCombo->Text);
  649. if (StoredSessions->IsFolder(WorkspaceNameCombo->Text))
  650. {
  651. throw Exception(FMTLOAD(FOLDER_NOT_WORKSPACE, (WorkspaceNameCombo->Text)));
  652. }
  653. if (SavePasswordsCheck->Enabled && SavePasswordsCheck->Checked &&
  654. CustomWinConfiguration->UseMasterPassword)
  655. {
  656. CustomWinConfiguration->AskForMasterPasswordIfNotSet();
  657. }
  658. TCustomDialog::DoValidate();
  659. }
  660. //---------------------------------------------------------------------------
  661. void __fastcall TSaveWorkspaceDialog::DoChange(bool & CanSubmit)
  662. {
  663. CanSubmit = !WorkspaceNameCombo->Text.IsEmpty();
  664. TCustomDialog::DoChange(CanSubmit);
  665. }
  666. //---------------------------------------------------------------------------
  667. bool __fastcall DoSaveWorkspaceDialog(UnicodeString & WorkspaceName,
  668. bool * SavePasswords, bool NotRecommendedSavingPasswords,
  669. bool & CreateShortcut, bool & EnableAutoSave)
  670. {
  671. std::unique_ptr<TSaveWorkspaceDialog> Dialog(
  672. new TSaveWorkspaceDialog((SavePasswords != NULL), NotRecommendedSavingPasswords));
  673. bool Dummy = false;
  674. if (SavePasswords == NULL)
  675. {
  676. SavePasswords = &Dummy;
  677. }
  678. return
  679. Dialog->Execute(
  680. WorkspaceName, *SavePasswords, CreateShortcut, EnableAutoSave);
  681. }
  682. //---------------------------------------------------------------------------
  683. //---------------------------------------------------------------------------
  684. class TShortCutDialog : public TCustomDialog
  685. {
  686. public:
  687. __fastcall TShortCutDialog(const TShortCuts & ShortCuts, UnicodeString HelpKeyword);
  688. bool __fastcall Execute(TShortCut & ShortCut);
  689. private:
  690. TComboBox * ShortCutCombo;
  691. };
  692. //---------------------------------------------------------------------------
  693. __fastcall TShortCutDialog::TShortCutDialog(const TShortCuts & ShortCuts, UnicodeString HelpKeyword) :
  694. TCustomDialog(HelpKeyword)
  695. {
  696. Caption = LoadStr(SHORTCUT_CAPTION);
  697. ShortCutCombo = new TUIStateAwareComboBox(this);
  698. AddShortCutComboBox(ShortCutCombo, CreateLabel(LoadStr(SHORTCUT_LABEL)), ShortCuts);
  699. }
  700. //---------------------------------------------------------------------------
  701. bool __fastcall TShortCutDialog::Execute(TShortCut & ShortCut)
  702. {
  703. SetShortCutCombo(ShortCutCombo, ShortCut);
  704. bool Result = TCustomDialog::Execute();
  705. if (Result)
  706. {
  707. ShortCut = GetShortCutCombo(ShortCutCombo);
  708. }
  709. return Result;
  710. }
  711. //---------------------------------------------------------------------------
  712. bool __fastcall DoShortCutDialog(TShortCut & ShortCut,
  713. const TShortCuts & ShortCuts, UnicodeString HelpKeyword)
  714. {
  715. bool Result;
  716. TShortCutDialog * Dialog = new TShortCutDialog(ShortCuts, HelpKeyword);
  717. try
  718. {
  719. Result = Dialog->Execute(ShortCut);
  720. }
  721. __finally
  722. {
  723. delete Dialog;
  724. }
  725. return Result;
  726. }
  727. //---------------------------------------------------------------------------
  728. //---------------------------------------------------------------------------
  729. class TRemoteMoveDialog : public TCustomDialog
  730. {
  731. public:
  732. __fastcall TRemoteMoveDialog(bool Multi, TDirectoryExistsEvent OnDirectoryExists);
  733. bool __fastcall Execute(UnicodeString & Target, UnicodeString & FileMask);
  734. protected:
  735. DYNAMIC void __fastcall DoShow();
  736. virtual void __fastcall DoValidate();
  737. UnicodeString __fastcall GetFileMask();
  738. private:
  739. THistoryComboBox * Combo;
  740. bool FMulti;
  741. TDirectoryExistsEvent FOnDirectoryExists;
  742. };
  743. //---------------------------------------------------------------------------
  744. __fastcall TRemoteMoveDialog::TRemoteMoveDialog(bool Multi, TDirectoryExistsEvent OnDirectoryExists) :
  745. TCustomDialog(HELP_REMOTE_MOVE)
  746. {
  747. Caption = LoadStr(REMOTE_MOVE_TITLE);
  748. // The same as TRemoteTransferDialog
  749. ClientWidth = ScaleByTextHeight(this, 466);
  750. FMulti = Multi;
  751. FOnDirectoryExists = OnDirectoryExists;
  752. AddImage(L"Move L to R");
  753. Combo = new THistoryComboBox(this);
  754. Combo->AutoComplete = false;
  755. AddComboBox(Combo, CreateLabel(LoadStr(REMOTE_TRANSFER_PROMPT2)));
  756. }
  757. //---------------------------------------------------------------------------
  758. bool __fastcall TRemoteMoveDialog::Execute(UnicodeString & Target, UnicodeString & FileMask)
  759. {
  760. Combo->Items = CustomWinConfiguration->History[L"RemoteTarget"];
  761. Combo->Text = UnixIncludeTrailingBackslash(Target) + FileMask;
  762. bool Result = TCustomDialog::Execute();
  763. if (Result)
  764. {
  765. Target = UnixExtractFilePath(Combo->Text);
  766. FileMask = GetFileMask();
  767. Combo->SaveToHistory();
  768. CustomWinConfiguration->History[L"RemoteTarget"] = Combo->Items;
  769. }
  770. return Result;
  771. }
  772. //---------------------------------------------------------------------------
  773. UnicodeString __fastcall TRemoteMoveDialog::GetFileMask()
  774. {
  775. return UnixExtractFileName(Combo->Text);
  776. }
  777. //---------------------------------------------------------------------------
  778. void __fastcall TRemoteMoveDialog::DoShow()
  779. {
  780. TCustomDialog::DoShow();
  781. InstallPathWordBreakProc(Combo);
  782. }
  783. //---------------------------------------------------------------------------
  784. void __fastcall TRemoteMoveDialog::DoValidate()
  785. {
  786. if (FOnDirectoryExists(NULL, Combo->Text))
  787. {
  788. Combo->Text = UnixCombinePaths(Combo->Text, AnyMask);
  789. }
  790. if (!IsFileNameMask(GetFileMask()) && FMulti)
  791. {
  792. UnicodeString Message =
  793. FormatMultiFilesToOneConfirmation(Combo->Text, true);
  794. if (MessageDialog(Message, qtConfirmation, qaOK | qaCancel, HELP_NONE) == qaCancel)
  795. {
  796. Abort();
  797. }
  798. }
  799. TCustomDialog::DoValidate();
  800. }
  801. //---------------------------------------------------------------------------
  802. bool __fastcall DoRemoteMoveDialog(
  803. bool Multi, UnicodeString & Target, UnicodeString & FileMask, TDirectoryExistsEvent OnDirectoryExists)
  804. {
  805. std::unique_ptr<TRemoteMoveDialog> Dialog(new TRemoteMoveDialog(Multi, OnDirectoryExists));
  806. return Dialog->Execute(Target, FileMask);
  807. }
  808. //---------------------------------------------------------------------------
  809. //---------------------------------------------------------------------------
  810. class TCustomCommandOptionsDialog : public TCustomDialog
  811. {
  812. public:
  813. __fastcall TCustomCommandOptionsDialog(
  814. const TCustomCommandType * Command, TStrings * CustomCommandOptions, unsigned int Flags,
  815. TCustomCommand * CustomCommandForOptions, const UnicodeString & Site, const TShortCuts * ShortCuts);
  816. bool __fastcall Execute(TShortCut * ShortCut);
  817. protected:
  818. virtual void __fastcall DoHelp();
  819. DYNAMIC void __fastcall DoShow();
  820. private:
  821. const TCustomCommandType * FCommand;
  822. TStrings * FCustomCommandOptions;
  823. std::vector<TControl *> FControls;
  824. std::vector<std::vector<UnicodeString> > FValues;
  825. unsigned int FFlags;
  826. UnicodeString FSite;
  827. TComboBox * FShortCutCombo;
  828. UnicodeString __fastcall HistoryKey(const TCustomCommandType::TOption & Option);
  829. THistoryComboBox * __fastcall CreateHistoryComboBox(const TCustomCommandType::TOption & Option, const UnicodeString & Value);
  830. void __fastcall BrowseButtonClick(TObject * Sender);
  831. void __fastcall LinkLabelClick(TObject * Sender);
  832. UnicodeString __fastcall SaveHistoryComboBoxValue(TControl * Control, const TCustomCommandType::TOption & Option);
  833. void __fastcall AddOptionComboBox(
  834. TComboBox * ComboBox, const UnicodeString & Value, const TCustomCommandType::TOption & Option,
  835. std::vector<UnicodeString> & Values);
  836. UnicodeString __fastcall GetComboBoxValue(TControl * Control, const UnicodeString & Default);
  837. int __fastcall GetOptionIndex(TControl * Control);
  838. int __fastcall GetControlIndex(TControl * Control);
  839. };
  840. //---------------------------------------------------------------------------
  841. __fastcall TCustomCommandOptionsDialog::TCustomCommandOptionsDialog(
  842. const TCustomCommandType * Command, TStrings * CustomCommandOptions,
  843. unsigned int Flags, TCustomCommand * CustomCommandForOptions,
  844. const UnicodeString & Site, const TShortCuts * ShortCuts) :
  845. TCustomDialog(HELP_EXTENSION_OPTIONS)
  846. {
  847. FCommand = Command;
  848. FFlags = Flags;
  849. FCustomCommandOptions = CustomCommandOptions;
  850. FSite = Site;
  851. Caption = StripEllipsis(StripHotkey(FCommand->Name));
  852. Width = ScaleByTextHeight(this, 444);
  853. bool HasGroups = false;
  854. int ControlIndex = 0;
  855. for (int OptionIndex = 0; OptionIndex < FCommand->OptionsCount; OptionIndex++)
  856. {
  857. const TCustomCommandType::TOption & Option = FCommand->GetOption(OptionIndex);
  858. if ((Option.Flags & FFlags) != 0)
  859. {
  860. UnicodeString OptionKey = FCommand->GetOptionKey(Option, FSite);
  861. UnicodeString Value;
  862. if ((CustomCommandForOptions != NULL) &&
  863. Option.HasPatterns(CustomCommandForOptions))
  864. {
  865. Value = CustomCommandForOptions->Complete(Option.Default, true);
  866. }
  867. else
  868. {
  869. if (FCustomCommandOptions->IndexOfName(OptionKey) >= 0)
  870. {
  871. Value = FCustomCommandOptions->Values[OptionKey];
  872. }
  873. else
  874. {
  875. Value = Option.Default;
  876. }
  877. }
  878. int Tag = (OptionIndex << 16) + ControlIndex;
  879. TControl * Control = NULL;
  880. std::vector<UnicodeString> Values;
  881. if (Option.Kind == TCustomCommandType::okUnknown)
  882. {
  883. Control = NULL;
  884. }
  885. else if (Option.Kind == TCustomCommandType::okLabel)
  886. {
  887. TLabel * Label = CreateLabel(Option.Caption);
  888. AddText(Label);
  889. Control = Label;
  890. }
  891. else if (Option.Kind == TCustomCommandType::okLink)
  892. {
  893. TStaticText * Label = new TStaticText(this);
  894. Label->Caption = Option.Caption;
  895. if (IsHttpOrHttpsUrl(Label->Caption))
  896. {
  897. Label->Caption = SecureUrl(Label->Caption);
  898. LinkLabel(Label);
  899. Label->TabStop = true;
  900. }
  901. else if (!Option.Default.IsEmpty() && IsHttpOrHttpsUrl(Option.Default))
  902. {
  903. Label->OnClick = LinkLabelClick;
  904. LinkLabel(Label);
  905. Label->TabStop = true;
  906. }
  907. else
  908. {
  909. // keep it plain text, as we have no URL
  910. }
  911. AddText(Label);
  912. Control = Label;
  913. }
  914. else if (Option.Kind == TCustomCommandType::okGroup)
  915. {
  916. StartGroup(Option.Caption);
  917. HasGroups = true;
  918. }
  919. else if (Option.Kind == TCustomCommandType::okSeparator)
  920. {
  921. AddSeparator();
  922. }
  923. else if (Option.Kind == TCustomCommandType::okTextBox)
  924. {
  925. Control = CreateHistoryComboBox(Option, Value);
  926. }
  927. else if (Option.Kind == TCustomCommandType::okFile)
  928. {
  929. THistoryComboBox * ComboBox = CreateHistoryComboBox(Option, Value);
  930. TButton * Button = CreateButton(this);
  931. AddButtonNextToEdit(Button, ComboBox);
  932. Button->Tag = Tag;
  933. Button->Caption = LoadStr(EXTENSION_OPTIONS_BROWSE);
  934. Button->OnClick = BrowseButtonClick;
  935. Control = ComboBox;
  936. }
  937. else if (Option.Kind == TCustomCommandType::okDropDownList)
  938. {
  939. TComboBox * ComboBox = new TUIStateAwareComboBox(this);
  940. ComboBox->Style = csDropDownList;
  941. AddOptionComboBox(ComboBox, Value, Option, Values);
  942. Control = ComboBox;
  943. }
  944. else if (Option.Kind == TCustomCommandType::okComboBox)
  945. {
  946. TComboBox * ComboBox = new TUIStateAwareComboBox(this);
  947. ComboBox->Style = csDropDown;
  948. AddOptionComboBox(ComboBox, Value, Option, Values);
  949. if (ComboBox->ItemIndex < 0)
  950. {
  951. ComboBox->Text = Value;
  952. }
  953. Control = ComboBox;
  954. }
  955. else if (Option.Kind == TCustomCommandType::okCheckBox)
  956. {
  957. TCheckBox * CheckBox = CreateAndAddCheckBox(Option.Caption);
  958. CheckBox->Checked =
  959. (Option.Params.size() >= 1) &&
  960. (Value == Option.Params[0]);
  961. Control = CheckBox;
  962. }
  963. else
  964. {
  965. DebugFail();
  966. }
  967. if (Control != NULL)
  968. {
  969. Control->Tag = Tag;
  970. }
  971. FControls.push_back(Control);
  972. FValues.push_back(Values);
  973. ControlIndex++;
  974. DebugAssert(static_cast<int>(FControls.size()) == ControlIndex);
  975. }
  976. }
  977. if (ShortCuts != NULL)
  978. {
  979. if (HasGroups)
  980. {
  981. StartGroup(LoadStr(EXTENSION_GENERAL_GROUP));
  982. }
  983. else if (ControlIndex > 0)
  984. {
  985. AddSeparator();
  986. }
  987. FShortCutCombo = new TUIStateAwareComboBox(this);
  988. AddShortCutComboBox(FShortCutCombo, CreateLabel(LoadStr(EXTENSION_SHORTCUT)), *ShortCuts);
  989. }
  990. }
  991. //---------------------------------------------------------------------------
  992. void __fastcall TCustomCommandOptionsDialog::AddOptionComboBox(
  993. TComboBox * ComboBox, const UnicodeString & Value, const TCustomCommandType::TOption & Option, std::vector<UnicodeString> & Values)
  994. {
  995. std::unique_ptr<TStringList> Items(new TStringList());
  996. int ItemIndex = -1;
  997. TCustomCommandType::TOption::TParams::const_iterator ParamI = Option.Params.begin();
  998. while (ParamI != Option.Params.end())
  999. {
  1000. UnicodeString Item = (*ParamI);
  1001. int P = Item.Pos(L"=");
  1002. UnicodeString ParamValue;
  1003. if (P > 0)
  1004. {
  1005. ParamValue = Item.SubString(1, P - 1);
  1006. Item.Delete(1, P);
  1007. }
  1008. else
  1009. {
  1010. ParamValue = Item;
  1011. }
  1012. Item = WinConfiguration->ExtensionStringTranslation(FCommand->Id, Item);
  1013. Items->Add(Item);
  1014. if (Value == ParamValue)
  1015. {
  1016. ItemIndex = Items->Count - 1;
  1017. }
  1018. Values.push_back(ParamValue);
  1019. ParamI++;
  1020. }
  1021. AddComboBox(ComboBox, CreateLabel(Option.Caption), Items.get(), true);
  1022. ComboBox->ItemIndex = ItemIndex;
  1023. }
  1024. //---------------------------------------------------------------------------
  1025. int __fastcall TCustomCommandOptionsDialog::GetOptionIndex(TControl * Control)
  1026. {
  1027. return (Control->Tag >> 16);
  1028. }
  1029. //---------------------------------------------------------------------------
  1030. int __fastcall TCustomCommandOptionsDialog::GetControlIndex(TControl * Control)
  1031. {
  1032. return (Control->Tag & 0xFFFF);
  1033. }
  1034. //---------------------------------------------------------------------------
  1035. void __fastcall TCustomCommandOptionsDialog::LinkLabelClick(TObject * Sender)
  1036. {
  1037. TStaticText * Label = DebugNotNull(dynamic_cast<TStaticText *>(Sender));
  1038. const TCustomCommandType::TOption & Option = FCommand->GetOption(GetOptionIndex(Label));
  1039. OpenBrowser(SecureUrl(Option.Default));
  1040. }
  1041. //---------------------------------------------------------------------------
  1042. void __fastcall TCustomCommandOptionsDialog::BrowseButtonClick(TObject * Sender)
  1043. {
  1044. TButton * Button = DebugNotNull(dynamic_cast<TButton *>(Sender));
  1045. int OptionIndex = GetOptionIndex(Button);
  1046. const TCustomCommandType::TOption & Option = FCommand->GetOption(OptionIndex);
  1047. int ControlIndex = GetControlIndex(Button);
  1048. THistoryComboBox * ComboBox = dynamic_cast<THistoryComboBox *>(FControls[ControlIndex]);
  1049. std::unique_ptr<TOpenDialog> OpenDialog(new TOpenDialog(Application));
  1050. UnicodeString Title;
  1051. if (!Option.FileCaption.IsEmpty())
  1052. {
  1053. Title = Option.FileCaption;
  1054. }
  1055. else
  1056. {
  1057. UnicodeString Caption = Option.Caption;
  1058. Caption = StripHotkey(Caption);
  1059. if (!Caption.IsEmpty() && (Caption[Caption.Length()] == L':'))
  1060. {
  1061. Caption.SetLength(Caption.Length() - 1);
  1062. }
  1063. Title = FMTLOAD(EXTENSION_OPTIONS_BROWSE_TITLE, (Caption));
  1064. }
  1065. OpenDialog->Title = Title;
  1066. UnicodeString Value;
  1067. if (ComboBox->Text.IsEmpty())
  1068. {
  1069. Value = Option.FileInitial;
  1070. }
  1071. else
  1072. {
  1073. Value = ComboBox->Text;
  1074. }
  1075. UnicodeString ExpandedValue = ExpandEnvironmentVariables(Value);
  1076. OpenDialog->FileName = ExpandedValue;
  1077. UnicodeString InitialDir = ExtractFilePath(ExpandedValue);
  1078. if (!InitialDir.IsEmpty())
  1079. {
  1080. OpenDialog->InitialDir = InitialDir;
  1081. }
  1082. OpenDialog->Filter = Option.FileFilter;
  1083. OpenDialog->DefaultExt = Option.FileExt;
  1084. if (OpenDialog->Execute())
  1085. {
  1086. if (OpenDialog->FileName != ExpandedValue)
  1087. {
  1088. ComboBox->Text = OpenDialog->FileName;
  1089. }
  1090. // If user just confirms the initial value, persist it
  1091. else if (ComboBox->Text.IsEmpty())
  1092. {
  1093. DebugAssert(Option.FileInitial == Value);
  1094. ComboBox->Text = Value;
  1095. }
  1096. }
  1097. }
  1098. //---------------------------------------------------------------------------
  1099. THistoryComboBox * __fastcall TCustomCommandOptionsDialog::CreateHistoryComboBox(
  1100. const TCustomCommandType::TOption & Option, const UnicodeString & Value)
  1101. {
  1102. THistoryComboBox * ComboBox = new THistoryComboBox(this);
  1103. ComboBox->AutoComplete = false;
  1104. AddComboBox(ComboBox, CreateLabel(Option.Caption));
  1105. ComboBox->Items = CustomWinConfiguration->History[HistoryKey(Option)];
  1106. ComboBox->Text = Value;
  1107. return ComboBox;
  1108. }
  1109. //---------------------------------------------------------------------------
  1110. UnicodeString __fastcall TCustomCommandOptionsDialog::HistoryKey(const TCustomCommandType::TOption & Option)
  1111. {
  1112. UnicodeString Result = FCommand->GetOptionKey(Option, FSite);
  1113. Result = CustomWinConfiguration->GetValidHistoryKey(Result);
  1114. return L"CustomCommandOption_" + Result;
  1115. }
  1116. //---------------------------------------------------------------------------
  1117. bool __fastcall TCustomCommandOptionsDialog::Execute(TShortCut * ShortCut)
  1118. {
  1119. if (ShortCut != NULL)
  1120. {
  1121. SetShortCutCombo(FShortCutCombo, *ShortCut);
  1122. }
  1123. bool Result = TCustomDialog::Execute();
  1124. if (Result)
  1125. {
  1126. int ControlIndex = 0;
  1127. for (int OptionIndex = 0; OptionIndex < FCommand->OptionsCount; OptionIndex++)
  1128. {
  1129. const TCustomCommandType::TOption & Option = FCommand->GetOption(OptionIndex);
  1130. if ((Option.Flags & FFlags) != 0)
  1131. {
  1132. if ((Option.Kind != TCustomCommandType::okUnknown) &&
  1133. Option.IsControl)
  1134. {
  1135. UnicodeString OptionKey = FCommand->GetOptionKey(Option, FSite);
  1136. TControl * Control = FControls[ControlIndex];
  1137. UnicodeString Value;
  1138. if (Option.Kind == TCustomCommandType::okTextBox)
  1139. {
  1140. Value = SaveHistoryComboBoxValue(Control, Option);
  1141. }
  1142. else if (Option.Kind == TCustomCommandType::okFile)
  1143. {
  1144. Value = SaveHistoryComboBoxValue(Control, Option);
  1145. }
  1146. else if (Option.Kind == TCustomCommandType::okDropDownList)
  1147. {
  1148. Value = GetComboBoxValue(Control, Option.Default);
  1149. }
  1150. else if (Option.Kind == TCustomCommandType::okComboBox)
  1151. {
  1152. TComboBox * ComboBox = DebugNotNull(dynamic_cast<TComboBox *>(Control));
  1153. Value = GetComboBoxValue(Control, ComboBox->Text);
  1154. }
  1155. else if (Option.Kind == TCustomCommandType::okCheckBox)
  1156. {
  1157. TCheckBox * CheckBox = DebugNotNull(dynamic_cast<TCheckBox *>(Control));
  1158. int Index = (CheckBox->Checked ? 0 : 1);
  1159. Value = (Index < static_cast<int>(Option.Params.size())) ? Option.Params[Index] : UnicodeString();
  1160. }
  1161. else
  1162. {
  1163. DebugFail();
  1164. }
  1165. // The default value setter deletes the "name" when the value is empty.
  1166. // It would cause us to fall back to the default value, but we want to remember the empty value.
  1167. SetStringValueEvenIfEmpty(FCustomCommandOptions, OptionKey, Value);
  1168. }
  1169. ControlIndex++;
  1170. }
  1171. }
  1172. if (ShortCut != NULL)
  1173. {
  1174. *ShortCut = GetShortCutCombo(FShortCutCombo);
  1175. }
  1176. }
  1177. return Result;
  1178. }
  1179. //---------------------------------------------------------------------------
  1180. UnicodeString __fastcall TCustomCommandOptionsDialog::GetComboBoxValue(
  1181. TControl * Control, const UnicodeString & Default)
  1182. {
  1183. TComboBox * ComboBox = DebugNotNull(dynamic_cast<TComboBox *>(Control));
  1184. UnicodeString Result;
  1185. if (ComboBox->ItemIndex < 0)
  1186. {
  1187. Result = Default;
  1188. }
  1189. else
  1190. {
  1191. Result = FValues[GetControlIndex(Control)][ComboBox->ItemIndex];
  1192. }
  1193. return Result;
  1194. }
  1195. //---------------------------------------------------------------------------
  1196. UnicodeString __fastcall TCustomCommandOptionsDialog::SaveHistoryComboBoxValue(
  1197. TControl * Control, const TCustomCommandType::TOption & Option)
  1198. {
  1199. THistoryComboBox * ComboBox = DebugNotNull(dynamic_cast<THistoryComboBox *>(Control));
  1200. ComboBox->SaveToHistory();
  1201. CustomWinConfiguration->History[HistoryKey(Option)] = ComboBox->Items;
  1202. return ComboBox->Text;
  1203. }
  1204. //---------------------------------------------------------------------------
  1205. void __fastcall TCustomCommandOptionsDialog::DoHelp()
  1206. {
  1207. UnicodeString HelpPage;
  1208. if (!FCommand->OptionsPage.IsEmpty())
  1209. {
  1210. HelpPage = FCommand->OptionsPage;
  1211. }
  1212. else
  1213. {
  1214. HelpPage = FCommand->HomePage;
  1215. }
  1216. if (!HelpPage.IsEmpty())
  1217. {
  1218. OpenBrowser(HelpPage);
  1219. }
  1220. else
  1221. {
  1222. TCustomDialog::DoHelp();
  1223. }
  1224. }
  1225. //---------------------------------------------------------------------------
  1226. void __fastcall TCustomCommandOptionsDialog::DoShow()
  1227. {
  1228. TCustomDialog::DoShow();
  1229. int ControlIndex = 0;
  1230. for (int OptionIndex = 0; OptionIndex < FCommand->OptionsCount; OptionIndex++)
  1231. {
  1232. const TCustomCommandType::TOption & Option = FCommand->GetOption(OptionIndex);
  1233. if ((Option.Flags & FFlags) != 0)
  1234. {
  1235. if (Option.Kind == TCustomCommandType::okFile)
  1236. {
  1237. TControl * Control = FControls[ControlIndex];
  1238. InstallPathWordBreakProc(DebugNotNull(dynamic_cast<TWinControl *>(Control)));
  1239. }
  1240. ControlIndex++;
  1241. }
  1242. }
  1243. }
  1244. //---------------------------------------------------------------------------
  1245. bool __fastcall DoCustomCommandOptionsDialog(
  1246. const TCustomCommandType * Command, TStrings * CustomCommandOptions, TShortCut * ShortCut,
  1247. unsigned int Flags, TCustomCommand * CustomCommandForOptions,
  1248. const UnicodeString & Site, const TShortCuts * ShortCuts)
  1249. {
  1250. std::unique_ptr<TCustomCommandOptionsDialog> Dialog(
  1251. new TCustomCommandOptionsDialog(Command, CustomCommandOptions, Flags, CustomCommandForOptions, Site, ShortCuts));
  1252. return Dialog->Execute(ShortCut);
  1253. }
  1254. //---------------------------------------------------------------------------
  1255. //---------------------------------------------------------------------------
  1256. class TUsageStatisticsDialog : public TCustomDialog
  1257. {
  1258. public:
  1259. __fastcall TUsageStatisticsDialog();
  1260. protected:
  1261. virtual void __fastcall DoChange(bool & CanSubmit);
  1262. private:
  1263. TEdit * FilterEdit;
  1264. TMemo * UsageMemo;
  1265. TButton * ClipboardButton;
  1266. void __fastcall ClipboardButtonClick(TObject * Sender);
  1267. };
  1268. //---------------------------------------------------------------------------
  1269. __fastcall TUsageStatisticsDialog::TUsageStatisticsDialog() :
  1270. TCustomDialog(HELP_USAGE)
  1271. {
  1272. Caption = LoadStr(USAGE_CAPTION);
  1273. Width = ScaleByTextHeight(this, 444);
  1274. // UnformatMessage is called, because previously, ** markup was used and translations may still contain that
  1275. AddText(CreateLabel(UnformatMessage(LoadStr(USAGE_DATA2))));
  1276. FilterEdit = new TEdit(this);
  1277. FilterEdit->Width = ScaleByTextHeight(this, 277);
  1278. AddEdit(FilterEdit, CreateLabel(LoadStr(USAGE_FILTER)), true);
  1279. UsageMemo = new TMemo(this);
  1280. UsageMemo->Height = ScaleByTextHeight(this, 333);
  1281. UsageMemo->ScrollBars = ssVertical;
  1282. AddEdit(UsageMemo, NULL);
  1283. ReadOnlyControl(UsageMemo);
  1284. ClipboardButton = CreateButton(this);
  1285. ClipboardButton->Caption = LoadStr(USAGE_COPY);
  1286. ClipboardButton->Width = ScaleByTextHeight(this, 179);
  1287. ClipboardButton->OnClick = ClipboardButtonClick;
  1288. AddDialogButton(ClipboardButton);
  1289. RemoveCancelButton();
  1290. }
  1291. //---------------------------------------------------------------------------
  1292. void __fastcall TUsageStatisticsDialog::ClipboardButtonClick(TObject * /*Sender*/)
  1293. {
  1294. TInstantOperationVisualizer Visualizer;
  1295. CopyToClipboard(UsageMemo->Lines);
  1296. }
  1297. //---------------------------------------------------------------------------
  1298. void __fastcall TUsageStatisticsDialog::DoChange(bool & CanSubmit)
  1299. {
  1300. TCustomDialog::DoChange(CanSubmit);
  1301. UnicodeString Text = Configuration->Usage->Serialize(L"\n", FilterEdit->Text);
  1302. bool NoUsage = Text.IsEmpty();
  1303. ClipboardButton->Enabled = !NoUsage;
  1304. if (NoUsage)
  1305. {
  1306. Text = LoadStr(USAGE_DATA_NONE2);
  1307. }
  1308. UsageMemo->Lines->Text = Text;
  1309. }
  1310. //---------------------------------------------------------------------------
  1311. void __fastcall DoUsageStatisticsDialog()
  1312. {
  1313. std::unique_ptr<TUsageStatisticsDialog> Dialog(new TUsageStatisticsDialog());
  1314. Dialog->Execute();
  1315. }
  1316. //---------------------------------------------------------------------------
  1317. //---------------------------------------------------------------------------
  1318. class TSiteRawDialog : public TCustomDialog
  1319. {
  1320. public:
  1321. __fastcall TSiteRawDialog();
  1322. bool __fastcall Execute(TSessionData * Data);
  1323. protected:
  1324. DYNAMIC void __fastcall DoShow();
  1325. private:
  1326. TMemo * SettingsMemo;
  1327. void __fastcall AddButtonClick(TObject * Sender);
  1328. void __fastcall SettingsMemoKeyDown(TObject * Sender, WORD & Key, TShiftState Shift);
  1329. void DeleteNames(TStrings * Names, TStrings * Options);
  1330. };
  1331. //---------------------------------------------------------------------------
  1332. __fastcall TSiteRawDialog::TSiteRawDialog() :
  1333. TCustomDialog(HELP_SITE_RAW)
  1334. {
  1335. Caption = LoadStr(SITE_RAW_CAPTION);
  1336. Width = ScaleByTextHeight(this, 444);
  1337. SettingsMemo = new TMemo(this);
  1338. SettingsMemo->Height = ScaleByTextHeight(this, 333);
  1339. SettingsMemo->OnKeyDown = SettingsMemoKeyDown;
  1340. AddEdit(SettingsMemo, NULL);
  1341. TButton * AddButton = CreateButton(this);
  1342. AddButton->Caption = LoadStr(SITE_RAW_ADD);
  1343. AddButton->Width = OKButton->Width;
  1344. AddButton->OnClick = AddButtonClick;
  1345. AddDialogButton(AddButton);
  1346. }
  1347. //---------------------------------------------------------------------------
  1348. void __fastcall TSiteRawDialog::DoShow()
  1349. {
  1350. TCustomDialog::DoShow();
  1351. InstallPathWordBreakProc(SettingsMemo);
  1352. }
  1353. //---------------------------------------------------------------------------
  1354. bool __fastcall TSiteRawDialog::Execute(TSessionData * Data)
  1355. {
  1356. std::unique_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
  1357. std::unique_ptr<TSessionData> RawData(new TSessionData(L""));
  1358. RawData->Assign(Data);
  1359. // SFTP-only is not reflected by the protocol prefix, we have to use rawsettings for that
  1360. if (RawData->FSProtocol != fsSFTPonly)
  1361. {
  1362. RawData->FSProtocol = FactoryDefaults->FSProtocol;
  1363. }
  1364. RawData->HostName = FactoryDefaults->HostName;
  1365. RawData->PortNumber = FactoryDefaults->PortNumber;
  1366. RawData->UserName = FactoryDefaults->UserName;
  1367. RawData->Password = FactoryDefaults->Password;
  1368. RawData->Ftps = FactoryDefaults->Ftps;
  1369. std::unique_ptr<TStrings> Options(RawData->SaveToOptions(FactoryDefaults.get(), false, false));
  1370. SettingsMemo->Lines = Options.get();
  1371. bool Result = TCustomDialog::Execute();
  1372. if (Result)
  1373. {
  1374. std::unique_ptr<TSessionData> BackupData(new TSessionData(L""));
  1375. BackupData->Assign(Data);
  1376. Data->DefaultSettings();
  1377. Data->FSProtocol = BackupData->FSProtocol;
  1378. Data->HostName = BackupData->HostName;
  1379. Data->PortNumber = BackupData->PortNumber;
  1380. Data->UserName = BackupData->UserName;
  1381. Data->Password = BackupData->Password;
  1382. Data->Ftps = BackupData->Ftps;
  1383. Data->ApplyRawSettings(SettingsMemo->Lines, false);
  1384. }
  1385. return Result;
  1386. }
  1387. //---------------------------------------------------------------------------
  1388. void __fastcall TSiteRawDialog::SettingsMemoKeyDown(TObject * Sender, WORD & Key, TShiftState Shift)
  1389. {
  1390. MemoKeyDown(Sender, Key, Shift);
  1391. }
  1392. //---------------------------------------------------------------------------
  1393. void __fastcall TSiteRawDialog::AddButtonClick(TObject *)
  1394. {
  1395. std::unique_ptr<TSessionData> FactoryDefaults(new TSessionData(L""));
  1396. std::unique_ptr<TSessionData> BasicData(new TSessionData(L""));
  1397. BasicData->FSProtocol = TFSProtocol(FactoryDefaults->FSProtocol + 1);
  1398. UnicodeString RandomAppendix(L"_");
  1399. BasicData->HostName = FactoryDefaults->HostName + RandomAppendix;
  1400. BasicData->Ftps = TFtps(FactoryDefaults->Ftps + 1);
  1401. BasicData->PortNumber = BasicData->GetDefaultPort() + 1;
  1402. BasicData->UserName = FactoryDefaults->UserName + RandomAppendix;
  1403. BasicData->Password = FactoryDefaults->Password + RandomAppendix;
  1404. std::unique_ptr<TStrings> BasicOptions(BasicData->SaveToOptions(FactoryDefaults.get(), false, false));
  1405. std::unique_ptr<TStrings> AllOptions(TSessionData::GetAllOptionNames(false));
  1406. std::unique_ptr<TStrings> Names(CreateSortedStringList());
  1407. for (int Index = 0; Index < AllOptions->Count; Index++)
  1408. {
  1409. Names->Add(AllOptions->Names[Index]);
  1410. }
  1411. DeleteNames(Names.get(), BasicOptions.get());
  1412. DeleteNames(Names.get(), SettingsMemo->Lines);
  1413. std::unique_ptr<TCustomDialog> AddDialog(new TCustomDialog(HelpKeyword));
  1414. AddDialog->Caption = LoadStr(SITE_RAW_ADD_CAPTION);
  1415. TComboBox * AddComboBox = new TUIStateAwareComboBox(AddDialog.get());
  1416. AddComboBox->Style = csDropDownList;
  1417. AddComboBox->DropDownCount = Max(AddComboBox->DropDownCount, 16);
  1418. AddDialog->AddComboBox(AddComboBox, CreateLabel(LoadStr(SITE_RAW_ADD_LABEL)), Names.get(), true);
  1419. AddComboBox->ItemIndex = 0;
  1420. if (AddDialog->Execute())
  1421. {
  1422. UnicodeString Name = AddComboBox->Items->Strings[AddComboBox->ItemIndex];
  1423. UnicodeString Value = AllOptions->Values[Name];
  1424. UnicodeString NameAndSeparator = Name + SettingsMemo->Lines->NameValueSeparator;
  1425. int Start = (SettingsMemo->Lines->Text + NameAndSeparator).Length();
  1426. SettingsMemo->Lines->Add(NameAndSeparator + Value);
  1427. SettingsMemo->SetFocus();
  1428. SettingsMemo->SelStart = Start;
  1429. SettingsMemo->SelLength = Value.Length();
  1430. }
  1431. }
  1432. //---------------------------------------------------------------------------
  1433. void TSiteRawDialog::DeleteNames(TStrings * Names, TStrings * Options)
  1434. {
  1435. for (int Index = 0; Index < Options->Count; Index++)
  1436. {
  1437. UnicodeString Name = Options->Names[Index];
  1438. if (!Name.IsEmpty())
  1439. {
  1440. int I = Names->IndexOf(Name);
  1441. if (I >= 0)
  1442. {
  1443. Names->Delete(I);
  1444. }
  1445. }
  1446. }
  1447. }
  1448. //---------------------------------------------------------------------------
  1449. void __fastcall DoSiteRawDialog(TSessionData * Data)
  1450. {
  1451. std::unique_ptr<TSiteRawDialog> Dialog(new TSiteRawDialog());
  1452. Dialog->Execute(Data);
  1453. }
  1454. //---------------------------------------------------------------------------
  1455. //---------------------------------------------------------------------------
  1456. class TSshHostCADialog : public TCustomDialog
  1457. {
  1458. public:
  1459. TSshHostCADialog(bool Add);
  1460. bool Execute(TSshHostCA & SshHostCA);
  1461. protected:
  1462. virtual void __fastcall DoChange(bool & CanSubmit);
  1463. virtual void __fastcall DoValidate();
  1464. private:
  1465. TEdit * NameEdit;
  1466. TEdit * PublicKeyEdit;
  1467. TEdit * PublicKeyLabel;
  1468. TEdit * ValidityExpressionEdit;
  1469. TCheckBox * PermitRsaSha1Check;
  1470. TCheckBox * PermitRsaSha256Check;
  1471. TCheckBox * PermitRsaSha512Check;
  1472. void __fastcall BrowseButtonClick(TObject * Sender);
  1473. TCheckBox * AddValidityCheckBox(int CaptionStrPart);
  1474. bool ValidatePublicKey(UnicodeString & Status);
  1475. };
  1476. //---------------------------------------------------------------------------
  1477. TSshHostCADialog::TSshHostCADialog(bool Add) :
  1478. TCustomDialog(HELP_SSH_HOST_CA)
  1479. {
  1480. ClientWidth = ScaleByTextHeight(this, 577);
  1481. Caption = LoadStr(Add ? SSH_HOST_CA_ADD : SSH_HOST_CA_EDIT);
  1482. NameEdit = new TEdit(this);
  1483. AddEdit(NameEdit, CreateLabel(LoadStr(SSH_HOST_CA_NAME)));
  1484. PublicKeyEdit = new TEdit(this);
  1485. AddEdit(PublicKeyEdit, CreateLabel(LoadStr(SSH_HOST_CA_PUBLIC_KEY)));
  1486. TButton * BrowseButton = CreateButton(this);
  1487. BrowseButton->Caption = LoadStr(SSH_HOST_CA_BROWSE);
  1488. BrowseButton->OnClick = BrowseButtonClick;
  1489. AddButtonNextToEdit(BrowseButton, PublicKeyEdit);
  1490. NameEdit->Width = PublicKeyEdit->Width;
  1491. PublicKeyLabel = new TEdit(this);
  1492. ReadOnlyControl(PublicKeyLabel);
  1493. PublicKeyLabel->BorderStyle = bsNone;
  1494. PublicKeyLabel->TabStop = false;
  1495. AddEditLikeControl(PublicKeyLabel, NULL);
  1496. ValidityExpressionEdit = new TEdit(this);
  1497. AddEdit(ValidityExpressionEdit, CreateLabel(LoadStr(SSH_HOST_CA_PUBLIC_HOSTS)));
  1498. TLabel * Label = CreateLabel(LoadStr(SSH_HOST_CA_SIGNATURE_TYPES));
  1499. AddText(Label);
  1500. PermitRsaSha1Check = AddValidityCheckBox(1);
  1501. int PermitCheckBoxTop = Label->Top - (PermitRsaSha1Check->Height - Label->Height) / 2;
  1502. PermitRsaSha1Check->Left = OKButton->Left + 1;
  1503. PermitRsaSha1Check->Top = PermitCheckBoxTop;
  1504. PermitRsaSha256Check = AddValidityCheckBox(2);
  1505. PermitRsaSha256Check->Left = CancelButton->Left + 1;
  1506. PermitRsaSha256Check->Top = PermitCheckBoxTop;
  1507. PermitRsaSha512Check = AddValidityCheckBox(3);
  1508. PermitRsaSha512Check->Left = HelpButton->Left + 1;
  1509. PermitRsaSha512Check->Top = PermitCheckBoxTop;
  1510. }
  1511. //---------------------------------------------------------------------------
  1512. TCheckBox * TSshHostCADialog::AddValidityCheckBox(int CaptionStrPart)
  1513. {
  1514. TCheckBox * Result = new TCheckBox(this);
  1515. Result->Parent = this;
  1516. Result->Caption = LoadStrPart(SSH_HOST_CA_SIGNATURES, CaptionStrPart);
  1517. ScaleButtonControl(Result);
  1518. Result->Left = Left;
  1519. Result->OnClick = Change;
  1520. AddWinControl(Result);
  1521. return Result;
  1522. }
  1523. //---------------------------------------------------------------------------
  1524. bool TSshHostCADialog::ValidatePublicKey(UnicodeString & Status)
  1525. {
  1526. bool Result = false;
  1527. UnicodeString PublicKeyText = PublicKeyEdit->Text.Trim();
  1528. if (PublicKeyText.IsEmpty())
  1529. {
  1530. Status = LoadStr(SSH_HOST_CA_NO_KEY);
  1531. }
  1532. else
  1533. {
  1534. RawByteString PublicKeyDummy;
  1535. try
  1536. {
  1537. ParseCertificatePublicKey(PublicKeyText, PublicKeyDummy, Status);
  1538. Result = true;
  1539. }
  1540. catch (Exception & E)
  1541. {
  1542. Status = E.Message;
  1543. }
  1544. }
  1545. return Result;
  1546. }
  1547. //---------------------------------------------------------------------------
  1548. void __fastcall TSshHostCADialog::DoChange(bool & CanSubmit)
  1549. {
  1550. TCustomDialog::DoChange(CanSubmit);
  1551. UnicodeString PublicKeyStatus;
  1552. ValidatePublicKey(PublicKeyStatus);
  1553. // Should drop "SHA256:" prefix, the way we do in TSecureShell::VerifyHostKey
  1554. PublicKeyLabel->Text = PublicKeyStatus;
  1555. CanSubmit = !NameEdit->Text.Trim().IsEmpty() && !PublicKeyEdit->Text.Trim().IsEmpty();
  1556. }
  1557. //---------------------------------------------------------------------
  1558. void __fastcall TSshHostCADialog::DoValidate()
  1559. {
  1560. TCustomDialog::DoValidate();
  1561. UnicodeString PublicKeyStatus;
  1562. if (!ValidatePublicKey(PublicKeyStatus))
  1563. {
  1564. PublicKeyEdit->SetFocus();
  1565. throw Exception(MainInstructions(PublicKeyStatus));
  1566. }
  1567. if (ValidityExpressionEdit->Text.Trim().IsEmpty())
  1568. {
  1569. ValidityExpressionEdit->SetFocus();
  1570. throw Exception(MainInstructions(LoadStr(SSH_HOST_CA_NO_HOSTS)));
  1571. }
  1572. UnicodeString Error;
  1573. int ErrorStart, ErrorLen;
  1574. if (!IsCertificateValidityExpressionValid(ValidityExpressionEdit->Text, Error, ErrorStart, ErrorLen))
  1575. {
  1576. std::unique_ptr<TStrings> MoreMessages(TextToStringList(Error));
  1577. MoreMessageDialog(MainInstructions(LoadStr(SSH_HOST_CA_HOSTS_INVALID)), MoreMessages.get(), qtError, qaOK, HelpKeyword);
  1578. ValidityExpressionEdit->SetFocus();
  1579. ValidityExpressionEdit->SelStart = ErrorStart;
  1580. ValidityExpressionEdit->SelLength = ErrorLen;
  1581. Abort();
  1582. }
  1583. }
  1584. //---------------------------------------------------------------------------
  1585. bool TSshHostCADialog::Execute(TSshHostCA & SshHostCA)
  1586. {
  1587. NameEdit->Text = SshHostCA.Name;
  1588. RawByteString PublicKey = SshHostCA.PublicKey;
  1589. PublicKeyEdit->Text = EncodeStrToBase64(PublicKey);
  1590. ValidityExpressionEdit->Text = SshHostCA.ValidityExpression;
  1591. PermitRsaSha1Check->Checked = SshHostCA.PermitRsaSha1;
  1592. PermitRsaSha256Check->Checked = SshHostCA.PermitRsaSha256;
  1593. PermitRsaSha512Check->Checked = SshHostCA.PermitRsaSha512;
  1594. bool Result = TCustomDialog::Execute();
  1595. if (Result)
  1596. {
  1597. SshHostCA.Name = NameEdit->Text;
  1598. SshHostCA.PublicKey = DecodeBase64ToStr(PublicKeyEdit->Text);
  1599. SshHostCA.ValidityExpression = ValidityExpressionEdit->Text;
  1600. SshHostCA.PermitRsaSha1 = PermitRsaSha1Check->Checked;
  1601. SshHostCA.PermitRsaSha256 = PermitRsaSha256Check->Checked;
  1602. SshHostCA.PermitRsaSha512 = PermitRsaSha512Check->Checked;
  1603. }
  1604. return Result;
  1605. }
  1606. //---------------------------------------------------------------------------
  1607. void __fastcall TSshHostCADialog::BrowseButtonClick(TObject *)
  1608. {
  1609. std::unique_ptr<TOpenDialog> OpenDialog(new TOpenDialog(Application));
  1610. OpenDialog->Title = LoadStr(SSH_HOST_CA_BROWSE_TITLE);
  1611. OpenDialog->Filter = LoadStr(SSH_HOST_CA_BROWSE_FILTER);
  1612. bool Result = OpenDialog->Execute();
  1613. if (Result)
  1614. {
  1615. UnicodeString FileName = OpenDialog->FileName;
  1616. UnicodeString Algorithm, Comment;
  1617. bool HasCertificate;
  1618. RawByteString PublicKey;
  1619. try
  1620. {
  1621. PublicKey = LoadPublicKey(FileName, Algorithm, Comment, HasCertificate);
  1622. }
  1623. catch (Exception & E)
  1624. {
  1625. throw ExtException(&E, MainInstructions(FMTLOAD(SSH_HOST_CA_LOAD_ERROR, (FileName))));
  1626. }
  1627. if (NameEdit->Text.IsEmpty())
  1628. {
  1629. NameEdit->Text = Comment;
  1630. }
  1631. PublicKeyEdit->Text = EncodeStrToBase64(PublicKey);
  1632. }
  1633. }
  1634. //---------------------------------------------------------------------------
  1635. bool DoSshHostCADialog(bool Add, TSshHostCA & SshHostCA)
  1636. {
  1637. std::unique_ptr<TSshHostCADialog> Dialog(new TSshHostCADialog(Add));
  1638. return Dialog->Execute(SshHostCA);
  1639. }
  1640. //---------------------------------------------------------------------------
  1641. //---------------------------------------------------------------------------
  1642. class TTagDialog : public TCustomDialog
  1643. {
  1644. public:
  1645. TTagDialog(bool Add, TStrings * Tags);
  1646. bool Execute(UnicodeString & Key, UnicodeString & Value);
  1647. protected:
  1648. virtual void __fastcall DoChange(bool & CanSubmit);
  1649. virtual void __fastcall DoValidate();
  1650. private:
  1651. TEdit * KeyEdit;
  1652. TEdit * ValueEdit;
  1653. TStrings * FTags;
  1654. void ValidateTag(TEdit * Edit);
  1655. };
  1656. //---------------------------------------------------------------------------
  1657. TTagDialog::TTagDialog(bool Add, TStrings * Tags) :
  1658. TCustomDialog(HELP_TAG)
  1659. {
  1660. Caption = LoadStr(Add ? TAG_ADD : TAG_EDIT);
  1661. FTags = Tags;
  1662. KeyEdit = new TEdit(this);
  1663. KeyEdit->MaxLength = 128;
  1664. AddEdit(KeyEdit, CreateLabel(LoadStr(TAG_KEY)));
  1665. ValueEdit = new TEdit(this);
  1666. ValueEdit->MaxLength = 256;
  1667. AddEdit(ValueEdit, CreateLabel(LoadStr(TAG_VALUE)));
  1668. }
  1669. //---------------------------------------------------------------------------
  1670. bool TTagDialog::Execute(UnicodeString & Key, UnicodeString & Value)
  1671. {
  1672. // if we happen to get values longer than what we believed was possible, allow them.
  1673. KeyEdit->MaxLength = std::max(KeyEdit->MaxLength, Key.Length());
  1674. KeyEdit->Text = Key;
  1675. ValueEdit->MaxLength = std::max(ValueEdit->MaxLength, Value.Length());
  1676. ValueEdit->Text = Value;
  1677. bool Result = TCustomDialog::Execute();
  1678. if (Result)
  1679. {
  1680. Key = KeyEdit->Text;
  1681. Value = ValueEdit->Text;
  1682. }
  1683. return Result;
  1684. }
  1685. //---------------------------------------------------------------------------
  1686. void __fastcall TTagDialog::DoChange(bool & CanSubmit)
  1687. {
  1688. CanSubmit = !KeyEdit->Text.IsEmpty();
  1689. }
  1690. //---------------------------------------------------------------------------
  1691. void TTagDialog::ValidateTag(TEdit * Edit)
  1692. {
  1693. // there are lot more in various scripts
  1694. UnicodeString InvalidChars = L"!\"#$%&'()*,;<>?[\\]^`{|}~¡¢£¤¥¦§¨©«¬­®¯°±´¶·¸»¿×÷";
  1695. UnicodeString Text = Edit->Text;
  1696. for (int Index = 1; Index <= Text.Length(); Index++)
  1697. {
  1698. wchar_t Ch = Text[Index];
  1699. if (TCharacter::IsControl(Ch) ||
  1700. (InvalidChars.Pos(Ch) > 0))
  1701. {
  1702. UnicodeString Message = MainInstructions(FMTLOAD(TAG_INVALID_CHAR, (Ch)));
  1703. if (MoreMessageDialog(Message, NULL, qtWarning, qaIgnore | qaAbort, HelpKeyword) != qaIgnore)
  1704. {
  1705. Edit->SetFocus();
  1706. Abort();
  1707. }
  1708. else
  1709. {
  1710. break;
  1711. }
  1712. }
  1713. }
  1714. }
  1715. //---------------------------------------------------------------------------
  1716. void __fastcall TTagDialog::DoValidate()
  1717. {
  1718. UnicodeString Key = KeyEdit->Text;
  1719. if (FTags->IndexOf(Key) >= 0)
  1720. {
  1721. throw Exception(MainInstructions(LoadStr(TAG_NOT_UNIQUE)));
  1722. }
  1723. ValidateTag(KeyEdit);
  1724. ValidateTag(ValueEdit);
  1725. TCustomDialog::DoValidate();
  1726. }
  1727. //---------------------------------------------------------------------------
  1728. bool DoTagDialog(bool Add, TStrings * Tags, UnicodeString & Key, UnicodeString & Value)
  1729. {
  1730. std::unique_ptr<TTagDialog> Dialog(new TTagDialog(Add, Tags));
  1731. return Dialog->Execute(Key, Value);
  1732. }