Configuration.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <FileInfo.h>
  5. #include "Exceptions.h"
  6. #include "Common.h"
  7. #include "Configuration.h"
  8. #include "PuttyIntf.h"
  9. #include "TextsCore.h"
  10. #include "Interface.h"
  11. #include "CoreMain.h"
  12. #include "Security.h"
  13. #include <shlobj.h>
  14. #include <System.IOUtils.hpp>
  15. //---------------------------------------------------------------------------
  16. #pragma package(smart_init)
  17. //---------------------------------------------------------------------------
  18. __fastcall TConfiguration::TConfiguration()
  19. {
  20. FCriticalSection = new TCriticalSection();
  21. FUpdating = 0;
  22. FStorage = stDetect;
  23. FDontSave = false;
  24. FApplicationInfo = NULL;
  25. FUsage = new TUsage(this);
  26. FDefaultCollectUsage = false;
  27. wchar_t Buf[10];
  28. UnicodeString RandomSeedPath;
  29. if (GetEnvironmentVariable(L"APPDATA", Buf, LENOF(Buf)) > 0)
  30. {
  31. RandomSeedPath = L"%APPDATA%";
  32. }
  33. else
  34. {
  35. RandomSeedPath = GetShellFolderPath(CSIDL_LOCAL_APPDATA);
  36. if (RandomSeedPath.IsEmpty())
  37. {
  38. RandomSeedPath = GetShellFolderPath(CSIDL_APPDATA);
  39. }
  40. }
  41. FDefaultRandomSeedFile = IncludeTrailingBackslash(RandomSeedPath) + L"winscp.rnd";
  42. }
  43. //---------------------------------------------------------------------------
  44. void __fastcall TConfiguration::Default()
  45. {
  46. TGuard Guard(FCriticalSection);
  47. FDisablePasswordStoring = false;
  48. FForceBanners = false;
  49. FDisableAcceptingHostKeys = false;
  50. TRegistryStorage * AdminStorage;
  51. AdminStorage = new TRegistryStorage(RegistryStorageKey, HKEY_LOCAL_MACHINE);
  52. try
  53. {
  54. if (AdminStorage->OpenRootKey(false))
  55. {
  56. LoadAdmin(AdminStorage);
  57. AdminStorage->CloseSubKey();
  58. }
  59. }
  60. __finally
  61. {
  62. delete AdminStorage;
  63. }
  64. RandomSeedFile = FDefaultRandomSeedFile;
  65. PuttyRegistryStorageKey = L"Software\\SimonTatham\\PuTTY";
  66. FConfirmOverwriting = true;
  67. FConfirmResume = true;
  68. FAutoReadDirectoryAfterOp = true;
  69. FSessionReopenAuto = 5000;
  70. FSessionReopenBackground = 2000;
  71. FSessionReopenTimeout = 0;
  72. FSessionReopenAutoStall = 60000;
  73. FTunnelLocalPortNumberLow = 50000;
  74. FTunnelLocalPortNumberHigh = 50099;
  75. FCacheDirectoryChangesMaxSize = 100;
  76. FShowFtpWelcomeMessage = false;
  77. FExternalIpAddress = L"";
  78. FTryFtpWhenSshFails = true;
  79. CollectUsage = FDefaultCollectUsage;
  80. FLogging = false;
  81. FPermanentLogging = false;
  82. FLogFileName = DefaultLogFileName;
  83. FPermanentLogFileName = FLogFileName;
  84. FLogFileAppend = true;
  85. FLogWindowLines = 100;
  86. FLogProtocol = 0;
  87. UpdateActualLogProtocol();
  88. FLogActions = false;
  89. FPermanentLogActions = false;
  90. FActionsLogFileName = L"%TEMP%\\!S.xml";
  91. FPermanentActionsLogFileName = FActionsLogFileName;
  92. FProgramIniPathWrittable = -1;
  93. Changed();
  94. }
  95. //---------------------------------------------------------------------------
  96. __fastcall TConfiguration::~TConfiguration()
  97. {
  98. assert(!FUpdating);
  99. if (FApplicationInfo) FreeFileInfo(FApplicationInfo);
  100. delete FCriticalSection;
  101. delete FUsage;
  102. }
  103. //---------------------------------------------------------------------------
  104. THierarchicalStorage * TConfiguration::CreateScpStorage(bool /*SessionList*/)
  105. {
  106. if (Storage == stRegistry)
  107. {
  108. return new TRegistryStorage(RegistryStorageKey);
  109. }
  110. else if (Storage == stNul)
  111. {
  112. return new TIniFileStorage(L"nul");
  113. }
  114. else
  115. {
  116. return new TIniFileStorage(IniFileStorageName);
  117. }
  118. }
  119. //---------------------------------------------------------------------------
  120. UnicodeString __fastcall TConfiguration::PropertyToKey(const UnicodeString & Property)
  121. {
  122. // no longer useful
  123. int P = Property.LastDelimiter(L".>");
  124. return Property.SubString(P + 1, Property.Length() - P);
  125. }
  126. //---------------------------------------------------------------------------
  127. #define BLOCK(KEY, CANCREATE, BLOCK) \
  128. if (Storage->OpenSubKey(KEY, CANCREATE, true)) try { BLOCK } __finally { Storage->CloseSubKey(); }
  129. #define KEY(TYPE, VAR) KEYEX(TYPE, VAR, PropertyToKey(TEXT(#VAR)))
  130. #define REGCONFIG(CANCREATE) \
  131. BLOCK(L"Interface", CANCREATE, \
  132. KEY(String, RandomSeedFile); \
  133. KEY(String, PuttyRegistryStorageKey); \
  134. KEY(Bool, ConfirmOverwriting); \
  135. KEY(Bool, ConfirmResume); \
  136. KEY(Bool, AutoReadDirectoryAfterOp); \
  137. KEY(Integer, SessionReopenAuto); \
  138. KEY(Integer, SessionReopenBackground); \
  139. KEY(Integer, SessionReopenTimeout); \
  140. KEY(Integer, SessionReopenAutoStall); \
  141. KEY(Integer, TunnelLocalPortNumberLow); \
  142. KEY(Integer, TunnelLocalPortNumberHigh); \
  143. KEY(Integer, CacheDirectoryChangesMaxSize); \
  144. KEY(Bool, ShowFtpWelcomeMessage); \
  145. KEY(String, ExternalIpAddress); \
  146. KEY(Bool, TryFtpWhenSshFails); \
  147. KEY(Bool, CollectUsage); \
  148. ); \
  149. BLOCK(L"Logging", CANCREATE, \
  150. KEYEX(Bool, PermanentLogging, L"Logging"); \
  151. KEYEX(String,PermanentLogFileName, L"LogFileName"); \
  152. KEY(Bool, LogFileAppend); \
  153. KEY(Integer, LogWindowLines); \
  154. KEY(Integer, LogProtocol); \
  155. KEYEX(Bool, PermanentLogActions, L"LogActions"); \
  156. KEYEX(String,PermanentActionsLogFileName, L"ActionsLogFileName"); \
  157. );
  158. //---------------------------------------------------------------------------
  159. void __fastcall TConfiguration::SaveData(THierarchicalStorage * Storage, bool /*All*/)
  160. {
  161. #define KEYEX(TYPE, VAR, NAME) Storage->Write ## TYPE(NAME, VAR)
  162. REGCONFIG(true);
  163. #undef KEYEX
  164. if (Storage->OpenSubKey(L"Usage", true))
  165. {
  166. FUsage->Save(Storage);
  167. Storage->CloseSubKey();
  168. }
  169. }
  170. //---------------------------------------------------------------------------
  171. void __fastcall TConfiguration::Save(bool All, bool Explicit)
  172. {
  173. if (FDontSave) return;
  174. THierarchicalStorage * AStorage = CreateScpStorage(false);
  175. try
  176. {
  177. AStorage->AccessMode = smReadWrite;
  178. AStorage->Explicit = Explicit;
  179. if (AStorage->OpenSubKey(ConfigurationSubKey, true))
  180. {
  181. SaveData(AStorage, All);
  182. }
  183. }
  184. __finally
  185. {
  186. delete AStorage;
  187. }
  188. Saved();
  189. if (All)
  190. {
  191. StoredSessions->Save(true, Explicit);
  192. }
  193. // clean up as last, so that if it fails (read only INI), the saving can proceed
  194. if (Storage == stRegistry)
  195. {
  196. CleanupIniFile();
  197. }
  198. }
  199. //---------------------------------------------------------------------------
  200. void __fastcall TConfiguration::Export(const UnicodeString & FileName)
  201. {
  202. THierarchicalStorage * Storage = NULL;
  203. THierarchicalStorage * ExportStorage = NULL;
  204. try
  205. {
  206. ExportStorage = new TIniFileStorage(FileName);
  207. ExportStorage->AccessMode = smReadWrite;
  208. ExportStorage->Explicit = true;
  209. Storage = CreateScpStorage(false);
  210. Storage->AccessMode = smRead;
  211. CopyData(Storage, ExportStorage);
  212. if (ExportStorage->OpenSubKey(ConfigurationSubKey, true))
  213. {
  214. SaveData(ExportStorage, true);
  215. }
  216. }
  217. __finally
  218. {
  219. delete ExportStorage;
  220. delete Storage;
  221. }
  222. StoredSessions->Export(FileName);
  223. }
  224. //---------------------------------------------------------------------------
  225. void __fastcall TConfiguration::Import(const UnicodeString & FileName)
  226. {
  227. THierarchicalStorage * Storage = NULL;
  228. THierarchicalStorage * ImportStorage = NULL;
  229. try
  230. {
  231. ImportStorage = new TIniFileStorage(FileName);
  232. ImportStorage->AccessMode = smRead;
  233. Storage = CreateScpStorage(false);
  234. Storage->AccessMode = smReadWrite;
  235. Storage->Explicit = true;
  236. CopyData(ImportStorage, Storage);
  237. Default();
  238. LoadFrom(ImportStorage);
  239. if (ImportStorage->OpenSubKey(Configuration->StoredSessionsSubKey, false))
  240. {
  241. StoredSessions->Clear();
  242. StoredSessions->DefaultSettings->Default();
  243. StoredSessions->Load(ImportStorage);
  244. }
  245. }
  246. __finally
  247. {
  248. delete ImportStorage;
  249. delete Storage;
  250. }
  251. // save all and explicit
  252. Save(true, true);
  253. }
  254. //---------------------------------------------------------------------------
  255. void __fastcall TConfiguration::LoadData(THierarchicalStorage * Storage)
  256. {
  257. #define KEYEX(TYPE, VAR, NAME) VAR = Storage->Read ## TYPE(NAME, VAR)
  258. #pragma warn -eas
  259. REGCONFIG(false);
  260. #pragma warn +eas
  261. #undef KEYEX
  262. if (Storage->OpenSubKey(L"Usage", false))
  263. {
  264. FUsage->Load(Storage);
  265. Storage->CloseSubKey();
  266. }
  267. if (FPermanentLogActions && FPermanentActionsLogFileName.IsEmpty() &&
  268. FPermanentLogging && !FPermanentLogFileName.IsEmpty())
  269. {
  270. FPermanentActionsLogFileName = FPermanentLogFileName;
  271. FPermanentLogging = false;
  272. FPermanentLogFileName = L"";
  273. }
  274. }
  275. //---------------------------------------------------------------------------
  276. void __fastcall TConfiguration::LoadAdmin(THierarchicalStorage * Storage)
  277. {
  278. FDisablePasswordStoring = Storage->ReadBool(L"DisablePasswordStoring", FDisablePasswordStoring);
  279. FForceBanners = Storage->ReadBool(L"ForceBanners", FForceBanners);
  280. FDisableAcceptingHostKeys = Storage->ReadBool(L"DisableAcceptingHostKeys", FDisableAcceptingHostKeys);
  281. FDefaultCollectUsage = Storage->ReadBool(L"DefaultCollectUsage", FDefaultCollectUsage);
  282. }
  283. //---------------------------------------------------------------------------
  284. void __fastcall TConfiguration::LoadFrom(THierarchicalStorage * Storage)
  285. {
  286. if (Storage->OpenSubKey(ConfigurationSubKey, false))
  287. {
  288. LoadData(Storage);
  289. Storage->CloseSubKey();
  290. }
  291. }
  292. //---------------------------------------------------------------------------
  293. void __fastcall TConfiguration::Load()
  294. {
  295. TGuard Guard(FCriticalSection);
  296. THierarchicalStorage * Storage = CreateScpStorage(false);
  297. try
  298. {
  299. Storage->AccessMode = smRead;
  300. LoadFrom(Storage);
  301. }
  302. __finally
  303. {
  304. delete Storage;
  305. }
  306. }
  307. //---------------------------------------------------------------------------
  308. void __fastcall TConfiguration::CopyData(THierarchicalStorage * Source,
  309. THierarchicalStorage * Target)
  310. {
  311. TStrings * Names = new TStringList();
  312. try
  313. {
  314. if (Source->OpenSubKey(ConfigurationSubKey, false))
  315. {
  316. if (Target->OpenSubKey(ConfigurationSubKey, true))
  317. {
  318. if (Source->OpenSubKey(L"CDCache", false))
  319. {
  320. if (Target->OpenSubKey(L"CDCache", true))
  321. {
  322. Names->Clear();
  323. Source->GetValueNames(Names);
  324. for (int Index = 0; Index < Names->Count; Index++)
  325. {
  326. Target->WriteBinaryData(Names->Strings[Index],
  327. Source->ReadBinaryData(Names->Strings[Index]));
  328. }
  329. Target->CloseSubKey();
  330. }
  331. Source->CloseSubKey();
  332. }
  333. if (Source->OpenSubKey(L"Banners", false))
  334. {
  335. if (Target->OpenSubKey(L"Banners", true))
  336. {
  337. Names->Clear();
  338. Source->GetValueNames(Names);
  339. for (int Index = 0; Index < Names->Count; Index++)
  340. {
  341. Target->WriteString(Names->Strings[Index],
  342. Source->ReadString(Names->Strings[Index], L""));
  343. }
  344. Target->CloseSubKey();
  345. }
  346. Source->CloseSubKey();
  347. }
  348. Target->CloseSubKey();
  349. }
  350. Source->CloseSubKey();
  351. }
  352. if (Source->OpenSubKey(SshHostKeysSubKey, false))
  353. {
  354. if (Target->OpenSubKey(SshHostKeysSubKey, true))
  355. {
  356. Names->Clear();
  357. Source->GetValueNames(Names);
  358. for (int Index = 0; Index < Names->Count; Index++)
  359. {
  360. Target->WriteStringRaw(Names->Strings[Index],
  361. Source->ReadStringRaw(Names->Strings[Index], L""));
  362. }
  363. Target->CloseSubKey();
  364. }
  365. Source->CloseSubKey();
  366. }
  367. }
  368. __finally
  369. {
  370. delete Names;
  371. }
  372. }
  373. //---------------------------------------------------------------------------
  374. void __fastcall TConfiguration::LoadDirectoryChangesCache(const UnicodeString SessionKey,
  375. TRemoteDirectoryChangesCache * DirectoryChangesCache)
  376. {
  377. THierarchicalStorage * Storage = CreateScpStorage(false);
  378. try
  379. {
  380. Storage->AccessMode = smRead;
  381. if (Storage->OpenSubKey(ConfigurationSubKey, false) &&
  382. Storage->OpenSubKey(L"CDCache", false) &&
  383. Storage->ValueExists(SessionKey))
  384. {
  385. DirectoryChangesCache->Deserialize(Storage->ReadBinaryData(SessionKey));
  386. }
  387. }
  388. __finally
  389. {
  390. delete Storage;
  391. }
  392. }
  393. //---------------------------------------------------------------------------
  394. void __fastcall TConfiguration::SaveDirectoryChangesCache(const UnicodeString SessionKey,
  395. TRemoteDirectoryChangesCache * DirectoryChangesCache)
  396. {
  397. THierarchicalStorage * Storage = CreateScpStorage(false);
  398. try
  399. {
  400. Storage->AccessMode = smReadWrite;
  401. if (Storage->OpenSubKey(ConfigurationSubKey, true) &&
  402. Storage->OpenSubKey(L"CDCache", true))
  403. {
  404. UnicodeString Data;
  405. DirectoryChangesCache->Serialize(Data);
  406. Storage->WriteBinaryData(SessionKey, Data);
  407. }
  408. }
  409. __finally
  410. {
  411. delete Storage;
  412. }
  413. }
  414. //---------------------------------------------------------------------------
  415. UnicodeString __fastcall TConfiguration::BannerHash(const UnicodeString & Banner)
  416. {
  417. RawByteString Result;
  418. Result.SetLength(16);
  419. md5checksum(
  420. reinterpret_cast<const char*>(Banner.c_str()), Banner.Length() * sizeof(wchar_t),
  421. (unsigned char*)Result.c_str());
  422. return BytesToHex(Result);
  423. }
  424. //---------------------------------------------------------------------------
  425. bool __fastcall TConfiguration::ShowBanner(const UnicodeString SessionKey,
  426. const UnicodeString & Banner)
  427. {
  428. bool Result;
  429. THierarchicalStorage * Storage = CreateScpStorage(false);
  430. try
  431. {
  432. Storage->AccessMode = smRead;
  433. Result =
  434. !Storage->OpenSubKey(ConfigurationSubKey, false) ||
  435. !Storage->OpenSubKey(L"Banners", false) ||
  436. !Storage->ValueExists(SessionKey) ||
  437. (Storage->ReadString(SessionKey, L"") != BannerHash(Banner));
  438. }
  439. __finally
  440. {
  441. delete Storage;
  442. }
  443. return Result;
  444. }
  445. //---------------------------------------------------------------------------
  446. void __fastcall TConfiguration::NeverShowBanner(const UnicodeString SessionKey,
  447. const UnicodeString & Banner)
  448. {
  449. THierarchicalStorage * Storage = CreateScpStorage(false);
  450. try
  451. {
  452. Storage->AccessMode = smReadWrite;
  453. if (Storage->OpenSubKey(ConfigurationSubKey, true) &&
  454. Storage->OpenSubKey(L"Banners", true))
  455. {
  456. Storage->WriteString(SessionKey, BannerHash(Banner));
  457. }
  458. }
  459. __finally
  460. {
  461. delete Storage;
  462. }
  463. }
  464. //---------------------------------------------------------------------------
  465. void __fastcall TConfiguration::Changed()
  466. {
  467. if (FUpdating == 0)
  468. {
  469. if (OnChange)
  470. {
  471. OnChange(this);
  472. }
  473. }
  474. else
  475. {
  476. FChanged = true;
  477. }
  478. }
  479. //---------------------------------------------------------------------------
  480. void __fastcall TConfiguration::BeginUpdate()
  481. {
  482. if (FUpdating == 0)
  483. {
  484. FChanged = false;
  485. }
  486. FUpdating++;
  487. // Greater value would probably indicate some nesting problem in code
  488. assert(FUpdating < 6);
  489. }
  490. //---------------------------------------------------------------------------
  491. void __fastcall TConfiguration::EndUpdate()
  492. {
  493. assert(FUpdating > 0);
  494. FUpdating--;
  495. if ((FUpdating == 0) && FChanged)
  496. {
  497. FChanged = false;
  498. Changed();
  499. }
  500. }
  501. //---------------------------------------------------------------------------
  502. void __fastcall TConfiguration::CleanupConfiguration()
  503. {
  504. try
  505. {
  506. CleanupRegistry(ConfigurationSubKey);
  507. if (Storage == stRegistry)
  508. {
  509. FDontSave = true;
  510. }
  511. }
  512. catch (Exception &E)
  513. {
  514. throw ExtException(&E, CLEANUP_CONFIG_ERROR);
  515. }
  516. }
  517. //---------------------------------------------------------------------------
  518. void __fastcall TConfiguration::CleanupRegistry(UnicodeString CleanupSubKey)
  519. {
  520. TRegistryStorage *Registry = new TRegistryStorage(RegistryStorageKey);
  521. try
  522. {
  523. Registry->RecursiveDeleteSubKey(CleanupSubKey);
  524. }
  525. __finally
  526. {
  527. delete Registry;
  528. }
  529. }
  530. //---------------------------------------------------------------------------
  531. void __fastcall TConfiguration::CleanupHostKeys()
  532. {
  533. try
  534. {
  535. CleanupRegistry(SshHostKeysSubKey);
  536. }
  537. catch (Exception &E)
  538. {
  539. throw ExtException(&E, CLEANUP_HOSTKEYS_ERROR);
  540. }
  541. }
  542. //---------------------------------------------------------------------------
  543. void __fastcall TConfiguration::CleanupRandomSeedFile()
  544. {
  545. try
  546. {
  547. DontSaveRandomSeed();
  548. if (FileExists(RandomSeedFileName))
  549. {
  550. if (!DeleteFile(RandomSeedFileName))
  551. {
  552. RaiseLastOSError();
  553. }
  554. }
  555. }
  556. catch (Exception &E)
  557. {
  558. throw ExtException(&E, CLEANUP_SEEDFILE_ERROR);
  559. }
  560. }
  561. //---------------------------------------------------------------------------
  562. void __fastcall TConfiguration::CleanupIniFile()
  563. {
  564. try
  565. {
  566. if (FileExists(IniFileStorageNameForReading))
  567. {
  568. if (!DeleteFile(IniFileStorageNameForReading))
  569. {
  570. RaiseLastOSError();
  571. }
  572. }
  573. if (Storage == stIniFile)
  574. {
  575. FDontSave = true;
  576. }
  577. }
  578. catch (Exception &E)
  579. {
  580. throw ExtException(&E, CLEANUP_INIFILE_ERROR);
  581. }
  582. }
  583. //---------------------------------------------------------------------------
  584. RawByteString __fastcall TConfiguration::EncryptPassword(UnicodeString Password, UnicodeString Key)
  585. {
  586. if (Password.IsEmpty())
  587. {
  588. return RawByteString();
  589. }
  590. else
  591. {
  592. return ::EncryptPassword(Password, Key);
  593. }
  594. }
  595. //---------------------------------------------------------------------------
  596. UnicodeString __fastcall TConfiguration::DecryptPassword(RawByteString Password, UnicodeString Key)
  597. {
  598. if (Password.IsEmpty())
  599. {
  600. return UnicodeString();
  601. }
  602. else
  603. {
  604. return ::DecryptPassword(Password, Key);
  605. }
  606. }
  607. //---------------------------------------------------------------------------
  608. RawByteString __fastcall TConfiguration::StronglyRecryptPassword(RawByteString Password, UnicodeString /*Key*/)
  609. {
  610. return Password;
  611. }
  612. //---------------------------------------------------------------------------
  613. UnicodeString __fastcall TConfiguration::GetOSVersionStr()
  614. {
  615. UnicodeString Result;
  616. OSVERSIONINFO OSVersionInfo;
  617. OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo);
  618. if (GetVersionEx(&OSVersionInfo) != 0)
  619. {
  620. Result = FORMAT(L"%d.%d.%d %s", (int(OSVersionInfo.dwMajorVersion),
  621. int(OSVersionInfo.dwMinorVersion), int(OSVersionInfo.dwBuildNumber),
  622. OSVersionInfo.szCSDVersion)).Trim();
  623. }
  624. return Result;
  625. }
  626. //---------------------------------------------------------------------------
  627. TVSFixedFileInfo *__fastcall TConfiguration::GetFixedApplicationInfo()
  628. {
  629. return GetFixedFileInfo(ApplicationInfo);
  630. }
  631. //---------------------------------------------------------------------------
  632. int __fastcall TConfiguration::GetCompoundVersion()
  633. {
  634. TVSFixedFileInfo * FileInfo = FixedApplicationInfo;
  635. return CalculateCompoundVersion(
  636. HIWORD(FileInfo->dwFileVersionMS), LOWORD(FileInfo->dwFileVersionMS),
  637. HIWORD(FileInfo->dwFileVersionLS), LOWORD(FileInfo->dwFileVersionLS));
  638. }
  639. //---------------------------------------------------------------------------
  640. UnicodeString __fastcall TConfiguration::ModuleFileName()
  641. {
  642. return ParamStr(0);
  643. }
  644. //---------------------------------------------------------------------------
  645. void * __fastcall TConfiguration::GetFileApplicationInfo(const UnicodeString FileName)
  646. {
  647. void * Result;
  648. if (FileName.IsEmpty())
  649. {
  650. if (!FApplicationInfo)
  651. {
  652. FApplicationInfo = CreateFileInfo(ModuleFileName());
  653. }
  654. Result = FApplicationInfo;
  655. }
  656. else
  657. {
  658. Result = CreateFileInfo(FileName);
  659. }
  660. return Result;
  661. }
  662. //---------------------------------------------------------------------------
  663. void * __fastcall TConfiguration::GetApplicationInfo()
  664. {
  665. return GetFileApplicationInfo("");
  666. }
  667. //---------------------------------------------------------------------------
  668. UnicodeString __fastcall TConfiguration::GetFileProductName(const UnicodeString FileName)
  669. {
  670. return GetFileFileInfoString(L"ProductName", FileName);
  671. }
  672. //---------------------------------------------------------------------------
  673. UnicodeString __fastcall TConfiguration::GetFileCompanyName(const UnicodeString FileName)
  674. {
  675. return GetFileFileInfoString(L"CompanyName", FileName);
  676. }
  677. //---------------------------------------------------------------------------
  678. UnicodeString __fastcall TConfiguration::GetProductName()
  679. {
  680. return GetFileProductName(L"");
  681. }
  682. //---------------------------------------------------------------------------
  683. UnicodeString __fastcall TConfiguration::GetCompanyName()
  684. {
  685. return GetFileCompanyName(L"");
  686. }
  687. //---------------------------------------------------------------------------
  688. UnicodeString __fastcall TConfiguration::GetFileProductVersion(const UnicodeString FileName)
  689. {
  690. return TrimVersion(GetFileFileInfoString(L"ProductVersion", FileName));
  691. }
  692. //---------------------------------------------------------------------------
  693. UnicodeString __fastcall TConfiguration::GetFileDescription(const UnicodeString & FileName)
  694. {
  695. return GetFileFileInfoString(L"FileDescription", FileName);
  696. }
  697. //---------------------------------------------------------------------------
  698. UnicodeString __fastcall TConfiguration::GetProductVersion()
  699. {
  700. return GetFileProductVersion(L"");
  701. }
  702. //---------------------------------------------------------------------------
  703. UnicodeString __fastcall TConfiguration::TrimVersion(UnicodeString Version)
  704. {
  705. while ((Version.Pos(L".") != Version.LastDelimiter(L".")) &&
  706. (Version.SubString(Version.Length() - 1, 2) == L".0"))
  707. {
  708. Version.SetLength(Version.Length() - 2);
  709. }
  710. return Version;
  711. }
  712. //---------------------------------------------------------------------------
  713. UnicodeString __fastcall TConfiguration::GetVersionStr()
  714. {
  715. TGuard Guard(FCriticalSection);
  716. try
  717. {
  718. TVSFixedFileInfo * Info = FixedApplicationInfo;
  719. return FMTLOAD(VERSION, (
  720. HIWORD(Info->dwFileVersionMS),
  721. LOWORD(Info->dwFileVersionMS),
  722. HIWORD(Info->dwFileVersionLS),
  723. LOWORD(Info->dwFileVersionLS)));
  724. }
  725. catch (Exception &E)
  726. {
  727. throw ExtException(&E, L"Can't get application version");
  728. }
  729. }
  730. //---------------------------------------------------------------------------
  731. UnicodeString __fastcall TConfiguration::GetVersion()
  732. {
  733. TGuard Guard(FCriticalSection);
  734. try
  735. {
  736. TVSFixedFileInfo * Info = FixedApplicationInfo;
  737. UnicodeString Result;
  738. Result = TrimVersion(FORMAT(L"%d.%d.%d", (
  739. HIWORD(Info->dwFileVersionMS),
  740. LOWORD(Info->dwFileVersionMS),
  741. HIWORD(Info->dwFileVersionLS))));
  742. return Result;
  743. }
  744. catch (Exception &E)
  745. {
  746. throw ExtException(&E, L"Can't get application version");
  747. }
  748. }
  749. //---------------------------------------------------------------------------
  750. UnicodeString __fastcall TConfiguration::GetFileFileInfoString(const UnicodeString Key,
  751. const UnicodeString FileName)
  752. {
  753. TGuard Guard(FCriticalSection);
  754. UnicodeString Result;
  755. void * Info = GetFileApplicationInfo(FileName);
  756. try
  757. {
  758. if ((Info != NULL) && (GetTranslationCount(Info) > 0))
  759. {
  760. TTranslation Translation;
  761. Translation = GetTranslation(Info, 0);
  762. Result = ::GetFileInfoString(Info, Translation, Key);
  763. }
  764. else
  765. {
  766. assert(!FileName.IsEmpty());
  767. }
  768. }
  769. __finally
  770. {
  771. if (!FileName.IsEmpty())
  772. {
  773. FreeFileInfo(Info);
  774. }
  775. }
  776. return Result;
  777. }
  778. //---------------------------------------------------------------------------
  779. UnicodeString __fastcall TConfiguration::GetFileInfoString(const UnicodeString Key)
  780. {
  781. return GetFileFileInfoString(Key, L"");
  782. }
  783. //---------------------------------------------------------------------------
  784. UnicodeString __fastcall TConfiguration::GetRegistryStorageKey()
  785. {
  786. return GetRegistryKey();
  787. }
  788. //---------------------------------------------------------------------------
  789. void __fastcall TConfiguration::SetNulStorage()
  790. {
  791. FStorage = stNul;
  792. }
  793. //---------------------------------------------------------------------------
  794. void __fastcall TConfiguration::SetDefaultStorage()
  795. {
  796. FStorage = stDetect;
  797. }
  798. //---------------------------------------------------------------------------
  799. void __fastcall TConfiguration::SetIniFileStorageName(UnicodeString value)
  800. {
  801. FIniFileStorageName = value;
  802. FStorage = stIniFile;
  803. }
  804. //---------------------------------------------------------------------------
  805. UnicodeString __fastcall TConfiguration::GetIniFileStorageNameForReading()
  806. {
  807. return GetIniFileStorageName(true);
  808. }
  809. //---------------------------------------------------------------------------
  810. UnicodeString __fastcall TConfiguration::GetIniFileStorageNameForReadingWritting()
  811. {
  812. return GetIniFileStorageName(false);
  813. }
  814. //---------------------------------------------------------------------------
  815. UnicodeString __fastcall TConfiguration::GetIniFileStorageName(bool ReadingOnly)
  816. {
  817. if (FIniFileStorageName.IsEmpty())
  818. {
  819. UnicodeString ProgramPath = ParamStr(0);
  820. UnicodeString ProgramIniPath = ChangeFileExt(ProgramPath, L".ini");
  821. UnicodeString IniPath;
  822. if (FileExists(ProgramIniPath))
  823. {
  824. IniPath = ProgramIniPath;
  825. }
  826. else
  827. {
  828. UnicodeString AppDataIniPath =
  829. IncludeTrailingBackslash(GetShellFolderPath(CSIDL_APPDATA)) +
  830. ExtractFileName(ProgramIniPath);
  831. if (FileExists(AppDataIniPath))
  832. {
  833. IniPath = AppDataIniPath;
  834. }
  835. else
  836. {
  837. // avoid expensive test if we are interested in existing files only
  838. if (!ReadingOnly && (FProgramIniPathWrittable < 0))
  839. {
  840. UnicodeString ProgramDir = ExtractFilePath(ProgramPath);
  841. FProgramIniPathWrittable = IsDirectoryWriteable(ProgramDir) ? 1 : 0;
  842. }
  843. // does not really matter what we return when < 0
  844. IniPath = (FProgramIniPathWrittable == 0) ? AppDataIniPath : ProgramIniPath;
  845. }
  846. }
  847. if (FVirtualIniFileStorageName.IsEmpty() &&
  848. TPath::IsDriveRooted(IniPath))
  849. {
  850. UnicodeString LocalAppDataPath = GetShellFolderPath(CSIDL_LOCAL_APPDATA);
  851. // virtual store for non-system drives have a different virtual store,
  852. // do not bother about them
  853. if (TPath::IsDriveRooted(LocalAppDataPath) &&
  854. SameText(ExtractFileDrive(IniPath), ExtractFileDrive(LocalAppDataPath)))
  855. {
  856. FVirtualIniFileStorageName =
  857. IncludeTrailingBackslash(LocalAppDataPath) +
  858. L"VirtualStore\\" +
  859. IniPath.SubString(4, IniPath.Length() - 3);
  860. }
  861. }
  862. if (!FVirtualIniFileStorageName.IsEmpty() &&
  863. FileExists(FVirtualIniFileStorageName))
  864. {
  865. return FVirtualIniFileStorageName;
  866. }
  867. else
  868. {
  869. return IniPath;
  870. }
  871. }
  872. else
  873. {
  874. return FIniFileStorageName;
  875. }
  876. }
  877. //---------------------------------------------------------------------------
  878. UnicodeString __fastcall TConfiguration::GetPuttySessionsKey()
  879. {
  880. return PuttyRegistryStorageKey + L"\\Sessions";
  881. }
  882. //---------------------------------------------------------------------------
  883. UnicodeString __fastcall TConfiguration::GetStoredSessionsSubKey()
  884. {
  885. return L"Sessions";
  886. }
  887. //---------------------------------------------------------------------------
  888. UnicodeString __fastcall TConfiguration::GetSshHostKeysSubKey()
  889. {
  890. return L"SshHostKeys";
  891. }
  892. //---------------------------------------------------------------------------
  893. UnicodeString __fastcall TConfiguration::GetConfigurationSubKey()
  894. {
  895. return L"Configuration";
  896. }
  897. //---------------------------------------------------------------------------
  898. UnicodeString __fastcall TConfiguration::GetRootKeyStr()
  899. {
  900. return RootKeyToStr(HKEY_CURRENT_USER);
  901. }
  902. //---------------------------------------------------------------------------
  903. bool __fastcall TConfiguration::GetGSSAPIInstalled()
  904. {
  905. return HasGSSAPI();
  906. }
  907. //---------------------------------------------------------------------------
  908. void __fastcall TConfiguration::SetStorage(TStorage value)
  909. {
  910. if (FStorage != value)
  911. {
  912. THierarchicalStorage * SourceStorage = NULL;
  913. THierarchicalStorage * TargetStorage = NULL;
  914. try
  915. {
  916. SourceStorage = CreateScpStorage(false);
  917. SourceStorage->AccessMode = smRead;
  918. FStorage = value;
  919. TargetStorage = CreateScpStorage(false);
  920. TargetStorage->AccessMode = smReadWrite;
  921. TargetStorage->Explicit = true;
  922. // copy before save as it removes the ini file,
  923. // when switching from ini to registry
  924. CopyData(SourceStorage, TargetStorage);
  925. }
  926. __finally
  927. {
  928. delete SourceStorage;
  929. delete TargetStorage;
  930. }
  931. // save all and explicit
  932. Save(true, true);
  933. }
  934. }
  935. //---------------------------------------------------------------------------
  936. void __fastcall TConfiguration::Saved()
  937. {
  938. // nothing
  939. }
  940. //---------------------------------------------------------------------------
  941. TStorage __fastcall TConfiguration::GetStorage()
  942. {
  943. if (FStorage == stDetect)
  944. {
  945. if (FileExists(IniFileStorageNameForReading))
  946. {
  947. FStorage = stIniFile;
  948. }
  949. else
  950. {
  951. FStorage = stRegistry;
  952. }
  953. }
  954. return FStorage;
  955. }
  956. //---------------------------------------------------------------------------
  957. void __fastcall TConfiguration::SetRandomSeedFile(UnicodeString value)
  958. {
  959. if (RandomSeedFile != value)
  960. {
  961. UnicodeString PrevRandomSeedFileName = RandomSeedFileName;
  962. FRandomSeedFile = value;
  963. // never allow empty seed file to avoid Putty trying to reinitialize the path
  964. if (RandomSeedFileName.IsEmpty())
  965. {
  966. FRandomSeedFile = FDefaultRandomSeedFile;
  967. }
  968. if (!PrevRandomSeedFileName.IsEmpty() &&
  969. (PrevRandomSeedFileName != RandomSeedFileName) &&
  970. FileExists(PrevRandomSeedFileName))
  971. {
  972. // ignore any error
  973. DeleteFile(PrevRandomSeedFileName);
  974. }
  975. }
  976. }
  977. //---------------------------------------------------------------------
  978. UnicodeString __fastcall TConfiguration::GetRandomSeedFileName()
  979. {
  980. return StripPathQuotes(ExpandEnvironmentVariables(FRandomSeedFile)).Trim();
  981. }
  982. //---------------------------------------------------------------------
  983. void __fastcall TConfiguration::SetExternalIpAddress(UnicodeString value)
  984. {
  985. SET_CONFIG_PROPERTY(ExternalIpAddress);
  986. }
  987. //---------------------------------------------------------------------
  988. void __fastcall TConfiguration::SetTryFtpWhenSshFails(bool value)
  989. {
  990. SET_CONFIG_PROPERTY(TryFtpWhenSshFails);
  991. }
  992. //---------------------------------------------------------------------
  993. void __fastcall TConfiguration::SetPuttyRegistryStorageKey(UnicodeString value)
  994. {
  995. SET_CONFIG_PROPERTY(PuttyRegistryStorageKey);
  996. }
  997. //---------------------------------------------------------------------------
  998. TEOLType __fastcall TConfiguration::GetLocalEOLType()
  999. {
  1000. return eolCRLF;
  1001. }
  1002. //---------------------------------------------------------------------
  1003. bool __fastcall TConfiguration::GetCollectUsage()
  1004. {
  1005. return FUsage->Collect;
  1006. }
  1007. //---------------------------------------------------------------------
  1008. void __fastcall TConfiguration::SetCollectUsage(bool value)
  1009. {
  1010. FUsage->Collect = value;
  1011. }
  1012. //---------------------------------------------------------------------
  1013. void __fastcall TConfiguration::TemporaryLogging(const UnicodeString ALogFileName)
  1014. {
  1015. if (SameText(ExtractFileExt(ALogFileName), L".xml"))
  1016. {
  1017. TemporaryActionsLogging(ALogFileName);
  1018. }
  1019. else
  1020. {
  1021. FLogging = true;
  1022. FLogFileName = ALogFileName;
  1023. UpdateActualLogProtocol();
  1024. }
  1025. }
  1026. //---------------------------------------------------------------------
  1027. void __fastcall TConfiguration::TemporaryActionsLogging(const UnicodeString ALogFileName)
  1028. {
  1029. FLogActions = true;
  1030. FActionsLogFileName = ALogFileName;
  1031. }
  1032. //---------------------------------------------------------------------
  1033. void __fastcall TConfiguration::SetLogging(bool value)
  1034. {
  1035. if (Logging != value)
  1036. {
  1037. FPermanentLogging = value;
  1038. FLogging = value;
  1039. UpdateActualLogProtocol();
  1040. Changed();
  1041. }
  1042. }
  1043. //---------------------------------------------------------------------
  1044. void __fastcall TConfiguration::SetLogFileName(UnicodeString value)
  1045. {
  1046. if (LogFileName != value)
  1047. {
  1048. FPermanentLogFileName = value;
  1049. FLogFileName = value;
  1050. Changed();
  1051. }
  1052. }
  1053. //---------------------------------------------------------------------
  1054. void __fastcall TConfiguration::SetActionsLogFileName(UnicodeString value)
  1055. {
  1056. if (ActionsLogFileName != value)
  1057. {
  1058. FPermanentActionsLogFileName = value;
  1059. FActionsLogFileName = value;
  1060. Changed();
  1061. }
  1062. }
  1063. //---------------------------------------------------------------------
  1064. bool __fastcall TConfiguration::GetLogToFile()
  1065. {
  1066. return !LogFileName.IsEmpty();
  1067. }
  1068. //---------------------------------------------------------------------
  1069. void __fastcall TConfiguration::UpdateActualLogProtocol()
  1070. {
  1071. FActualLogProtocol = FLogging ? FLogProtocol : 0;
  1072. }
  1073. //---------------------------------------------------------------------
  1074. void __fastcall TConfiguration::SetLogProtocol(int value)
  1075. {
  1076. SET_CONFIG_PROPERTY(LogProtocol);
  1077. UpdateActualLogProtocol();
  1078. }
  1079. //---------------------------------------------------------------------
  1080. void __fastcall TConfiguration::SetLogActions(bool value)
  1081. {
  1082. if (LogActions != value)
  1083. {
  1084. FPermanentLogActions = value;
  1085. FLogActions = value;
  1086. Changed();
  1087. }
  1088. }
  1089. //---------------------------------------------------------------------
  1090. void __fastcall TConfiguration::SetLogFileAppend(bool value)
  1091. {
  1092. SET_CONFIG_PROPERTY(LogFileAppend);
  1093. }
  1094. //---------------------------------------------------------------------
  1095. void __fastcall TConfiguration::SetLogWindowLines(int value)
  1096. {
  1097. SET_CONFIG_PROPERTY(LogWindowLines);
  1098. }
  1099. //---------------------------------------------------------------------
  1100. void __fastcall TConfiguration::SetLogWindowComplete(bool value)
  1101. {
  1102. if (value != LogWindowComplete)
  1103. {
  1104. LogWindowLines = value ? 0 : 50;
  1105. Changed();
  1106. }
  1107. }
  1108. //---------------------------------------------------------------------
  1109. bool __fastcall TConfiguration::GetLogWindowComplete()
  1110. {
  1111. return (bool)(LogWindowLines == 0);
  1112. }
  1113. //---------------------------------------------------------------------
  1114. UnicodeString __fastcall TConfiguration::GetDefaultLogFileName()
  1115. {
  1116. return L"%TEMP%\\!S.log";
  1117. }
  1118. //---------------------------------------------------------------------------
  1119. void __fastcall TConfiguration::SetConfirmOverwriting(bool value)
  1120. {
  1121. TGuard Guard(FCriticalSection);
  1122. SET_CONFIG_PROPERTY(ConfirmOverwriting);
  1123. }
  1124. //---------------------------------------------------------------------------
  1125. bool __fastcall TConfiguration::GetConfirmOverwriting()
  1126. {
  1127. TGuard Guard(FCriticalSection);
  1128. return FConfirmOverwriting;
  1129. }
  1130. //---------------------------------------------------------------------------
  1131. void __fastcall TConfiguration::SetConfirmResume(bool value)
  1132. {
  1133. TGuard Guard(FCriticalSection);
  1134. SET_CONFIG_PROPERTY(ConfirmResume);
  1135. }
  1136. //---------------------------------------------------------------------------
  1137. bool __fastcall TConfiguration::GetConfirmResume()
  1138. {
  1139. TGuard Guard(FCriticalSection);
  1140. return FConfirmResume;
  1141. }
  1142. //---------------------------------------------------------------------------
  1143. void __fastcall TConfiguration::SetAutoReadDirectoryAfterOp(bool value)
  1144. {
  1145. TGuard Guard(FCriticalSection);
  1146. SET_CONFIG_PROPERTY(AutoReadDirectoryAfterOp);
  1147. }
  1148. //---------------------------------------------------------------------------
  1149. bool __fastcall TConfiguration::GetAutoReadDirectoryAfterOp()
  1150. {
  1151. TGuard Guard(FCriticalSection);
  1152. return FAutoReadDirectoryAfterOp;
  1153. }
  1154. //---------------------------------------------------------------------------
  1155. UnicodeString __fastcall TConfiguration::GetTimeFormat()
  1156. {
  1157. return L"h:nn:ss";
  1158. }
  1159. //---------------------------------------------------------------------------
  1160. UnicodeString __fastcall TConfiguration::GetPartialExt() const
  1161. {
  1162. return PARTIAL_EXT;
  1163. }
  1164. //---------------------------------------------------------------------------
  1165. UnicodeString __fastcall TConfiguration::GetDefaultKeyFile()
  1166. {
  1167. return L"";
  1168. }
  1169. //---------------------------------------------------------------------------
  1170. bool __fastcall TConfiguration::GetRememberPassword()
  1171. {
  1172. return false;
  1173. }
  1174. //---------------------------------------------------------------------------
  1175. void __fastcall TConfiguration::SetSessionReopenAuto(int value)
  1176. {
  1177. SET_CONFIG_PROPERTY(SessionReopenAuto);
  1178. }
  1179. //---------------------------------------------------------------------------
  1180. void __fastcall TConfiguration::SetSessionReopenBackground(int value)
  1181. {
  1182. SET_CONFIG_PROPERTY(SessionReopenBackground);
  1183. }
  1184. //---------------------------------------------------------------------------
  1185. void __fastcall TConfiguration::SetSessionReopenTimeout(int value)
  1186. {
  1187. SET_CONFIG_PROPERTY(SessionReopenTimeout);
  1188. }
  1189. //---------------------------------------------------------------------------
  1190. void __fastcall TConfiguration::SetSessionReopenAutoStall(int value)
  1191. {
  1192. SET_CONFIG_PROPERTY(SessionReopenAutoStall);
  1193. }
  1194. //---------------------------------------------------------------------------
  1195. void __fastcall TConfiguration::SetTunnelLocalPortNumberLow(int value)
  1196. {
  1197. SET_CONFIG_PROPERTY(TunnelLocalPortNumberLow);
  1198. }
  1199. //---------------------------------------------------------------------------
  1200. void __fastcall TConfiguration::SetTunnelLocalPortNumberHigh(int value)
  1201. {
  1202. SET_CONFIG_PROPERTY(TunnelLocalPortNumberHigh);
  1203. }
  1204. //---------------------------------------------------------------------------
  1205. void __fastcall TConfiguration::SetCacheDirectoryChangesMaxSize(int value)
  1206. {
  1207. SET_CONFIG_PROPERTY(CacheDirectoryChangesMaxSize);
  1208. }
  1209. //---------------------------------------------------------------------------
  1210. void __fastcall TConfiguration::SetShowFtpWelcomeMessage(bool value)
  1211. {
  1212. SET_CONFIG_PROPERTY(ShowFtpWelcomeMessage);
  1213. }
  1214. //---------------------------------------------------------------------------
  1215. //---------------------------------------------------------------------------
  1216. void __fastcall TShortCuts::Add(TShortCut ShortCut)
  1217. {
  1218. FShortCuts.insert(ShortCut);
  1219. }
  1220. //---------------------------------------------------------------------------
  1221. bool __fastcall TShortCuts::Has(TShortCut ShortCut) const
  1222. {
  1223. return (FShortCuts.count(ShortCut) != 0);
  1224. }