TerminalManager.cpp 31 KB

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