TerminalManager.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "TerminalManager.h"
  5. #include "CustomScpExplorer.h"
  6. #include "LogMemo.h"
  7. #include "NonVisual.h"
  8. #include "WinConfiguration.h"
  9. #include <Log.h>
  10. #include <OperationStatus.h>
  11. #include <Common.h>
  12. #include <ScpMain.h>
  13. #include <TextsWin.h>
  14. #include <Progress.h>
  15. #include <Queue.h>
  16. //---------------------------------------------------------------------------
  17. #pragma package(smart_init)
  18. //---------------------------------------------------------------------------
  19. TTerminalManager * TTerminalManager::FInstance = NULL;
  20. //---------------------------------------------------------------------------
  21. TTerminalManager * __fastcall TTerminalManager::Instance(bool ForceCreation)
  22. {
  23. if (!FInstance && ForceCreation)
  24. {
  25. FInstance = new TTerminalManager();
  26. }
  27. return FInstance;
  28. }
  29. //---------------------------------------------------------------------------
  30. void __fastcall TTerminalManager::DestroyInstance()
  31. {
  32. assert(FInstance);
  33. SAFE_DESTROY(FInstance);
  34. }
  35. //---------------------------------------------------------------------------
  36. __fastcall TTerminalManager::TTerminalManager() :
  37. TTerminalList(Configuration)
  38. {
  39. FLogMemo = NULL;
  40. FActiveTerminal = NULL;
  41. FScpExplorer = NULL;
  42. FDestroying = false;
  43. FTerminalPendingAction = tpNull;
  44. FProgress = -1;
  45. assert(Application && !Application->OnException);
  46. Application->OnException = ApplicationException;
  47. assert(Configuration && !Configuration->OnChange);
  48. Configuration->OnChange = ConfigurationChange;
  49. FOnLastTerminalClosed = NULL;
  50. FOnTerminalListChanged = NULL;
  51. FTerminalList = new TStringList();
  52. FQueues = new TList();
  53. }
  54. //---------------------------------------------------------------------------
  55. __fastcall TTerminalManager::~TTerminalManager()
  56. {
  57. FreeAll();
  58. assert(!ScpExplorer);
  59. assert(Configuration->OnChange == ConfigurationChange);
  60. Configuration->OnChange = NULL;
  61. assert(Application && (Application->OnException == ApplicationException));
  62. Application->OnException = NULL;
  63. delete FQueues;
  64. delete FTerminalList;
  65. }
  66. //---------------------------------------------------------------------------
  67. TTerminal * __fastcall TTerminalManager::NewTerminal(TSessionData * Data)
  68. {
  69. FTerminalList->Clear();
  70. TTerminal * Terminal = TTerminalList::NewTerminal(Data);
  71. try
  72. {
  73. TTerminalQueue * Queue = new TTerminalQueue(Terminal, Configuration);
  74. Queue->TransfersLimit = GUIConfiguration->QueueTransfersLimit;
  75. Queue->OnQueryUser = TerminalQueryUser;
  76. Queue->OnPromptUser = TerminalPromptUser;
  77. Queue->OnShowExtendedException = TerminalShowExtendedException;
  78. FQueues->Add(Queue);
  79. Terminal->OnQueryUser = TerminalQueryUser;
  80. Terminal->OnPromptUser = TerminalPromptUser;
  81. Terminal->OnShowExtendedException = TerminalShowExtendedException;
  82. Terminal->OnProgress = OperationProgress;
  83. Terminal->OnFinished = OperationFinished;
  84. Terminal->OnDeleteLocalFile = DeleteLocalFile;
  85. if (!ActiveTerminal)
  86. {
  87. ActiveTerminal = Terminal;
  88. }
  89. }
  90. catch(...)
  91. {
  92. if (Terminal != NULL)
  93. {
  94. FreeTerminal(Terminal);
  95. }
  96. throw;
  97. }
  98. if (OnTerminalListChanged)
  99. {
  100. OnTerminalListChanged(this);
  101. }
  102. return Terminal;
  103. }
  104. //---------------------------------------------------------------------------
  105. void __fastcall TTerminalManager::FreeActiveTerminal()
  106. {
  107. if (FTerminalPendingAction == tpNull)
  108. {
  109. assert(ActiveTerminal);
  110. FreeTerminal(ActiveTerminal);
  111. }
  112. else
  113. {
  114. assert(FTerminalPendingAction == tpNone);
  115. FTerminalPendingAction = tpFree;
  116. }
  117. }
  118. //---------------------------------------------------------------------------
  119. bool __fastcall TTerminalManager::ConnectActiveTerminal()
  120. {
  121. TTerminalPendingAction Action;
  122. bool Result;
  123. do
  124. {
  125. Action = tpNull;
  126. Result = false;
  127. try
  128. {
  129. assert(ActiveTerminal);
  130. bool ShowLogPending = false;
  131. if (Configuration->Logging && (WinConfiguration->LogView == lvWindow))
  132. {
  133. if (WinConfiguration->LogWindowOnStartup)
  134. {
  135. RequireLogForm(LogMemo);
  136. }
  137. else
  138. {
  139. ShowLogPending = true;
  140. }
  141. }
  142. TOperationStatusForm * Form = new TOperationStatusForm(Application);
  143. Busy(true);
  144. try
  145. {
  146. Form->SecureShell = ActiveTerminal;
  147. Form->ShowAsModal();
  148. ActiveTerminal->Open();
  149. ActiveTerminal->DoStartup();
  150. }
  151. __finally
  152. {
  153. Busy(false);
  154. delete Form;
  155. }
  156. if (ScpExplorer)
  157. {
  158. assert(ActiveTerminal->Status == sshReady);
  159. TerminalReady();
  160. }
  161. WinConfiguration->ClearTemporaryLoginData();
  162. if (LogForm && (WinConfiguration->LogView != lvWindow))
  163. {
  164. FreeLogForm();
  165. }
  166. if (ShowLogPending)
  167. {
  168. RequireLogForm(LogMemo);
  169. }
  170. Result = true;
  171. }
  172. catch(Exception & E)
  173. {
  174. assert(FTerminalPendingAction == tpNull);
  175. FTerminalPendingAction = tpNone;
  176. try
  177. {
  178. assert(ActiveTerminal != NULL);
  179. ActiveTerminal->DoShowExtendedException(&E);
  180. Action = FTerminalPendingAction;
  181. }
  182. __finally
  183. {
  184. FTerminalPendingAction = tpNull;
  185. }
  186. }
  187. }
  188. while (Action == tpReconnect);
  189. if (Action == tpFree)
  190. {
  191. FreeActiveTerminal();
  192. }
  193. return Result;
  194. }
  195. //---------------------------------------------------------------------------
  196. void __fastcall TTerminalManager::ReconnectActiveTerminal()
  197. {
  198. assert(ActiveTerminal);
  199. TTerminal * Terminal;
  200. if (ScpExplorer)
  201. {
  202. TSessionData * Data = new TSessionData(ActiveTerminal->SessionData->Name);
  203. try
  204. {
  205. Data->Assign(ActiveTerminal->SessionData);
  206. if (ScpExplorer->Terminal == ActiveTerminal)
  207. {
  208. ScpExplorer->UpdateSessionData(Data);
  209. }
  210. Terminal = NewTerminal(Data);
  211. }
  212. __finally
  213. {
  214. delete Data;
  215. }
  216. }
  217. else
  218. {
  219. // otherwise the ScpExplorer would be created already
  220. assert(ActiveTerminal->Status < sshReady);
  221. Terminal = NewTerminal(ActiveTerminal->SessionData);
  222. }
  223. try
  224. {
  225. FreeTerminal(ActiveTerminal);
  226. ActiveTerminal = Terminal;
  227. if (FTerminalPendingAction == tpNull)
  228. {
  229. ConnectActiveTerminal();
  230. }
  231. else
  232. {
  233. FTerminalPendingAction = tpReconnect;
  234. }
  235. }
  236. catch(...)
  237. {
  238. FreeTerminal(Terminal);
  239. throw;
  240. }
  241. }
  242. //---------------------------------------------------------------------------
  243. void __fastcall TTerminalManager::FreeAll()
  244. {
  245. FDestroying = true;
  246. try
  247. {
  248. while (Count)
  249. {
  250. FreeTerminal(Terminals[0]);
  251. }
  252. }
  253. __finally
  254. {
  255. FDestroying = false;
  256. }
  257. }
  258. //---------------------------------------------------------------------------
  259. void __fastcall TTerminalManager::FreeTerminal(TTerminal * Terminal)
  260. {
  261. try
  262. {
  263. Terminal->Active = false;
  264. }
  265. __finally
  266. {
  267. int Index = IndexOf(Terminal);
  268. FTerminalList->Clear();
  269. Extract(Terminal);
  270. TTerminalQueue * Queue;
  271. Queue = reinterpret_cast<TTerminalQueue *>(FQueues->Items[Index]);
  272. FQueues->Delete(Index);
  273. delete Queue;
  274. if (ActiveTerminal && (Terminal == ActiveTerminal))
  275. {
  276. if ((Count > 0) && !FDestroying)
  277. {
  278. for (int i = 0; i < Count; i++)
  279. {
  280. if (Terminals[i]->Status == sshReady)
  281. {
  282. ActiveTerminal = Terminals[i];
  283. break;
  284. }
  285. }
  286. if (ActiveTerminal == Terminal)
  287. {
  288. ActiveTerminal = Terminals[Index];
  289. }
  290. }
  291. else
  292. {
  293. ActiveTerminal = NULL;
  294. }
  295. }
  296. else
  297. {
  298. SaveTerminal(Terminal);
  299. }
  300. delete Terminal;
  301. if (OnTerminalListChanged)
  302. {
  303. OnTerminalListChanged(this);
  304. }
  305. }
  306. }
  307. //---------------------------------------------------------------------------
  308. void __fastcall TTerminalManager::SetScpExplorer(TCustomScpExplorerForm * value)
  309. {
  310. if (ScpExplorer != value)
  311. {
  312. // changing explorer is not supported yet
  313. assert(!ScpExplorer || !value);
  314. FScpExplorer = value;
  315. if (FScpExplorer)
  316. {
  317. assert(!OnChangeTerminal);
  318. FScpExplorer->Terminal = ActiveTerminal;
  319. FScpExplorer->Queue = ActiveQueue;
  320. FOnLastTerminalClosed = FScpExplorer->LastTerminalClosed;
  321. FOnTerminalListChanged = FScpExplorer->TerminalListChanged;
  322. }
  323. else
  324. {
  325. FOnLastTerminalClosed = NULL;
  326. FOnTerminalListChanged = NULL;
  327. }
  328. }
  329. }
  330. //---------------------------------------------------------------------------
  331. void __fastcall TTerminalManager::SetActiveTerminal(TTerminal * value)
  332. {
  333. if (ActiveTerminal != value)
  334. {
  335. if (ActiveTerminal && ScpExplorer)
  336. {
  337. assert(!ScpExplorer->Terminal || (ScpExplorer->Terminal == ActiveTerminal));
  338. if (ScpExplorer->Terminal == ActiveTerminal)
  339. {
  340. ScpExplorer->UpdateSessionData();
  341. }
  342. }
  343. TTerminal * PActiveTerminal = ActiveTerminal;
  344. FActiveTerminal = NULL;
  345. if (OnChangeTerminal)
  346. {
  347. OnChangeTerminal(this);
  348. }
  349. FActiveTerminal = value;
  350. // moved from else block of next if (ActiveTerminal) statement
  351. // so ScpExplorer can update its caption
  352. UpdateAppTitle();
  353. if (ScpExplorer)
  354. {
  355. if (ActiveTerminal && (ActiveTerminal->Status == sshReady))
  356. {
  357. TerminalReady();
  358. }
  359. else
  360. {
  361. ScpExplorer->Terminal = NULL;
  362. ScpExplorer->Queue = NULL;
  363. }
  364. }
  365. if (PActiveTerminal && !PActiveTerminal->Active)
  366. {
  367. SaveTerminal(PActiveTerminal);
  368. }
  369. if (ActiveTerminal)
  370. {
  371. if (!PActiveTerminal)
  372. {
  373. CreateLogMemo();
  374. }
  375. assert(LogMemo);
  376. LogMemo->SessionLog = ActiveTerminal->Log;
  377. }
  378. else
  379. {
  380. if (LogForm)
  381. {
  382. FreeLogForm();
  383. }
  384. FreeLogMemo();
  385. if (OnLastTerminalClosed)
  386. {
  387. OnLastTerminalClosed(this);
  388. }
  389. }
  390. }
  391. }
  392. //---------------------------------------------------------------------------
  393. void __fastcall TTerminalManager::UpdateAppTitle()
  394. {
  395. AnsiString NewTitle;
  396. if (ActiveTerminal)
  397. {
  398. NewTitle = FMTLOAD(APP_CAPTION, (ActiveTerminalTitle, AppName));
  399. }
  400. else
  401. {
  402. NewTitle = AppName;
  403. }
  404. if (FProgress >= 0)
  405. {
  406. NewTitle = FORMAT("%d%% %s - %s",
  407. (FProgress, TProgressForm::OperationName(FOperation), NewTitle));
  408. }
  409. Application->Title = NewTitle;
  410. }
  411. //---------------------------------------------------------------------------
  412. void __fastcall TTerminalManager::SaveTerminal(TTerminal * Terminal)
  413. {
  414. if (!Terminal->SessionData->Name.IsEmpty())
  415. {
  416. TSessionData * Data;
  417. Data = (TSessionData *)StoredSessions->FindByName(Terminal->SessionData->Name);
  418. if (Data)
  419. {
  420. bool Changed = false;
  421. if (Terminal->SessionData->UpdateDirectories)
  422. {
  423. Data->LocalDirectory = Terminal->SessionData->LocalDirectory;
  424. Data->RemoteDirectory = Terminal->SessionData->RemoteDirectory;
  425. Changed = true;
  426. }
  427. if (Changed)
  428. {
  429. StoredSessions->Save();
  430. }
  431. }
  432. }
  433. }
  434. //---------------------------------------------------------------------------
  435. void __fastcall TTerminalManager::CreateLogMemo()
  436. {
  437. assert(!FLogMemo);
  438. assert(ActiveTerminal);
  439. FLogMemo = new TLogMemo(Application);
  440. try
  441. {
  442. FLogMemo->SessionLog = ActiveTerminal->Log;
  443. FLogMemo->PopupMenu = NonVisualDataModule->LogMemoPopup;
  444. }
  445. catch (...)
  446. {
  447. delete FLogMemo;
  448. throw;
  449. }
  450. }
  451. //---------------------------------------------------------------------------
  452. void __fastcall TTerminalManager::FreeLogMemo()
  453. {
  454. assert(LogMemo);
  455. LogMemo->PopupMenu = NULL;
  456. SAFE_DESTROY(FLogMemo);
  457. }
  458. //---------------------------------------------------------------------------
  459. void __fastcall TTerminalManager::ApplicationException(TObject * /*Sender*/,
  460. Exception * E)
  461. {
  462. ShowExtendedExceptionEx(ActiveTerminal, E);
  463. }
  464. //---------------------------------------------------------------------------
  465. void __fastcall TTerminalManager::DeleteLocalFile(const AnsiString FileName)
  466. {
  467. if (!RecursiveDeleteFile(FileName, WinConfiguration->DeleteToRecycleBin))
  468. {
  469. throw Exception(FMTLOAD(DELETE_LOCAL_FILE_ERROR, (FileName)));
  470. }
  471. }
  472. //---------------------------------------------------------------------------
  473. void __fastcall TTerminalManager::TerminalQueryUser(TObject * /*Sender*/,
  474. const AnsiString Query, TStrings * MoreMessages, int Answers,
  475. int Params, int & Answer, TQueryType Type)
  476. {
  477. AnsiString AQuery = Query;
  478. if (Params & qpFatalAbort)
  479. {
  480. AQuery = FMTLOAD(WARN_FATAL_ERROR, (AQuery));
  481. }
  482. int MessageParams = 0;
  483. if (Params & qpNeverAskAgainCheck)
  484. {
  485. MessageParams |= mpNeverAskAgainCheck;
  486. }
  487. if (Params & qpAllowContinueOnError)
  488. {
  489. MessageParams |= mpAllowContinueOnError;
  490. }
  491. if (ScpExplorer)
  492. {
  493. Answer = ScpExplorer->MoreMessageDialog(AQuery, MoreMessages, Type, Answers, 0, MessageParams);
  494. }
  495. else
  496. {
  497. Answer = MoreMessageDialog(AQuery, MoreMessages, Type, Answers, 0, MessageParams);
  498. }
  499. }
  500. //---------------------------------------------------------------------------
  501. void __fastcall TTerminalManager::TerminalPromptUser(
  502. TSecureShell * /*SecureShell*/, AnsiString Prompt, TPromptKind Kind,
  503. AnsiString & Response, bool & Result)
  504. {
  505. Result = DoPasswordDialog(Prompt, Kind, Response);
  506. }
  507. //---------------------------------------------------------------------------
  508. void __fastcall TTerminalManager::TerminalShowExtendedException(
  509. TSecureShell * SecureShell, Exception * E)
  510. {
  511. ShowExtendedExceptionEx(SecureShell, E);
  512. }
  513. //---------------------------------------------------------------------------
  514. void __fastcall TTerminalManager::OperationFinished(::TFileOperation Operation,
  515. TOperationSide Side, bool DragDrop, const AnsiString FileName, bool Success,
  516. bool & DisconnectWhenFinished)
  517. {
  518. assert(ScpExplorer);
  519. ScpExplorer->OperationFinished(Operation, Side, DragDrop, FileName, Success,
  520. DisconnectWhenFinished);
  521. }
  522. //---------------------------------------------------------------------------
  523. void __fastcall TTerminalManager::OperationProgress(
  524. TFileOperationProgressType & ProgressData, TCancelStatus & Cancel)
  525. {
  526. FProgress = ProgressData.InProgress ? ProgressData.OverallProgress() : -1;
  527. FOperation = ProgressData.Operation;
  528. UpdateAppTitle();
  529. assert(ScpExplorer);
  530. ScpExplorer->OperationProgress(ProgressData, Cancel);
  531. }
  532. //---------------------------------------------------------------------------
  533. void __fastcall TTerminalManager::ConfigurationChange(TObject * /*Sender*/)
  534. {
  535. assert(Configuration);
  536. assert(Configuration == WinConfiguration);
  537. if (!Application->Terminated && Configuration->Logging &&
  538. (WinConfiguration->LogView == lvWindow))
  539. {
  540. if (ActiveTerminal)
  541. {
  542. RequireLogForm(LogMemo);
  543. }
  544. }
  545. else
  546. {
  547. FreeLogForm();
  548. }
  549. TTerminalQueue * Queue;
  550. for (int Index = 0; Index < Count; Index++)
  551. {
  552. assert(Terminals[Index]->Log);
  553. Terminals[Index]->Log->ReflectSettings();
  554. Queue = reinterpret_cast<TTerminalQueue *>(FQueues->Items[Index]);
  555. Queue->TransfersLimit = GUIConfiguration->QueueTransfersLimit;
  556. }
  557. if (ScpExplorer)
  558. {
  559. ScpExplorer->ConfigurationChanged();
  560. }
  561. }
  562. //---------------------------------------------------------------------------
  563. void __fastcall TTerminalManager::TerminalReady()
  564. {
  565. ScpExplorer->Terminal = ActiveTerminal;
  566. ScpExplorer->Queue = ActiveQueue;
  567. if (OnChangeTerminal)
  568. {
  569. OnChangeTerminal(this);
  570. }
  571. }
  572. //---------------------------------------------------------------------------
  573. TStrings * __fastcall TTerminalManager::GetTerminalList()
  574. {
  575. if (FTerminalList->Count != Count)
  576. {
  577. for (int i = 0; i < Count; i++)
  578. {
  579. AnsiString NameN;
  580. AnsiString Name = Terminals[i]->SessionData->SessionName;
  581. int Number = 1;
  582. NameN = Name;
  583. while (FTerminalList->IndexOf(NameN) >= 0)
  584. {
  585. Number++;
  586. NameN = FORMAT("%s (%d)", (Name, Number));
  587. }
  588. if (Number > 1)
  589. {
  590. Name = FORMAT("%s (%d)", (Name, Number));
  591. }
  592. FTerminalList->AddObject(Name, Terminals[i]);
  593. }
  594. }
  595. return FTerminalList;
  596. }
  597. //---------------------------------------------------------------------------
  598. int __fastcall TTerminalManager::GetActiveTerminalIndex()
  599. {
  600. return ActiveTerminal ? IndexOf(ActiveTerminal) : -1;
  601. }
  602. //---------------------------------------------------------------------------
  603. void __fastcall TTerminalManager::SetActiveTerminalIndex(int value)
  604. {
  605. ActiveTerminal = Terminals[value];
  606. }
  607. //---------------------------------------------------------------------------
  608. AnsiString __fastcall TTerminalManager::GetActiveTerminalTitle()
  609. {
  610. AnsiString Result = ActiveTerminal ?
  611. TerminalList->Strings[IndexOf(ActiveTerminal)] : AnsiString("");
  612. return Result;
  613. }
  614. //---------------------------------------------------------------------------
  615. TTerminalQueue * __fastcall TTerminalManager::GetActiveQueue()
  616. {
  617. TTerminalQueue * Result = NULL;
  618. if (ActiveTerminal != NULL)
  619. {
  620. Result = reinterpret_cast<TTerminalQueue *>(FQueues->Items[ActiveTerminalIndex]);
  621. }
  622. return Result;
  623. }
  624. //---------------------------------------------------------------------------
  625. void __fastcall TTerminalManager::CycleTerminals(bool Forward)
  626. {
  627. int Index = ActiveTerminalIndex;
  628. Index += Forward ? 1 : -1;
  629. if (Index < 0)
  630. {
  631. Index = Count-1;
  632. }
  633. else if (Index >= Count)
  634. {
  635. Index = 0;
  636. }
  637. ActiveTerminalIndex = Index;
  638. }