TerminalManager.cpp 32 KB

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