SessionInfo.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <stdio.h>
  5. #include <lmcons.h>
  6. #define SECURITY_WIN32
  7. #include <sspi.h>
  8. #include <secext.h>
  9. #include "Common.h"
  10. #include "SessionInfo.h"
  11. #include "Exceptions.h"
  12. #include "TextsCore.h"
  13. //---------------------------------------------------------------------------
  14. #pragma package(smart_init)
  15. //---------------------------------------------------------------------------
  16. UnicodeString __fastcall DoXmlEscape(UnicodeString Str, bool NewLine)
  17. {
  18. for (int i = 1; i <= Str.Length(); i++)
  19. {
  20. const wchar_t * Repl = NULL;
  21. switch (Str[i])
  22. {
  23. case L'&':
  24. Repl = L"amp;";
  25. break;
  26. case L'>':
  27. Repl = L"gt;";
  28. break;
  29. case L'<':
  30. Repl = L"lt;";
  31. break;
  32. case L'"':
  33. Repl = L"quot;";
  34. break;
  35. case L'\n':
  36. if (NewLine)
  37. {
  38. Repl = L"#10;";
  39. }
  40. break;
  41. case L'\r':
  42. Str.Delete(i, 1);
  43. i--;
  44. break;
  45. }
  46. if (Repl != NULL)
  47. {
  48. Str[i] = L'&';
  49. Str.Insert(Repl, i + 1);
  50. i += wcslen(Repl);
  51. }
  52. }
  53. return Str;
  54. }
  55. //---------------------------------------------------------------------------
  56. UnicodeString __fastcall XmlEscape(UnicodeString Str)
  57. {
  58. return DoXmlEscape(Str, false);
  59. }
  60. //---------------------------------------------------------------------------
  61. UnicodeString __fastcall XmlAttributeEscape(UnicodeString Str)
  62. {
  63. return DoXmlEscape(Str, true);
  64. }
  65. //---------------------------------------------------------------------------
  66. TStrings * __fastcall ExceptionToMessages(Exception * E)
  67. {
  68. TStrings * Result = NULL;
  69. UnicodeString Message;
  70. if (ExceptionMessage(E, Message))
  71. {
  72. Result = new TStringList();
  73. Result->Add(Message);
  74. ExtException * EE = dynamic_cast<ExtException *>(E);
  75. if ((EE != NULL) && (EE->MoreMessages != NULL))
  76. {
  77. Result->AddStrings(EE->MoreMessages);
  78. }
  79. }
  80. return Result;
  81. }
  82. //---------------------------------------------------------------------------
  83. //---------------------------------------------------------------------------
  84. #pragma warn -inl
  85. class TSessionActionRecord
  86. {
  87. public:
  88. __fastcall TSessionActionRecord(TActionLog * Log, TLogAction Action) :
  89. FLog(Log),
  90. FAction(Action),
  91. FState(Opened),
  92. FRecursive(false),
  93. FErrorMessages(NULL),
  94. FNames(new TStringList()),
  95. FValues(new TStringList()),
  96. FFileList(NULL),
  97. FFile(NULL)
  98. {
  99. FLog->AddPendingAction(this);
  100. }
  101. __fastcall ~TSessionActionRecord()
  102. {
  103. delete FErrorMessages;
  104. delete FNames;
  105. delete FValues;
  106. delete FFileList;
  107. delete FFile;
  108. }
  109. void __fastcall Restart()
  110. {
  111. FState = Opened;
  112. FRecursive = false;
  113. delete FErrorMessages;
  114. FErrorMessages = NULL;
  115. delete FFileList;
  116. FFileList = NULL;
  117. delete FFile;
  118. FFile = NULL;
  119. FNames->Clear();
  120. FValues->Clear();
  121. }
  122. bool __fastcall Record()
  123. {
  124. bool Result = (FState != Opened);
  125. if (Result)
  126. {
  127. if (FLog->FLogging && (FState != Cancelled))
  128. {
  129. const wchar_t * Name = ActionName();
  130. UnicodeString Attrs;
  131. if (FRecursive)
  132. {
  133. Attrs = L" recursive=\"true\"";
  134. }
  135. FLog->AddIndented(FORMAT(L"<%s%s>", (Name, Attrs)));
  136. for (int Index = 0; Index < FNames->Count; Index++)
  137. {
  138. UnicodeString Value = FValues->Strings[Index];
  139. if (Value.IsEmpty())
  140. {
  141. FLog->AddIndented(FORMAT(L" <%s />", (FNames->Strings[Index])));
  142. }
  143. else
  144. {
  145. FLog->AddIndented(FORMAT(L" <%s value=\"%s\" />",
  146. (FNames->Strings[Index], XmlAttributeEscape(Value))));
  147. }
  148. }
  149. if (FFileList != NULL)
  150. {
  151. FLog->AddIndented(L" <files>");
  152. for (int Index = 0; Index < FFileList->Count; Index++)
  153. {
  154. TRemoteFile * File = FFileList->Files[Index];
  155. FLog->AddIndented(L" <file>");
  156. FLog->AddIndented(FORMAT(L" <filename value=\"%s\" />", (XmlAttributeEscape(File->FileName))));
  157. FLog->AddIndented(FORMAT(L" <type value=\"%s\" />", (XmlAttributeEscape(File->Type))));
  158. if (!File->IsDirectory)
  159. {
  160. FLog->AddIndented(FORMAT(L" <size value=\"%s\" />", (IntToStr(File->Size))));
  161. }
  162. FLog->AddIndented(FORMAT(L" <modification value=\"%s\" />", (StandardTimestamp(File->Modification))));
  163. FLog->AddIndented(FORMAT(L" <permissions value=\"%s\" />", (XmlAttributeEscape(File->Rights->Text))));
  164. FLog->AddIndented(L" </file>");
  165. }
  166. FLog->AddIndented(L" </files>");
  167. }
  168. if (FFile != NULL)
  169. {
  170. FLog->AddIndented(L" <file>");
  171. FLog->AddIndented(FORMAT(L" <type value=\"%s\" />", (XmlAttributeEscape(FFile->Type))));
  172. if (!FFile->IsDirectory)
  173. {
  174. FLog->AddIndented(FORMAT(L" <size value=\"%s\" />", (IntToStr(FFile->Size))));
  175. }
  176. FLog->AddIndented(FORMAT(L" <modification value=\"%s\" />", (StandardTimestamp(FFile->Modification))));
  177. FLog->AddIndented(FORMAT(L" <permissions value=\"%s\" />", (XmlAttributeEscape(FFile->Rights->Text))));
  178. FLog->AddIndented(L" </file>");
  179. }
  180. if (FState == RolledBack)
  181. {
  182. if (FErrorMessages != NULL)
  183. {
  184. FLog->AddIndented(L" <result success=\"false\">");
  185. FLog->AddMessages(L" ", FErrorMessages);
  186. FLog->AddIndented(L" </result>");
  187. }
  188. else
  189. {
  190. FLog->AddIndented(L" <result success=\"false\" />");
  191. }
  192. }
  193. else
  194. {
  195. FLog->AddIndented(L" <result success=\"true\" />");
  196. }
  197. FLog->AddIndented(FORMAT(L"</%s>", (Name)));
  198. }
  199. delete this;
  200. }
  201. return Result;
  202. }
  203. void __fastcall Commit()
  204. {
  205. Close(Committed);
  206. }
  207. void __fastcall Rollback(Exception * E)
  208. {
  209. assert(FErrorMessages == NULL);
  210. FErrorMessages = ExceptionToMessages(E);
  211. Close(RolledBack);
  212. }
  213. void __fastcall Cancel()
  214. {
  215. Close(Cancelled);
  216. }
  217. void __fastcall FileName(const UnicodeString & FileName)
  218. {
  219. Parameter(L"filename", FileName);
  220. }
  221. void __fastcall Destination(const UnicodeString & Destination)
  222. {
  223. Parameter(L"destination", Destination);
  224. }
  225. void __fastcall Rights(const TRights & Rights)
  226. {
  227. Parameter(L"permissions", Rights.Text);
  228. }
  229. void __fastcall Modification(const TDateTime & DateTime)
  230. {
  231. Parameter(L"modification", StandardTimestamp(DateTime));
  232. }
  233. void __fastcall Recursive()
  234. {
  235. FRecursive = true;
  236. }
  237. void __fastcall Command(const UnicodeString & Command)
  238. {
  239. Parameter(L"command", Command);
  240. }
  241. void __fastcall AddOutput(UnicodeString Output, bool StdError)
  242. {
  243. const wchar_t * Name = (StdError ? L"erroroutput" : L"output");
  244. int Index = FNames->IndexOf(Name);
  245. if (Index >= 0)
  246. {
  247. FValues->Strings[Index] = FValues->Strings[Index] + L"\r\n" + Output;
  248. }
  249. else
  250. {
  251. Parameter(Name, Output);
  252. }
  253. }
  254. void __fastcall FileList(TRemoteFileList * FileList)
  255. {
  256. if (FFileList == NULL)
  257. {
  258. FFileList = new TRemoteFileList();
  259. }
  260. FileList->DuplicateTo(FFileList);
  261. }
  262. void __fastcall File(TRemoteFile * File)
  263. {
  264. if (FFile != NULL)
  265. {
  266. delete FFile;
  267. }
  268. FFile = File->Duplicate(true);
  269. }
  270. protected:
  271. enum TState { Opened, Committed, RolledBack, Cancelled };
  272. inline void __fastcall Close(TState State)
  273. {
  274. assert(FState == Opened);
  275. FState = State;
  276. FLog->RecordPendingActions();
  277. }
  278. const wchar_t * __fastcall ActionName()
  279. {
  280. switch (FAction)
  281. {
  282. case laUpload: return L"upload";
  283. case laDownload: return L"download";
  284. case laTouch: return L"touch";
  285. case laChmod: return L"chmod";
  286. case laMkdir: return L"mkdir";
  287. case laRm: return L"rm";
  288. case laMv: return L"mv";
  289. case laCall: return L"call";
  290. case laLs: return L"ls";
  291. case laStat: return L"stat";
  292. default: assert(false); return L"";
  293. }
  294. }
  295. void __fastcall Parameter(const UnicodeString & Name, const UnicodeString & Value = L"")
  296. {
  297. FNames->Add(Name);
  298. FValues->Add(Value);
  299. }
  300. private:
  301. TActionLog * FLog;
  302. TLogAction FAction;
  303. TState FState;
  304. bool FRecursive;
  305. TStrings * FErrorMessages;
  306. TStrings * FNames;
  307. TStrings * FValues;
  308. TRemoteFileList * FFileList;
  309. TRemoteFile * FFile;
  310. };
  311. #pragma warn .inl
  312. //---------------------------------------------------------------------------
  313. //---------------------------------------------------------------------------
  314. __fastcall TSessionAction::TSessionAction(TActionLog * Log, TLogAction Action)
  315. {
  316. if (Log->FLogging)
  317. {
  318. FRecord = new TSessionActionRecord(Log, Action);
  319. }
  320. else
  321. {
  322. FRecord = NULL;
  323. }
  324. }
  325. //---------------------------------------------------------------------------
  326. __fastcall TSessionAction::~TSessionAction()
  327. {
  328. if (FRecord != NULL)
  329. {
  330. Commit();
  331. }
  332. }
  333. //---------------------------------------------------------------------------
  334. void __fastcall TSessionAction::Restart()
  335. {
  336. if (FRecord != NULL)
  337. {
  338. FRecord->Restart();
  339. }
  340. }
  341. //---------------------------------------------------------------------------
  342. void __fastcall TSessionAction::Commit()
  343. {
  344. if (FRecord != NULL)
  345. {
  346. TSessionActionRecord * Record = FRecord;
  347. FRecord = NULL;
  348. Record->Commit();
  349. }
  350. }
  351. //---------------------------------------------------------------------------
  352. void __fastcall TSessionAction::Rollback(Exception * E)
  353. {
  354. if (FRecord != NULL)
  355. {
  356. TSessionActionRecord * Record = FRecord;
  357. FRecord = NULL;
  358. Record->Rollback(E);
  359. }
  360. }
  361. //---------------------------------------------------------------------------
  362. void __fastcall TSessionAction::Cancel()
  363. {
  364. if (FRecord != NULL)
  365. {
  366. TSessionActionRecord * Record = FRecord;
  367. FRecord = NULL;
  368. Record->Cancel();
  369. }
  370. }
  371. //---------------------------------------------------------------------------
  372. //---------------------------------------------------------------------------
  373. __fastcall TFileSessionAction::TFileSessionAction(TActionLog * Log, TLogAction Action) :
  374. TSessionAction(Log, Action)
  375. {
  376. }
  377. //---------------------------------------------------------------------------
  378. __fastcall TFileSessionAction::TFileSessionAction(
  379. TActionLog * Log, TLogAction Action, const UnicodeString & AFileName) :
  380. TSessionAction(Log, Action)
  381. {
  382. FileName(AFileName);
  383. }
  384. //---------------------------------------------------------------------------
  385. void __fastcall TFileSessionAction::FileName(const UnicodeString & FileName)
  386. {
  387. if (FRecord != NULL)
  388. {
  389. FRecord->FileName(FileName);
  390. }
  391. }
  392. //---------------------------------------------------------------------------
  393. //---------------------------------------------------------------------------
  394. __fastcall TFileLocationSessionAction::TFileLocationSessionAction(
  395. TActionLog * Log, TLogAction Action) :
  396. TFileSessionAction(Log, Action)
  397. {
  398. }
  399. //---------------------------------------------------------------------------
  400. __fastcall TFileLocationSessionAction::TFileLocationSessionAction(
  401. TActionLog * Log, TLogAction Action, const UnicodeString & FileName) :
  402. TFileSessionAction(Log, Action, FileName)
  403. {
  404. }
  405. //---------------------------------------------------------------------------
  406. void __fastcall TFileLocationSessionAction::Destination(const UnicodeString & Destination)
  407. {
  408. if (FRecord != NULL)
  409. {
  410. FRecord->Destination(Destination);
  411. }
  412. }
  413. //---------------------------------------------------------------------------
  414. //---------------------------------------------------------------------------
  415. __fastcall TUploadSessionAction::TUploadSessionAction(TActionLog * Log) :
  416. TFileLocationSessionAction(Log, laUpload)
  417. {
  418. }
  419. //---------------------------------------------------------------------------
  420. //---------------------------------------------------------------------------
  421. __fastcall TDownloadSessionAction::TDownloadSessionAction(TActionLog * Log) :
  422. TFileLocationSessionAction(Log, laDownload)
  423. {
  424. }
  425. //---------------------------------------------------------------------------
  426. //---------------------------------------------------------------------------
  427. __fastcall TChmodSessionAction::TChmodSessionAction(
  428. TActionLog * Log, const UnicodeString & FileName) :
  429. TFileSessionAction(Log, laChmod, FileName)
  430. {
  431. }
  432. //---------------------------------------------------------------------------
  433. void __fastcall TChmodSessionAction::Recursive()
  434. {
  435. if (FRecord != NULL)
  436. {
  437. FRecord->Recursive();
  438. }
  439. }
  440. //---------------------------------------------------------------------------
  441. __fastcall TChmodSessionAction::TChmodSessionAction(
  442. TActionLog * Log, const UnicodeString & FileName, const TRights & ARights) :
  443. TFileSessionAction(Log, laChmod, FileName)
  444. {
  445. Rights(ARights);
  446. }
  447. //---------------------------------------------------------------------------
  448. void __fastcall TChmodSessionAction::Rights(const TRights & Rights)
  449. {
  450. if (FRecord != NULL)
  451. {
  452. FRecord->Rights(Rights);
  453. }
  454. }
  455. //---------------------------------------------------------------------------
  456. __fastcall TTouchSessionAction::TTouchSessionAction(
  457. TActionLog * Log, const UnicodeString & FileName, const TDateTime & Modification) :
  458. TFileSessionAction(Log, laTouch, FileName)
  459. {
  460. if (FRecord != NULL)
  461. {
  462. FRecord->Modification(Modification);
  463. }
  464. }
  465. //---------------------------------------------------------------------------
  466. __fastcall TMkdirSessionAction::TMkdirSessionAction(
  467. TActionLog * Log, const UnicodeString & FileName) :
  468. TFileSessionAction(Log, laMkdir, FileName)
  469. {
  470. }
  471. //---------------------------------------------------------------------------
  472. __fastcall TRmSessionAction::TRmSessionAction(
  473. TActionLog * Log, const UnicodeString & FileName) :
  474. TFileSessionAction(Log, laRm, FileName)
  475. {
  476. }
  477. //---------------------------------------------------------------------------
  478. void __fastcall TRmSessionAction::Recursive()
  479. {
  480. if (FRecord != NULL)
  481. {
  482. FRecord->Recursive();
  483. }
  484. }
  485. //---------------------------------------------------------------------------
  486. __fastcall TMvSessionAction::TMvSessionAction(TActionLog * Log,
  487. const UnicodeString & FileName, const UnicodeString & ADestination) :
  488. TFileLocationSessionAction(Log, laMv, FileName)
  489. {
  490. Destination(ADestination);
  491. }
  492. //---------------------------------------------------------------------------
  493. __fastcall TCallSessionAction::TCallSessionAction(TActionLog * Log,
  494. const UnicodeString & Command, const UnicodeString & Destination) :
  495. TSessionAction(Log, laCall)
  496. {
  497. if (FRecord != NULL)
  498. {
  499. FRecord->Command(Command);
  500. FRecord->Destination(Destination);
  501. }
  502. }
  503. //---------------------------------------------------------------------------
  504. void __fastcall TCallSessionAction::AddOutput(const UnicodeString & Output, bool StdError)
  505. {
  506. if (FRecord != NULL)
  507. {
  508. FRecord->AddOutput(Output, StdError);
  509. }
  510. }
  511. //---------------------------------------------------------------------------
  512. __fastcall TLsSessionAction::TLsSessionAction(TActionLog * Log,
  513. const UnicodeString & Destination) :
  514. TSessionAction(Log, laLs)
  515. {
  516. if (FRecord != NULL)
  517. {
  518. FRecord->Destination(Destination);
  519. }
  520. }
  521. //---------------------------------------------------------------------------
  522. void __fastcall TLsSessionAction::FileList(TRemoteFileList * FileList)
  523. {
  524. if (FRecord != NULL)
  525. {
  526. FRecord->FileList(FileList);
  527. }
  528. }
  529. //---------------------------------------------------------------------------
  530. //---------------------------------------------------------------------------
  531. __fastcall TStatSessionAction::TStatSessionAction(TActionLog * Log, const UnicodeString & FileName) :
  532. TFileSessionAction(Log, laStat, FileName)
  533. {
  534. }
  535. //---------------------------------------------------------------------------
  536. void __fastcall TStatSessionAction::File(TRemoteFile * File)
  537. {
  538. if (FRecord != NULL)
  539. {
  540. FRecord->File(File);
  541. }
  542. }
  543. //---------------------------------------------------------------------------
  544. //---------------------------------------------------------------------------
  545. TSessionInfo::TSessionInfo()
  546. {
  547. LoginTime = Now();
  548. }
  549. //---------------------------------------------------------------------------
  550. TFileSystemInfo::TFileSystemInfo()
  551. {
  552. memset(&IsCapable, false, sizeof(IsCapable));
  553. }
  554. //---------------------------------------------------------------------------
  555. //---------------------------------------------------------------------------
  556. FILE * __fastcall OpenFile(UnicodeString LogFileName, TSessionData * SessionData, bool Append, UnicodeString & NewFileName)
  557. {
  558. FILE * Result;
  559. UnicodeString ANewFileName = StripPathQuotes(ExpandEnvironmentVariables(LogFileName));
  560. TDateTime N = Now();
  561. for (int Index = 1; Index < ANewFileName.Length(); Index++)
  562. {
  563. if (ANewFileName[Index] == L'!')
  564. {
  565. UnicodeString Replacement;
  566. // keep consistent with TFileCustomCommand::PatternReplacement
  567. switch (tolower(ANewFileName[Index + 1]))
  568. {
  569. case L'y':
  570. Replacement = FormatDateTime(L"yyyy", N);
  571. break;
  572. case L'm':
  573. Replacement = FormatDateTime(L"mm", N);
  574. break;
  575. case L'd':
  576. Replacement = FormatDateTime(L"dd", N);
  577. break;
  578. case L't':
  579. Replacement = FormatDateTime(L"hhnnss", N);
  580. break;
  581. case L'@':
  582. Replacement = MakeValidFileName(SessionData->HostNameExpanded);
  583. break;
  584. case L's':
  585. Replacement = MakeValidFileName(SessionData->SessionName);
  586. break;
  587. case L'!':
  588. Replacement = L"!";
  589. break;
  590. default:
  591. Replacement = UnicodeString(L"!") + ANewFileName[Index + 1];
  592. break;
  593. }
  594. ANewFileName.Delete(Index, 2);
  595. ANewFileName.Insert(Replacement, Index);
  596. Index += Replacement.Length() - 1;
  597. }
  598. }
  599. Result = _wfopen(ANewFileName.c_str(), (Append ? L"a" : L"w"));
  600. if (Result != NULL)
  601. {
  602. setvbuf(Result, NULL, _IONBF, BUFSIZ);
  603. NewFileName = ANewFileName;
  604. }
  605. else
  606. {
  607. throw Exception(FMTLOAD(LOG_OPENERROR, (ANewFileName)));
  608. }
  609. return Result;
  610. }
  611. //---------------------------------------------------------------------------
  612. //---------------------------------------------------------------------------
  613. const wchar_t *LogLineMarks = L"<>!.*";
  614. __fastcall TSessionLog::TSessionLog(TSessionUI* UI, TSessionData * SessionData,
  615. TConfiguration * Configuration):
  616. TStringList()
  617. {
  618. FCriticalSection = new TCriticalSection;
  619. FLogging = false;
  620. FConfiguration = Configuration;
  621. FParent = NULL;
  622. FUI = UI;
  623. FSessionData = SessionData;
  624. FFile = NULL;
  625. FLoggedLines = 0;
  626. FTopIndex = -1;
  627. FCurrentLogFileName = L"";
  628. FCurrentFileName = L"";
  629. FClosed = false;
  630. }
  631. //---------------------------------------------------------------------------
  632. __fastcall TSessionLog::~TSessionLog()
  633. {
  634. FClosed = true;
  635. ReflectSettings();
  636. assert(FFile == NULL);
  637. delete FCriticalSection;
  638. }
  639. //---------------------------------------------------------------------------
  640. void __fastcall TSessionLog::Lock()
  641. {
  642. FCriticalSection->Enter();
  643. }
  644. //---------------------------------------------------------------------------
  645. void __fastcall TSessionLog::Unlock()
  646. {
  647. FCriticalSection->Leave();
  648. }
  649. //---------------------------------------------------------------------------
  650. UnicodeString __fastcall TSessionLog::GetSessionName()
  651. {
  652. assert(FSessionData != NULL);
  653. return FSessionData->SessionName;
  654. }
  655. //---------------------------------------------------------------------------
  656. UnicodeString __fastcall TSessionLog::GetLine(Integer Index)
  657. {
  658. return Strings[Index - FTopIndex];
  659. }
  660. //---------------------------------------------------------------------------
  661. TLogLineType __fastcall TSessionLog::GetType(int Index)
  662. {
  663. return (TLogLineType)Objects[Index - FTopIndex];
  664. }
  665. //---------------------------------------------------------------------------
  666. void __fastcall TSessionLog::DoAddToParent(TLogLineType Type, const UnicodeString & Line)
  667. {
  668. assert(FParent != NULL);
  669. FParent->Add(Type, Line);
  670. }
  671. //---------------------------------------------------------------------------
  672. void __fastcall TSessionLog::DoAddToSelf(TLogLineType Type, const UnicodeString & Line)
  673. {
  674. if (FTopIndex < 0)
  675. {
  676. FTopIndex = 0;
  677. }
  678. TStringList::AddObject(Line, (TObject*)Type);
  679. FLoggedLines++;
  680. if (LogToFile())
  681. {
  682. if (FFile == NULL)
  683. {
  684. OpenLogFile();
  685. }
  686. if (FFile != NULL)
  687. {
  688. UnicodeString Timestamp = FormatDateTime(L" yyyy-mm-dd hh:nn:ss.zzz ", Now());
  689. UTF8String UtfLine = UTF8String(UnicodeString(LogLineMarks[Type]) + Timestamp + Line + "\n");
  690. fwrite(UtfLine.c_str(), UtfLine.Length(), 1, (FILE *)FFile);
  691. }
  692. }
  693. }
  694. //---------------------------------------------------------------------------
  695. void __fastcall TSessionLog::DoAdd(TLogLineType Type, UnicodeString Line,
  696. void __fastcall (__closure *f)(TLogLineType Type, const UnicodeString & Line))
  697. {
  698. UnicodeString Prefix;
  699. if (!Name.IsEmpty())
  700. {
  701. Prefix = L"[" + Name + L"] ";
  702. }
  703. while (!Line.IsEmpty())
  704. {
  705. f(Type, Prefix + CutToChar(Line, L'\n', false));
  706. }
  707. }
  708. //---------------------------------------------------------------------------
  709. void __fastcall TSessionLog::Add(TLogLineType Type, const UnicodeString & Line)
  710. {
  711. assert(FConfiguration);
  712. if (Logging)
  713. {
  714. try
  715. {
  716. if (FParent != NULL)
  717. {
  718. DoAdd(Type, Line, DoAddToParent);
  719. }
  720. else
  721. {
  722. TGuard Guard(FCriticalSection);
  723. BeginUpdate();
  724. try
  725. {
  726. DoAdd(Type, Line, DoAddToSelf);
  727. }
  728. __finally
  729. {
  730. DeleteUnnecessary();
  731. EndUpdate();
  732. }
  733. }
  734. }
  735. catch (Exception &E)
  736. {
  737. // We failed logging, turn it off and notify user.
  738. FConfiguration->Logging = false;
  739. try
  740. {
  741. throw ExtException(&E, LOG_GEN_ERROR);
  742. }
  743. catch (Exception &E)
  744. {
  745. AddException(&E);
  746. FUI->HandleExtendedException(&E);
  747. }
  748. }
  749. }
  750. }
  751. //---------------------------------------------------------------------------
  752. void __fastcall TSessionLog::AddException(Exception * E)
  753. {
  754. if (E != NULL)
  755. {
  756. Add(llException, ExceptionLogString(E));
  757. }
  758. }
  759. //---------------------------------------------------------------------------
  760. void __fastcall TSessionLog::ReflectSettings()
  761. {
  762. TGuard Guard(FCriticalSection);
  763. bool ALogging =
  764. !FClosed &&
  765. ((FParent != NULL) || FConfiguration->Logging);
  766. if (FLogging != ALogging)
  767. {
  768. FLogging = ALogging;
  769. StateChange();
  770. }
  771. // if logging to file was turned off or log file was changed -> close current log file
  772. if ((FFile != NULL) &&
  773. (!LogToFile() || (FCurrentLogFileName != FConfiguration->LogFileName)))
  774. {
  775. CloseLogFile();
  776. }
  777. DeleteUnnecessary();
  778. }
  779. //---------------------------------------------------------------------------
  780. bool __fastcall TSessionLog::LogToFile()
  781. {
  782. return Logging && FConfiguration->LogToFile && (FParent == NULL);
  783. }
  784. //---------------------------------------------------------------------------
  785. void __fastcall TSessionLog::CloseLogFile()
  786. {
  787. if (FFile != NULL)
  788. {
  789. fclose((FILE *)FFile);
  790. FFile = NULL;
  791. }
  792. FCurrentLogFileName = L"";
  793. FCurrentFileName = L"";
  794. StateChange();
  795. }
  796. //---------------------------------------------------------------------------
  797. void __fastcall TSessionLog::OpenLogFile()
  798. {
  799. try
  800. {
  801. assert(FFile == NULL);
  802. assert(FConfiguration != NULL);
  803. FCurrentLogFileName = FConfiguration->LogFileName;
  804. FFile = OpenFile(FCurrentLogFileName, FSessionData, FConfiguration->LogFileAppend, FCurrentFileName);
  805. }
  806. catch (Exception & E)
  807. {
  808. // We failed logging to file, turn it off and notify user.
  809. FCurrentLogFileName = L"";
  810. FCurrentFileName = L"";
  811. FConfiguration->LogFileName = UnicodeString();
  812. try
  813. {
  814. throw ExtException(&E, LOG_GEN_ERROR);
  815. }
  816. catch (Exception & E)
  817. {
  818. AddException(&E);
  819. FUI->HandleExtendedException(&E);
  820. }
  821. }
  822. StateChange();
  823. }
  824. //---------------------------------------------------------------------------
  825. void __fastcall TSessionLog::StateChange()
  826. {
  827. if (FOnStateChange != NULL)
  828. {
  829. FOnStateChange(this);
  830. }
  831. }
  832. //---------------------------------------------------------------------------
  833. void __fastcall TSessionLog::DeleteUnnecessary()
  834. {
  835. BeginUpdate();
  836. try
  837. {
  838. if (!Logging || (FParent != NULL))
  839. {
  840. Clear();
  841. }
  842. else
  843. {
  844. while (!FConfiguration->LogWindowComplete && (Count > FConfiguration->LogWindowLines))
  845. {
  846. Delete(0);
  847. FTopIndex++;
  848. }
  849. }
  850. }
  851. __finally
  852. {
  853. EndUpdate();
  854. }
  855. }
  856. //---------------------------------------------------------------------------
  857. void __fastcall TSessionLog::AddStartupInfo()
  858. {
  859. if (Logging)
  860. {
  861. if (FParent != NULL)
  862. {
  863. // do not add session info for secondary session
  864. // (this should better be handled in the TSecondaryTerminal)
  865. }
  866. else
  867. {
  868. DoAddStartupInfo(FSessionData);
  869. }
  870. }
  871. }
  872. //---------------------------------------------------------------------------
  873. void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
  874. {
  875. TGuard Guard(FCriticalSection);
  876. BeginUpdate();
  877. try
  878. {
  879. #define ADF(S, F) DoAdd(llMessage, FORMAT(S, F), DoAddToSelf);
  880. AddSeparator();
  881. ADF(L"WinSCP %s (OS %s)", (FConfiguration->VersionStr, FConfiguration->OSVersionStr));
  882. THierarchicalStorage * Storage = FConfiguration->CreateScpStorage(false);
  883. try
  884. {
  885. ADF(L"Configuration: %s", (Storage->Source));
  886. }
  887. __finally
  888. {
  889. delete Storage;
  890. }
  891. typedef BOOL WINAPI (* TGetUserNameEx)(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize);
  892. HINSTANCE Secur32 = LoadLibrary(L"secur32.dll");
  893. TGetUserNameEx GetUserNameEx =
  894. (Secur32 != NULL) ? (TGetUserNameEx)GetProcAddress(Secur32, "GetUserNameExW") : NULL;
  895. wchar_t UserName[UNLEN + 1];
  896. unsigned long UserNameSize = LENOF(UserName);
  897. if ((GetUserNameEx == NULL) || !GetUserNameEx(NameSamCompatible, UserName, &UserNameSize))
  898. {
  899. wcscpy(UserName, L"<Failed to retrieve username>");
  900. }
  901. ADF(L"Local account: %s", (UserName));
  902. ADF(L"Working directory: %s", (GetCurrentDir()));
  903. ADF(L"Command-line: %s", (CmdLine));
  904. ADF(L"Time zone: %s", (GetTimeZoneLogString()));
  905. ADF(L"Login time: %s", (FormatDateTime(L"dddddd tt", Now())));
  906. AddSeparator();
  907. ADF(L"Session name: %s (%s)", (Data->SessionName, Data->Source));
  908. ADF(L"Host name: %s (Port: %d)", (Data->HostNameExpanded, Data->PortNumber));
  909. ADF(L"User name: %s (Password: %s, Key file: %s)",
  910. (Data->UserNameExpanded, BooleanToEngStr(!Data->Password.IsEmpty()),
  911. BooleanToEngStr(!Data->PublicKeyFile.IsEmpty())))
  912. ADF(L"Tunnel: %s", (BooleanToEngStr(Data->Tunnel)));
  913. if (Data->Tunnel)
  914. {
  915. ADF(L"Tunnel: Host name: %s (Port: %d)", (Data->TunnelHostName, Data->TunnelPortNumber));
  916. ADF(L"Tunnel: User name: %s (Password: %s, Key file: %s)",
  917. (Data->TunnelUserName, BooleanToEngStr(!Data->TunnelPassword.IsEmpty()),
  918. BooleanToEngStr(!Data->TunnelPublicKeyFile.IsEmpty())))
  919. ADF(L"Tunnel: Local port number: %d", (Data->TunnelLocalPortNumber));
  920. }
  921. ADF(L"Transfer Protocol: %s", (Data->FSProtocolStr));
  922. wchar_t * PingTypes = L"-NC";
  923. TPingType PingType;
  924. int PingInterval;
  925. if (Data->FSProtocol == fsFTP)
  926. {
  927. PingType = Data->FtpPingType;
  928. PingInterval = Data->FtpPingInterval;
  929. }
  930. else
  931. {
  932. PingType = Data->PingType;
  933. PingInterval = Data->PingInterval;
  934. }
  935. ADF(L"Ping type: %s, Ping interval: %d sec; Timeout: %d sec",
  936. (UnicodeString(PingTypes[PingType]), PingInterval, Data->Timeout));
  937. ADF(L"Proxy: %s", (ProxyMethodList[Data->ProxyMethod]));
  938. if (Data->ProxyMethod != ::pmNone)
  939. {
  940. ADF(L"HostName: %s (Port: %d); Username: %s; Passwd: %s",
  941. (Data->ProxyHost, Data->ProxyPort,
  942. Data->ProxyUsername, BooleanToEngStr(!Data->ProxyPassword.IsEmpty())));
  943. if (Data->ProxyMethod == pmTelnet)
  944. {
  945. ADF(L"Telnet command: %s", (Data->ProxyTelnetCommand));
  946. }
  947. if (Data->ProxyMethod == pmCmd)
  948. {
  949. ADF(L"Local command: %s", (Data->ProxyLocalCommand));
  950. }
  951. }
  952. wchar_t const * BugFlags = L"+-A";
  953. if (Data->UsesSsh)
  954. {
  955. ADF(L"SSH protocol version: %s; Compression: %s",
  956. (Data->SshProtStr, BooleanToEngStr(Data->Compression)));
  957. ADF(L"Bypass authentication: %s",
  958. (BooleanToEngStr(Data->SshNoUserAuth)));
  959. ADF(L"Try agent: %s; Agent forwarding: %s; TIS/CryptoCard: %s; KI: %s; GSSAPI: %s",
  960. (BooleanToEngStr(Data->TryAgent), BooleanToEngStr(Data->AgentFwd), BooleanToEngStr(Data->AuthTIS),
  961. BooleanToEngStr(Data->AuthKI), BooleanToEngStr(Data->AuthGSSAPI)));
  962. if (Data->AuthGSSAPI)
  963. {
  964. ADF(L"GSSAPI: Forwarding: %s; Server realm: %s",
  965. (BooleanToEngStr(Data->GSSAPIFwdTGT), Data->GSSAPIServerRealm));
  966. }
  967. ADF(L"Ciphers: %s; Ssh2DES: %s",
  968. (Data->CipherList, BooleanToEngStr(Data->Ssh2DES)));
  969. UnicodeString Bugs;
  970. for (int Index = 0; Index < BUG_COUNT; Index++)
  971. {
  972. Bugs += UnicodeString(BugFlags[Data->Bug[(TSshBug)Index]])+(Index<BUG_COUNT-1?L",":L"");
  973. }
  974. ADF(L"SSH Bugs: %s", (Bugs));
  975. Bugs = L"";
  976. for (int Index = 0; Index < SFTP_BUG_COUNT; Index++)
  977. {
  978. Bugs += UnicodeString(BugFlags[Data->SFTPBug[(TSftpBug)Index]])+(Index<SFTP_BUG_COUNT-1?L",":L"");
  979. }
  980. ADF(L"SFTP Bugs: %s", (Bugs));
  981. ADF(L"Return code variable: %s; Lookup user groups: %s",
  982. ((Data->DetectReturnVar ? UnicodeString(L"Autodetect") : Data->ReturnVar),
  983. BugFlags[Data->LookupUserGroups]));
  984. ADF(L"Shell: %s", ((Data->Shell.IsEmpty()? UnicodeString(L"default") : Data->Shell)));
  985. ADF(L"EOL: %d, UTF: %d", (Data->EOLType, Data->NotUtf));
  986. ADF(L"Clear aliases: %s, Unset nat.vars: %s, Resolve symlinks: %s",
  987. (BooleanToEngStr(Data->ClearAliases), BooleanToEngStr(Data->UnsetNationalVars),
  988. BooleanToEngStr(Data->ResolveSymlinks)));
  989. ADF(L"LS: %s, Ign LS warn: %s, Scp1 Comp: %s",
  990. (Data->ListingCommand,
  991. BooleanToEngStr(Data->IgnoreLsWarnings),
  992. BooleanToEngStr(Data->Scp1Compatibility)));
  993. }
  994. if (Data->FSProtocol == fsFTP)
  995. {
  996. UnicodeString Ftps;
  997. switch (Data->Ftps)
  998. {
  999. case ftpsImplicit:
  1000. Ftps = L"Implicit SSL/TLS";
  1001. break;
  1002. case ftpsExplicitSsl:
  1003. Ftps = L"Explicit SSL";
  1004. break;
  1005. case ftpsExplicitTls:
  1006. Ftps = L"Explicit TLS";
  1007. break;
  1008. default:
  1009. assert(Data->Ftps == ftpsNone);
  1010. Ftps = L"None";
  1011. break;
  1012. }
  1013. ADF(L"FTP: FTPS: %s; Passive: %s [Force IP: %s]",
  1014. (Ftps, BooleanToEngStr(Data->FtpPasvMode),
  1015. BugFlags[Data->FtpForcePasvIp]));
  1016. }
  1017. ADF(L"Local directory: %s, Remote directory: %s, Update: %s, Cache: %s",
  1018. ((Data->LocalDirectory.IsEmpty() ? UnicodeString(L"default") : Data->LocalDirectory),
  1019. (Data->RemoteDirectory.IsEmpty() ? UnicodeString(L"home") : Data->RemoteDirectory),
  1020. BooleanToEngStr(Data->UpdateDirectories),
  1021. BooleanToEngStr(Data->CacheDirectories)));
  1022. ADF(L"Cache directory changes: %s, Permanent: %s",
  1023. (BooleanToEngStr(Data->CacheDirectoryChanges),
  1024. BooleanToEngStr(Data->PreserveDirectoryChanges)));
  1025. ADF(L"DST mode: %d", (int(Data->DSTMode)));
  1026. AddSeparator();
  1027. #undef ADF
  1028. }
  1029. __finally
  1030. {
  1031. DeleteUnnecessary();
  1032. EndUpdate();
  1033. }
  1034. }
  1035. //---------------------------------------------------------------------------
  1036. void __fastcall TSessionLog::AddSeparator()
  1037. {
  1038. Add(llMessage, L"--------------------------------------------------------------------------");
  1039. }
  1040. //---------------------------------------------------------------------------
  1041. int __fastcall TSessionLog::GetBottomIndex()
  1042. {
  1043. return (Count > 0 ? (TopIndex + Count - 1) : -1);
  1044. }
  1045. //---------------------------------------------------------------------------
  1046. bool __fastcall TSessionLog::GetLoggingToFile()
  1047. {
  1048. assert((FFile == NULL) || LogToFile());
  1049. return (FFile != NULL);
  1050. }
  1051. //---------------------------------------------------------------------------
  1052. void __fastcall TSessionLog::Clear()
  1053. {
  1054. TGuard Guard(FCriticalSection);
  1055. FTopIndex += Count;
  1056. TStringList::Clear();
  1057. }
  1058. //---------------------------------------------------------------------------
  1059. //---------------------------------------------------------------------------
  1060. __fastcall TActionLog::TActionLog(TSessionUI* UI, TSessionData * SessionData,
  1061. TConfiguration * Configuration)
  1062. {
  1063. FCriticalSection = new TCriticalSection;
  1064. FConfiguration = Configuration;
  1065. FUI = UI;
  1066. FSessionData = SessionData;
  1067. FFile = NULL;
  1068. FCurrentLogFileName = L"";
  1069. FCurrentFileName = L"";
  1070. FLogging = false;
  1071. FClosed = false;
  1072. FPendingActions = new TList();
  1073. FIndent = L" ";
  1074. FInGroup = false;
  1075. FEnabled = true;
  1076. }
  1077. //---------------------------------------------------------------------------
  1078. __fastcall TActionLog::~TActionLog()
  1079. {
  1080. assert(FPendingActions->Count == 0);
  1081. delete FPendingActions;
  1082. FClosed = true;
  1083. ReflectSettings();
  1084. assert(FFile == NULL);
  1085. delete FCriticalSection;
  1086. }
  1087. //---------------------------------------------------------------------------
  1088. void __fastcall TActionLog::Add(const UnicodeString & Line)
  1089. {
  1090. assert(FConfiguration);
  1091. if (FLogging)
  1092. {
  1093. try
  1094. {
  1095. TGuard Guard(FCriticalSection);
  1096. if (FFile == NULL)
  1097. {
  1098. OpenLogFile();
  1099. }
  1100. if (FFile != NULL)
  1101. {
  1102. UTF8String UtfLine = UTF8String(Line);
  1103. fwrite(UtfLine.c_str(), 1, UtfLine.Length(), (FILE *)FFile);
  1104. fwrite("\n", 1, 1, (FILE *)FFile);
  1105. }
  1106. }
  1107. catch (Exception &E)
  1108. {
  1109. // We failed logging, turn it off and notify user.
  1110. FConfiguration->LogActions = false;
  1111. try
  1112. {
  1113. throw ExtException(&E, LOG_GEN_ERROR);
  1114. }
  1115. catch (Exception &E)
  1116. {
  1117. FUI->HandleExtendedException(&E);
  1118. }
  1119. }
  1120. }
  1121. }
  1122. //---------------------------------------------------------------------------
  1123. void __fastcall TActionLog::AddIndented(const UnicodeString & Line)
  1124. {
  1125. Add(FIndent + Line);
  1126. }
  1127. //---------------------------------------------------------------------------
  1128. void __fastcall TActionLog::AddFailure(TStrings * Messages)
  1129. {
  1130. AddIndented(L"<failure>");
  1131. AddMessages(L" ", Messages);
  1132. AddIndented(L"</failure>");
  1133. }
  1134. //---------------------------------------------------------------------------
  1135. void __fastcall TActionLog::AddFailure(Exception * E)
  1136. {
  1137. TStrings * Messages = ExceptionToMessages(E);
  1138. if (Messages != NULL)
  1139. {
  1140. try
  1141. {
  1142. AddFailure(Messages);
  1143. }
  1144. __finally
  1145. {
  1146. delete Messages;
  1147. }
  1148. }
  1149. }
  1150. //---------------------------------------------------------------------------
  1151. void __fastcall TActionLog::AddMessages(UnicodeString Indent, TStrings * Messages)
  1152. {
  1153. for (int Index = 0; Index < Messages->Count; Index++)
  1154. {
  1155. AddIndented(
  1156. FORMAT(Indent + L"<message>%s</message>", (XmlEscape(Messages->Strings[Index]))));
  1157. }
  1158. }
  1159. //---------------------------------------------------------------------------
  1160. void __fastcall TActionLog::ReflectSettings()
  1161. {
  1162. TGuard Guard(FCriticalSection);
  1163. bool ALogging =
  1164. !FClosed && FConfiguration->LogActions && Enabled;
  1165. if (ALogging && !FLogging)
  1166. {
  1167. FLogging = true;
  1168. Add(L"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
  1169. Add(FORMAT(L"<session xmlns=\"http://winscp.net/schema/session/1.0\" name=\"%s\" start=\"%s\">",
  1170. (XmlAttributeEscape(FSessionData->SessionName), StandardTimestamp())));
  1171. }
  1172. else if (!ALogging && FLogging)
  1173. {
  1174. if (FInGroup)
  1175. {
  1176. EndGroup();
  1177. }
  1178. Add(L"</session>");
  1179. CloseLogFile();
  1180. FLogging = false;
  1181. }
  1182. }
  1183. //---------------------------------------------------------------------------
  1184. void __fastcall TActionLog::CloseLogFile()
  1185. {
  1186. if (FFile != NULL)
  1187. {
  1188. fclose((FILE *)FFile);
  1189. FFile = NULL;
  1190. }
  1191. FCurrentLogFileName = L"";
  1192. FCurrentFileName = L"";
  1193. }
  1194. //---------------------------------------------------------------------------
  1195. void __fastcall TActionLog::OpenLogFile()
  1196. {
  1197. try
  1198. {
  1199. assert(FFile == NULL);
  1200. assert(FConfiguration != NULL);
  1201. FCurrentLogFileName = FConfiguration->ActionsLogFileName;
  1202. FFile = OpenFile(FCurrentLogFileName, FSessionData, false, FCurrentFileName);
  1203. }
  1204. catch (Exception & E)
  1205. {
  1206. // We failed logging to file, turn it off and notify user.
  1207. FCurrentLogFileName = L"";
  1208. FCurrentFileName = L"";
  1209. FConfiguration->LogActions = false;
  1210. try
  1211. {
  1212. throw ExtException(&E, LOG_GEN_ERROR);
  1213. }
  1214. catch (Exception & E)
  1215. {
  1216. FUI->HandleExtendedException(&E);
  1217. }
  1218. }
  1219. }
  1220. //---------------------------------------------------------------------------
  1221. void __fastcall TActionLog::AddPendingAction(TSessionActionRecord * Action)
  1222. {
  1223. FPendingActions->Add(Action);
  1224. }
  1225. //---------------------------------------------------------------------------
  1226. void __fastcall TActionLog::RecordPendingActions()
  1227. {
  1228. while ((FPendingActions->Count > 0) &&
  1229. static_cast<TSessionActionRecord *>(FPendingActions->Items[0])->Record())
  1230. {
  1231. FPendingActions->Delete(0);
  1232. }
  1233. }
  1234. //---------------------------------------------------------------------------
  1235. void __fastcall TActionLog::BeginGroup(UnicodeString Name)
  1236. {
  1237. assert(!FInGroup);
  1238. FInGroup = true;
  1239. assert(FIndent == L" ");
  1240. AddIndented(FORMAT("<group name=\"%s\" start=\"%s\">",
  1241. (XmlAttributeEscape(Name), StandardTimestamp())));
  1242. FIndent = L" ";
  1243. }
  1244. //---------------------------------------------------------------------------
  1245. void __fastcall TActionLog::EndGroup()
  1246. {
  1247. assert(FInGroup);
  1248. FInGroup = false;
  1249. assert(FIndent == L" ");
  1250. FIndent = L" ";
  1251. AddIndented("</group>");
  1252. }
  1253. //---------------------------------------------------------------------------
  1254. void __fastcall TActionLog::SetEnabled(bool value)
  1255. {
  1256. if (Enabled != value)
  1257. {
  1258. FEnabled = value;
  1259. ReflectSettings();
  1260. }
  1261. }