TerminalManager.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "TerminalManager.h"
  5. #include <Authenticate.h>
  6. #include "CustomScpExplorer.h"
  7. #include "LogMemo.h"
  8. #include "NonVisual.h"
  9. #include "WinConfiguration.h"
  10. #include <Log.h>
  11. #include <Common.h>
  12. #include <CoreMain.h>
  13. #include <GUITools.h>
  14. #include <TextsWin.h>
  15. #include <TextsCore.h>
  16. #include <Progress.h>
  17. #include <Exceptions.h>
  18. #include <VCLCommon.h>
  19. //---------------------------------------------------------------------------
  20. #pragma package(smart_init)
  21. //---------------------------------------------------------------------------
  22. TTerminalManager * TTerminalManager::FInstance = NULL;
  23. //---------------------------------------------------------------------------
  24. __fastcall TManagedTerminal::TManagedTerminal(TSessionData * SessionData,
  25. TConfiguration * Configuration) :
  26. TTerminal(SessionData, Configuration),
  27. Color((TColor)SessionData->Color), SynchronizeBrowsing(false),
  28. LocalDirectory(::ExpandFileName(SessionData->LocalDirectory)),
  29. RemoteDirectory(SessionData->RemoteDirectory),
  30. LocalExplorerState(NULL), RemoteExplorerState(NULL),
  31. ReopenStart(0)
  32. {
  33. }
  34. //---------------------------------------------------------------------------
  35. __fastcall TManagedTerminal::~TManagedTerminal()
  36. {
  37. delete LocalExplorerState;
  38. delete RemoteExplorerState;
  39. }
  40. //---------------------------------------------------------------------------
  41. //---------------------------------------------------------------------------
  42. TTerminalManager * __fastcall TTerminalManager::Instance(bool ForceCreation)
  43. {
  44. if (!FInstance && ForceCreation)
  45. {
  46. FInstance = new TTerminalManager();
  47. }
  48. return FInstance;
  49. }
  50. //---------------------------------------------------------------------------
  51. void __fastcall TTerminalManager::DestroyInstance()
  52. {
  53. assert(FInstance);
  54. SAFE_DESTROY(FInstance);
  55. }
  56. //---------------------------------------------------------------------------
  57. __fastcall TTerminalManager::TTerminalManager() :
  58. TTerminalList(Configuration)
  59. {
  60. FQueueSection = new TCriticalSection();
  61. FLogMemo = NULL;
  62. FActiveTerminal = NULL;
  63. FScpExplorer = NULL;
  64. FDestroying = false;
  65. FTerminalPendingAction = tpNull;
  66. FDirectoryReadingStart = 0;
  67. FAuthenticateForm = NULL;
  68. FQueueWithEvent = NULL;
  69. assert(Application && !Application->OnException);
  70. Application->OnException = ApplicationException;
  71. assert(Application->OnShowHint == NULL);
  72. Application->OnShowHint = ApplicationShowHint;
  73. assert(Application->OnActivate == NULL);
  74. Application->OnActivate = ApplicationActivate;
  75. assert(WinConfiguration->OnMasterPasswordPrompt == NULL);
  76. WinConfiguration->OnMasterPasswordPrompt = MasterPasswordPrompt;
  77. assert(Configuration && !Configuration->OnChange);
  78. Configuration->OnChange = ConfigurationChange;
  79. FOnLastTerminalClosed = NULL;
  80. FOnTerminalListChanged = NULL;
  81. FTerminalList = new TStringList();
  82. FQueues = new TList();
  83. FTerminationMessages = new TStringList();
  84. }
  85. //---------------------------------------------------------------------------
  86. __fastcall TTerminalManager::~TTerminalManager()
  87. {
  88. FreeAll();
  89. assert(!ScpExplorer);
  90. assert(Configuration->OnChange == ConfigurationChange);
  91. Configuration->OnChange = NULL;
  92. assert(Application && (Application->OnException == ApplicationException));
  93. Application->OnException = NULL;
  94. assert(Application->OnShowHint == ApplicationShowHint);
  95. Application->OnShowHint = ApplicationShowHint;
  96. assert(Application->OnActivate == ApplicationActivate);
  97. Application->OnActivate = NULL;
  98. assert(WinConfiguration->OnMasterPasswordPrompt == MasterPasswordPrompt);
  99. WinConfiguration->OnMasterPasswordPrompt = NULL;
  100. delete FQueues;
  101. delete FTerminationMessages;
  102. delete FTerminalList;
  103. delete FAuthenticateForm;
  104. delete FQueueSection;
  105. }
  106. //---------------------------------------------------------------------------
  107. TTerminalQueue * __fastcall TTerminalManager::NewQueue(TTerminal * Terminal)
  108. {
  109. TTerminalQueue * Queue = new TTerminalQueue(Terminal, Configuration);
  110. Queue->TransfersLimit = GUIConfiguration->QueueTransfersLimit;
  111. Queue->OnQueryUser = TerminalQueryUser;
  112. Queue->OnPromptUser = TerminalPromptUser;
  113. Queue->OnShowExtendedException = TerminalShowExtendedException;
  114. Queue->OnEvent = QueueEvent;
  115. return Queue;
  116. }
  117. //---------------------------------------------------------------------------
  118. TTerminal * __fastcall TTerminalManager::CreateTerminal(TSessionData * Data)
  119. {
  120. return new TManagedTerminal(Data, Configuration);
  121. }
  122. //---------------------------------------------------------------------------
  123. TTerminal * __fastcall TTerminalManager::NewTerminal(TSessionData * Data)
  124. {
  125. FTerminalList->Clear();
  126. TTerminal * Terminal = TTerminalList::NewTerminal(Data);
  127. try
  128. {
  129. FQueues->Add(NewQueue(Terminal));
  130. FTerminationMessages->Add("");
  131. Terminal->OnQueryUser = TerminalQueryUser;
  132. Terminal->OnPromptUser = TerminalPromptUser;
  133. Terminal->OnDisplayBanner = TerminalDisplayBanner;
  134. Terminal->OnShowExtendedException = TerminalShowExtendedException;
  135. Terminal->OnProgress = OperationProgress;
  136. Terminal->OnFinished = OperationFinished;
  137. Terminal->OnDeleteLocalFile = DeleteLocalFile;
  138. Terminal->OnReadDirectoryProgress = TerminalReadDirectoryProgress;
  139. Terminal->OnInformation = TerminalInformation;
  140. if (!ActiveTerminal)
  141. {
  142. ActiveTerminal = Terminal;
  143. }
  144. }
  145. catch(...)
  146. {
  147. if (Terminal != NULL)
  148. {
  149. FreeTerminal(Terminal);
  150. }
  151. throw;
  152. }
  153. if (OnTerminalListChanged)
  154. {
  155. OnTerminalListChanged(this);
  156. }
  157. return Terminal;
  158. }
  159. //---------------------------------------------------------------------------
  160. void __fastcall TTerminalManager::FreeActiveTerminal()
  161. {
  162. if (FTerminalPendingAction == tpNull)
  163. {
  164. assert(ActiveTerminal);
  165. FreeTerminal(ActiveTerminal);
  166. }
  167. else
  168. {
  169. assert(FTerminalPendingAction == ::tpNone);
  170. FTerminalPendingAction = tpFree;
  171. }
  172. }
  173. //---------------------------------------------------------------------------
  174. void TTerminalManager::ConnectTerminal(TTerminal * Terminal, bool Reopen)
  175. {
  176. TManagedTerminal * ManagedTerminal = dynamic_cast<TManagedTerminal *>(Terminal);
  177. // it must be managed terminal, unless it is secondary terminal (of managed terminal)
  178. assert((ManagedTerminal != NULL) || (dynamic_cast<TSecondaryTerminal *>(Terminal) != NULL));
  179. // particularly when we are reconnecting RemoteDirectory of managed terminal
  180. // hold the last used remote directory as opposite to session data, which holds
  181. // the default remote directory.
  182. // make sure the last used directory is used, but the default is preserved too
  183. AnsiString OrigRemoteDirectory = Terminal->SessionData->RemoteDirectory;
  184. try
  185. {
  186. if (ManagedTerminal != NULL)
  187. {
  188. Terminal->SessionData->RemoteDirectory = ManagedTerminal->RemoteDirectory;
  189. if ((double)ManagedTerminal->ReopenStart == 0)
  190. {
  191. ManagedTerminal->ReopenStart = Now();
  192. }
  193. }
  194. if (Reopen)
  195. {
  196. Terminal->Reopen(0);
  197. }
  198. else
  199. {
  200. Terminal->Open();
  201. }
  202. }
  203. __finally
  204. {
  205. Terminal->SessionData->RemoteDirectory = OrigRemoteDirectory;
  206. if (Terminal->Active && (ManagedTerminal != NULL))
  207. {
  208. ManagedTerminal->ReopenStart = 0;
  209. }
  210. }
  211. }
  212. //---------------------------------------------------------------------------
  213. bool __fastcall TTerminalManager::ConnectActiveTerminalImpl(bool Reopen)
  214. {
  215. TTerminalPendingAction Action;
  216. bool Result;
  217. do
  218. {
  219. Action = tpNull;
  220. Result = false;
  221. try
  222. {
  223. assert(ActiveTerminal);
  224. bool ShowLogPending = false;
  225. if (Configuration->Logging && (WinConfiguration->LogView == lvWindow))
  226. {
  227. if (WinConfiguration->LogWindowOnStartup)
  228. {
  229. RequireLogForm(LogMemo);
  230. }
  231. else
  232. {
  233. ShowLogPending = true;
  234. }
  235. }
  236. ConnectTerminal(ActiveTerminal, Reopen);
  237. if (ScpExplorer)
  238. {
  239. assert(ActiveTerminal->Status == ssOpened);
  240. TerminalReady();
  241. }
  242. WinConfiguration->ClearTemporaryLoginData();
  243. if (LogForm && (WinConfiguration->LogView != lvWindow))
  244. {
  245. FreeLogForm();
  246. }
  247. if (ShowLogPending)
  248. {
  249. RequireLogForm(LogMemo);
  250. }
  251. Result = true;
  252. }
  253. catch(Exception & E)
  254. {
  255. assert(FTerminalPendingAction == tpNull);
  256. FTerminalPendingAction = ::tpNone;
  257. try
  258. {
  259. assert(ActiveTerminal != NULL);
  260. ActiveTerminal->ShowExtendedException(&E);
  261. Action = FTerminalPendingAction;
  262. }
  263. __finally
  264. {
  265. FTerminalPendingAction = tpNull;
  266. }
  267. }
  268. }
  269. while (Action == tpReconnect);
  270. if (Action == tpFree)
  271. {
  272. FreeActiveTerminal();
  273. }
  274. return Result;
  275. }
  276. //---------------------------------------------------------------------------
  277. bool __fastcall TTerminalManager::ConnectActiveTerminal()
  278. {
  279. bool Result = ConnectActiveTerminalImpl(false);
  280. if (Result && WinConfiguration->AutoOpenInPutty && CanOpenInPutty())
  281. {
  282. try
  283. {
  284. OpenInPutty();
  285. }
  286. catch(Exception & E)
  287. {
  288. ShowExtendedExceptionEx(NULL, &E);
  289. }
  290. }
  291. return Result;
  292. }
  293. //---------------------------------------------------------------------------
  294. void __fastcall TTerminalManager::DisconnectActiveTerminal()
  295. {
  296. assert(ActiveTerminal);
  297. int Index = IndexOf(ActiveTerminal);
  298. TTerminalQueue * OldQueue;
  299. TTerminalQueue * NewQueue;
  300. OldQueue = reinterpret_cast<TTerminalQueue *>(FQueues->Items[Index]);
  301. NewQueue = this->NewQueue(ActiveTerminal);
  302. FQueues->Items[Index] = NewQueue;
  303. ScpExplorer->Queue = NewQueue;
  304. delete OldQueue;
  305. }
  306. //---------------------------------------------------------------------------
  307. void __fastcall TTerminalManager::ReconnectActiveTerminal()
  308. {
  309. assert(ActiveTerminal);
  310. if (ScpExplorer)
  311. {
  312. if (ScpExplorer->Terminal == ActiveTerminal)
  313. {
  314. ScpExplorer->UpdateTerminal(ActiveTerminal);
  315. }
  316. }
  317. try
  318. {
  319. if (FTerminalPendingAction == tpNull)
  320. {
  321. ConnectActiveTerminalImpl(true);
  322. }
  323. else
  324. {
  325. FTerminalPendingAction = tpReconnect;
  326. }
  327. }
  328. catch(...)
  329. {
  330. FreeActiveTerminal();
  331. throw;
  332. }
  333. }
  334. //---------------------------------------------------------------------------
  335. void __fastcall TTerminalManager::FreeAll()
  336. {
  337. FDestroying = true;
  338. try
  339. {
  340. while (Count)
  341. {
  342. FreeTerminal(Terminals[0]);
  343. }
  344. }
  345. __finally
  346. {
  347. FDestroying = false;
  348. }
  349. }
  350. //---------------------------------------------------------------------------
  351. void __fastcall TTerminalManager::FreeTerminal(TTerminal * Terminal)
  352. {
  353. try
  354. {
  355. if (Terminal->Active)
  356. {
  357. Terminal->Close();
  358. }
  359. }
  360. __finally
  361. {
  362. int Index = IndexOf(Terminal);
  363. FTerminalList->Clear();
  364. Extract(Terminal);
  365. TTerminalQueue * Queue;
  366. Queue = reinterpret_cast<TTerminalQueue *>(FQueues->Items[Index]);
  367. FQueues->Delete(Index);
  368. FTerminationMessages->Delete(Index);
  369. if (ActiveTerminal && (Terminal == ActiveTerminal))
  370. {
  371. if ((Count > 0) && !FDestroying)
  372. {
  373. for (int i = 0; i < Count; i++)
  374. {
  375. if (Terminals[i]->Status == ssOpened)
  376. {
  377. ActiveTerminal = Terminals[i];
  378. break;
  379. }
  380. }
  381. if (ActiveTerminal == Terminal)
  382. {
  383. ActiveTerminal = Terminals[Index < Count ? Index : 0];
  384. }
  385. }
  386. else
  387. {
  388. ActiveTerminal = NULL;
  389. }
  390. }
  391. else
  392. {
  393. SaveTerminal(Terminal);
  394. }
  395. // only now all references to/from queue (particularly events to explorer)
  396. // are cleared
  397. delete Queue;
  398. delete Terminal;
  399. if (OnTerminalListChanged)
  400. {
  401. OnTerminalListChanged(this);
  402. }
  403. }
  404. }
  405. //---------------------------------------------------------------------------
  406. void __fastcall TTerminalManager::SetScpExplorer(TCustomScpExplorerForm * value)
  407. {
  408. if (ScpExplorer != value)
  409. {
  410. // changing explorer is not supported yet
  411. assert(!ScpExplorer || !value);
  412. FScpExplorer = value;
  413. if (FScpExplorer)
  414. {
  415. FScpExplorer->Terminal = ActiveTerminal;
  416. FScpExplorer->Queue = ActiveQueue;
  417. FOnLastTerminalClosed = FScpExplorer->LastTerminalClosed;
  418. FOnTerminalListChanged = FScpExplorer->TerminalListChanged;
  419. }
  420. else
  421. {
  422. FOnLastTerminalClosed = NULL;
  423. FOnTerminalListChanged = NULL;
  424. }
  425. }
  426. }
  427. //---------------------------------------------------------------------------
  428. void __fastcall TTerminalManager::SetActiveTerminal(TTerminal * value)
  429. {
  430. if (ActiveTerminal != value)
  431. {
  432. // here used to be call to TCustomScpExporer::UpdateSessionData (now UpdateTerminal)
  433. // but it seems to be duplicate to call from TCustomScpExporer::TerminalChanging
  434. TTerminal * PActiveTerminal = ActiveTerminal;
  435. FActiveTerminal = NULL;
  436. FActiveTerminal = value;
  437. // moved from else block of next if (ActiveTerminal) statement
  438. // so ScpExplorer can update its caption
  439. UpdateAppTitle();
  440. if (ScpExplorer)
  441. {
  442. if (ActiveTerminal && (ActiveTerminal->Status == ssOpened))
  443. {
  444. TerminalReady();
  445. }
  446. else
  447. {
  448. ScpExplorer->Terminal = NULL;
  449. ScpExplorer->Queue = NULL;
  450. }
  451. }
  452. if (PActiveTerminal && !PActiveTerminal->Active)
  453. {
  454. SaveTerminal(PActiveTerminal);
  455. }
  456. if (ActiveTerminal)
  457. {
  458. if (!PActiveTerminal)
  459. {
  460. CreateLogMemo();
  461. }
  462. assert(LogMemo);
  463. LogMemo->SessionLog = ActiveTerminal->Log;
  464. int Index = ActiveTerminalIndex;
  465. if (!ActiveTerminal->Active && !FTerminationMessages->Strings[Index].IsEmpty())
  466. {
  467. AnsiString Message = FTerminationMessages->Strings[Index];
  468. FTerminationMessages->Strings[Index] = "";
  469. Exception * E = new ESshFatal(NULL, Message);
  470. try
  471. {
  472. // finally show pending terminal message,
  473. // this gives user also possibility to reconnect
  474. ActiveTerminal->ShowExtendedException(E);
  475. }
  476. __finally
  477. {
  478. delete E;
  479. }
  480. }
  481. }
  482. else
  483. {
  484. if (LogForm)
  485. {
  486. FreeLogForm();
  487. }
  488. FreeLogMemo();
  489. if (OnLastTerminalClosed)
  490. {
  491. OnLastTerminalClosed(this);
  492. }
  493. }
  494. }
  495. }
  496. //---------------------------------------------------------------------------
  497. AnsiString __fastcall TTerminalManager::UpdateAppTitle()
  498. {
  499. AnsiString NewTitle;
  500. if (ActiveTerminal)
  501. {
  502. NewTitle = FMTLOAD(APP_CAPTION, (ActiveTerminalTitle, AppName));
  503. }
  504. else
  505. {
  506. NewTitle = AppName;
  507. }
  508. if (!FProgressTitle.IsEmpty())
  509. {
  510. NewTitle = FProgressTitle + " - " + NewTitle;
  511. }
  512. else if (ActiveTerminal && (ScpExplorer != NULL))
  513. {
  514. AnsiString Path = ScpExplorer->PathForCaption();
  515. if (!Path.IsEmpty())
  516. {
  517. NewTitle = Path + " - " + NewTitle;
  518. }
  519. }
  520. Application->Title = NewTitle;
  521. if (ScpExplorer)
  522. {
  523. ScpExplorer->ApplicationTitleChanged();
  524. }
  525. return NewTitle;
  526. }
  527. //---------------------------------------------------------------------------
  528. void __fastcall TTerminalManager::SaveTerminal(TTerminal * Terminal)
  529. {
  530. if (!Terminal->SessionData->Name.IsEmpty())
  531. {
  532. TSessionData * Data;
  533. Data = (TSessionData *)StoredSessions->FindByName(Terminal->SessionData->Name);
  534. if (Data)
  535. {
  536. bool Changed = false;
  537. if (Terminal->SessionData->UpdateDirectories)
  538. {
  539. TManagedTerminal * ManagedTerminal = dynamic_cast<TManagedTerminal *>(Terminal);
  540. assert(ManagedTerminal != NULL);
  541. Data->LocalDirectory = ManagedTerminal->LocalDirectory;
  542. Data->RemoteDirectory = ManagedTerminal->RemoteDirectory;
  543. Changed = true;
  544. }
  545. if (Changed)
  546. {
  547. // modified only, implicit
  548. StoredSessions->Save(false, false);
  549. }
  550. }
  551. }
  552. }
  553. //---------------------------------------------------------------------------
  554. void __fastcall TTerminalManager::CreateLogMemo()
  555. {
  556. assert(!FLogMemo);
  557. assert(ActiveTerminal);
  558. FLogMemo = new TLogMemo(Application);
  559. try
  560. {
  561. FLogMemo->SessionLog = ActiveTerminal->Log;
  562. FLogMemo->PopupMenu = NonVisualDataModule->LogMemoPopup;
  563. }
  564. catch (...)
  565. {
  566. delete FLogMemo;
  567. throw;
  568. }
  569. }
  570. //---------------------------------------------------------------------------
  571. void __fastcall TTerminalManager::FreeLogMemo()
  572. {
  573. assert(LogMemo);
  574. LogMemo->PopupMenu = NULL;
  575. SAFE_DESTROY(FLogMemo);
  576. }
  577. //---------------------------------------------------------------------------
  578. void __fastcall TTerminalManager::ApplicationException(TObject * /*Sender*/,
  579. Exception * E)
  580. {
  581. // can be null for example when exception is thrown on login dialog
  582. if (ActiveTerminal != NULL)
  583. {
  584. ActiveTerminal->ShowExtendedException(E);
  585. }
  586. else
  587. {
  588. ShowExtendedException(E);
  589. }
  590. }
  591. //---------------------------------------------------------------------------
  592. void __fastcall TTerminalManager::ApplicationShowHint(AnsiString & HintStr,
  593. bool & /*CanShow*/, THintInfo & HintInfo)
  594. {
  595. TLabel * HintLabel = dynamic_cast<TLabel *>(HintInfo.HintControl);
  596. if ((HintLabel != NULL) && (HintLabel->Caption == HintStr))
  597. {
  598. // Hack for transfer setting labels.
  599. // Should be converted to something like HintLabel()
  600. HintInfo.HintPos = HintLabel->ClientToScreen(TPoint(0, 0));
  601. HintInfo.HintMaxWidth = HintLabel->Width;
  602. HintInfo.HideTimeout = 100000; // "almost" never
  603. }
  604. else if (dynamic_cast<TProgressBar *>(HintInfo.HintControl) != NULL)
  605. {
  606. HintInfo.HideTimeout = 100000; // "almost" never
  607. HintInfo.ReshowTimeout = 500; // updated each 0.5s
  608. }
  609. else
  610. {
  611. HintInfo.HintMaxWidth = 300;
  612. }
  613. }
  614. //---------------------------------------------------------------------------
  615. void __fastcall TTerminalManager::ApplicationActivate(TObject * /*Sender*/)
  616. {
  617. // make sure the taskbar button of main window is pressed
  618. // (but only if main window is our application focused window,
  619. // note that there can also be an editor window)
  620. if ((ScpExplorer != NULL) && (Screen->ActiveForm == ScpExplorer))
  621. {
  622. // unfortunatelly this causes the main window to redraw (flicker).
  623. // also the same problem happens for any top-level window (login, authentication),
  624. // not only to main explorer, so the solution should be generalized
  625. SetActiveWindow(Application->Handle);
  626. }
  627. }
  628. //---------------------------------------------------------------------------
  629. void __fastcall TTerminalManager::DeleteLocalFile(const AnsiString FileName, bool Alternative)
  630. {
  631. if (!RecursiveDeleteFile(FileName, (WinConfiguration->DeleteToRecycleBin != Alternative)))
  632. {
  633. throw EOSExtException(FMTLOAD(DELETE_LOCAL_FILE_ERROR, (FileName)));
  634. }
  635. }
  636. //---------------------------------------------------------------------------
  637. void __fastcall TTerminalManager::TerminalQueryUser(TObject * Sender,
  638. const AnsiString Query, TStrings * MoreMessages, int Answers,
  639. const TQueryParams * Params, int & Answer, TQueryType Type, void * /*Arg*/)
  640. {
  641. AnsiString HelpKeyword;
  642. TMessageParams MessageParams(Params);
  643. AnsiString AQuery = Query;
  644. if (Params != NULL)
  645. {
  646. HelpKeyword = Params->HelpKeyword;
  647. if (FLAGSET(Params->Params, qpFatalAbort))
  648. {
  649. AQuery = FMTLOAD(WARN_FATAL_ERROR, (AQuery));
  650. if (!MessageParams.TimerMessage.IsEmpty())
  651. {
  652. MessageParams.TimerMessage = FMTLOAD(WARN_FATAL_ERROR, (MessageParams.TimerMessage));
  653. }
  654. }
  655. }
  656. if (ScpExplorer)
  657. {
  658. Answer = ScpExplorer->MoreMessageDialog(AQuery, MoreMessages, Type, Answers,
  659. HelpKeyword, &MessageParams, dynamic_cast<TTerminal *>(Sender));
  660. }
  661. else
  662. {
  663. Answer = MoreMessageDialog(AQuery, MoreMessages, Type, Answers, HelpKeyword,
  664. &MessageParams);
  665. }
  666. }
  667. //---------------------------------------------------------------------------
  668. TAuthenticateForm * __fastcall TTerminalManager::MakeAuthenticateForm(
  669. TSessionData * Data)
  670. {
  671. TAuthenticateForm * Dialog = SafeFormCreate<TAuthenticateForm>();
  672. Dialog->Init(Data);
  673. return Dialog;
  674. }
  675. //---------------------------------------------------------------------------
  676. void __fastcall TTerminalManager::TerminalPromptUser(
  677. TTerminal * Terminal, TPromptKind Kind, AnsiString Name, AnsiString Instructions,
  678. TStrings * Prompts, TStrings * Results, bool & Result, void * /*Arg*/)
  679. {
  680. if ((Kind == pkPrompt) && (FAuthenticateForm == NULL) &&
  681. (Terminal->Status != ssOpening))
  682. {
  683. assert(Instructions.IsEmpty());
  684. assert(Prompts->Count == 1);
  685. assert(bool(Prompts->Objects[0]));
  686. AnsiString AResult = Results->Strings[0];
  687. Result = InputDialog(Name, Prompts->Strings[0], AResult);
  688. if (Result)
  689. {
  690. Results->Strings[0] = AResult;
  691. }
  692. }
  693. else
  694. {
  695. TAuthenticateForm * AuthenticateForm = FAuthenticateForm;
  696. if (AuthenticateForm == NULL)
  697. {
  698. AuthenticateForm = MakeAuthenticateForm(Terminal->SessionData);
  699. }
  700. try
  701. {
  702. Result = AuthenticateForm->PromptUser(Kind, Name, Instructions, Prompts, Results,
  703. (FAuthenticateForm != NULL), Terminal->StoredCredentialsTried);
  704. }
  705. __finally
  706. {
  707. if (FAuthenticateForm == NULL)
  708. {
  709. delete AuthenticateForm;
  710. }
  711. }
  712. }
  713. }
  714. //---------------------------------------------------------------------------
  715. void __fastcall TTerminalManager::TerminalDisplayBanner(
  716. TTerminal * Terminal, AnsiString SessionName,
  717. const AnsiString & Banner, bool & NeverShowAgain, int Options)
  718. {
  719. assert(FAuthenticateForm != NULL);
  720. TAuthenticateForm * AuthenticateForm = FAuthenticateForm;
  721. if (AuthenticateForm == NULL)
  722. {
  723. AuthenticateForm = MakeAuthenticateForm(Terminal->SessionData);
  724. }
  725. try
  726. {
  727. AuthenticateForm->Banner(Banner, NeverShowAgain, Options);
  728. }
  729. __finally
  730. {
  731. if (FAuthenticateForm == NULL)
  732. {
  733. delete AuthenticateForm;
  734. }
  735. }
  736. }
  737. //---------------------------------------------------------------------------
  738. void __fastcall TTerminalManager::TerminalShowExtendedException(
  739. TTerminal * Terminal, Exception * E, void * /*Arg*/)
  740. {
  741. if (ScpExplorer)
  742. {
  743. ScpExplorer->ShowExtendedException(Terminal, E);
  744. }
  745. else
  746. {
  747. ShowExtendedExceptionEx(Terminal, E);
  748. }
  749. }
  750. //---------------------------------------------------------------------------
  751. void __fastcall TTerminalManager::TerminalReadDirectoryProgress(
  752. TObject * /*Sender*/, int Progress, bool & Cancel)
  753. {
  754. static TDateTime DirectoryReadingProgressDelay(0, 0, 1, 500);
  755. if (Progress == 0)
  756. {
  757. if (ScpExplorer != NULL)
  758. {
  759. ScpExplorer->LockWindow();
  760. }
  761. FDirectoryReadingStart = Now();
  762. if (!FProgressTitle.IsEmpty())
  763. {
  764. FProgressTitle = "";
  765. UpdateAppTitle();
  766. }
  767. // Reset "was ESC ever pressed?" state
  768. GetAsyncKeyState(VK_ESCAPE);
  769. }
  770. else if (Progress < 0)
  771. {
  772. if (Progress == -2)
  773. {
  774. // cancelled
  775. if (ScpExplorer != NULL)
  776. {
  777. ScpExplorer->ReadDirectoryCancelled();
  778. }
  779. }
  780. else
  781. {
  782. if (ScpExplorer != NULL)
  783. {
  784. ScpExplorer->UnlockWindow();
  785. }
  786. FProgressTitle = "";
  787. UpdateAppTitle();
  788. }
  789. }
  790. else
  791. {
  792. // If the least significant bit is set,
  793. // the key was pressed after the previous call to GetAsyncKeyState.
  794. int KeyState = GetAsyncKeyState(VK_ESCAPE);
  795. if (FLAGSET(KeyState, 0x01))
  796. {
  797. Cancel = true;
  798. }
  799. if ((Now() - FDirectoryReadingStart) >= DirectoryReadingProgressDelay)
  800. {
  801. FProgressTitle = FMTLOAD(DIRECTORY_READING_PROGRESS, (Progress));
  802. UpdateAppTitle();
  803. }
  804. }
  805. }
  806. //---------------------------------------------------------------------------
  807. void __fastcall TTerminalManager::TerminalInformation(
  808. TTerminal * Terminal, const AnsiString & Str, bool /*Status*/, bool Active)
  809. {
  810. if (Active)
  811. {
  812. if (Terminal->Status == ssOpening)
  813. {
  814. bool ShowPending = false;
  815. if (FAuthenticateForm == NULL)
  816. {
  817. FAuthenticateForm = MakeAuthenticateForm(Terminal->SessionData);
  818. ShowPending = true;
  819. Busy(true);
  820. }
  821. FAuthenticateForm->Log(Str);
  822. if (ShowPending)
  823. {
  824. FAuthenticateForm->ShowAsModal();
  825. }
  826. }
  827. }
  828. else
  829. {
  830. Busy(false);
  831. SAFE_DESTROY(FAuthenticateForm);
  832. }
  833. }
  834. //---------------------------------------------------------------------------
  835. void __fastcall TTerminalManager::OperationFinished(::TFileOperation Operation,
  836. TOperationSide Side, bool Temp, const AnsiString & FileName, bool Success,
  837. TOnceDoneOperation & OnceDoneOperation)
  838. {
  839. assert(ScpExplorer);
  840. ScpExplorer->OperationFinished(Operation, Side, Temp, FileName, Success,
  841. OnceDoneOperation);
  842. }
  843. //---------------------------------------------------------------------------
  844. void __fastcall TTerminalManager::OperationProgress(
  845. TFileOperationProgressType & ProgressData, TCancelStatus & Cancel)
  846. {
  847. if (ProgressData.InProgress)
  848. {
  849. FProgressTitle = FORMAT("%d%% %s",
  850. (ProgressData.OverallProgress(),
  851. TProgressForm::OperationName(ProgressData.Operation)));
  852. }
  853. else
  854. {
  855. FProgressTitle = "";
  856. }
  857. UpdateAppTitle();
  858. assert(ScpExplorer);
  859. ScpExplorer->OperationProgress(ProgressData, Cancel);
  860. }
  861. //---------------------------------------------------------------------------
  862. void __fastcall TTerminalManager::QueueEvent(TTerminalQueue * Queue, TQueueEvent Event)
  863. {
  864. TGuard Guard(FQueueSection);
  865. FQueueWithEvent = Queue;
  866. FQueueEvent = Event;
  867. }
  868. //---------------------------------------------------------------------------
  869. void __fastcall TTerminalManager::ConfigurationChange(TObject * /*Sender*/)
  870. {
  871. assert(Configuration);
  872. assert(Configuration == WinConfiguration);
  873. if (!Application->Terminated && Configuration->Logging &&
  874. (WinConfiguration->LogView == lvWindow))
  875. {
  876. if (ActiveTerminal)
  877. {
  878. RequireLogForm(LogMemo);
  879. }
  880. }
  881. else
  882. {
  883. FreeLogForm();
  884. }
  885. TTerminalQueue * Queue;
  886. for (int Index = 0; Index < Count; Index++)
  887. {
  888. assert(Terminals[Index]->Log);
  889. Terminals[Index]->Log->ReflectSettings();
  890. Queue = reinterpret_cast<TTerminalQueue *>(FQueues->Items[Index]);
  891. Queue->TransfersLimit = GUIConfiguration->QueueTransfersLimit;
  892. }
  893. if (ScpExplorer)
  894. {
  895. ScpExplorer->ConfigurationChanged();
  896. }
  897. }
  898. //---------------------------------------------------------------------------
  899. void __fastcall TTerminalManager::TerminalReady()
  900. {
  901. ScpExplorer->Terminal = ActiveTerminal;
  902. ScpExplorer->Queue = ActiveQueue;
  903. }
  904. //---------------------------------------------------------------------------
  905. TStrings * __fastcall TTerminalManager::GetTerminalList()
  906. {
  907. if (FTerminalList->Count != Count)
  908. {
  909. for (int i = 0; i < Count; i++)
  910. {
  911. AnsiString NameN;
  912. AnsiString Name = Terminals[i]->SessionData->SessionName;
  913. int Number = 1;
  914. NameN = Name;
  915. while (FTerminalList->IndexOf(NameN) >= 0)
  916. {
  917. Number++;
  918. NameN = FORMAT("%s (%d)", (Name, Number));
  919. }
  920. if (Number > 1)
  921. {
  922. Name = FORMAT("%s (%d)", (Name, Number));
  923. }
  924. FTerminalList->AddObject(Name, Terminals[i]);
  925. }
  926. }
  927. return FTerminalList;
  928. }
  929. //---------------------------------------------------------------------------
  930. int __fastcall TTerminalManager::GetActiveTerminalIndex()
  931. {
  932. return ActiveTerminal ? IndexOf(ActiveTerminal) : -1;
  933. }
  934. //---------------------------------------------------------------------------
  935. void __fastcall TTerminalManager::SetActiveTerminalIndex(int value)
  936. {
  937. ActiveTerminal = Terminals[value];
  938. }
  939. //---------------------------------------------------------------------------
  940. AnsiString __fastcall TTerminalManager::TerminalTitle(TTerminal * Terminal)
  941. {
  942. int Index = IndexOf(Terminal);
  943. assert(Index >= 0);
  944. AnsiString Result;
  945. if (Index >= 0)
  946. {
  947. Result = TerminalList->Strings[Index];
  948. }
  949. else
  950. {
  951. Result = Terminal->SessionData->SessionName;
  952. }
  953. return Result;
  954. }
  955. //---------------------------------------------------------------------------
  956. AnsiString __fastcall TTerminalManager::GetActiveTerminalTitle()
  957. {
  958. AnsiString Result = ActiveTerminal ?
  959. TerminalTitle(ActiveTerminal) : AnsiString("");
  960. return Result;
  961. }
  962. //---------------------------------------------------------------------------
  963. TTerminalQueue * __fastcall TTerminalManager::GetActiveQueue()
  964. {
  965. TTerminalQueue * Result = NULL;
  966. if (ActiveTerminal != NULL)
  967. {
  968. Result = reinterpret_cast<TTerminalQueue *>(FQueues->Items[ActiveTerminalIndex]);
  969. }
  970. return Result;
  971. }
  972. //---------------------------------------------------------------------------
  973. void __fastcall TTerminalManager::CycleTerminals(bool Forward)
  974. {
  975. int Index = ActiveTerminalIndex;
  976. Index += Forward ? 1 : -1;
  977. if (Index < 0)
  978. {
  979. Index = Count-1;
  980. }
  981. else if (Index >= Count)
  982. {
  983. Index = 0;
  984. }
  985. ActiveTerminalIndex = Index;
  986. }
  987. //---------------------------------------------------------------------------
  988. bool __fastcall TTerminalManager::CanOpenInPutty()
  989. {
  990. return (ActiveTerminal != NULL) && !GUIConfiguration->PuttyPath.Trim().IsEmpty();
  991. }
  992. //---------------------------------------------------------------------------
  993. void __fastcall TTerminalManager::OpenInPutty()
  994. {
  995. TSessionData * Data = new TSessionData("");
  996. try
  997. {
  998. Data->Assign(ActiveTerminal->SessionData);
  999. if (ActiveTerminal->TunnelLocalPortNumber != 0)
  1000. {
  1001. Data->ConfigureTunnel(ActiveTerminal->TunnelLocalPortNumber);
  1002. }
  1003. assert(ActiveTerminal != NULL);
  1004. OpenSessionInPutty(GUIConfiguration->PuttyPath, Data,
  1005. GUIConfiguration->PuttyPassword ? ActiveTerminal->Password : AnsiString());
  1006. }
  1007. __finally
  1008. {
  1009. delete Data;
  1010. }
  1011. }
  1012. //---------------------------------------------------------------------------
  1013. bool __fastcall TTerminalManager::NewSession()
  1014. {
  1015. bool Result;
  1016. TSessionData * Data = new TSessionData("");
  1017. try
  1018. {
  1019. Data->Assign(StoredSessions->DefaultSettings);
  1020. if (DoLoginDialog(StoredSessions, Data, loAddSession))
  1021. {
  1022. assert(Data->CanLogin);
  1023. TTerminalManager * Manager = TTerminalManager::Instance();
  1024. TTerminal * Terminal = Manager->NewTerminal(Data);
  1025. Manager->ActiveTerminal = Terminal;
  1026. Result = Manager->ConnectActiveTerminal();
  1027. }
  1028. }
  1029. __finally
  1030. {
  1031. delete Data;
  1032. }
  1033. return Result;
  1034. }
  1035. //---------------------------------------------------------------------------
  1036. void __fastcall TTerminalManager::Idle()
  1037. {
  1038. for (int Index = 0; Index < Count; Index++)
  1039. {
  1040. TTerminal * Terminal = Terminals[Index];
  1041. try
  1042. {
  1043. if (Terminal->Active)
  1044. {
  1045. Terminal->Idle();
  1046. assert(Index < FQueues->Count);
  1047. if (Index < FQueues->Count)
  1048. {
  1049. reinterpret_cast<TTerminalQueue *>(FQueues->Items[Index])->Idle();
  1050. }
  1051. }
  1052. }
  1053. catch(Exception & E)
  1054. {
  1055. if (Terminal == ActiveTerminal)
  1056. {
  1057. // throw further, so that the exception is handled in proper place
  1058. // (particularly in broken-transfer reconnect handler, bug 72)
  1059. throw;
  1060. }
  1061. else
  1062. {
  1063. // we may not have inactive terminal, unless there is a explorer,
  1064. // also Idle is called from explorer anyway
  1065. assert(ScpExplorer != NULL);
  1066. if (ScpExplorer != NULL)
  1067. {
  1068. ScpExplorer->InactiveTerminalException(Terminal, &E);
  1069. }
  1070. if (!Terminal->Active)
  1071. {
  1072. // if session is lost, save the error message and rethrow it
  1073. // once the terminal gets activated
  1074. FTerminationMessages->Strings[Index] = E.Message;
  1075. }
  1076. }
  1077. }
  1078. }
  1079. TTerminalQueue * QueueWithEvent;
  1080. TQueueEvent QueueEvent;
  1081. {
  1082. TGuard Guard(FQueueSection);
  1083. QueueWithEvent = FQueueWithEvent;
  1084. FQueueWithEvent = NULL;
  1085. QueueEvent = FQueueEvent;
  1086. }
  1087. if (QueueWithEvent != NULL)
  1088. {
  1089. int Index = FQueues->IndexOf(QueueWithEvent);
  1090. // the session may not exist anymore
  1091. if (Index >= 0)
  1092. {
  1093. TTerminal * Terminal = Terminals[Index];
  1094. // we can hardly have a queue event without explorer
  1095. assert(ScpExplorer != NULL);
  1096. if (ScpExplorer != NULL)
  1097. {
  1098. ScpExplorer->QueueEvent(Terminal, QueueWithEvent, QueueEvent);
  1099. }
  1100. }
  1101. }
  1102. }
  1103. //---------------------------------------------------------------------------
  1104. void __fastcall TTerminalManager::MasterPasswordPrompt()
  1105. {
  1106. if (GetCurrentThreadId() == MainThreadID)
  1107. {
  1108. if (!DoMasterPasswordDialog())
  1109. {
  1110. Abort();
  1111. }
  1112. }
  1113. else
  1114. {
  1115. // this can happen only when we keep cancelling all master password prompts
  1116. // as long as the sessing finally connects (session password has to be
  1117. // explictly typed in), and background transfer is started
  1118. Abort();
  1119. }
  1120. }