TerminalManager.cpp 36 KB

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